@evolu/common 6.0.1-preview.19 → 6.0.1-preview.20

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 (140) hide show
  1. package/dist/src/Assert.d.ts.map +1 -1
  2. package/dist/src/Assert.js +1 -1
  3. package/dist/src/Buffer.d.ts +1 -1
  4. package/dist/src/Buffer.d.ts.map +1 -1
  5. package/dist/src/Buffer.js +1 -1
  6. package/dist/src/CallbackRegistry.d.ts +53 -0
  7. package/dist/src/CallbackRegistry.d.ts.map +1 -0
  8. package/dist/src/CallbackRegistry.js +25 -0
  9. package/dist/src/Console.d.ts +31 -6
  10. package/dist/src/Console.d.ts.map +1 -1
  11. package/dist/src/Console.js +72 -9
  12. package/dist/src/Crypto.d.ts +48 -37
  13. package/dist/src/Crypto.d.ts.map +1 -1
  14. package/dist/src/Crypto.js +27 -50
  15. package/dist/src/Evolu/Db.d.ts +138 -66
  16. package/dist/src/Evolu/Db.d.ts.map +1 -1
  17. package/dist/src/Evolu/Db.js +248 -645
  18. package/dist/src/Evolu/Diff.d.ts +3 -3
  19. package/dist/src/Evolu/Diff.d.ts.map +1 -1
  20. package/dist/src/Evolu/Diff.js +7 -5
  21. package/dist/src/Evolu/Evolu.d.ts +79 -116
  22. package/dist/src/Evolu/Evolu.d.ts.map +1 -1
  23. package/dist/src/Evolu/Evolu.js +275 -132
  24. package/dist/src/Evolu/Internal.d.ts +0 -2
  25. package/dist/src/Evolu/Internal.d.ts.map +1 -1
  26. package/dist/src/Evolu/Internal.js +0 -2
  27. package/dist/src/Evolu/LocalAuth.d.ts +144 -0
  28. package/dist/src/Evolu/LocalAuth.d.ts.map +1 -0
  29. package/dist/src/Evolu/LocalAuth.js +171 -0
  30. package/dist/src/Evolu/Owner.d.ts +129 -83
  31. package/dist/src/Evolu/Owner.d.ts.map +1 -1
  32. package/dist/src/Evolu/Owner.js +80 -89
  33. package/dist/src/Evolu/Platform.d.ts +9 -7
  34. package/dist/src/Evolu/Platform.d.ts.map +1 -1
  35. package/dist/src/Evolu/Protocol.d.ts +114 -191
  36. package/dist/src/Evolu/Protocol.d.ts.map +1 -1
  37. package/dist/src/Evolu/Protocol.js +409 -416
  38. package/dist/src/Evolu/Public.d.ts +6 -8
  39. package/dist/src/Evolu/Public.d.ts.map +1 -1
  40. package/dist/src/Evolu/Public.js +2 -3
  41. package/dist/src/Evolu/PublicKysely.js +3 -3
  42. package/dist/src/Evolu/Relay.d.ts +1 -2
  43. package/dist/src/Evolu/Relay.d.ts.map +1 -1
  44. package/dist/src/Evolu/Relay.js +11 -9
  45. package/dist/src/Evolu/Schema.d.ts +88 -27
  46. package/dist/src/Evolu/Schema.d.ts.map +1 -1
  47. package/dist/src/Evolu/Schema.js +141 -24
  48. package/dist/src/Evolu/Storage.d.ts +158 -14
  49. package/dist/src/Evolu/Storage.d.ts.map +1 -1
  50. package/dist/src/Evolu/Storage.js +32 -32
  51. package/dist/src/Evolu/Sync.d.ts +77 -13
  52. package/dist/src/Evolu/Sync.d.ts.map +1 -1
  53. package/dist/src/Evolu/Sync.js +453 -20
  54. package/dist/src/Evolu/Timestamp.d.ts +29 -27
  55. package/dist/src/Evolu/Timestamp.d.ts.map +1 -1
  56. package/dist/src/Evolu/Timestamp.js +20 -18
  57. package/dist/src/ManyToManyMap.d.ts +74 -10
  58. package/dist/src/ManyToManyMap.d.ts.map +1 -1
  59. package/dist/src/ManyToManyMap.js +41 -6
  60. package/dist/src/Random.d.ts +3 -2
  61. package/dist/src/Random.d.ts.map +1 -1
  62. package/dist/src/RefCountedResourceManager.d.ts +119 -0
  63. package/dist/src/RefCountedResourceManager.d.ts.map +1 -0
  64. package/dist/src/RefCountedResourceManager.js +197 -0
  65. package/dist/src/Result.d.ts +144 -22
  66. package/dist/src/Result.d.ts.map +1 -1
  67. package/dist/src/Result.js +5 -2
  68. package/dist/src/Sqlite.d.ts +20 -4
  69. package/dist/src/Sqlite.d.ts.map +1 -1
  70. package/dist/src/Sqlite.js +50 -8
  71. package/dist/src/Task.d.ts +511 -0
  72. package/dist/src/Task.d.ts.map +1 -0
  73. package/dist/src/Task.js +410 -0
  74. package/dist/src/Time.d.ts +59 -0
  75. package/dist/src/Time.d.ts.map +1 -1
  76. package/dist/src/Time.js +87 -4
  77. package/dist/src/Type.d.ts +431 -341
  78. package/dist/src/Type.d.ts.map +1 -1
  79. package/dist/src/Type.js +458 -466
  80. package/dist/src/WebSocket.d.ts +5 -2
  81. package/dist/src/WebSocket.d.ts.map +1 -1
  82. package/dist/src/WebSocket.js +12 -13
  83. package/dist/src/Worker.d.ts +39 -11
  84. package/dist/src/Worker.d.ts.map +1 -1
  85. package/dist/src/Worker.js +22 -4
  86. package/dist/src/index.d.ts +2 -3
  87. package/dist/src/index.d.ts.map +1 -1
  88. package/dist/src/index.js +2 -3
  89. package/package.json +7 -7
  90. package/src/Assert.ts +2 -4
  91. package/src/Buffer.ts +1 -1
  92. package/src/CallbackRegistry.ts +84 -0
  93. package/src/Console.ts +91 -11
  94. package/src/Crypto.ts +78 -91
  95. package/src/Evolu/Db.ts +455 -947
  96. package/src/Evolu/Diff.ts +7 -5
  97. package/src/Evolu/Evolu.ts +545 -307
  98. package/src/Evolu/Internal.ts +0 -2
  99. package/src/Evolu/LocalAuth.ts +422 -0
  100. package/src/Evolu/Owner.ts +191 -131
  101. package/src/Evolu/Platform.ts +9 -9
  102. package/src/Evolu/Protocol.ts +536 -653
  103. package/src/Evolu/Public.ts +7 -9
  104. package/src/Evolu/PublicKysely.ts +3 -3
  105. package/src/Evolu/Relay.ts +17 -12
  106. package/src/Evolu/Schema.ts +271 -66
  107. package/src/Evolu/Storage.ts +263 -55
  108. package/src/Evolu/Sync.ts +758 -37
  109. package/src/Evolu/Timestamp.ts +30 -35
  110. package/src/ManyToManyMap.ts +127 -24
  111. package/src/Random.ts +3 -2
  112. package/src/RefCountedResourceManager.ts +368 -0
  113. package/src/Result.ts +149 -23
  114. package/src/Sqlite.ts +59 -24
  115. package/src/Task.ts +779 -0
  116. package/src/Time.ts +168 -4
  117. package/src/Type.ts +657 -695
  118. package/src/WebSocket.ts +23 -17
  119. package/src/Worker.ts +72 -23
  120. package/src/index.ts +2 -3
  121. package/dist/src/Callbacks.d.ts +0 -20
  122. package/dist/src/Callbacks.d.ts.map +0 -1
  123. package/dist/src/Callbacks.js +0 -18
  124. package/dist/src/Evolu/Config.d.ts +0 -82
  125. package/dist/src/Evolu/Config.d.ts.map +0 -1
  126. package/dist/src/Evolu/Config.js +0 -9
  127. package/dist/src/Evolu/Kysely.d.ts +0 -6
  128. package/dist/src/Evolu/Kysely.d.ts.map +0 -1
  129. package/dist/src/Evolu/Kysely.js +0 -21
  130. package/dist/src/NanoId.d.ts +0 -27
  131. package/dist/src/NanoId.d.ts.map +0 -1
  132. package/dist/src/NanoId.js +0 -6
  133. package/dist/src/Promise.d.ts +0 -180
  134. package/dist/src/Promise.d.ts.map +0 -1
  135. package/dist/src/Promise.js +0 -176
  136. package/src/Callbacks.ts +0 -43
  137. package/src/Evolu/Config.ts +0 -97
  138. package/src/Evolu/Kysely.ts +0 -38
  139. package/src/NanoId.ts +0 -39
  140. package/src/Promise.ts +0 -295
