@hashtree/core 0.1.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 (138) hide show
  1. package/LICENSE +21 -0
  2. package/dist/bep52.d.ts +179 -0
  3. package/dist/bep52.d.ts.map +1 -0
  4. package/dist/bep52.js +384 -0
  5. package/dist/bep52.js.map +1 -0
  6. package/dist/builder.d.ts +137 -0
  7. package/dist/builder.d.ts.map +1 -0
  8. package/dist/builder.js +281 -0
  9. package/dist/builder.js.map +1 -0
  10. package/dist/codec.d.ts +37 -0
  11. package/dist/codec.d.ts.map +1 -0
  12. package/dist/codec.js +109 -0
  13. package/dist/codec.js.map +1 -0
  14. package/dist/crypto.d.ts +92 -0
  15. package/dist/crypto.d.ts.map +1 -0
  16. package/dist/crypto.js +212 -0
  17. package/dist/crypto.js.map +1 -0
  18. package/dist/encrypted.d.ts +114 -0
  19. package/dist/encrypted.d.ts.map +1 -0
  20. package/dist/encrypted.js +446 -0
  21. package/dist/encrypted.js.map +1 -0
  22. package/dist/hash.d.ts +14 -0
  23. package/dist/hash.d.ts.map +1 -0
  24. package/dist/hash.js +27 -0
  25. package/dist/hash.js.map +1 -0
  26. package/dist/hashtree.d.ts +237 -0
  27. package/dist/hashtree.d.ts.map +1 -0
  28. package/dist/hashtree.js +557 -0
  29. package/dist/hashtree.js.map +1 -0
  30. package/dist/index.d.ts +27 -0
  31. package/dist/index.d.ts.map +1 -0
  32. package/dist/index.js +44 -0
  33. package/dist/index.js.map +1 -0
  34. package/dist/nhash.d.ts +94 -0
  35. package/dist/nhash.d.ts.map +1 -0
  36. package/dist/nhash.js +293 -0
  37. package/dist/nhash.js.map +1 -0
  38. package/dist/resolver/index.d.ts +5 -0
  39. package/dist/resolver/index.d.ts.map +1 -0
  40. package/dist/resolver/index.js +5 -0
  41. package/dist/resolver/index.js.map +1 -0
  42. package/dist/resolver/nostr.d.ts +82 -0
  43. package/dist/resolver/nostr.d.ts.map +1 -0
  44. package/dist/resolver/nostr.js +868 -0
  45. package/dist/resolver/nostr.js.map +1 -0
  46. package/dist/store/blossom.d.ts +100 -0
  47. package/dist/store/blossom.d.ts.map +1 -0
  48. package/dist/store/blossom.js +355 -0
  49. package/dist/store/blossom.js.map +1 -0
  50. package/dist/store/dexie.d.ts +44 -0
  51. package/dist/store/dexie.d.ts.map +1 -0
  52. package/dist/store/dexie.js +196 -0
  53. package/dist/store/dexie.js.map +1 -0
  54. package/dist/store/fallback.d.ts +40 -0
  55. package/dist/store/fallback.d.ts.map +1 -0
  56. package/dist/store/fallback.js +71 -0
  57. package/dist/store/fallback.js.map +1 -0
  58. package/dist/store/index.d.ts +6 -0
  59. package/dist/store/index.d.ts.map +1 -0
  60. package/dist/store/index.js +6 -0
  61. package/dist/store/index.js.map +1 -0
  62. package/dist/store/memory.d.ts +29 -0
  63. package/dist/store/memory.d.ts.map +1 -0
  64. package/dist/store/memory.js +66 -0
  65. package/dist/store/memory.js.map +1 -0
  66. package/dist/store/opfs.d.ts +56 -0
  67. package/dist/store/opfs.d.ts.map +1 -0
  68. package/dist/store/opfs.js +200 -0
  69. package/dist/store/opfs.js.map +1 -0
  70. package/dist/streaming.d.ts +74 -0
  71. package/dist/streaming.d.ts.map +1 -0
  72. package/dist/streaming.js +199 -0
  73. package/dist/streaming.js.map +1 -0
  74. package/dist/tree/create.d.ts +35 -0
  75. package/dist/tree/create.d.ts.map +1 -0
  76. package/dist/tree/create.js +90 -0
  77. package/dist/tree/create.js.map +1 -0
  78. package/dist/tree/edit.d.ts +28 -0
  79. package/dist/tree/edit.d.ts.map +1 -0
  80. package/dist/tree/edit.js +115 -0
  81. package/dist/tree/edit.js.map +1 -0
  82. package/dist/tree/editEncrypted.d.ts +46 -0
  83. package/dist/tree/editEncrypted.d.ts.map +1 -0
  84. package/dist/tree/editEncrypted.js +225 -0
  85. package/dist/tree/editEncrypted.js.map +1 -0
  86. package/dist/tree/index.d.ts +7 -0
  87. package/dist/tree/index.d.ts.map +1 -0
  88. package/dist/tree/index.js +7 -0
  89. package/dist/tree/index.js.map +1 -0
  90. package/dist/tree/read.d.ts +75 -0
  91. package/dist/tree/read.d.ts.map +1 -0
  92. package/dist/tree/read.js +389 -0
  93. package/dist/tree/read.js.map +1 -0
  94. package/dist/tree/writeAt.d.ts +44 -0
  95. package/dist/tree/writeAt.d.ts.map +1 -0
  96. package/dist/tree/writeAt.js +282 -0
  97. package/dist/tree/writeAt.js.map +1 -0
  98. package/dist/types.d.ts +274 -0
  99. package/dist/types.d.ts.map +1 -0
  100. package/dist/types.js +47 -0
  101. package/dist/types.js.map +1 -0
  102. package/dist/verify.d.ts +12 -0
  103. package/dist/verify.d.ts.map +1 -0
  104. package/dist/verify.js +32 -0
  105. package/dist/verify.js.map +1 -0
  106. package/dist/visibility.d.ts +50 -0
  107. package/dist/visibility.d.ts.map +1 -0
  108. package/dist/visibility.js +111 -0
  109. package/dist/visibility.js.map +1 -0
  110. package/dist/webrtc/index.d.ts +4 -0
  111. package/dist/webrtc/index.d.ts.map +1 -0
  112. package/dist/webrtc/index.js +4 -0
  113. package/dist/webrtc/index.js.map +1 -0
  114. package/dist/webrtc/lruCache.d.ts +20 -0
  115. package/dist/webrtc/lruCache.d.ts.map +1 -0
  116. package/dist/webrtc/lruCache.js +59 -0
  117. package/dist/webrtc/lruCache.js.map +1 -0
  118. package/dist/webrtc/peer.d.ts +122 -0
  119. package/dist/webrtc/peer.d.ts.map +1 -0
  120. package/dist/webrtc/peer.js +583 -0
  121. package/dist/webrtc/peer.js.map +1 -0
  122. package/dist/webrtc/protocol.d.ts +76 -0
  123. package/dist/webrtc/protocol.d.ts.map +1 -0
  124. package/dist/webrtc/protocol.js +167 -0
  125. package/dist/webrtc/protocol.js.map +1 -0
  126. package/dist/webrtc/store.d.ts +190 -0
  127. package/dist/webrtc/store.d.ts.map +1 -0
  128. package/dist/webrtc/store.js +1043 -0
  129. package/dist/webrtc/store.js.map +1 -0
  130. package/dist/webrtc/types.d.ts +196 -0
  131. package/dist/webrtc/types.d.ts.map +1 -0
  132. package/dist/webrtc/types.js +46 -0
  133. package/dist/webrtc/types.js.map +1 -0
  134. package/dist/worker/protocol.d.ts +493 -0
  135. package/dist/worker/protocol.d.ts.map +1 -0
  136. package/dist/worker/protocol.js +15 -0
  137. package/dist/worker/protocol.js.map +1 -0
  138. package/package.json +59 -0
