@evolu/common 8.13.0 → 8.15.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.
Files changed (205) hide show
  1. package/dist/src/Crypto.d.ts +2 -1
  2. package/dist/src/Crypto.d.ts.map +1 -1
  3. package/dist/src/Redacted.d.ts +19 -39
  4. package/dist/src/Redacted.d.ts.map +1 -1
  5. package/dist/src/Redacted.js +18 -33
  6. package/dist/src/Type.d.ts +161 -0
  7. package/dist/src/Type.d.ts.map +1 -1
  8. package/dist/src/Type.js +152 -2
  9. package/dist/src/WebSocket.d.ts +16 -1
  10. package/dist/src/WebSocket.d.ts.map +1 -1
  11. package/dist/src/WebSocket.js +14 -2
  12. package/dist/src/intl/_en.d.ts +5 -1
  13. package/dist/src/intl/_en.d.ts.map +1 -1
  14. package/dist/src/intl/_en.js +4 -0
  15. package/dist/src/intl/ar.d.ts +5 -1
  16. package/dist/src/intl/ar.d.ts.map +1 -1
  17. package/dist/src/intl/ar.js +4 -0
  18. package/dist/src/intl/bn.d.ts +5 -1
  19. package/dist/src/intl/bn.d.ts.map +1 -1
  20. package/dist/src/intl/bn.js +4 -0
  21. package/dist/src/intl/ca.d.ts +5 -1
  22. package/dist/src/intl/ca.d.ts.map +1 -1
  23. package/dist/src/intl/ca.js +4 -0
  24. package/dist/src/intl/cs.d.ts +5 -1
  25. package/dist/src/intl/cs.d.ts.map +1 -1
  26. package/dist/src/intl/cs.js +4 -0
  27. package/dist/src/intl/da.d.ts +5 -1
  28. package/dist/src/intl/da.d.ts.map +1 -1
  29. package/dist/src/intl/da.js +4 -0
  30. package/dist/src/intl/de.d.ts +5 -1
  31. package/dist/src/intl/de.d.ts.map +1 -1
  32. package/dist/src/intl/de.js +4 -0
  33. package/dist/src/intl/el.d.ts +5 -1
  34. package/dist/src/intl/el.d.ts.map +1 -1
  35. package/dist/src/intl/el.js +4 -0
  36. package/dist/src/intl/es.d.ts +5 -1
  37. package/dist/src/intl/es.d.ts.map +1 -1
  38. package/dist/src/intl/es.js +4 -0
  39. package/dist/src/intl/fa.d.ts +5 -1
  40. package/dist/src/intl/fa.d.ts.map +1 -1
  41. package/dist/src/intl/fa.js +4 -0
  42. package/dist/src/intl/fi.d.ts +5 -1
  43. package/dist/src/intl/fi.d.ts.map +1 -1
  44. package/dist/src/intl/fi.js +4 -0
  45. package/dist/src/intl/fil.d.ts +5 -1
  46. package/dist/src/intl/fil.d.ts.map +1 -1
  47. package/dist/src/intl/fil.js +4 -0
  48. package/dist/src/intl/fr.d.ts +5 -1
  49. package/dist/src/intl/fr.d.ts.map +1 -1
  50. package/dist/src/intl/fr.js +4 -0
  51. package/dist/src/intl/he.d.ts +5 -1
  52. package/dist/src/intl/he.d.ts.map +1 -1
  53. package/dist/src/intl/he.js +4 -0
  54. package/dist/src/intl/hi.d.ts +5 -1
  55. package/dist/src/intl/hi.d.ts.map +1 -1
  56. package/dist/src/intl/hi.js +4 -0
  57. package/dist/src/intl/hr.d.ts +5 -1
  58. package/dist/src/intl/hr.d.ts.map +1 -1
  59. package/dist/src/intl/hr.js +4 -0
  60. package/dist/src/intl/hu.d.ts +3 -1
  61. package/dist/src/intl/hu.d.ts.map +1 -1
  62. package/dist/src/intl/hu.js +2 -0
  63. package/dist/src/intl/id.d.ts +5 -1
  64. package/dist/src/intl/id.d.ts.map +1 -1
  65. package/dist/src/intl/id.js +4 -0
  66. package/dist/src/intl/it.d.ts +5 -1
  67. package/dist/src/intl/it.d.ts.map +1 -1
  68. package/dist/src/intl/it.js +4 -0
  69. package/dist/src/intl/ja.d.ts +5 -1
  70. package/dist/src/intl/ja.d.ts.map +1 -1
  71. package/dist/src/intl/ja.js +4 -0
  72. package/dist/src/intl/ko.d.ts +5 -1
  73. package/dist/src/intl/ko.d.ts.map +1 -1
  74. package/dist/src/intl/ko.js +4 -0
  75. package/dist/src/intl/ml.d.ts +5 -1
  76. package/dist/src/intl/ml.d.ts.map +1 -1
  77. package/dist/src/intl/ml.js +4 -0
  78. package/dist/src/intl/mr.d.ts +5 -1
  79. package/dist/src/intl/mr.d.ts.map +1 -1
  80. package/dist/src/intl/mr.js +4 -0
  81. package/dist/src/intl/ms.d.ts +5 -1
  82. package/dist/src/intl/ms.d.ts.map +1 -1
  83. package/dist/src/intl/ms.js +4 -0
  84. package/dist/src/intl/nb.d.ts +3 -1
  85. package/dist/src/intl/nb.d.ts.map +1 -1
  86. package/dist/src/intl/nb.js +2 -0
  87. package/dist/src/intl/nl.d.ts +5 -1
  88. package/dist/src/intl/nl.d.ts.map +1 -1
  89. package/dist/src/intl/nl.js +4 -0
  90. package/dist/src/intl/pa.d.ts +5 -1
  91. package/dist/src/intl/pa.d.ts.map +1 -1
  92. package/dist/src/intl/pa.js +4 -0
  93. package/dist/src/intl/pl.d.ts +4 -0
  94. package/dist/src/intl/pl.d.ts.map +1 -1
  95. package/dist/src/intl/pl.js +4 -0
  96. package/dist/src/intl/pt-BR.d.ts +5 -1
  97. package/dist/src/intl/pt-BR.d.ts.map +1 -1
  98. package/dist/src/intl/pt-BR.js +4 -0
  99. package/dist/src/intl/pt.d.ts +5 -1
  100. package/dist/src/intl/pt.d.ts.map +1 -1
  101. package/dist/src/intl/pt.js +4 -0
  102. package/dist/src/intl/ro.d.ts +5 -1
  103. package/dist/src/intl/ro.d.ts.map +1 -1
  104. package/dist/src/intl/ro.js +4 -0
  105. package/dist/src/intl/sk.d.ts +5 -1
  106. package/dist/src/intl/sk.d.ts.map +1 -1
  107. package/dist/src/intl/sk.js +4 -0
  108. package/dist/src/intl/sl.d.ts +5 -1
  109. package/dist/src/intl/sl.d.ts.map +1 -1
  110. package/dist/src/intl/sl.js +4 -0
  111. package/dist/src/intl/sv.d.ts +5 -1
  112. package/dist/src/intl/sv.d.ts.map +1 -1
  113. package/dist/src/intl/sv.js +4 -0
  114. package/dist/src/intl/sw.d.ts +2 -0
  115. package/dist/src/intl/sw.d.ts.map +1 -1
  116. package/dist/src/intl/sw.js +2 -0
  117. package/dist/src/intl/ta.d.ts +5 -1
  118. package/dist/src/intl/ta.d.ts.map +1 -1
  119. package/dist/src/intl/ta.js +4 -0
  120. package/dist/src/intl/te.d.ts +5 -1
  121. package/dist/src/intl/te.d.ts.map +1 -1
  122. package/dist/src/intl/te.js +4 -0
  123. package/dist/src/intl/th.d.ts +5 -1
  124. package/dist/src/intl/th.d.ts.map +1 -1
  125. package/dist/src/intl/th.js +4 -0
  126. package/dist/src/intl/tr.d.ts +5 -1
  127. package/dist/src/intl/tr.d.ts.map +1 -1
  128. package/dist/src/intl/tr.js +4 -0
  129. package/dist/src/intl/uk.d.ts +5 -1
  130. package/dist/src/intl/uk.d.ts.map +1 -1
  131. package/dist/src/intl/uk.js +4 -0
  132. package/dist/src/intl/ur.d.ts +5 -1
  133. package/dist/src/intl/ur.d.ts.map +1 -1
  134. package/dist/src/intl/ur.js +4 -0
  135. package/dist/src/intl/vi.d.ts +5 -1
  136. package/dist/src/intl/vi.d.ts.map +1 -1
  137. package/dist/src/intl/vi.js +4 -0
  138. package/dist/src/intl/zh-CN.d.ts +5 -1
  139. package/dist/src/intl/zh-CN.d.ts.map +1 -1
  140. package/dist/src/intl/zh-CN.js +4 -0
  141. package/dist/src/intl/zh-TW.d.ts +5 -1
  142. package/dist/src/intl/zh-TW.d.ts.map +1 -1
  143. package/dist/src/intl/zh-TW.js +4 -0
  144. package/dist/src/local-first/Evolu.d.ts +66 -2
  145. package/dist/src/local-first/Evolu.d.ts.map +1 -1
  146. package/dist/src/local-first/Evolu.js +28 -4
  147. package/dist/src/local-first/Shared.d.ts +46 -39
  148. package/dist/src/local-first/Shared.d.ts.map +1 -1
  149. package/dist/src/local-first/Shared.js +30 -19
  150. package/package.json +1 -1
  151. package/src/Crypto.ts +2 -1
  152. package/src/Redacted.test.ts +231 -0
  153. package/src/Redacted.ts +36 -47
  154. package/src/Type.test.ts +166 -0
  155. package/src/Type.ts +198 -2
  156. package/src/WebSocket.ts +33 -4
  157. package/src/intl/_en.ts +10 -0
  158. package/src/intl/ar.ts +8 -0
  159. package/src/intl/bn.ts +10 -0
  160. package/src/intl/ca.ts +10 -0
  161. package/src/intl/cs.ts +10 -0
  162. package/src/intl/da.ts +10 -0
  163. package/src/intl/de.ts +10 -0
  164. package/src/intl/el.ts +10 -0
  165. package/src/intl/es.ts +10 -0
  166. package/src/intl/fa.ts +10 -0
  167. package/src/intl/fi.ts +10 -0
  168. package/src/intl/fil.ts +10 -0
  169. package/src/intl/fr.ts +10 -0
  170. package/src/intl/he.ts +10 -0
  171. package/src/intl/hi.ts +10 -0
  172. package/src/intl/hr.ts +10 -0
  173. package/src/intl/hu.ts +6 -0
  174. package/src/intl/id.ts +10 -0
  175. package/src/intl/intl.test.ts +88 -0
  176. package/src/intl/it.ts +10 -0
  177. package/src/intl/ja.ts +10 -0
  178. package/src/intl/ko.ts +10 -0
  179. package/src/intl/ml.ts +10 -0
  180. package/src/intl/mr.ts +10 -0
  181. package/src/intl/ms.ts +8 -0
  182. package/src/intl/nb.ts +6 -0
  183. package/src/intl/nl.ts +10 -0
  184. package/src/intl/pa.ts +10 -0
  185. package/src/intl/pl.ts +12 -0
  186. package/src/intl/pt-BR.ts +10 -0
  187. package/src/intl/pt.ts +8 -0
  188. package/src/intl/ro.ts +10 -0
  189. package/src/intl/sk.ts +8 -0
  190. package/src/intl/sl.ts +10 -0
  191. package/src/intl/sv.ts +10 -0
  192. package/src/intl/sw.ts +4 -0
  193. package/src/intl/ta.ts +10 -0
  194. package/src/intl/te.ts +10 -0
  195. package/src/intl/th.ts +10 -0
  196. package/src/intl/tr.ts +10 -0
  197. package/src/intl/uk.ts +10 -0
  198. package/src/intl/ur.ts +8 -0
  199. package/src/intl/vi.ts +8 -0
  200. package/src/intl/zh-CN.ts +10 -0
  201. package/src/intl/zh-TW.ts +10 -0
  202. package/src/local-first/Evolu.test.ts +162 -18
  203. package/src/local-first/Evolu.ts +102 -6
  204. package/src/local-first/Shared.test.ts +113 -30
  205. package/src/local-first/Shared.ts +73 -57