@@ -1,118 +1,159 @@
1
- /* eslint-disable jsdoc/no-undefined-types */
2
- /**
3
- * Evolu Owner - Data Ownership and Collaboration
4
- *
5
- * An {@link Owner} is an entity that represents ownership of data in Evolu. It
6
- * consists of cryptographic keys derived from a {@link Mnemonic} via SLIP-21:
7
- *
8
- * - **{@link OwnerId}**: Globally unique public identifier
9
- * - **{@link EncryptionKey}**: Symmetric encryption key for data protection
10
- * - **{@link WriteKey}**: Authentication token for write operations
11
- *
12
- * Every Evolu app has at least one owner, the {@link AppOwner}. There are
13
- * several owner variants for different use cases:
14
- *
15
- * **{@link ShardOwner}**: Derived from {@link AppOwner} for partitioning data and
16
- * selective synchronization using {@link createShardOwner}
17
- *
18
- * **{@link SharedOwner}**: Created for collaboration with write access, not
19
- * meant to be shared directly
20
- *
21
- * **{@link SharedReadonlyOwner}**: Read-only version for safe data sharing,
22
- * created from {@link SharedOwner} using {@link createSharedReadonlyOwner}
23
- *
24
- * Owners are designed for data synchronization and backup. Authentication
25
- * systems built on public/private key cryptography use these primitives. This
26
- * design ensures Evolu Relay knows as little as possible - it only sees
27
- * Timestamp, OwnerId, and EncryptedDbChange.
28
- *
29
- * @module
30
- */
31
-
1
+ import * as bip39 from "@scure/bip39";
2
+ import { wordlist } from "@scure/bip39/wordlists/english.js";
32
3
  import { NonEmptyReadonlyArray } from "../Array.js";
