@evolu/common 7.4.0 → 8.0.0-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (251) hide show
  1. package/README.md +4 -61
  2. package/dist/src/Array.d.ts +343 -102
  3. package/dist/src/Array.d.ts.map +1 -1
  4. package/dist/src/Array.js +181 -85
  5. package/dist/src/Assert.d.ts +57 -11
  6. package/dist/src/Assert.d.ts.map +1 -1
  7. package/dist/src/Assert.js +47 -11
  8. package/dist/src/BigInt.d.ts +6 -1
  9. package/dist/src/BigInt.d.ts.map +1 -1
  10. package/dist/src/BigInt.js +5 -0
  11. package/dist/src/Brand.d.ts +40 -12
  12. package/dist/src/Brand.d.ts.map +1 -1
  13. package/dist/src/Brand.js +5 -0
  14. package/dist/src/Buffer.d.ts +6 -1
  15. package/dist/src/Buffer.d.ts.map +1 -1
  16. package/dist/src/Buffer.js +7 -2
  17. package/dist/src/Cache.d.ts +10 -2
  18. package/dist/src/Cache.d.ts.map +1 -1
  19. package/dist/src/Cache.js +6 -0
  20. package/dist/src/Callbacks.d.ts +10 -7
  21. package/dist/src/Callbacks.d.ts.map +1 -1
  22. package/dist/src/Callbacks.js +23 -13
  23. package/dist/src/Console.d.ts +361 -69
  24. package/dist/src/Console.d.ts.map +1 -1
  25. package/dist/src/Console.js +217 -117
  26. package/dist/src/Crypto.d.ts +70 -21
  27. package/dist/src/Crypto.d.ts.map +1 -1
  28. package/dist/src/Crypto.js +72 -27
  29. package/dist/src/Eq.d.ts +22 -2
  30. package/dist/src/Eq.d.ts.map +1 -1
  31. package/dist/src/Eq.js +21 -1
  32. package/dist/src/Error.d.ts +23 -12
  33. package/dist/src/Error.d.ts.map +1 -1
  34. package/dist/src/Error.js +27 -11
  35. package/dist/src/Function.d.ts +128 -56
  36. package/dist/src/Function.d.ts.map +1 -1
  37. package/dist/src/Function.js +118 -14
  38. package/dist/src/Identicon.d.ts +5 -0
  39. package/dist/src/Identicon.d.ts.map +1 -1
  40. package/dist/src/Identicon.js +6 -1
  41. package/dist/src/Lookup.d.ts +160 -0
  42. package/dist/src/Lookup.d.ts.map +1 -0
  43. package/dist/src/Lookup.js +192 -0
  44. package/dist/src/Microtask.d.ts +21 -0
  45. package/dist/src/Microtask.d.ts.map +1 -0
  46. package/dist/src/Microtask.js +37 -0
  47. package/dist/src/Number.d.ts +18 -4
  48. package/dist/src/Number.d.ts.map +1 -1
  49. package/dist/src/Number.js +23 -1
  50. package/dist/src/Object.d.ts +110 -5
  51. package/dist/src/Object.d.ts.map +1 -1
  52. package/dist/src/Object.js +108 -5
  53. package/dist/src/Option.d.ts +58 -0
  54. package/dist/src/Option.d.ts.map +1 -0
  55. package/dist/src/Option.js +43 -0
  56. package/dist/src/Order.d.ts +5 -0
  57. package/dist/src/Order.d.ts.map +1 -1
  58. package/dist/src/Order.js +8 -3
  59. package/dist/src/Platform.d.ts +36 -2
  60. package/dist/src/Platform.d.ts.map +1 -1
  61. package/dist/src/Platform.js +10 -6
  62. package/dist/src/Polyfills.d.ts +27 -0
  63. package/dist/src/Polyfills.d.ts.map +1 -0
  64. package/dist/src/Polyfills.js +299 -0
  65. package/dist/src/Random.d.ts +18 -7
  66. package/dist/src/Random.d.ts.map +1 -1
  67. package/dist/src/Random.js +9 -7
  68. package/dist/src/Redacted.d.ts +7 -4
  69. package/dist/src/Redacted.d.ts.map +1 -1
  70. package/dist/src/Redacted.js +5 -0
  71. package/dist/src/Ref.d.ts +31 -16
  72. package/dist/src/Ref.d.ts.map +1 -1
  73. package/dist/src/Ref.js +35 -7
  74. package/dist/src/RefCount.d.ts +62 -0
  75. package/dist/src/RefCount.d.ts.map +1 -0
  76. package/dist/src/RefCount.js +83 -0
  77. package/dist/src/Relation.d.ts +84 -29
  78. package/dist/src/Relation.d.ts.map +1 -1
  79. package/dist/src/Relation.js +83 -105
  80. package/dist/src/Resource.d.ts +263 -0
  81. package/dist/src/Resource.d.ts.map +1 -0
  82. package/dist/src/Resource.js +389 -0
  83. package/dist/src/Result.d.ts +390 -374
  84. package/dist/src/Result.d.ts.map +1 -1
  85. package/dist/src/Result.js +142 -70
  86. package/dist/src/Schedule.d.ts +953 -0
  87. package/dist/src/Schedule.d.ts.map +1 -0
  88. package/dist/src/Schedule.js +1199 -0
  89. package/dist/src/Set.d.ts +181 -0
  90. package/dist/src/Set.d.ts.map +1 -0
  91. package/dist/src/Set.js +137 -0
  92. package/dist/src/Skiplist.d.ts +6 -1
  93. package/dist/src/Skiplist.d.ts.map +1 -1
  94. package/dist/src/Skiplist.js +5 -0
  95. package/dist/src/Sqlite.d.ts +160 -60
  96. package/dist/src/Sqlite.d.ts.map +1 -1
  97. package/dist/src/Sqlite.js +290 -190
  98. package/dist/src/Store.d.ts +36 -28
  99. package/dist/src/Store.d.ts.map +1 -1
  100. package/dist/src/Store.js +55 -15
  101. package/dist/src/String.d.ts +5 -0
  102. package/dist/src/String.d.ts.map +1 -1
  103. package/dist/src/String.js +5 -0
  104. package/dist/src/Task.d.ts +2263 -423
  105. package/dist/src/Task.d.ts.map +1 -1
  106. package/dist/src/Task.js +1488 -348
  107. package/dist/src/Test.d.ts +122 -0
  108. package/dist/src/Test.d.ts.map +1 -0
  109. package/dist/src/Test.js +66 -0
  110. package/dist/src/Time.d.ts +201 -48
  111. package/dist/src/Time.d.ts.map +1 -1
  112. package/dist/src/Time.js +190 -86
  113. package/dist/src/Tracer.d.ts +48 -0
  114. package/dist/src/Tracer.d.ts.map +1 -0
  115. package/dist/src/Tracer.js +6 -0
  116. package/dist/src/Type.d.ts +582 -209
  117. package/dist/src/Type.d.ts.map +1 -1
  118. package/dist/src/Type.js +362 -240
  119. package/dist/src/Types.d.ts +160 -6
  120. package/dist/src/Types.d.ts.map +1 -1
  121. package/dist/src/Types.js +22 -2
  122. package/dist/src/WebSocket.d.ts +113 -58
  123. package/dist/src/WebSocket.d.ts.map +1 -1
  124. package/dist/src/WebSocket.js +210 -118
  125. package/dist/src/Worker.d.ts +245 -60
  126. package/dist/src/Worker.d.ts.map +1 -1
  127. package/dist/src/Worker.js +220 -64
  128. package/dist/src/index.d.ts +25 -3
  129. package/dist/src/index.d.ts.map +1 -1
  130. package/dist/src/index.js +19 -3
  131. package/dist/src/local-first/Db.d.ts +24 -213
  132. package/dist/src/local-first/Db.d.ts.map +1 -1
  133. package/dist/src/local-first/Db.js +622 -293
  134. package/dist/src/local-first/Error.d.ts +12 -0
  135. package/dist/src/local-first/Error.d.ts.map +1 -0
  136. package/dist/src/local-first/Error.js +6 -0
  137. package/dist/src/local-first/Evolu.d.ts +330 -285
  138. package/dist/src/local-first/Evolu.d.ts.map +1 -1
  139. package/dist/src/local-first/Evolu.js +472 -402
  140. package/dist/src/local-first/LocalAuth.d.ts +10 -10
  141. package/dist/src/local-first/LocalAuth.d.ts.map +1 -1
  142. package/dist/src/local-first/LocalAuth.js +6 -1
  143. package/dist/src/local-first/Owner.d.ts +70 -27
  144. package/dist/src/local-first/Owner.d.ts.map +1 -1
  145. package/dist/src/local-first/Owner.js +27 -14
  146. package/dist/src/local-first/Protocol.d.ts +58 -50
  147. package/dist/src/local-first/Protocol.d.ts.map +1 -1
  148. package/dist/src/local-first/Protocol.js +253 -155
  149. package/dist/src/local-first/Query.d.ts +133 -43
  150. package/dist/src/local-first/Query.d.ts.map +1 -1
  151. package/dist/src/local-first/Query.js +139 -90
  152. package/dist/src/local-first/Relay.d.ts +18 -38
  153. package/dist/src/local-first/Relay.d.ts.map +1 -1
  154. package/dist/src/local-first/Relay.js +59 -171
  155. package/dist/src/local-first/Schema.d.ts +139 -144
  156. package/dist/src/local-first/Schema.d.ts.map +1 -1
  157. package/dist/src/local-first/Schema.js +78 -163
  158. package/dist/src/local-first/Shared.d.ts +125 -0
  159. package/dist/src/local-first/Shared.d.ts.map +1 -0
  160. package/dist/src/local-first/Shared.js +569 -0
  161. package/dist/src/local-first/Storage.d.ts +50 -53
  162. package/dist/src/local-first/Storage.d.ts.map +1 -1
  163. package/dist/src/local-first/Storage.js +121 -173
  164. package/dist/src/local-first/Timestamp.d.ts +28 -35
  165. package/dist/src/local-first/Timestamp.d.ts.map +1 -1
  166. package/dist/src/local-first/Timestamp.js +24 -25
  167. package/dist/src/local-first/index.d.ts +2 -15
  168. package/dist/src/local-first/index.d.ts.map +1 -1
  169. package/dist/src/local-first/index.js +2 -15
  170. package/package.json +36 -26
  171. package/src/Array.ts +467 -106
  172. package/src/Assert.ts +87 -12
  173. package/src/BigInt.ts +7 -1
  174. package/src/Brand.ts +41 -12
  175. package/src/Buffer.ts +10 -4
  176. package/src/Cache.ts +11 -2
  177. package/src/Callbacks.ts +33 -23
  178. package/src/Console.ts +567 -178
  179. package/src/Crypto.ts +111 -62
  180. package/src/Eq.ts +30 -3
  181. package/src/Error.ts +50 -34
  182. package/src/Function.ts +140 -68
  183. package/src/Identicon.ts +7 -1
  184. package/src/Lookup.ts +415 -0
  185. package/src/Microtask.ts +58 -0
  186. package/src/Number.ts +40 -7
  187. package/src/Object.ts +155 -16
  188. package/src/Option.ts +74 -0
  189. package/src/Order.ts +11 -3
  190. package/src/Platform.ts +43 -7
  191. package/src/Polyfills.ts +465 -0
  192. package/src/Random.ts +25 -11
  193. package/src/Redacted.ts +8 -4
  194. package/src/Ref.ts +72 -21
  195. package/src/RefCount.ts +170 -0
  196. package/src/Relation.ts +188 -136
  197. package/src/Resource.ts +864 -0
  198. package/src/Result.ts +548 -381
  199. package/src/Schedule.ts +1471 -0
  200. package/src/Set.ts +247 -0
  201. package/src/Skiplist.ts +7 -1
  202. package/src/Sqlite.ts +409 -304
  203. package/src/Store.ts +94 -48
  204. package/src/String.ts +6 -0
  205. package/src/Task.ts +3685 -740
  206. package/src/Test.ts +162 -0
  207. package/src/Time.ts +348 -145
  208. package/src/Tracer.ts +54 -0
  209. package/src/Type.ts +1064 -630
  210. package/src/Types.ts +202 -7
  211. package/src/WebSocket.ts +311 -178
  212. package/src/Worker.ts +527 -147
  213. package/src/index.ts +74 -3
  214. package/src/local-first/Db.ts +871 -597
  215. package/src/local-first/Error.ts +17 -0
  216. package/src/local-first/Evolu.ts +884 -823
  217. package/src/local-first/LocalAuth.ts +10 -10
  218. package/src/local-first/Owner.ts +94 -42
  219. package/src/local-first/Protocol.ts +440 -303
  220. package/src/local-first/Query.ts +243 -194
  221. package/src/local-first/Relay.ts +91 -252
  222. package/src/local-first/Schema.ts +284 -394
  223. package/src/local-first/Shared.ts +932 -0
  224. package/src/local-first/Storage.ts +209 -282
  225. package/src/local-first/Timestamp.ts +38 -45
  226. package/src/local-first/index.ts +2 -16
  227. package/LICENSE +0 -21
  228. package/dist/src/Instances.d.ts +0 -34
  229. package/dist/src/Instances.d.ts.map +0 -1
  230. package/dist/src/Instances.js +0 -44
  231. package/dist/src/Resources.d.ts +0 -118
  232. package/dist/src/Resources.d.ts.map +0 -1
  233. package/dist/src/Resources.js +0 -197
  234. package/dist/src/local-first/Platform.d.ts +0 -25
  235. package/dist/src/local-first/Platform.d.ts.map +0 -1
  236. package/dist/src/local-first/Platform.js +0 -1
  237. package/dist/src/local-first/Public.d.ts +0 -22
  238. package/dist/src/local-first/Public.d.ts.map +0 -1
  239. package/dist/src/local-first/Public.js +0 -15
  240. package/dist/src/local-first/PublicKysely.d.ts +0 -148
  241. package/dist/src/local-first/PublicKysely.d.ts.map +0 -1
  242. package/dist/src/local-first/PublicKysely.js +0 -184
  243. package/dist/src/local-first/Sync.d.ts +0 -112
  244. package/dist/src/local-first/Sync.d.ts.map +0 -1
  245. package/dist/src/local-first/Sync.js +0 -529
  246. package/src/Instances.ts +0 -90
  247. package/src/Resources.ts +0 -367
  248. package/src/local-first/Platform.ts +0 -27
  249. package/src/local-first/Public.ts +0 -42
  250. package/src/local-first/PublicKysely.ts +0 -239
  251. package/src/local-first/Sync.ts +0 -960
