@evolu/common 6.0.1-preview.19 → 6.0.1-preview.20
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/dist/src/Assert.d.ts.map +1 -1
- package/dist/src/Assert.js +1 -1
- package/dist/src/Buffer.d.ts +1 -1
- package/dist/src/Buffer.d.ts.map +1 -1
- package/dist/src/Buffer.js +1 -1
- package/dist/src/CallbackRegistry.d.ts +53 -0
- package/dist/src/CallbackRegistry.d.ts.map +1 -0
- package/dist/src/CallbackRegistry.js +25 -0
- 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 +48 -37
- package/dist/src/Crypto.d.ts.map +1 -1
- package/dist/src/Crypto.js +27 -50
- package/dist/src/Evolu/Db.d.ts +138 -66
- package/dist/src/Evolu/Db.d.ts.map +1 -1
- package/dist/src/Evolu/Db.js +248 -645
- 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 +79 -116
- package/dist/src/Evolu/Evolu.d.ts.map +1 -1
- package/dist/src/Evolu/Evolu.js +275 -132
- 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 +144 -0
- package/dist/src/Evolu/LocalAuth.d.ts.map +1 -0
- package/dist/src/Evolu/LocalAuth.js +171 -0
- package/dist/src/Evolu/Owner.d.ts +129 -83
- package/dist/src/Evolu/Owner.d.ts.map +1 -1
- package/dist/src/Evolu/Owner.js +80 -89
- 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 +114 -191
- package/dist/src/Evolu/Protocol.d.ts.map +1 -1
- package/dist/src/Evolu/Protocol.js +409 -416
- 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.js +3 -3
- package/dist/src/Evolu/Relay.d.ts +1 -2
- package/dist/src/Evolu/Relay.d.ts.map +1 -1
- package/dist/src/Evolu/Relay.js +11 -9
- package/dist/src/Evolu/Schema.d.ts +88 -27
- package/dist/src/Evolu/Schema.d.ts.map +1 -1
- package/dist/src/Evolu/Schema.js +141 -24
- package/dist/src/Evolu/Storage.d.ts +158 -14
- package/dist/src/Evolu/Storage.d.ts.map +1 -1
- package/dist/src/Evolu/Storage.js +32 -32
- package/dist/src/Evolu/Sync.d.ts +77 -13
- package/dist/src/Evolu/Sync.d.ts.map +1 -1
- package/dist/src/Evolu/Sync.js +453 -20
- package/dist/src/Evolu/Timestamp.d.ts +29 -27
- package/dist/src/Evolu/Timestamp.d.ts.map +1 -1
- package/dist/src/Evolu/Timestamp.js +20 -18
- package/dist/src/ManyToManyMap.d.ts +74 -10
- package/dist/src/ManyToManyMap.d.ts.map +1 -1
- package/dist/src/ManyToManyMap.js +41 -6
- package/dist/src/Random.d.ts +3 -2
- package/dist/src/Random.d.ts.map +1 -1
- package/dist/src/RefCountedResourceManager.d.ts +119 -0
- package/dist/src/RefCountedResourceManager.d.ts.map +1 -0
- package/dist/src/RefCountedResourceManager.js +197 -0
- package/dist/src/Result.d.ts +144 -22
- package/dist/src/Result.d.ts.map +1 -1
- package/dist/src/Result.js +5 -2
- package/dist/src/Sqlite.d.ts +20 -4
- package/dist/src/Sqlite.d.ts.map +1 -1
- package/dist/src/Sqlite.js +50 -8
- package/dist/src/Task.d.ts +511 -0
- package/dist/src/Task.d.ts.map +1 -0
- package/dist/src/Task.js +410 -0
- package/dist/src/Time.d.ts +59 -0
- package/dist/src/Time.d.ts.map +1 -1
- package/dist/src/Time.js +87 -4
- package/dist/src/Type.d.ts +431 -341
- package/dist/src/Type.d.ts.map +1 -1
- package/dist/src/Type.js +458 -466
- package/dist/src/WebSocket.d.ts +5 -2
- package/dist/src/WebSocket.d.ts.map +1 -1
- package/dist/src/WebSocket.js +12 -13
- 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 +2 -3
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +2 -3
- package/package.json +7 -7
- package/src/Assert.ts +2 -4
- package/src/Buffer.ts +1 -1
- package/src/CallbackRegistry.ts +84 -0
- package/src/Console.ts +91 -11
- package/src/Crypto.ts +78 -91
- package/src/Evolu/Db.ts +455 -947
- package/src/Evolu/Diff.ts +7 -5
- package/src/Evolu/Evolu.ts +545 -307
- package/src/Evolu/Internal.ts +0 -2
- package/src/Evolu/LocalAuth.ts +422 -0
- package/src/Evolu/Owner.ts +191 -131
- package/src/Evolu/Platform.ts +9 -9
- package/src/Evolu/Protocol.ts +536 -653
- package/src/Evolu/Public.ts +7 -9
- package/src/Evolu/PublicKysely.ts +3 -3
- package/src/Evolu/Relay.ts +17 -12
- package/src/Evolu/Schema.ts +271 -66
- package/src/Evolu/Storage.ts +263 -55
- package/src/Evolu/Sync.ts +758 -37
- package/src/Evolu/Timestamp.ts +30 -35
- package/src/ManyToManyMap.ts +127 -24
- package/src/Random.ts +3 -2
- package/src/RefCountedResourceManager.ts +368 -0
- package/src/Result.ts +149 -23
- package/src/Sqlite.ts +59 -24
- package/src/Task.ts +779 -0
- package/src/Time.ts +168 -4
- package/src/Type.ts +657 -695
- package/src/WebSocket.ts +23 -17
- package/src/Worker.ts +72 -23
- package/src/index.ts +2 -3
- package/dist/src/Callbacks.d.ts +0 -20
- package/dist/src/Callbacks.d.ts.map +0 -1
- package/dist/src/Callbacks.js +0 -18
- package/dist/src/Evolu/Config.d.ts +0 -82
- 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/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/Callbacks.ts +0 -43
- package/src/Evolu/Config.ts +0 -97
- package/src/Evolu/Kysely.ts +0 -38
- package/src/NanoId.ts +0 -39
- package/src/Promise.ts +0 -295
package/dist/src/Type.d.ts
CHANGED
|
@@ -1,77 +1,179 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* 🧩
|
|
2
|
+
* 🧩 Type-safe runtime types
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Evolu {@link Type} is like a type guard that returns typed errors (via
|
|
5
|
+
* {@link Result}) instead of throwing. We either get a safely typed value or a
|
|
6
|
+
* precise, composable error value telling us exactly why validation failed.
|
|
5
7
|
*
|
|
6
|
-
*
|
|
8
|
+
* Why another validation library?
|
|
7
9
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
+
* - **Result-based error handling** – no exceptions for normal control flow.
|
|
11
|
+
* - **Typed errors with decoupled formatters** – validation logic ≠ user
|
|
12
|
+
* messages.
|
|
13
|
+
* - **Consistent constraints via {@link Brand}** – every constraint becomes part
|
|
14
|
+
* of the type.
|
|
15
|
+
* - **No user-land chaining DSL** – designed with the upcoming ES pipe operator
|
|
16
|
+
* in mind.
|
|
17
|
+
* - **Selective validation** – parent validations are skipped when already proved
|
|
18
|
+
* by typing.
|
|
19
|
+
* - **Simple, top-down implementation** – readable source code from top to bottom
|
|
20
|
+
* with no hidden magic; just plain functions and composition.
|
|
10
21
|
*
|
|
11
|
-
*
|
|
12
|
-
* exceptions.
|
|
13
|
-
* - **Consistent constraints**: Enforcing {@link Brand} for all constraints.
|
|
14
|
-
* - **Typed errors with decoupled formatters**: Avoiding coupling error messages
|
|
15
|
-
* with validators.
|
|
16
|
-
* - **No user-land chaining**: Designed with ES pipe operator in mind.
|
|
17
|
-
* - **Selective validation/transformation**: Skipping parent Type validations and
|
|
18
|
-
* transformations when TypeScript's type system can be relied upon.
|
|
19
|
-
* - **Bidirectional transformations**: Supporting transformations in both
|
|
20
|
-
* directions.
|
|
21
|
-
* - **Minimal and transparent code**: No runtime dependencies or hidden magic.
|
|
22
|
+
* ### Base Types Quick Start
|
|
22
23
|
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
24
|
+
* ```ts
|
|
25
|
+
* // Validate unknown values
|
|
26
|
+
* const value: unknown = "hello";
|
|
27
|
+
* const stringResult = String.fromUnknown(value);
|
|
28
|
+
* if (!stringResult.ok) {
|
|
29
|
+
* // console.error(formatStringError(stringResult.error));
|
|
30
|
+
* return stringResult; // inside a function returning Result<string, _>
|
|
31
|
+
* }
|
|
32
|
+
* // Safe branch: value is now string
|
|
33
|
+
* const upper = stringResult.value.toUpperCase();
|
|
27
34
|
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* cannot fail.
|
|
35
|
+
* // Type guard style
|
|
36
|
+
* if (String.is(value)) {
|
|
37
|
+
* // narrowed to string
|
|
38
|
+
* }
|
|
33
39
|
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
* this:
|
|
40
|
+
* // Composing: arrays & objects
|
|
41
|
+
* const Numbers = array(Number); // ReadonlyArray<number>
|
|
42
|
+
* const Point = object({ x: Number, y: Number });
|
|
38
43
|
*
|
|
39
|
-
*
|
|
44
|
+
* Numbers.from([1, 2, 3]); // ok
|
|
45
|
+
* Point.from({ x: 1, y: 2 }); // ok
|
|
46
|
+
* Point.from({ x: 1, y: "2" }); // err -> nested Number error
|
|
47
|
+
* ```
|
|
40
48
|
*
|
|
41
|
-
*
|
|
42
|
-
* `TrimmedString`, the parent Type is `String`.
|
|
49
|
+
* ### Branding Basics
|
|
43
50
|
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
* `fromParent` and `toParent` can be called on any Type.
|
|
51
|
+
* Branding adds semantic meaning & constraints while preserving the runtime
|
|
52
|
+
* shape:
|
|
47
53
|
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
54
|
+
* ```ts
|
|
55
|
+
* const CurrencyCode = brand("CurrencyCode", String, (value) =>
|
|
56
|
+
* /^[A-Z]{3}$/.test(value)
|
|
57
|
+
* ? ok(value)
|
|
58
|
+
* : err<CurrencyCodeError>({ type: "CurrencyCode", value }),
|
|
59
|
+
* );
|
|
60
|
+
* type CurrencyCode = typeof CurrencyCode.Type; // string & Brand<"CurrencyCode">
|
|
61
|
+
*
|
|
62
|
+
* interface CurrencyCodeError extends TypeError<"CurrencyCode"> {}
|
|
50
63
|
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
64
|
+
* const formatCurrencyCodeError =
|
|
65
|
+
* createTypeErrorFormatter<CurrencyCodeError>(
|
|
66
|
+
* (error) => `Invalid currency code: ${error.value}`,
|
|
67
|
+
* );
|
|
68
|
+
*
|
|
69
|
+
* const r = CurrencyCode.from("USD"); // ok("USD")
|
|
70
|
+
* const e = CurrencyCode.from("usd"); // err(...)
|
|
71
|
+
* ```
|
|
72
|
+
*
|
|
73
|
+
* See also reusable brand factories like `minLength`, `maxLength`, `trimmed`,
|
|
74
|
+
* `positive`, `between`, etc.
|
|
75
|
+
*
|
|
76
|
+
* ### Objects & Optional Fields
|
|
77
|
+
*
|
|
78
|
+
* ```ts
|
|
79
|
+
* const User = object({
|
|
80
|
+
* name: NonEmptyTrimmedString100,
|
|
81
|
+
* age: optional(PositiveInt),
|
|
82
|
+
* });
|
|
83
|
+
* type User = typeof User.Type;
|
|
84
|
+
*
|
|
85
|
+
* User.from({ name: "Alice" }); // ok
|
|
86
|
+
* User.from({ name: "Alice", age: -1 }); // err(PositiveInt)
|
|
87
|
+
* ```
|
|
88
|
+
*
|
|
89
|
+
* ### Deriving JSON String Types
|
|
90
|
+
*
|
|
91
|
+
* ```ts
|
|
92
|
+
* const Person = object({
|
|
93
|
+
* name: NonEmptyString50,
|
|
94
|
+
* // Did you know that JSON.stringify converts NaN (a number) into null?
|
|
95
|
+
* // To prevent this, use FiniteNumber.
|
|
96
|
+
* age: FiniteNumber,
|
|
97
|
+
* });
|
|
98
|
+
* type Person = typeof Person.Type;
|
|
99
|
+
*
|
|
100
|
+
* const [PersonJson, personToPersonJson, personJsonToPerson] = json(
|
|
101
|
+
* Person,
|
|
102
|
+
* "PersonJson",
|
|
103
|
+
* );
|
|
104
|
+
* // string & Brand<"PersonJson">
|
|
105
|
+
* type PersonJson = typeof PersonJson.Type;
|
|
106
|
+
*
|
|
107
|
+
* const person = Person.orThrow({
|
|
108
|
+
* name: "Alice",
|
|
109
|
+
* age: 30,
|
|
110
|
+
* });
|
|
111
|
+
*
|
|
112
|
+
* const personJson = personToPersonJson(person);
|
|
113
|
+
* expect(personJsonToPerson(personJson)).toEqual(person);
|
|
114
|
+
* ```
|
|
115
|
+
*
|
|
116
|
+
* ### Error Formatting
|
|
117
|
+
*
|
|
118
|
+
* Evolu separates validation logic from human-readable messages. There are two
|
|
119
|
+
* layers:
|
|
120
|
+
*
|
|
121
|
+
* 1. Per-type formatters (e.g. `formatStringError`) – simple, focused, already
|
|
122
|
+
* used earlier in the quick start example.
|
|
123
|
+
* 2. A unified formatter via `createFormatTypeError` – composes all built-in and
|
|
124
|
+
* custom errors (including nested composite types) and lets us override
|
|
125
|
+
* selected messages.
|
|
126
|
+
*
|
|
127
|
+
* #### 1. Per-Type Formatter (recap)
|
|
128
|
+
*
|
|
129
|
+
* ```ts
|
|
130
|
+
* const r = String.fromUnknown(42);
|
|
131
|
+
* if (!r.ok) console.error(formatStringError(r.error));
|
|
132
|
+
* ```
|
|
133
|
+
*
|
|
134
|
+
* #### 2. Unified Formatter with Overrides
|
|
135
|
+
*
|
|
136
|
+
* ```ts
|
|
137
|
+
* // Override only what we care about; fall back to built-ins for the rest.
|
|
138
|
+
* const formatTypeError = createFormatTypeError((error) => {
|
|
139
|
+
* if (error.type === "MinLength") return `Min length is ${error.min}`;
|
|
140
|
+
* });
|
|
141
|
+
*
|
|
142
|
+
* const User = object({ name: NonEmptyTrimmedString100 });
|
|
143
|
+
* const resultUser = User.from({ name: "" });
|
|
144
|
+
* if (!resultUser.ok) console.error(formatTypeError(resultUser.error));
|
|
145
|
+
*
|
|
146
|
+
* const badPoint = object({ x: Number, y: Number }).from({
|
|
147
|
+
* x: 1,
|
|
148
|
+
* y: "foo",
|
|
149
|
+
* });
|
|
150
|
+
* if (!badPoint.ok) console.error(formatTypeError(badPoint.error));
|
|
151
|
+
* ```
|
|
152
|
+
*
|
|
153
|
+
* The unified formatter walks nested structures (object / array / record /
|
|
154
|
+
* tuple / union) and applies overrides only where specified, greatly reducing
|
|
155
|
+
* boilerplate when formatting complex validation errors.
|
|
56
156
|
*
|
|
57
157
|
* ### Tip
|
|
58
158
|
*
|
|
59
159
|
* If necessary, write `globalThis.String` instead of `String` to avoid naming
|
|
60
|
-
* clashes with
|
|
160
|
+
* clashes with native types.
|
|
61
161
|
*
|
|
62
|
-
* ### Design Decision:
|
|
162
|
+
* ### Design Decision: No Bidirectional Transformations
|
|
63
163
|
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
164
|
+
* Evolu Type intentionally does not support bidirectional transformations. It
|
|
165
|
+
* previously did, but supporting that while keeping typed error fidelity added
|
|
166
|
+
* complexity that hurt readability & reliability. Most persistence pipelines
|
|
167
|
+
* (e.g. SQLite) already require explicit mapping of query results, so implicit
|
|
168
|
+
* reverse transforms would not buy much. We may revisit this if we can design a
|
|
169
|
+
* minimal, 100% safe API that preserves simplicity.
|
|
68
170
|
*
|
|
69
171
|
* @module
|
|
70
172
|
*/
|
|
71
|
-
import { NanoIdLibDep } from "./NanoId.js";
|
|
72
|
-
import { Ok, Result } from "./Result.js";
|
|
73
|
-
import type { Literal, Simplify, WidenLiteral } from "./Types.js";
|
|
74
173
|
import type { Brand } from "./Brand.js";
|
|
174
|
+
import { type RandomBytesDep } from "./Crypto.js";
|
|
175
|
+
import { Result } from "./Result.js";
|
|
176
|
+
import type { Literal, Simplify, WidenLiteral } from "./Types.js";
|
|
75
177
|
export interface Type<Name extends TypeName,
|
|
76
178
|
/** The type this Type resolves to. */
|
|
77
179
|
T,
|
|
@@ -93,38 +195,58 @@ ParentError extends TypeError = Error> {
|
|
|
93
195
|
*/
|
|
94
196
|
readonly from: (value: Input) => Result<T, ParentError | Error>;
|
|
95
197
|
/**
|
|
96
|
-
* Creates `T` from an
|
|
198
|
+
* Creates `T` from an `Input` value, throwing an error if validation fails.
|
|
97
199
|
*
|
|
98
|
-
* This is
|
|
99
|
-
*/
|
|
100
|
-
readonly fromUnknown: (value: unknown) => Result<T, ParentError | Error>;
|
|
101
|
-
/**
|
|
102
|
-
* The opposite of `from` and `fromUnknown`.
|
|
200
|
+
* This is a convenience method that combines `from` with `getOrThrow`.
|
|
103
201
|
*
|
|
104
|
-
*
|
|
202
|
+
* **When to use:**
|
|
105
203
|
*
|
|
106
|
-
*
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
*
|
|
204
|
+
* - Configuration values that are guaranteed to be valid (e.g., hardcoded
|
|
205
|
+
* constants)
|
|
206
|
+
* - Application startup where failure should crash the program
|
|
207
|
+
* - Test code with known valid inputs
|
|
208
|
+
* - Converting from trusted sources where validation failure indicates a
|
|
209
|
+
* programming error
|
|
111
210
|
*
|
|
112
|
-
*
|
|
113
|
-
* already partially validated/transformed value.
|
|
211
|
+
* **When NOT to use:**
|
|
114
212
|
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
213
|
+
* - User input validation - use `from` and handle errors gracefully
|
|
214
|
+
* - Data from external APIs or files - use `from` for proper error handling
|
|
215
|
+
* - Library code that should return Results rather than throw
|
|
117
216
|
*
|
|
118
217
|
* ### Example
|
|
119
218
|
*
|
|
120
219
|
* ```ts
|
|
121
|
-
* //
|
|
122
|
-
* const
|
|
220
|
+
* // ✅ Good: Known valid constant
|
|
221
|
+
* const maxRetries = PositiveInt.orThrow(3);
|
|
222
|
+
*
|
|
223
|
+
* // ✅ Good: App configuration that should crash on invalid values
|
|
224
|
+
* const appName = SimpleName.orThrow("MyApp");
|
|
225
|
+
*
|
|
226
|
+
* // ❌ Avoid: User input (use `from` instead)
|
|
227
|
+
* const userAge = PositiveInt.orThrow(userInput); // Could crash!
|
|
228
|
+
*
|
|
229
|
+
* // ✅ Better: Handle user input gracefully
|
|
230
|
+
* const ageResult = PositiveInt.from(userInput);
|
|
231
|
+
* if (!ageResult.ok) {
|
|
232
|
+
* // Handle validation error
|
|
233
|
+
* }
|
|
123
234
|
* ```
|
|
124
235
|
*/
|
|
236
|
+
readonly orThrow: (value: Input) => T;
|
|
237
|
+
/**
|
|
238
|
+
* Creates `T` from an unknown value.
|
|
239
|
+
*
|
|
240
|
+
* This is useful when a value is unknown.
|
|
241
|
+
*/
|
|
242
|
+
readonly fromUnknown: (value: unknown) => Result<T, ParentError | Error>;
|
|
243
|
+
/**
|
|
244
|
+
* Creates `T` from `Parent` type.
|
|
245
|
+
*
|
|
246
|
+
* This function skips parent Types validations when we have already partially
|
|
247
|
+
* validated value.
|
|
248
|
+
*/
|
|
125
249
|
readonly fromParent: (value: Parent) => Result<T, Error>;
|
|
126
|
-
/** The opposite of `fromParent`. */
|
|
127
|
-
readonly toParent: (value: T) => Parent;
|
|
128
250
|
/**
|
|
129
251
|
* A **type guard** that checks whether an unknown value satisfies the
|
|
130
252
|
* {@link Type}.
|
|
@@ -230,12 +352,47 @@ export interface TypeErrorWithReason<Name extends TypeName = TypeName, Reason ex
|
|
|
230
352
|
readonly reason: Reason;
|
|
231
353
|
}
|
|
232
354
|
export type AnyType = Type<any, any, any, any, any, any>;
|
|
355
|
+
/**
|
|
356
|
+
* Extracts the name from a {@link Type}.
|
|
357
|
+
*
|
|
358
|
+
* @category Utilities
|
|
359
|
+
*/
|
|
233
360
|
export type InferName<A extends AnyType> = A extends Type<infer Name, any, any, any, any, any> ? Name : never;
|
|
361
|
+
/**
|
|
362
|
+
* Extracts the type from a {@link Type}.
|
|
363
|
+
*
|
|
364
|
+
* @category Utilities
|
|
365
|
+
*/
|
|
234
366
|
export type InferType<A extends AnyType> = A extends Type<any, infer T, any, any, any, any> ? T : never;
|
|
367
|
+
/**
|
|
368
|
+
* Extracts the input type from a {@link Type}.
|
|
369
|
+
*
|
|
370
|
+
* @category Utilities
|
|
371
|
+
*/
|
|
235
372
|
export type InferInput<A extends AnyType> = A extends Type<any, any, infer Input, any, any, any> ? Input : never;
|
|
373
|
+
/**
|
|
374
|
+
* Extracts the specific error type from a {@link Type}.
|
|
375
|
+
*
|
|
376
|
+
* @category Utilities
|
|
377
|
+
*/
|
|
236
378
|
export type InferError<A extends AnyType> = A extends Type<any, any, any, infer Error, any, any> ? Error : never;
|
|
379
|
+
/**
|
|
380
|
+
* Extracts the parent type from a {@link Type}.
|
|
381
|
+
*
|
|
382
|
+
* @category Utilities
|
|
383
|
+
*/
|
|
237
384
|
export type InferParent<A extends AnyType> = A extends Type<any, any, any, any, infer Parent, any> ? Parent : never;
|
|
385
|
+
/**
|
|
386
|
+
* Extracts the parent error type from a {@link Type}.
|
|
387
|
+
*
|
|
388
|
+
* @category Utilities
|
|
389
|
+
*/
|
|
238
390
|
export type InferParentError<A extends AnyType> = A extends Type<any, any, any, any, any, infer ParentError> ? ParentError : never;
|
|
391
|
+
/**
|
|
392
|
+
* Extracts all error types (Error | ParentError) from a {@link Type}.
|
|
393
|
+
*
|
|
394
|
+
* @category Utilities
|
|
395
|
+
*/
|
|
239
396
|
export type InferErrors<T extends AnyType> = T extends Type<any, any, any, infer Error, any, infer ParentError> ? Error | ParentError : never;
|
|
240
397
|
declare const EvoluTypeSymbol: unique symbol;
|
|
241
398
|
/**
|
|
@@ -268,12 +425,6 @@ export type TypeErrorFormatter<Error extends TypeError> = (error: Error) => stri
|
|
|
268
425
|
* Base {@link Type}.
|
|
269
426
|
*
|
|
270
427
|
* A Base Type validates that a value conforms to a specific TypeScript type.
|
|
271
|
-
* Unlike refinements or transformations, Base Types establish the fundamental
|
|
272
|
-
* shape of a value before any branding or transformation occurs.
|
|
273
|
-
*
|
|
274
|
-
* - To **refine** a Base Type further, use the {@link brand} Type Factory.
|
|
275
|
-
* - To **transform** a Base Type into a different representation, use the
|
|
276
|
-
* {@link transform} Type Factory.
|
|
277
428
|
*
|
|
278
429
|
* ### Example
|
|
279
430
|
*
|
|
@@ -410,7 +561,7 @@ export declare const formatIsTypeError: TypeErrorFormatter<EvoluTypeError>;
|
|
|
410
561
|
* The `brand` Type Factory takes the name of a new {@link Brand}, a parent Type
|
|
411
562
|
* to be branded, and the optional `refine` function for additional constraint.
|
|
412
563
|
*
|
|
413
|
-
*
|
|
564
|
+
* The `refine` function can be omitted if we only want to add a brand.
|
|
414
565
|
*
|
|
415
566
|
* ### Examples
|
|
416
567
|
*
|
|
@@ -489,7 +640,7 @@ export declare const formatIsTypeError: TypeErrorFormatter<EvoluTypeError>;
|
|
|
489
640
|
* confirmPassword: SimplePassword,
|
|
490
641
|
* });
|
|
491
642
|
*
|
|
492
|
-
* const ValidForm = brand("
|
|
643
|
+
* const ValidForm = brand("ValidForm", Form, (value) => {
|
|
493
644
|
* if (value.password !== value.confirmPassword)
|
|
494
645
|
* return err<ValidFormError>({
|
|
495
646
|
* type: "ValidForm",
|
|
@@ -567,17 +718,19 @@ export declare const formatCurrencyCodeError: TypeErrorFormatter<CurrencyCodeErr
|
|
|
567
718
|
* ### Example
|
|
568
719
|
*
|
|
569
720
|
* ```ts
|
|
570
|
-
* const result =
|
|
571
|
-
* const error =
|
|
721
|
+
* const result = DateIso.from("2023-01-01T12:00:00.000Z"); // ok
|
|
722
|
+
* const error = DateIso.from("10000-01-01T00:00:00.000Z"); // err
|
|
572
723
|
* ```
|
|
573
724
|
*
|
|
574
725
|
* @category String
|
|
575
726
|
*/
|
|
576
|
-
export declare const
|
|
577
|
-
export type
|
|
578
|
-
export interface
|
|
727
|
+
export declare const DateIso: BrandType<Type<"String", string, string, StringError, string, StringError>, "DateIso", DateIsoError, StringError>;
|
|
728
|
+
export type DateIso = typeof DateIso.Type;
|
|
729
|
+
export interface DateIsoError extends TypeError<"DateIso"> {
|
|
579
730
|
}
|
|
580
|
-
export declare const
|
|
731
|
+
export declare const formatDateIsoError: TypeErrorFormatter<DateIsoError>;
|
|
732
|
+
export declare const dateToDateIso: (value: Date) => Result<DateIso, DateIsoError>;
|
|
733
|
+
export declare const dateIsoToDate: (value: DateIso) => Date;
|
|
581
734
|
/**
|
|
582
735
|
* Helper type for Type Factory that creates a branded Type.
|
|
583
736
|
*
|
|
@@ -600,18 +753,12 @@ export type BrandFactory<Name extends TypeName, Input, RefineError extends TypeE
|
|
|
600
753
|
/**
|
|
601
754
|
* Trimmed string.
|
|
602
755
|
*
|
|
603
|
-
* This Type Factory
|
|
604
|
-
*
|
|
605
|
-
* Factory.
|
|
756
|
+
* This Type Factory validates whether a string has no leading or trailing
|
|
757
|
+
* whitespaces.
|
|
606
758
|
*
|
|
607
|
-
* ###
|
|
759
|
+
* ### Example
|
|
608
760
|
*
|
|
609
761
|
* ```ts
|
|
610
|
-
* // this Type already exists
|
|
611
|
-
* const TrimmedString = trimmed(String);
|
|
612
|
-
* type TrimmedString = typeof TrimmedString.Type;
|
|
613
|
-
*
|
|
614
|
-
* // we can make any branded Type trimmed:
|
|
615
762
|
* const TrimmedNonEmptyString = trimmed(minLength(1)(String));
|
|
616
763
|
* // string & Brand<"MinLength1"> & Brand<"Trimmed">
|
|
617
764
|
* type TrimmedNonEmptyString = typeof TrimmedNonEmptyString.Type;
|
|
@@ -623,33 +770,6 @@ export declare const trimmed: BrandFactory<"Trimmed", string, TrimmedError>;
|
|
|
623
770
|
export interface TrimmedError extends TypeError<"Trimmed"> {
|
|
624
771
|
}
|
|
625
772
|
export declare const formatTrimmedError: TypeErrorFormatter<TrimmedError>;
|
|
626
|
-
export type TransformBrandFactory<Name extends TypeName, Input, TransformError extends TypeError = never> = <PName extends TypeName, P extends Input, PInput, PParent, PError extends TypeError = never, PParentError extends TypeError = never>(parent: Type<PName, P, PInput, PError, PParent, PParentError>) => TransformType<Type<PName, P, PInput, PError, PParent, PParentError>, BrandType<Type<PName, P, PInput, PError, PParent, PParentError>, Name, never, PError | PParentError>, TransformError>;
|
|
627
|
-
/**
|
|
628
|
-
* Trims leading and trailing whitespace from a string.
|
|
629
|
-
*
|
|
630
|
-
* This Type Factory **transforms** the input string by removing whitespace from
|
|
631
|
-
* both ends. For validation only, use {@link trimmed} Type Factory.
|
|
632
|
-
*
|
|
633
|
-
* ### Example
|
|
634
|
-
*
|
|
635
|
-
* ```ts
|
|
636
|
-
* const TrimString = trim(String);
|
|
637
|
-
* expect(TrimString.from("a ")).toEqual(ok("a"));
|
|
638
|
-
* expect(TrimString.fromParent("a ").value).toEqual("a");
|
|
639
|
-
*
|
|
640
|
-
* const TrimNonEmptyString = trim(NonEmptyString);
|
|
641
|
-
* expect(TrimNonEmptyString.from("a " as NonEmptyString)).toEqual(ok("a"));
|
|
642
|
-
* expect(
|
|
643
|
-
* TrimNonEmptyString.fromParent("a " as NonEmptyString).value,
|
|
644
|
-
* ).toEqual("a");
|
|
645
|
-
* ```
|
|
646
|
-
*
|
|
647
|
-
* **Note:** This transformation is irreversible. Calling `toParent` will not
|
|
648
|
-
* restore the original representation.
|
|
649
|
-
*
|
|
650
|
-
* @category String
|
|
651
|
-
*/
|
|
652
|
-
export declare const trim: TransformBrandFactory<"Trimmed", string>;
|
|
653
773
|
/**
|
|
654
774
|
* Trimmed string
|
|
655
775
|
*
|
|
@@ -660,6 +780,7 @@ export declare const trim: TransformBrandFactory<"Trimmed", string>;
|
|
|
660
780
|
*/
|
|
661
781
|
export declare const TrimmedString: BrandType<Type<"String", string, string, StringError, string, StringError>, "Trimmed", TrimmedError, StringError>;
|
|
662
782
|
export type TrimmedString = typeof TrimmedString.Type;
|
|
783
|
+
export declare const trim: (value: string) => TrimmedString;
|
|
663
784
|
/**
|
|
664
785
|
* Minimum length.
|
|
665
786
|
*
|
|
@@ -782,9 +903,9 @@ export interface RegexError<Name extends TypeName = TypeName> extends TypeError<
|
|
|
782
903
|
}
|
|
783
904
|
export declare const formatRegexError: TypeErrorFormatter<RegexError<Capitalize<string>>>;
|
|
784
905
|
/**
|
|
785
|
-
* URL-safe
|
|
906
|
+
* URL-safe string.
|
|
786
907
|
*
|
|
787
|
-
* A `
|
|
908
|
+
* A `UrlSafeString` uses a limited alphabet that is safe for URLs:
|
|
788
909
|
*
|
|
789
910
|
* - Uppercase letters (`A-Z`)
|
|
790
911
|
* - Lowercase letters (`a-z`)
|
|
@@ -792,36 +913,47 @@ export declare const formatRegexError: TypeErrorFormatter<RegexError<Capitalize<
|
|
|
792
913
|
* - Dash (`-`)
|
|
793
914
|
* - Underscore (`_`)
|
|
794
915
|
*
|
|
916
|
+
* This is the same character set used by Base64Url encoding, but this type does
|
|
917
|
+
* not validate that the string is actually Base64Url-encoded data.
|
|
918
|
+
*
|
|
795
919
|
* ### Example
|
|
796
920
|
*
|
|
797
921
|
* ```ts
|
|
798
|
-
* const result =
|
|
922
|
+
* const result = UrlSafeString.from("abc123_-");
|
|
799
923
|
* if (result.ok) {
|
|
800
|
-
* console.log("Valid
|
|
924
|
+
* console.log("Valid URL-safe string:", result.value);
|
|
801
925
|
* } else {
|
|
802
|
-
* console.error("Invalid
|
|
926
|
+
* console.error("Invalid URL-safe string:", result.error);
|
|
803
927
|
* }
|
|
804
928
|
* ```
|
|
805
929
|
*
|
|
806
930
|
* @category String
|
|
807
931
|
*/
|
|
808
|
-
export declare const
|
|
809
|
-
export type
|
|
810
|
-
export type
|
|
932
|
+
export declare const UrlSafeString: BrandType<Type<"String", string, string, StringError, string, StringError>, "UrlSafeString", RegexError<"UrlSafeString">, StringError>;
|
|
933
|
+
export type UrlSafeString = typeof UrlSafeString.Type;
|
|
934
|
+
export type UrlSafeStringError = typeof UrlSafeString.Error;
|
|
811
935
|
/**
|
|
812
|
-
*
|
|
813
|
-
*
|
|
936
|
+
* Base64Url without padding.
|
|
937
|
+
*
|
|
938
|
+
* Encode with {@link uint8ArrayToBase64Url}, decode with
|
|
939
|
+
* {@link base64UrlToUint8Array}.
|
|
940
|
+
*
|
|
941
|
+
* @category String
|
|
814
942
|
*/
|
|
815
|
-
export declare const
|
|
943
|
+
export declare const Base64Url: BrandType<Type<"String", string, string, StringError, string, StringError>, "Base64Url", Base64UrlError, StringError>;
|
|
944
|
+
export type Base64Url = typeof Base64Url.Type;
|
|
945
|
+
export interface Base64UrlError extends TypeError<"Base64Url"> {
|
|
946
|
+
}
|
|
947
|
+
export declare const formatBase64UrlError: TypeErrorFormatter<Base64UrlError>;
|
|
948
|
+
/** Encodes a Uint8Array to a {@link Base64Url} string. */
|
|
949
|
+
export declare const uint8ArrayToBase64Url: (bytes: Uint8Array) => Base64Url;
|
|
950
|
+
/** Decodes a {@link Base64Url} string to a Uint8Array. */
|
|
951
|
+
export declare const base64UrlToUint8Array: (str: Base64Url) => Uint8Array;
|
|
816
952
|
/**
|
|
817
|
-
* Simple alphanumeric string for naming.
|
|
953
|
+
* Simple alphanumeric string for naming in file systems, URLs, and identifiers.
|
|
818
954
|
*
|
|
819
|
-
*
|
|
820
|
-
*
|
|
821
|
-
* - Uppercase letters (`A-Z`)
|
|
822
|
-
* - Lowercase letters (`a-z`)
|
|
823
|
-
* - Digits (`0-9`)
|
|
824
|
-
* - Dash (`-`)
|
|
955
|
+
* Uses the same safe alphabet as {@link UrlSafeString} (letters, digits, `-`,
|
|
956
|
+
* `_`). See `UrlSafeString` for details.
|
|
825
957
|
*
|
|
826
958
|
* The string must be between 1 and 42 characters.
|
|
827
959
|
*
|
|
@@ -838,17 +970,10 @@ export declare const base64UrlAlphabet = "useandom-26T198340PX75pxJACKVERYMINDBU
|
|
|
838
970
|
*
|
|
839
971
|
* @category String
|
|
840
972
|
*/
|
|
841
|
-
export declare const SimpleName: BrandType<Type<"String", string, string, StringError, string, StringError>, "
|
|
973
|
+
export declare const SimpleName: BrandType<BrandType<Type<"String", string, string, StringError, string, StringError>, "UrlSafeString", RegexError<"UrlSafeString">, StringError>, "SimpleName", SimpleNameError, StringError | RegexError<"UrlSafeString">>;
|
|
842
974
|
export type SimpleName = typeof SimpleName.Type;
|
|
843
|
-
export
|
|
844
|
-
|
|
845
|
-
* Default NanoId.
|
|
846
|
-
*
|
|
847
|
-
* @category String
|
|
848
|
-
*/
|
|
849
|
-
export declare const NanoId: BrandType<Type<"String", string, string, StringError, string, StringError>, "NanoId", RegexError<"NanoId">, StringError>;
|
|
850
|
-
export type NanoId = typeof NanoId.Type;
|
|
851
|
-
export type NanoIdError = typeof NanoId.Error;
|
|
975
|
+
export interface SimpleNameError extends TypeError<"SimpleName"> {
|
|
976
|
+
}
|
|
852
977
|
/**
|
|
853
978
|
* Trimmed string between 8 and 64 characters, branded as `SimplePassword`.
|
|
854
979
|
*
|
|
@@ -859,16 +984,37 @@ export type SimplePassword = typeof SimplePassword.Type;
|
|
|
859
984
|
export type SimplePasswordError = typeof SimplePassword.Error;
|
|
860
985
|
export declare const formatSimplePasswordError: (formatTypeError: TypeErrorFormatter<StringError | MinLengthError<8> | MaxLengthError<64> | TrimmedError>) => TypeErrorFormatter<SimplePasswordError>;
|
|
861
986
|
/**
|
|
862
|
-
*
|
|
987
|
+
* Globally unique identifier.
|
|
988
|
+
*
|
|
989
|
+
* **Evolu Id** is 16 random bytes from a cryptographically secure random
|
|
990
|
+
* generator, encoded as 22-character Base64Url string. This provides strong
|
|
991
|
+
* collision resistance for distributed ID generation.
|
|
992
|
+
*
|
|
993
|
+
* ### Design Rationale
|
|
994
|
+
*
|
|
995
|
+
* Why Evolu Id over alternatives:
|
|
863
996
|
*
|
|
864
|
-
*
|
|
865
|
-
*
|
|
997
|
+
* - **NanoID**: No standard binary serialization format, and uses only ~126 bits
|
|
998
|
+
* of entropy (21 characters from 64-symbol alphabet) compared to Evolu Id's
|
|
999
|
+
* 128 bits.
|
|
1000
|
+
* - **UUID (v4)**: String format is 36 characters (with hyphens) compared to
|
|
1001
|
+
* Evolu Id's 22 characters. While UUIDs can be stored as 16 bytes, their
|
|
1002
|
+
* standard string representation is verbose.
|
|
1003
|
+
* - **UUID v7**: Includes timestamp in the ID, which leaks information about when
|
|
1004
|
+
* data was created. This is a privacy concern for local-first applications
|
|
1005
|
+
* where creation time must remain private.
|
|
1006
|
+
*
|
|
1007
|
+
* Evolu Id provides 128 bits of entropy, compact string representation (22
|
|
1008
|
+
* characters), standard and native string serialization (Base64Url), and no
|
|
1009
|
+
* privacy leaks.
|
|
866
1010
|
*
|
|
867
1011
|
* @category String
|
|
868
1012
|
*/
|
|
869
|
-
export declare const Id: BrandType<Type<"String", string, string, StringError, string, StringError>, "Id",
|
|
1013
|
+
export declare const Id: BrandType<Type<"String", string, string, StringError, string, StringError>, "Id", IdError, StringError>;
|
|
870
1014
|
export type Id = typeof Id.Type;
|
|
871
|
-
export
|
|
1015
|
+
export interface IdError extends TypeError<"Id"> {
|
|
1016
|
+
}
|
|
1017
|
+
export declare const formatIdError: TypeErrorFormatter<IdError>;
|
|
872
1018
|
/**
|
|
873
1019
|
* Creates an {@link Id}.
|
|
874
1020
|
*
|
|
@@ -882,13 +1028,12 @@ export declare const idTypeValueLength = 21;
|
|
|
882
1028
|
* const todoId = createId<"Todo">(deps);
|
|
883
1029
|
* ```
|
|
884
1030
|
*/
|
|
885
|
-
export declare const createId: <B extends string = never>(deps:
|
|
1031
|
+
export declare const createId: <B extends string = never>(deps: RandomBytesDep) => [B] extends [never] ? Id : Id & Brand<B>;
|
|
886
1032
|
/**
|
|
887
1033
|
* Creates an {@link Id} from a string using SHA-256.
|
|
888
1034
|
*
|
|
889
|
-
*
|
|
890
|
-
*
|
|
891
|
-
* function to convert external IDs into valid Evolu IDs.
|
|
1035
|
+
* When integrating with external systems that use different ID formats, use
|
|
1036
|
+
* this function to convert external IDs into valid Evolu IDs.
|
|
892
1037
|
*
|
|
893
1038
|
* In Evolu's CRDT, the ID serves as the unique identifier for conflict
|
|
894
1039
|
* resolution across distributed clients. When multiple clients create records
|
|
@@ -909,15 +1054,17 @@ export declare const createId: <B extends string = never>(deps: NanoIdLibDep) =>
|
|
|
909
1054
|
* });
|
|
910
1055
|
* ```
|
|
911
1056
|
*
|
|
912
|
-
* **Important**: This transformation is one-way.
|
|
913
|
-
*
|
|
914
|
-
*
|
|
1057
|
+
* **Important**: This transformation is one-way. We cannot recover the original
|
|
1058
|
+
* external string from the generated {@link Id}. If we need to preserve the
|
|
1059
|
+
* original external ID, store it in a separate column.
|
|
915
1060
|
*
|
|
916
1061
|
* @category String
|
|
917
1062
|
*/
|
|
918
1063
|
export declare const createIdFromString: <B extends string = never>(value: string) => [B] extends [never] ? Id : Id & Brand<B>;
|
|
919
1064
|
/**
|
|
920
|
-
*
|
|
1065
|
+
* Creates a branded {@link Id} Type for a table's primary key.
|
|
1066
|
+
*
|
|
1067
|
+
* The table name becomes an additional brand for type safety.
|
|
921
1068
|
*
|
|
922
1069
|
* ### Example
|
|
923
1070
|
*
|
|
@@ -929,14 +1076,20 @@ export declare const createIdFromString: <B extends string = never>(value: strin
|
|
|
929
1076
|
*
|
|
930
1077
|
* @category String
|
|
931
1078
|
*/
|
|
932
|
-
export declare const id: <Table extends TypeName>(table: Table) =>
|
|
933
|
-
export interface
|
|
1079
|
+
export declare const id: <Table extends TypeName>(table: Table) => TableId<Table>;
|
|
1080
|
+
export interface TableId<Table extends TypeName> extends Type<"Id", string & Brand<"Id"> & Brand<Table>, string, TableIdError<Table>, string, StringError> {
|
|
934
1081
|
table: Table;
|
|
935
1082
|
}
|
|
936
|
-
export interface
|
|
1083
|
+
export interface TableIdError<Table extends TypeName = TypeName> extends TypeError<"TableId"> {
|
|
937
1084
|
readonly table: Table;
|
|
938
1085
|
}
|
|
939
|
-
export declare const
|
|
1086
|
+
export declare const formatTableIdError: TypeErrorFormatter<TableIdError<Capitalize<string>>>;
|
|
1087
|
+
/** Binary representation of an {@link Id}. */
|
|
1088
|
+
export declare const IdBytes: BrandType<BrandType<Type<"Uint8Array", Uint8Array<ArrayBufferLike>, Uint8Array<ArrayBufferLike>, Uint8ArrayError, Uint8Array<ArrayBufferLike>, Uint8ArrayError>, "Length16", LengthError<16>, Uint8ArrayError>, "IdBytes", BrandWithoutRefineError<"IdBytes", LengthError<16> | Uint8ArrayError>, never>;
|
|
1089
|
+
export type IdBytes = typeof IdBytes.Type;
|
|
1090
|
+
export declare const idBytesTypeValueLength: NonNegativeInt;
|
|
1091
|
+
export declare const idToIdBytes: (id: Id) => IdBytes;
|
|
1092
|
+
export declare const idBytesToId: (idBytes: IdBytes) => Id;
|
|
940
1093
|
/**
|
|
941
1094
|
* Positive number.
|
|
942
1095
|
*
|
|
@@ -1004,7 +1157,7 @@ export declare const formatNonNegativeError: TypeErrorFormatter<NonNegativeError
|
|
|
1004
1157
|
export declare const NonNegativeNumber: BrandType<Type<"Number", number, number, NumberError, number, NumberError>, "NonNegative", NonNegativeError, NumberError>;
|
|
1005
1158
|
export type NonNegativeNumber = typeof NonNegativeNumber.Type;
|
|
1006
1159
|
/** @category Number */
|
|
1007
|
-
export declare const PositiveNumber: BrandType<Type<"Brand", number & Brand<"NonNegative">, number, NonNegativeError, number, NumberError>, "Positive", PositiveError,
|
|
1160
|
+
export declare const PositiveNumber: BrandType<Type<"Brand", number & Brand<"NonNegative">, number, NonNegativeError, number, NumberError>, "Positive", PositiveError, NonNegativeError | NumberError>;
|
|
1008
1161
|
export type PositiveNumber = typeof PositiveNumber.Type;
|
|
1009
1162
|
/** @category Number */
|
|
1010
1163
|
export declare const NonPositiveNumber: BrandType<Type<"Number", number, number, NumberError, number, NumberError>, "NonPositive", NonPositiveError, NumberError>;
|
|
@@ -1035,16 +1188,18 @@ export declare const formatIntError: TypeErrorFormatter<IntError>;
|
|
|
1035
1188
|
export declare const Int: BrandType<Type<"Number", number, number, NumberError, number, NumberError>, "Int", IntError, NumberError>;
|
|
1036
1189
|
export type Int = typeof Int.Type;
|
|
1037
1190
|
/** @category Number */
|
|
1038
|
-
export declare const NonNegativeInt: BrandType<Type<"Brand", number & Brand<"Int">, number, IntError, number, NumberError>, "NonNegative", NonNegativeError,
|
|
1191
|
+
export declare const NonNegativeInt: BrandType<Type<"Brand", number & Brand<"Int">, number, IntError, number, NumberError>, "NonNegative", NonNegativeError, IntError | NumberError>;
|
|
1039
1192
|
export type NonNegativeInt = typeof NonNegativeInt.Type;
|
|
1040
1193
|
/** @category Number */
|
|
1041
|
-
export declare const PositiveInt: BrandType<Type<"Brand", number & Brand<"Int"> & Brand<"NonNegative">, number, NonNegativeError, number & Brand<"Int">,
|
|
1194
|
+
export declare const PositiveInt: BrandType<Type<"Brand", number & Brand<"Int"> & Brand<"NonNegative">, number, NonNegativeError, number & Brand<"Int">, IntError | NumberError>, "Positive", PositiveError, NonNegativeError | IntError | NumberError>;
|
|
1042
1195
|
export type PositiveInt = typeof PositiveInt.Type;
|
|
1196
|
+
/** Maximum safe positive integer value for practically infinite operations. */
|
|
1197
|
+
export declare const maxPositiveInt: number & Brand<"Int"> & Brand<"NonNegative"> & Brand<"Positive">;
|
|
1043
1198
|
/** @category Number */
|
|
1044
|
-
export declare const NonPositiveInt: BrandType<Type<"Brand", number & Brand<"Int">, number, IntError, number, NumberError>, "NonPositive", NonPositiveError,
|
|
1199
|
+
export declare const NonPositiveInt: BrandType<Type<"Brand", number & Brand<"Int">, number, IntError, number, NumberError>, "NonPositive", NonPositiveError, IntError | NumberError>;
|
|
1045
1200
|
export type NonPositiveInt = typeof NonPositiveInt.Type;
|
|
1046
1201
|
/** @category Number */
|
|
1047
|
-
export declare const NegativeInt: BrandType<Type<"Brand", number & Brand<"Int"> & Brand<"NonPositive">, number, NonPositiveError, number & Brand<"Int">,
|
|
1202
|
+
export declare const NegativeInt: BrandType<Type<"Brand", number & Brand<"Int"> & Brand<"NonPositive">, number, NonPositiveError, number & Brand<"Int">, IntError | NumberError>, "Negative", NegativeError, IntError | NumberError | NonPositiveError>;
|
|
1048
1203
|
export type NegativeInt = typeof NegativeInt.Type;
|
|
1049
1204
|
/**
|
|
1050
1205
|
* Number greater than a specified value.
|
|
@@ -1151,9 +1306,6 @@ export interface BetweenError<Min extends number = number, Max extends number =
|
|
|
1151
1306
|
readonly max: Max;
|
|
1152
1307
|
}
|
|
1153
1308
|
export declare const formatBetweenError: TypeErrorFormatter<BetweenError<number, number>>;
|
|
1154
|
-
/** @category Number */
|
|
1155
|
-
export declare const Between1And10: BrandType<Type<"Number", number, number, NumberError, number, NumberError>, "Between1-10", BetweenError<1, 10>, NumberError>;
|
|
1156
|
-
export type Between1And10 = typeof Between1And10.Type;
|
|
1157
1309
|
/**
|
|
1158
1310
|
* Literal {@link Type}.
|
|
1159
1311
|
*
|
|
@@ -1179,71 +1331,6 @@ export interface LiteralError<T extends Literal = Literal> extends TypeError<"Li
|
|
|
1179
1331
|
readonly expected: T;
|
|
1180
1332
|
}
|
|
1181
1333
|
export declare const formatLiteralError: TypeErrorFormatter<LiteralError<Literal>>;
|
|
1182
|
-
/**
|
|
1183
|
-
* {@link Type} that transforms values between `FromType` and `ToType`.
|
|
1184
|
-
*
|
|
1185
|
-
* - `fromParent`: Converts `FromType` to `ToType`, may fail.
|
|
1186
|
-
* - `toParent`: Converts `ToType` back to `FromType`, must not fail.
|
|
1187
|
-
*
|
|
1188
|
-
* ### Example
|
|
1189
|
-
*
|
|
1190
|
-
* // TODO: Examples
|
|
1191
|
-
*
|
|
1192
|
-
* @category Base Factories
|
|
1193
|
-
*/
|
|
1194
|
-
export declare const transform: <FromType extends AnyType, ToType extends AnyType, TransformError extends TypeError = never>(fromType: FromType, toType: ToType, fromParent: (parentValue: InferType<FromType>) => Result<InferType<ToType>, TransformError>, toParent: (value: InferType<ToType>) => InferType<FromType>) => TransformType<FromType, ToType, TransformError>;
|
|
1195
|
-
/**
|
|
1196
|
-
* TransformType extends {@link Type} with additional `fromType` and `toType`
|
|
1197
|
-
* properties for reflection.
|
|
1198
|
-
*/
|
|
1199
|
-
export interface TransformType<FromType extends AnyType, ToType extends AnyType, TransformError extends TypeError = never> extends Type<"Transform", InferType<ToType>, InferInput<FromType>, TransformError, InferType<FromType>, InferErrors<FromType>> {
|
|
1200
|
-
readonly fromType: FromType;
|
|
1201
|
-
readonly toType: ToType;
|
|
1202
|
-
readonly fromParent: (value: InferType<FromType>) => [TransformError] extends [never] ? Ok<InferType<ToType>> : Result<InferType<ToType>, TransformError>;
|
|
1203
|
-
}
|
|
1204
|
-
/**
|
|
1205
|
-
* Trims leading and trailing whitespace from a string.
|
|
1206
|
-
*
|
|
1207
|
-
* ### Example
|
|
1208
|
-
*
|
|
1209
|
-
* ```ts
|
|
1210
|
-
* expect(TrimString.from("a ")).toEqual(ok("a"));
|
|
1211
|
-
* expect(TrimString.fromParent("a ").value).toEqual("a");
|
|
1212
|
-
* ```
|
|
1213
|
-
*
|
|
1214
|
-
* @category String
|
|
1215
|
-
*/
|
|
1216
|
-
export declare const TrimString: TransformType<Type<"String", string, string, StringError, string, StringError>, BrandType<Type<"String", string, string, StringError, string, StringError>, "Trimmed", never, StringError>, never>;
|
|
1217
|
-
/**
|
|
1218
|
-
* Transforms a {@link Date} into a {@link DateIsoString} string and vice versa.
|
|
1219
|
-
*
|
|
1220
|
-
* ### Example
|
|
1221
|
-
*
|
|
1222
|
-
* ```ts
|
|
1223
|
-
* DateIso.from(new Date("2023-12-25T10:30:00.000Z")); // ok("2023-12-25T10:30:00.000Z")
|
|
1224
|
-
* DateIso.to("2023-12-25T10:30:00.000Z"); // Date object
|
|
1225
|
-
* DateIso.from(new Date("invalid")); // err({ type: "DateIsoString", value: "Invalid Date" })
|
|
1226
|
-
* ```
|
|
1227
|
-
*
|
|
1228
|
-
* @category String
|
|
1229
|
-
*/
|
|
1230
|
-
export declare const DateIso: TransformType<InstanceOfType<DateConstructor>, BrandType<Type<"String", string, string, StringError, string, StringError>, "DateIso", DateIsoStringError, StringError>, DateIsoStringError>;
|
|
1231
|
-
/**
|
|
1232
|
-
* Transforms a {@link NonEmptyTrimmedString} into a {@link FiniteNumber}.
|
|
1233
|
-
*
|
|
1234
|
-
* ### Example
|
|
1235
|
-
*
|
|
1236
|
-
* ```ts
|
|
1237
|
-
* NumberFromString.from("42"); // ok(42)
|
|
1238
|
-
* NumberFromString.from("abc"); // err({ type: "NumberFromString", value: "abc" })
|
|
1239
|
-
* ```
|
|
1240
|
-
*
|
|
1241
|
-
* @category Number
|
|
1242
|
-
*/
|
|
1243
|
-
export declare const NumberFromString: TransformType<BrandType<Type<"Brand", string & Brand<"Trimmed">, string, TrimmedError, string, StringError>, "MinLength1", MinLengthError<1>, StringError | TrimmedError>, BrandType<Type<"Number", number, number, NumberError, number, NumberError>, "Finite", FiniteError, NumberError>, NumberFromStringError>;
|
|
1244
|
-
export interface NumberFromStringError extends TypeError<"NumberFromString"> {
|
|
1245
|
-
}
|
|
1246
|
-
export declare const formatNumberFromStringError: TypeErrorFormatter<NumberFromStringError>;
|
|
1247
1334
|
/**
|
|
1248
1335
|
* Array of a specific {@link Type}.
|
|
1249
1336
|
*
|
|
@@ -1701,16 +1788,12 @@ export type Int64 = typeof Int64.Type;
|
|
|
1701
1788
|
export interface Int64Error extends TypeError<"Int64"> {
|
|
1702
1789
|
}
|
|
1703
1790
|
export declare const formatInt64Error: TypeErrorFormatter<Int64Error>;
|
|
1704
|
-
export declare const BigIntFromString: TransformType<Type<"String", string, string, StringError, string, StringError>, Type<"BigInt", bigint, bigint, BigIntError, bigint, BigIntError>, BigIntFromStringError>;
|
|
1705
|
-
export interface BigIntFromStringError extends TypeError<"BigIntFromString"> {
|
|
1706
|
-
}
|
|
1707
|
-
export declare const formatBigIntFromStringError: TypeErrorFormatter<BigIntFromStringError>;
|
|
1708
1791
|
/**
|
|
1709
1792
|
* Stringified {@link Int64}.
|
|
1710
1793
|
*
|
|
1711
|
-
* @category
|
|
1794
|
+
* @category String
|
|
1712
1795
|
*/
|
|
1713
|
-
export declare const Int64String: BrandType<Type<"
|
|
1796
|
+
export declare const Int64String: BrandType<BrandType<Type<"Brand", string & Brand<"Trimmed">, string, TrimmedError, string, StringError>, "MinLength1", MinLengthError<1>, StringError | TrimmedError>, "Int64", Int64StringError, StringError | TrimmedError | MinLengthError<1>>;
|
|
1714
1797
|
export type Int64String = typeof Int64String.Type;
|
|
1715
1798
|
export interface Int64StringError extends TypeError<"Int64String"> {
|
|
1716
1799
|
}
|
|
@@ -1745,42 +1828,63 @@ export declare const JsonArray: ArrayType<RecursiveType<UnionType<[Type<"String"
|
|
|
1745
1828
|
* @category Object
|
|
1746
1829
|
*/
|
|
1747
1830
|
export declare const JsonObject: RecordType<"String", string, string, StringError, string, StringError, RecursiveType<UnionType<[Type<"String", string, string, StringError, string, StringError>, BrandType<Type<"Number", number, number, NumberError, number, NumberError>, "Finite", FiniteError, NumberError>, Type<"Boolean", boolean, boolean, BooleanError, boolean, BooleanError>, Type<"Null", null, null, NullError, null, NullError>, ArrayType<Type<"Recursive", JsonValue, JsonValueInput, JsonValueError, JsonValueInput, JsonValueError>>, RecordType<"String", string, string, StringError, string, StringError, Type<"Recursive", JsonValue, JsonValueInput, JsonValueError, JsonValueInput, JsonValueError>>]>>>;
|
|
1831
|
+
export declare const parseJson: (value: string) => Result<JsonValue, JsonError>;
|
|
1748
1832
|
/**
|
|
1749
|
-
*
|
|
1750
|
-
* JsonValue back into a JSON string.
|
|
1833
|
+
* JSON-string {@link Type}.
|
|
1751
1834
|
*
|
|
1752
1835
|
* ### Example
|
|
1753
1836
|
*
|
|
1754
1837
|
* ```ts
|
|
1755
|
-
*
|
|
1756
|
-
*
|
|
1838
|
+
* const result = Json.from('{"key":"value"}'); // ok
|
|
1839
|
+
* const error = Json.from("invalid json"); // err
|
|
1757
1840
|
* ```
|
|
1758
1841
|
*
|
|
1759
1842
|
* @category String
|
|
1760
1843
|
*/
|
|
1761
|
-
export declare const
|
|
1762
|
-
export
|
|
1844
|
+
export declare const Json: BrandType<Type<"String", string, string, StringError, string, StringError>, "Json", JsonError, StringError>;
|
|
1845
|
+
export type Json = typeof Json.Type;
|
|
1846
|
+
export interface JsonError extends TypeError<"Json"> {
|
|
1763
1847
|
readonly message: string;
|
|
1764
1848
|
}
|
|
1765
|
-
export declare const
|
|
1849
|
+
export declare const formatJsonError: TypeErrorFormatter<JsonError>;
|
|
1850
|
+
export declare const jsonValueToJson: (value: JsonValue) => Json;
|
|
1851
|
+
export declare const jsonToJsonValue: (value: Json) => JsonValue;
|
|
1766
1852
|
/**
|
|
1767
|
-
* JSON
|
|
1853
|
+
* Creates a branded JSON string {@link Type} and type-safe conversion functions
|
|
1854
|
+
* for a given Type.
|
|
1855
|
+
*
|
|
1856
|
+
* This factory creates:
|
|
1857
|
+
*
|
|
1858
|
+
* 1. A branded string Type that validates JSON parsing and structural conformity
|
|
1859
|
+
* 2. A serialization function (Type → branded JSON string)
|
|
1860
|
+
* 3. A parsing function (branded JSON string → Type, skipping validation)
|
|
1861
|
+
*
|
|
1862
|
+
* Optimized for Evolu's SQLite workflow where we store typed JSON strings and
|
|
1863
|
+
* need type-safe conversions without double parsing.
|
|
1768
1864
|
*
|
|
1769
1865
|
* ### Example
|
|
1770
1866
|
*
|
|
1771
1867
|
* ```ts
|
|
1772
|
-
* const
|
|
1773
|
-
*
|
|
1774
|
-
*
|
|
1868
|
+
* const Person = object({
|
|
1869
|
+
* name: NonEmptyString100,
|
|
1870
|
+
* age: FiniteNumber,
|
|
1871
|
+
* });
|
|
1872
|
+
* type Person = typeof Person.Type;
|
|
1775
1873
|
*
|
|
1776
|
-
*
|
|
1874
|
+
* const [PersonJson, personToPersonJson, personJsonToPerson] = json(
|
|
1875
|
+
* Person,
|
|
1876
|
+
* "PersonJson",
|
|
1877
|
+
* );
|
|
1878
|
+
* // string & Brand<"PersonJson">
|
|
1879
|
+
* type PersonJson = typeof PersonJson.Type;
|
|
1880
|
+
*
|
|
1881
|
+
* // Usage:
|
|
1882
|
+
* const person: Person = { name: "Alice", age: 30 };
|
|
1883
|
+
* const jsonString = personToPersonJson(person); // PersonJson
|
|
1884
|
+
* const backToPerson = personJsonToPerson(jsonString); // Person
|
|
1885
|
+
* ```
|
|
1777
1886
|
*/
|
|
1778
|
-
export declare const
|
|
1779
|
-
export type Json = typeof Json.Type;
|
|
1780
|
-
export interface JsonError extends TypeError<"Json"> {
|
|
1781
|
-
readonly message: string;
|
|
1782
|
-
}
|
|
1783
|
-
export declare const formatJsonError: TypeErrorFormatter<JsonError>;
|
|
1887
|
+
export declare const json: <T extends AnyType, Name extends TypeName>(type: T, name: Name) => [BrandType<typeof String, Name, JsonError | InferErrors<T>, StringError>, (value: InferType<T>) => InferType<BrandType<typeof String, Name, JsonError | InferErrors<T>, StringError>>, (value: InferType<BrandType<typeof String, Name, JsonError | InferErrors<T>, StringError>>) => InferType<T>];
|
|
1784
1888
|
/**
|
|
1785
1889
|
* Optional {@link Type}.
|
|
1786
1890
|
*
|
|
@@ -1811,7 +1915,7 @@ export declare const isOptionalType: (x: unknown) => x is OptionalType<any>;
|
|
|
1811
1915
|
/**
|
|
1812
1916
|
* Creates a partial object type where all properties are optional.
|
|
1813
1917
|
*
|
|
1814
|
-
* This is useful when
|
|
1918
|
+
* This is useful when we want to validate an object in which none of the keys
|
|
1815
1919
|
* are required, but if they are present they must conform to their
|
|
1816
1920
|
* corresponding Types.
|
|
1817
1921
|
*
|
|
@@ -1857,36 +1961,18 @@ export type NullTypeInMembers<Members extends [AnyType, ...Array<AnyType>]> = Me
|
|
|
1857
1961
|
* @category Object
|
|
1858
1962
|
*/
|
|
1859
1963
|
export declare function omit<T extends ObjectType<any>, Keys extends keyof T["props"]>(objectType: T, ...keys: ReadonlyArray<Keys>): ObjectType<Omit<T["props"], Keys>>;
|
|
1964
|
+
export declare const maxMutationSize = 655360;
|
|
1860
1965
|
/**
|
|
1861
|
-
*
|
|
1862
|
-
*
|
|
1863
|
-
*
|
|
1864
|
-
*
|
|
1865
|
-
* ### Example
|
|
1866
|
-
*
|
|
1867
|
-
* ```ts
|
|
1868
|
-
* const Person = object({
|
|
1869
|
-
* name: NonEmptyString50,
|
|
1870
|
-
* age: FiniteNumber,
|
|
1871
|
-
* });
|
|
1872
|
-
* type Person = typeof Person.Type;
|
|
1873
|
-
*
|
|
1874
|
-
* const PersonJson = json(Person, "PersonJson");
|
|
1875
|
-
* // string & Brand<"PersonJson">
|
|
1876
|
-
* type PersonJson = typeof PersonJson.Type;
|
|
1877
|
-
*
|
|
1878
|
-
* // Person -> string & Brand<"PersonJson">
|
|
1879
|
-
* const personJson = PersonJson.from({ name: "Alice", age: 30 });
|
|
1880
|
-
* expect(personJson).toEqual(ok('{"name":"Alice","age":30}'));
|
|
1881
|
-
*
|
|
1882
|
-
* // string & Brand<"PersonJson"> -> Person
|
|
1883
|
-
* const person = PersonJson.to(personJson);
|
|
1884
|
-
*
|
|
1885
|
-
* // serialize/parse any JSON value
|
|
1886
|
-
* const AnyJson = json(JsonValue, "AnyJson");
|
|
1887
|
-
* ```
|
|
1966
|
+
* Evolu has to limit the maximum mutation size. Otherwise, sync couldn't use
|
|
1967
|
+
* the `maxProtocolMessageRangesSize`. The max size is 640KB in bytes, measured
|
|
1968
|
+
* via MessagePack. Evolu Protocol DbChange will be smaller thanks to various
|
|
1969
|
+
* optimizations.
|
|
1888
1970
|
*/
|
|
1889
|
-
export declare const
|
|
1971
|
+
export declare const validMutationSize: <T extends AnyType>(type: T) => BrandType<T, "ValidMutationSize", ValidMutationSizeError, InferErrors<T>>;
|
|
1972
|
+
export interface ValidMutationSizeError extends TypeError<"ValidMutationSize"> {
|
|
1973
|
+
}
|
|
1974
|
+
export declare const formatValidMutationSizeError: TypeErrorFormatter<ValidMutationSizeError>;
|
|
1975
|
+
export type ValidMutationSize<Props extends Record<string, AnyType>> = BrandType<ObjectType<Props>, "ValidMutationSize", ValidMutationSizeError, InferErrors<ObjectType<Props>>>;
|
|
1890
1976
|
/**
|
|
1891
1977
|
* Union of all `TypeError`s defined in the `Type.ts` file, including base type
|
|
1892
1978
|
* errors (e.g., `StringError`, `NumberError`), composite type errors
|
|
@@ -1900,72 +1986,76 @@ export declare const json: <T extends AnyType, Name extends TypeName>(type: T, n
|
|
|
1900
1986
|
*
|
|
1901
1987
|
* @category Utilities
|
|
1902
1988
|
*/
|
|
1903
|
-
export type TypeErrors<ExtraErrors extends TypeError = never> = StringError | NumberError | BigIntError | BooleanError | UndefinedError | NullError | FunctionError | Uint8ArrayError | InstanceOfError | EvoluTypeError | CurrencyCodeError |
|
|
1989
|
+
export type TypeErrors<ExtraErrors extends TypeError = never> = StringError | NumberError | BigIntError | BooleanError | UndefinedError | NullError | FunctionError | Uint8ArrayError | InstanceOfError | EvoluTypeError | CurrencyCodeError | DateIsoError | TrimmedError | MinLengthError | MaxLengthError | LengthError | MnemonicError | RegexError | SimplePasswordError | IdError | TableIdError | PositiveError | NegativeError | NonPositiveError | NonNegativeError | IntError | GreaterThanError | LessThanError | GreaterThanOrEqualToError | LessThanOrEqualToError | NonNaNError | FiniteError | MultipleOfError | BetweenError | LiteralError | Int64Error | Int64StringError | JsonError | ValidMutationSizeError | ExtraErrors | ArrayError<TypeErrors<ExtraErrors>> | RecordError<TypeErrors<ExtraErrors>, TypeErrors<ExtraErrors>> | ObjectError<Record<string, TypeErrors<ExtraErrors>>> | ObjectWithRecordError<Record<string, TypeErrors<ExtraErrors>>, TypeErrors<ExtraErrors>, TypeErrors<ExtraErrors>> | UnionError<TypeErrors<ExtraErrors>> | TupleError<TypeErrors<ExtraErrors>>;
|
|
1904
1990
|
/**
|
|
1905
|
-
*
|
|
1906
|
-
* {@link TypeErrors} and custom errors. It also lets us override the default
|
|
1907
|
-
* formatting for specific errors.
|
|
1991
|
+
* Formats Evolu Type errors into user-friendly messages.
|
|
1908
1992
|
*
|
|
1909
|
-
*
|
|
1910
|
-
*
|
|
1993
|
+
* Evolu Type typed errors ensure every error type must have a formatter.
|
|
1994
|
+
* TypeScript enforces this at compile-time, preventing unhandled validation
|
|
1995
|
+
* errors from reaching users.
|
|
1911
1996
|
*
|
|
1912
|
-
*
|
|
1997
|
+
* The `createFormatTypeError` function handles both built-in {@link TypeErrors}
|
|
1998
|
+
* and custom errors, and lets us override default formatting for specific
|
|
1999
|
+
* errors.
|
|
2000
|
+
*
|
|
2001
|
+
* ### Example
|
|
1913
2002
|
*
|
|
1914
2003
|
* ```ts
|
|
1915
|
-
* const
|
|
1916
|
-
*
|
|
1917
|
-
*
|
|
2004
|
+
* const formatTypeError = createFormatTypeError<
|
|
2005
|
+
* MinLengthError | MaxLengthError
|
|
2006
|
+
* >((error): string => {
|
|
2007
|
+
* switch (error.type) {
|
|
2008
|
+
* case "MinLength":
|
|
2009
|
+
* return `Text must be at least ${error.min} character${error.min === 1 ? "" : "s"} long`;
|
|
2010
|
+
* case "MaxLength":
|
|
2011
|
+
* return `Text is too long (maximum ${error.max} characters)`;
|
|
2012
|
+
* }
|
|
2013
|
+
* });
|
|
1918
2014
|
* ```
|
|
1919
2015
|
*
|
|
1920
|
-
*
|
|
2016
|
+
* Alternatively, write a custom formatter from scratch without using
|
|
2017
|
+
* `createFormatTypeError`. This gives us full control over error formatting:
|
|
1921
2018
|
*
|
|
1922
2019
|
* ```ts
|
|
1923
|
-
*
|
|
1924
|
-
*
|
|
2020
|
+
* const Person = object({
|
|
2021
|
+
* name: NonEmptyTrimmedString100,
|
|
2022
|
+
* age: optional(PositiveInt),
|
|
2023
|
+
* });
|
|
2024
|
+
*
|
|
2025
|
+
* // Define only the errors actually used by Person Type
|
|
2026
|
+
* type PersonErrors =
|
|
1925
2027
|
* | StringError
|
|
1926
|
-
* | MinLengthError
|
|
1927
2028
|
* | MaxLengthError
|
|
1928
|
-
* |
|
|
1929
|
-
* | IdError
|
|
2029
|
+
* | MinLengthError
|
|
1930
2030
|
* | TrimmedError
|
|
1931
|
-
* |
|
|
1932
|
-
* |
|
|
1933
|
-
*
|
|
1934
|
-
* |
|
|
1935
|
-
* |
|
|
1936
|
-
*
|
|
1937
|
-
* const formatTypeError: TypeErrorFormatter<
|
|
1938
|
-
* // In the real code, we would use the createTypeErrorFormatter helper
|
|
1939
|
-
* // that safely stringifies error value.
|
|
2031
|
+
* | PositiveError
|
|
2032
|
+
* | NonNegativeError
|
|
2033
|
+
* | IntError
|
|
2034
|
+
* | NumberError
|
|
2035
|
+
* | ObjectError<Record<string, PersonErrors>>;
|
|
2036
|
+
*
|
|
2037
|
+
* const formatTypeError: TypeErrorFormatter<PersonErrors> = (error) => {
|
|
1940
2038
|
* switch (error.type) {
|
|
1941
|
-
* case "Id":
|
|
1942
|
-
* return `Invalid Id on table: ${error.table}.`;
|
|
1943
|
-
* case "MaxLength":
|
|
1944
|
-
* return `Max length is ${error.max}.`;
|
|
1945
|
-
* case "MinLength":
|
|
1946
|
-
* return `Min length is ${error.min}.`;
|
|
1947
|
-
* case "Mnemonic":
|
|
1948
|
-
* return `Invalid mnemonic: ${String(error.value)}`;
|
|
1949
|
-
* case "Null":
|
|
1950
|
-
* return `Not null`;
|
|
1951
2039
|
* case "String":
|
|
1952
|
-
* // We can reuse existing formatter.
|
|
1953
2040
|
* return formatStringError(error);
|
|
2041
|
+
* case "Number":
|
|
2042
|
+
* return "Must be a number";
|
|
2043
|
+
* case "MinLength":
|
|
2044
|
+
* return `Must be at least ${error.min} characters`;
|
|
2045
|
+
* case "MaxLength":
|
|
2046
|
+
* return `Cannot exceed ${error.max} characters`;
|
|
1954
2047
|
* case "Trimmed":
|
|
1955
|
-
* return "
|
|
1956
|
-
* case "
|
|
1957
|
-
* return "
|
|
1958
|
-
* case "
|
|
1959
|
-
* return
|
|
1960
|
-
*
|
|
1961
|
-
*
|
|
1962
|
-
* return `Union errors: ${error.errors.map(formatTypeError).join(", ")}`;
|
|
2048
|
+
* return "Cannot have leading or trailing spaces";
|
|
2049
|
+
* case "Positive":
|
|
2050
|
+
* return "Must be a positive number";
|
|
2051
|
+
* case "NonNegative":
|
|
2052
|
+
* return "Must be zero or positive";
|
|
2053
|
+
* case "Int":
|
|
2054
|
+
* return "Must be an integer";
|
|
1963
2055
|
* case "Object": {
|
|
1964
|
-
* if (
|
|
1965
|
-
*
|
|
1966
|
-
*
|
|
1967
|
-
* )
|
|
1968
|
-
* return "A developer made an error, this should not happen.";
|
|
2056
|
+
* if (error.reason.kind === "NotObject") return "Must be an object";
|
|
2057
|
+
* if (error.reason.kind === "ExtraKeys")
|
|
2058
|
+
* return "Contains unexpected fields";
|
|
1969
2059
|
* const firstError = Object.values(error.reason.errors).find(
|
|
1970
2060
|
* (e) => e !== undefined,
|
|
1971
2061
|
* )!;
|