33
4
  import {
34
- CreateMnemonicDep,
35
- CreateRandomBytesDep,
36
5
  createSlip21,
37
- createSlip21Id,
38
6
  EncryptionKey,
39
- MnemonicSeed,
40
- mnemonicToMnemonicSeed,
7
+ Entropy16,
8
+ Entropy32,
9
+ RandomBytesDep,
41
10
  } from "../Crypto.js";
42
11
  import {
43
- Base64Url,
44
12
  brand,
45
13
  Id,
46
- length,
14
+ IdBytes,
15
+ idBytesToId,
16
+ idToIdBytes,
47
17
  Mnemonic,
48
18
  NonNegativeInt,
49
- Uint8Array,
50
19
  } from "../Type.js";
51
20
 
52
21
  /**
53
- * Represents ownership of data in Evolu. Created from a {@link Mnemonic} via
54
- * SLIP-21 key derivation using {@link createOwner}, providing cryptographic keys
55
- * for data access and authentication.
22
+ * 32 bytes of cryptographic entropy used to derive {@link Owner} keys.
23
+ *
24
+ * Can be created using {@link createOwnerSecret} or converted from a
25
+ * {@link Mnemonic} using {@link mnemonicToOwnerSecret}.
26
+ */
27
+ export const OwnerSecret = brand("OwnerSecret", Entropy32);
28
+ export type OwnerSecret = typeof OwnerSecret.Type;
29
+
30
+ /** Creates a {@link OwnerSecret}. */
31
+ export const createOwnerSecret = (deps: RandomBytesDep): OwnerSecret =>
32
+ deps.randomBytes.create(32) as OwnerSecret;
33
+
34
+ /** Converts an {@link OwnerSecret} to a {@link Mnemonic}. */
35
+ export const ownerSecretToMnemonic = (secret: OwnerSecret): Mnemonic =>
36
+ bip39.entropyToMnemonic(secret, wordlist) as Mnemonic;
37
+
38
+ /** Converts a {@link Mnemonic} to an {@link OwnerSecret}. */
39
+ export const mnemonicToOwnerSecret = (mnemonic: Mnemonic): OwnerSecret =>
40
+ bip39.mnemonicToEntropy(mnemonic, wordlist) as OwnerSecret;
41
+
42
+ /**
43
+ * The Owner represents ownership of data in Evolu. Every database change is
44
+ * assigned to an owner, enabling sync functionality and access control.
45
+ *
46
+ * Owners enable **partial sync** - applications can choose which owners to
47
+ * sync, allowing selective data synchronization based on specific needs.
48
+ *
49
+ * Owners also provide **real data deletion** - while individual changes in
50
+ * local-first/distributed systems can only be marked as deleted, entire owners
51
+ * can be completely deleted from both relays and devices (except for
52
+ * {@link AppOwner}, which must be preserved for sync coordination).
53
+ *
54
+ * Evolu provides different owner types depending on their use case:
55
+ *
56
+ * - **Coordination**: {@link AppOwner} for sync coordination and long-term
57
+ * persistence
58
+ * - **Data partitioning**: {@link ShardOwner} for partitioning application data
59
+ * - **Collaboration**: {@link SharedOwner} for collaborative write access
60
+ * - **Data sharing**: {@link SharedReadonlyOwner} for read-only access to shared
61
+ * data
62
+ *
63
+ * Owners are cryptographically derived from an {@link OwnerSecret} using
64
+ * SLIP-21, ensuring secure and deterministic key generation:
56
65
  *
57
66
  * - {@link OwnerId}: Globally unique public identifier
58
67
  * - {@link EncryptionKey}: Symmetric encryption key for data protection
59
- * - {@link WriteKey}: Authentication token for write operations (rotatable)
68
+ * - {@link OwnerWriteKey}: Authentication token for write operations (rotatable)
69
+ *
70
+ * @see {@link createOwner}
60
71
  */
