@evolu/common 7.4.0 → 8.0.0-next.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 +4 -61
- package/dist/src/Array.d.ts +343 -102
- package/dist/src/Array.d.ts.map +1 -1
- package/dist/src/Array.js +181 -85
- package/dist/src/Assert.d.ts +57 -11
- package/dist/src/Assert.d.ts.map +1 -1
- package/dist/src/Assert.js +47 -11
- package/dist/src/BigInt.d.ts +6 -1
- package/dist/src/BigInt.d.ts.map +1 -1
- package/dist/src/BigInt.js +5 -0
- package/dist/src/Brand.d.ts +40 -12
- package/dist/src/Brand.d.ts.map +1 -1
- package/dist/src/Brand.js +5 -0
- package/dist/src/Buffer.d.ts +6 -1
- package/dist/src/Buffer.d.ts.map +1 -1
- package/dist/src/Buffer.js +7 -2
- package/dist/src/Cache.d.ts +10 -2
- package/dist/src/Cache.d.ts.map +1 -1
- package/dist/src/Cache.js +6 -0
- package/dist/src/Callbacks.d.ts +10 -7
- package/dist/src/Callbacks.d.ts.map +1 -1
- package/dist/src/Callbacks.js +23 -13
- package/dist/src/Console.d.ts +361 -69
- package/dist/src/Console.d.ts.map +1 -1
- package/dist/src/Console.js +217 -117
- package/dist/src/Crypto.d.ts +70 -21
- package/dist/src/Crypto.d.ts.map +1 -1
- package/dist/src/Crypto.js +72 -27
- package/dist/src/Eq.d.ts +22 -2
- package/dist/src/Eq.d.ts.map +1 -1
- package/dist/src/Eq.js +21 -1
- package/dist/src/Error.d.ts +23 -12
- package/dist/src/Error.d.ts.map +1 -1
- package/dist/src/Error.js +27 -11
- package/dist/src/Function.d.ts +128 -56
- package/dist/src/Function.d.ts.map +1 -1
- package/dist/src/Function.js +118 -14
- package/dist/src/Identicon.d.ts +5 -0
- package/dist/src/Identicon.d.ts.map +1 -1
- package/dist/src/Identicon.js +6 -1
- package/dist/src/Lookup.d.ts +160 -0
- package/dist/src/Lookup.d.ts.map +1 -0
- package/dist/src/Lookup.js +192 -0
- package/dist/src/Microtask.d.ts +21 -0
- package/dist/src/Microtask.d.ts.map +1 -0
- package/dist/src/Microtask.js +37 -0
- package/dist/src/Number.d.ts +18 -4
- package/dist/src/Number.d.ts.map +1 -1
- package/dist/src/Number.js +23 -1
- package/dist/src/Object.d.ts +110 -5
- package/dist/src/Object.d.ts.map +1 -1
- package/dist/src/Object.js +108 -5
- package/dist/src/Option.d.ts +58 -0
- package/dist/src/Option.d.ts.map +1 -0
- package/dist/src/Option.js +43 -0
- package/dist/src/Order.d.ts +5 -0
- package/dist/src/Order.d.ts.map +1 -1
- package/dist/src/Order.js +8 -3
- package/dist/src/Platform.d.ts +36 -2
- package/dist/src/Platform.d.ts.map +1 -1
- package/dist/src/Platform.js +10 -6
- package/dist/src/Polyfills.d.ts +27 -0
- package/dist/src/Polyfills.d.ts.map +1 -0
- package/dist/src/Polyfills.js +299 -0
- package/dist/src/Random.d.ts +18 -7
- package/dist/src/Random.d.ts.map +1 -1
- package/dist/src/Random.js +9 -7
- package/dist/src/Redacted.d.ts +7 -4
- package/dist/src/Redacted.d.ts.map +1 -1
- package/dist/src/Redacted.js +5 -0
- package/dist/src/Ref.d.ts +31 -16
- package/dist/src/Ref.d.ts.map +1 -1
- package/dist/src/Ref.js +35 -7
- package/dist/src/RefCount.d.ts +62 -0
- package/dist/src/RefCount.d.ts.map +1 -0
- package/dist/src/RefCount.js +83 -0
- package/dist/src/Relation.d.ts +84 -29
- package/dist/src/Relation.d.ts.map +1 -1
- package/dist/src/Relation.js +83 -105
- package/dist/src/Resource.d.ts +263 -0
- package/dist/src/Resource.d.ts.map +1 -0
- package/dist/src/Resource.js +389 -0
- package/dist/src/Result.d.ts +390 -374
- package/dist/src/Result.d.ts.map +1 -1
- package/dist/src/Result.js +142 -70
- package/dist/src/Schedule.d.ts +953 -0
- package/dist/src/Schedule.d.ts.map +1 -0
- package/dist/src/Schedule.js +1199 -0
- package/dist/src/Set.d.ts +181 -0
- package/dist/src/Set.d.ts.map +1 -0
- package/dist/src/Set.js +137 -0
- package/dist/src/Skiplist.d.ts +6 -1
- package/dist/src/Skiplist.d.ts.map +1 -1
- package/dist/src/Skiplist.js +5 -0
- package/dist/src/Sqlite.d.ts +160 -60
- package/dist/src/Sqlite.d.ts.map +1 -1
- package/dist/src/Sqlite.js +290 -190
- package/dist/src/Store.d.ts +36 -28
- package/dist/src/Store.d.ts.map +1 -1
- package/dist/src/Store.js +55 -15
- package/dist/src/String.d.ts +5 -0
- package/dist/src/String.d.ts.map +1 -1
- package/dist/src/String.js +5 -0
- package/dist/src/Task.d.ts +2263 -423
- package/dist/src/Task.d.ts.map +1 -1
- package/dist/src/Task.js +1488 -348
- package/dist/src/Test.d.ts +122 -0
- package/dist/src/Test.d.ts.map +1 -0
- package/dist/src/Test.js +66 -0
- package/dist/src/Time.d.ts +201 -48
- package/dist/src/Time.d.ts.map +1 -1
- package/dist/src/Time.js +190 -86
- package/dist/src/Tracer.d.ts +48 -0
- package/dist/src/Tracer.d.ts.map +1 -0
- package/dist/src/Tracer.js +6 -0
- package/dist/src/Type.d.ts +582 -209
- package/dist/src/Type.d.ts.map +1 -1
- package/dist/src/Type.js +362 -240
- package/dist/src/Types.d.ts +160 -6
- package/dist/src/Types.d.ts.map +1 -1
- package/dist/src/Types.js +22 -2
- package/dist/src/WebSocket.d.ts +113 -58
- package/dist/src/WebSocket.d.ts.map +1 -1
- package/dist/src/WebSocket.js +210 -118
- package/dist/src/Worker.d.ts +245 -60
- package/dist/src/Worker.d.ts.map +1 -1
- package/dist/src/Worker.js +220 -64
- package/dist/src/index.d.ts +25 -3
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +19 -3
- package/dist/src/local-first/Db.d.ts +24 -213
- package/dist/src/local-first/Db.d.ts.map +1 -1
- package/dist/src/local-first/Db.js +622 -293
- package/dist/src/local-first/Error.d.ts +12 -0
- package/dist/src/local-first/Error.d.ts.map +1 -0
- package/dist/src/local-first/Error.js +6 -0
- package/dist/src/local-first/Evolu.d.ts +330 -285
- package/dist/src/local-first/Evolu.d.ts.map +1 -1
- package/dist/src/local-first/Evolu.js +472 -402
- package/dist/src/local-first/LocalAuth.d.ts +10 -10
- package/dist/src/local-first/LocalAuth.d.ts.map +1 -1
- package/dist/src/local-first/LocalAuth.js +6 -1
- package/dist/src/local-first/Owner.d.ts +70 -27
- package/dist/src/local-first/Owner.d.ts.map +1 -1
- package/dist/src/local-first/Owner.js +27 -14
- package/dist/src/local-first/Protocol.d.ts +58 -50
- package/dist/src/local-first/Protocol.d.ts.map +1 -1
- package/dist/src/local-first/Protocol.js +253 -155
- package/dist/src/local-first/Query.d.ts +133 -43
- package/dist/src/local-first/Query.d.ts.map +1 -1
- package/dist/src/local-first/Query.js +139 -90
- package/dist/src/local-first/Relay.d.ts +18 -38
- package/dist/src/local-first/Relay.d.ts.map +1 -1
- package/dist/src/local-first/Relay.js +59 -171
- package/dist/src/local-first/Schema.d.ts +139 -144
- package/dist/src/local-first/Schema.d.ts.map +1 -1
- package/dist/src/local-first/Schema.js +78 -163
- package/dist/src/local-first/Shared.d.ts +125 -0
- package/dist/src/local-first/Shared.d.ts.map +1 -0
- package/dist/src/local-first/Shared.js +569 -0
- package/dist/src/local-first/Storage.d.ts +50 -53
- package/dist/src/local-first/Storage.d.ts.map +1 -1
- package/dist/src/local-first/Storage.js +121 -173
- package/dist/src/local-first/Timestamp.d.ts +28 -35
- package/dist/src/local-first/Timestamp.d.ts.map +1 -1
- package/dist/src/local-first/Timestamp.js +24 -25
- package/dist/src/local-first/index.d.ts +2 -15
- package/dist/src/local-first/index.d.ts.map +1 -1
- package/dist/src/local-first/index.js +2 -15
- package/package.json +36 -26
- package/src/Array.ts +467 -106
- package/src/Assert.ts +87 -12
- package/src/BigInt.ts +7 -1
- package/src/Brand.ts +41 -12
- package/src/Buffer.ts +10 -4
- package/src/Cache.ts +11 -2
- package/src/Callbacks.ts +33 -23
- package/src/Console.ts +567 -178
- package/src/Crypto.ts +111 -62
- package/src/Eq.ts +30 -3
- package/src/Error.ts +50 -34
- package/src/Function.ts +140 -68
- package/src/Identicon.ts +7 -1
- package/src/Lookup.ts +415 -0
- package/src/Microtask.ts +58 -0
- package/src/Number.ts +40 -7
- package/src/Object.ts +155 -16
- package/src/Option.ts +74 -0
- package/src/Order.ts +11 -3
- package/src/Platform.ts +43 -7
- package/src/Polyfills.ts +465 -0
- package/src/Random.ts +25 -11
- package/src/Redacted.ts +8 -4
- package/src/Ref.ts +72 -21
- package/src/RefCount.ts +170 -0
- package/src/Relation.ts +188 -136
- package/src/Resource.ts +864 -0
- package/src/Result.ts +548 -381
- package/src/Schedule.ts +1471 -0
- package/src/Set.ts +247 -0
- package/src/Skiplist.ts +7 -1
- package/src/Sqlite.ts +409 -304
- package/src/Store.ts +94 -48
- package/src/String.ts +6 -0
- package/src/Task.ts +3685 -740
- package/src/Test.ts +162 -0
- package/src/Time.ts +348 -145
- package/src/Tracer.ts +54 -0
- package/src/Type.ts +1064 -630
- package/src/Types.ts +202 -7
- package/src/WebSocket.ts +311 -178
- package/src/Worker.ts +527 -147
- package/src/index.ts +74 -3
- package/src/local-first/Db.ts +871 -597
- package/src/local-first/Error.ts +17 -0
- package/src/local-first/Evolu.ts +884 -823
- package/src/local-first/LocalAuth.ts +10 -10
- package/src/local-first/Owner.ts +94 -42
- package/src/local-first/Protocol.ts +440 -303
- package/src/local-first/Query.ts +243 -194
- package/src/local-first/Relay.ts +91 -252
- package/src/local-first/Schema.ts +284 -394
- package/src/local-first/Shared.ts +932 -0
- package/src/local-first/Storage.ts +209 -282
- package/src/local-first/Timestamp.ts +38 -45
- package/src/local-first/index.ts +2 -16
- package/LICENSE +0 -21
- package/dist/src/Instances.d.ts +0 -34
- package/dist/src/Instances.d.ts.map +0 -1
- package/dist/src/Instances.js +0 -44
- package/dist/src/Resources.d.ts +0 -118
- package/dist/src/Resources.d.ts.map +0 -1
- package/dist/src/Resources.js +0 -197
- package/dist/src/local-first/Platform.d.ts +0 -25
- package/dist/src/local-first/Platform.d.ts.map +0 -1
- package/dist/src/local-first/Platform.js +0 -1
- package/dist/src/local-first/Public.d.ts +0 -22
- package/dist/src/local-first/Public.d.ts.map +0 -1
- package/dist/src/local-first/Public.js +0 -15
- package/dist/src/local-first/PublicKysely.d.ts +0 -148
- package/dist/src/local-first/PublicKysely.d.ts.map +0 -1
- package/dist/src/local-first/PublicKysely.js +0 -184
- package/dist/src/local-first/Sync.d.ts +0 -112
- package/dist/src/local-first/Sync.d.ts.map +0 -1
- package/dist/src/local-first/Sync.js +0 -529
- package/src/Instances.ts +0 -90
- package/src/Resources.ts +0 -367
- package/src/local-first/Platform.ts +0 -27
- package/src/local-first/Public.ts +0 -42
- package/src/local-first/PublicKysely.ts +0 -239
- package/src/local-first/Sync.ts +0 -960
package/dist/src/Type.js
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime type validation, parsing, and branded types.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
1
6
|
import { utf8ToBytes } from "@noble/ciphers/utils.js";
|
|
2
7
|
import { sha256 } from "@noble/hashes/sha2.js";
|
|
3
8
|
import * as bip39 from "@scure/bip39";
|
|
4
9
|
import { wordlist } from "@scure/bip39/wordlists/english.js";
|
|
5
|
-
import {
|
|
6
|
-
import { isPlainObject } from "./Object.js";
|
|
10
|
+
import { exhaustiveCheck } from "./Function.js";
|
|
11
|
+
import { isFunction, isPlainObject } from "./Object.js";
|
|
7
12
|
import { hasNodeBuffer } from "./Platform.js";
|
|
8
13
|
import { err, getOrNull, getOrThrow, ok, trySync } from "./Result.js";
|
|
9
14
|
import { safelyStringifyUnknownValue } from "./String.js";
|
|
@@ -11,7 +16,7 @@ const EvoluTypeSymbol = Symbol("evolu.Type");
|
|
|
11
16
|
/**
|
|
12
17
|
* Checks if the given value is an {@link Type}.
|
|
13
18
|
*
|
|
14
|
-
* @
|
|
19
|
+
* @group Utilities
|
|
15
20
|
*/
|
|
16
21
|
export const isType = (value) => typeof value === "object" && value !== null && EvoluTypeSymbol in value;
|
|
17
22
|
const createType = (name, definition) => ({
|
|
@@ -36,9 +41,8 @@ const createType = (name, definition) => ({
|
|
|
36
41
|
if (result.ok) {
|
|
37
42
|
return { value: result.value };
|
|
38
43
|
}
|
|
39
|
-
cachedStandardSchemaFormatTypeError ??= createFormatTypeError();
|
|
40
44
|
return {
|
|
41
|
-
issues: typeErrorToStandardSchemaIssues(result.error
|
|
45
|
+
issues: typeErrorToStandardSchemaIssues(result.error),
|
|
42
46
|
};
|
|
43
47
|
},
|
|
44
48
|
types: {
|
|
@@ -61,7 +65,7 @@ const createType = (name, definition) => ({
|
|
|
61
65
|
* );
|
|
62
66
|
* ```
|
|
63
67
|
*
|
|
64
|
-
* @
|
|
68
|
+
* @group Utilities
|
|
65
69
|
*/
|
|
66
70
|
export const createTypeErrorFormatter = (format) => (error) => format({ ...error, value: safelyStringifyUnknownValue(error.value) });
|
|
67
71
|
/**
|
|
@@ -85,7 +89,7 @@ export const createTypeErrorFormatter = (format) => (error) => format({ ...error
|
|
|
85
89
|
* );
|
|
86
90
|
* ```
|
|
87
91
|
*
|
|
88
|
-
* @
|
|
92
|
+
* @group Base factories
|
|
89
93
|
*/
|
|
90
94
|
export const base = (name, fromUnknown) => createType(name, {
|
|
91
95
|
fromUnknown,
|
|
@@ -104,52 +108,60 @@ export const base = (name, fromUnknown) => createType(name, {
|
|
|
104
108
|
* createBaseTypeErrorFormatter<StringError>();
|
|
105
109
|
* ```
|
|
106
110
|
*
|
|
107
|
-
* @
|
|
111
|
+
* @group Utilities
|
|
108
112
|
*/
|
|
109
113
|
export const createBaseTypeErrorFormatter = () => createTypeErrorFormatter((error) => `A value ${error.value} is not a ${error.type.toLowerCase()}.`);
|
|
110
|
-
/** @
|
|
111
|
-
export const Unknown = base("Unknown", ok);
|
|
114
|
+
/** @group Base Types */
|
|
115
|
+
export const Unknown = /*#__PURE__*/ base("Unknown", ok);
|
|
112
116
|
/**
|
|
113
|
-
* @
|
|
114
|
-
* @
|
|
117
|
+
* @group Base Types
|
|
118
|
+
* @group String
|
|
115
119
|
*/
|
|
116
|
-
export const String = base("String", (value) => typeof value === "string"
|
|
120
|
+
export const String = /*#__PURE__*/ base("String", (value) => typeof value === "string"
|
|
117
121
|
? ok(value)
|
|
118
122
|
: err({ type: "String", value }));
|
|
119
|
-
export const formatStringError =
|
|
120
|
-
|
|
121
|
-
|
|
123
|
+
export const formatStringError =
|
|
124
|
+
/*#__PURE__*/ createBaseTypeErrorFormatter();
|
|
125
|
+
/** @group Base Types */
|
|
126
|
+
export const Number = /*#__PURE__*/ base("Number", (value) => typeof value === "number"
|
|
122
127
|
? ok(value)
|
|
123
128
|
: err({ type: "Number", value }));
|
|
124
|
-
export const formatNumberError =
|
|
125
|
-
|
|
126
|
-
|
|
129
|
+
export const formatNumberError =
|
|
130
|
+
/*#__PURE__*/ createBaseTypeErrorFormatter();
|
|
131
|
+
/** @group Base Types */
|
|
132
|
+
export const BigInt = /*#__PURE__*/ base("BigInt", (value) => typeof value === "bigint"
|
|
127
133
|
? ok(value)
|
|
128
134
|
: err({ type: "BigInt", value }));
|
|
129
|
-
export const formatBigIntError =
|
|
130
|
-
|
|
131
|
-
|
|
135
|
+
export const formatBigIntError =
|
|
136
|
+
/*#__PURE__*/ createBaseTypeErrorFormatter();
|
|
137
|
+
/** @group Base Types */
|
|
138
|
+
export const Boolean = /*#__PURE__*/ base("Boolean", (value) => typeof value === "boolean"
|
|
132
139
|
? ok(value)
|
|
133
140
|
: err({ type: "Boolean", value }));
|
|
134
|
-
export const formatBooleanError =
|
|
135
|
-
|
|
136
|
-
|
|
141
|
+
export const formatBooleanError =
|
|
142
|
+
/*#__PURE__*/ createBaseTypeErrorFormatter();
|
|
143
|
+
/** @group Base Types */
|
|
144
|
+
export const Undefined = /*#__PURE__*/ base("Undefined", (value) => value === undefined
|
|
137
145
|
? ok(value)
|
|
138
146
|
: err({ type: "Undefined", value }));
|
|
139
|
-
export const formatUndefinedError =
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
export const
|
|
143
|
-
|
|
144
|
-
|
|
147
|
+
export const formatUndefinedError =
|
|
148
|
+
/*#__PURE__*/ createBaseTypeErrorFormatter();
|
|
149
|
+
/** @group Base Types */
|
|
150
|
+
export const Null = /*#__PURE__*/ base("Null", (value) => value === null ? ok(value) : err({ type: "Null", value }));
|
|
151
|
+
export const formatNullError =
|
|
152
|
+
/*#__PURE__*/ createBaseTypeErrorFormatter();
|
|
153
|
+
/** @group Base Types */
|
|
154
|
+
export const Function = /*#__PURE__*/ base("Function", (value) => isFunction(value)
|
|
145
155
|
? ok(value)
|
|
146
156
|
: err({ type: "Function", value }));
|
|
147
|
-
export const formatFunctionError =
|
|
148
|
-
|
|
149
|
-
|
|
157
|
+
export const formatFunctionError =
|
|
158
|
+
/*#__PURE__*/ createBaseTypeErrorFormatter();
|
|
159
|
+
/** @group Base Types */
|
|
160
|
+
export const Uint8Array = /*#__PURE__*/ base("Uint8Array", (value) => Object.prototype.toString.call(value) === "[object Uint8Array]"
|
|
150
161
|
? ok(value)
|
|
151
162
|
: err({ type: "Uint8Array", value }));
|
|
152
|
-
export const formatUint8ArrayError =
|
|
163
|
+
export const formatUint8ArrayError =
|
|
164
|
+
/*#__PURE__*/ createBaseTypeErrorFormatter();
|
|
153
165
|
/**
|
|
154
166
|
* `instanceof` {@link Type}.
|
|
155
167
|
*
|
|
@@ -168,7 +180,7 @@ export const formatUint8ArrayError = createBaseTypeErrorFormatter();
|
|
|
168
180
|
* const error = UserInstance.from({}); // err
|
|
169
181
|
* ```
|
|
170
182
|
*
|
|
171
|
-
* @
|
|
183
|
+
* @group Base factories
|
|
172
184
|
*/
|
|
173
185
|
export const instanceOf = (ctor) => ({
|
|
174
186
|
...base("InstanceOf", (value) => value instanceof ctor
|
|
@@ -176,13 +188,14 @@ export const instanceOf = (ctor) => ({
|
|
|
176
188
|
: err({ type: "InstanceOf", value, ctor: ctor.name })),
|
|
177
189
|
ctor,
|
|
178
190
|
});
|
|
179
|
-
export const formatInstanceOfError =
|
|
191
|
+
export const formatInstanceOfError =
|
|
192
|
+
/*#__PURE__*/ createTypeErrorFormatter((error) => `The value ${error.value} is not an instance of ${error.ctor}.`);
|
|
180
193
|
/**
|
|
181
194
|
* JavaScript Date.
|
|
182
195
|
*
|
|
183
|
-
* @
|
|
196
|
+
* @group Base Types
|
|
184
197
|
*/
|
|
185
|
-
export const Date = instanceOf(globalThis.Date);
|
|
198
|
+
export const Date = /*#__PURE__*/ instanceOf(globalThis.Date);
|
|
186
199
|
/**
|
|
187
200
|
* Validates that an unknown value is an Evolu {@link Type} (i.e., satisfies
|
|
188
201
|
* `AnyType`).
|
|
@@ -195,13 +208,14 @@ export const Date = instanceOf(globalThis.Date);
|
|
|
195
208
|
* ```
|
|
196
209
|
*/
|
|
197
210
|
// TODO: Rename to TypeInstance or something like that.
|
|
198
|
-
export const EvoluType = base("EvoluType", (value) => isType(value)
|
|
211
|
+
export const EvoluType = /*#__PURE__*/ base("EvoluType", (value) => isType(value)
|
|
199
212
|
? ok(value)
|
|
200
213
|
: err({
|
|
201
214
|
type: "EvoluType",
|
|
202
215
|
value,
|
|
203
216
|
}));
|
|
204
|
-
export const formatIsTypeError =
|
|
217
|
+
export const formatIsTypeError =
|
|
218
|
+
/*#__PURE__*/ createTypeErrorFormatter((error) => `Value ${error.value} is not a valid Evolu Type.`);
|
|
205
219
|
export function brand(name, parent, refine) {
|
|
206
220
|
const fromUnknown = refine
|
|
207
221
|
? (value) => {
|
|
@@ -232,12 +246,13 @@ export function brand(name, parent, refine) {
|
|
|
232
246
|
/**
|
|
233
247
|
* A three-letter ISO 4217 currency code (e.g., USD, EUR).
|
|
234
248
|
*
|
|
235
|
-
* @
|
|
249
|
+
* @group String
|
|
236
250
|
*/
|
|
237
|
-
export const CurrencyCode = brand("CurrencyCode", String, (value) => /^[A-Z]{3}$/.test(value)
|
|
251
|
+
export const CurrencyCode = /*#__PURE__*/ brand("CurrencyCode", String, (value) => /^[A-Z]{3}$/.test(value)
|
|
238
252
|
? ok(value)
|
|
239
253
|
: err({ type: "CurrencyCode", value }));
|
|
240
|
-
export const formatCurrencyCodeError =
|
|
254
|
+
export const formatCurrencyCodeError =
|
|
255
|
+
/*#__PURE__*/ createTypeErrorFormatter((error) => `Invalid currency code: ${error.value}.`);
|
|
241
256
|
/**
|
|
242
257
|
* ISO 8601 date-time string.
|
|
243
258
|
*
|
|
@@ -257,9 +272,9 @@ export const formatCurrencyCodeError = createTypeErrorFormatter((error) => `Inva
|
|
|
257
272
|
* const error = DateIso.from("10000-01-01T00:00:00.000Z"); // err
|
|
258
273
|
* ```
|
|
259
274
|
*
|
|
260
|
-
* @
|
|
275
|
+
* @group String
|
|
261
276
|
*/
|
|
262
|
-
export const DateIso = brand("DateIso", String, (value) => {
|
|
277
|
+
export const DateIso = /*#__PURE__*/ brand("DateIso", String, (value) => {
|
|
263
278
|
if (value.length !== 24) {
|
|
264
279
|
return err({ type: "DateIso", value });
|
|
265
280
|
}
|
|
@@ -274,7 +289,8 @@ export const DateIso = brand("DateIso", String, (value) => {
|
|
|
274
289
|
}
|
|
275
290
|
return ok(value);
|
|
276
291
|
});
|
|
277
|
-
export const formatDateIsoError =
|
|
292
|
+
export const formatDateIsoError =
|
|
293
|
+
/*#__PURE__*/ createTypeErrorFormatter((error) => `The value ${error.value} is not a valid ISO 8601 date string.`);
|
|
278
294
|
export const dateToDateIso = (value) => DateIso.fromParent(value.toISOString());
|
|
279
295
|
export const dateIsoToDate = (value) => new globalThis.Date(value);
|
|
280
296
|
/**
|
|
@@ -291,25 +307,28 @@ export const dateIsoToDate = (value) => new globalThis.Date(value);
|
|
|
291
307
|
* type TrimmedNonEmptyString = typeof TrimmedNonEmptyString.Type;
|
|
292
308
|
* ```
|
|
293
309
|
*
|
|
294
|
-
* @
|
|
310
|
+
* @group String
|
|
295
311
|
*/
|
|
296
312
|
export const trimmed = (parent) => brand("Trimmed", parent, (value) => value.trim().length === value.length
|
|
297
313
|
? ok(value)
|
|
298
314
|
: err({ type: "Trimmed", value }));
|
|
299
|
-
export const formatTrimmedError =
|
|
315
|
+
export const formatTrimmedError =
|
|
316
|
+
/*#__PURE__*/ createTypeErrorFormatter((error) => `The value ${error.value} must be trimmed.`);
|
|
300
317
|
/**
|
|
301
318
|
* Trimmed string
|
|
302
319
|
*
|
|
303
320
|
* - Use `TrimmedString.is` to check if an unknown value is trimmed.
|
|
304
321
|
* - Use `TrimmedString.from` to check if a string is trimmed.
|
|
305
322
|
*
|
|
306
|
-
* @
|
|
323
|
+
* @group String
|
|
307
324
|
*/
|
|
308
|
-
export const TrimmedString = trimmed(String);
|
|
325
|
+
export const TrimmedString = /*#__PURE__*/ trimmed(String);
|
|
309
326
|
export const trim = (value) => value.trim();
|
|
310
327
|
/**
|
|
311
328
|
* Minimum length.
|
|
312
329
|
*
|
|
330
|
+
* Use numeric literal, not expression. See {@link BrandFactory}.
|
|
331
|
+
*
|
|
313
332
|
* ### Example
|
|
314
333
|
*
|
|
315
334
|
* ```ts
|
|
@@ -317,14 +336,17 @@ export const trim = (value) => value.trim();
|
|
|
317
336
|
* const NonEmptyString = minLength(1)(String);
|
|
318
337
|
* ```
|
|
319
338
|
*
|
|
320
|
-
* @
|
|
321
|
-
* @
|
|
339
|
+
* @group String
|
|
340
|
+
* @group Array
|
|
322
341
|
*/
|
|
323
342
|
export const minLength = (min) => (parent) => brand(`MinLength${min}`, parent, (value) => value.length >= min ? ok(value) : err({ type: "MinLength", value, min }));
|
|
324
|
-
export const formatMinLengthError =
|
|
343
|
+
export const formatMinLengthError =
|
|
344
|
+
/*#__PURE__*/ createTypeErrorFormatter((error) => `The value ${error.value} does not meet the minimum length of ${error.min}.`);
|
|
325
345
|
/**
|
|
326
346
|
* Maximum length.
|
|
327
347
|
*
|
|
348
|
+
* Use numeric literal, not expression. See {@link BrandFactory}.
|
|
349
|
+
*
|
|
328
350
|
* ### Example
|
|
329
351
|
*
|
|
330
352
|
* ```ts
|
|
@@ -332,14 +354,17 @@ export const formatMinLengthError = createTypeErrorFormatter((error) => `The val
|
|
|
332
354
|
* const String100 = maxLength(100)(String);
|
|
333
355
|
* ```
|
|
334
356
|
*
|
|
335
|
-
* @
|
|
336
|
-
* @
|
|
357
|
+
* @group String
|
|
358
|
+
* @group Array
|
|
337
359
|
*/
|
|
338
360
|
export const maxLength = (max) => (parent) => brand(`MaxLength${max}`, parent, (value) => value.length <= max ? ok(value) : err({ type: "MaxLength", value, max }));
|
|
339
|
-
export const formatMaxLengthError =
|
|
361
|
+
export const formatMaxLengthError =
|
|
362
|
+
/*#__PURE__*/ createTypeErrorFormatter((error) => `The value ${error.value} exceeds the maximum length of ${error.max}.`);
|
|
340
363
|
/**
|
|
341
364
|
* Exact length.
|
|
342
365
|
*
|
|
366
|
+
* Use numeric literal, not expression. See {@link BrandFactory}.
|
|
367
|
+
*
|
|
343
368
|
* ### Example
|
|
344
369
|
*
|
|
345
370
|
* ```ts
|
|
@@ -347,33 +372,36 @@ export const formatMaxLengthError = createTypeErrorFormatter((error) => `The val
|
|
|
347
372
|
* const Length1String = length(1)(String);
|
|
348
373
|
* ```
|
|
349
374
|
*
|
|
350
|
-
* @
|
|
351
|
-
* @
|
|
375
|
+
* @group String
|
|
376
|
+
* @group Array
|
|
352
377
|
*/
|
|
353
378
|
export const length = (exact) => (parent) => brand(`Length${exact}`, parent, (value) => value.length === exact
|
|
354
379
|
? ok(value)
|
|
355
380
|
: err({ type: "Length", value, exact }));
|
|
356
|
-
export const formatLengthError =
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
381
|
+
export const formatLengthError =
|
|
382
|
+
/*#__PURE__*/ createTypeErrorFormatter((error) => `The value ${error.value} does not have the required length of ${error.exact}.`);
|
|
383
|
+
/** @group String */
|
|
384
|
+
export const NonEmptyString = /*#__PURE__*/ minLength(1)(String);
|
|
385
|
+
/** @group String */
|
|
386
|
+
export const String100 = /*#__PURE__*/ maxLength(100)(String);
|
|
387
|
+
/** @group String */
|
|
388
|
+
export const String1000 = /*#__PURE__*/ maxLength(1000)(String);
|
|
389
|
+
/** @group String */
|
|
390
|
+
export const NonEmptyString100 = /*#__PURE__*/ minLength(1)(String100);
|
|
391
|
+
/** @group String */
|
|
392
|
+
export const NonEmptyString1000 = /*#__PURE__*/ minLength(1)(String1000);
|
|
393
|
+
/** @group String */
|
|
394
|
+
export const NonEmptyTrimmedString = /*#__PURE__*/ minLength(1)(TrimmedString);
|
|
395
|
+
/** @group String */
|
|
396
|
+
export const TrimmedString100 = /*#__PURE__*/ maxLength(100)(TrimmedString);
|
|
397
|
+
/** @group String */
|
|
398
|
+
export const TrimmedString1000 = /*#__PURE__*/ maxLength(1000)(TrimmedString);
|
|
399
|
+
/** @group String */
|
|
400
|
+
export const NonEmptyTrimmedString100 =
|
|
401
|
+
/*#__PURE__*/ minLength(1)(TrimmedString100);
|
|
402
|
+
/** @group String */
|
|
403
|
+
export const NonEmptyTrimmedString1000 =
|
|
404
|
+
/*#__PURE__*/ minLength(1)(TrimmedString1000);
|
|
377
405
|
/**
|
|
378
406
|
* The mnemonic, also known as a "seed phrase," is a set of 12 words in a
|
|
379
407
|
* specific order chosen from a predefined list (BIP39). It provides a
|
|
@@ -381,12 +409,13 @@ export const NonEmptyTrimmedString1000 = minLength(1)(TrimmedString1000);
|
|
|
381
409
|
* safely on the user's device using cryptographically secure random number
|
|
382
410
|
* generation, ensuring it remains private and unique.
|
|
383
411
|
*
|
|
384
|
-
* @
|
|
412
|
+
* @group String
|
|
385
413
|
*/
|
|
386
|
-
export const Mnemonic = brand("Mnemonic", NonEmptyTrimmedString, (value) => bip39.validateMnemonic(value, wordlist)
|
|
414
|
+
export const Mnemonic = /*#__PURE__*/ brand("Mnemonic", NonEmptyTrimmedString, (value) => bip39.validateMnemonic(value, wordlist)
|
|
387
415
|
? ok(value)
|
|
388
416
|
: err({ type: "Mnemonic", value }));
|
|
389
|
-
export const formatMnemonicError =
|
|
417
|
+
export const formatMnemonicError =
|
|
418
|
+
/*#__PURE__*/ createTypeErrorFormatter((error) => `Invalid BIP39 mnemonic: ${error.value}.`);
|
|
390
419
|
/**
|
|
391
420
|
* String matching a regular expression.
|
|
392
421
|
*
|
|
@@ -396,7 +425,7 @@ export const formatMnemonicError = createTypeErrorFormatter((error) => `Invalid
|
|
|
396
425
|
* const Alphanumeric = regex("Alphanumeric", /^[a-z0-9]+$/i)(String);
|
|
397
426
|
* ```
|
|
398
427
|
*
|
|
399
|
-
* @
|
|
428
|
+
* @group String
|
|
400
429
|
*/
|
|
401
430
|
export const regex = (name, pattern) => {
|
|
402
431
|
// Clone the regex to avoid shared state.
|
|
@@ -410,7 +439,8 @@ export const regex = (name, pattern) => {
|
|
|
410
439
|
: err({ type: "Regex", name, value, pattern });
|
|
411
440
|
});
|
|
412
441
|
};
|
|
413
|
-
export const formatRegexError =
|
|
442
|
+
export const formatRegexError =
|
|
443
|
+
/*#__PURE__*/ createTypeErrorFormatter((error) => `The value ${error.value} does not match the pattern for ${error.name}: ${error.pattern}.`);
|
|
414
444
|
/**
|
|
415
445
|
* URL-safe string.
|
|
416
446
|
*
|
|
@@ -436,18 +466,18 @@ export const formatRegexError = createTypeErrorFormatter((error) => `The value $
|
|
|
436
466
|
* }
|
|
437
467
|
* ```
|
|
438
468
|
*
|
|
439
|
-
* @
|
|
469
|
+
* @group String
|
|
440
470
|
*/
|
|
441
|
-
export const UrlSafeString = regex("UrlSafeString", /^[A-Za-z0-9_-]+$/)(String);
|
|
471
|
+
export const UrlSafeString = /*#__PURE__*/ regex("UrlSafeString", /^[A-Za-z0-9_-]+$/)(String);
|
|
442
472
|
/**
|
|
443
473
|
* Base64Url without padding.
|
|
444
474
|
*
|
|
445
475
|
* Encode with {@link uint8ArrayToBase64Url}, decode with
|
|
446
476
|
* {@link base64UrlToUint8Array}.
|
|
447
477
|
*
|
|
448
|
-
* @
|
|
478
|
+
* @group String
|
|
449
479
|
*/
|
|
450
|
-
export const Base64Url = brand("Base64Url", String, (value) => {
|
|
480
|
+
export const Base64Url = /*#__PURE__*/ brand("Base64Url", String, (value) => {
|
|
451
481
|
// Round-trip validation ensures consistency across different base64url
|
|
452
482
|
// implementations (Node.js Buffer, native browser API, manual fallback).
|
|
453
483
|
// Only strings that decode and encode identically are accepted.
|
|
@@ -462,7 +492,8 @@ export const Base64Url = brand("Base64Url", String, (value) => {
|
|
|
462
492
|
? ok(value)
|
|
463
493
|
: err({ type: "Base64Url", value });
|
|
464
494
|
});
|
|
465
|
-
export const formatBase64UrlError =
|
|
495
|
+
export const formatBase64UrlError =
|
|
496
|
+
/*#__PURE__*/ createTypeErrorFormatter((error) => `The value ${error.value} is not a valid Base64Url string.`);
|
|
466
497
|
const base64UrlOptions = { alphabet: "base64url", omitPadding: true };
|
|
467
498
|
/** Encodes a Uint8Array to a {@link Base64Url} string. */
|
|
468
499
|
export const uint8ArrayToBase64Url = hasNodeBuffer
|
|
@@ -500,29 +531,30 @@ export const base64UrlToUint8Array = hasNodeBuffer
|
|
|
500
531
|
return globalThis.Uint8Array.from(binaryString, (c) => c.charCodeAt(0));
|
|
501
532
|
};
|
|
502
533
|
/**
|
|
503
|
-
*
|
|
534
|
+
* Alphanumeric string for naming in file systems, URLs, and identifiers.
|
|
504
535
|
*
|
|
505
536
|
* Uses the same safe alphabet as {@link UrlSafeString} (letters, digits, `-`,
|
|
506
|
-
* `_`).
|
|
537
|
+
* `_`).
|
|
507
538
|
*
|
|
508
539
|
* The string must be between 1 and 64 characters.
|
|
509
540
|
*
|
|
510
541
|
* ### Example
|
|
511
542
|
*
|
|
512
543
|
* ```ts
|
|
513
|
-
* const result =
|
|
544
|
+
* const result = Name.from("data-report-123");
|
|
514
545
|
* if (result.ok) {
|
|
515
|
-
* console.log("Valid
|
|
546
|
+
* console.log("Valid Name string:", result.value);
|
|
516
547
|
* } else {
|
|
517
|
-
* console.error("Invalid
|
|
548
|
+
* console.error("Invalid Name string:", result.error);
|
|
518
549
|
* }
|
|
519
550
|
* ```
|
|
520
551
|
*
|
|
521
|
-
* @
|
|
552
|
+
* @group String
|
|
522
553
|
*/
|
|
523
|
-
export const
|
|
554
|
+
export const Name = /*#__PURE__*/ brand("Name", UrlSafeString, (value) => value.length >= 1 && value.length <= 64
|
|
524
555
|
? ok(value)
|
|
525
|
-
: err({ type: "
|
|
556
|
+
: err({ type: "Name", value }));
|
|
557
|
+
export const testName = /*#__PURE__*/ Name.orThrow("Name");
|
|
526
558
|
/**
|
|
527
559
|
* Trimmed string between 8 and 64 characters, branded as `SimplePassword`.
|
|
528
560
|
*
|
|
@@ -545,9 +577,10 @@ export const SimpleName = brand("SimpleName", UrlSafeString, (value) => value.le
|
|
|
545
577
|
* // |> brand("SimplePassword", %)
|
|
546
578
|
* ```
|
|
547
579
|
*
|
|
548
|
-
* @
|
|
580
|
+
* @group String
|
|
549
581
|
*/
|
|
550
|
-
export const SimplePassword = brand("SimplePassword",
|
|
582
|
+
export const SimplePassword = /*#__PURE__*/ brand("SimplePassword",
|
|
583
|
+
/*#__PURE__*/ minLength(8)(/*#__PURE__*/ maxLength(64)(TrimmedString)));
|
|
551
584
|
export const formatSimplePasswordError = (formatTypeError) => createTypeErrorFormatter((error) => `Invalid password: ${formatTypeError(error.parentError)}`);
|
|
552
585
|
/**
|
|
553
586
|
* Evolu Id: 16 bytes encoded as a 22‑character Base64Url string.
|
|
@@ -565,19 +598,19 @@ export const formatSimplePasswordError = (formatTypeError) => createTypeErrorFor
|
|
|
565
598
|
* copied (logs, URLs, exports); only use it when you explicitly want insertion
|
|
566
599
|
* locality for very large write‑heavy tables and accept timestamp exposure.
|
|
567
600
|
*
|
|
568
|
-
*
|
|
601
|
+
* ## Future
|
|
569
602
|
*
|
|
570
603
|
* A possible hybrid masked‑time approach (`timestamp ^ H(cluster_id, timestamp
|
|
571
604
|
*
|
|
572
605
|
* > > N)`) could provide locality without exposing raw creation time. See
|
|
573
606
|
* > > https://brooker.co.za/blog/2025/10/22/uuidv7.html
|
|
574
607
|
*
|
|
575
|
-
* @
|
|
608
|
+
* @group String
|
|
576
609
|
*/
|
|
577
|
-
export const Id = brand("Id", String, (value) => value.length === 22 && Base64Url.fromParent(value).ok
|
|
610
|
+
export const Id = /*#__PURE__*/ brand("Id", String, (value) => value.length === 22 && Base64Url.fromParent(value).ok
|
|
578
611
|
? ok(value)
|
|
579
612
|
: err({ type: "Id", value }));
|
|
580
|
-
export const formatIdError = createTypeErrorFormatter((error) => `The value ${error.value} is not a valid Id.`);
|
|
613
|
+
export const formatIdError = /*#__PURE__*/ createTypeErrorFormatter((error) => `The value ${error.value} is not a valid Id.`);
|
|
581
614
|
/**
|
|
582
615
|
* Creates a random {@link Id}. This is the recommended default.
|
|
583
616
|
*
|
|
@@ -626,7 +659,7 @@ export const createId = (deps) => {
|
|
|
626
659
|
* external string from the generated {@link Id}. If you need to preserve the
|
|
627
660
|
* original external ID, store it in a separate column.
|
|
628
661
|
*
|
|
629
|
-
* @
|
|
662
|
+
* @group String
|
|
630
663
|
*/
|
|
631
664
|
export const createIdFromString = (value) => {
|
|
632
665
|
const hash = sha256(utf8ToBytes(value));
|
|
@@ -661,7 +694,7 @@ export const createIdAsUuidv7 = (deps) => {
|
|
|
661
694
|
id[5] = globalThis.Number(timestamp & 0xffn);
|
|
662
695
|
id[6] = (id[6] & 0x0f) | 0x70;
|
|
663
696
|
id[8] = (id[8] & 0x3f) | 0x80;
|
|
664
|
-
return id;
|
|
697
|
+
return uint8ArrayToBase64Url(id);
|
|
665
698
|
};
|
|
666
699
|
/**
|
|
667
700
|
* Creates a branded {@link Id} Type for a table's primary key.
|
|
@@ -676,7 +709,7 @@ export const createIdAsUuidv7 = (deps) => {
|
|
|
676
709
|
* type TodoId = typeof TodoId.Type;
|
|
677
710
|
* ```
|
|
678
711
|
*
|
|
679
|
-
* @
|
|
712
|
+
* @group String
|
|
680
713
|
*/
|
|
681
714
|
export const id = (table) => {
|
|
682
715
|
const fromUnknown = (value) => {
|
|
@@ -697,9 +730,11 @@ export const id = (table) => {
|
|
|
697
730
|
table,
|
|
698
731
|
};
|
|
699
732
|
};
|
|
700
|
-
export const formatTableIdError =
|
|
733
|
+
export const formatTableIdError =
|
|
734
|
+
/*#__PURE__*/ createTypeErrorFormatter((error) => `Invalid Id for table ${error.table}: ${error.value}.`);
|
|
701
735
|
/** Binary representation of an {@link Id}. */
|
|
702
|
-
export const IdBytes = brand("IdBytes",
|
|
736
|
+
export const IdBytes = /*#__PURE__*/ brand("IdBytes",
|
|
737
|
+
/*#__PURE__*/ length(16)(Uint8Array));
|
|
703
738
|
export const idBytesTypeValueLength = 16;
|
|
704
739
|
export const idToIdBytes = (id) =>
|
|
705
740
|
// Id is Base64Url (validated by Id.from), cast is safe
|
|
@@ -719,10 +754,11 @@ uint8ArrayToBase64Url(idBytes);
|
|
|
719
754
|
* const errorResult = PositiveNumber.from(-5); // err
|
|
720
755
|
* ```
|
|
721
756
|
*
|
|
722
|
-
* @
|
|
757
|
+
* @group Number
|
|
723
758
|
*/
|
|
724
759
|
export const positive = (parent) => brand("Positive", parent, (value) => value > 0 ? ok(value) : err({ type: "Positive", value }));
|
|
725
|
-
export const formatPositiveError =
|
|
760
|
+
export const formatPositiveError =
|
|
761
|
+
/*#__PURE__*/ createTypeErrorFormatter((error) => `The value ${error.value} must be positive (> 0).`);
|
|
726
762
|
/**
|
|
727
763
|
* Negative number (< 0).
|
|
728
764
|
*
|
|
@@ -732,10 +768,11 @@ export const formatPositiveError = createTypeErrorFormatter((error) => `The valu
|
|
|
732
768
|
* const NegativeNumber = negative(Number);
|
|
733
769
|
* ```
|
|
734
770
|
*
|
|
735
|
-
* @
|
|
771
|
+
* @group Number
|
|
736
772
|
*/
|
|
737
773
|
export const negative = (parent) => brand("Negative", parent, (value) => value < 0 ? ok(value) : err({ type: "Negative", value }));
|
|
738
|
-
export const formatNegativeError =
|
|
774
|
+
export const formatNegativeError =
|
|
775
|
+
/*#__PURE__*/ createTypeErrorFormatter((error) => `The value ${error.value} must be negative (< 0).`);
|
|
739
776
|
/**
|
|
740
777
|
* Non-positive number (≤ 0).
|
|
741
778
|
*
|
|
@@ -745,12 +782,13 @@ export const formatNegativeError = createTypeErrorFormatter((error) => `The valu
|
|
|
745
782
|
* const NonPositiveNumber = nonPositive(Number);
|
|
746
783
|
* ```
|
|
747
784
|
*
|
|
748
|
-
* @
|
|
785
|
+
* @group Number
|
|
749
786
|
*/
|
|
750
787
|
export const nonPositive = (parent) => brand("NonPositive", parent, (value) => value <= 0
|
|
751
788
|
? ok(value)
|
|
752
789
|
: err({ type: "NonPositive", value }));
|
|
753
|
-
export const formatNonPositiveError =
|
|
790
|
+
export const formatNonPositiveError =
|
|
791
|
+
/*#__PURE__*/ createTypeErrorFormatter((error) => `The value ${error.value} must be non-positive (≤ 0).`);
|
|
754
792
|
/**
|
|
755
793
|
* Non-negative number (≥ 0).
|
|
756
794
|
*
|
|
@@ -760,133 +798,156 @@ export const formatNonPositiveError = createTypeErrorFormatter((error) => `The v
|
|
|
760
798
|
* const NonNegativeNumber = nonNegative(Number);
|
|
761
799
|
* ```
|
|
762
800
|
*
|
|
763
|
-
* @
|
|
801
|
+
* @group Number
|
|
764
802
|
*/
|
|
765
803
|
export const nonNegative = (parent) => brand("NonNegative", parent, (value) => value >= 0
|
|
766
804
|
? ok(value)
|
|
767
805
|
: err({ type: "NonNegative", value }));
|
|
768
|
-
export const formatNonNegativeError =
|
|
806
|
+
export const formatNonNegativeError =
|
|
807
|
+
/*#__PURE__*/ createTypeErrorFormatter((error) => `The value ${error.value} must be non-negative (≥ 0).`);
|
|
769
808
|
/**
|
|
770
809
|
* Non-negative number (≥ 0).
|
|
771
810
|
*
|
|
772
|
-
* @
|
|
811
|
+
* @group Number
|
|
773
812
|
*/
|
|
774
|
-
export const NonNegativeNumber = nonNegative(Number);
|
|
813
|
+
export const NonNegativeNumber = /*#__PURE__*/ nonNegative(Number);
|
|
775
814
|
/**
|
|
776
815
|
* Positive number (> 0).
|
|
777
816
|
*
|
|
778
|
-
* @
|
|
817
|
+
* @group Number
|
|
779
818
|
*/
|
|
780
|
-
export const PositiveNumber = positive(NonNegativeNumber);
|
|
819
|
+
export const PositiveNumber = /*#__PURE__*/ positive(NonNegativeNumber);
|
|
781
820
|
/**
|
|
782
821
|
* Non-positive number (≤ 0).
|
|
783
822
|
*
|
|
784
|
-
* @
|
|
823
|
+
* @group Number
|
|
785
824
|
*/
|
|
786
|
-
export const NonPositiveNumber = nonPositive(Number);
|
|
825
|
+
export const NonPositiveNumber = /*#__PURE__*/ nonPositive(Number);
|
|
787
826
|
/**
|
|
788
827
|
* Negative number (< 0).
|
|
789
828
|
*
|
|
790
|
-
* @
|
|
829
|
+
* @group Number
|
|
791
830
|
*/
|
|
792
|
-
export const NegativeNumber = negative(NonPositiveNumber);
|
|
831
|
+
export const NegativeNumber = /*#__PURE__*/ negative(NonPositiveNumber);
|
|
793
832
|
/**
|
|
794
833
|
* Integer within the safe range of JavaScript numbers.
|
|
795
834
|
*
|
|
796
835
|
* ### Example
|
|
797
836
|
*
|
|
798
837
|
* ```ts
|
|
799
|
-
* const Int =
|
|
838
|
+
* const Int = safeInt(Number);
|
|
800
839
|
* ```
|
|
801
840
|
*
|
|
802
|
-
*
|
|
841
|
+
* Note: This helper was previously named `int`. A Next.js regression produced
|
|
842
|
+
* runtime `int is not defined`, so we keep the implementation under the
|
|
843
|
+
* `safeInt` alias.
|
|
844
|
+
*
|
|
845
|
+
* @group Number
|
|
803
846
|
*/
|
|
804
|
-
|
|
847
|
+
const safeInt = (parent) => brand("Int", parent, (value) => globalThis.Number.isSafeInteger(value)
|
|
805
848
|
? ok(value)
|
|
806
849
|
: err({ type: "Int", value }));
|
|
807
|
-
export const formatIntError = createTypeErrorFormatter((error) => `The value ${error.value} must be an integer.`);
|
|
850
|
+
export const formatIntError = /*#__PURE__*/ createTypeErrorFormatter((error) => `The value ${error.value} must be an integer.`);
|
|
808
851
|
/**
|
|
809
852
|
* Integer within the safe range of JavaScript numbers.
|
|
810
853
|
*
|
|
811
|
-
* @
|
|
854
|
+
* @group Number
|
|
812
855
|
*/
|
|
813
|
-
export const Int =
|
|
856
|
+
export const Int = /*#__PURE__*/ safeInt(Number);
|
|
814
857
|
/**
|
|
815
858
|
* Non-negative integer (≥ 0).
|
|
816
859
|
*
|
|
817
|
-
* @
|
|
860
|
+
* @group Number
|
|
818
861
|
*/
|
|
819
|
-
export const NonNegativeInt = nonNegative(Int);
|
|
862
|
+
export const NonNegativeInt = /*#__PURE__*/ nonNegative(Int);
|
|
863
|
+
/** Minimum {@link NonNegativeInt} value (0). */
|
|
864
|
+
export const zeroNonNegativeInt = /*#__PURE__*/ NonNegativeInt.orThrow(0);
|
|
820
865
|
/**
|
|
821
866
|
* Positive integer (> 0).
|
|
822
867
|
*
|
|
823
|
-
* @
|
|
868
|
+
* @group Number
|
|
824
869
|
*/
|
|
825
|
-
export const PositiveInt = positive(NonNegativeInt);
|
|
826
|
-
/**
|
|
827
|
-
export const
|
|
870
|
+
export const PositiveInt = /*#__PURE__*/ positive(NonNegativeInt);
|
|
871
|
+
/** {@link PositiveInt} value 1. */
|
|
872
|
+
export const onePositiveInt = /*#__PURE__*/ PositiveInt.orThrow(1);
|
|
873
|
+
/** Maximum {@link PositiveInt} value (MAX_SAFE_INTEGER). */
|
|
874
|
+
export const maxPositiveInt = /*#__PURE__*/ PositiveInt.orThrow(globalThis.Number.MAX_SAFE_INTEGER);
|
|
828
875
|
/**
|
|
829
876
|
* Non-positive integer (≤ 0).
|
|
830
877
|
*
|
|
831
|
-
* @
|
|
878
|
+
* @group Number
|
|
832
879
|
*/
|
|
833
|
-
export const NonPositiveInt = nonPositive(Int);
|
|
880
|
+
export const NonPositiveInt = /*#__PURE__*/ nonPositive(Int);
|
|
834
881
|
/**
|
|
835
882
|
* Negative integer (< 0).
|
|
836
883
|
*
|
|
837
|
-
* @
|
|
884
|
+
* @group Number
|
|
838
885
|
*/
|
|
839
|
-
export const NegativeInt = negative(NonPositiveInt);
|
|
886
|
+
export const NegativeInt = /*#__PURE__*/ negative(NonPositiveInt);
|
|
840
887
|
/**
|
|
841
888
|
* Number greater than a specified value.
|
|
842
889
|
*
|
|
843
|
-
* @
|
|
890
|
+
* Use numeric literal, not expression. See {@link BrandFactory}.
|
|
891
|
+
*
|
|
892
|
+
* @group Number
|
|
844
893
|
*/
|
|
845
894
|
export const greaterThan = (min) => (parent) => brand(`GreaterThan${min}`, parent, (value) => value > min ? ok(value) : err({ type: "GreaterThan", value, min }));
|
|
846
|
-
export const formatGreaterThanError =
|
|
895
|
+
export const formatGreaterThanError =
|
|
896
|
+
/*#__PURE__*/ createTypeErrorFormatter((error) => `The value ${error.value} is not > ${error.min}.`);
|
|
847
897
|
/**
|
|
848
898
|
* Number less than a specified value.
|
|
849
899
|
*
|
|
850
|
-
* @
|
|
900
|
+
* Use numeric literal, not expression. See {@link BrandFactory}.
|
|
901
|
+
*
|
|
902
|
+
* @group Number
|
|
851
903
|
*/
|
|
852
904
|
export const lessThan = (max) => (parent) => brand(`LessThan${max}`, parent, (value) => value < max ? ok(value) : err({ type: "LessThan", value, max }));
|
|
853
|
-
export const formatLessThanError =
|
|
905
|
+
export const formatLessThanError =
|
|
906
|
+
/*#__PURE__*/ createTypeErrorFormatter((error) => `The value ${error.value} is not < ${error.max}.`);
|
|
854
907
|
/**
|
|
855
908
|
* Number ≥ a specified value.
|
|
856
909
|
*
|
|
857
|
-
* @
|
|
910
|
+
* Use numeric literal, not expression. See {@link BrandFactory}.
|
|
911
|
+
*
|
|
912
|
+
* @group Number
|
|
858
913
|
*/
|
|
859
914
|
export const greaterThanOrEqualTo = (min) => (parent) => brand(`GreaterThanOrEqualTo${min}`, parent, (value) => value >= min
|
|
860
915
|
? ok(value)
|
|
861
916
|
: err({ type: "GreaterThanOrEqualTo", value, min }));
|
|
862
|
-
export const formatGreaterThanOrEqualToError =
|
|
917
|
+
export const formatGreaterThanOrEqualToError =
|
|
918
|
+
/*#__PURE__*/ createTypeErrorFormatter((error) => `The value ${error.value} is not >= ${error.min}.`);
|
|
863
919
|
/**
|
|
864
920
|
* Number ≤ a specified value.
|
|
865
921
|
*
|
|
866
|
-
* @
|
|
922
|
+
* Use numeric literal, not expression. See {@link BrandFactory}.
|
|
923
|
+
*
|
|
924
|
+
* @group Number
|
|
867
925
|
*/
|
|
868
926
|
export const lessThanOrEqualTo = (max) => (parent) => brand(`LessThanOrEqualTo${max}`, parent, (value) => value <= max ? ok(value) : err({ type: "LessThanOrEqualTo", value, max }));
|
|
869
|
-
export const formatLessThanOrEqualToError =
|
|
927
|
+
export const formatLessThanOrEqualToError =
|
|
928
|
+
/*#__PURE__*/ createTypeErrorFormatter((error) => `The value ${error.value} is not <= ${error.max}.`);
|
|
870
929
|
/**
|
|
871
930
|
* Number that is not NaN.
|
|
872
931
|
*
|
|
873
|
-
* @
|
|
932
|
+
* @group Number
|
|
874
933
|
*/
|
|
875
934
|
export const nonNaN = (parent) => brand("NonNaN", parent, (value) => !globalThis.Number.isNaN(value)
|
|
876
935
|
? ok(value)
|
|
877
936
|
: err({ type: "NonNaN", value }));
|
|
878
|
-
export const formatNonNaNError =
|
|
879
|
-
|
|
880
|
-
|
|
937
|
+
export const formatNonNaNError =
|
|
938
|
+
/*#__PURE__*/ createTypeErrorFormatter(() => `The value must not be NaN.`);
|
|
939
|
+
/** @group Number */
|
|
940
|
+
export const NonNaNNumber = /*#__PURE__*/ nonNaN(Number);
|
|
881
941
|
/**
|
|
882
942
|
* Finite number.
|
|
883
943
|
*
|
|
884
|
-
* @
|
|
944
|
+
* @group Number
|
|
885
945
|
*/
|
|
886
946
|
export const finite = (parent) => brand("Finite", parent, (value) => globalThis.Number.isFinite(value)
|
|
887
947
|
? ok(value)
|
|
888
948
|
: err({ type: "Finite", value }));
|
|
889
|
-
export const formatFiniteError =
|
|
949
|
+
export const formatFiniteError =
|
|
950
|
+
/*#__PURE__*/ createTypeErrorFormatter((error) => `The value ${error.value} must be finite.`);
|
|
890
951
|
/**
|
|
891
952
|
* Finite number.
|
|
892
953
|
*
|
|
@@ -898,21 +959,26 @@ export const formatFiniteError = createTypeErrorFormatter((error) => `The value
|
|
|
898
959
|
* finite (e.g., `Infinity`, `-Infinity`, or `NaN`). Using `FiniteNumber` helps
|
|
899
960
|
* prevent these unexpected behaviors when working with JSON serialization.
|
|
900
961
|
*
|
|
901
|
-
* @
|
|
962
|
+
* @group Number
|
|
902
963
|
*/
|
|
903
|
-
export const FiniteNumber = finite(Number);
|
|
964
|
+
export const FiniteNumber = /*#__PURE__*/ finite(Number);
|
|
904
965
|
/**
|
|
905
966
|
* Number that is a multiple of a divisor.
|
|
906
967
|
*
|
|
907
|
-
* @
|
|
968
|
+
* Use numeric literal, not expression. See {@link BrandFactory}.
|
|
969
|
+
*
|
|
970
|
+
* @group Number
|
|
908
971
|
*/
|
|
909
972
|
export const multipleOf = (divisor) => (parent) => brand(`MultipleOf${divisor}`, parent, (value) => value % divisor === 0
|
|
910
973
|
? ok(value)
|
|
911
974
|
: err({ type: "MultipleOf", value, divisor }));
|
|
912
|
-
export const formatMultipleOfError =
|
|
975
|
+
export const formatMultipleOfError =
|
|
976
|
+
/*#__PURE__*/ createTypeErrorFormatter((error) => `The value ${error.value} is not a multiple of ${error.divisor}.`);
|
|
913
977
|
/**
|
|
914
978
|
* Number within a range, inclusive.
|
|
915
979
|
*
|
|
980
|
+
* Use numeric literal, not expression. See {@link BrandFactory}.
|
|
981
|
+
*
|
|
916
982
|
* ### Example
|
|
917
983
|
*
|
|
918
984
|
* ```ts
|
|
@@ -921,12 +987,13 @@ export const formatMultipleOfError = createTypeErrorFormatter((error) => `The va
|
|
|
921
987
|
* const errorResult = Between1And10.from(11); // err
|
|
922
988
|
* ```
|
|
923
989
|
*
|
|
924
|
-
* @
|
|
990
|
+
* @group Number
|
|
925
991
|
*/
|
|
926
992
|
export const between = (min, max) => (parent) => brand(`Between${min}-${max}`, parent, (value) => value >= min && value <= max
|
|
927
993
|
? ok(value)
|
|
928
994
|
: err({ type: "Between", value, min, max }));
|
|
929
|
-
export const formatBetweenError =
|
|
995
|
+
export const formatBetweenError =
|
|
996
|
+
/*#__PURE__*/ createTypeErrorFormatter((error) => `The value ${error.value} is not between ${error.min} and ${error.max}, inclusive.`);
|
|
930
997
|
/**
|
|
931
998
|
* Literal {@link Type}.
|
|
932
999
|
*
|
|
@@ -942,7 +1009,7 @@ export const formatBetweenError = createTypeErrorFormatter((error) => `The value
|
|
|
942
1009
|
*
|
|
943
1010
|
* TODO: Add JsonValue
|
|
944
1011
|
*
|
|
945
|
-
* @
|
|
1012
|
+
* @group Base factories
|
|
946
1013
|
*/
|
|
947
1014
|
export const literal = (expected) => {
|
|
948
1015
|
const fromUnknown = (value) => value === expected
|
|
@@ -956,11 +1023,12 @@ export const literal = (expected) => {
|
|
|
956
1023
|
expected,
|
|
957
1024
|
};
|
|
958
1025
|
};
|
|
959
|
-
export const formatLiteralError =
|
|
1026
|
+
export const formatLiteralError =
|
|
1027
|
+
/*#__PURE__*/ createTypeErrorFormatter((error) => `The value ${error.value} is not strictly equal to the expected literal: ${globalThis.String(error.expected)}.`);
|
|
960
1028
|
/**
|
|
961
1029
|
* Array of a specific {@link Type}.
|
|
962
1030
|
*
|
|
963
|
-
*
|
|
1031
|
+
* ### Example
|
|
964
1032
|
*
|
|
965
1033
|
* ```ts
|
|
966
1034
|
* const NumberArray = array(Number);
|
|
@@ -969,8 +1037,8 @@ export const formatLiteralError = createTypeErrorFormatter((error) => `The value
|
|
|
969
1037
|
* const result2 = NumberArray.from(["a", "b"]); // err(...)
|
|
970
1038
|
* ```
|
|
971
1039
|
*
|
|
972
|
-
* @
|
|
973
|
-
* @
|
|
1040
|
+
* @group Base factories
|
|
1041
|
+
* @group Array
|
|
974
1042
|
*/
|
|
975
1043
|
export const array = (element) => {
|
|
976
1044
|
const fromUnknown = (value) => {
|
|
@@ -1043,7 +1111,7 @@ export const formatArrayError = (formatTypeError) => createTypeErrorFormatter((e
|
|
|
1043
1111
|
* const result2 = NumberSet.from(new Set(["a", "b"])); // err(...)
|
|
1044
1112
|
* ```
|
|
1045
1113
|
*
|
|
1046
|
-
* @
|
|
1114
|
+
* @group Base factories
|
|
1047
1115
|
*/
|
|
1048
1116
|
export const set = (element) => {
|
|
1049
1117
|
const fromUnknown = (value) => {
|
|
@@ -1128,8 +1196,8 @@ export const formatSetError = (formatTypeError) => createTypeErrorFormatter((err
|
|
|
1128
1196
|
* StringToNumberRecord.from({ a: "x", b: 2 });
|
|
1129
1197
|
* ```
|
|
1130
1198
|
*
|
|
1131
|
-
* @
|
|
1132
|
-
* @
|
|
1199
|
+
* @group Base factories
|
|
1200
|
+
* @group Object
|
|
1133
1201
|
*/
|
|
1134
1202
|
export const record = (keyType, valueType) => {
|
|
1135
1203
|
const fromUnknown = (value) => {
|
|
@@ -1375,6 +1443,9 @@ export const formatObjectWithRecordError = (formatTypeError) => createTypeErrorF
|
|
|
1375
1443
|
return `Invalid value at index key ${error.reason.key}: ${formatTypeError(error.reason.error)}`;
|
|
1376
1444
|
}
|
|
1377
1445
|
});
|
|
1446
|
+
export function typed(tag, props) {
|
|
1447
|
+
return object({ type: literal(tag), ...props });
|
|
1448
|
+
}
|
|
1378
1449
|
export function union(...args) {
|
|
1379
1450
|
/**
|
|
1380
1451
|
* Good First Issue:
|
|
@@ -1420,6 +1491,75 @@ export const formatUnionError = (formatTypeError) => createTypeErrorFormatter((e
|
|
|
1420
1491
|
return `Value ${error.value} does not match any member of the union.\nErrors:\n${formattedErrors}`;
|
|
1421
1492
|
});
|
|
1422
1493
|
export const isUnionType = (t) => t.name === "Union" && Array.isArray(t.members);
|
|
1494
|
+
/**
|
|
1495
|
+
* Creates a {@link Type} for {@link Result} values.
|
|
1496
|
+
*
|
|
1497
|
+
* Use for validating serialized Results from storage, APIs, or message passing.
|
|
1498
|
+
*
|
|
1499
|
+
* ### Example
|
|
1500
|
+
*
|
|
1501
|
+
* ```ts
|
|
1502
|
+
* const SyncResponse = result(
|
|
1503
|
+
* object({ timestamp: NonNegativeInt }),
|
|
1504
|
+
* typed("SyncError", { message: String }),
|
|
1505
|
+
* );
|
|
1506
|
+
*
|
|
1507
|
+
* // Validate response from worker or API
|
|
1508
|
+
* const validated = SyncResponse.from(JSON.parse(message));
|
|
1509
|
+
* if (!validated.ok) return validated; // validation error
|
|
1510
|
+
* // validated.value is Result<{ timestamp }, SyncError>
|
|
1511
|
+
* ```
|
|
1512
|
+
*
|
|
1513
|
+
* @group Composite factories
|
|
1514
|
+
*/
|
|
1515
|
+
export const result = (okType, errType) => union(object({ ok: literal(true), value: okType }), object({ ok: literal(false), error: errType }));
|
|
1516
|
+
/**
|
|
1517
|
+
* A {@link result} type for `Result<unknown, unknown>`.
|
|
1518
|
+
*
|
|
1519
|
+
* Useful for serializing Results where the value and error types are unknown.
|
|
1520
|
+
*
|
|
1521
|
+
* @group Composite factories
|
|
1522
|
+
*/
|
|
1523
|
+
export const UnknownResult = /*#__PURE__*/ result(Unknown, Unknown);
|
|
1524
|
+
/**
|
|
1525
|
+
* Creates a {@link Type} for {@link NextResult} with three outcomes.
|
|
1526
|
+
*
|
|
1527
|
+
* Validates results where the producer responds with:
|
|
1528
|
+
*
|
|
1529
|
+
* - `Ok<A>` — produced a value
|
|
1530
|
+
* - `Err<Done<D>>` — completed normally with a done value
|
|
1531
|
+
* - `Err<E>` — failed with an error
|
|
1532
|
+
*
|
|
1533
|
+
* ### Example
|
|
1534
|
+
*
|
|
1535
|
+
* ```ts
|
|
1536
|
+
* const MyNextResult = nextResult(Item, MyError, Summary);
|
|
1537
|
+
*
|
|
1538
|
+
* const validated = MyNextResult.fromUnknown(data);
|
|
1539
|
+
* if (!validated.ok) return validated;
|
|
1540
|
+
*
|
|
1541
|
+
* const result = validated.value;
|
|
1542
|
+
* if (result.ok) {
|
|
1543
|
+
* console.log(result.value);
|
|
1544
|
+
* } else if (result.error.type === "Done") {
|
|
1545
|
+
* console.log("Done:", result.error.done);
|
|
1546
|
+
* } else {
|
|
1547
|
+
* console.error(result.error);
|
|
1548
|
+
* }
|
|
1549
|
+
* ```
|
|
1550
|
+
*
|
|
1551
|
+
* @group Composite factories
|
|
1552
|
+
*/
|
|
1553
|
+
export const nextResult = (valueType, errorType, doneType) => result(valueType, union(errorType, typed("Done", { done: doneType })));
|
|
1554
|
+
/**
|
|
1555
|
+
* A {@link nextResult} type for `NextResult<unknown, unknown, unknown>`.
|
|
1556
|
+
*
|
|
1557
|
+
* Useful for checking if a value is a {@link NextResult} via
|
|
1558
|
+
* `UnknownNextResult.is(value)`.
|
|
1559
|
+
*
|
|
1560
|
+
* @group Composite factories
|
|
1561
|
+
*/
|
|
1562
|
+
export const UnknownNextResult = /*#__PURE__*/ nextResult(Unknown, Unknown, Unknown);
|
|
1423
1563
|
/**
|
|
1424
1564
|
* Recursive {@link Type}.
|
|
1425
1565
|
*
|
|
@@ -1453,7 +1593,7 @@ export const isUnionType = (t) => t.name === "Union" && Array.isArray(t.members)
|
|
|
1453
1593
|
* );
|
|
1454
1594
|
* ```
|
|
1455
1595
|
*
|
|
1456
|
-
* @
|
|
1596
|
+
* @group Base factories
|
|
1457
1597
|
*/
|
|
1458
1598
|
export const recursive = (create) => {
|
|
1459
1599
|
let type;
|
|
@@ -1494,7 +1634,7 @@ export const recursive = (create) => {
|
|
|
1494
1634
|
* NullOrString.from(42); // err(...)
|
|
1495
1635
|
* ```
|
|
1496
1636
|
*
|
|
1497
|
-
* @
|
|
1637
|
+
* @group Base factories
|
|
1498
1638
|
*/
|
|
1499
1639
|
export const nullOr = (type) => union(Null, type);
|
|
1500
1640
|
/**
|
|
@@ -1509,7 +1649,7 @@ export const nullOr = (type) => union(Null, type);
|
|
|
1509
1649
|
* UndefinedOrString.from(42); // err(...)
|
|
1510
1650
|
* ```
|
|
1511
1651
|
*
|
|
1512
|
-
* @
|
|
1652
|
+
* @group Base factories
|
|
1513
1653
|
*/
|
|
1514
1654
|
export const undefinedOr = (type) => union(Undefined, type);
|
|
1515
1655
|
/**
|
|
@@ -1528,7 +1668,7 @@ export const undefinedOr = (type) => union(Undefined, type);
|
|
|
1528
1668
|
* NullishOrString.from(42); // err(...)
|
|
1529
1669
|
* ```
|
|
1530
1670
|
*
|
|
1531
|
-
* @
|
|
1671
|
+
* @group Base factories
|
|
1532
1672
|
*/
|
|
1533
1673
|
export const nullishOr = (type) => union(Undefined, Null, type);
|
|
1534
1674
|
/**
|
|
@@ -1545,7 +1685,7 @@ export const nullishOr = (type) => union(Undefined, Null, type);
|
|
|
1545
1685
|
* const error = NameAndAge.from(["Alice", -10]); // err
|
|
1546
1686
|
* ```
|
|
1547
1687
|
*
|
|
1548
|
-
* @
|
|
1688
|
+
* @group Base factories
|
|
1549
1689
|
*/
|
|
1550
1690
|
export const tuple = (...elements) => {
|
|
1551
1691
|
const fromUnknown = (value) => {
|
|
@@ -1631,42 +1771,44 @@ export const formatTupleError = (formatTypeError) => createTypeErrorFormatter((e
|
|
|
1631
1771
|
*
|
|
1632
1772
|
* https://www.sqlite.org/c3ref/int64.html
|
|
1633
1773
|
*
|
|
1634
|
-
* @
|
|
1774
|
+
* @group Number
|
|
1635
1775
|
*/
|
|
1636
|
-
export const Int64 = brand("Int64", BigInt, (value) => value >= -9223372036854775808n && value <= 9223372036854775807n
|
|
1776
|
+
export const Int64 = /*#__PURE__*/ brand("Int64", BigInt, (value) => value >= -9223372036854775808n && value <= 9223372036854775807n
|
|
1637
1777
|
? ok(value)
|
|
1638
1778
|
: err({ type: "Int64", value }));
|
|
1639
|
-
export const formatInt64Error =
|
|
1779
|
+
export const formatInt64Error =
|
|
1780
|
+
/*#__PURE__*/ createTypeErrorFormatter((error) => `The value ${error.value} is not a valid 64-bit signed integer (Int64).`);
|
|
1640
1781
|
/**
|
|
1641
1782
|
* Stringified {@link Int64}.
|
|
1642
1783
|
*
|
|
1643
|
-
* @
|
|
1784
|
+
* @group String
|
|
1644
1785
|
*/
|
|
1645
|
-
export const Int64String = brand("Int64", NonEmptyTrimmedString, (value) => trySync(() => {
|
|
1786
|
+
export const Int64String = /*#__PURE__*/ brand("Int64", NonEmptyTrimmedString, (value) => trySync(() => {
|
|
1646
1787
|
const maybeInt = globalThis.BigInt(value);
|
|
1647
1788
|
Int64.orThrow(maybeInt);
|
|
1648
1789
|
return value;
|
|
1649
1790
|
}, () => ({ type: "Int64String", value })));
|
|
1650
|
-
export const formatInt64StringError =
|
|
1791
|
+
export const formatInt64StringError =
|
|
1792
|
+
/*#__PURE__*/ createTypeErrorFormatter((error) => `The value ${error.value} is not a valid Int64 string.`);
|
|
1651
1793
|
/**
|
|
1652
1794
|
* JSON-compatible value: string, {@link FiniteNumber}, boolean, null,
|
|
1653
1795
|
* {@link JsonArray}, or {@link JsonObject}.
|
|
1654
1796
|
*
|
|
1655
|
-
* @
|
|
1797
|
+
* @group Base Types
|
|
1656
1798
|
*/
|
|
1657
|
-
export const JsonValue = recursive(() => union(String, FiniteNumber, Boolean, Null, JsonArray, JsonObject));
|
|
1799
|
+
export const JsonValue = /*#__PURE__*/ recursive(() => union(String, FiniteNumber, Boolean, Null, JsonArray, JsonObject));
|
|
1658
1800
|
/**
|
|
1659
1801
|
* JSON-compatible array of {@link JsonValue} elements.
|
|
1660
1802
|
*
|
|
1661
|
-
* @
|
|
1803
|
+
* @group Array
|
|
1662
1804
|
*/
|
|
1663
|
-
export const JsonArray = array(JsonValue);
|
|
1805
|
+
export const JsonArray = /*#__PURE__*/ array(JsonValue);
|
|
1664
1806
|
/**
|
|
1665
1807
|
* JSON-compatible object with string keys and {@link JsonValue} values.
|
|
1666
1808
|
*
|
|
1667
|
-
* @
|
|
1809
|
+
* @group Object
|
|
1668
1810
|
*/
|
|
1669
|
-
export const JsonObject = record(String, JsonValue);
|
|
1811
|
+
export const JsonObject = /*#__PURE__*/ record(String, JsonValue);
|
|
1670
1812
|
export const parseJson = (value) => trySync(() => JSON.parse(value), (error) => ({
|
|
1671
1813
|
type: `Json`,
|
|
1672
1814
|
value,
|
|
@@ -1682,15 +1824,16 @@ export const parseJson = (value) => trySync(() => JSON.parse(value), (error) =>
|
|
|
1682
1824
|
* const error = Json.from("invalid json"); // err
|
|
1683
1825
|
* ```
|
|
1684
1826
|
*
|
|
1685
|
-
* @
|
|
1827
|
+
* @group String
|
|
1686
1828
|
*/
|
|
1687
|
-
export const Json = brand("Json", String, (value) => {
|
|
1829
|
+
export const Json = /*#__PURE__*/ brand("Json", String, (value) => {
|
|
1688
1830
|
const result = parseJson(value);
|
|
1689
1831
|
if (!result.ok)
|
|
1690
1832
|
return result;
|
|
1691
1833
|
return ok(value);
|
|
1692
1834
|
});
|
|
1693
|
-
export const formatJsonError =
|
|
1835
|
+
export const formatJsonError =
|
|
1836
|
+
/*#__PURE__*/ createTypeErrorFormatter((error) => `Invalid JSON: ${error.value}. Error: ${error.message}`);
|
|
1694
1837
|
export const jsonValueToJson = (value) => JSON.stringify(value);
|
|
1695
1838
|
export const jsonToJsonValue = (value) => JSON.parse(value);
|
|
1696
1839
|
/**
|
|
@@ -1713,7 +1856,7 @@ export const jsonToJsonValue = (value) => JSON.parse(value);
|
|
|
1713
1856
|
* name: NonEmptyString100,
|
|
1714
1857
|
* age: FiniteNumber,
|
|
1715
1858
|
* });
|
|
1716
|
-
*
|
|
1859
|
+
* interface Person extends InferType<typeof Person> {}
|
|
1717
1860
|
*
|
|
1718
1861
|
* const [PersonJson, personToPersonJson, personJsonToPerson] = json(
|
|
1719
1862
|
* Person,
|
|
@@ -1738,11 +1881,7 @@ export const json = (type, name) => {
|
|
|
1738
1881
|
return validationResult;
|
|
1739
1882
|
return ok(value);
|
|
1740
1883
|
});
|
|
1741
|
-
return [
|
|
1742
|
-
BrandedJsonType,
|
|
1743
|
-
jsonValueToJson,
|
|
1744
|
-
jsonToJsonValue,
|
|
1745
|
-
];
|
|
1884
|
+
return [BrandedJsonType, jsonValueToJson, jsonToJsonValue];
|
|
1746
1885
|
};
|
|
1747
1886
|
/**
|
|
1748
1887
|
* Optional {@link Type}.
|
|
@@ -1799,7 +1938,7 @@ export const isOptionalType = (x) => typeof x === "object" && x != null && "name
|
|
|
1799
1938
|
* PartialUser.from({ age: -5 });
|
|
1800
1939
|
* ```
|
|
1801
1940
|
*
|
|
1802
|
-
* @
|
|
1941
|
+
* @group Object
|
|
1803
1942
|
*/
|
|
1804
1943
|
export const partial = (props) => {
|
|
1805
1944
|
const optionalProps = {};
|
|
@@ -1816,7 +1955,7 @@ export const partial = (props) => {
|
|
|
1816
1955
|
* entirely, or set it to `null`, or set it to the non-null member of the
|
|
1817
1956
|
* union.
|
|
1818
1957
|
*
|
|
1819
|
-
* @
|
|
1958
|
+
* @group Object
|
|
1820
1959
|
*/
|
|
1821
1960
|
export const nullableToOptional = (props) => {
|
|
1822
1961
|
const transformedProps = {};
|
|
@@ -1836,9 +1975,9 @@ export const nullableToOptional = (props) => {
|
|
|
1836
1975
|
/**
|
|
1837
1976
|
* Create a new `object` {@link Type} by omitting some keys.
|
|
1838
1977
|
*
|
|
1839
|
-
* @
|
|
1978
|
+
* @group Object
|
|
1840
1979
|
*/
|
|
1841
|
-
export
|
|
1980
|
+
export const omit = (objectType, ...keys) => {
|
|
1842
1981
|
const newProps = {};
|
|
1843
1982
|
for (const key in objectType.props) {
|
|
1844
1983
|
if (!keys.includes(key)) {
|
|
@@ -1847,18 +1986,7 @@ export function omit(objectType, ...keys) {
|
|
|
1847
1986
|
}
|
|
1848
1987
|
}
|
|
1849
1988
|
return object(newProps);
|
|
1850
|
-
}
|
|
1851
|
-
export const maxMutationSize = 655360;
|
|
1852
|
-
/**
|
|
1853
|
-
* Evolu has to limit the maximum mutation size. Otherwise, sync couldn't use
|
|
1854
|
-
* the `maxProtocolMessageRangesSize`. The max size is 640KB in bytes, measured
|
|
1855
|
-
* via MessagePack. Evolu Protocol DbChange will be smaller thanks to various
|
|
1856
|
-
* optimizations.
|
|
1857
|
-
*/
|
|
1858
|
-
export const validMutationSize = (type) => brand("ValidMutationSize", type, (value) => pack(value).byteLength <= maxMutationSize
|
|
1859
|
-
? ok(value)
|
|
1860
|
-
: err({ type: "ValidMutationSize", value }));
|
|
1861
|
-
export const formatValidMutationSizeError = createTypeErrorFormatter((error) => `The mutation size exceeds the maximum limit of ${maxMutationSize} bytes. The provided mutation has a size of ${pack(error.value).byteLength} bytes.`);
|
|
1989
|
+
};
|
|
1862
1990
|
/**
|
|
1863
1991
|
* Formats Evolu Type errors into user-friendly messages.
|
|
1864
1992
|
*
|
|
@@ -1937,7 +2065,7 @@ export const formatValidMutationSizeError = createTypeErrorFormatter((error) =>
|
|
|
1937
2065
|
* };
|
|
1938
2066
|
* ```
|
|
1939
2067
|
*
|
|
1940
|
-
* @
|
|
2068
|
+
* @group Utilities
|
|
1941
2069
|
*/
|
|
1942
2070
|
export const createFormatTypeError = (extraFormatter) => {
|
|
1943
2071
|
const formatTypeError = (error) => {
|
|
@@ -2020,8 +2148,6 @@ export const createFormatTypeError = (extraFormatter) => {
|
|
|
2020
2148
|
return formatInt64StringError(error);
|
|
2021
2149
|
case "Json":
|
|
2022
2150
|
return formatJsonError(error);
|
|
2023
|
-
case "ValidMutationSize":
|
|
2024
|
-
return formatValidMutationSizeError(error);
|
|
2025
2151
|
// Composite Types
|
|
2026
2152
|
case "SimplePassword":
|
|
2027
2153
|
return formatSimplePasswordError(formatTypeError)(error);
|
|
@@ -2052,82 +2178,78 @@ export const createFormatTypeError = (extraFormatter) => {
|
|
|
2052
2178
|
* Converts an Evolu {@link TypeError} to Standard Schema V1 issues format.
|
|
2053
2179
|
*
|
|
2054
2180
|
* This function recursively converts Evolu's typed errors into the Standard
|
|
2055
|
-
* Schema issue format with proper path tracking for nested structures.
|
|
2181
|
+
* Schema issue format with proper path tracking for nested structures. The
|
|
2182
|
+
* `message` field contains the JSON-serialized typed error, which users can
|
|
2183
|
+
* deserialize and format using appropriate {@link TypeErrorFormatter}s.
|
|
2056
2184
|
*
|
|
2057
|
-
* @
|
|
2185
|
+
* @group Utilities
|
|
2058
2186
|
*/
|
|
2059
|
-
export const typeErrorToStandardSchemaIssues = (error,
|
|
2187
|
+
export const typeErrorToStandardSchemaIssues = (error, path = []) => {
|
|
2060
2188
|
if (error.type === "Array") {
|
|
2061
2189
|
const arrayError = error;
|
|
2062
2190
|
if (arrayError.reason.kind === "NotArray") {
|
|
2063
|
-
return [{ message:
|
|
2191
|
+
return [{ message: JSON.stringify(error), path }];
|
|
2064
2192
|
}
|
|
2065
|
-
return typeErrorToStandardSchemaIssues(arrayError.reason.error,
|
|
2193
|
+
return typeErrorToStandardSchemaIssues(arrayError.reason.error, [...path, arrayError.reason.index]);
|
|
2066
2194
|
}
|
|
2067
2195
|
if (error.type === "Set") {
|
|
2068
2196
|
const setError = error;
|
|
2069
2197
|
if (setError.reason.kind === "NotSet") {
|
|
2070
|
-
return [{ message:
|
|
2198
|
+
return [{ message: JSON.stringify(error), path }];
|
|
2071
2199
|
}
|
|
2072
|
-
return typeErrorToStandardSchemaIssues(setError.reason.error,
|
|
2200
|
+
return typeErrorToStandardSchemaIssues(setError.reason.error, [...path, setError.reason.index]);
|
|
2073
2201
|
}
|
|
2074
2202
|
if (error.type === "Object") {
|
|
2075
2203
|
const objectError = error;
|
|
2076
2204
|
if (objectError.reason.kind === "NotObject" ||
|
|
2077
2205
|
objectError.reason.kind === "ExtraKeys") {
|
|
2078
|
-
return [{ message:
|
|
2206
|
+
return [{ message: JSON.stringify(error), path }];
|
|
2079
2207
|
}
|
|
2080
2208
|
const issues = [];
|
|
2081
2209
|
for (const [key, propError] of Object.entries(objectError.reason.errors)) {
|
|
2082
|
-
issues.push(...typeErrorToStandardSchemaIssues(propError,
|
|
2210
|
+
issues.push(...typeErrorToStandardSchemaIssues(propError, [...path, key]));
|
|
2083
2211
|
}
|
|
2084
2212
|
return issues;
|
|
2085
2213
|
}
|
|
2086
2214
|
if (error.type === "ObjectWithRecord") {
|
|
2087
2215
|
const objectWithRecordError = error;
|
|
2088
2216
|
if (objectWithRecordError.reason.kind === "NotObject") {
|
|
2089
|
-
return [{ message:
|
|
2217
|
+
return [{ message: JSON.stringify(error), path }];
|
|
2090
2218
|
}
|
|
2091
2219
|
if (objectWithRecordError.reason.kind === "IndexKey" ||
|
|
2092
2220
|
objectWithRecordError.reason.kind === "IndexValue") {
|
|
2093
|
-
return typeErrorToStandardSchemaIssues(objectWithRecordError.reason.error,
|
|
2221
|
+
return typeErrorToStandardSchemaIssues(objectWithRecordError.reason.error, [...path, objectWithRecordError.reason.key]);
|
|
2094
2222
|
}
|
|
2095
2223
|
const issues = [];
|
|
2096
2224
|
for (const [key, propError] of Object.entries(objectWithRecordError.reason.errors)) {
|
|
2097
|
-
issues.push(...typeErrorToStandardSchemaIssues(propError,
|
|
2225
|
+
issues.push(...typeErrorToStandardSchemaIssues(propError, [...path, key]));
|
|
2098
2226
|
}
|
|
2099
2227
|
return issues;
|
|
2100
2228
|
}
|
|
2101
2229
|
if (error.type === "Record") {
|
|
2102
2230
|
const recordError = error;
|
|
2103
2231
|
if (recordError.reason.kind === "NotRecord") {
|
|
2104
|
-
return [{ message:
|
|
2232
|
+
return [{ message: JSON.stringify(error), path }];
|
|
2105
2233
|
}
|
|
2106
|
-
return typeErrorToStandardSchemaIssues(recordError.reason.error,
|
|
2234
|
+
return typeErrorToStandardSchemaIssues(recordError.reason.error, [...path, recordError.reason.key]);
|
|
2107
2235
|
}
|
|
2108
2236
|
if (error.type === "Tuple") {
|
|
2109
2237
|
const tupleError = error;
|
|
2110
2238
|
if (tupleError.reason.kind === "InvalidLength") {
|
|
2111
|
-
return [{ message:
|
|
2239
|
+
return [{ message: JSON.stringify(error), path }];
|
|
2112
2240
|
}
|
|
2113
|
-
return typeErrorToStandardSchemaIssues(tupleError.reason.error,
|
|
2241
|
+
return typeErrorToStandardSchemaIssues(tupleError.reason.error, [...path, tupleError.reason.index]);
|
|
2114
2242
|
}
|
|
2115
2243
|
if (error.type === "Union") {
|
|
2116
2244
|
const unionError = error;
|
|
2117
|
-
return unionError.errors.flatMap((err) => typeErrorToStandardSchemaIssues(err,
|
|
2245
|
+
return unionError.errors.flatMap((err) => typeErrorToStandardSchemaIssues(err, path));
|
|
2118
2246
|
}
|
|
2119
2247
|
if (error.type === "Brand") {
|
|
2120
2248
|
const brandError = error;
|
|
2121
2249
|
if ("parentError" in brandError) {
|
|
2122
|
-
return typeErrorToStandardSchemaIssues(brandError.parentError,
|
|
2250
|
+
return typeErrorToStandardSchemaIssues(brandError.parentError, path);
|
|
2123
2251
|
}
|
|
2124
|
-
return [{ message:
|
|
2252
|
+
return [{ message: JSON.stringify(error), path }];
|
|
2125
2253
|
}
|
|
2126
|
-
return [{ message:
|
|
2254
|
+
return [{ message: JSON.stringify(error), path }];
|
|
2127
2255
|
};
|
|
2128
|
-
/**
|
|
2129
|
-
* Shared formatter cache for Standard Schema integration - avoids circular
|
|
2130
|
-
* dependency by lazily creating the formatter on first use rather than during
|
|
2131
|
-
* module initialization.
|
|
2132
|
-
*/
|
|
2133
|
-
let cachedStandardSchemaFormatTypeError;
|