@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/Crypto.ts
CHANGED
|
@@ -24,6 +24,11 @@ import {
|
|
|
24
24
|
zeroNonNegativeInt,
|
|
25
25
|
} from "./Type.ts";
|
|
26
26
|
|
|
27
|
+
/**
|
|
28
|
+
* Cryptographically secure random bytes with length-branded results.
|
|
29
|
+
*
|
|
30
|
+
* @group Random bytes
|
|
31
|
+
*/
|
|
27
32
|
export interface RandomBytes {
|
|
28
33
|
/**
|
|
29
34
|
* Creates cryptographically secure random bytes with type-safe length
|
|
@@ -77,6 +82,11 @@ export interface RandomBytes {
|
|
|
77
82
|
create(bytesLength: number): Entropy;
|
|
78
83
|
}
|
|
79
84
|
|
|
85
|
+
/**
|
|
86
|
+
* Dependency wrapper for {@link RandomBytes}.
|
|
87
|
+
*
|
|
88
|
+
* @group Random bytes
|
|
89
|
+
*/
|
|
80
90
|
export interface RandomBytesDep {
|
|
81
91
|
readonly randomBytes: RandomBytes;
|
|
82
92
|
}
|
|
@@ -84,23 +94,53 @@ export interface RandomBytesDep {
|
|
|
84
94
|
const Entropy = /*#__PURE__*/ brand("Entropy", Uint8Array);
|
|
85
95
|
type Entropy = typeof Entropy.Output;
|
|
86
96
|
|
|
97
|
+
/**
|
|
98
|
+
* Cryptographic entropy of exactly 16 bytes.
|
|
99
|
+
*
|
|
100
|
+
* @group Random bytes
|
|
101
|
+
*/
|
|
87
102
|
export const Entropy16 = /*#__PURE__*/ length(16)(Entropy);
|
|
88
103
|
export type Entropy16 = typeof Entropy16.Output;
|
|
89
104
|
|
|
105
|
+
/**
|
|
106
|
+
* Cryptographic entropy of exactly 24 bytes.
|
|
107
|
+
*
|
|
108
|
+
* @group Random bytes
|
|
109
|
+
*/
|
|
90
110
|
export const Entropy24 = /*#__PURE__*/ length(24)(Entropy);
|
|
91
111
|
export type Entropy24 = typeof Entropy24.Output;
|
|
92
112
|
|
|
113
|
+
/**
|
|
114
|
+
* Cryptographic entropy of exactly 32 bytes.
|
|
115
|
+
*
|
|
116
|
+
* @group Random bytes
|
|
117
|
+
*/
|
|
93
118
|
export const Entropy32 = /*#__PURE__*/ length(32)(Entropy);
|
|
94
119
|
export type Entropy32 = typeof Entropy32.Output;
|
|
95
120
|
|
|
121
|
+
/**
|
|
122
|
+
* Cryptographic entropy of exactly 64 bytes.
|
|
123
|
+
*
|
|
124
|
+
* @group Random bytes
|
|
125
|
+
*/
|
|
96
126
|
export const Entropy64 = /*#__PURE__*/ length(64)(Entropy);
|
|
97
127
|
export type Entropy64 = typeof Entropy64.Output;
|
|
98
128
|
|
|
129
|
+
/**
|
|
130
|
+
* Creates {@link RandomBytes} backed by the platform's secure random number
|
|
131
|
+
* generator.
|
|
132
|
+
*
|
|
133
|
+
* @group Random bytes
|
|
134
|
+
*/
|
|
99
135
|
export const createRandomBytes = (): RandomBytes => ({
|
|
100
136
|
create: randomBytes as RandomBytes["create"],
|
|
101
137
|
});
|
|
102
138
|
|
|
103
|
-
/**
|
|
139
|
+
/**
|
|
140
|
+
* Creates seeded random bytes for deterministic tests.
|
|
141
|
+
*
|
|
142
|
+
* @group Testing
|
|
143
|
+
*/
|
|
104
144
|
export const testCreateRandomBytes = (deps: RandomLibDep): RandomBytes =>
|
|
105
145
|
({
|
|
106
146
|
create: (bytesLength: number) =>
|
|
@@ -113,6 +153,8 @@ export const testCreateRandomBytes = (deps: RandomLibDep): RandomBytes =>
|
|
|
113
153
|
* SLIP21.
|
|
114
154
|
*
|
|
115
155
|
* https://github.com/satoshilabs/slips/blob/master/slip-0021.md
|
|
156
|
+
*
|
|
157
|
+
* @group Key derivation
|
|
116
158
|
*/
|
|
117
159
|
export const createSlip21 = (
|
|
118
160
|
seed: Entropy16 | Entropy32 | Entropy64,
|
|
@@ -135,6 +177,7 @@ export const createSlip21 = (
|
|
|
135
177
|
/**
|
|
136
178
|
* Derives a single node in the SLIP-21 hierarchical key derivation.
|
|
137
179
|
*
|
|
180
|
+
* @group Key derivation
|
|
138
181
|
* @see {@link createSlip21}
|
|
139
182
|
*/
|
|
140
183
|
export const deriveSlip21Node = (
|
|
@@ -148,16 +191,25 @@ export const deriveSlip21Node = (
|
|
|
148
191
|
return hmac(sha512, parentNode.slice(0, 32), message) as Entropy64;
|
|
149
192
|
};
|
|
150
193
|
|
|
151
|
-
/**
|
|
194
|
+
/**
|
|
195
|
+
* The encryption key for symmetric encryption.
|
|
196
|
+
*
|
|
197
|
+
* @group Encryption
|
|
198
|
+
*/
|
|
152
199
|
export const EncryptionKey = /*#__PURE__*/ brand("EncryptionKey", Entropy32);
|
|
153
200
|
export type EncryptionKey = typeof EncryptionKey.Output;
|
|
154
201
|
|
|
155
|
-
/**
|
|
202
|
+
/**
|
|
203
|
+
* The nonce length for XChaCha20-Poly1305 encryption.
|
|
204
|
+
*
|
|
205
|
+
* @group Encryption
|
|
206
|
+
*/
|
|
156
207
|
export const xChaCha20Poly1305NonceLength = 24;
|
|
157
208
|
|
|
158
209
|
/**
|
|
159
210
|
* Branded Uint8Array for XChaCha20-Poly1305 encryption.
|
|
160
211
|
*
|
|
212
|
+
* @group Encryption
|
|
161
213
|
* @see {@link encryptWithXChaCha20Poly1305}
|
|
162
214
|
*/
|
|
163
215
|
export const XChaCha20Poly1305Ciphertext = /*#__PURE__*/ brand(
|
|
@@ -196,6 +248,7 @@ export type XChaCha20Poly1305Ciphertext =
|
|
|
196
248
|
* assertEqual(nonce.length, 24);
|
|
197
249
|
* ```
|
|
198
250
|
*
|
|
251
|
+
* @group Encryption
|
|
199
252
|
* @see https://github.com/paulmillr/noble-ciphers
|
|
200
253
|
*/
|
|
201
254
|
export const encryptWithXChaCha20Poly1305 =
|
|
@@ -211,6 +264,11 @@ export const encryptWithXChaCha20Poly1305 =
|
|
|
211
264
|
return [ciphertext, nonce];
|
|
212
265
|
};
|
|
213
266
|
|
|
267
|
+
/**
|
|
268
|
+
* Error returned by {@link decryptWithXChaCha20Poly1305} when decryption fails.
|
|
269
|
+
*
|
|
270
|
+
* @group Encryption
|
|
271
|
+
*/
|
|
214
272
|
export interface DecryptWithXChaCha20Poly1305Error extends Typed<"DecryptWithXChaCha20Poly1305Error"> {
|
|
215
273
|
readonly error: unknown;
|
|
216
274
|
}
|
|
@@ -254,6 +312,8 @@ export interface DecryptWithXChaCha20Poly1305Error extends Typed<"DecryptWithXCh
|
|
|
254
312
|
*
|
|
255
313
|
* assertOk(decryptMessage(), "secret message");
|
|
256
314
|
* ```
|
|
315
|
+
*
|
|
316
|
+
* @group Encryption
|
|
257
317
|
*/
|
|
258
318
|
export const decryptWithXChaCha20Poly1305 = (
|
|
259
319
|
ciphertext: XChaCha20Poly1305Ciphertext,
|
|
@@ -275,6 +335,8 @@ export const decryptWithXChaCha20Poly1305 = (
|
|
|
275
335
|
* wide range of encrypted data sizes.
|
|
276
336
|
*
|
|
277
337
|
* See the PURBs paper for details: https://bford.info/pub/sec/purb.pdf
|
|
338
|
+
*
|
|
339
|
+
* @group Padding
|
|
278
340
|
*/
|
|
279
341
|
export const createPadmePaddedLength = (
|
|
280
342
|
length: NonNegativeInt,
|
|
@@ -287,7 +349,11 @@ export const createPadmePaddedLength = (
|
|
|
287
349
|
return NonNegativeInt.orThrow((length + mask) & ~mask);
|
|
288
350
|
};
|
|
289
351
|
|
|
290
|
-
/**
|
|
352
|
+
/**
|
|
353
|
+
* Creates a PADMÉ padding array of zeros for the given input length.
|
|
354
|
+
*
|
|
355
|
+
* @group Padding
|
|
356
|
+
*/
|
|
291
357
|
export const createPadmePadding = (length: NonNegativeInt): Uint8Array => {
|
|
292
358
|
const paddedLength = createPadmePaddedLength(length);
|
|
293
359
|
const paddingLength = NonNegativeInt.orThrow(paddedLength - length);
|
|
@@ -299,10 +365,16 @@ export const createPadmePadding = (length: NonNegativeInt): Uint8Array => {
|
|
|
299
365
|
* are equal, false otherwise. Takes constant time regardless of where the
|
|
300
366
|
* arrays differ.
|
|
301
367
|
*
|
|
368
|
+
* @group Comparison
|
|
302
369
|
* @see https://nodejs.org/api/crypto.html#cryptotimingsafeequala-b
|
|
303
370
|
*/
|
|
304
371
|
export type TimingSafeEqual = (a: Uint8Array, b: Uint8Array) => boolean;
|
|
305
372
|
|
|
373
|
+
/**
|
|
374
|
+
* Dependency wrapper for {@link TimingSafeEqual}.
|
|
375
|
+
*
|
|
376
|
+
* @group Comparison
|
|
377
|
+
*/
|
|
306
378
|
export interface TimingSafeEqualDep {
|
|
307
379
|
readonly timingSafeEqual: TimingSafeEqual;
|
|
308
380
|
}
|
package/src/Eq.test.ts
CHANGED
|
@@ -293,13 +293,12 @@ test("eqData", () => {
|
|
|
293
293
|
}
|
|
294
294
|
const service: Service = { run: () => undefined };
|
|
295
295
|
const broadObject: NonNullable<unknown> = new WeakMap();
|
|
296
|
-
|
|
296
|
+
void (() => {
|
|
297
297
|
// @ts-expect-error ⛔ eqData error: Actual and expected values must consist only of Data.
|
|
298
298
|
eqData(service, service);
|
|
299
299
|
// @ts-expect-error ⛔ eqData error: Actual and expected values must consist only of Data.
|
|
300
300
|
eqData(broadObject, broadObject);
|
|
301
|
-
};
|
|
302
|
-
assertEqual(typeof compileTimeAssertions, "function");
|
|
301
|
+
});
|
|
303
302
|
});
|
|
304
303
|
|
|
305
304
|
test("eqData compares deeply nested Set and Map data", () => {
|
package/src/Error.test.ts
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
import { describe, it } from "node:test";
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
import { runInNewContext } from "node:vm";
|
|
3
|
+
import {
|
|
4
|
+
assertEqual,
|
|
5
|
+
assertFalse,
|
|
6
|
+
assertInstanceOf,
|
|
7
|
+
assertSame,
|
|
8
|
+
assertTrue,
|
|
9
|
+
} from "./Assert.ts";
|
|
10
|
+
|
|
11
|
+
import { UnknownError, createUnknownError, defectToError } from "./Error.ts";
|
|
12
|
+
import { createRun } from "./Task.ts";
|
|
5
13
|
import { assertType, Object, String } from "./Type.ts";
|
|
6
14
|
|
|
7
15
|
describe("createUnknownError", () => {
|
|
@@ -116,3 +124,68 @@ describe("createUnknownError", () => {
|
|
|
116
124
|
assertSame(actual.self, actual);
|
|
117
125
|
});
|
|
118
126
|
});
|
|
127
|
+
|
|
128
|
+
describe("defectToError", () => {
|
|
129
|
+
it("converts a panic to its Error defect", async () => {
|
|
130
|
+
const reported: Array<unknown> = [];
|
|
131
|
+
await using run = createRun({
|
|
132
|
+
reportDefect: (defect) => {
|
|
133
|
+
reported.push(defect);
|
|
134
|
+
},
|
|
135
|
+
});
|
|
136
|
+
const defect = new Error("boom");
|
|
137
|
+
|
|
138
|
+
run.panic(defect);
|
|
139
|
+
|
|
140
|
+
assertSame(defectToError(reported[0]), defect);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it("returns an Error from another realm as it is", () => {
|
|
144
|
+
const defect: unknown = runInNewContext(
|
|
145
|
+
'new TypeError("other realm failed")',
|
|
146
|
+
);
|
|
147
|
+
assertFalse(defect instanceof Error);
|
|
148
|
+
|
|
149
|
+
assertSame(defectToError(defect), defect);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it("describes a DOMException with its name and message", () => {
|
|
153
|
+
const defect = new DOMException("dom failed", "NotFoundError");
|
|
154
|
+
|
|
155
|
+
const error = defectToError(defect);
|
|
156
|
+
|
|
157
|
+
assertEqual(error.message, "NotFoundError: dom failed");
|
|
158
|
+
assertSame(error.cause, defect);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it("describes a panic's defect that is not an Error", async () => {
|
|
162
|
+
const reported: Array<unknown> = [];
|
|
163
|
+
await using run = createRun({
|
|
164
|
+
reportDefect: (defect) => {
|
|
165
|
+
reported.push(defect);
|
|
166
|
+
},
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
const abortError = run.panic({ type: "UnexpectedState", count: 1 });
|
|
170
|
+
|
|
171
|
+
const error = defectToError(reported[0]);
|
|
172
|
+
assertInstanceOf(error, Error);
|
|
173
|
+
assertEqual(error.message, 'Defect: {"type":"UnexpectedState","count":1}');
|
|
174
|
+
assertSame(error.cause, abortError);
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it("describes an AbortError that is not a panic", () => {
|
|
178
|
+
const abortError = {
|
|
179
|
+
type: "AbortError",
|
|
180
|
+
reason: { type: "OtherAbortReason" },
|
|
181
|
+
} as const;
|
|
182
|
+
|
|
183
|
+
const error = defectToError(abortError);
|
|
184
|
+
|
|
185
|
+
assertEqual(
|
|
186
|
+
error.message,
|
|
187
|
+
'Defect: {"type":"AbortError","reason":{"type":"OtherAbortReason"}}',
|
|
188
|
+
);
|
|
189
|
+
assertSame(error.cause, abortError);
|
|
190
|
+
});
|
|
191
|
+
});
|
package/src/Error.ts
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
* @module
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import { safelyStringifyUnknownValue } from "./String.ts";
|
|
8
|
+
import { AbortError, type createRun, type ReportDefect } from "./Task.ts";
|
|
7
9
|
import { type InferType, typed, type TypedType, Unknown } from "./Type.ts";
|
|
8
10
|
|
|
9
11
|
/**
|
|
@@ -84,3 +86,72 @@ export const createUnknownError = (error: unknown): UnknownError => {
|
|
|
84
86
|
}
|
|
85
87
|
}
|
|
86
88
|
};
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Converts a reported defect to an `Error` that a host error reporter shows
|
|
92
|
+
* readably.
|
|
93
|
+
*
|
|
94
|
+
* Hosts such as browsers and React Native show a reported value that is not an
|
|
95
|
+
* `Error` only as text such as "[object Object]", and a worker's error reaches
|
|
96
|
+
* its page, including an error tracker listening there, as that text alone. A
|
|
97
|
+
* panic reports a plain {@link AbortError}, so its defect is converted instead.
|
|
98
|
+
* An `Error` is returned as it is, including one from another realm, such as an
|
|
99
|
+
* iframe. A `DOMException` is described in an `Error` with its name and
|
|
100
|
+
* message, because Chromium reports one from a worker without them. Any other
|
|
101
|
+
* value is described in an `Error` whose cause is what was reported.
|
|
102
|
+
*
|
|
103
|
+
* Platform {@link createRun} adapters use it for their default reporting. A
|
|
104
|
+
* custom {@link ReportDefect} can use it too, such as before passing a defect to
|
|
105
|
+
* an error tracker.
|
|
106
|
+
*
|
|
107
|
+
* ### Example
|
|
108
|
+
*
|
|
109
|
+
* ```ts
|
|
110
|
+
* import {
|
|
111
|
+
* assertEqual,
|
|
112
|
+
* assertSame,
|
|
113
|
+
* createRun,
|
|
114
|
+
* defectToError,
|
|
115
|
+
* } from "@evolu/common";
|
|
116
|
+
*
|
|
117
|
+
* const errors: Array<Error> = [];
|
|
118
|
+
* await using run = createRun({
|
|
119
|
+
* reportDefect: (reported) => {
|
|
120
|
+
* errors.push(defectToError(reported));
|
|
121
|
+
* },
|
|
122
|
+
* });
|
|
123
|
+
* const defect = new Error("boom");
|
|
124
|
+
*
|
|
125
|
+
* run.panic(defect);
|
|
126
|
+
*
|
|
127
|
+
* assertSame(errors[0], defect);
|
|
128
|
+
* assertEqual(
|
|
129
|
+
* defectToError({ type: "UnexpectedState" }).message,
|
|
130
|
+
* 'Defect: {"type":"UnexpectedState"}',
|
|
131
|
+
* );
|
|
132
|
+
* ```
|
|
133
|
+
*/
|
|
134
|
+
export const defectToError = (reported: unknown): Error => {
|
|
135
|
+
const defect =
|
|
136
|
+
AbortError.is(reported) && reported.reason.type === "PanicAbortReason"
|
|
137
|
+
? reported.reason.defect
|
|
138
|
+
: reported;
|
|
139
|
+
// The internal tag survives crossing realms, such as from an iframe, where
|
|
140
|
+
// instanceof fails.
|
|
141
|
+
const tag = Object.prototype.toString.call(defect);
|
|
142
|
+
// Chromium reports a DOMException from a worker without its name or message,
|
|
143
|
+
// so it is described in an Error.
|
|
144
|
+
if (tag === "[object DOMException]") {
|
|
145
|
+
const { name, message } = defect as Error;
|
|
146
|
+
return new Error(`${name}: ${message}`, { cause: defect });
|
|
147
|
+
}
|
|
148
|
+
if (defect instanceof Error || tag === "[object Error]") {
|
|
149
|
+
return defect as Error;
|
|
150
|
+
}
|
|
151
|
+
// A value with a cycle or a bigint falls back to String, often
|
|
152
|
+
// "[object Object]", and a nested Error shows as "{}". That is enough:
|
|
153
|
+
// Evolu's own defects are Errors, and the cause still holds the value.
|
|
154
|
+
return new Error(`Defect: ${safelyStringifyUnknownValue(defect)}`, {
|
|
155
|
+
cause: reported,
|
|
156
|
+
});
|
|
157
|
+
};
|
package/src/Fs.test.ts
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { describe, it } from "node:test";
|
|
2
|
+
import {
|
|
3
|
+
assert,
|
|
4
|
+
assertEqual,
|
|
5
|
+
assertErr,
|
|
6
|
+
assertInstanceOf,
|
|
7
|
+
assertOk,
|
|
8
|
+
assertSame,
|
|
9
|
+
} from "./Assert.ts";
|
|
10
|
+
import { testCreateFs, type Fs, type FsDep, type FsError } from "./Fs.ts";
|
|
11
|
+
import { err, ok } from "./Result.ts";
|
|
12
|
+
import { AbortError, testCreateRun, type Task } from "./Task.ts";
|
|
13
|
+
import { assertType } from "./Type.ts";
|
|
14
|
+
|
|
15
|
+
describe("testCreateFs", () => {
|
|
16
|
+
it("accepts native copy options and rejects the former overwrite option", () => {
|
|
17
|
+
const fs = testCreateFs();
|
|
18
|
+
const task = fs.copy("source", "destination", {
|
|
19
|
+
force: false,
|
|
20
|
+
errorOnExist: true,
|
|
21
|
+
preserveTimestamps: true,
|
|
22
|
+
});
|
|
23
|
+
assertType<typeof task, Task<void, FsError>>();
|
|
24
|
+
|
|
25
|
+
// @ts-expect-error: FsCopyOptions has no overwrite property; use Node's force and errorOnExist options.
|
|
26
|
+
fs.copy("source", "destination", { overwrite: false });
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
for (const [method, createTask] of [
|
|
30
|
+
["readFile", (fs: Fs) => fs.readFile("file.txt")],
|
|
31
|
+
["writeFile", (fs: Fs) => fs.writeFile("file.txt", "content")],
|
|
32
|
+
["readDirectory", (fs: Fs) => fs.readDirectory("directory")],
|
|
33
|
+
["createDirectory", (fs: Fs) => fs.createDirectory("directory")],
|
|
34
|
+
["copy", (fs: Fs) => fs.copy("source", "destination")],
|
|
35
|
+
["copyFile", (fs: Fs) => fs.copyFile("source", "destination")],
|
|
36
|
+
["rename", (fs: Fs) => fs.rename("source", "destination")],
|
|
37
|
+
["remove", (fs: Fs) => fs.remove("file.txt")],
|
|
38
|
+
["getMetadata", (fs: Fs) => fs.getMetadata("file.txt")],
|
|
39
|
+
["exists", (fs: Fs) => fs.exists("file.txt")],
|
|
40
|
+
["createTempDirectory", (fs: Fs) => fs.createTempDirectory()],
|
|
41
|
+
] as const) {
|
|
42
|
+
it(`panics when an unconfigured ${method} Task runs`, async () => {
|
|
43
|
+
const fs = testCreateFs();
|
|
44
|
+
const task = createTask(fs);
|
|
45
|
+
await using run = testCreateRun();
|
|
46
|
+
|
|
47
|
+
const result = await run.abortable<unknown, FsError>(task);
|
|
48
|
+
|
|
49
|
+
assertErr(result);
|
|
50
|
+
assert(AbortError.is(result.error), "Unexpected Fs calls must abort.");
|
|
51
|
+
assertEqual(result.error.reason.type, "PanicAbortReason");
|
|
52
|
+
const { defect } = result.error.reason;
|
|
53
|
+
assertInstanceOf(defect, Error);
|
|
54
|
+
assertEqual(defect.message, `Unexpected Fs.${method} call`);
|
|
55
|
+
assertEqual(run.deps.reportDefect.getDefects(), [result.error]);
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
it("uses an injected override with the original arguments", async () => {
|
|
60
|
+
const path = new URL("file:///message.txt");
|
|
61
|
+
const data = new TextEncoder().encode("hello");
|
|
62
|
+
const options = { flag: "a" } as const;
|
|
63
|
+
let calls = 0;
|
|
64
|
+
const writeFile: Fs["writeFile"] =
|
|
65
|
+
(receivedPath, receivedData, receivedOptions) => () => {
|
|
66
|
+
calls += 1;
|
|
67
|
+
assertSame(receivedPath, path);
|
|
68
|
+
assertSame(receivedData, data);
|
|
69
|
+
assertSame(receivedOptions, options);
|
|
70
|
+
return ok();
|
|
71
|
+
};
|
|
72
|
+
const fs = testCreateFs({ writeFile });
|
|
73
|
+
assertSame(fs.writeFile, writeFile);
|
|
74
|
+
await using run = testCreateRun({ fs });
|
|
75
|
+
const saveMessage: Task<void, FsError, FsDep> = (run) =>
|
|
76
|
+
run(run.deps.fs.writeFile(path, data, options));
|
|
77
|
+
|
|
78
|
+
assertEqual(calls, 0);
|
|
79
|
+
assertOk(await run(saveMessage));
|
|
80
|
+
assertEqual(calls, 1);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it("preserves readFile overloads and injected errors", async () => {
|
|
84
|
+
const error: FsError = {
|
|
85
|
+
type: "FsError",
|
|
86
|
+
reason: "PermissionDenied",
|
|
87
|
+
path: "protected.txt",
|
|
88
|
+
syscall: "open",
|
|
89
|
+
message: "Permission denied",
|
|
90
|
+
};
|
|
91
|
+
const fs = testCreateFs({ readFile: () => () => err(error) });
|
|
92
|
+
await using run = testCreateRun();
|
|
93
|
+
const bytes = fs.readFile("protected.txt");
|
|
94
|
+
const text = fs.readFile("protected.txt", "utf8");
|
|
95
|
+
const encoded = fs.readFile("protected.txt", { encoding: "utf8" });
|
|
96
|
+
assertType<typeof bytes, Task<Uint8Array, FsError>>();
|
|
97
|
+
assertType<typeof text, Task<string, FsError>>();
|
|
98
|
+
assertType<typeof encoded, Task<string, FsError>>();
|
|
99
|
+
|
|
100
|
+
assertErr(await run(bytes), error);
|
|
101
|
+
assertErr(await run(text), error);
|
|
102
|
+
assertErr(await run(encoded), error);
|
|
103
|
+
assertEqual(run.deps.reportDefect.getDefects(), []);
|
|
104
|
+
});
|
|
105
|
+
});
|