61
72
  export interface Owner {
62
73
  readonly id: OwnerId;
63
- readonly encryptionKey: EncryptionKey;
64
- readonly writeKey: WriteKey;
74
+ readonly encryptionKey: OwnerEncryptionKey;
75
+ readonly writeKey: OwnerWriteKey;
65
76
  }
66
77
 
67
78
  /**
68
- * The unique identifier of {@link Owner} derived from the {@link Mnemonic}.
69
- *
70
- * This branded {@link Id} type, generated by {@link createSlip21Id}, is a
71
- * 21-character {@link Base64Url} string (126 bits of entropy), providing a
72
- * compact, shareable, and secure identifier for UI use, tied to the owner's
73
- * mnemonic and derivation path.
79
+ * OwnerId is a branded {@link Id} that uniquely identifies an {@link Owner}.
80
+ * Branded from {@link Id} to leverage existing helpers like {@link idToIdBytes}.
74
81
  */
75
82
  export const OwnerId = brand("OwnerId", Id);
76
83
  export type OwnerId = typeof OwnerId.Type;
77
84
 
78
- export const writeKeyLength = 16 as NonNegativeInt;
85
+ /** Bytes representation of {@link OwnerId}. */
86
+ export const OwnerIdBytes = brand("OwnerIdBytes", IdBytes);
87
+ export type OwnerIdBytes = typeof OwnerIdBytes.Type;
88
+
89
+ export const ownerIdToOwnerIdBytes = (ownerId: OwnerId): OwnerIdBytes =>
90
+ idToIdBytes(ownerId) as OwnerIdBytes;
91
+
92
+ export const ownerIdBytesToOwnerId = (ownerIdBytes: OwnerIdBytes): OwnerId =>
93
+ idBytesToId(ownerIdBytes as IdBytes) as OwnerId;
94
+
95
+ export const ownerWriteKeyLength = 16 as NonNegativeInt;
96
+
97
+ export const OwnerEncryptionKey = brand("OwnerEncryptionKey", EncryptionKey);
98
+ export type OwnerEncryptionKey = typeof OwnerEncryptionKey.Type;
79
99
 
80
100
  /**
81
- * A secure token proving that the initiator can write changes. Derived from a
82
- * mnemonic or randomly generated via {@link createWriteKey}. It is rotatable.
101
+ * A secure token for write operations. It's derived from {@link OwnerSecret} by
102
+ * default and can be rotated via {@link createOwnerWriteKey}.
83
103
  */
