@weaveprotocol/core 0.1.1 → 0.2.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 (183) hide show
  1. package/README.md +264 -42
  2. package/dist/identity/contact-key.d.ts +42 -0
  3. package/dist/identity/contact-key.d.ts.map +1 -0
  4. package/dist/identity/contact-key.js +133 -0
  5. package/dist/identity/contact-key.js.map +1 -0
  6. package/dist/index.d.ts +16 -7
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +10 -5
  9. package/dist/index.js.map +1 -1
  10. package/dist/network/mesh.d.ts +6 -0
  11. package/dist/network/mesh.d.ts.map +1 -1
  12. package/dist/network/mesh.js +11 -1
  13. package/dist/network/mesh.js.map +1 -1
  14. package/dist/network/multi-signaling.d.ts +12 -2
  15. package/dist/network/multi-signaling.d.ts.map +1 -1
  16. package/dist/network/multi-signaling.js +86 -14
  17. package/dist/network/multi-signaling.js.map +1 -1
  18. package/dist/network/peer-auth.d.ts +50 -16
  19. package/dist/network/peer-auth.d.ts.map +1 -1
  20. package/dist/network/peer-auth.js +52 -15
  21. package/dist/network/peer-auth.js.map +1 -1
  22. package/dist/node/carrier.d.ts +87 -0
  23. package/dist/node/carrier.d.ts.map +1 -1
  24. package/dist/node/carrier.js +180 -59
  25. package/dist/node/carrier.js.map +1 -1
  26. package/dist/node/copy.d.ts.map +1 -1
  27. package/dist/node/copy.js +6 -3
  28. package/dist/node/copy.js.map +1 -1
  29. package/dist/node/host.d.ts +117 -0
  30. package/dist/node/host.d.ts.map +1 -0
  31. package/dist/node/host.js +192 -0
  32. package/dist/node/host.js.map +1 -0
  33. package/dist/node/index.d.ts +6 -2
  34. package/dist/node/index.d.ts.map +1 -1
  35. package/dist/node/index.js +1 -0
  36. package/dist/node/index.js.map +1 -1
  37. package/dist/node/node.d.ts.map +1 -1
  38. package/dist/node/node.js +640 -25
  39. package/dist/node/node.js.map +1 -1
  40. package/dist/node/space-runtime.d.ts +42 -25
  41. package/dist/node/space-runtime.d.ts.map +1 -1
  42. package/dist/node/space-runtime.js +734 -35
  43. package/dist/node/space-runtime.js.map +1 -1
  44. package/dist/node/types.d.ts +269 -3
  45. package/dist/node/types.d.ts.map +1 -1
  46. package/dist/privacy/space-encryption.d.ts +16 -0
  47. package/dist/privacy/space-encryption.d.ts.map +1 -1
  48. package/dist/privacy/space-encryption.js +40 -0
  49. package/dist/privacy/space-encryption.js.map +1 -1
  50. package/dist/query/engine.js +1 -1
  51. package/dist/query/engine.js.map +1 -1
  52. package/dist/query/types.d.ts +7 -0
  53. package/dist/query/types.d.ts.map +1 -1
  54. package/dist/query/types.js.map +1 -1
  55. package/dist/react/use-query.d.ts +1 -1
  56. package/dist/react/use-query.d.ts.map +1 -1
  57. package/dist/records/topics.d.ts +21 -0
  58. package/dist/records/topics.d.ts.map +1 -0
  59. package/dist/records/topics.js +86 -0
  60. package/dist/records/topics.js.map +1 -0
  61. package/dist/schema/collection-def.d.ts +7 -0
  62. package/dist/schema/collection-def.d.ts.map +1 -1
  63. package/dist/schema/collection-def.js +4 -0
  64. package/dist/schema/collection-def.js.map +1 -1
  65. package/dist/schema/expression.d.ts +2 -0
  66. package/dist/schema/expression.d.ts.map +1 -1
  67. package/dist/schema/expression.js +1 -0
  68. package/dist/schema/expression.js.map +1 -1
  69. package/dist/schemas/contacts.d.ts +77 -0
  70. package/dist/schemas/contacts.d.ts.map +1 -0
  71. package/dist/schemas/contacts.js +35 -0
  72. package/dist/schemas/contacts.js.map +1 -0
  73. package/dist/schemas/index.d.ts +2 -0
  74. package/dist/schemas/index.d.ts.map +1 -1
  75. package/dist/schemas/index.js +1 -0
  76. package/dist/schemas/index.js.map +1 -1
  77. package/dist/session/auth.d.ts.map +1 -1
  78. package/dist/session/auth.js +14 -3
  79. package/dist/session/auth.js.map +1 -1
  80. package/dist/session/connect.d.ts +25 -1
  81. package/dist/session/connect.d.ts.map +1 -1
  82. package/dist/session/connect.js +9 -2
  83. package/dist/session/connect.js.map +1 -1
  84. package/dist/session/hosting.d.ts +155 -0
  85. package/dist/session/hosting.d.ts.map +1 -0
  86. package/dist/session/hosting.js +160 -0
  87. package/dist/session/hosting.js.map +1 -0
  88. package/dist/space/account-registry.d.ts +6 -0
  89. package/dist/space/account-registry.d.ts.map +1 -1
  90. package/dist/space/account-registry.js +16 -4
  91. package/dist/space/account-registry.js.map +1 -1
  92. package/dist/space/notify.d.ts +88 -0
  93. package/dist/space/notify.d.ts.map +1 -0
  94. package/dist/space/notify.js +127 -0
  95. package/dist/space/notify.js.map +1 -0
  96. package/dist/space/pass.d.ts +6 -0
  97. package/dist/space/pass.d.ts.map +1 -1
  98. package/dist/space/pass.js +5 -2
  99. package/dist/space/pass.js.map +1 -1
  100. package/dist/space/roles.d.ts +71 -0
  101. package/dist/space/roles.d.ts.map +1 -1
  102. package/dist/space/roles.js +114 -0
  103. package/dist/space/roles.js.map +1 -1
  104. package/dist/space/space-access.d.ts +24 -0
  105. package/dist/space/space-access.d.ts.map +1 -1
  106. package/dist/space/space-access.js +24 -0
  107. package/dist/space/space-access.js.map +1 -1
  108. package/dist/space/space-manager.d.ts +35 -1
  109. package/dist/space/space-manager.d.ts.map +1 -1
  110. package/dist/space/space-manager.js +72 -25
  111. package/dist/space/space-manager.js.map +1 -1
  112. package/dist/storage/blob/memory.d.ts +9 -0
  113. package/dist/storage/blob/memory.d.ts.map +1 -0
  114. package/dist/storage/blob/memory.js +20 -0
  115. package/dist/storage/blob/memory.js.map +1 -0
  116. package/dist/storage/blob/s3.d.ts +16 -0
  117. package/dist/storage/blob/s3.d.ts.map +1 -0
  118. package/dist/storage/blob/s3.js +86 -0
  119. package/dist/storage/blob/s3.js.map +1 -0
  120. package/dist/storage/blob-store.d.ts +26 -0
  121. package/dist/storage/blob-store.d.ts.map +1 -0
  122. package/dist/storage/blob-store.js +2 -0
  123. package/dist/storage/blob-store.js.map +1 -0
  124. package/dist/storage/encrypted-adapter.d.ts +3 -3
  125. package/dist/storage/encrypted-adapter.js +3 -3
  126. package/dist/storage/folder-adapter.d.ts +8 -8
  127. package/dist/storage/folder-adapter.d.ts.map +1 -1
  128. package/dist/storage/folder-adapter.js +7 -7
  129. package/dist/storage/folder-reconcile.d.ts +12 -14
  130. package/dist/storage/folder-reconcile.d.ts.map +1 -1
  131. package/dist/storage/folder-reconcile.js +20 -14
  132. package/dist/storage/folder-reconcile.js.map +1 -1
  133. package/dist/storage/index.d.ts +0 -1
  134. package/dist/storage/index.d.ts.map +1 -1
  135. package/dist/storage/index.js +0 -1
  136. package/dist/storage/index.js.map +1 -1
  137. package/dist/storage/indexeddb-adapter.d.ts.map +1 -1
  138. package/dist/storage/indexeddb-adapter.js +8 -9
  139. package/dist/storage/indexeddb-adapter.js.map +1 -1
  140. package/dist/storage/mirror.d.ts +68 -0
  141. package/dist/storage/mirror.d.ts.map +1 -0
  142. package/dist/storage/mirror.js +174 -0
  143. package/dist/storage/mirror.js.map +1 -0
  144. package/dist/storage/segment.d.ts +20 -0
  145. package/dist/storage/segment.d.ts.map +1 -0
  146. package/dist/storage/segment.js +27 -0
  147. package/dist/storage/segment.js.map +1 -0
  148. package/dist/storage/storage-provider.d.ts +36 -40
  149. package/dist/storage/storage-provider.d.ts.map +1 -1
  150. package/dist/storage/storage-provider.js +208 -117
  151. package/dist/storage/storage-provider.js.map +1 -1
  152. package/dist/sync/index.d.ts +1 -1
  153. package/dist/sync/index.d.ts.map +1 -1
  154. package/dist/sync/index.js +1 -1
  155. package/dist/sync/index.js.map +1 -1
  156. package/dist/sync/negentropy.d.ts +68 -0
  157. package/dist/sync/negentropy.d.ts.map +1 -0
  158. package/dist/sync/negentropy.js +379 -0
  159. package/dist/sync/negentropy.js.map +1 -0
  160. package/dist/sync/sync-engine.d.ts +45 -13
  161. package/dist/sync/sync-engine.d.ts.map +1 -1
  162. package/dist/sync/sync-engine.js +290 -207
  163. package/dist/sync/sync-engine.js.map +1 -1
  164. package/dist/sync/sync-messages.d.ts +42 -32
  165. package/dist/sync/sync-messages.d.ts.map +1 -1
  166. package/dist/sync/sync-messages.js +1 -1
  167. package/dist/sync/sync-messages.js.map +1 -1
  168. package/dist/types.d.ts +9 -0
  169. package/dist/types.d.ts.map +1 -1
  170. package/dist/types.js.map +1 -1
  171. package/dist/utils/hash.d.ts +9 -0
  172. package/dist/utils/hash.d.ts.map +1 -1
  173. package/dist/utils/hash.js +33 -0
  174. package/dist/utils/hash.js.map +1 -1
  175. package/package.json +9 -3
  176. package/dist/storage/mst.d.ts +0 -121
  177. package/dist/storage/mst.d.ts.map +0 -1
  178. package/dist/storage/mst.js +0 -402
  179. package/dist/storage/mst.js.map +0 -1
  180. package/dist/sync/anti-entropy.d.ts +0 -49
  181. package/dist/sync/anti-entropy.d.ts.map +0 -1
  182. package/dist/sync/anti-entropy.js +0 -62
  183. package/dist/sync/anti-entropy.js.map +0 -1