package/src/intl/te.ts CHANGED
@@ -23,6 +23,7 @@ import type {
23
23
  DateIsoFromDateError,
24
24
  DecimalStringError,
25
25
  DiscriminatedUnionError,
26
+ EmailError,
26
27
  EvoluTypeError,
27
28
  FiniteError,
28
29
  GreaterThanError,
@@ -74,6 +75,7 @@ import type {
74
75
  TypeOfError,
75
76
  UInt64Error,
76
77
  UnionError,
78
+ UuidError,
77
79
  } from "../Type.ts";
78
80
 
79
81
  const formatTypeOfError = (
@@ -258,6 +260,10 @@ export const formatBase64UrlError: TypeErrorFormatter<Base64UrlError> = (
258
260
  export const formatNameError: TypeErrorFormatter<NameError> = (error) =>
259
261
  `విలువ ${safelyStringifyUnknownValue(error.value)} చెల్లుబాటు అయ్యే Name కాదు.`;
260
262
 
263
+ /** EmailErrorను తెలుగులో ఫార్మాట్ చేస్తుంది. */
264
+ export const formatEmailError: TypeErrorFormatter<EmailError> = (error) =>
265
+ `విలువ ${safelyStringifyUnknownValue(error.value)} చెల్లుబాటు అయ్యే ఇమెయిల్ చిరునామా కాదు.`;
266
+
261
267
  /** MnemonicErrorను తెలుగులో ఫార్మాట్ చేస్తుంది. */
262
268
  export const formatMnemonicError: TypeErrorFormatter<MnemonicError> = (error) =>
263
269
  `విలువ ${safelyStringifyUnknownValue(error.value)} చెల్లుబాటు అయ్యే ఆంగ్ల BIP39 mnemonic కాదు.`;
@@ -270,6 +276,10 @@ export const formatIdError: TypeErrorFormatter<IdError> = (error) =>
270
276
  export const formatTableIdError: TypeErrorFormatter<TableIdError> = (error) =>
271
277
  `విలువ ${safelyStringifyUnknownValue(error.value)} పట్టిక ${error.table} కు చెల్లుబాటు అయ్యే Id కాదు.`;
272
278
 
279
+ /** UuidErrorను తెలుగులో ఫార్మాట్ చేస్తుంది. */
280
+ export const formatUuidError: TypeErrorFormatter<UuidError> = (error) =>
281
+ `విలువ ${safelyStringifyUnknownValue(error.value)} చిన్న అక్షరాలలోని ప్రామాణిక UUID కాదు.`;
282
+
273
283
  /** NonNegativeErrorను తెలుగులో ఫార్మాట్ చేస్తుంది. */
274
284
  export const formatNonNegativeError: TypeErrorFormatter<NonNegativeError> = (
275
285
  error,
package/src/intl/th.ts CHANGED
@@ -23,6 +23,7 @@ import type {
23
23
  DateIsoFromDateError,
24
24
  DecimalStringError,
25
25
  DiscriminatedUnionError,
26
+ EmailError,
26
27
  EvoluTypeError,
27
28
  FiniteError,
28
29
  GreaterThanError,
@@ -74,6 +75,7 @@ import type {
74
75
  TypeOfError,
75
76
  UInt64Error,
76
77
  UnionError,
78
+ UuidError,
77
79
  } from "../Type.ts";
78
80
 
79
81
  const formatTypeOfError = (
@@ -256,6 +258,10 @@ export const formatBase64UrlError: TypeErrorFormatter<Base64UrlError> = (
256
258
  export const formatNameError: TypeErrorFormatter<NameError> = (error) =>
257
259
  `ค่า ${safelyStringifyUnknownValue(error.value)} ไม่ใช่ Name ที่ถูกต้อง`;
258
260
 
261
+ /** จัดรูปแบบ EmailError เป็นภาษาไทย */
262
+ export const formatEmailError: TypeErrorFormatter<EmailError> = (error) =>
263
+ `ค่า ${safelyStringifyUnknownValue(error.value)} ไม่ใช่ที่อยู่อีเมลที่ถูกต้อง`;
264
+
259
265
  /** จัดรูปแบบ MnemonicError เป็นภาษาไทย */
260
266
  export const formatMnemonicError: TypeErrorFormatter<MnemonicError> = (error) =>
261
267
  `ค่า ${safelyStringifyUnknownValue(error.value)} ไม่ใช่ mnemonic BIP39 ภาษาอังกฤษที่ถูกต้อง`;
@@ -268,6 +274,10 @@ export const formatIdError: TypeErrorFormatter<IdError> = (error) =>
268
274
  export const formatTableIdError: TypeErrorFormatter<TableIdError> = (error) =>
269
275
  `ค่า ${safelyStringifyUnknownValue(error.value)} ไม่ใช่ Id ที่ถูกต้องสำหรับตาราง ${error.table}`;
270
276
 
277
+ /** จัดรูปแบบ UuidError เป็นภาษาไทย */
278
+ export const formatUuidError: TypeErrorFormatter<UuidError> = (error) =>
279
+ `ค่า ${safelyStringifyUnknownValue(error.value)} ไม่ใช่ UUID ตัวพิมพ์เล็กรูปแบบมาตรฐาน`;
280
+
271
281
  /** จัดรูปแบบ NonNegativeError เป็นภาษาไทย */
272
282
  export const formatNonNegativeError: TypeErrorFormatter<NonNegativeError> = (
273
283
  error,
package/src/intl/tr.ts CHANGED
@@ -23,6 +23,7 @@ import type {
23
23
  DateIsoFromDateError,
24
24
  DecimalStringError,
25
25
  DiscriminatedUnionError,
26
+ EmailError,
26
27
  EvoluTypeError,
27
28
  FiniteError,
28
29
  GreaterThanError,
@@ -74,6 +75,7 @@ import type {
74
75
  TypeOfError,
75
76
  UInt64Error,
76
77
  UnionError,
78
+ UuidError,
77
79
  } from "../Type.ts";
78
80
 
79
81
  const formatValueMustBe = (value: unknown, expected: string): string =>
@@ -258,6 +260,10 @@ export const formatBase64UrlError: TypeErrorFormatter<Base64UrlError> = (
258
260
  export const formatNameError: TypeErrorFormatter<NameError> = (error) =>
259
261
  `Değer ${safelyStringifyUnknownValue(error.value)} geçerli bir Name değildir.`;
260
262
 
263
+ /** Formats an EmailError in Turkish. */
264
+ export const formatEmailError: TypeErrorFormatter<EmailError> = (error) =>
265
+ `Değer ${safelyStringifyUnknownValue(error.value)} geçerli bir e-posta adresi değildir.`;
266
+
261
267
  /** Formats a MnemonicError in Turkish. */
262
268
  export const formatMnemonicError: TypeErrorFormatter<MnemonicError> = (error) =>
263
269
  `Değer ${safelyStringifyUnknownValue(error.value)} geçerli bir İngilizce BIP39 anımsatıcı değildir.`;
@@ -270,6 +276,10 @@ export const formatIdError: TypeErrorFormatter<IdError> = (error) =>
270
276
  export const formatTableIdError: TypeErrorFormatter<TableIdError> = (error) =>
271
277
  `Değer ${safelyStringifyUnknownValue(error.value)} ${error.table} tablosu için geçerli bir Id değildir.`;
272
278
 
279
+ /** Formats a UuidError in Turkish. */
280
+ export const formatUuidError: TypeErrorFormatter<UuidError> = (error) =>
281
+ `Değer ${safelyStringifyUnknownValue(error.value)} kurallı bir küçük harfli UUID değildir.`;
282
+
273
283
  /** Formats a NonNegativeError in Turkish. */
274
284
  export const formatNonNegativeError: TypeErrorFormatter<NonNegativeError> = (
275
285
  error,
package/src/intl/uk.ts CHANGED
@@ -23,6 +23,7 @@ import type {
23
23
  DateIsoFromDateError,
24
24
  DecimalStringError,
25
25
  DiscriminatedUnionError,
26
+ EmailError,
26
27
  EvoluTypeError,
27
28
  FiniteError,
28
29
  GreaterThanError,
@@ -74,6 +75,7 @@ import type {
74
75
  TypeOfError,
75
76
  UInt64Error,
76
77
  UnionError,
78
+ UuidError,
77
79
  } from "../Type.ts";
78
80
 
79
81
  const typeOfNames = {
@@ -262,6 +264,10 @@ export const formatBase64UrlError: TypeErrorFormatter<Base64UrlError> = (
262
264
  export const formatNameError: TypeErrorFormatter<NameError> = (error) =>
263
265
  `Значення ${safelyStringifyUnknownValue(error.value)} не є допустимим Name.`;
264
266
 
267
+ /** Форматує EmailError українською. */
268
+ export const formatEmailError: TypeErrorFormatter<EmailError> = (error) =>
269
+ `Значення ${safelyStringifyUnknownValue(error.value)} не є допустимою адресою електронної пошти.`;
270
+
265
271
  /** Форматує MnemonicError українською. */
266
272
  export const formatMnemonicError: TypeErrorFormatter<MnemonicError> = (error) =>
267
273
  `Значення ${safelyStringifyUnknownValue(error.value)} не є допустимою англійською мнемонічною фразою BIP39.`;
@@ -274,6 +280,10 @@ export const formatIdError: TypeErrorFormatter<IdError> = (error) =>
274
280
  export const formatTableIdError: TypeErrorFormatter<TableIdError> = (error) =>
275
281
  `Значення ${safelyStringifyUnknownValue(error.value)} не є допустимим Id для таблиці ${error.table}.`;
276
282
 
283
+ /** Форматує UuidError українською. */
284
+ export const formatUuidError: TypeErrorFormatter<UuidError> = (error) =>
285
+ `Значення ${safelyStringifyUnknownValue(error.value)} не є канонічним UUID у нижньому регістрі.`;
286
+
277
287
  /** Форматує NonNegativeError українською. */
278
288
  export const formatNonNegativeError: TypeErrorFormatter<NonNegativeError> = (
279
289
  error,
package/src/intl/ur.ts CHANGED
@@ -23,6 +23,7 @@ import type {
23
23
  DateIsoFromDateError,
24
24
  DecimalStringError,
25
25
  DiscriminatedUnionError,
26
+ EmailError,
26
27
  EvoluTypeError,
27
28
  FiniteError,
28
29
  GreaterThanError,
@@ -74,6 +75,7 @@ import type {
74
75
  TypeOfError,
75
76
  UInt64Error,
76
77
  UnionError,
78
+ UuidError,
77
79
  } from "../Type.ts";
78
80
 
79
81
  const formatTypeOfError = (
@@ -224,6 +226,9 @@ export const formatBase64UrlError: TypeErrorFormatter<Base64UrlError> = (
224
226
  /** NameError کو اردو میں فارمیٹ کرتا ہے۔ */
225
227
  export const formatNameError: TypeErrorFormatter<NameError> = (error) =>
226
228
  `قدر ${safelyStringifyUnknownValue(error.value)} درست Name نہیں ہے۔`;
229
+ /** EmailError کو اردو میں فارمیٹ کرتا ہے۔ */
230
+ export const formatEmailError: TypeErrorFormatter<EmailError> = (error) =>
231
+ `قدر ${safelyStringifyUnknownValue(error.value)} درست ای میل ایڈریس نہیں ہے۔`;
227
232
  /** MnemonicError کو اردو میں فارمیٹ کرتا ہے۔ */
228
233
  export const formatMnemonicError: TypeErrorFormatter<MnemonicError> = (error) =>
229
234
  `قدر ${safelyStringifyUnknownValue(error.value)} درست انگریزی BIP39 mnemonic نہیں ہے۔`;
@@ -233,6 +238,9 @@ export const formatIdError: TypeErrorFormatter<IdError> = (error) =>
233
238
  /** TableIdError کو اردو میں فارمیٹ کرتا ہے۔ */
234
239
  export const formatTableIdError: TypeErrorFormatter<TableIdError> = (error) =>
235
240
  `قدر ${safelyStringifyUnknownValue(error.value)} جدول ${error.table} کے لیے درست Id نہیں ہے۔`;
241
+ /** UuidError کو اردو میں فارمیٹ کرتا ہے۔ */
242
+ export const formatUuidError: TypeErrorFormatter<UuidError> = (error) =>
243
+ `قدر ${safelyStringifyUnknownValue(error.value)} چھوٹے حروف والا canonical UUID نہیں ہے۔`;
236
244
  /** NonNegativeError کو اردو میں فارمیٹ کرتا ہے۔ */
237
245
  export const formatNonNegativeError: TypeErrorFormatter<NonNegativeError> = (
238
246
  error,
package/src/intl/vi.ts CHANGED
@@ -23,6 +23,7 @@ import type {
23
23
  DateIsoFromDateError,
24
24
  DecimalStringError,
25
25
  DiscriminatedUnionError,
26
+ EmailError,
26
27
  EvoluTypeError,
27
28
  FiniteError,
28
29
  GreaterThanError,
@@ -74,6 +75,7 @@ import type {
74
75
  TypeOfError,
75
76
  UInt64Error,
76
77
  UnionError,
78
+ UuidError,
77
79
  } from "../Type.ts";
78
80
 
79
81
  const formatTypeOfError = (
@@ -225,6 +227,9 @@ export const formatBase64UrlError: TypeErrorFormatter<Base64UrlError> = (
225
227
  /** Định dạng NameError bằng tiếng Việt. */
226
228
  export const formatNameError: TypeErrorFormatter<NameError> = (error) =>
227
229
  `Giá trị ${safelyStringifyUnknownValue(error.value)} không phải là Name hợp lệ.`;
230
+ /** Định dạng EmailError bằng tiếng Việt. */
231
+ export const formatEmailError: TypeErrorFormatter<EmailError> = (error) =>
232
+ `Giá trị ${safelyStringifyUnknownValue(error.value)} không phải là địa chỉ email hợp lệ.`;
228
233
  /** Định dạng MnemonicError bằng tiếng Việt. */
229
234
  export const formatMnemonicError: TypeErrorFormatter<MnemonicError> = (error) =>
230
235
  `Giá trị ${safelyStringifyUnknownValue(error.value)} không phải là cụm từ gợi nhớ BIP39 tiếng Anh hợp lệ.`;
@@ -234,6 +239,9 @@ export const formatIdError: TypeErrorFormatter<IdError> = (error) =>
234
239
  /** Định dạng TableIdError bằng tiếng Việt. */
235
240
  export const formatTableIdError: TypeErrorFormatter<TableIdError> = (error) =>
236
241
  `Giá trị ${safelyStringifyUnknownValue(error.value)} không phải là Id hợp lệ cho bảng ${error.table}.`;
242
+ /** Định dạng UuidError bằng tiếng Việt. */
243
+ export const formatUuidError: TypeErrorFormatter<UuidError> = (error) =>
244
+ `Giá trị ${safelyStringifyUnknownValue(error.value)} không phải là UUID chữ thường chính tắc.`;
237
245
  /** Định dạng NonNegativeError bằng tiếng Việt. */
238
246
  export const formatNonNegativeError: TypeErrorFormatter<NonNegativeError> = (
239
247
  error,
package/src/intl/zh-CN.ts CHANGED
@@ -23,6 +23,7 @@ import type {
23
23
  DateIsoFromDateError,
24
24
  DecimalStringError,
25
25
  DiscriminatedUnionError,
26
+ EmailError,
26
27
  EvoluTypeError,
27
28
  FiniteError,
28
29
  GreaterThanError,
@@ -74,6 +75,7 @@ import type {
74
75
  TypeOfError,
75
76
  UInt64Error,
76
77
  UnionError,
78
+ UuidError,
77
79
  } from "../Type.ts";
78
80
 
79
81
  const formatTypeOfError = (
@@ -254,6 +256,10 @@ export const formatBase64UrlError: TypeErrorFormatter<Base64UrlError> = (
254
256
  export const formatNameError: TypeErrorFormatter<NameError> = (error) =>
255
257
  `值 ${safelyStringifyUnknownValue(error.value)} 不是有效的 Name。`;
256
258
 
259
+ /** 以简体中文格式化 EmailError。 */
260
+ export const formatEmailError: TypeErrorFormatter<EmailError> = (error) =>
261
+ `值 ${safelyStringifyUnknownValue(error.value)} 不是有效的电子邮件地址。`;
262
+
257
263
  /** 以简体中文格式化 MnemonicError。 */
258
264
  export const formatMnemonicError: TypeErrorFormatter<MnemonicError> = (error) =>
259
265
  `值 ${safelyStringifyUnknownValue(error.value)} 不是有效的英文 BIP39 助记词。`;
@@ -266,6 +272,10 @@ export const formatIdError: TypeErrorFormatter<IdError> = (error) =>
266
272
  export const formatTableIdError: TypeErrorFormatter<TableIdError> = (error) =>
267
273
  `值 ${safelyStringifyUnknownValue(error.value)} 不是表 ${error.table} 的有效 Id。`;
268
274
 
275
+ /** 以简体中文格式化 UuidError。 */
276
+ export const formatUuidError: TypeErrorFormatter<UuidError> = (error) =>
277
+ `值 ${safelyStringifyUnknownValue(error.value)} 不是规范的小写 UUID。`;
278
+
269
279
  /** 以简体中文格式化 NonNegativeError。 */
270
280
  export const formatNonNegativeError: TypeErrorFormatter<NonNegativeError> = (
271
281
  error,
package/src/intl/zh-TW.ts CHANGED
@@ -23,6 +23,7 @@ import type {
23
23
  DateIsoFromDateError,
24
24
  DecimalStringError,
25
25
  DiscriminatedUnionError,
26
+ EmailError,
26
27
  EvoluTypeError,
27
28
  FiniteError,
28
29
  GreaterThanError,
@@ -74,6 +75,7 @@ import type {
74
75
  TypeOfError,
75
76
  UInt64Error,
76
77
  UnionError,
78
+ UuidError,
77
79
  } from "../Type.ts";
78
80
 
79
81
  const formatTypeOfError = (
@@ -254,6 +256,10 @@ export const formatBase64UrlError: TypeErrorFormatter<Base64UrlError> = (
254
256
  export const formatNameError: TypeErrorFormatter<NameError> = (error) =>
255
257
  `值 ${safelyStringifyUnknownValue(error.value)} 不是有效的 Name。`;
256
258
 
259
+ /** 以繁體中文格式化 EmailError。 */
260
+ export const formatEmailError: TypeErrorFormatter<EmailError> = (error) =>
261
+ `值 ${safelyStringifyUnknownValue(error.value)} 不是有效的電子郵件地址。`;
262
+
257
263
  /** 以繁體中文格式化 MnemonicError。 */
258
264
  export const formatMnemonicError: TypeErrorFormatter<MnemonicError> = (error) =>
259
265
  `值 ${safelyStringifyUnknownValue(error.value)} 不是有效的英文 BIP39 助記詞。`;
@@ -266,6 +272,10 @@ export const formatIdError: TypeErrorFormatter<IdError> = (error) =>
266
272
  export const formatTableIdError: TypeErrorFormatter<TableIdError> = (error) =>
267
273
  `值 ${safelyStringifyUnknownValue(error.value)} 不是資料表 ${error.table} 的有效 Id。`;
268
274
 
275
+ /** 以繁體中文格式化 UuidError。 */
276
+ export const formatUuidError: TypeErrorFormatter<UuidError> = (error) =>
277
+ `值 ${safelyStringifyUnknownValue(error.value)} 不是標準小寫 UUID。`;
278
+
269
279
  /** 以繁體中文格式化 NonNegativeError。 */
270
280
  export const formatNonNegativeError: TypeErrorFormatter<NonNegativeError> = (
271
281
  error,
@@ -35,6 +35,8 @@ import {
35
35
  createOwnerSecret,
36
36
  createOwnerWebSocketTransport,
37
37
  createSharedOwner,
38
+ createSharedReadonlyOwner,
39
+ type Owner,
38
40
  testAppOwner,
39
41
  } from "./Owner.ts";
40
42
  import {
@@ -124,6 +126,13 @@ const testOwnerTransport = createOwnerWebSocketTransport({
124
126
  ownerId: testAppOwner.id,
125
127
  });
126
128
 
129
+ /** {@link testAppOwner} as useOwner posts it, without its type and mnemonic. */
130
+ const testPostedAppOwner: Owner = {
131
+ id: testAppOwner.id,
132
+ encryptionKey: testAppOwner.encryptionKey,
133
+ writeKey: testAppOwner.writeKey,
134
+ };
135
+
127
136
  const createQuery = createQueryBuilder(Schema);
128
137
 
129
138
  const todoTitleQuery = createQuery((db) =>
@@ -372,16 +381,6 @@ describe("Evolu", () => {
372
381
  assertSame(setup.deps.evoluError.get(), null);
373
382
  });
374
383
 
375
- it("says nothing to a worker that reports it keeps databases in memory", async () => {
376
- using setup = await setupCreateEvoluDeps();
377
-
378
- setup.sharedWorkerPort.postMessage({ type: "StorageUnavailable" });
379
- await testWaitForWorkerMessage();
380
-
381
- assertEqual(setup.messages, []);
382
- assertSame(setup.deps.evoluError.get(), null);
383
- });
384
-
385
384
  it("announces itself as tab leader with its console level once its worker connects", async () => {
386
385
  const testConsole = testCreateConsole();
387
386
  using setup = await setupCreateEvoluDeps(testConsole);
@@ -1188,7 +1187,7 @@ describe("Evolu", () => {
1188
1187
  {
1189
1188
  action: "add",
1190
1189
  owner: {
1191
- owner: testAppOwner,
1190
+ owner: testPostedAppOwner,
1192
1191
  transports: [{ type: "WebSocket", url: "wss://free.evoluhq.com" }],
1193
1192
  },
1194
1193
  },
@@ -1270,7 +1269,14 @@ describe("Evolu", () => {
1270
1269
  const { run, evoluInputs } = setup;
1271
1270
  const evolu = await run.ok(testCreateEvolu);
1272
1271
  const sharedOwner = createSharedOwner(createOwnerSecret(run.deps));
1273
- const owner = { owner: sharedOwner, transports: [testOwnerTransport] };
1272
+ const owner = {
1273
+ owner: {
1274
+ id: sharedOwner.id,
1275
+ encryptionKey: sharedOwner.encryptionKey,
1276
+ writeKey: sharedOwner.writeKey,
1277
+ },
1278
+ transports: [testOwnerTransport],
1279
+ };
1274
1280
  assertNotSame(sharedOwner.id, evolu.appOwner.id);
1275
1281
 
1276
1282
  const unuse = evolu.useOwner(sharedOwner, [testOwnerTransport]);
@@ -1350,7 +1356,7 @@ describe("Evolu", () => {
1350
1356
  actions: [
1351
1357
  {
1352
1358
  owner: {
1353
- owner: testAppOwner,
1359
+ owner: testPostedAppOwner,
1354
1360
  transports: [testOwnerTransport],
1355
1361
  },
1356
1362
  action: "add",
@@ -1386,7 +1392,45 @@ describe("Evolu", () => {
1386
1392
  actions: [
1387
1393
  {
1388
1394
  owner: {
1389
- owner: testAppOwner,
1395
+ owner: testPostedAppOwner,
1396
+ transports: [testOwnerTransport],
1397
+ },
1398
+ action: "add",
1399
+ },
1400
+ ],
1401
+ },
1402
+ ]);
1403
+ });
1404
+
1405
+ it("posts only the owner id and keys", async () => {
1406
+ await using setup = await setupRunWithEvoluDeps();
1407
+ const { run, evoluInputs } = setup;
1408
+ const evolu = await run.ok(testCreateEvolu);
1409
+ const readonlyOwner = createSharedReadonlyOwner(
1410
+ createSharedOwner(createOwnerSecret(run.deps)),
1411
+ );
1412
+
1413
+ evolu.useOwner(testAppOwner, [testOwnerTransport]);
1414
+ evolu.useOwner(readonlyOwner, [testOwnerTransport]);
1415
+ await testWaitForWorkerMessage();
1416
+
1417
+ assertEqual(evoluInputs, [
1418
+ {
1419
+ type: "UseOwner",
1420
+ actions: [
1421
+ {
1422
+ owner: {
1423
+ owner: testPostedAppOwner,
1424
+ transports: [testOwnerTransport],
1425
+ },
1426
+ action: "add",
1427
+ },
1428
+ {
1429
+ owner: {
1430
+ owner: {
1431
+ id: readonlyOwner.id,
1432
+ encryptionKey: readonlyOwner.encryptionKey,
1433
+ },
1390
1434
  transports: [testOwnerTransport],
1391
1435
  },
1392
1436
  action: "add",
@@ -1414,14 +1458,14 @@ describe("Evolu", () => {
1414
1458
  actions: [
1415
1459
  {
1416
1460
  owner: {
1417
- owner: testAppOwner,
1461
+ owner: testPostedAppOwner,
1418
1462
  transports: [testOwnerTransport],
1419
1463
  },
1420
1464
  action: "add",
1421
1465
  },
1422
1466
  {
1423
1467
  owner: {
1424
- owner: testAppOwner,
1468
+ owner: testPostedAppOwner,
1425
1469
  transports: [testOwnerTransport],
1426
1470
  },
1427
1471
  action: "remove",
@@ -1457,7 +1501,7 @@ describe("Evolu", () => {
1457
1501
  actions: [
1458
1502
  {
1459
1503
  owner: {
1460
- owner: testAppOwner,
1504
+ owner: testPostedAppOwner,
1461
1505
  transports: [testOwnerTransport],
1462
1506
  },
1463
1507
  action: "remove",
@@ -1490,7 +1534,7 @@ describe("Evolu", () => {
1490
1534
  actions: [
1491
1535
  {
1492
1536
  owner: {
1493
- owner: testAppOwner,
1537
+ owner: testPostedAppOwner,
1494
1538
  transports: [testOwnerTransport],
1495
1539
  },
1496
1540
  action: "add",
@@ -1502,6 +1546,106 @@ describe("Evolu", () => {
1502
1546
  });
1503
1547
  });
1504
1548
 
1549
+ describe("device persistence", () => {
1550
+ const setupPersistenceRequests = async () => {
1551
+ let requestCount = 0;
1552
+ const setup = await setupRunWithEvoluDeps({
1553
+ requestPersistentStorage: () => {
1554
+ requestCount += 1;
1555
+ },
1556
+ });
1557
+ return Object.assign(setup, { getRequestCount: () => requestCount });
1558
+ };
1559
+
1560
+ it("resolves devicePersistence to what its tenant sends", async () => {
1561
+ await using setup = await setupRunWithEvoluDeps();
1562
+ const evolu = await setup.run.ok(testCreateEvolu);
1563
+
1564
+ setup.postEvoluOutput({
1565
+ type: "OnDevicePersistence",
1566
+ devicePersistence: "NotPersisted",
1567
+ });
1568
+
1569
+ assertSame(await evolu.devicePersistence, "NotPersisted");
1570
+ });
1571
+
1572
+ it("resolves devicePersistence to Unknown when disposed before its tenant sends it", async () => {
1573
+ await using setup = await setupRunWithEvoluDeps();
1574
+ const evolu = await setup.run.ok(testCreateEvolu);
1575
+
1576
+ await evolu[Symbol.asyncDispose]();
1577
+
1578
+ assertSame(await evolu.devicePersistence, "Unknown");
1579
+ });
1580
+
1581
+ it("requests persistent storage once, after the first mutation, when devicePersistence is Unknown", async () => {
1582
+ await using setup = await setupPersistenceRequests();
1583
+ const evolu = await setup.run.ok(testCreateEvolu);
1584
+ setup.postEvoluOutput({
1585
+ type: "OnDevicePersistence",
1586
+ devicePersistence: "Unknown",
1587
+ });
1588
+ await evolu.devicePersistence;
1589
+ await testWaitForWorkerMessage();
1590
+ assertSame(setup.getRequestCount(), 0);
1591
+
1592
+ evolu.insert("todo", { title: NonEmptyTrimmedString100.orThrow("A") });
1593
+ evolu.insert("todo", { title: NonEmptyTrimmedString100.orThrow("B") });
1594
+ await testWaitForWorkerMessage();
1595
+ evolu.insert("todo", { title: NonEmptyTrimmedString100.orThrow("C") });
1596
+ await testWaitForWorkerMessage();
1597
+
1598
+ assertSame(setup.getRequestCount(), 1);
1599
+ });
1600
+
1601
+ it("requests persistent storage once devicePersistence resolves after the first mutation", async () => {
1602
+ await using setup = await setupPersistenceRequests();
1603
+ const evolu = await setup.run.ok(testCreateEvolu);
1604
+
1605
+ evolu.insert("todo", { title: NonEmptyTrimmedString100.orThrow("A") });
1606
+ await testWaitForWorkerMessage();
1607
+ assertSame(setup.getRequestCount(), 0);
1608
+
1609
+ setup.postEvoluOutput({
1610
+ type: "OnDevicePersistence",
1611
+ devicePersistence: "Unknown",
1612
+ });
1613
+ await evolu.devicePersistence;
1614
+ await testWaitForWorkerMessage();
1615
+
1616
+ assertSame(setup.getRequestCount(), 1);
1617
+ });
1618
+
1619
+ for (const devicePersistence of ["Persisted", "NotPersisted"] as const) {
1620
+ it(`does not request persistent storage when devicePersistence is ${devicePersistence}`, async () => {
1621
+ await using setup = await setupPersistenceRequests();
1622
+ const evolu = await setup.run.ok(testCreateEvolu);
1623
+ setup.postEvoluOutput({
1624
+ type: "OnDevicePersistence",
1625
+ devicePersistence,
1626
+ });
1627
+
1628
+ evolu.insert("todo", { title: NonEmptyTrimmedString100.orThrow("A") });
1629
+ await evolu.devicePersistence;
1630
+ await testWaitForWorkerMessage();
1631
+
1632
+ assertSame(setup.getRequestCount(), 0);
1633
+ });
1634
+ }
1635
+
1636
+ it("does not request persistent storage after disposal", async () => {
1637
+ await using setup = await setupPersistenceRequests();
1638
+ const evolu = await setup.run.ok(testCreateEvolu);
1639
+
1640
+ evolu.insert("todo", { title: NonEmptyTrimmedString100.orThrow("A") });
1641
+ await evolu[Symbol.asyncDispose]();
1642
+ await evolu.devicePersistence;
1643
+ await testWaitForWorkerMessage();
1644
+
1645
+ assertSame(setup.getRequestCount(), 0);
1646
+ });
1647
+ });
1648
+
1505
1649
  describe("dispose evolu", () => {
1506
1650
  it("logs disposeEvolu once", async () => {
1507
1651
  const testConsole = testCreateConsole();