84
- export const WriteKey = brand("WriteKey", length(writeKeyLength)(Uint8Array));
85
- export type WriteKey = typeof WriteKey.Type;
86
-
87
- /** Creates a randomly generated {@link WriteKey}. */
88
- export const createWriteKey = (deps: CreateRandomBytesDep): WriteKey =>
89
- deps.createRandomBytes(16) as unknown as WriteKey;
104
+ export const OwnerWriteKey = brand("OwnerWriteKey", Entropy16);
105
+ export type OwnerWriteKey = typeof OwnerWriteKey.Type;
90
106
 
91
- /** Creates an {@link Owner} from a {@link Mnemonic} using SLIP-21 key derivation. */
92
- export const createOwner = (mnemonic: Mnemonic): Owner => {
93
- const seed = mnemonicToMnemonicSeed(mnemonic);
94
- return createOwnerFromMnemonicSeed(seed);
95
- };
107
+ /** Creates a randomly generated {@link OwnerWriteKey}. */
108
+ export const createOwnerWriteKey = (deps: RandomBytesDep): OwnerWriteKey =>
109
+ deps.randomBytes.create(16) as OwnerWriteKey;
96
110
 
97
111
  /**
98
- * Creates an {@link Owner} from a {@link MnemonicSeed} using SLIP-21 key
112
+ * Creates an {@link Owner} from a {@link OwnerSecret} using SLIP-21 key
99
113
  * derivation.
114
+ *
115
+ * This is an internal helper function, use:
116
+ *
117
+ * - {@link createAppOwner}
118
+ * - {@link createShardOwner}
119
+ * - {@link createSharedOwner}
120
+ * - {@link createSharedReadonlyOwner}
100
121
  */