@@ -1,7 +1,13 @@
1
- import { RandomBytesDep } from "../Crypto.js";
2
- import { Mnemonic } from "../Type.js";
1
+ /**
2
+ * Local authentication and owner management.
3
+ *
4
+ * @module
5
+ */
6
+
7
+ import type { RandomBytesDep } from "../Crypto.js";
8
+ import type { Mnemonic } from "../Type.js";
9
+ import type { AppOwner } from "./Owner.js";
3
10
  import {
4
- AppOwner,
5
11
  createAppOwner,
6
12
  createOwnerSecret,
7
13
  mnemonicToOwnerSecret,
@@ -13,8 +19,6 @@ import {
13
19
  /**
14
20
  * Local authentication and authorization system for Evolu. This is API is
15
21
  * subject to change and not recommended for production use.
16
- *
17
- * @experimental
18
22
  */
19
23
  export interface LocalAuth {
20
24
  /** Logs in with the given owner ID, or loads the target owner if not provided. */
@@ -46,11 +50,7 @@ export interface LocalAuthDep {
46
50
  readonly localAuth: LocalAuth;
47
51
  }
48
52
 
49
- /**
50
- * Secure storage interface that must be implemented by each platform.
51
- *
52
- * @experimental
53
- */
53
+ /** Secure storage interface that must be implemented by each platform. */
54
54
  export interface SecureStorage {
55
55
  setItem: (
56
56
  key: string,
@@ -1,13 +1,21 @@
1
+ /**
2
+ * Owner identity and cryptographic key derivation.
3
+ *
4
+ * @module
5
+ */
6
+
1
7
  import * as bip39 from "@scure/bip39";
2
8
  import { wordlist } from "@scure/bip39/wordlists/english.js";
3
- import { NonEmptyReadonlyArray } from "../Array.js";
9
+ import type { NonEmptyReadonlyArray } from "../Array.js";
10
+ import type { RandomBytesDep } from "../Crypto.js";
4
11
  import {
5
12
  createSlip21,
6
13
  EncryptionKey,
7
14
  Entropy16,
8
15
  Entropy32,
9
- RandomBytesDep,
16
+ testCreateRandomBytes,
10
17
  } from "../Crypto.js";
18
+ import { testCreateRandomLib } from "../Random.js";
11
19
  import { getOrNull } from "../Result.js";
12
20
  import {
13
21
  brand,
@@ -17,6 +25,7 @@ import {
17
25
  idToIdBytes,
18
26
  Mnemonic,
19
27
  NonNegativeInt,
28
+ type Typed,
20
29
  } from "../Type.js";
21
30
  import type { EncryptedDbChange, Storage } from "./Storage.js";
22
31
  import { TimestampBytes } from "./Timestamp.js";
@@ -68,12 +77,21 @@ export interface Owner extends ReadonlyOwner {
68
77
  readonly writeKey: OwnerWriteKey;
69
78
  }
70
79
 
80
+ /**
81
+ * An {@link ReadonlyOwner} or {@link Owner} with non-empty {@link OwnerTransport}s
82
+ * so it can be synced.
83
+ */
84
+ export interface SyncOwner {
85
+ readonly owner: ReadonlyOwner | Owner;
86
+ readonly transports: NonEmptyReadonlyArray<OwnerTransport>;
87
+ }
88
+
71
89
  /** OwnerId is a branded {@link Id} that uniquely identifies an {@link Owner}. */
72
- export const OwnerId = brand("OwnerId", Id);
90
+ export const OwnerId = /*#__PURE__*/ brand("OwnerId", Id);
73
91
  export type OwnerId = typeof OwnerId.Type;
74
92
 
75
93
  /** Bytes representation of {@link OwnerId}. */
76
- export const OwnerIdBytes = brand("OwnerIdBytes", IdBytes);
94
+ export const OwnerIdBytes = /*#__PURE__*/ brand("OwnerIdBytes", IdBytes);
77
95
  export type OwnerIdBytes = typeof OwnerIdBytes.Type;
78
96
 
79
97
  /** Converts {@link OwnerId} to {@link OwnerIdBytes}. */
@@ -84,17 +102,20 @@ export const ownerIdToOwnerIdBytes = (ownerId: OwnerId): OwnerIdBytes =>
84
102
  export const ownerIdBytesToOwnerId = (ownerIdBytes: OwnerIdBytes): OwnerId =>
85
103
  idBytesToId(ownerIdBytes as IdBytes) as OwnerId;
86
104
 
87
- export const ownerWriteKeyLength = NonNegativeInt.orThrow(16);
105
+ export const ownerWriteKeyLength = /*#__PURE__*/ NonNegativeInt.orThrow(16);
88
106
 
89
107
  /** Symmetric encryption key for {@link Owner} data protection. */
90
- export const OwnerEncryptionKey = brand("OwnerEncryptionKey", EncryptionKey);
108
+ export const OwnerEncryptionKey = /*#__PURE__*/ brand(
109
+ "OwnerEncryptionKey",
110
+ EncryptionKey,
111
+ );
91
112
  export type OwnerEncryptionKey = typeof OwnerEncryptionKey.Type;
92
113
 
93
114
  /**
94
115
  * A secure token for write operations. It's derived from {@link OwnerSecret} by
95
116
  * default and can be rotated via {@link createOwnerWriteKey}.
96
117
  */
97
- export const OwnerWriteKey = brand("OwnerWriteKey", Entropy16);
118
+ export const OwnerWriteKey = /*#__PURE__*/ brand("OwnerWriteKey", Entropy16);
98
119
  export type OwnerWriteKey = typeof OwnerWriteKey.Type;
99
120
 
100
121
  /**
@@ -113,13 +134,20 @@ export const createOwnerWriteKey = (deps: RandomBytesDep): OwnerWriteKey =>
113
134
  * Can be created using {@link createOwnerSecret} or converted from a
114
135
  * {@link Mnemonic} using {@link mnemonicToOwnerSecret}.
115
136
  */
116
- export const OwnerSecret = brand("OwnerSecret", Entropy32);
137
+ export const OwnerSecret = /*#__PURE__*/ brand("OwnerSecret", Entropy32);
117
138
  export type OwnerSecret = typeof OwnerSecret.Type;
118
139
 
119
140
  /** Creates a {@link OwnerSecret}. */
120
141
  export const createOwnerSecret = (deps: RandomBytesDep): OwnerSecret =>
121
142
  deps.randomBytes.create(32) as OwnerSecret;
122
143
 
144
+ /** Deterministic {@link OwnerSecret} for tests. */
145
+ export const testOwnerSecret = /*#__PURE__*/ createOwnerSecret({
146
+ randomBytes: /*#__PURE__*/ testCreateRandomBytes({
147
+ randomLib: /*#__PURE__*/ testCreateRandomLib(),
148
+ }),
149
+ });
150
+
123
151
  /** Converts an {@link OwnerSecret} to a {@link Mnemonic}. */
124
152
  export const ownerSecretToMnemonic = (secret: OwnerSecret): Mnemonic =>
125
153
  bip39.entropyToMnemonic(secret, wordlist) as Mnemonic;
@@ -168,20 +196,19 @@ const createOwner = (secret: OwnerSecret): Owner => ({
168
196
  * devices need to sync the information that an owner was deleted so they can
169
197
  * delete their local data as well.
170
198
  *
171
- * ### Privacy Considerations
199
+ * ## Privacy Considerations
200
+ *
201
+ * AppOwner must never be shared with anyone.
172
202
  *
173
- * AppOwner must never be shared with anyone, except for its {@link OwnerId},
174
- * which can be used for authorization with
175
- * {@link createOwnerWebSocketTransport}. It's safe because OwnerId is
176
- * pseudonymous (it can't be assigned to a specific person).
203
+ * AppOwner's {@link OwnerId} is used for authorization with
204
+ * {@link createOwnerWebSocketTransport}. Share it only with trusted relay
205
+ * parties that must verify access, and do not share it with anyone else.
177
206
  *
178
207
  * For data sharing scenarios, use {@link SharedOwner} and
179
- * {@link SharedReadonlyOwner} instead, which are designed specifically for
180
- * collaborative access.
208
+ * {@link SharedReadonlyOwner} to make intent explicit and distinguish
209
+ * collaborative usage from {@link AppOwner} coordination.
181
210
  */
182
- export interface AppOwner extends Owner {
183
- readonly type: "AppOwner";
184
-
211
+ export interface AppOwner extends Owner, Typed<"AppOwner"> {
185
212
  /**
186
213
  * The mnemonic that was used to derive the AppOwner keys. Optional when the
187
214
  * AppOwner is created from external keys to avoid sharing the mnemonic with
@@ -189,11 +216,7 @@ export interface AppOwner extends Owner {
189
216
  *
190
217
  * TODO: Wrap with `Redacted` in the next major version.
191
218
  */
192
- readonly mnemonic?: Mnemonic | null;
193
- }
194
-
195
- export interface AppOwnerDep {
196
- readonly appOwner: AppOwner;
219
+ readonly mnemonic: Mnemonic;
197
220
  }
198
221
 
199
222
  /** Creates an {@link AppOwner} from an {@link OwnerSecret}. */
@@ -203,6 +226,9 @@ export const createAppOwner = (secret: OwnerSecret): AppOwner => ({
203
226
  mnemonic: ownerSecretToMnemonic(secret),
204
227
  });
205
228
 
229
+ /** Deterministic {@link AppOwner} for tests. */
230
+ export const testAppOwner = /*#__PURE__*/ createAppOwner(testOwnerSecret);
231
+
206
232
  /**
207
233
  * An {@link Owner} for sharding data.
208
234
  *
@@ -214,17 +240,13 @@ export const createAppOwner = (secret: OwnerSecret): AppOwner => ({
214
240
  * deterministically derived from {@link AppOwner} using
215
241
  * {@link deriveShardOwner}.
216
242
  */
217
- export interface ShardOwner extends Owner {
218
- readonly type: "ShardOwner";
219
- }
243
+ export interface ShardOwner extends Owner, Typed<"ShardOwner"> {}
220
244
 
221
245
  /** Creates a {@link ShardOwner} from an {@link OwnerSecret}. */
222
- export const createShardOwner = (secret: OwnerSecret): ShardOwner => {
223
- return {
224
- ...createOwner(secret),
225
- type: "ShardOwner",
226
- };
227
- };
246
+ export const createShardOwner = (secret: OwnerSecret): ShardOwner => ({
247
+ ...createOwner(secret),
248
+ type: "ShardOwner",
249
+ });
228
250
 
229
251
  /**
230
252
  * Derives a {@link ShardOwner} from an {@link AppOwner} using the specified path.
@@ -257,9 +279,7 @@ export const deriveShardOwner = (
257
279
  };
258
280
 
259
281
  /** An {@link Owner} for collaborative data with write access. */
260
- export interface SharedOwner extends Owner {
261
- readonly type: "SharedOwner";
262
- }
282
+ export interface SharedOwner extends Owner, Typed<"SharedOwner"> {}
263
283
 
264
284
  /**
265
285
  * Creates a {@link SharedOwner} from an {@link OwnerSecret} for collaborative
@@ -278,9 +298,8 @@ export const createSharedOwner = (secret: OwnerSecret): SharedOwner => ({
278
298
  * {@link OwnerId} and {@link EncryptionKey} needed for others to read the shared
279
299
  * data without write access.
280
300
  */
281
- export interface SharedReadonlyOwner extends ReadonlyOwner {
282
- readonly type: "SharedReadonlyOwner";
283
- }
301
+ export interface SharedReadonlyOwner
302
+ extends ReadonlyOwner, Typed<"SharedReadonlyOwner"> {}
284
303
 
285
304
  /** Creates a {@link SharedReadonlyOwner} from a {@link SharedOwner}. */
286
305
  export const createSharedReadonlyOwner = (
@@ -301,7 +320,7 @@ export type OwnerTransport = OwnerWebSocketTransport;
301
320
  /**
302
321
  * WebSocket transport configuration.
303
322
  *
304
- * ### Authentication via URL
323
+ * ## Authentication via URL
305
324
  *
306
325
  * The {@link OwnerId} is passed as a URL query parameter. While this approach is
307
326
  * generally discouraged for authentication tokens (they get logged), it's safe
@@ -311,7 +330,7 @@ export type OwnerTransport = OwnerWebSocketTransport;
311
330
  * See: [HTTP headers in Websockets client
312
331
  * API](https://stackoverflow.com/questions/4361173/http-headers-in-websockets-client-api/74564827#74564827)
313
332
  *
314
- * ### Error Handling
333
+ * ## Error Handling
315
334
  *
316
335
  * When a relay rejects a connection (invalid OwnerId, unauthorized owner, or
317
336
  * server error), the browser WebSocket API does not expose the specific HTTP
@@ -325,8 +344,7 @@ export type OwnerTransport = OwnerWebSocketTransport;
325
344
  * @see {@link createOwnerWebSocketTransport}
326
345
  * @see {@link parseOwnerIdFromOwnerWebSocketTransportUrl}
327
346
  */
328
- export interface OwnerWebSocketTransport {
329
- readonly type: "WebSocket";
347
+ export interface OwnerWebSocketTransport extends Typed<"WebSocket"> {
330
348
  readonly url: string;
331
349
  }
332
350
 
@@ -425,3 +443,37 @@ export interface OwnerUsage {
425
443
  */
426
444
  readonly lastTimestamp: TimestampBytes | null;
427
445
  }
446
+
447
+ /**
448
+ * An {@link AppOwner} for encrypting device-only data.
449
+ *
450
+ * Device-only data belongs to the current device rather than to the synced app
451
+ * identity. A common example is the last used {@link AppOwner}, which can be
452
+ * stored so users do not need to enter the mnemonic every time they reopen the
453
+ * app.
454
+ *
455
+ * This data must be encrypted because other OS processes may be able to read
456
+ * unencrypted app-controlled storage such as `localStorage`, `IndexedDB`, or
457
+ * similar stores.
458
+ *
459
+ * DeviceAppOwner is backed by a platform-specific secure primitive such as Expo
460
+ * SecureStore, Electron safeStorage, or WebAuthn PRF.
461
+ *
462
+ * Use DeviceAppOwner with a local-only Evolu instance. Local-only means an
463
+ * Evolu instance with empty transports (`transports: []`) so it does not sync
464
+ * its AppOwner, and local-only (prefixed with "_") tables.
465
+ *
466
+ * A local-only Evolu instance is better than plain platform storage because
467
+ * device-only data gets schema, reactivity, and the same cross-platform
468
+ * behavior as the rest of Evolu.
469
+ *
470
+ * The local-only Evolu instance can still use other owners for sync via
471
+ * `useOwner`. Use it for data that belongs to the current device rather than
472
+ * the user app Evolu instance (news delivery etc.).
473
+ *
474
+ * DeviceAppOwner Evolu instance is secure only when its data stays on the
475
+ * device.
476
+ */
477
+ export interface DeviceAppOwner extends AppOwner {
478
+ readonly source: "ExpoSecureStore" | "WebAuthnPrf" | "ElectronSafeStorage";
479
+ }