@@ -0,0 +1,282 @@
1
+ /**
2
+ * writeAt - Efficiently patch bytes at a specific offset without rewriting entire file
3
+ *
4
+ * Only affected chunks and their parent nodes are rewritten.
5
+ * For a large file with a small patch, this is much more efficient than putFile.
6
+ */
7
+ import { LinkType, toHex } from '../types.js';
8
+ import { sha256 } from '../hash.js';
9
+ import { encodeAndHash, decodeTreeNode, tryDecodeTreeNode } from '../codec.js';
10
+ import { encryptChk, decryptChk } from '../crypto.js';
11
+ /**
12
+ * Write data at a specific offset in an unencrypted file
13
+ *
14
+ * @param config - Tree configuration
15
+ * @param rootHash - Current root hash of the file
16
+ * @param offset - Byte offset to write at
17
+ * @param data - Data to write
18
+ * @returns New root hash
19
+ */
20
+ export async function writeAt(config, rootHash, offset, data) {
21
+ const { store } = config;
22
+ // Get root data
23
+ const rootData = await store.get(rootHash);
24
+ if (!rootData) {
25
+ throw new Error(`Root not found: ${toHex(rootHash)}`);
26
+ }
27
+ // Check if it's a tree node or single blob
28
+ const node = tryDecodeTreeNode(rootData);
29
+ if (!node) {
30
+ // Single blob - modify in place
31
+ if (offset + data.length > rootData.length) {
32
+ throw new Error(`Write extends beyond file: offset=${offset}, data=${data.length}, file=${rootData.length}`);
33
+ }
34
+ const newData = new Uint8Array(rootData);
35
+ newData.set(data, offset);
36
+ const newHash = await sha256(newData);
37
+ await store.put(newHash, newData);
38
+ return { hash: newHash, size: newData.length };
39
+ }
40
+ // Multi-chunk file - find and modify affected chunks
41
+ const totalSize = node.links.reduce((sum, l) => sum + l.size, 0);
42
+ if (offset + data.length > totalSize) {
43
+ throw new Error(`Write extends beyond file: offset=${offset}, data=${data.length}, file=${totalSize}`);
44
+ }
45
+ const newLinks = await writeAtInNode(config, node, offset, data);
46
+ // Rebuild tree with new links
47
+ const newRootHash = await buildTreeFromLinks(config, newLinks, totalSize);
48
+ return { hash: newRootHash, size: totalSize };
49
+ }
50
+ /**
51
+ * Write data at a specific offset in an encrypted file
52
+ *
53
+ * @param config - Tree configuration
54
+ * @param rootHash - Current root hash of the encrypted file
55
+ * @param rootKey - Current encryption key for the root
56
+ * @param offset - Byte offset to write at
57
+ * @param data - Data to write (plaintext)
58
+ * @returns New root hash and key
59
+ */
60
+ export async function writeAtEncrypted(config, rootHash, rootKey, offset, data) {
61
+ const { store } = config;
62
+ // Get and decrypt root
63
+ const encryptedRoot = await store.get(rootHash);
64
+ if (!encryptedRoot) {
65
+ throw new Error(`Root not found: ${toHex(rootHash)}`);
66
+ }
67
+ const decryptedRoot = await decryptChk(encryptedRoot, rootKey);
68
+ // Check if it's a tree node or single blob
69
+ const node = tryDecodeTreeNode(decryptedRoot);
70
+ if (!node) {
71
+ // Single blob - modify in place
72
+ if (offset + data.length > decryptedRoot.length) {
73
+ throw new Error(`Write extends beyond file: offset=${offset}, data=${data.length}, file=${decryptedRoot.length}`);
74
+ }
75
+ const newData = new Uint8Array(decryptedRoot);
76
+ newData.set(data, offset);
77
+ // Re-encrypt with CHK
78
+ const { ciphertext, key } = await encryptChk(newData);
79
+ const newHash = await sha256(ciphertext);
80
+ await store.put(newHash, ciphertext);
81
+ return { hash: newHash, size: newData.length, key };
82
+ }
83
+ // Multi-chunk file - find and modify affected chunks
84
+ const totalSize = node.links.reduce((sum, l) => sum + l.size, 0);
85
+ if (offset + data.length > totalSize) {
86
+ throw new Error(`Write extends beyond file: offset=${offset}, data=${data.length}, file=${totalSize}`);
87
+ }
88
+ const newLinks = await writeAtInNodeEncrypted(config, node, offset, data);
89
+ // Rebuild encrypted tree with new links
90
+ const { hash: newRootHash, key: newRootKey } = await buildEncryptedTreeFromLinks(config, newLinks, totalSize);
91
+ return { hash: newRootHash, size: totalSize, key: newRootKey };
92
+ }
93
+ /**
94
+ * Recursively modify chunks in a tree node (unencrypted)
95
+ */
96
+ async function writeAtInNode(config, node, offset, data) {
97
+ const { store } = config;
98
+ const newLinks = [];
99
+ let position = 0;
100
+ for (const link of node.links) {
101
+ const linkStart = position;
102
+ const linkEnd = position + link.size;
103
+ position = linkEnd;
104
+ // Check if this chunk overlaps with the write range
105
+ const writeStart = offset;
106
+ const writeEnd = offset + data.length;
107
+ if (linkEnd <= writeStart || linkStart >= writeEnd) {
108
+ // No overlap - keep original link
109
+ newLinks.push(link);
110
+ continue;
111
+ }
112
+ // This chunk needs modification
113
+ const chunkData = await store.get(link.hash);
114
+ if (!chunkData) {
115
+ throw new Error(`Missing chunk: ${toHex(link.hash)}`);
116
+ }
117
+ if (link.type !== LinkType.Blob) {
118
+ // Intermediate node - recurse
119
+ const childNode = decodeTreeNode(chunkData);
120
+ const childOffset = Math.max(0, offset - linkStart);
121
+ const childData = data.slice(Math.max(0, linkStart - offset), Math.min(data.length, linkEnd - offset));
122
+ const newChildLinks = await writeAtInNode(config, childNode, childOffset, childData);
123
+ // Build new intermediate node
124
+ const newChildNode = {
125
+ type: LinkType.File,
126
+ links: newChildLinks,
127
+ };
128
+ const { data: encodedNode, hash: newChildHash } = await encodeAndHash(newChildNode);
129
+ await store.put(newChildHash, encodedNode);
130
+ newLinks.push({
131
+ hash: newChildHash,
132
+ size: link.size,
133
+ type: LinkType.File,
134
+ });
135
+ }
136
+ else {
137
+ // Leaf blob - modify bytes
138
+ const newChunkData = new Uint8Array(chunkData);
139
+ // Calculate which bytes to modify in this chunk
140
+ const chunkWriteStart = Math.max(0, writeStart - linkStart);
141
+ const chunkWriteEnd = Math.min(chunkData.length, writeEnd - linkStart);
142
+ const dataReadStart = Math.max(0, linkStart - writeStart);
143
+ const dataReadEnd = dataReadStart + (chunkWriteEnd - chunkWriteStart);
144
+ newChunkData.set(data.slice(dataReadStart, dataReadEnd), chunkWriteStart);
145
+ const newHash = await sha256(newChunkData);
146
+ await store.put(newHash, newChunkData);
147
+ newLinks.push({
148
+ hash: newHash,
149
+ size: newChunkData.length,
150
+ type: LinkType.Blob,
151
+ });
152
+ }
153
+ }
154
+ return newLinks;
155
+ }
156
+ /**
157
+ * Recursively modify chunks in an encrypted tree node
158
+ *
159
+ * NOTE: For encrypted files, link.size stores CIPHERTEXT size (includes AES-GCM tag),
160
+ * but offset/data are in PLAINTEXT terms. We need to decrypt each chunk to get
161
+ * the actual plaintext size for offset calculations.
162
+ */
163
+ async function writeAtInNodeEncrypted(config, node, offset, data) {
164
+ const { store } = config;
165
+ const newLinks = [];
166
+ // First pass: collect plaintext sizes by decrypting headers or using heuristics
167
+ // AES-GCM adds 16 bytes tag, so plaintext size = ciphertext size - 16
168
+ const AES_GCM_TAG_SIZE = 16;
169
+ let position = 0; // Track plaintext position
170
+ for (const link of node.links) {
171
+ // For blobs, plaintext size = ciphertext size - tag
172
+ // For intermediate nodes, the size stored is the sum of child plaintext sizes
173
+ const plaintextSize = link.type === LinkType.Blob
174
+ ? link.size - AES_GCM_TAG_SIZE
175
+ : link.size; // Intermediate nodes store total plaintext size of subtree
176
+ const linkStart = position;
177
+ const linkEnd = position + plaintextSize;
178
+ position = linkEnd;
179
+ // Check if this chunk overlaps with the write range
180
+ const writeStart = offset;
181
+ const writeEnd = offset + data.length;
182
+ if (linkEnd <= writeStart || linkStart >= writeEnd) {
183
+ // No overlap - keep original link
184
+ newLinks.push(link);
185
+ continue;
186
+ }
187
+ // This chunk needs modification
188
+ if (!link.key) {
189
+ throw new Error(`Missing decryption key for chunk: ${toHex(link.hash)}`);
190
+ }
191
+ const encryptedChunk = await store.get(link.hash);
192
+ if (!encryptedChunk) {
193
+ throw new Error(`Missing chunk: ${toHex(link.hash)}`);
194
+ }
195
+ const decryptedChunk = await decryptChk(encryptedChunk, link.key);
196
+ if (link.type !== LinkType.Blob) {
197
+ // Intermediate node - recurse
198
+ const childNode = decodeTreeNode(decryptedChunk);
199
+ const childOffset = Math.max(0, offset - linkStart);
200
+ const childData = data.slice(Math.max(0, linkStart - offset), Math.min(data.length, linkEnd - offset));
201
+ const newChildLinks = await writeAtInNodeEncrypted(config, childNode, childOffset, childData);
202
+ // Build new encrypted intermediate node
203
+ const newChildNode = {
204
+ type: LinkType.File,
205
+ links: newChildLinks,
206
+ };
207
+ const { data: encodedNode } = await encodeAndHash(newChildNode);
208
+ const { ciphertext, key } = await encryptChk(encodedNode);
209
+ const newChildHash = await sha256(ciphertext);
210
+ await store.put(newChildHash, ciphertext);
211
+ // Recalculate total plaintext size from new links
212
+ const newPlaintextSize = newChildLinks.reduce((sum, l) => {
213
+ return sum + (l.type === LinkType.Blob ? l.size - AES_GCM_TAG_SIZE : l.size);
214
+ }, 0);
215
+ newLinks.push({
216
+ hash: newChildHash,
217
+ size: newPlaintextSize, // Store plaintext size for intermediate nodes
218
+ key,
219
+ type: LinkType.File,
220
+ });
221
+ }
222
+ else {
223
+ // Leaf blob - modify bytes
224
+ const newChunkData = new Uint8Array(decryptedChunk);
225
+ // Calculate which bytes to modify in this chunk
226
+ const chunkWriteStart = Math.max(0, writeStart - linkStart);
227
+ const chunkWriteEnd = Math.min(decryptedChunk.length, writeEnd - linkStart);
228
+ const dataReadStart = Math.max(0, linkStart - writeStart);
229
+ const dataReadEnd = dataReadStart + (chunkWriteEnd - chunkWriteStart);
230
+ newChunkData.set(data.slice(dataReadStart, dataReadEnd), chunkWriteStart);
231
+ // Re-encrypt with CHK
232
+ const { ciphertext, key } = await encryptChk(newChunkData);
233
+ const newHash = await sha256(ciphertext);
234
+ await store.put(newHash, ciphertext);
235
+ newLinks.push({
236
+ hash: newHash,
237
+ size: ciphertext.length, // Store ciphertext size for blobs
238
+ key,
239
+ type: LinkType.Blob,
240
+ });
241
+ }
242
+ }
243
+ return newLinks;
244
+ }
245
+ /**
246
+ * Build tree from links (unencrypted)
247
+ */
248
+ async function buildTreeFromLinks(config, links, totalSize) {
249
+ const { store } = config;
250
+ if (links.length === 1 && links[0].size === totalSize) {
251
+ return links[0].hash;
252
+ }
253
+ // Create single flat node with all links
254
+ const node = {
255
+ type: LinkType.File,
256
+ links,
257
+ };
258
+ const { data, hash } = await encodeAndHash(node);
259
+ await store.put(hash, data);
260
+ return hash;
261
+ }
262
+ /**
263
+ * Build encrypted tree from links
264
+ */
265
+ async function buildEncryptedTreeFromLinks(config, links, totalSize) {
266
+ const { store } = config;
267
+ // Single link with key - return directly
268
+ if (links.length === 1 && links[0].key && links[0].size === totalSize) {
269
+ return { hash: links[0].hash, key: links[0].key };
270
+ }
271
+ // Create single flat node with all links
272
+ const node = {
273
+ type: LinkType.File,
274
+ links,
275
+ };
276
+ const { data } = await encodeAndHash(node);
277
+ const { ciphertext, key } = await encryptChk(data);
278
+ const hash = await sha256(ciphertext);
279
+ await store.put(hash, ciphertext);
280
+ return { hash, key };
281
+ }
282
+ //# sourceMappingURL=writeAt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"writeAt.js","sourceRoot":"","sources":["../../src/tree/writeAt.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAA+B,QAAQ,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAC3E,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAC/E,OAAO,EAAE,UAAU,EAAE,UAAU,EAAsB,MAAM,cAAc,CAAC;AAmB1E;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,MAAqB,EACrB,QAAc,EACd,MAAc,EACd,IAAgB;IAEhB,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC;IAEzB,gBAAgB;IAChB,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC3C,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,mBAAmB,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IACxD,CAAC;IAED,2CAA2C;IAC3C,MAAM,IAAI,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IACzC,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,gCAAgC;QAChC,IAAI,MAAM,GAAG,IAAI,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC;YAC3C,MAAM,IAAI,KAAK,CAAC,qCAAqC,MAAM,UAAU,IAAI,CAAC,MAAM,UAAU,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;QAC/G,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,UAAU,CAAC,QAAQ,CAAC,CAAC;QACzC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAE1B,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,CAAC;QACtC,MAAM,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAElC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;IACjD,CAAC;IAED,qDAAqD;IACrD,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAEjE,IAAI,MAAM,GAAG,IAAI,CAAC,MAAM,GAAG,SAAS,EAAE,CAAC;QACrC,MAAM,IAAI,KAAK,CAAC,qCAAqC,MAAM,UAAU,IAAI,CAAC,MAAM,UAAU,SAAS,EAAE,CAAC,CAAC;IACzG,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;IAEjE,8BAA8B;IAC9B,MAAM,WAAW,GAAG,MAAM,kBAAkB,CAAC,MAAM,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;IAE1E,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;AAChD,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,MAAqB,EACrB,QAAc,EACd,OAAsB,EACtB,MAAc,EACd,IAAgB;IAEhB,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC;IAEzB,uBAAuB;IACvB,MAAM,aAAa,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAChD,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CAAC,mBAAmB,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IACxD,CAAC;IAED,MAAM,aAAa,GAAG,MAAM,UAAU,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;IAE/D,2CAA2C;IAC3C,MAAM,IAAI,GAAG,iBAAiB,CAAC,aAAa,CAAC,CAAC;IAC9C,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,gCAAgC;QAChC,IAAI,MAAM,GAAG,IAAI,CAAC,MAAM,GAAG,aAAa,CAAC,MAAM,EAAE,CAAC;YAChD,MAAM,IAAI,KAAK,CAAC,qCAAqC,MAAM,UAAU,IAAI,CAAC,MAAM,UAAU,aAAa,CAAC,MAAM,EAAE,CAAC,CAAC;QACpH,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,UAAU,CAAC,aAAa,CAAC,CAAC;QAC9C,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAE1B,sBAAsB;QACtB,MAAM,EAAE,UAAU,EAAE,GAAG,EAAE,GAAG,MAAM,UAAU,CAAC,OAAO,CAAC,CAAC;QACtD,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC;QACzC,MAAM,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;QAErC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC;IACtD,CAAC;IAED,qDAAqD;IACrD,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAEjE,IAAI,MAAM,GAAG,IAAI,CAAC,MAAM,GAAG,SAAS,EAAE,CAAC;QACrC,MAAM,IAAI,KAAK,CAAC,qCAAqC,MAAM,UAAU,IAAI,CAAC,MAAM,UAAU,SAAS,EAAE,CAAC,CAAC;IACzG,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,sBAAsB,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;IAE1E,wCAAwC;IACxC,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,UAAU,EAAE,GAAG,MAAM,2BAA2B,CAAC,MAAM,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;IAE9G,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC;AACjE,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,aAAa,CAC1B,MAAqB,EACrB,IAAc,EACd,MAAc,EACd,IAAgB;IAEhB,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC;IACzB,MAAM,QAAQ,GAAW,EAAE,CAAC;IAC5B,IAAI,QAAQ,GAAG,CAAC,CAAC;IAEjB,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QAC9B,MAAM,SAAS,GAAG,QAAQ,CAAC;QAC3B,MAAM,OAAO,GAAG,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC;QACrC,QAAQ,GAAG,OAAO,CAAC;QAEnB,oDAAoD;QACpD,MAAM,UAAU,GAAG,MAAM,CAAC;QAC1B,MAAM,QAAQ,GAAG,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAEtC,IAAI,OAAO,IAAI,UAAU,IAAI,SAAS,IAAI,QAAQ,EAAE,CAAC;YACnD,kCAAkC;YAClC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACpB,SAAS;QACX,CAAC;QAED,gCAAgC;QAChC,MAAM,SAAS,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7C,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CAAC,kBAAkB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACxD,CAAC;QAED,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,IAAI,EAAE,CAAC;YAChC,8BAA8B;YAC9B,MAAM,SAAS,GAAG,cAAc,CAAC,SAAS,CAAC,CAAC;YAC5C,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;YACpD,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAC1B,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC,EAC/B,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,CAAC,CACxC,CAAC;YAEF,MAAM,aAAa,GAAG,MAAM,aAAa,CAAC,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,CAAC,CAAC;YAErF,8BAA8B;YAC9B,MAAM,YAAY,GAAa;gBAC7B,IAAI,EAAE,QAAQ,CAAC,IAAI;gBACnB,KAAK,EAAE,aAAa;aACrB,CAAC;YACF,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,YAAY,EAAE,GAAG,MAAM,aAAa,CAAC,YAAY,CAAC,CAAC;YACpF,MAAM,KAAK,CAAC,GAAG,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC;YAE3C,QAAQ,CAAC,IAAI,CAAC;gBACZ,IAAI,EAAE,YAAY;gBAClB,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,IAAI,EAAE,QAAQ,CAAC,IAAI;aACpB,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,2BAA2B;YAC3B,MAAM,YAAY,GAAG,IAAI,UAAU,CAAC,SAAS,CAAC,CAAC;YAE/C,gDAAgD;YAChD,MAAM,eAAe,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC,CAAC;YAC5D,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE,QAAQ,GAAG,SAAS,CAAC,CAAC;YACvE,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,GAAG,UAAU,CAAC,CAAC;YAC1D,MAAM,WAAW,GAAG,aAAa,GAAG,CAAC,aAAa,GAAG,eAAe,CAAC,CAAC;YAEtE,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE,WAAW,CAAC,EAAE,eAAe,CAAC,CAAC;YAE1E,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,CAAC;YAC3C,MAAM,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;YAEvC,QAAQ,CAAC,IAAI,CAAC;gBACZ,IAAI,EAAE,OAAO;gBACb,IAAI,EAAE,YAAY,CAAC,MAAM;gBACzB,IAAI,EAAE,QAAQ,CAAC,IAAI;aACpB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;;;GAMG;AACH,KAAK,UAAU,sBAAsB,CACnC,MAAqB,EACrB,IAAc,EACd,MAAc,EACd,IAAgB;IAEhB,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC;IACzB,MAAM,QAAQ,GAAW,EAAE,CAAC;IAE5B,gFAAgF;IAChF,sEAAsE;IACtE,MAAM,gBAAgB,GAAG,EAAE,CAAC;IAE5B,IAAI,QAAQ,GAAG,CAAC,CAAC,CAAC,2BAA2B;IAE7C,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QAC9B,oDAAoD;QACpD,8EAA8E;QAC9E,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,IAAI;YAC/C,CAAC,CAAC,IAAI,CAAC,IAAI,GAAG,gBAAgB;YAC9B,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,2DAA2D;QAE1E,MAAM,SAAS,GAAG,QAAQ,CAAC;QAC3B,MAAM,OAAO,GAAG,QAAQ,GAAG,aAAa,CAAC;QACzC,QAAQ,GAAG,OAAO,CAAC;QAEnB,oDAAoD;QACpD,MAAM,UAAU,GAAG,MAAM,CAAC;QAC1B,MAAM,QAAQ,GAAG,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAEtC,IAAI,OAAO,IAAI,UAAU,IAAI,SAAS,IAAI,QAAQ,EAAE,CAAC;YACnD,kCAAkC;YAClC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACpB,SAAS;QACX,CAAC;QAED,gCAAgC;QAChC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;YACd,MAAM,IAAI,KAAK,CAAC,qCAAqC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC3E,CAAC;QAED,MAAM,cAAc,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClD,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,MAAM,IAAI,KAAK,CAAC,kBAAkB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACxD,CAAC;QAED,MAAM,cAAc,GAAG,MAAM,UAAU,CAAC,cAAc,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;QAElE,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,IAAI,EAAE,CAAC;YAChC,8BAA8B;YAC9B,MAAM,SAAS,GAAG,cAAc,CAAC,cAAc,CAAC,CAAC;YACjD,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;YACpD,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAC1B,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC,EAC/B,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,CAAC,CACxC,CAAC;YAEF,MAAM,aAAa,GAAG,MAAM,sBAAsB,CAAC,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,CAAC,CAAC;YAE9F,wCAAwC;YACxC,MAAM,YAAY,GAAa;gBAC7B,IAAI,EAAE,QAAQ,CAAC,IAAI;gBACnB,KAAK,EAAE,aAAa;aACrB,CAAC;YACF,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,MAAM,aAAa,CAAC,YAAY,CAAC,CAAC;YAChE,MAAM,EAAE,UAAU,EAAE,GAAG,EAAE,GAAG,MAAM,UAAU,CAAC,WAAW,CAAC,CAAC;YAC1D,MAAM,YAAY,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC;YAC9C,MAAM,KAAK,CAAC,GAAG,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;YAE1C,kDAAkD;YAClD,MAAM,gBAAgB,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE;gBACvD,OAAO,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YAC/E,CAAC,EAAE,CAAC,CAAC,CAAC;YAEN,QAAQ,CAAC,IAAI,CAAC;gBACZ,IAAI,EAAE,YAAY;gBAClB,IAAI,EAAE,gBAAgB,EAAE,8CAA8C;gBACtE,GAAG;gBACH,IAAI,EAAE,QAAQ,CAAC,IAAI;aACpB,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,2BAA2B;YAC3B,MAAM,YAAY,GAAG,IAAI,UAAU,CAAC,cAAc,CAAC,CAAC;YAEpD,gDAAgD;YAChD,MAAM,eAAe,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC,CAAC;YAC5D,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,cAAc,CAAC,MAAM,EAAE,QAAQ,GAAG,SAAS,CAAC,CAAC;YAC5E,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,GAAG,UAAU,CAAC,CAAC;YAC1D,MAAM,WAAW,GAAG,aAAa,GAAG,CAAC,aAAa,GAAG,eAAe,CAAC,CAAC;YAEtE,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE,WAAW,CAAC,EAAE,eAAe,CAAC,CAAC;YAE1E,sBAAsB;YACtB,MAAM,EAAE,UAAU,EAAE,GAAG,EAAE,GAAG,MAAM,UAAU,CAAC,YAAY,CAAC,CAAC;YAC3D,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC;YACzC,MAAM,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;YAErC,QAAQ,CAAC,IAAI,CAAC;gBACZ,IAAI,EAAE,OAAO;gBACb,IAAI,EAAE,UAAU,CAAC,MAAM,EAAE,kCAAkC;gBAC3D,GAAG;gBACH,IAAI,EAAE,QAAQ,CAAC,IAAI;aACpB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,kBAAkB,CAC/B,MAAqB,EACrB,KAAa,EACb,SAAiB;IAEjB,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC;IAEzB,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QACtD,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACvB,CAAC;IAED,yCAAyC;IACzC,MAAM,IAAI,GAAa;QACrB,IAAI,EAAE,QAAQ,CAAC,IAAI;QACnB,KAAK;KACN,CAAC;IACF,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,CAAC;IACjD,MAAM,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC5B,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,2BAA2B,CACxC,MAAqB,EACrB,KAAa,EACb,SAAiB;IAEjB,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC;IAEzB,yCAAyC;IACzC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QACtE,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;IACpD,CAAC;IAED,yCAAyC;IACzC,MAAM,IAAI,GAAa;QACrB,IAAI,EAAE,QAAQ,CAAC,IAAI;QACnB,KAAK;KACN,CAAC;IACF,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,CAAC;IAC3C,MAAM,EAAE,UAAU,EAAE,GAAG,EAAE,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC;IACnD,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC;IACtC,MAAM,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;IAClC,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC;AACvB,CAAC"}
@@ -0,0 +1,274 @@
1
+ /**
2
+ * HashTree - Simple content-addressed merkle tree
3
+ *
4
+ * Core principle: Every node is stored by SHA256(msgpack(node)) -> msgpack(node)
5
+ * This enables pure KV content-addressed storage.
6
+ */
7
+ import type { TreeVisibility } from './visibility.js';
8
+ export type { TreeVisibility };
9
+ /**
10
+ * 32-byte SHA256 hash used as content address
11
+ */
12
+ export type Hash = Uint8Array;
13
+ /**
14
+ * Content Identifier - hash + optional decryption key
15
+ *
16
+ * For public content: just the hash
17
+ * For encrypted content: hash + CHK decryption key
18
+ */
19
+ export interface CID {
20
+ /** SHA256 hash of the (encrypted) content */
21
+ hash: Hash;
22
+ /** CHK decryption key (for encrypted content) */
23
+ key?: Uint8Array;
24
+ }
25
+ /**
26
+ * Create a CID from hash and optional key
27
+ */
28
+ export declare function cid(hash: Hash, key?: Uint8Array): CID;
29
+ /**
30
+ * Link/node types - what kind of content a link points to or a node contains
31
+ */
32
+ export declare enum LinkType {
33
+ /** Raw data blob (leaf chunk) */
34
+ Blob = 0,
35
+ /** Chunked file tree (TreeNode with unnamed links) */
36
+ File = 1,
37
+ /** Directory tree (TreeNode with named links) */
38
+ Dir = 2
39
+ }
40
+ /**
41
+ * A link to a child node with optional metadata
42
+ */
43
+ export interface Link {
44
+ /** SHA256 hash of the child node's MessagePack encoding */
45
+ hash: Hash;
46
+ /** Optional name (for directory entries) */
47
+ name?: string;
48
+ /** Size of subtree in bytes (for efficient seeks). 0 for Dir links. */
49
+ size: number;
50
+ /** CHK decryption key (content hash) for encrypted nodes */
51
+ key?: Uint8Array;
52
+ /** Type of content this link points to: Blob, File, or Dir */
53
+ type: LinkType;
54
+ /** Optional metadata (for directory entries: createdAt, mimeType, thumbnail, etc.) */
55
+ meta?: Record<string, unknown>;
56
+ }
57
+ /**
58
+ * Tree node - contains links to children
59
+ * Stored as: SHA256(msgpack(TreeNode)) -> msgpack(TreeNode)
60
+ *
61
+ * For directories: type=Dir, links have names
62
+ * For chunked files: type=File, links are ordered chunks
63
+ */
64
+ export interface TreeNode {
65
+ /** Type of this node: File or Dir */
66
+ type: LinkType.File | LinkType.Dir;
67
+ /** Links to child nodes */
68
+ links: Link[];
69
+ }
70
+ /**
71
+ * Blob - raw data (leaf)
72
+ * Stored as: SHA256(data) -> data
73
+ *
74
+ * Note: Blobs are stored directly as raw bytes, not as a structured type
75
+ */
76
+ export type Blob = Uint8Array;
77
+ /**
78
+ * Result of adding content to the tree
79
+ */
80
+ export interface PutResult {
81
+ /** Hash of the stored node */
82
+ hash: Hash;
83
+ /** Size of the stored data */
84
+ size: number;
85
+ }
86
+ /**
87
+ * Options for building trees
88
+ */
89
+ export interface TreeOptions {
90
+ /** Max links per tree node before splitting (default: 256) */
91
+ fanout?: number;
92
+ /** Max blob size before chunking (default: 2MB) */
93
+ chunkSize?: number;
94
+ }
95
+ /**
96
+ * Directory entry for building directory trees
97
+ */
98
+ export interface DirEntry {
99
+ name: string;
100
+ hash: Hash;
101
+ size: number;
102
+ /** Type of content this entry points to: Blob, File, or Dir */
103
+ type: LinkType;
104
+ }
105
+ /**
106
+ * Content-addressed key-value store interface
107
+ */
108
+ export interface Store {
109
+ /**
110
+ * Store data by its hash
111
+ * @returns true if newly stored, false if already existed
112
+ */
113
+ put(hash: Hash, data: Uint8Array): Promise<boolean>;
114
+ /**
115
+ * Retrieve data by hash
116
+ * @returns data or null if not found
117
+ */
118
+ get(hash: Hash): Promise<Uint8Array | null>;
119
+ /**
120
+ * Check if hash exists
121
+ */
122
+ has(hash: Hash): Promise<boolean>;
123
+ /**
124
+ * Delete by hash
125
+ * @returns true if deleted, false if didn't exist
126
+ */
127
+ delete(hash: Hash): Promise<boolean>;
128
+ }
129
+ /**
130
+ * Extended store with metadata support (e.g., Blossom)
131
+ */
132
+ export interface StoreWithMeta extends Store {
133
+ /**
134
+ * Store with content type
135
+ */
136
+ put(hash: Hash, data: Uint8Array, contentType?: string): Promise<boolean>;
137
+ }
138
+ /**
139
+ * Hex string representation of a hash
140
+ */
141
+ export type HashHex = string;
142
+ /**
143
+ * Convert hash to hex string
144
+ */
145
+ export declare function toHex(hash: Hash): HashHex;
146
+ /**
147
+ * Convert hex string to hash
148
+ */
149
+ export declare function fromHex(hex: HashHex): Hash;
150
+ /**
151
+ * Compare two hashes for equality
152
+ */
153
+ export declare function hashEquals(a: Hash, b: Hash): boolean;
154
+ /**
155
+ * Entry returned from RefResolver.list()
156
+ */
157
+ export interface RefResolverListEntry {
158
+ key: string;
159
+ cid: CID;
160
+ /** Tree visibility: public, link-visible, or private */
161
+ visibility?: TreeVisibility;
162
+ /** Encrypted key for link-visible trees - decrypt with link key from URL */
163
+ encryptedKey?: string;
164
+ /** Key ID for link-visible trees */
165
+ keyId?: string;
166
+ /** Self-encrypted key for private/link-visible trees - decrypt with NIP-44 */
167
+ selfEncryptedKey?: string;
168
+ /** Self-encrypted link key for link-visible trees - allows owner to recover link key */
169
+ selfEncryptedLinkKey?: string;
170
+ /** Unix timestamp when the tree was created/last updated */
171
+ createdAt?: number;
172
+ }
173
+ /**
174
+ * Visibility info passed to subscribe callbacks
175
+ */
176
+ export interface SubscribeVisibilityInfo {
177
+ /** Tree visibility: public, link-visible, or private */
178
+ visibility: TreeVisibility;
179
+ /** Encrypted key for link-visible trees - decrypt with link key from URL */
180
+ encryptedKey?: string;
181
+ /** Key ID for link-visible trees */
182
+ keyId?: string;
183
+ /** Self-encrypted key for private/link-visible trees - decrypt with NIP-44 */
184
+ selfEncryptedKey?: string;
185
+ /** Self-encrypted link key for link-visible trees - allows owner to recover link key for sharing */
186
+ selfEncryptedLinkKey?: string;
187
+ }
188
+ /**
189
+ * Options for publishing a tree
190
+ */
191
+ export interface PublishOptions {
192
+ /** Tree visibility: public (default), link-visible, or private */
193
+ visibility?: TreeVisibility;
194
+ /** Link key for link-visible trees - if not provided, one will be generated */
195
+ linkKey?: Uint8Array;
196
+ /** Additional l-tags to add (e.g., ['docs'] for document trees) */
197
+ labels?: string[];
198
+ }
199
+ /**
200
+ * Result from publishing a tree
201
+ */
202
+ export interface PublishResult {
203
+ /** Whether the publish succeeded */
204
+ success: boolean;
205
+ /** Link key for link-visible trees (include in URL as k= param) */
206
+ linkKey?: Uint8Array;
207
+ }
208
+ /**
209
+ * RefResolver - Maps human-readable keys to merkle root hashes (refs)
210
+ *
211
+ * This abstraction allows different backends (Nostr, DNS, HTTP, local storage)
212
+ * to provide mutable pointers to immutable content-addressed data.
213
+ *
214
+ * Key format is implementation-specific, e.g.:
215
+ * - Nostr: "npub1.../treename"
216
+ * - DNS: "example.com/treename"
217
+ * - Local: "local/mydata"
218
+ *
219
+ * All methods wait indefinitely until data is available - caller should apply timeout if needed.
220
+ */
221
+ export interface RefResolver {
222
+ /**
223
+ * Resolve a key to its current CID.
224
+ * Waits indefinitely until found - caller should apply timeout if needed.
225
+ * @returns CID (never null - waits until found)
226
+ */
227
+ resolve(key: string): Promise<CID | null>;
228
+ /**
229
+ * Subscribe to CID changes for a key.
230
+ * Callback fires immediately with current value (if available), then on each update.
231
+ * Subscription stays open indefinitely until unsubscribed.
232
+ *
233
+ * @param key The key to watch
234
+ * @param callback Called with new CID (or null if deleted/unavailable) and visibility info
235
+ * @returns Unsubscribe function
236
+ */
237
+ subscribe(key: string, callback: (cid: CID | null, visibilityInfo?: SubscribeVisibilityInfo) => void): () => void;
238
+ /**
239
+ * Publish/update a CID (optional - only for writable backends)
240
+ * Handles all visibility types: public, link-visible, private
241
+ * @param key The key to publish to
242
+ * @param cid The CID to publish (with encryption key if encrypted)
243
+ * @param options Publish options (visibility, linkKey, labels)
244
+ * @returns Result with success status and linkKey (for link-visible)
245
+ */
246
+ publish?(key: string, cid: CID, options?: PublishOptions): Promise<PublishResult>;
247
+ /**
248
+ * List all keys matching a prefix.
249
+ * Streams results as they arrive - stays open indefinitely.
250
+ * Callback fires on each new entry or update.
251
+ *
252
+ * @param prefix The prefix to watch (e.g., "npub1..." for all trees of a user)
253
+ * @param callback Called with updated list as entries arrive (includes visibility info)
254
+ * @returns Unsubscribe function
255
+ */
256
+ list?(prefix: string, callback: (entries: Array<RefResolverListEntry>) => void): () => void;
257
+ /**
258
+ * Stop the resolver and clean up resources
259
+ */
260
+ stop?(): void;
261
+ /**
262
+ * Inject a local list entry (for instant UI updates)
263
+ * This makes trees appear immediately without waiting for network
264
+ * @param entry The entry to inject with full visibility info
265
+ */
266
+ injectListEntry?(entry: RefResolverListEntry): void;
267
+ /**
268
+ * Delete a tree (publish event without hash to nullify)
269
+ * @param key The key to delete (e.g., "npub1.../treename")
270
+ * @returns true if deleted successfully
271
+ */
272
+ delete?(key: string): Promise<boolean>;
273
+ }
274
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Create a CID from hash and optional key
3
+ */
4
+ export function cid(hash, key) {
5
+ return key ? { hash, key } : { hash };
6
+ }
7
+ /**
8
+ * Link/node types - what kind of content a link points to or a node contains
9
+ */
10
+ export var LinkType;
11
+ (function (LinkType) {
12
+ /** Raw data blob (leaf chunk) */
13
+ LinkType[LinkType["Blob"] = 0] = "Blob";
14
+ /** Chunked file tree (TreeNode with unnamed links) */
15
+ LinkType[LinkType["File"] = 1] = "File";
16
+ /** Directory tree (TreeNode with named links) */
17
+ LinkType[LinkType["Dir"] = 2] = "Dir";
18
+ })(LinkType || (LinkType = {}));
19
+ /**
20
+ * Convert hash to hex string
21
+ */
22
+ export function toHex(hash) {
23
+ return Array.from(hash).map(b => b.toString(16).padStart(2, '0')).join('');
24
+ }
25
+ /**
26
+ * Convert hex string to hash
27
+ */
28
+ export function fromHex(hex) {
29
+ const bytes = new Uint8Array(hex.length / 2);
30
+ for (let i = 0; i < bytes.length; i++) {
31
+ bytes[i] = parseInt(hex.substr(i * 2, 2), 16);
32
+ }
33
+ return bytes;
34
+ }
35
+ /**
36
+ * Compare two hashes for equality
37
+ */
38
+ export function hashEquals(a, b) {
39
+ if (a.length !== b.length)
40
+ return false;
41
+ for (let i = 0; i < a.length; i++) {
42
+ if (a[i] !== b[i])
43
+ return false;
44
+ }
45
+ return true;
46
+ }
47
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AA2BA;;GAEG;AACH,MAAM,UAAU,GAAG,CAAC,IAAU,EAAE,GAAgB;IAC9C,OAAO,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;AACxC,CAAC;AAED;;GAEG;AACH,MAAM,CAAN,IAAY,QAOX;AAPD,WAAY,QAAQ;IAClB,iCAAiC;IACjC,uCAAQ,CAAA;IACR,sDAAsD;IACtD,uCAAQ,CAAA;IACR,iDAAiD;IACjD,qCAAO,CAAA;AACT,CAAC,EAPW,QAAQ,KAAR,QAAQ,QAOnB;AAoHD;;GAEG;AACH,MAAM,UAAU,KAAK,CAAC,IAAU;IAC9B,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAC7E,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,OAAO,CAAC,GAAY;IAClC,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC7C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,KAAK,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAChD,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,CAAO,EAAE,CAAO;IACzC,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IACxC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAClC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAAE,OAAO,KAAK,CAAC;IAClC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Tree verification utilities
3
+ */
4
+ import { Store, Hash } from './types.js';
5
+ /**
6
+ * Verify tree integrity - checks that all referenced hashes exist
7
+ */
8
+ export declare function verifyTree(store: Store, rootHash: Hash): Promise<{
9
+ valid: boolean;
10
+ missing: Hash[];
11
+ }>;
12
+ //# sourceMappingURL=verify.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../src/verify.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,KAAK,EAAE,IAAI,EAAS,MAAM,YAAY,CAAC;AAGhD;;GAEG;AACH,wBAAsB,UAAU,CAC9B,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,IAAI,GACb,OAAO,CAAC;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,IAAI,EAAE,CAAA;CAAE,CAAC,CA0B9C"}