101
- export const createOwnerFromMnemonicSeed = (seed: MnemonicSeed): Owner => ({
102
- id: createSlip21Id(seed, ["Evolu", "Owner Id"]) as OwnerId,
122
+ export const createOwner = (secret: OwnerSecret): Owner => ({
123
+ id: ownerIdBytesToOwnerId(
124
+ OwnerIdBytes.orThrow(
125
+ createSlip21(secret, ["Evolu", "OwnerIdBytes"]).slice(0, 16),
126
+ ),
127
+ ),
103
128
 
104
- encryptionKey: createSlip21(seed, [
105
- "Evolu",
106
- "Encryption Key",
107
- ]) as EncryptionKey,
129
+ encryptionKey: OwnerEncryptionKey.orThrow(
130
+ createSlip21(secret, ["Evolu", "OwnerEncryptionKey"]),
131
+ ),
108
132
 
109
- writeKey: createSlip21(seed, ["Evolu", "Write Key"]).slice(0, 16) as WriteKey,
133
+ writeKey: OwnerWriteKey.orThrow(
134
+ createSlip21(secret, ["Evolu", "OwnerWriteKey"]).slice(0, 16),
135
+ ),
110
136
  });
111
137
 
112
138
  /**
113
- * The owner representing app data. Can be created from a {@link Mnemonic} or
114
- * from external keys when the mnemonic should not be shared with the Evolu
115
- * app.
139
+ * The AppOwner represents the application owner. It's created using a
140
+ * cryptographically secure random generator or derived from an external source,
141
+ * e.g., mnemonic stored securely in a hardware device.
142
+ *
143
+ * While it's possible to store all application data in AppOwner, the better
144
+ * approach is to use it only for sync coordination. Storing all app data in
145
+ * AppOwner means that data will be stored/synced forever. And that's a problem
146
+ * if we want to provide real data deletion or in-app data migration without
147
+ * data duplication. In local-first apps/distributed systems, we can't delete
148
+ * individual changes, we only mark them as deleted, otherwise sync could not
149
+ * work.
150
+ *
151
+ * If we really want to delete data or at least avoid syncing it, we must store
152
+ * it using a different owner than AppOwner, e.g. {@link ShardOwner} or
153
+ * {@link SharedOwner}, and delete that owner. The AppOwner itself must be
154
+ * preserved because it coordinates deletion information across devices. Other
155
+ * devices need to sync the information that an owner was deleted so they can
156
+ * delete their local data as well.
116
157
  */
117
158
  export interface AppOwner extends Owner {
118
159
  readonly type: "AppOwner";
@@ -125,71 +166,102 @@ export interface AppOwner extends Owner {
125
166
  readonly mnemonic?: Mnemonic | null;
126
167
  }
127
168
 
128
- export const createAppOwner = (mnemonic: Mnemonic): AppOwner => ({
169
+ /** Creates an {@link AppOwner} from an {@link OwnerSecret}. */
170
+ export const createAppOwner = (secret: OwnerSecret): AppOwner => ({
129
171
  type: "AppOwner",
130
- mnemonic,
131
- ...createOwner(mnemonic),
172
+ mnemonic: ownerSecretToMnemonic(secret),
173
+ ...createOwner(secret),
132
174
  });
133
175
 
176
+ // DEV: Future transports: Bluetooth, LocalNetwork, etc.
177
+ export type TransportConfig = WebSocketTransportConfig;
178
+
179
+ export interface WebSocketTransportConfig {
180
+ readonly type: "WebSocket";
181
+ readonly url: string;
182
+ }
183
+
134
184
  /**
135
- * Owner for sharding app data. Allows partitioning of database changes for
136
- * selective synchronization.
185
+ * An {@link Owner} for sharding data.
186
+ *
187
+ * ShardOwners are the recommended storage location for most application data
188
+ * because they can be completely deleted (both on relays and devices) and
189
+ * conditionally synced.
190
+ *
191
+ * Can be created from {@link OwnerSecret} via {@link createShardOwner} or
192
+ * deterministically derived from {@link AppOwner} using
193
+ * {@link deriveShardOwner}.
137
194
  */
138
195
  export interface ShardOwner extends Owner {
139
196
  readonly type: "ShardOwner";
197
+ readonly transports?: ReadonlyArray<TransportConfig>;
140
198
  }
141
199
 
142
- /**
143
- * Creates a {@link ShardOwner} derived from an {@link AppOwner} using the
144
- * specified path.
145
- *
146
- * ### Example
147
- *
148
- * ```ts
149
- * const contactsShard = createShardOwner(appOwner, ["contacts"]);
150
- * const projectShard = createShardOwner(appOwner, [
151
- * "projects",
152
- * "project-1",
153
- * ]);
154
- * ```
155
- */
200
+ /** Creates a {@link ShardOwner} from an {@link OwnerSecret}. */
156
201
  export const createShardOwner = (
157
- appOwner: AppOwner,
158
- path: NonEmptyReadonlyArray<string>,
202
+ secret: OwnerSecret,
203
+ transports?: ReadonlyArray<TransportConfig>,
159
204
  ): ShardOwner => {
160
- /**
161
- * The shardSeed is never shared or persisted, only used for SLIP-21
162
- * derivation to create shard-specific keys.
163
- */
164
- const shardSeed = createSlip21(
165
- appOwner.encryptionKey as unknown as MnemonicSeed,
166
- path,
167
- ) as MnemonicSeed;
168
-
169
205
  return {
170
206
  type: "ShardOwner",
171
- ...createOwnerFromMnemonicSeed(shardSeed),
207
+ ...createOwner(secret),
208
+ ...(transports && { transports }),
172
209
  };
173
210
  };
174
211
 
175
212
  /**
176
- * Owner for collaborative data with write access. Created by a user for their
177
- * own use, not meant to be shared directly. To share data, use
178
- * {@link createSharedReadonlyOwner} to create a {@link SharedReadonlyOwner} for
179
- * read-only access.
213
+ * Derives a {@link ShardOwner} from an {@link AppOwner} using the specified path.
214
+ *
215
+ * **Advantages of derived owners:**
216
+ *
217
+ * - **Deterministic**: Same path always produces the same ShardOwner across all
218
+ * devices
219
+ * - **Immediate availability**: Can be hardcoded and used before sync occurs
220
+ * - **Consistent setup**: All devices start with identical data structure
221
+ * - **Lifecycle management**: Can implement epoch patterns for clean data
222
+ * deletion and recreation
223
+ *
224
+ * **Common patterns:**
225
+ *
226
+ * - Use paths like `["shard", 1]` for versioned data lifecycle
227
+ * - Use paths like `["project", "MyApp", 1]` for named partitions with versions
228
+ * - Each device can derive the same owners and set up initial structure
180
229
  */
230
+ export const deriveShardOwner = (
231
+ owner: AppOwner,
232
+ path: NonEmptyReadonlyArray<string | number>,
233
+ transports?: ReadonlyArray<TransportConfig>,
234
+ ): ShardOwner => {
235
+ const secret = createSlip21(owner.encryptionKey, path) as OwnerSecret;
236
+
237
+ return {
238
+ type: "ShardOwner",
239
+ ...createOwner(secret),
240
+ ...(transports && { transports }),
241
+ };
242
+ };
243
+
244
+ /** An {@link Owner} for collaborative data with write access. */
181
245
  export interface SharedOwner extends Owner {
182
246
  readonly type: "SharedOwner";
183
- readonly mnemonic: Mnemonic;
247
+ readonly transports?: ReadonlyArray<TransportConfig>;
184
248
  }
185
249
 
186
- /** Creates a {@link SharedOwner} with a freshly generated {@link Mnemonic}. */
187
- export const createSharedOwner = (deps: CreateMnemonicDep): SharedOwner => {
188
- const mnemonic = deps.createMnemonic();
250
+ /**
251
+ * Creates a {@link SharedOwner} from an {@link OwnerSecret} for collaborative
252
+ * write access.
253
+ *
254
+ * Use {@link createSharedReadonlyOwner} to create a read-only version for
255
+ * sharing.
256
+ */
257
+ export const createSharedOwner = (
258
+ secret: OwnerSecret,
259
+ transports?: ReadonlyArray<TransportConfig>,
260
+ ): SharedOwner => {
189
261
  return {
190
262
  type: "SharedOwner",
191
- mnemonic,
192
- ...createOwner(mnemonic),
263
+ ...createOwner(secret),
264
+ ...(transports && { transports }),
193
265
  };
194
266
  };
195
267
 
@@ -202,6 +274,7 @@ export interface SharedReadonlyOwner {
202
274
  readonly type: "SharedReadonlyOwner";
203
275
  readonly id: OwnerId;
204
276
  readonly encryptionKey: EncryptionKey;
277
+ readonly transports?: ReadonlyArray<TransportConfig>;
205
278
  }
206
279
 
207
280
  /** Creates a {@link SharedReadonlyOwner} from a {@link SharedOwner}. */
@@ -211,18 +284,5 @@ export const createSharedReadonlyOwner = (
211
284
  type: "SharedReadonlyOwner",
212
285
  id: sharedOwner.id,
213
286
  encryptionKey: sharedOwner.encryptionKey,
287
+ ...(sharedOwner.transports && { transports: sharedOwner.transports }),
214
288
  });
215
-
216
- /**
217
- * Rotates the {@link WriteKey} for an {@link AppOwner}, {@link ShardOwner}, or
218
- * {@link SharedOwner}, returning a new instance with the updated key.
219
- */
220
- export const rotateWriteKey = <T extends AppOwner | ShardOwner | SharedOwner>(
221
- owner: T,
222
- newWriteKey: WriteKey,
223
- ): T => {
224
- return {
225
- ...owner,
226
- writeKey: newWriteKey,
227
- } as T;
228
- };
@@ -1,5 +1,3 @@
1
- import { Config } from "./Config.js";
2
-
3
1
  /**
4
2
  * FlushSync is for libraries like React to flush updates synchronously inside
5
3
  * the provided callback to ensure the DOM is updated immediately.
@@ -16,12 +14,14 @@ export interface FlushSyncDep {
16
14
  readonly flushSync: FlushSync;
17
15
  }
18
16
 
19
- export interface AppState {
20
- readonly reset: () => void;
21
- }
22
-
23
- export type CreateAppState = (config: Config) => AppState;
17
+ /**
18
+ * Reload the app in a platform-specific way.
19
+ *
20
+ * - **Web**: Redirects to the specified URL
21
+ * - **React Native**: Restarts the app (URL parameter ignored)
22
+ */
23
+ export type ReloadApp = (url: string) => void;
24
24
 
25
- export interface CreateAppStateDep {
26
- readonly createAppState: CreateAppState;
25
+ export interface ReloadAppDep {
26
+ readonly reloadApp: ReloadApp;
27
27
  }