@@ -10,13 +10,16 @@
10
10
  */
11
11
  import { createP256Provider } from '../identity/crypto-p256.js';
12
12
  import { base64UrlEncode, base64UrlDecode, utf8Encode, utf8Decode } from '../utils/encoding.js';
13
- import { generateSpaceKey } from '../privacy/space-encryption.js';
13
+ import { generateSpaceKey, spaceKeyFromRaw } from '../privacy/space-encryption.js';
14
14
  import { checkSpace, checkStartingRoles, deriveInviteKey, deriveReadKey, spaceGenesis, spaceIdOf } from './space-access.js';
15
15
  import { solo } from './presets.js';
16
+ import { checkRelays } from './roles.js';
16
17
  const SPACE_PREFIX = 'space:';
17
18
  const KEY_PREFIX = 'spacekey:';
18
19
  const INVITE_PREFIX = 'spaceinvite:';
19
20
  const ROLE_PREFIX = 'spacerole:';
21
+ const MEMBER_KEY_PREFIX = 'spacememberkey:';
22
+ const RELAYS_PREFIX = 'spacerelays:';
20
23
  async function exportKey(key) {
21
24
  const raw = await globalThis.crypto.subtle.exportKey('raw', key.key);
22
25
  return {
@@ -43,16 +46,22 @@ export function createSpaceManager(adapter, provider = createP256Provider()) {
43
46
  async function writeSpace(space) {
44
47
  await adapter.put(`${SPACE_PREFIX}${space.id}`, utf8Encode(JSON.stringify(space)));
45
48
  }
46
- async function readKey(spaceId) {
49
+ async function readKeyring(spaceId) {
47
50
  const bytes = await adapter.get(`${KEY_PREFIX}${spaceId}`);
48
51
  if (!bytes)
49
- return null;
50
- return importKey(JSON.parse(utf8Decode(bytes)));
52
+ return { key: null, keys: [] };
53
+ const stored = JSON.parse(utf8Decode(bytes));
54
+ const keys = await Promise.all(stored.keys.map(importKey));
55
+ return { key: keys.find((key) => key.id === stored.current) ?? keys.at(-1) ?? null, keys };
51
56
  }
52
- async function writeKey(spaceId, key) {
53
- const stored = await exportKey(key);
57
+ async function writeKeyring(spaceId, keys, current) {
58
+ const stored = { keys: await Promise.all(keys.map(exportKey)), current };
54
59
  await adapter.put(`${KEY_PREFIX}${spaceId}`, utf8Encode(JSON.stringify(stored)));
55
60
  }
61
+ async function writeKey(spaceId, key) {
62
+ const { keys } = await readKeyring(spaceId);
63
+ await writeKeyring(spaceId, [...keys.filter((held) => held.id !== key.id), key], key.id);
64
+ }
56
65
  async function readText(prefix, spaceId) {
57
66
  const bytes = await adapter.get(`${prefix}${spaceId}`);
58
67
  return bytes ? utf8Decode(bytes) : null;
@@ -62,11 +71,17 @@ export function createSpaceManager(adapter, provider = createP256Provider()) {
62
71
  if (!space)
63
72
  return null;
64
73
  const invite = await readText(INVITE_PREFIX, spaceId);
74
+ const memberKey = await readText(MEMBER_KEY_PREFIX, spaceId);
75
+ const relays = await readText(RELAYS_PREFIX, spaceId);
76
+ const { key, keys } = await readKeyring(spaceId);
65
77
  return {
66
78
  space,
67
- key: await readKey(spaceId),
79
+ key,
80
+ keys,
68
81
  invite: invite ? base64UrlDecode(invite) : null,
69
82
  role: await readText(ROLE_PREFIX, spaceId),
83
+ ...(memberKey ? { memberKey: base64UrlDecode(memberKey) } : {}),
84
+ ...(relays ? { relays: JSON.parse(relays) } : {}),
70
85
  };
71
86
  }
72
87
  return Object.freeze({
@@ -95,7 +110,7 @@ export function createSpaceManager(adapter, provider = createP256Provider()) {
95
110
  if (key)
96
111
  await writeKey(id, key);
97
112
  await adapter.put(`${ROLE_PREFIX}${id}`, utf8Encode(creatorRole));
98
- return { space, key, invite: null, role: creatorRole };
113
+ return { space, key, keys: key ? [key] : [], invite: null, role: creatorRole };
99
114
  },
100
115
  async get(spaceId) {
101
116
  return load(spaceId);
@@ -108,23 +123,14 @@ export function createSpaceManager(adapter, provider = createP256Provider()) {
108
123
  .sort((a, b) => a.space.createdAt.localeCompare(b.space.createdAt));
109
124
  },
110
125
  async remove(spaceId) {
111
- for (const prefix of [SPACE_PREFIX, KEY_PREFIX, INVITE_PREFIX, ROLE_PREFIX])
126
+ for (const prefix of [SPACE_PREFIX, KEY_PREFIX, INVITE_PREFIX, ROLE_PREFIX, MEMBER_KEY_PREFIX, RELAYS_PREFIX])
112
127
  await adapter.delete(`${prefix}${spaceId}`);
113
128
  },
114
129
  async createInvite(spaceId, invitedBy, options = {}) {
115
130
  const record = await load(spaceId);
116
131
  if (!record)
117
132
  throw new Error(`Unknown space: ${spaceId}`);
118
- // The key rides along for private spaces — which is why an invite is a
119
- // secret, and why it belongs in a URL fragment rather than a path.
120
- const invite = {
121
- space: record.space,
122
- invitedBy,
123
- ...(record.key ? { key: (await exportKey(record.key)).raw } : {}),
124
- ...(options.secret ? { invite: base64UrlEncode(options.secret) } : {}),
125
- ...(options.secret && options.role ? { role: options.role } : {}),
126
- };
127
- return base64UrlEncode(utf8Encode(JSON.stringify(invite)));
133
+ return encodeSpaceInvite(record, invitedBy, options);
128
134
  },
129
135
  async join(invite) {
130
136
  const parsed = parseSpaceInvite(invite);
@@ -133,12 +139,12 @@ export function createSpaceManager(adapter, provider = createP256Provider()) {
133
139
  const problem = await checkSpace(parsed.space);
134
140
  if (problem)
135
141
  throw new Error(`That invite does not describe a real space: ${problem.charAt(0).toLowerCase()}${problem.slice(1)}.`);
136
- const key = parsed.key
137
- ? await importKey({ id: parsed.space.encryptionKeyId ?? '', raw: parsed.key, createdAt: parsed.space.createdAt, version: 1 })
138
- : null;
139
- if (key && (await deriveReadKey(key, provider)).did !== parsed.space.readKey) {
140
- throw new Error('That invite carries a key that does not belong to its space.');
141
- }
142
+ if (parsed.key && parsed.space.visibility !== 'private')
143
+ throw new Error('That invite carries a key for a space that has none.');
144
+ // The key may be the space's first or a later one — the space's key
145
+ // changed since. Its id is its hash, so it is only ever the key the
146
+ // history names or one that opens nothing.
147
+ const key = parsed.key ? await spaceKeyFromRaw(base64UrlDecode(parsed.key), parsed.space.createdAt) : null;
142
148
  const secret = parsed.invite ? base64UrlDecode(parsed.invite) : null;
143
149
  // A secret of the wrong length cannot be an invite's; refuse it here rather than wait on it forever.
144
150
  if (secret && secret.length !== 32)
@@ -152,11 +158,35 @@ export function createSpaceManager(adapter, provider = createP256Provider()) {
152
158
  // Joining again with a secret while one is waiting keeps the newer one.
153
159
  if (secret)
154
160
  await adapter.put(`${INVITE_PREFIX}${space.id}`, utf8Encode(base64UrlEncode(secret)));
161
+ // Only a hint, but a checked one: a relay list the space itself could not hold is dropped.
162
+ if (parsed.relays && checkRelays(parsed.relays) === null && parsed.relays.length > 0 && !(await readText(RELAYS_PREFIX, space.id))) {
163
+ await adapter.put(`${RELAYS_PREFIX}${space.id}`, utf8Encode(JSON.stringify(parsed.relays)));
164
+ }
155
165
  return (await load(space.id));
156
166
  },
157
167
  async clearInvite(spaceId) {
158
168
  await adapter.delete(`${INVITE_PREFIX}${spaceId}`);
159
169
  },
170
+ async addKeys(spaceId, keys, current) {
171
+ if (!(await readSpace(spaceId)))
172
+ return;
173
+ const held = (await readKeyring(spaceId)).keys;
174
+ const known = new Set(held.map((key) => key.id));
175
+ const all = [...held, ...keys.filter((key) => !known.has(key.id) && (known.add(key.id), true))];
176
+ if (!all.some((key) => key.id === current))
177
+ throw new Error('The current key must be one of the keys held');
178
+ await writeKeyring(spaceId, all, current);
179
+ },
180
+ async setRelays(spaceId, relays) {
181
+ if (!(await readSpace(spaceId)) || checkRelays(relays) !== null)
182
+ return;
183
+ await adapter.put(`${RELAYS_PREFIX}${spaceId}`, utf8Encode(JSON.stringify(relays)));
184
+ },
185
+ async setMemberKey(spaceId, memberKey) {
186
+ if (!(await readSpace(spaceId)))
187
+ return;
188
+ await adapter.put(`${MEMBER_KEY_PREFIX}${spaceId}`, utf8Encode(base64UrlEncode(memberKey)));
189
+ },
160
190
  async setRole(spaceId, role) {
161
191
  if (!(await readSpace(spaceId)))
162
192
  return;
@@ -167,6 +197,23 @@ export function createSpaceManager(adapter, provider = createP256Provider()) {
167
197
  },
168
198
  });
169
199
  }
200
+ /**
201
+ * Encodes a space, its key if private, and an invite's secret if given, as a
202
+ * shareable string — for a space this node holds, or one it derived.
203
+ */
204
+ export async function encodeSpaceInvite(record, invitedBy, options = {}) {
205
+ // The key rides along for private spaces — which is why an invite is a
206
+ // secret, and why it belongs in a URL fragment rather than a path.
207
+ const invite = {
208
+ space: record.space,
209
+ invitedBy,
210
+ ...(record.key ? { key: (await exportKey(record.key)).raw } : {}),
211
+ ...(options.secret ? { invite: base64UrlEncode(options.secret) } : {}),
212
+ ...(options.secret && options.role ? { role: options.role } : {}),
213
+ ...((options.relays ?? record.relays)?.length ? { relays: [...(options.relays ?? record.relays)] } : {}),
214
+ };
215
+ return base64UrlEncode(utf8Encode(JSON.stringify(invite)));
216
+ }
170
217
  /**
171
218
  * Decodes an invite without touching storage.
172
219
  * @param invite The encoded invite string
@@ -1 +1 @@
1
- {"version":3,"file":"space-manager.js","sourceRoot":"","sources":["../../src/space/space-manager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"space-manager.js","sourceRoot":"","sources":["../../src/space/space-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * @module storage/blob/memory
3
+ * A blob store in memory, for tests — and for trying a mirror without a service.
4
+ */
5
+ import type { BlobStore } from '../blob-store.js';
6
+ export declare function createMemoryBlobStore(): BlobStore & {
7
+ readonly size: () => number;
8
+ };
9
+ //# sourceMappingURL=memory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../../src/storage/blob/memory.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAElD,wBAAgB,qBAAqB,IAAI,SAAS,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,MAAM,CAAA;CAAE,CAkBnF"}
@@ -0,0 +1,20 @@
1
+ export function createMemoryBlobStore() {
2
+ const blobs = new Map();
3
+ return Object.freeze({
4
+ async get(key) {
5
+ const found = blobs.get(key);
6
+ return found ? new Uint8Array(found) : null;
7
+ },
8
+ async put(key, bytes) {
9
+ blobs.set(key, new Uint8Array(bytes));
10
+ },
11
+ async delete(key) {
12
+ blobs.delete(key);
13
+ },
14
+ async list(prefix) {
15
+ return [...blobs.keys()].filter((key) => key.startsWith(prefix));
16
+ },
17
+ size: () => [...blobs.values()].reduce((total, bytes) => total + bytes.length, 0),
18
+ });
19
+ }
20
+ //# sourceMappingURL=memory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory.js","sourceRoot":"","sources":["../../../src/storage/blob/memory.ts"],"names":[],"mappings":"AAMA,MAAM,UAAU,qBAAqB;IACnC,MAAM,KAAK,GAAG,IAAI,GAAG,EAAsB,CAAC;IAC5C,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,KAAK,CAAC,GAAG,CAAC,GAAW;YACnB,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAC7B,OAAO,KAAK,CAAC,CAAC,CAAC,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAC9C,CAAC;QACD,KAAK,CAAC,GAAG,CAAC,GAAW,EAAE,KAAiB;YACtC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;QACxC,CAAC;QACD,KAAK,CAAC,MAAM,CAAC,GAAW;YACtB,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACpB,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,MAAc;YACvB,OAAO,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;QACnE,CAAC;QACD,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;KAClF,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,16 @@
1
+ import type { BlobStore } from '../blob-store.js';
2
+ export interface S3Config {
3
+ /** https://<account>.r2.cloudflarestorage.com, https://s3.us-west-004.backblazeb2.com, … */
4
+ readonly endpoint: string;
5
+ readonly bucket: string;
6
+ readonly accessKeyId: string;
7
+ readonly secretAccessKey: string;
8
+ /** R2 ignores it but the signature needs one: `auto` */
9
+ readonly region?: string;
10
+ /** A namespace within the bucket */
11
+ readonly prefix?: string;
12
+ /** For tests */
13
+ readonly fetch?: typeof fetch;
14
+ }
15
+ export declare function createS3BlobStore(config: S3Config): BlobStore;
16
+ //# sourceMappingURL=s3.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"s3.d.ts","sourceRoot":"","sources":["../../../src/storage/blob/s3.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAElD,MAAM,WAAW,QAAQ;IACvB,4FAA4F;IAC5F,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,wDAAwD;IACxD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,oCAAoC;IACpC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB;IAChB,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CAC/B;AAKD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,QAAQ,GAAG,SAAS,CAiE7D"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * @module storage/blob/s3
3
+ * A blob store in any S3-compatible bucket: Cloudflare R2, Backblaze B2,
4
+ * MinIO, Wasabi, AWS itself.
5
+ *
6
+ * Requests are signed with `aws4fetch` rather than the AWS SDK or hand-written
7
+ * SigV4 (see docs/DEPENDENCIES.md): tiny, no dependencies, `fetch` and
8
+ * `crypto.subtle` only, so it runs in browsers, Node and Bun alike.
9
+ */
10
+ import { AwsClient } from 'aws4fetch';
11
+ /** Attempts per request before giving up, on 429 and 5xx */
12
+ const ATTEMPTS = 5;
13
+ export function createS3BlobStore(config) {
14
+ const client = new AwsClient({
15
+ accessKeyId: config.accessKeyId,
16
+ secretAccessKey: config.secretAccessKey,
17
+ service: 's3',
18
+ region: config.region ?? 'auto',
19
+ });
20
+ const call = config.fetch ?? fetch;
21
+ const base = `${config.endpoint.replace(/\/+$/, '')}/${config.bucket}`;
22
+ const prefix = config.prefix ? `${config.prefix.replace(/\/+$/, '')}/` : '';
23
+ const objectUrl = (key) => `${base}/${(prefix + key).split('/').map(encodeURIComponent).join('/')}`;
24
+ /** Signs and sends, backing off on 429 and 5xx, honouring Retry-After */
25
+ async function send(url, init = {}) {
26
+ for (let attempt = 1;; attempt += 1) {
27
+ const signed = await client.sign(url, init);
28
+ const response = await call(signed);
29
+ if (response.status !== 429 && response.status < 500)
30
+ return response;
31
+ if (attempt >= ATTEMPTS)
32
+ return response;
33
+ const after = Number(response.headers.get('retry-after'));
34
+ const wait = Number.isFinite(after) && after > 0 ? after * 1000 : Math.min(200 * 2 ** attempt, 5000) * (0.5 + Math.random() / 2);
35
+ await new Promise((resolve) => setTimeout(resolve, wait));
36
+ }
37
+ }
38
+ const fail = async (what, response) => {
39
+ // The body can name the bucket and key, never a credential; the signed URL is not repeated.
40
+ throw new Error(`S3 ${what} failed: ${response.status} ${(await response.text()).slice(0, 200)}`);
41
+ };
42
+ return Object.freeze({
43
+ async get(key) {
44
+ const response = await send(objectUrl(key));
45
+ if (response.status === 404)
46
+ return null;
47
+ if (!response.ok)
48
+ await fail('get', response);
49
+ return new Uint8Array(await response.arrayBuffer());
50
+ },
51
+ async put(key, bytes) {
52
+ const response = await send(objectUrl(key), { method: 'PUT', body: bytes });
53
+ if (!response.ok)
54
+ await fail('put', response);
55
+ },
56
+ async delete(key) {
57
+ const response = await send(objectUrl(key), { method: 'DELETE' });
58
+ // Already gone is gone.
59
+ if (!response.ok && response.status !== 404)
60
+ await fail('delete', response);
61
+ },
62
+ async list(within) {
63
+ const keys = [];
64
+ let token = null;
65
+ do {
66
+ const query = new URLSearchParams({ 'list-type': '2', prefix: prefix + within });
67
+ if (token)
68
+ query.set('continuation-token', token);
69
+ const response = await send(`${base}?${query}`);
70
+ if (!response.ok)
71
+ await fail('list', response);
72
+ const xml = await response.text();
73
+ for (const match of xml.matchAll(/<Key>([^<]*)<\/Key>/g))
74
+ keys.push(unescapeXml(match[1]).slice(prefix.length));
75
+ token = /<IsTruncated>true<\/IsTruncated>/.test(xml) ? (/<NextContinuationToken>([^<]*)<\/NextContinuationToken>/.exec(xml)?.[1] ?? null) : null;
76
+ if (token)
77
+ token = unescapeXml(token);
78
+ } while (token);
79
+ return keys;
80
+ },
81
+ });
82
+ }
83
+ function unescapeXml(text) {
84
+ return text.replace(/&(lt|gt|quot|apos|amp);/g, (_, name) => ({ lt: '<', gt: '>', quot: '"', apos: "'", amp: '&' })[name]);
85
+ }
86
+ //# sourceMappingURL=s3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"s3.js","sourceRoot":"","sources":["../../../src/storage/blob/s3.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAiBtC,4DAA4D;AAC5D,MAAM,QAAQ,GAAG,CAAC,CAAC;AAEnB,MAAM,UAAU,iBAAiB,CAAC,MAAgB;IAChD,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,eAAe,EAAE,MAAM,CAAC,eAAe;QACvC,OAAO,EAAE,IAAI;QACb,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,MAAM;KAChC,CAAC,CAAC;IACH,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,IAAI,KAAK,CAAC;IACnC,MAAM,IAAI,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;IACvE,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IAC5E,MAAM,SAAS,GAAG,CAAC,GAAW,EAAE,EAAE,CAAC,GAAG,IAAI,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;IAE5G,yEAAyE;IACzE,KAAK,UAAU,IAAI,CAAC,GAAW,EAAE,OAAoB,EAAE;QACrD,KAAK,IAAI,OAAO,GAAG,CAAC,GAAI,OAAO,IAAI,CAAC,EAAE,CAAC;YACrC,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;YAC5C,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC;YACpC,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,IAAI,QAAQ,CAAC,MAAM,GAAG,GAAG;gBAAE,OAAO,QAAQ,CAAC;YACtE,IAAI,OAAO,IAAI,QAAQ;gBAAE,OAAO,QAAQ,CAAC;YACzC,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC;YAC1D,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,IAAI,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;YACjI,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC;IAED,MAAM,IAAI,GAAG,KAAK,EAAE,IAAY,EAAE,QAAkB,EAAE,EAAE;QACtD,4FAA4F;QAC5F,MAAM,IAAI,KAAK,CAAC,MAAM,IAAI,YAAY,QAAQ,CAAC,MAAM,IAAI,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;IACpG,CAAC,CAAC;IAEF,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,KAAK,CAAC,GAAG,CAAC,GAAW;YACnB,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;YAC5C,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG;gBAAE,OAAO,IAAI,CAAC;YACzC,IAAI,CAAC,QAAQ,CAAC,EAAE;gBAAE,MAAM,IAAI,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;YAC9C,OAAO,IAAI,UAAU,CAAC,MAAM,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC;QACtD,CAAC;QAED,KAAK,CAAC,GAAG,CAAC,GAAW,EAAE,KAAiB;YACtC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,KAAiB,EAAE,CAAC,CAAC;YACxF,IAAI,CAAC,QAAQ,CAAC,EAAE;gBAAE,MAAM,IAAI,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;QAChD,CAAC;QAED,KAAK,CAAC,MAAM,CAAC,GAAW;YACtB,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;YAClE,wBAAwB;YACxB,IAAI,CAAC,QAAQ,CAAC,EAAE,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG;gBAAE,MAAM,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAC9E,CAAC;QAED,KAAK,CAAC,IAAI,CAAC,MAAc;YACvB,MAAM,IAAI,GAAa,EAAE,CAAC;YAC1B,IAAI,KAAK,GAAkB,IAAI,CAAC;YAChC,GAAG,CAAC;gBACF,MAAM,KAAK,GAAG,IAAI,eAAe,CAAC,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;gBACjF,IAAI,KAAK;oBAAE,KAAK,CAAC,GAAG,CAAC,oBAAoB,EAAE,KAAK,CAAC,CAAC;gBAClD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,GAAG,IAAI,IAAI,KAAK,EAAE,CAAC,CAAC;gBAChD,IAAI,CAAC,QAAQ,CAAC,EAAE;oBAAE,MAAM,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;gBAC/C,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;gBAClC,KAAK,MAAM,KAAK,IAAI,GAAG,CAAC,QAAQ,CAAC,sBAAsB,CAAC;oBAAE,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;gBACjH,KAAK,GAAG,kCAAkC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,yDAAyD,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;gBACjJ,IAAI,KAAK;oBAAE,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;YACxC,CAAC,QAAQ,KAAK,EAAE;YAChB,OAAO,IAAI,CAAC;QACd,CAAC;KACF,CAAC,CAAC;AACL,CAAC;AAED,SAAS,WAAW,CAAC,IAAY;IAC/B,OAAO,IAAI,CAAC,OAAO,CAAC,0BAA0B,EAAE,CAAC,CAAC,EAAE,IAAY,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,IAAI,CAAE,CAAC,CAAC;AACtI,CAAC"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @module blob-store
3
+ * A dumb file store. Anything that can keep bytes by name can be one: S3, R2,
4
+ * Backblaze, a Dropbox or OneDrive app folder, a Drive folder, a directory.
5
+ *
6
+ * Deliberately narrower than `StorageAdapter`. Assume it is slow, eventually
7
+ * consistent and without atomic operations — the mirror above
8
+ * (`storage/mirror.ts`) is what turns one into a place a space can live.
9
+ */
10
+ export interface BlobStore {
11
+ get(key: string): Promise<Uint8Array | null>;
12
+ put(key: string, bytes: Uint8Array): Promise<void>;
13
+ delete(key: string): Promise<void>;
14
+ /** Every key under `prefix`, in no particular order */
15
+ list(prefix: string): Promise<string[]>;
16
+ /**
17
+ * Keys that appeared or went away under `prefix` since `cursor`, where the
18
+ * service can say so cheaply. Without it the mirror lists.
19
+ */
20
+ changes?(prefix: string, cursor: string | null): Promise<{
21
+ added: string[];
22
+ removed: string[];
23
+ cursor: string;
24
+ }>;
25
+ }
26
+ //# sourceMappingURL=blob-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blob-store.d.ts","sourceRoot":"","sources":["../../src/storage/blob-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,MAAM,WAAW,SAAS;IACxB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;IAC7C,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnD,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,uDAAuD;IACvD,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACxC;;;OAGG;IACH,OAAO,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,EAAE,CAAC;QAAC,OAAO,EAAE,MAAM,EAAE,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAClH"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=blob-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blob-store.js","sourceRoot":"","sources":["../../src/storage/blob-store.ts"],"names":[],"mappings":""}
@@ -10,9 +10,9 @@
10
10
  * the space record go in sealed under a key derived from the account seed, so
11
11
  * they are readable only once the folder has actually been unlocked.
12
12
  *
13
- * Scoped deliberately narrowly. Expressions and MST nodes pass straight through:
14
- * their bodies are already encrypted where it matters, they are content
15
- * addressed, and sealing them would cost the property that makes a folder worth
13
+ * Scoped deliberately narrowly. Expressions and their index entries pass
14
+ * straight through: bodies are already encrypted where it matters, files are
15
+ * content addressed, and sealing them would cost the property that makes a folder worth
16
16
  * having — that you can open it and see what is in it. What stays legible is
17
17
  * each record's author, timestamp and collection, plus anything in a space its
18
18
  * owner made public.
@@ -10,9 +10,9 @@
10
10
  * the space record go in sealed under a key derived from the account seed, so
11
11
  * they are readable only once the folder has actually been unlocked.
12
12
  *
13
- * Scoped deliberately narrowly. Expressions and MST nodes pass straight through:
14
- * their bodies are already encrypted where it matters, they are content
15
- * addressed, and sealing them would cost the property that makes a folder worth
13
+ * Scoped deliberately narrowly. Expressions and their index entries pass
14
+ * straight through: bodies are already encrypted where it matters, files are
15
+ * content addressed, and sealing them would cost the property that makes a folder worth
16
16
  * having — that you can open it and see what is in it. What stays legible is
17
17
  * each record's author, timestamp and collection, plus anything in a space its
18
18
  * owner made public.
@@ -17,16 +17,16 @@
17
17
  * accounts.json who has an account here
18
18
  * accounts/<id>/account.json that account's keys, locked
19
19
  * accounts/<id>/stores/<name>/
20
- * kv/<key> MST nodes, the root pointer, space records
20
+ * kv/<key> which version is current, what sync compares, space records
21
21
  * expressions/<cid>.json
22
22
  * ```
23
23
  *
24
- * **Expressions are the truth; the MST is an index over them.** That inversion
25
- * is what lets two origins share one folder with no locking. Every expression
26
- * file is immutable and named by its own content hash, so concurrent writers can
27
- * only ever add files that agree — the one genuinely mutable thing, the MST root
28
- * pointer, is derived state that either side can rebuild. {@link reconcileFolder}
29
- * is what rebuilds it.
24
+ * **Expressions are the truth; the entries are an index over them.** That
25
+ * inversion is what lets two origins share one folder with no locking. Every
26
+ * expression file is immutable and named by its own content hash, so
27
+ * concurrent writers can only ever add files that agree — the one genuinely
28
+ * mutable thing, which version is current, is derived state that either side
29
+ * can put right. {@link reconcileFolder} is what puts it right.
30
30
  */
31
31
  import type { StorageAdapter } from '../types.js';
32
32
  export interface WritableFileLike {
@@ -71,7 +71,7 @@ export interface FolderAdapter extends StorageAdapter {
71
71
  * local tree.
72
72
  */
73
73
  reload(): Promise<FolderReload>;
74
- /** Every expression id currently on disk, whatever the MST believes */
74
+ /** Every expression id currently on disk, whatever the entries believe */
75
75
  listExpressionIds(): Promise<ReadonlyArray<string>>;
76
76
  }
77
77
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"folder-adapter.d.ts","sourceRoot":"","sources":["../../src/storage/folder-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAuB,MAAM,aAAa,CAAC;AAUvE,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,IAAI,OAAO,CAAC;QAAE,WAAW,IAAI,OAAO,CAAC,WAAW,CAAC,CAAA;KAAE,CAAC,CAAC;IAC5D,cAAc,IAAI,OAAO,CAAC,gBAAgB,CAAC,CAAC;CAC7C;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IACrF,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAC/F,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5E,IAAI,IAAI,qBAAqB,CAAC,MAAM,CAAC,CAAC;CACvC;AAED,+CAA+C;AAC/C,MAAM,WAAW,YAAY;IAC3B,kFAAkF;IAClF,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACtC,0CAA0C;IAC1C,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;CACzC;AAED,MAAM,WAAW,aAAc,SAAQ,cAAc;IACnD,2DAA2D;IAC3D,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B;;;;;;;OAOG;IACH,MAAM,IAAI,OAAO,CAAC,YAAY,CAAC,CAAC;IAChC,uEAAuE;IACvE,iBAAiB,IAAI,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC;CACrD;AAgED;;;;;GAKG;AACH,wBAAsB,cAAc,CAAC,GAAG,EAAE,mBAAmB,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CASvG;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CAAC,GAAG,EAAE,mBAAmB,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAK9G;AAeD;;;;;;;;;;;;GAYG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,mBAAmB,EACzB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,aAAa,CAAC,CAuJxB"}
1
+ {"version":3,"file":"folder-adapter.d.ts","sourceRoot":"","sources":["../../src/storage/folder-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAuB,MAAM,aAAa,CAAC;AAUvE,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,IAAI,OAAO,CAAC;QAAE,WAAW,IAAI,OAAO,CAAC,WAAW,CAAC,CAAA;KAAE,CAAC,CAAC;IAC5D,cAAc,IAAI,OAAO,CAAC,gBAAgB,CAAC,CAAC;CAC7C;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IACrF,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAC/F,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5E,IAAI,IAAI,qBAAqB,CAAC,MAAM,CAAC,CAAC;CACvC;AAED,+CAA+C;AAC/C,MAAM,WAAW,YAAY;IAC3B,kFAAkF;IAClF,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACtC,0CAA0C;IAC1C,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;CACzC;AAED,MAAM,WAAW,aAAc,SAAQ,cAAc;IACnD,2DAA2D;IAC3D,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B;;;;;;;OAOG;IACH,MAAM,IAAI,OAAO,CAAC,YAAY,CAAC,CAAC;IAChC,0EAA0E;IAC1E,iBAAiB,IAAI,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC;CACrD;AAgED;;;;;GAKG;AACH,wBAAsB,cAAc,CAAC,GAAG,EAAE,mBAAmB,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CASvG;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CAAC,GAAG,EAAE,mBAAmB,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAK9G;AAeD;;;;;;;;;;;;GAYG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,mBAAmB,EACzB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,aAAa,CAAC,CAuJxB"}
@@ -17,16 +17,16 @@
17
17
  * accounts.json who has an account here
18
18
  * accounts/<id>/account.json that account's keys, locked
19
19
  * accounts/<id>/stores/<name>/
20
- * kv/<key> MST nodes, the root pointer, space records
20
+ * kv/<key> which version is current, what sync compares, space records
21
21
  * expressions/<cid>.json
22
22
  * ```
23
23
  *
24
- * **Expressions are the truth; the MST is an index over them.** That inversion
25
- * is what lets two origins share one folder with no locking. Every expression
26
- * file is immutable and named by its own content hash, so concurrent writers can
27
- * only ever add files that agree — the one genuinely mutable thing, the MST root
28
- * pointer, is derived state that either side can rebuild. {@link reconcileFolder}
29
- * is what rebuilds it.
24
+ * **Expressions are the truth; the entries are an index over them.** That
25
+ * inversion is what lets two origins share one folder with no locking. Every
26
+ * expression file is immutable and named by its own content hash, so
27
+ * concurrent writers can only ever add files that agree — the one genuinely
28
+ * mutable thing, which version is current, is derived state that either side
29
+ * can put right. {@link reconcileFolder} is what puts it right.
30
30
  */
31
31
  import { utf8Encode, utf8Decode } from '../utils/encoding.js';
32
32
  const EXPRESSION_SUFFIX = '.json';
@@ -5,13 +5,14 @@
5
5
  * Two origins — or two devices behind Dropbox, iCloud or Syncthing — can write
6
6
  * into one folder at the same time. Almost nothing there can actually conflict:
7
7
  * expression files are named by their own content hash, so two writers either
8
- * produce different files or produce byte-identical ones. The single mutable
9
- * thing is the MST root pointer, and a lost write to it costs nothing, because
10
- * the tree is derived state.
8
+ * produce different files or produce byte-identical ones. The entries saying
9
+ * which version is current can be written by both, and one write can be lost;
10
+ * that costs nothing, because they are derived from the files.
11
11
  *
12
12
  * So the rule is: **the set of expression files wins.** Reconciling means
13
- * rebuilding the tree until it agrees with the directory — adding what turned up
14
- * and dropping what went away. That is the whole concurrency story.
13
+ * placing every file that turned up — which also puts right a current-version
14
+ * entry the other writer overwrote — and dropping entries whose file went
15
+ * away. That is the whole concurrency story.
15
16
  */
16
17
  import type { StorageProvider } from './storage-provider.js';
17
18
  import type { FolderAdapter } from './folder-adapter.js';
@@ -23,25 +24,22 @@ export interface FolderReconciliation {
23
24
  /** Expression files that are gone */
24
25
  readonly removed: ReadonlyArray<string>;
25
26
  /**
26
- * Tree entries that had to be fixed to match the directory.
27
- *
28
- * Usually empty, and that is the expected case rather than a lucky one: both
29
- * origins read and write the same root pointer, so the tree one of them built
30
- * is normally already right for the other. This fills in when a pointer write
31
- * was lost — two writers racing, or a folder that came back from Dropbox with
32
- * files the pointer never saw.
27
+ * Versions placed or unplaced to match the directory: files another writer
28
+ * added (placed again, which corrects a current entry a race left wrong),
29
+ * files that came back from Dropbox with no entries, and entries whose file
30
+ * is gone.
33
31
  */
34
32
  readonly repaired: ReadonlyArray<string>;
35
33
  /** Whether anything moved at all — worth a re-render when true */
36
34
  readonly changed: boolean;
37
35
  }
38
36
  /**
39
- * Re-reads the folder and brings the Merkle tree back in line with it.
37
+ * Re-reads the folder and brings the entries back in line with it.
40
38
  *
41
39
  * Safe to call as often as you like: with nothing new on disk it is two
42
40
  * directory listings and no writes.
43
41
  *
44
- * @param storage The provider whose tree should be brought up to date
42
+ * @param storage The provider whose entries should be brought up to date
45
43
  * @param adapter The folder adapter underneath it
46
44
  * @param accept Whether a version found on disk may be placed. Anyone who can
47
45
  * write the folder can drop a file in it — another site given the folder, a
@@ -1 +1 @@
1
- {"version":3,"file":"folder-reconcile.d.ts","sourceRoot":"","sources":["../../src/storage/folder-reconcile.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,wCAAwC;AACxC,MAAM,WAAW,oBAAoB;IACnC,mFAAmF;IACnF,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACtC,qCAAqC;IACrC,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACxC;;;;;;;;OAQG;IACH,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACzC,kEAAkE;IAClE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,aAAa,EACtB,MAAM,GAAE,CAAC,UAAU,EAAE,UAAU,KAAK,OAAO,CAAC,OAAO,CAAoB,GACtE,OAAO,CAAC,oBAAoB,CAAC,CAoC/B"}
1
+ {"version":3,"file":"folder-reconcile.d.ts","sourceRoot":"","sources":["../../src/storage/folder-reconcile.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,wCAAwC;AACxC,MAAM,WAAW,oBAAoB;IACnC,mFAAmF;IACnF,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACtC,qCAAqC;IACrC,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACxC;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACzC,kEAAkE;IAClE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,aAAa,EACtB,MAAM,GAAE,CAAC,UAAU,EAAE,UAAU,KAAK,OAAO,CAAC,OAAO,CAAoB,GACtE,OAAO,CAAC,oBAAoB,CAAC,CAwC/B"}