@evolu/common 8.9.0 → 8.11.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/dist/src/Bytes.d.ts +647 -0
- package/dist/src/Bytes.d.ts.map +1 -0
- package/dist/src/{Binary.js → Bytes.js} +266 -16
- package/dist/src/Config.d.ts +142 -0
- package/dist/src/Config.d.ts.map +1 -0
- package/dist/src/Config.js +181 -0
- package/dist/src/Console.d.ts +62 -7
- package/dist/src/Console.d.ts.map +1 -1
- package/dist/src/Console.js +20 -4
- package/dist/src/Crypto.d.ts +76 -4
- package/dist/src/Crypto.d.ts.map +1 -1
- package/dist/src/Crypto.js +55 -4
- package/dist/src/Error.d.ts +45 -0
- package/dist/src/Error.d.ts.map +1 -1
- package/dist/src/Error.js +69 -0
- package/dist/src/Fs.d.ts +376 -0
- package/dist/src/Fs.d.ts.map +1 -0
- package/dist/src/Fs.js +113 -0
- package/dist/src/Identicon.d.ts +2 -2
- package/dist/src/Identicon.js +2 -2
- package/dist/src/LeakDetector.d.ts +22 -3
- package/dist/src/LeakDetector.d.ts.map +1 -1
- package/dist/src/LeakDetector.js +12 -2
- package/dist/src/LockManager.d.ts +8 -0
- package/dist/src/LockManager.d.ts.map +1 -1
- package/dist/src/LockManager.js +6 -0
- package/dist/src/Number.d.ts +50 -7
- package/dist/src/Number.d.ts.map +1 -1
- package/dist/src/Number.js +47 -8
- package/dist/src/Object.d.ts +32 -0
- package/dist/src/Object.d.ts.map +1 -1
- package/dist/src/Object.js +46 -0
- package/dist/src/Platform.d.ts +47 -7
- package/dist/src/Platform.d.ts.map +1 -1
- package/dist/src/Platform.js +24 -5
- package/dist/src/Random.d.ts +25 -2
- package/dist/src/Random.d.ts.map +1 -1
- package/dist/src/Random.js +14 -2
- package/dist/src/Resource.d.ts +156 -1
- package/dist/src/Resource.d.ts.map +1 -1
- package/dist/src/Resource.js +201 -72
- package/dist/src/Schedule.d.ts +11 -10
- package/dist/src/Schedule.d.ts.map +1 -1
- package/dist/src/Schedule.js +1 -1
- package/dist/src/Sqlite.d.ts +132 -16
- package/dist/src/Sqlite.d.ts.map +1 -1
- package/dist/src/Sqlite.js +64 -10
- package/dist/src/Task.d.ts +15 -4
- package/dist/src/Task.d.ts.map +1 -1
- package/dist/src/Task.js +41 -15
- package/dist/src/Test.d.ts +9 -0
- package/dist/src/Test.d.ts.map +1 -1
- package/dist/src/Test.js +4 -0
- package/dist/src/Time.d.ts +179 -20
- package/dist/src/Time.d.ts.map +1 -1
- package/dist/src/Time.js +95 -6
- package/dist/src/Type.d.ts +3056 -1539
- package/dist/src/Type.d.ts.map +1 -1
- package/dist/src/Type.js +2548 -584
- package/dist/src/WebSocket.d.ts +164 -13
- package/dist/src/WebSocket.d.ts.map +1 -1
- package/dist/src/WebSocket.js +133 -24
- package/dist/src/Worker.d.ts +90 -8
- package/dist/src/Worker.d.ts.map +1 -1
- package/dist/src/Worker.js +28 -2
- package/dist/src/index.d.ts +9 -8
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +5 -4
- package/dist/src/intl/_en.d.ts +24 -1
- package/dist/src/intl/_en.d.ts.map +1 -1
- package/dist/src/intl/_en.js +20 -0
- package/dist/src/intl/ar.d.ts +24 -1
- package/dist/src/intl/ar.d.ts.map +1 -1
- package/dist/src/intl/ar.js +20 -0
- package/dist/src/intl/bn.d.ts +24 -1
- package/dist/src/intl/bn.d.ts.map +1 -1
- package/dist/src/intl/bn.js +20 -0
- package/dist/src/intl/ca.d.ts +24 -1
- package/dist/src/intl/ca.d.ts.map +1 -1
- package/dist/src/intl/ca.js +20 -0
- package/dist/src/intl/cs.d.ts +24 -1
- package/dist/src/intl/cs.d.ts.map +1 -1
- package/dist/src/intl/cs.js +20 -0
- package/dist/src/intl/da.d.ts +24 -1
- package/dist/src/intl/da.d.ts.map +1 -1
- package/dist/src/intl/da.js +20 -0
- package/dist/src/intl/de.d.ts +24 -1
- package/dist/src/intl/de.d.ts.map +1 -1
- package/dist/src/intl/de.js +20 -0
- package/dist/src/intl/el.d.ts +24 -1
- package/dist/src/intl/el.d.ts.map +1 -1
- package/dist/src/intl/el.js +20 -0
- package/dist/src/intl/es.d.ts +24 -1
- package/dist/src/intl/es.d.ts.map +1 -1
- package/dist/src/intl/es.js +20 -0
- package/dist/src/intl/fa.d.ts +24 -1
- package/dist/src/intl/fa.d.ts.map +1 -1
- package/dist/src/intl/fa.js +20 -0
- package/dist/src/intl/fi.d.ts +24 -1
- package/dist/src/intl/fi.d.ts.map +1 -1
- package/dist/src/intl/fi.js +20 -0
- package/dist/src/intl/fil.d.ts +24 -1
- package/dist/src/intl/fil.d.ts.map +1 -1
- package/dist/src/intl/fil.js +20 -0
- package/dist/src/intl/fr.d.ts +24 -1
- package/dist/src/intl/fr.d.ts.map +1 -1
- package/dist/src/intl/fr.js +20 -0
- package/dist/src/intl/he.d.ts +24 -1
- package/dist/src/intl/he.d.ts.map +1 -1
- package/dist/src/intl/he.js +20 -0
- package/dist/src/intl/hi.d.ts +24 -1
- package/dist/src/intl/hi.d.ts.map +1 -1
- package/dist/src/intl/hi.js +20 -0
- package/dist/src/intl/hr.d.ts +24 -1
- package/dist/src/intl/hr.d.ts.map +1 -1
- package/dist/src/intl/hr.js +20 -0
- package/dist/src/intl/hu.d.ts +22 -1
- package/dist/src/intl/hu.d.ts.map +1 -1
- package/dist/src/intl/hu.js +18 -0
- package/dist/src/intl/id.d.ts +24 -1
- package/dist/src/intl/id.d.ts.map +1 -1
- package/dist/src/intl/id.js +20 -0
- package/dist/src/intl/it.d.ts +24 -1
- package/dist/src/intl/it.d.ts.map +1 -1
- package/dist/src/intl/it.js +20 -0
- package/dist/src/intl/ja.d.ts +24 -1
- package/dist/src/intl/ja.d.ts.map +1 -1
- package/dist/src/intl/ja.js +20 -0
- package/dist/src/intl/ko.d.ts +24 -1
- package/dist/src/intl/ko.d.ts.map +1 -1
- package/dist/src/intl/ko.js +20 -0
- package/dist/src/intl/ml.d.ts +24 -1
- package/dist/src/intl/ml.d.ts.map +1 -1
- package/dist/src/intl/ml.js +20 -0
- package/dist/src/intl/mr.d.ts +24 -1
- package/dist/src/intl/mr.d.ts.map +1 -1
- package/dist/src/intl/mr.js +20 -0
- package/dist/src/intl/ms.d.ts +24 -1
- package/dist/src/intl/ms.d.ts.map +1 -1
- package/dist/src/intl/ms.js +20 -0
- package/dist/src/intl/nb.d.ts +22 -1
- package/dist/src/intl/nb.d.ts.map +1 -1
- package/dist/src/intl/nb.js +18 -0
- package/dist/src/intl/nl.d.ts +24 -1
- package/dist/src/intl/nl.d.ts.map +1 -1
- package/dist/src/intl/nl.js +20 -0
- package/dist/src/intl/pa.d.ts +24 -1
- package/dist/src/intl/pa.d.ts.map +1 -1
- package/dist/src/intl/pa.js +20 -0
- package/dist/src/intl/pl.d.ts +23 -0
- package/dist/src/intl/pl.d.ts.map +1 -1
- package/dist/src/intl/pl.js +20 -0
- package/dist/src/intl/pt-BR.d.ts +24 -1
- package/dist/src/intl/pt-BR.d.ts.map +1 -1
- package/dist/src/intl/pt-BR.js +20 -0
- package/dist/src/intl/pt.d.ts +24 -1
- package/dist/src/intl/pt.d.ts.map +1 -1
- package/dist/src/intl/pt.js +20 -0
- package/dist/src/intl/ro.d.ts +24 -1
- package/dist/src/intl/ro.d.ts.map +1 -1
- package/dist/src/intl/ro.js +20 -0
- package/dist/src/intl/sk.d.ts +24 -1
- package/dist/src/intl/sk.d.ts.map +1 -1
- package/dist/src/intl/sk.js +20 -0
- package/dist/src/intl/sl.d.ts +24 -1
- package/dist/src/intl/sl.d.ts.map +1 -1
- package/dist/src/intl/sl.js +20 -0
- package/dist/src/intl/sv.d.ts +24 -1
- package/dist/src/intl/sv.d.ts.map +1 -1
- package/dist/src/intl/sv.js +20 -0
- package/dist/src/intl/sw.d.ts +21 -0
- package/dist/src/intl/sw.d.ts.map +1 -1
- package/dist/src/intl/sw.js +18 -0
- package/dist/src/intl/ta.d.ts +24 -1
- package/dist/src/intl/ta.d.ts.map +1 -1
- package/dist/src/intl/ta.js +20 -0
- package/dist/src/intl/te.d.ts +24 -1
- package/dist/src/intl/te.d.ts.map +1 -1
- package/dist/src/intl/te.js +20 -0
- package/dist/src/intl/th.d.ts +24 -1
- package/dist/src/intl/th.d.ts.map +1 -1
- package/dist/src/intl/th.js +20 -0
- package/dist/src/intl/tr.d.ts +24 -1
- package/dist/src/intl/tr.d.ts.map +1 -1
- package/dist/src/intl/tr.js +20 -0
- package/dist/src/intl/uk.d.ts +80 -57
- package/dist/src/intl/uk.d.ts.map +1 -1
- package/dist/src/intl/uk.js +174 -149
- package/dist/src/intl/ur.d.ts +24 -1
- package/dist/src/intl/ur.d.ts.map +1 -1
- package/dist/src/intl/ur.js +20 -0
- package/dist/src/intl/vi.d.ts +24 -1
- package/dist/src/intl/vi.d.ts.map +1 -1
- package/dist/src/intl/vi.js +20 -0
- package/dist/src/intl/zh-CN.d.ts +24 -1
- package/dist/src/intl/zh-CN.d.ts.map +1 -1
- package/dist/src/intl/zh-CN.js +20 -0
- package/dist/src/intl/zh-TW.d.ts +24 -1
- package/dist/src/intl/zh-TW.d.ts.map +1 -1
- package/dist/src/intl/zh-TW.js +20 -0
- package/dist/src/local-first/Db.d.ts +52 -3
- package/dist/src/local-first/Db.d.ts.map +1 -1
- package/dist/src/local-first/Db.js +412 -137
- package/dist/src/local-first/Evolu.d.ts +336 -211
- package/dist/src/local-first/Evolu.d.ts.map +1 -1
- package/dist/src/local-first/Evolu.js +102 -15
- package/dist/src/local-first/Owner.d.ts +13 -30
- package/dist/src/local-first/Owner.d.ts.map +1 -1
- package/dist/src/local-first/Owner.js +13 -30
- package/dist/src/local-first/Protocol.d.ts +95 -17
- package/dist/src/local-first/Protocol.d.ts.map +1 -1
- package/dist/src/local-first/Protocol.js +119 -39
- package/dist/src/local-first/Query.d.ts +8 -15
- package/dist/src/local-first/Query.d.ts.map +1 -1
- package/dist/src/local-first/Schema.d.ts +345 -21
- package/dist/src/local-first/Schema.d.ts.map +1 -1
- package/dist/src/local-first/Schema.js +214 -17
- package/dist/src/local-first/Shared.d.ts +537 -22
- package/dist/src/local-first/Shared.d.ts.map +1 -1
- package/dist/src/local-first/Shared.js +1437 -234
- package/dist/src/local-first/Storage.d.ts +192 -14
- package/dist/src/local-first/Storage.d.ts.map +1 -1
- package/dist/src/local-first/Storage.js +82 -21
- package/dist/src/local-first/Timestamp.d.ts +392 -41
- package/dist/src/local-first/Timestamp.d.ts.map +1 -1
- package/dist/src/local-first/Timestamp.js +404 -82
- package/dist/src/local-first/index.d.ts +0 -1
- package/dist/src/local-first/index.d.ts.map +1 -1
- package/dist/src/local-first/index.js +0 -1
- package/package.json +1 -1
- package/src/Assert.test.ts +2 -5
- package/src/{Binary.test.ts → Bytes.test.ts} +286 -1
- package/src/{Binary.ts → Bytes.ts} +652 -21
- package/src/Config.test.ts +668 -0
- package/src/Config.ts +410 -0
- package/src/Console.ts +62 -7
- package/src/Crypto.ts +76 -4
- package/src/Eq.test.ts +2 -3
- package/src/Error.test.ts +76 -3
- package/src/Error.ts +71 -0
- package/src/Fs.test.ts +105 -0
- package/src/Fs.ts +488 -0
- package/src/Identicon.ts +2 -2
- package/src/LeakDetector.ts +22 -3
- package/src/LockManager.ts +8 -0
- package/src/Number.test.ts +82 -18
- package/src/Number.ts +76 -8
- package/src/Object.test.ts +139 -10
- package/src/Object.ts +49 -0
- package/src/Platform.ts +50 -8
- package/src/Random.ts +25 -2
- package/src/Resource.test.ts +837 -0
- package/src/Resource.ts +235 -15
- package/src/Schedule.test.ts +50 -12
- package/src/Schedule.ts +24 -14
- package/src/Sqlite.ts +138 -18
- package/src/Task.test.ts +189 -8
- package/src/Task.ts +56 -17
- package/src/Test.ts +9 -0
- package/src/Time.test.ts +82 -11
- package/src/Time.ts +246 -24
- package/src/Type.test.ts +3994 -1119
- package/src/Type.ts +7258 -3842
- package/src/Types.test.ts +4 -14
- package/src/WebSocket.ts +313 -40
- package/src/Worker.ts +90 -8
- package/src/index.ts +18 -7
- package/src/intl/_en.ts +70 -0
- package/src/intl/ar.ts +71 -0
- package/src/intl/bn.ts +70 -0
- package/src/intl/ca.ts +70 -0
- package/src/intl/cs.ts +70 -0
- package/src/intl/da.ts +70 -0
- package/src/intl/de.ts +70 -0
- package/src/intl/el.ts +70 -0
- package/src/intl/es.ts +70 -0
- package/src/intl/fa.ts +70 -0
- package/src/intl/fi.ts +70 -0
- package/src/intl/fil.ts +70 -0
- package/src/intl/fr.ts +70 -0
- package/src/intl/he.ts +70 -0
- package/src/intl/hi.ts +70 -0
- package/src/intl/hr.ts +70 -0
- package/src/intl/hu.ts +69 -0
- package/src/intl/id.ts +70 -0
- package/src/intl/intl.test.ts +819 -1
- package/src/intl/it.ts +70 -0
- package/src/intl/ja.ts +70 -0
- package/src/intl/ko.ts +68 -0
- package/src/intl/ml.ts +70 -0
- package/src/intl/mr.ts +70 -0
- package/src/intl/ms.ts +71 -0
- package/src/intl/nb.ts +69 -0
- package/src/intl/nl.ts +70 -0
- package/src/intl/pa.ts +70 -0
- package/src/intl/pl.ts +63 -0
- package/src/intl/pt-BR.ts +70 -0
- package/src/intl/pt.ts +71 -0
- package/src/intl/ro.ts +70 -0
- package/src/intl/sk.ts +71 -0
- package/src/intl/sl.ts +70 -0
- package/src/intl/sv.ts +70 -0
- package/src/intl/sw.ts +62 -0
- package/src/intl/ta.ts +70 -0
- package/src/intl/te.ts +70 -0
- package/src/intl/th.ts +68 -0
- package/src/intl/tr.ts +70 -0
- package/src/intl/uk.ts +228 -155
- package/src/intl/ur.ts +70 -0
- package/src/intl/vi.ts +70 -0
- package/src/intl/zh-CN.ts +68 -0
- package/src/intl/zh-TW.ts +68 -0
- package/src/local-first/Db.ts +644 -339
- package/src/local-first/Evolu.test.ts +686 -21
- package/src/local-first/Evolu.ts +450 -228
- package/src/local-first/Owner.ts +13 -30
- package/src/local-first/Protocol.test.ts +618 -11
- package/src/local-first/Protocol.ts +197 -73
- package/src/local-first/Query.ts +8 -15
- package/src/local-first/Schema.test.ts +143 -0
- package/src/local-first/Schema.ts +374 -24
- package/src/local-first/Shared.test.ts +7731 -559
- package/src/local-first/Shared.ts +2036 -267
- package/src/local-first/Storage.ts +219 -33
- package/src/local-first/Timestamp.test.ts +344 -70
- package/src/local-first/Timestamp.ts +435 -119
- package/src/local-first/index.ts +0 -1
- package/dist/src/Binary.d.ts +0 -254
- package/dist/src/Binary.d.ts.map +0 -1
- package/dist/src/local-first/Error.d.ts +0 -12
- package/dist/src/local-first/Error.d.ts.map +0 -1
- package/dist/src/local-first/Error.js +0 -6
- package/dist/src/local-first/LocalAuth.d.ts +0 -150
- package/dist/src/local-first/LocalAuth.d.ts.map +0 -1
- package/dist/src/local-first/LocalAuth.js +0 -179
- package/src/local-first/Error.ts +0 -17
- package/src/local-first/LocalAuth.ts +0 -457
package/src/Config.ts
ADDED
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Strict configuration Types with explicit application policy.
|
|
3
|
+
*
|
|
4
|
+
* Decode configuration at startup, then pass validated values to constructors
|
|
5
|
+
* or Tasks. The application decides how to load configuration, combine sources,
|
|
6
|
+
* and apply defaults. Declare defaults with {@link withDefault}, or use `??`
|
|
7
|
+
* where a value is consumed. Invalid supplied values still fail decoding.
|
|
8
|
+
*
|
|
9
|
+
* Resolve source precedence before replacing absence with defaults. If a source
|
|
10
|
+
* Type already provides defaults and later composition needs to distinguish
|
|
11
|
+
* them from supplied values, use `strategy: "preserve"` and inspect
|
|
12
|
+
* `defaultUsed` explicitly. Preserving this evidence does not choose a merging
|
|
13
|
+
* policy: the application still decides which source wins.
|
|
14
|
+
*
|
|
15
|
+
* {@link env} creates a pure, reversible codec. It does not read global state,
|
|
16
|
+
* load files, merge sources, or introduce a Run dependency. Tests can pass
|
|
17
|
+
* ordinary objects; a Node.js entry point can pass `process.env`.
|
|
18
|
+
*
|
|
19
|
+
* @module
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { assert } from "./Assert.ts";
|
|
23
|
+
import {
|
|
24
|
+
createMutableRecord,
|
|
25
|
+
filterObjectKeys,
|
|
26
|
+
isPlainObject,
|
|
27
|
+
} from "./Object.ts";
|
|
28
|
+
import { ok } from "./Result.ts";
|
|
29
|
+
import {
|
|
30
|
+
CamelCaseIdentifier,
|
|
31
|
+
camelCaseToConstantCase,
|
|
32
|
+
ConstantCaseIdentifier,
|
|
33
|
+
EvoluType,
|
|
34
|
+
maxLength,
|
|
35
|
+
object,
|
|
36
|
+
objectKeys,
|
|
37
|
+
String,
|
|
38
|
+
transform,
|
|
39
|
+
Unknown,
|
|
40
|
+
type AnyType,
|
|
41
|
+
type InferErrors,
|
|
42
|
+
type ValidateLiteral,
|
|
43
|
+
type ObjectKeysType,
|
|
44
|
+
type ObjectProps,
|
|
45
|
+
type ObjectType,
|
|
46
|
+
type TransformType,
|
|
47
|
+
type TypeNode,
|
|
48
|
+
type withDefault,
|
|
49
|
+
} from "./Type.ts";
|
|
50
|
+
import type {
|
|
51
|
+
CompileTimeError,
|
|
52
|
+
IsUnion,
|
|
53
|
+
UnionToIntersection,
|
|
54
|
+
} from "./Types.ts";
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* An environment variable name in Evolu's configuration convention.
|
|
58
|
+
*
|
|
59
|
+
* Names are {@link ConstantCaseIdentifier}s of at most 255 characters, including
|
|
60
|
+
* the application prefix. This is an Evolu convention, not an operating-system
|
|
61
|
+
* limit. Double underscores do not introduce nesting.
|
|
62
|
+
*
|
|
63
|
+
* ### Example
|
|
64
|
+
*
|
|
65
|
+
* ```ts
|
|
66
|
+
* import { assertErr, assertOk, EnvName } from "@evolu/common";
|
|
67
|
+
*
|
|
68
|
+
* assertOk(
|
|
69
|
+
* EnvName.fromUnknown("APP_MAX_OWNER_BYTES"),
|
|
70
|
+
* "APP_MAX_OWNER_BYTES",
|
|
71
|
+
* );
|
|
72
|
+
* assertErr(EnvName.fromUnknown("APP_maxOwnerBytes"));
|
|
73
|
+
* assertErr(EnvName.fromUnknown("APP_DB__PORT"));
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
export const EnvName = /*#__PURE__*/ maxLength(255)(ConstantCaseIdentifier);
|
|
77
|
+
export type EnvName = typeof EnvName.Output;
|
|
78
|
+
|
|
79
|
+
/** The configuration codec returned by {@link env}. */
|
|
80
|
+
export interface EnvType<Props extends EnvProps> extends TransformType<
|
|
81
|
+
typeof Unknown,
|
|
82
|
+
ObjectKeysType<EnvKeyType, ObjectType<EnvFlatProps<Props>>>,
|
|
83
|
+
"Env",
|
|
84
|
+
never,
|
|
85
|
+
Readonly<
|
|
86
|
+
Record<
|
|
87
|
+
string,
|
|
88
|
+
ObjectType<EnvFlatProps<Props>>["CanonicalInput"][keyof ObjectType<
|
|
89
|
+
EnvFlatProps<Props>
|
|
90
|
+
>["CanonicalInput"]]
|
|
91
|
+
>
|
|
92
|
+
>
|
|
93
|
+
> {}
|
|
94
|
+
|
|
95
|
+
/** Fields and one-level namespace groups used to construct an {@link env} Type. */
|
|
96
|
+
export type EnvProps = Readonly<
|
|
97
|
+
Record<string, ObjectProps[string] | ObjectProps>
|
|
98
|
+
>;
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Creates a reversible environment-variable codec with a flat decoded output.
|
|
102
|
+
*
|
|
103
|
+
* Declare camelCase fields directly, or put them in one-level CONSTANT_CASE
|
|
104
|
+
* namespace groups. A direct `port` field reads `PORT`; a `maxOwnerBytes` field
|
|
105
|
+
* in an `EVOLU_RELAY` group reads `EVOLU_RELAY_MAX_OWNER_BYTES`. Groups affect
|
|
106
|
+
* external names only. Duplicate decoded fields or encoded names are rejected
|
|
107
|
+
* during construction, even when their Types are identical.
|
|
108
|
+
*
|
|
109
|
+
* Selects exact declared unprefixed names and all keys within declared
|
|
110
|
+
* namespaces. Namespace selection ignores casing so incorrectly cased names
|
|
111
|
+
* fail validation instead of being ignored. Selected names must match their
|
|
112
|
+
* exact declared spelling. Unrelated variables are ignored; misspelled
|
|
113
|
+
* unprefixed names or namespace prefixes can therefore still look absent.
|
|
114
|
+
*
|
|
115
|
+
* Field Types must encode to strings. Optional fields may be absent, but
|
|
116
|
+
* explicit `undefined` values are rejected. Empty strings remain present and
|
|
117
|
+
* must satisfy the field Type. Compose {@link withDefault} to supply defaults.
|
|
118
|
+
* Encoding emits canonical external names and string values, preserving absence
|
|
119
|
+
* when the field codec does. Errors retain external names and nested paths.
|
|
120
|
+
*
|
|
121
|
+
* Reads own string properties from any non-null object, including
|
|
122
|
+
* `process.env`. Selected properties must be enumerable data properties;
|
|
123
|
+
* getters are never read. Prototypes and internal contents such as Map entries
|
|
124
|
+
* are ignored. Non-object inputs fail with standard object errors. Schema names
|
|
125
|
+
* must satisfy {@link EnvName}; groups cannot be nested. Loading and source
|
|
126
|
+
* precedence remain explicit application code.
|
|
127
|
+
*
|
|
128
|
+
* ### Example
|
|
129
|
+
*
|
|
130
|
+
* ```ts
|
|
131
|
+
* import {
|
|
132
|
+
* assertEqual,
|
|
133
|
+
* assertErr,
|
|
134
|
+
* assertOk,
|
|
135
|
+
* assertType,
|
|
136
|
+
* ByteSizeLiteral,
|
|
137
|
+
* env,
|
|
138
|
+
* optional,
|
|
139
|
+
* Port,
|
|
140
|
+
* PortFromString,
|
|
141
|
+
* withDefault,
|
|
142
|
+
* } from "@evolu/common";
|
|
143
|
+
*
|
|
144
|
+
* const RelayEnv = env({
|
|
145
|
+
* port: withDefault(optional(PortFromString), Port.orThrow(4000)),
|
|
146
|
+
* EVOLU_RELAY: {
|
|
147
|
+
* maxOwnerBytes: optional(ByteSizeLiteral),
|
|
148
|
+
* },
|
|
149
|
+
* });
|
|
150
|
+
*
|
|
151
|
+
* const result = RelayEnv.fromUnknown({
|
|
152
|
+
* PORT: "04000",
|
|
153
|
+
* EVOLU_RELAY_MAX_OWNER_BYTES: "512KiB",
|
|
154
|
+
* HOME: "/home/evolu",
|
|
155
|
+
* });
|
|
156
|
+
*
|
|
157
|
+
* assertOk(result, { port: 4000, maxOwnerBytes: "512KiB" });
|
|
158
|
+
* assertType<typeof result.value.port, Port>();
|
|
159
|
+
* assertEqual(RelayEnv.to(result.value), {
|
|
160
|
+
* PORT: "4000",
|
|
161
|
+
* EVOLU_RELAY_MAX_OWNER_BYTES: "512KiB",
|
|
162
|
+
* });
|
|
163
|
+
*
|
|
164
|
+
* assertOk(RelayEnv.fromUnknown({}), { port: 4000 });
|
|
165
|
+
* assertErr(RelayEnv.fromUnknown({ PORT: "" }));
|
|
166
|
+
* assertErr(RelayEnv.fromUnknown({ EVOLU_RELAY_MAX_OWENR_BYTES: "1MiB" }));
|
|
167
|
+
* assertErr(RelayEnv.fromUnknown({ evolu_relay_max_owner_bytes: "1MiB" }));
|
|
168
|
+
* ```
|
|
169
|
+
*/
|
|
170
|
+
export const env = <const Props extends EnvProps>(
|
|
171
|
+
props: Props,
|
|
172
|
+
..._validation: [EnvValidation<Props>] extends [never]
|
|
173
|
+
? []
|
|
174
|
+
: [EnvValidation<Props>]
|
|
175
|
+
): EnvType<Props> => {
|
|
176
|
+
assert(
|
|
177
|
+
isPlainObject(props),
|
|
178
|
+
"Environment properties must be a plain object.",
|
|
179
|
+
);
|
|
180
|
+
const flat = createMutableRecord<string, ObjectProps[string]>();
|
|
181
|
+
const inputNameByOutputName = new Map<string, string>();
|
|
182
|
+
const outputNameByInputName = new Map<string, string>();
|
|
183
|
+
const prefixes: Array<string> = [];
|
|
184
|
+
const unprefixedNames = new Set<string>();
|
|
185
|
+
|
|
186
|
+
for (const rootName of Reflect.ownKeys(props)) {
|
|
187
|
+
const descriptor = Object.getOwnPropertyDescriptor(props, rootName)!;
|
|
188
|
+
assert(
|
|
189
|
+
typeof rootName === "string" &&
|
|
190
|
+
descriptor.enumerable &&
|
|
191
|
+
"value" in descriptor,
|
|
192
|
+
"Environment properties must be enumerable string data properties.",
|
|
193
|
+
);
|
|
194
|
+
const grouped = ConstantCaseIdentifier.is(rootName);
|
|
195
|
+
assert(
|
|
196
|
+
grouped || CamelCaseIdentifier.is(rootName),
|
|
197
|
+
`Invalid environment schema name ${JSON.stringify(rootName)}. Expected a camelCase field or CONSTANT_CASE namespace.`,
|
|
198
|
+
);
|
|
199
|
+
const rootValue: unknown = descriptor.value;
|
|
200
|
+
const fields = grouped ? rootValue : { [rootName]: rootValue };
|
|
201
|
+
assert(
|
|
202
|
+
isPlainObject(fields) && !EvoluType.is(fields),
|
|
203
|
+
"Environment groups must be plain objects containing fields.",
|
|
204
|
+
);
|
|
205
|
+
if (grouped) {
|
|
206
|
+
assert(
|
|
207
|
+
EnvName.is(rootName + "_A"),
|
|
208
|
+
`Invalid environment namespace ${JSON.stringify(rootName)}. Names must fit within 255 characters.`,
|
|
209
|
+
);
|
|
210
|
+
prefixes.push(rootName + "_");
|
|
211
|
+
}
|
|
212
|
+
for (const name of Reflect.ownKeys(fields)) {
|
|
213
|
+
const field = Object.getOwnPropertyDescriptor(fields, name)!;
|
|
214
|
+
assert(
|
|
215
|
+
typeof name === "string" && field.enumerable && "value" in field,
|
|
216
|
+
"Environment fields must be enumerable string data properties.",
|
|
217
|
+
);
|
|
218
|
+
assert(
|
|
219
|
+
CamelCaseIdentifier.is(name),
|
|
220
|
+
`Invalid environment field ${JSON.stringify(name)}. Expected a camelCase identifier; groups cannot be nested.`,
|
|
221
|
+
);
|
|
222
|
+
assert(
|
|
223
|
+
!inputNameByOutputName.has(name),
|
|
224
|
+
`Duplicate environment field ${JSON.stringify(name)}.`,
|
|
225
|
+
);
|
|
226
|
+
const encoded =
|
|
227
|
+
(grouped ? rootName + "_" : "") + camelCaseToConstantCase(name);
|
|
228
|
+
assert(
|
|
229
|
+
EnvName.is(encoded),
|
|
230
|
+
`Invalid environment schema name ${JSON.stringify(encoded)}. Expected a CONSTANT_CASE identifier of at most 255 characters.`,
|
|
231
|
+
);
|
|
232
|
+
assert(
|
|
233
|
+
!outputNameByInputName.has(encoded),
|
|
234
|
+
`Duplicate environment variable ${JSON.stringify(encoded)}.`,
|
|
235
|
+
);
|
|
236
|
+
const property: unknown = field.value;
|
|
237
|
+
const fieldType: unknown = EvoluType.is(property)
|
|
238
|
+
? property
|
|
239
|
+
: isPlainObject(property)
|
|
240
|
+
? Object.getOwnPropertyDescriptor(property, "type")?.value
|
|
241
|
+
: undefined;
|
|
242
|
+
assert(
|
|
243
|
+
EvoluType.is(fieldType),
|
|
244
|
+
`Invalid environment field ${JSON.stringify(name)}. Expected a Type or optional/defaulted property; groups must use CONSTANT_CASE names.`,
|
|
245
|
+
);
|
|
246
|
+
flat[name] = property as ObjectProps[string];
|
|
247
|
+
inputNameByOutputName.set(name, encoded);
|
|
248
|
+
outputNameByInputName.set(encoded, name);
|
|
249
|
+
if (!grouped) unprefixedNames.add(encoded);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Runtime construction validates the flattened fields; the public signature
|
|
254
|
+
// checks their concrete Types and string encodings before flattening.
|
|
255
|
+
const output = (
|
|
256
|
+
object as unknown as (props: ObjectProps) => ObjectType<ObjectProps>
|
|
257
|
+
)(flat);
|
|
258
|
+
const key = transform("EnvKey", String, CamelCaseIdentifier, {
|
|
259
|
+
// Identity fallback keeps this exposed codec round-trippable for other
|
|
260
|
+
// valid camelCase identifiers. objectKeys accepts only declared fields.
|
|
261
|
+
from: (value) => ok(outputNameByInputName.get(value) ?? value),
|
|
262
|
+
to: (value) => inputNameByOutputName.get(value) ?? value,
|
|
263
|
+
});
|
|
264
|
+
const withKeys = objectKeys(key)(output);
|
|
265
|
+
const type = transform("Env", Unknown, withKeys, {
|
|
266
|
+
from: (value) => {
|
|
267
|
+
if (typeof value !== "object" || value === null) return ok(value);
|
|
268
|
+
return ok(
|
|
269
|
+
filterObjectKeys(
|
|
270
|
+
value,
|
|
271
|
+
(key) =>
|
|
272
|
+
unprefixedNames.has(key) ||
|
|
273
|
+
prefixes.some((prefix) => key.toUpperCase().startsWith(prefix)),
|
|
274
|
+
),
|
|
275
|
+
);
|
|
276
|
+
},
|
|
277
|
+
to: (value) => value,
|
|
278
|
+
});
|
|
279
|
+
// The maps preserve each field's name and codec; only the static flattening
|
|
280
|
+
// cannot be expressed by the runtime loops above.
|
|
281
|
+
return type as unknown as EnvType<Props>;
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
type EnvFlatProps<Props extends EnvProps> =
|
|
285
|
+
UnionToIntersection<
|
|
286
|
+
{
|
|
287
|
+
[Key in keyof Props]: EnvDeclarationKind<Key> extends "group"
|
|
288
|
+
? Props[Key]
|
|
289
|
+
: EnvDeclarationKind<Key> extends "field"
|
|
290
|
+
? { readonly [Field in Key]: Props[Key] }
|
|
291
|
+
: never;
|
|
292
|
+
}[keyof Props]
|
|
293
|
+
> extends infer Flat extends ObjectProps
|
|
294
|
+
? Flat
|
|
295
|
+
: {};
|
|
296
|
+
|
|
297
|
+
type EnvKeyType = TransformType<
|
|
298
|
+
typeof String,
|
|
299
|
+
typeof CamelCaseIdentifier,
|
|
300
|
+
"EnvKey",
|
|
301
|
+
never,
|
|
302
|
+
string
|
|
303
|
+
>;
|
|
304
|
+
|
|
305
|
+
type EnvValidation<Props extends EnvProps> =
|
|
306
|
+
| EnvKeysValidation<Props>
|
|
307
|
+
| {
|
|
308
|
+
[Key in keyof Props]: EnvDeclarationKind<Key> extends "group"
|
|
309
|
+
? Props[Key] extends ObjectProps
|
|
310
|
+
? EnvFieldsValidation<Props[Key]>
|
|
311
|
+
: CompileTimeError<
|
|
312
|
+
"Env",
|
|
313
|
+
"Environment namespaces must contain a group of fields."
|
|
314
|
+
>
|
|
315
|
+
: EnvDeclarationKind<Key> extends "field"
|
|
316
|
+
? Props[Key] extends ObjectProps[string]
|
|
317
|
+
? EnvFieldValidation<Props[Key]>
|
|
318
|
+
: CompileTimeError<
|
|
319
|
+
"Env",
|
|
320
|
+
"Environment fields must be Types, optional properties, or defaulted properties."
|
|
321
|
+
>
|
|
322
|
+
: CompileTimeError<
|
|
323
|
+
"Env",
|
|
324
|
+
"Environment declarations must use camelCase field names or CONSTANT_CASE namespace names."
|
|
325
|
+
>;
|
|
326
|
+
}[keyof Props];
|
|
327
|
+
|
|
328
|
+
type EnvFieldsValidation<Props extends ObjectProps> =
|
|
329
|
+
| EnvKeysValidation<Props>
|
|
330
|
+
| {
|
|
331
|
+
[Key in keyof Props]: EnvDeclarationKind<Key> extends "field"
|
|
332
|
+
? EnvFieldValidation<Props[Key]>
|
|
333
|
+
: CompileTimeError<
|
|
334
|
+
"Env",
|
|
335
|
+
"Environment fields must use camelCase names."
|
|
336
|
+
>;
|
|
337
|
+
}[keyof Props];
|
|
338
|
+
|
|
339
|
+
type EnvFieldValidation<Field> =
|
|
340
|
+
IsUnion<Field> extends true
|
|
341
|
+
? CompileTimeError<"Env", "Environment fields must use one concrete Type.">
|
|
342
|
+
: EnvFieldType<Field> extends infer T extends AnyType
|
|
343
|
+
? IsUnion<T> extends true
|
|
344
|
+
? CompileTimeError<
|
|
345
|
+
"Env",
|
|
346
|
+
"Environment fields must use one concrete Type."
|
|
347
|
+
>
|
|
348
|
+
: [T["CanonicalInput"]] extends [string]
|
|
349
|
+
? Extract<
|
|
350
|
+
| "ObjectMissingProperty"
|
|
351
|
+
| "ObjectPropertyAccess"
|
|
352
|
+
| "ObjectExcessProperty",
|
|
353
|
+
InferErrors<T>["type"]
|
|
354
|
+
> extends never
|
|
355
|
+
? never
|
|
356
|
+
: CompileTimeError<
|
|
357
|
+
"Env",
|
|
358
|
+
"Environment fields must not use error tags reserved for Object structure."
|
|
359
|
+
>
|
|
360
|
+
: CompileTimeError<
|
|
361
|
+
"Env",
|
|
362
|
+
"Environment fields must encode to strings."
|
|
363
|
+
>
|
|
364
|
+
: CompileTimeError<
|
|
365
|
+
"Env",
|
|
366
|
+
"Environment fields must use one concrete Type."
|
|
367
|
+
>;
|
|
368
|
+
|
|
369
|
+
type EnvFieldType<Field> = Field extends TypeNode
|
|
370
|
+
? Field
|
|
371
|
+
: Field extends { readonly type: infer T extends TypeNode }
|
|
372
|
+
? T
|
|
373
|
+
: never;
|
|
374
|
+
|
|
375
|
+
type EnvKeysValidation<Props> =
|
|
376
|
+
| (string extends keyof Props
|
|
377
|
+
? CompileTimeError<
|
|
378
|
+
"Env",
|
|
379
|
+
"Environment properties must use fixed string keys."
|
|
380
|
+
>
|
|
381
|
+
: never)
|
|
382
|
+
| (IsUnion<Props> extends true
|
|
383
|
+
? CompileTimeError<
|
|
384
|
+
"Env",
|
|
385
|
+
"Environment properties must use one concrete schema."
|
|
386
|
+
>
|
|
387
|
+
: never)
|
|
388
|
+
| {
|
|
389
|
+
[Key in keyof Props]: Key extends string
|
|
390
|
+
? ValidateLiteral<Key> extends Key
|
|
391
|
+
? never
|
|
392
|
+
: CompileTimeError<
|
|
393
|
+
"Env",
|
|
394
|
+
"Environment properties must use fixed string keys."
|
|
395
|
+
>
|
|
396
|
+
: CompileTimeError<
|
|
397
|
+
"Env",
|
|
398
|
+
"Environment properties must use fixed string keys."
|
|
399
|
+
>;
|
|
400
|
+
}[keyof Props];
|
|
401
|
+
|
|
402
|
+
// Classify declarations by casing; identifier Types validate the full grammar
|
|
403
|
+
// and name lengths during construction.
|
|
404
|
+
type EnvDeclarationKind<Key> = Key extends string
|
|
405
|
+
? Key extends Uppercase<Key>
|
|
406
|
+
? "group"
|
|
407
|
+
: Key extends Uncapitalize<Key>
|
|
408
|
+
? "field"
|
|
409
|
+
: "invalid"
|
|
410
|
+
: "invalid";
|
package/src/Console.ts
CHANGED
|
@@ -93,6 +93,7 @@ import {
|
|
|
93
93
|
* For testing, use {@link testCreateConsole} which creates a {@link TestConsole}
|
|
94
94
|
* with array output and snapshot helpers.
|
|
95
95
|
*
|
|
96
|
+
* @group Core
|
|
96
97
|
* @see {@link createConsole}
|
|
97
98
|
*/
|
|
98
99
|
export interface Console {
|
|
@@ -176,6 +177,11 @@ export interface Console {
|
|
|
176
177
|
readonly write: (entry: ConsoleEntry) => void;
|
|
177
178
|
}
|
|
178
179
|
|
|
180
|
+
/**
|
|
181
|
+
* Dependency wrapper for {@link Console}.
|
|
182
|
+
*
|
|
183
|
+
* @group Core
|
|
184
|
+
*/
|
|
179
185
|
export interface ConsoleDep {
|
|
180
186
|
readonly console: Console;
|
|
181
187
|
}
|
|
@@ -193,6 +199,8 @@ export interface ConsoleDep {
|
|
|
193
199
|
* - `"warn"` — Recoverable issues that may need attention
|
|
194
200
|
* - `"error"` — Failures requiring immediate attention
|
|
195
201
|
* - `"silent"` — Disables all logging
|
|
202
|
+
*
|
|
203
|
+
* @group Core
|
|
196
204
|
*/
|
|
197
205
|
export type ConsoleLevel =
|
|
198
206
|
"trace" | "debug" | "log" | "info" | "warn" | "error" | "silent";
|
|
@@ -202,6 +210,8 @@ export type ConsoleLevel =
|
|
|
202
210
|
*
|
|
203
211
|
* Contains all information needed for outputs to route the log: method for
|
|
204
212
|
* routing, path for context, and the original arguments.
|
|
213
|
+
*
|
|
214
|
+
* @group Core
|
|
205
215
|
*/
|
|
206
216
|
export interface ConsoleEntry {
|
|
207
217
|
/** The console method that was called. */
|
|
@@ -219,6 +229,8 @@ export interface ConsoleEntry {
|
|
|
219
229
|
*
|
|
220
230
|
* Used in {@link ConsoleEntry} to identify which console method was invoked.
|
|
221
231
|
* Outputs can route or format differently based on the method.
|
|
232
|
+
*
|
|
233
|
+
* @group Core
|
|
222
234
|
*/
|
|
223
235
|
export type ConsoleMethod =
|
|
224
236
|
| "trace"
|
|
@@ -242,6 +254,8 @@ export type ConsoleMethod =
|
|
|
242
254
|
* array for testing, etc.).
|
|
243
255
|
*
|
|
244
256
|
* Use {@link createNativeConsoleOutput} for native console output.
|
|
257
|
+
*
|
|
258
|
+
* @group Output
|
|
245
259
|
*/
|
|
246
260
|
export interface ConsoleOutput {
|
|
247
261
|
/** Write a log entry to this output. */
|
|
@@ -253,10 +267,16 @@ export interface ConsoleOutput {
|
|
|
253
267
|
*
|
|
254
268
|
* Used by {@link ConsoleConfig.formatter} and {@link ConsoleOutput.write}. Create
|
|
255
269
|
* one with {@link createConsoleFormatter}.
|
|
270
|
+
*
|
|
271
|
+
* @group Output
|
|
256
272
|
*/
|
|
257
273
|
export type ConsoleFormatter = (entry: ConsoleEntry) => ReadonlyArray<unknown>;
|
|
258
274
|
|
|
259
|
-
/**
|
|
275
|
+
/**
|
|
276
|
+
* Configuration for {@link createConsole}.
|
|
277
|
+
*
|
|
278
|
+
* @group Core
|
|
279
|
+
*/
|
|
260
280
|
export interface ConsoleConfig {
|
|
261
281
|
/** Name of this console. Defaults to empty string. */
|
|
262
282
|
readonly name?: string;
|
|
@@ -283,7 +303,11 @@ export interface ConsoleConfig {
|
|
|
283
303
|
readonly formatter?: ConsoleFormatter;
|
|
284
304
|
}
|
|
285
305
|
|
|
286
|
-
/**
|
|
306
|
+
/**
|
|
307
|
+
* Configuration for {@link createConsoleFormatter}.
|
|
308
|
+
*
|
|
309
|
+
* @group Output
|
|
310
|
+
*/
|
|
287
311
|
export interface ConsoleFormatterConfig {
|
|
288
312
|
/**
|
|
289
313
|
* Timestamp format to prepend to log messages.
|
|
@@ -304,7 +328,11 @@ export interface ConsoleFormatterConfig {
|
|
|
304
328
|
readonly startTime?: Millis;
|
|
305
329
|
}
|
|
306
330
|
|
|
307
|
-
/**
|
|
331
|
+
/**
|
|
332
|
+
* Timestamp format for {@link ConsoleFormatterConfig}.
|
|
333
|
+
*
|
|
334
|
+
* @group Output
|
|
335
|
+
*/
|
|
308
336
|
export type ConsoleEntryTimestampFormat =
|
|
309
337
|
"relative" | "absolute" | "iso" | "none";
|
|
310
338
|
|
|
@@ -341,6 +369,8 @@ export type ConsoleEntryTimestampFormat =
|
|
|
341
369
|
* args: ["connected"],
|
|
342
370
|
* });
|
|
343
371
|
* ```
|
|
372
|
+
*
|
|
373
|
+
* @group Output
|
|
344
374
|
*/
|
|
345
375
|
export interface ConsoleStoreOutput extends ConsoleOutput {
|
|
346
376
|
/** Latest entry written to this output. */
|
|
@@ -350,6 +380,8 @@ export interface ConsoleStoreOutput extends ConsoleOutput {
|
|
|
350
380
|
/**
|
|
351
381
|
* Dependency providing the latest {@link ConsoleEntry} from a
|
|
352
382
|
* {@link ConsoleStoreOutput}.
|
|
383
|
+
*
|
|
384
|
+
* @group Output
|
|
353
385
|
*/
|
|
354
386
|
export interface ConsoleStoreOutputEntryDep {
|
|
355
387
|
readonly consoleStoreOutputEntry: ReadonlyStore<ConsoleEntry | null>;
|
|
@@ -359,6 +391,8 @@ export interface ConsoleStoreOutputEntryDep {
|
|
|
359
391
|
* A test console that captures all output for assertions.
|
|
360
392
|
*
|
|
361
393
|
* Use as a drop-in replacement for {@link Console} in tests.
|
|
394
|
+
*
|
|
395
|
+
* @group Testing
|
|
362
396
|
*/
|
|
363
397
|
export interface TestConsole extends Console {
|
|
364
398
|
/** Gets all captured entries and clears the internal buffer. */
|
|
@@ -368,6 +402,11 @@ export interface TestConsole extends Console {
|
|
|
368
402
|
readonly clearEntries: () => void;
|
|
369
403
|
}
|
|
370
404
|
|
|
405
|
+
/**
|
|
406
|
+
* Dependency wrapper for {@link TestConsole}.
|
|
407
|
+
*
|
|
408
|
+
* @group Testing
|
|
409
|
+
*/
|
|
371
410
|
export interface TestConsoleDep {
|
|
372
411
|
readonly console: TestConsole;
|
|
373
412
|
}
|
|
@@ -382,7 +421,11 @@ const levelOrder: Record<ConsoleLevel, number> = {
|
|
|
382
421
|
silent: 6,
|
|
383
422
|
};
|
|
384
423
|
|
|
385
|
-
/**
|
|
424
|
+
/**
|
|
425
|
+
* Creates a {@link Console}.
|
|
426
|
+
*
|
|
427
|
+
* @group Core
|
|
428
|
+
*/
|
|
386
429
|
export const createConsole = ({
|
|
387
430
|
name = "",
|
|
388
431
|
level = "log",
|
|
@@ -458,7 +501,6 @@ export const createConsole = ({
|
|
|
458
501
|
*
|
|
459
502
|
* ```ts
|
|
460
503
|
* import {
|
|
461
|
-
* assertEqual,
|
|
462
504
|
* assertType,
|
|
463
505
|
* createNativeConsoleOutput,
|
|
464
506
|
* type ConsoleOutput,
|
|
@@ -467,8 +509,9 @@ export const createConsole = ({
|
|
|
467
509
|
* const output = createNativeConsoleOutput();
|
|
468
510
|
*
|
|
469
511
|
* assertType<typeof output, ConsoleOutput>();
|
|
470
|
-
* assertEqual(typeof output.write, "function");
|
|
471
512
|
* ```
|
|
513
|
+
*
|
|
514
|
+
* @group Output
|
|
472
515
|
*/
|
|
473
516
|
export const createNativeConsoleOutput = (): ConsoleOutput => ({
|
|
474
517
|
write: (entry, formatter) => {
|
|
@@ -530,6 +573,8 @@ export const createNativeConsoleOutput = (): ConsoleOutput => ({
|
|
|
530
573
|
* assertType(Data, absolute);
|
|
531
574
|
* assertEqual(absolute, ["14:30:15.123 [relay]", "connected"]);
|
|
532
575
|
* ```
|
|
576
|
+
*
|
|
577
|
+
* @group Output
|
|
533
578
|
*/
|
|
534
579
|
export const createConsoleFormatter =
|
|
535
580
|
({ time = createTime() }: Partial<TimeDep> = {}) =>
|
|
@@ -566,7 +611,11 @@ export const createConsoleFormatter =
|
|
|
566
611
|
};
|
|
567
612
|
};
|
|
568
613
|
|
|
569
|
-
/**
|
|
614
|
+
/**
|
|
615
|
+
* Creates a {@link ConsoleStoreOutput}.
|
|
616
|
+
*
|
|
617
|
+
* @group Output
|
|
618
|
+
*/
|
|
570
619
|
export const createConsoleStoreOutput = (): ConsoleStoreOutput => {
|
|
571
620
|
const entry = createStore<ConsoleEntry | null>(null);
|
|
572
621
|
return {
|
|
@@ -600,6 +649,8 @@ export const createConsoleStoreOutput = (): ConsoleStoreOutput => {
|
|
|
600
649
|
* { method: "info", path: [], args: ["connected"] },
|
|
601
650
|
* ]);
|
|
602
651
|
* ```
|
|
652
|
+
*
|
|
653
|
+
* @group Output
|
|
603
654
|
*/
|
|
604
655
|
export const createConsoleArrayOutput = (
|
|
605
656
|
entries: Array<ConsoleEntry>,
|
|
@@ -644,6 +695,8 @@ export const createConsoleArrayOutput = (
|
|
|
644
695
|
* assertType(Data, entries[0]);
|
|
645
696
|
* assertEqual(storedEntry, entries[0]);
|
|
646
697
|
* ```
|
|
698
|
+
*
|
|
699
|
+
* @group Output
|
|
647
700
|
*/
|
|
648
701
|
export const createMultiOutput = (
|
|
649
702
|
outputs: ReadonlyArray<ConsoleOutput>,
|
|
@@ -672,6 +725,8 @@ export const createMultiOutput = (
|
|
|
672
725
|
* { method: "info", path: ["relay"], args: ["connected"] },
|
|
673
726
|
* ]);
|
|
674
727
|
* ```
|
|
728
|
+
*
|
|
729
|
+
* @group Testing
|
|
675
730
|
*/
|
|
676
731
|
export const testCreateConsole = ({
|
|
677
732
|
level = "trace",
|