@soulcraft/brainy 4.11.2 → 5.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.
- package/CHANGELOG.md +271 -0
- package/README.md +38 -1
- package/dist/augmentations/brainyAugmentation.d.ts +76 -0
- package/dist/augmentations/brainyAugmentation.js +126 -0
- package/dist/augmentations/cacheAugmentation.js +9 -4
- package/dist/brainy.d.ts +248 -15
- package/dist/brainy.js +707 -17
- package/dist/cli/commands/cow.d.ts +60 -0
- package/dist/cli/commands/cow.js +444 -0
- package/dist/cli/commands/import.js +1 -1
- package/dist/cli/commands/vfs.js +24 -40
- package/dist/cli/index.js +50 -0
- package/dist/hnsw/hnswIndex.d.ts +41 -0
- package/dist/hnsw/hnswIndex.js +96 -1
- package/dist/hnsw/typeAwareHNSWIndex.d.ts +9 -0
- package/dist/hnsw/typeAwareHNSWIndex.js +22 -0
- package/dist/import/ImportHistory.js +3 -3
- package/dist/importers/VFSStructureGenerator.d.ts +1 -1
- package/dist/importers/VFSStructureGenerator.js +3 -3
- package/dist/index.d.ts +6 -0
- package/dist/index.js +10 -0
- package/dist/storage/adapters/memoryStorage.d.ts +6 -0
- package/dist/storage/adapters/memoryStorage.js +39 -14
- package/dist/storage/adapters/typeAwareStorageAdapter.d.ts +31 -1
- package/dist/storage/adapters/typeAwareStorageAdapter.js +272 -43
- package/dist/storage/baseStorage.d.ts +64 -0
- package/dist/storage/baseStorage.js +252 -12
- package/dist/storage/cow/BlobStorage.d.ts +232 -0
- package/dist/storage/cow/BlobStorage.js +437 -0
- package/dist/storage/cow/CommitLog.d.ts +199 -0
- package/dist/storage/cow/CommitLog.js +363 -0
- package/dist/storage/cow/CommitObject.d.ts +276 -0
- package/dist/storage/cow/CommitObject.js +431 -0
- package/dist/storage/cow/RefManager.d.ts +213 -0
- package/dist/storage/cow/RefManager.js +409 -0
- package/dist/storage/cow/TreeObject.d.ts +177 -0
- package/dist/storage/cow/TreeObject.js +293 -0
- package/dist/storage/storageFactory.d.ts +6 -0
- package/dist/storage/storageFactory.js +92 -74
- package/dist/types/brainy.types.d.ts +1 -0
- package/dist/vfs/FSCompat.d.ts +1 -1
- package/dist/vfs/FSCompat.js +1 -1
- package/dist/vfs/VirtualFileSystem.js +5 -6
- package/package.json +1 -1
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RefManager: Branch and reference management for COW (Copy-on-Write)
|
|
3
|
+
*
|
|
4
|
+
* Similar to Git refs, manages symbolic names (branches, tags) that point to commits.
|
|
5
|
+
*
|
|
6
|
+
* Structure:
|
|
7
|
+
* - refs/heads/main → commit hash (main branch)
|
|
8
|
+
* - refs/heads/experiment → commit hash (experiment branch)
|
|
9
|
+
* - refs/tags/v1.0.0 → commit hash (version tag)
|
|
10
|
+
* - HEAD → ref name (current branch)
|
|
11
|
+
*
|
|
12
|
+
* Features:
|
|
13
|
+
* - Branch management (create, delete, list)
|
|
14
|
+
* - Tag management
|
|
15
|
+
* - HEAD pointer (current branch)
|
|
16
|
+
* - Fast-forward and force updates
|
|
17
|
+
* - Atomic operations
|
|
18
|
+
*
|
|
19
|
+
* @module storage/cow/RefManager
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* RefManager: Manages branches, tags, and HEAD pointer
|
|
23
|
+
*
|
|
24
|
+
* Pure implementation for v5.0.0 - no backward compatibility
|
|
25
|
+
*/
|
|
26
|
+
export class RefManager {
|
|
27
|
+
constructor(adapter) {
|
|
28
|
+
this.adapter = adapter;
|
|
29
|
+
this.cache = new Map();
|
|
30
|
+
this.cacheValid = false;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Get reference by name
|
|
34
|
+
*
|
|
35
|
+
* @param name - Reference name (e.g., 'main', 'refs/heads/main')
|
|
36
|
+
* @returns Reference object or undefined
|
|
37
|
+
*/
|
|
38
|
+
async getRef(name) {
|
|
39
|
+
const fullName = this.normalizeRefName(name);
|
|
40
|
+
// Check cache
|
|
41
|
+
if (this.cacheValid && this.cache.has(fullName)) {
|
|
42
|
+
return this.cache.get(fullName);
|
|
43
|
+
}
|
|
44
|
+
// Read from storage
|
|
45
|
+
const data = await this.adapter.get(`ref:${fullName}`);
|
|
46
|
+
if (!data) {
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
const ref = JSON.parse(data.toString());
|
|
50
|
+
// Update cache
|
|
51
|
+
this.cache.set(fullName, ref);
|
|
52
|
+
return ref;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Set reference to point to commit
|
|
56
|
+
*
|
|
57
|
+
* @param name - Reference name
|
|
58
|
+
* @param commitHash - Commit hash to point to
|
|
59
|
+
* @param options - Update options
|
|
60
|
+
*/
|
|
61
|
+
async setRef(name, commitHash, options = {}) {
|
|
62
|
+
const fullName = this.normalizeRefName(name);
|
|
63
|
+
// Validate commit hash format
|
|
64
|
+
if (!/^[a-f0-9]{64}$/.test(commitHash)) {
|
|
65
|
+
throw new Error(`Invalid commit hash: ${commitHash}`);
|
|
66
|
+
}
|
|
67
|
+
// Check if ref exists
|
|
68
|
+
const existing = await this.getRef(fullName);
|
|
69
|
+
// Handle createOnly
|
|
70
|
+
if (options.createOnly && existing) {
|
|
71
|
+
throw new Error(`Ref already exists: ${fullName}`);
|
|
72
|
+
}
|
|
73
|
+
// Handle updateOnly
|
|
74
|
+
if (options.updateOnly && !existing) {
|
|
75
|
+
throw new Error(`Ref does not exist: ${fullName}`);
|
|
76
|
+
}
|
|
77
|
+
// Handle CAS (Compare-And-Swap)
|
|
78
|
+
if (options.expectedOldValue !== undefined) {
|
|
79
|
+
if (!existing || existing.commitHash !== options.expectedOldValue) {
|
|
80
|
+
throw new Error(`Ref update failed: expected ${options.expectedOldValue}, ` +
|
|
81
|
+
`got ${existing?.commitHash ?? 'none'}`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
// Check for fast-forward (if not force)
|
|
85
|
+
if (!options.force && existing) {
|
|
86
|
+
// TODO: Verify this is a fast-forward update
|
|
87
|
+
// For now, allow all updates
|
|
88
|
+
}
|
|
89
|
+
// Create/update ref
|
|
90
|
+
const ref = {
|
|
91
|
+
name: fullName,
|
|
92
|
+
commitHash,
|
|
93
|
+
type: this.getRefType(fullName),
|
|
94
|
+
createdAt: existing?.createdAt ?? Date.now(),
|
|
95
|
+
updatedAt: Date.now(),
|
|
96
|
+
metadata: existing?.metadata
|
|
97
|
+
};
|
|
98
|
+
// Write to storage
|
|
99
|
+
await this.adapter.put(`ref:${fullName}`, Buffer.from(JSON.stringify(ref)));
|
|
100
|
+
// Update cache
|
|
101
|
+
this.cache.set(fullName, ref);
|
|
102
|
+
this.cacheValid = false; // Invalidate for listRefs
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Delete reference
|
|
106
|
+
*
|
|
107
|
+
* @param name - Reference name
|
|
108
|
+
*/
|
|
109
|
+
async deleteRef(name) {
|
|
110
|
+
const fullName = this.normalizeRefName(name);
|
|
111
|
+
// Don't allow deleting HEAD
|
|
112
|
+
if (fullName === 'HEAD') {
|
|
113
|
+
throw new Error('Cannot delete HEAD');
|
|
114
|
+
}
|
|
115
|
+
// Don't allow deleting main if it's the only branch
|
|
116
|
+
if (fullName === 'refs/heads/main') {
|
|
117
|
+
const branches = await this.listRefs('branch');
|
|
118
|
+
if (branches.length === 1) {
|
|
119
|
+
throw new Error('Cannot delete last branch');
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
// Delete from storage
|
|
123
|
+
await this.adapter.delete(`ref:${fullName}`);
|
|
124
|
+
// Update cache
|
|
125
|
+
this.cache.delete(fullName);
|
|
126
|
+
this.cacheValid = false;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* List all references
|
|
130
|
+
*
|
|
131
|
+
* @param type - Filter by type (optional)
|
|
132
|
+
* @returns Array of references
|
|
133
|
+
*/
|
|
134
|
+
async listRefs(type) {
|
|
135
|
+
// Get all ref keys
|
|
136
|
+
const keys = await this.adapter.list('ref:');
|
|
137
|
+
const refs = [];
|
|
138
|
+
for (const key of keys) {
|
|
139
|
+
const refName = key.replace(/^ref:/, '');
|
|
140
|
+
// Skip HEAD in listings (it's special)
|
|
141
|
+
if (refName === 'HEAD') {
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
const ref = await this.getRef(refName);
|
|
145
|
+
if (ref) {
|
|
146
|
+
// Filter by type if requested
|
|
147
|
+
if (!type || ref.type === type) {
|
|
148
|
+
refs.push(ref);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
// Mark cache as valid
|
|
153
|
+
this.cacheValid = true;
|
|
154
|
+
return refs.sort((a, b) => a.name.localeCompare(b.name));
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Copy reference (create branch from existing ref)
|
|
158
|
+
*
|
|
159
|
+
* @param sourceName - Source reference name
|
|
160
|
+
* @param targetName - Target reference name
|
|
161
|
+
* @param options - Update options
|
|
162
|
+
*/
|
|
163
|
+
async copyRef(sourceName, targetName, options = {}) {
|
|
164
|
+
const sourceRef = await this.getRef(sourceName);
|
|
165
|
+
if (!sourceRef) {
|
|
166
|
+
throw new Error(`Source ref not found: ${sourceName}`);
|
|
167
|
+
}
|
|
168
|
+
// Set target ref to same commit as source
|
|
169
|
+
await this.setRef(targetName, sourceRef.commitHash, options);
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Get current HEAD (current branch)
|
|
173
|
+
*
|
|
174
|
+
* @returns HEAD reference or undefined
|
|
175
|
+
*/
|
|
176
|
+
async getHead() {
|
|
177
|
+
const data = await this.adapter.get('ref:HEAD');
|
|
178
|
+
if (!data) {
|
|
179
|
+
return undefined;
|
|
180
|
+
}
|
|
181
|
+
const head = JSON.parse(data.toString());
|
|
182
|
+
// Resolve symbolic ref
|
|
183
|
+
return this.getRef(head.ref);
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Set HEAD to point to branch
|
|
187
|
+
*
|
|
188
|
+
* @param branchName - Branch name (e.g., 'main', 'refs/heads/experiment')
|
|
189
|
+
*/
|
|
190
|
+
async setHead(branchName) {
|
|
191
|
+
const fullName = this.normalizeRefName(branchName);
|
|
192
|
+
// Verify branch exists
|
|
193
|
+
const branch = await this.getRef(fullName);
|
|
194
|
+
if (!branch) {
|
|
195
|
+
throw new Error(`Branch not found: ${fullName}`);
|
|
196
|
+
}
|
|
197
|
+
if (branch.type !== 'branch') {
|
|
198
|
+
throw new Error(`Cannot set HEAD to non-branch ref: ${fullName}`);
|
|
199
|
+
}
|
|
200
|
+
// Set HEAD (symbolic ref)
|
|
201
|
+
const head = { ref: fullName };
|
|
202
|
+
await this.adapter.put('ref:HEAD', Buffer.from(JSON.stringify(head)));
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Get current commit hash (resolves HEAD)
|
|
206
|
+
*
|
|
207
|
+
* @returns Current commit hash or undefined
|
|
208
|
+
*/
|
|
209
|
+
async getCurrentCommit() {
|
|
210
|
+
const head = await this.getHead();
|
|
211
|
+
return head?.commitHash;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Create branch
|
|
215
|
+
*
|
|
216
|
+
* @param name - Branch name (e.g., 'experiment')
|
|
217
|
+
* @param commitHash - Commit hash to point to
|
|
218
|
+
* @param options - Create options
|
|
219
|
+
*/
|
|
220
|
+
async createBranch(name, commitHash, options) {
|
|
221
|
+
const fullName = this.normalizeRefName(name, 'branch');
|
|
222
|
+
await this.setRef(fullName, commitHash, { createOnly: true });
|
|
223
|
+
// Update metadata if provided
|
|
224
|
+
if (options?.description || options?.author) {
|
|
225
|
+
const ref = await this.getRef(fullName);
|
|
226
|
+
if (ref) {
|
|
227
|
+
ref.metadata = {
|
|
228
|
+
...ref.metadata,
|
|
229
|
+
description: options.description,
|
|
230
|
+
author: options.author
|
|
231
|
+
};
|
|
232
|
+
await this.adapter.put(`ref:${fullName}`, Buffer.from(JSON.stringify(ref)));
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Delete branch
|
|
238
|
+
*
|
|
239
|
+
* @param name - Branch name
|
|
240
|
+
*/
|
|
241
|
+
async deleteBranch(name) {
|
|
242
|
+
const fullName = this.normalizeRefName(name, 'branch');
|
|
243
|
+
await this.deleteRef(fullName);
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* List all branches
|
|
247
|
+
*
|
|
248
|
+
* @returns Array of branch references
|
|
249
|
+
*/
|
|
250
|
+
async listBranches() {
|
|
251
|
+
return this.listRefs('branch');
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Create tag
|
|
255
|
+
*
|
|
256
|
+
* @param name - Tag name (e.g., 'v1.0.0')
|
|
257
|
+
* @param commitHash - Commit hash to point to
|
|
258
|
+
* @param options - Create options
|
|
259
|
+
*/
|
|
260
|
+
async createTag(name, commitHash, options) {
|
|
261
|
+
const fullName = this.normalizeRefName(name, 'tag');
|
|
262
|
+
await this.setRef(fullName, commitHash, { createOnly: true });
|
|
263
|
+
// Update metadata if provided
|
|
264
|
+
if (options?.description || options?.author) {
|
|
265
|
+
const ref = await this.getRef(fullName);
|
|
266
|
+
if (ref) {
|
|
267
|
+
ref.metadata = {
|
|
268
|
+
...ref.metadata,
|
|
269
|
+
description: options.description,
|
|
270
|
+
author: options.author
|
|
271
|
+
};
|
|
272
|
+
await this.adapter.put(`ref:${fullName}`, Buffer.from(JSON.stringify(ref)));
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Delete tag
|
|
278
|
+
*
|
|
279
|
+
* @param name - Tag name
|
|
280
|
+
*/
|
|
281
|
+
async deleteTag(name) {
|
|
282
|
+
const fullName = this.normalizeRefName(name, 'tag');
|
|
283
|
+
await this.deleteRef(fullName);
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* List all tags
|
|
287
|
+
*
|
|
288
|
+
* @returns Array of tag references
|
|
289
|
+
*/
|
|
290
|
+
async listTags() {
|
|
291
|
+
return this.listRefs('tag');
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Check if reference exists
|
|
295
|
+
*
|
|
296
|
+
* @param name - Reference name
|
|
297
|
+
* @returns True if reference exists
|
|
298
|
+
*/
|
|
299
|
+
async hasRef(name) {
|
|
300
|
+
const ref = await this.getRef(name);
|
|
301
|
+
return ref !== undefined;
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Update reference to new commit (with validation)
|
|
305
|
+
*
|
|
306
|
+
* @param name - Reference name
|
|
307
|
+
* @param newCommitHash - New commit hash
|
|
308
|
+
* @param oldCommitHash - Expected old commit hash (for safety)
|
|
309
|
+
*/
|
|
310
|
+
async updateRef(name, newCommitHash, oldCommitHash) {
|
|
311
|
+
const options = {};
|
|
312
|
+
if (oldCommitHash) {
|
|
313
|
+
options.expectedOldValue = oldCommitHash;
|
|
314
|
+
}
|
|
315
|
+
await this.setRef(name, newCommitHash, options);
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Get commit hash for reference
|
|
319
|
+
*
|
|
320
|
+
* @param name - Reference name
|
|
321
|
+
* @returns Commit hash or undefined
|
|
322
|
+
*/
|
|
323
|
+
async resolveRef(name) {
|
|
324
|
+
const ref = await this.getRef(name);
|
|
325
|
+
return ref?.commitHash;
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Find references pointing to commit
|
|
329
|
+
*
|
|
330
|
+
* @param commitHash - Commit hash
|
|
331
|
+
* @returns Array of references pointing to this commit
|
|
332
|
+
*/
|
|
333
|
+
async findRefsPointingTo(commitHash) {
|
|
334
|
+
const allRefs = await this.listRefs();
|
|
335
|
+
return allRefs.filter(ref => ref.commitHash === commitHash);
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Clear cache (useful for testing)
|
|
339
|
+
*/
|
|
340
|
+
clearCache() {
|
|
341
|
+
this.cache.clear();
|
|
342
|
+
this.cacheValid = false;
|
|
343
|
+
}
|
|
344
|
+
// ========== PRIVATE METHODS ==========
|
|
345
|
+
/**
|
|
346
|
+
* Normalize reference name to full format
|
|
347
|
+
*
|
|
348
|
+
* Examples:
|
|
349
|
+
* - 'main' → 'refs/heads/main'
|
|
350
|
+
* - 'v1.0.0' (with type='tag') → 'refs/tags/v1.0.0'
|
|
351
|
+
* - 'refs/heads/experiment' → 'refs/heads/experiment'
|
|
352
|
+
*
|
|
353
|
+
* @param name - Reference name
|
|
354
|
+
* @param type - Reference type hint
|
|
355
|
+
* @returns Full reference name
|
|
356
|
+
*/
|
|
357
|
+
normalizeRefName(name, type) {
|
|
358
|
+
// Already full format
|
|
359
|
+
if (name.startsWith('refs/')) {
|
|
360
|
+
return name;
|
|
361
|
+
}
|
|
362
|
+
// HEAD is special
|
|
363
|
+
if (name === 'HEAD') {
|
|
364
|
+
return 'HEAD';
|
|
365
|
+
}
|
|
366
|
+
// Infer type from name if not provided
|
|
367
|
+
if (!type) {
|
|
368
|
+
// Tags usually start with 'v' or contain dots
|
|
369
|
+
if (name.startsWith('v') && /\d/.test(name)) {
|
|
370
|
+
type = 'tag';
|
|
371
|
+
}
|
|
372
|
+
else {
|
|
373
|
+
type = 'branch'; // Default to branch
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
// Add prefix
|
|
377
|
+
switch (type) {
|
|
378
|
+
case 'branch':
|
|
379
|
+
return `refs/heads/${name}`;
|
|
380
|
+
case 'tag':
|
|
381
|
+
return `refs/tags/${name}`;
|
|
382
|
+
case 'remote':
|
|
383
|
+
return `refs/remotes/${name}`;
|
|
384
|
+
default:
|
|
385
|
+
return name;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* Get reference type from full name
|
|
390
|
+
*
|
|
391
|
+
* @param fullName - Full reference name
|
|
392
|
+
* @returns Reference type
|
|
393
|
+
*/
|
|
394
|
+
getRefType(fullName) {
|
|
395
|
+
if (fullName.startsWith('refs/heads/')) {
|
|
396
|
+
return 'branch';
|
|
397
|
+
}
|
|
398
|
+
else if (fullName.startsWith('refs/tags/')) {
|
|
399
|
+
return 'tag';
|
|
400
|
+
}
|
|
401
|
+
else if (fullName.startsWith('refs/remotes/')) {
|
|
402
|
+
return 'remote';
|
|
403
|
+
}
|
|
404
|
+
else {
|
|
405
|
+
return 'branch'; // Default
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
//# sourceMappingURL=RefManager.js.map
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TreeObject: Directory structure for COW (Copy-on-Write)
|
|
3
|
+
*
|
|
4
|
+
* Similar to Git trees, represents the structure of a Brainy instance at a point in time.
|
|
5
|
+
* Trees contain entries mapping names to blob hashes.
|
|
6
|
+
*
|
|
7
|
+
* Structure:
|
|
8
|
+
* - entities/ → tree hash (entity blobs)
|
|
9
|
+
* - indexes/nouns → blob hash (HNSW noun index)
|
|
10
|
+
* - indexes/metadata → blob hash (metadata index)
|
|
11
|
+
* - indexes/graph → blob hash (graph adjacency index)
|
|
12
|
+
* - indexes/deleted → blob hash (deleted items index)
|
|
13
|
+
*
|
|
14
|
+
* @module storage/cow/TreeObject
|
|
15
|
+
*/
|
|
16
|
+
import { BlobStorage } from './BlobStorage.js';
|
|
17
|
+
/**
|
|
18
|
+
* Tree entry: name → blob hash mapping
|
|
19
|
+
*/
|
|
20
|
+
export interface TreeEntry {
|
|
21
|
+
name: string;
|
|
22
|
+
hash: string;
|
|
23
|
+
type: 'blob' | 'tree';
|
|
24
|
+
size: number;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Tree object structure
|
|
28
|
+
*/
|
|
29
|
+
export interface TreeObject {
|
|
30
|
+
entries: TreeEntry[];
|
|
31
|
+
createdAt: number;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* TreeBuilder: Fluent API for building tree objects
|
|
35
|
+
*
|
|
36
|
+
* Example:
|
|
37
|
+
* ```typescript
|
|
38
|
+
* const tree = await TreeBuilder.create(blobStorage)
|
|
39
|
+
* .addBlob('entities/abc123', entityHash, size)
|
|
40
|
+
* .addBlob('indexes/nouns', nounsHash, size)
|
|
41
|
+
* .build()
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export declare class TreeBuilder {
|
|
45
|
+
private entries;
|
|
46
|
+
private blobStorage;
|
|
47
|
+
constructor(blobStorage: BlobStorage);
|
|
48
|
+
static create(blobStorage: BlobStorage): TreeBuilder;
|
|
49
|
+
/**
|
|
50
|
+
* Add a blob entry to the tree
|
|
51
|
+
*
|
|
52
|
+
* @param name - Entry name (e.g., 'entities/abc123')
|
|
53
|
+
* @param hash - Blob hash
|
|
54
|
+
* @param size - Original blob size
|
|
55
|
+
*/
|
|
56
|
+
addBlob(name: string, hash: string, size: number): this;
|
|
57
|
+
/**
|
|
58
|
+
* Add a subtree entry to the tree
|
|
59
|
+
*
|
|
60
|
+
* @param name - Subtree name (e.g., 'entities/')
|
|
61
|
+
* @param treeHash - Tree hash
|
|
62
|
+
* @param size - Total size of subtree
|
|
63
|
+
*/
|
|
64
|
+
addTree(name: string, treeHash: string, size: number): this;
|
|
65
|
+
/**
|
|
66
|
+
* Build and persist the tree object
|
|
67
|
+
*
|
|
68
|
+
* @returns Tree hash
|
|
69
|
+
*/
|
|
70
|
+
build(): Promise<string>;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* TreeObject: Represents directory structure in COW storage
|
|
74
|
+
*/
|
|
75
|
+
export declare class TreeObject {
|
|
76
|
+
/**
|
|
77
|
+
* Serialize tree object to Buffer
|
|
78
|
+
*
|
|
79
|
+
* Format: JSON (simple, debuggable)
|
|
80
|
+
* Future: Could use protobuf for efficiency
|
|
81
|
+
*
|
|
82
|
+
* @param tree - Tree object
|
|
83
|
+
* @returns Serialized tree
|
|
84
|
+
*/
|
|
85
|
+
static serialize(tree: TreeObject): Buffer;
|
|
86
|
+
/**
|
|
87
|
+
* Deserialize tree object from Buffer
|
|
88
|
+
*
|
|
89
|
+
* @param data - Serialized tree
|
|
90
|
+
* @returns Tree object
|
|
91
|
+
*/
|
|
92
|
+
static deserialize(data: Buffer): TreeObject;
|
|
93
|
+
/**
|
|
94
|
+
* Compute hash of tree object
|
|
95
|
+
*
|
|
96
|
+
* @param tree - Tree object
|
|
97
|
+
* @returns SHA-256 hash
|
|
98
|
+
*/
|
|
99
|
+
static hash(tree: TreeObject): string;
|
|
100
|
+
/**
|
|
101
|
+
* Write tree object to blob storage
|
|
102
|
+
*
|
|
103
|
+
* @param blobStorage - Blob storage instance
|
|
104
|
+
* @param tree - Tree object
|
|
105
|
+
* @returns Tree hash
|
|
106
|
+
*/
|
|
107
|
+
static write(blobStorage: BlobStorage, tree: TreeObject): Promise<string>;
|
|
108
|
+
/**
|
|
109
|
+
* Read tree object from blob storage
|
|
110
|
+
*
|
|
111
|
+
* @param blobStorage - Blob storage instance
|
|
112
|
+
* @param hash - Tree hash
|
|
113
|
+
* @returns Tree object
|
|
114
|
+
*/
|
|
115
|
+
static read(blobStorage: BlobStorage, hash: string): Promise<TreeObject>;
|
|
116
|
+
/**
|
|
117
|
+
* Get specific entry from tree
|
|
118
|
+
*
|
|
119
|
+
* @param tree - Tree object
|
|
120
|
+
* @param name - Entry name
|
|
121
|
+
* @returns Tree entry or undefined
|
|
122
|
+
*/
|
|
123
|
+
static getEntry(tree: TreeObject, name: string): TreeEntry | undefined;
|
|
124
|
+
/**
|
|
125
|
+
* Get all blob entries from tree (non-recursive)
|
|
126
|
+
*
|
|
127
|
+
* @param tree - Tree object
|
|
128
|
+
* @returns Array of blob entries
|
|
129
|
+
*/
|
|
130
|
+
static getBlobs(tree: TreeObject): TreeEntry[];
|
|
131
|
+
/**
|
|
132
|
+
* Get all subtree entries from tree (non-recursive)
|
|
133
|
+
*
|
|
134
|
+
* @param tree - Tree object
|
|
135
|
+
* @returns Array of tree entries
|
|
136
|
+
*/
|
|
137
|
+
static getSubtrees(tree: TreeObject): TreeEntry[];
|
|
138
|
+
/**
|
|
139
|
+
* Walk tree recursively, yielding all blob entries
|
|
140
|
+
*
|
|
141
|
+
* @param blobStorage - Blob storage instance
|
|
142
|
+
* @param tree - Tree object
|
|
143
|
+
*/
|
|
144
|
+
static walk(blobStorage: BlobStorage, tree: TreeObject): AsyncIterableIterator<TreeEntry>;
|
|
145
|
+
/**
|
|
146
|
+
* Compute total size of tree (recursive)
|
|
147
|
+
*
|
|
148
|
+
* @param blobStorage - Blob storage instance
|
|
149
|
+
* @param tree - Tree object
|
|
150
|
+
* @returns Total size in bytes
|
|
151
|
+
*/
|
|
152
|
+
static getTotalSize(blobStorage: BlobStorage, tree: TreeObject): Promise<number>;
|
|
153
|
+
/**
|
|
154
|
+
* Create a new tree by updating a single entry
|
|
155
|
+
* (Copy-on-write: creates new tree, doesn't modify original)
|
|
156
|
+
*
|
|
157
|
+
* @param blobStorage - Blob storage instance
|
|
158
|
+
* @param tree - Original tree
|
|
159
|
+
* @param name - Entry name to update
|
|
160
|
+
* @param hash - New blob/tree hash
|
|
161
|
+
* @param size - New size
|
|
162
|
+
* @returns New tree hash
|
|
163
|
+
*/
|
|
164
|
+
static updateEntry(blobStorage: BlobStorage, tree: TreeObject, name: string, hash: string, size: number): Promise<string>;
|
|
165
|
+
/**
|
|
166
|
+
* Diff two trees, return changed/added/deleted entries
|
|
167
|
+
*
|
|
168
|
+
* @param tree1 - First tree (base)
|
|
169
|
+
* @param tree2 - Second tree (comparison)
|
|
170
|
+
* @returns Diff result
|
|
171
|
+
*/
|
|
172
|
+
static diff(tree1: TreeObject, tree2: TreeObject): {
|
|
173
|
+
added: TreeEntry[];
|
|
174
|
+
modified: TreeEntry[];
|
|
175
|
+
deleted: TreeEntry[];
|
|
176
|
+
};
|
|
177
|
+
}
|