@soulcraft/brainy 0.24.0 → 0.26.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 (107) hide show
  1. package/README.md +22 -16
  2. package/dist/brainy.js +4553 -2264
  3. package/dist/brainy.min.js +750 -750
  4. package/dist/brainyData.d.ts +141 -0
  5. package/dist/coreTypes.d.ts +31 -0
  6. package/dist/errors/brainyError.d.ts +45 -0
  7. package/dist/hnsw/hnswIndexOptimized.d.ts +13 -1
  8. package/dist/hnsw/hnswIndexOptimized.d.ts.map +1 -1
  9. package/dist/statistics/statisticsManager.d.ts +121 -0
  10. package/dist/storage/adapters/fileSystemStorage.d.ts +99 -30
  11. package/dist/storage/adapters/fileSystemStorage.d.ts.map +1 -1
  12. package/dist/storage/adapters/memoryStorage.d.ts.map +1 -1
  13. package/dist/storage/adapters/opfsStorage.d.ts +21 -1
  14. package/dist/storage/adapters/opfsStorage.d.ts.map +1 -1
  15. package/dist/storage/adapters/s3CompatibleStorage.d.ts +58 -1
  16. package/dist/storage/adapters/s3CompatibleStorage.d.ts.map +1 -1
  17. package/dist/storage/fileSystemStorage.d.ts +2 -15
  18. package/dist/storage/fileSystemStorage.d.ts.map +1 -1
  19. package/dist/storage/opfsStorage.d.ts +3 -66
  20. package/dist/storage/opfsStorage.d.ts.map +1 -1
  21. package/dist/storage/s3CompatibleStorage.d.ts +2 -14
  22. package/dist/storage/s3CompatibleStorage.d.ts.map +1 -1
  23. package/dist/storage/storageFactory.d.ts +6 -1
  24. package/dist/storage/storageFactory.d.ts.map +1 -1
  25. package/dist/testing/prettyReporter.d.ts +23 -0
  26. package/dist/testing/prettySummaryReporter.d.ts +22 -0
  27. package/dist/types/tensorflowTypes.d.ts +0 -8
  28. package/dist/types/tensorflowTypes.d.ts.map +1 -1
  29. package/dist/unified.d.ts +4 -0
  30. package/dist/unified.js +3170 -1464
  31. package/dist/unified.min.js +750 -750
  32. package/dist/utils/embedding.d.ts +7 -0
  33. package/dist/utils/embedding.d.ts.map +1 -1
  34. package/dist/utils/environmentDetection.d.ts +47 -0
  35. package/dist/utils/environmentDetection.d.ts.map +1 -0
  36. package/dist/utils/logger.d.ts +99 -0
  37. package/dist/utils/logger.d.ts.map +1 -0
  38. package/dist/utils/operationUtils.d.ts +58 -0
  39. package/dist/utils/operationUtils.d.ts.map +1 -0
  40. package/dist/utils/textEncoding.d.ts +0 -7
  41. package/dist/utils/textEncoding.d.ts.map +1 -1
  42. package/dist/utils/version.d.ts +1 -1
  43. package/package.json +14 -3
  44. package/dist/augmentations/conduitAugmentations.js +0 -1158
  45. package/dist/augmentations/conduitAugmentations.js.map +0 -1
  46. package/dist/augmentations/memoryAugmentations.js +0 -255
  47. package/dist/augmentations/memoryAugmentations.js.map +0 -1
  48. package/dist/augmentations/serverSearchAugmentations.js +0 -531
  49. package/dist/augmentations/serverSearchAugmentations.js.map +0 -1
  50. package/dist/examples/basicUsage.js +0 -128
  51. package/dist/examples/basicUsage.js.map +0 -1
  52. package/dist/hnsw/hnswIndex.js +0 -550
  53. package/dist/hnsw/hnswIndex.js.map +0 -1
  54. package/dist/hnsw/hnswIndexOptimized.js +0 -441
  55. package/dist/hnsw/hnswIndexOptimized.js.map +0 -1
  56. package/dist/mcp/brainyMCPAdapter.js +0 -142
  57. package/dist/mcp/brainyMCPAdapter.js.map +0 -1
  58. package/dist/mcp/brainyMCPService.js +0 -248
  59. package/dist/mcp/brainyMCPService.js.map +0 -1
  60. package/dist/mcp/index.js +0 -17
  61. package/dist/mcp/index.js.map +0 -1
  62. package/dist/mcp/mcpAugmentationToolset.js +0 -180
  63. package/dist/mcp/mcpAugmentationToolset.js.map +0 -1
  64. package/dist/storage/adapters/baseStorageAdapter.js +0 -233
  65. package/dist/storage/adapters/baseStorageAdapter.js.map +0 -1
  66. package/dist/storage/adapters/fileSystemStorage.js +0 -568
  67. package/dist/storage/adapters/fileSystemStorage.js.map +0 -1
  68. package/dist/storage/adapters/memoryStorage.js +0 -300
  69. package/dist/storage/adapters/memoryStorage.js.map +0 -1
  70. package/dist/storage/adapters/opfsStorage.js +0 -778
  71. package/dist/storage/adapters/opfsStorage.js.map +0 -1
  72. package/dist/storage/adapters/s3CompatibleStorage.js +0 -1021
  73. package/dist/storage/adapters/s3CompatibleStorage.js.map +0 -1
  74. package/dist/storage/baseStorage.js +0 -126
  75. package/dist/storage/baseStorage.js.map +0 -1
  76. package/dist/storage/storageFactory.js +0 -183
  77. package/dist/storage/storageFactory.js.map +0 -1
  78. package/dist/types/augmentations.js +0 -16
  79. package/dist/types/augmentations.js.map +0 -1
  80. package/dist/types/brainyDataInterface.js +0 -8
  81. package/dist/types/brainyDataInterface.js.map +0 -1
  82. package/dist/types/fileSystemTypes.js +0 -8
  83. package/dist/types/fileSystemTypes.js.map +0 -1
  84. package/dist/types/graphTypes.js +0 -36
  85. package/dist/types/graphTypes.js.map +0 -1
  86. package/dist/types/mcpTypes.js +0 -22
  87. package/dist/types/mcpTypes.js.map +0 -1
  88. package/dist/types/pipelineTypes.js +0 -7
  89. package/dist/types/pipelineTypes.js.map +0 -1
  90. package/dist/types/tensorflowTypes.js +0 -6
  91. package/dist/types/tensorflowTypes.js.map +0 -1
  92. package/dist/utils/distance.js +0 -239
  93. package/dist/utils/distance.js.map +0 -1
  94. package/dist/utils/embedding.js +0 -622
  95. package/dist/utils/embedding.js.map +0 -1
  96. package/dist/utils/environment.js +0 -75
  97. package/dist/utils/environment.js.map +0 -1
  98. package/dist/utils/index.js +0 -5
  99. package/dist/utils/index.js.map +0 -1
  100. package/dist/utils/statistics.js +0 -25
  101. package/dist/utils/statistics.js.map +0 -1
  102. package/dist/utils/tensorflowUtils.js +0 -25
  103. package/dist/utils/tensorflowUtils.js.map +0 -1
  104. package/dist/utils/textEncoding.js +0 -281
  105. package/dist/utils/textEncoding.js.map +0 -1
  106. package/dist/utils/workerUtils.js +0 -458
  107. package/dist/utils/workerUtils.js.map +0 -1
@@ -1,778 +0,0 @@
1
- /**
2
- * OPFS (Origin Private File System) Storage Adapter
3
- * Provides persistent storage for the vector database using the Origin Private File System API
4
- */
5
- import { BaseStorage, NOUNS_DIR, VERBS_DIR, METADATA_DIR, INDEX_DIR } from '../baseStorage.js';
6
- import '../../types/fileSystemTypes.js';
7
- /**
8
- * Helper function to safely get a file from a FileSystemHandle
9
- * This is needed because TypeScript doesn't recognize that a FileSystemHandle
10
- * can be a FileSystemFileHandle which has the getFile method
11
- */
12
- async function safeGetFile(handle) {
13
- // Type cast to any to avoid TypeScript error
14
- return handle.getFile();
15
- }
16
- // Root directory name for OPFS storage
17
- const ROOT_DIR = 'opfs-vector-db';
18
- /**
19
- * OPFS storage adapter for browser environments
20
- * Uses the Origin Private File System API to store data persistently
21
- */
22
- export class OPFSStorage extends BaseStorage {
23
- constructor() {
24
- super();
25
- this.rootDir = null;
26
- this.nounsDir = null;
27
- this.verbsDir = null;
28
- this.metadataDir = null;
29
- this.indexDir = null;
30
- this.isAvailable = false;
31
- this.isPersistentRequested = false;
32
- this.isPersistentGranted = false;
33
- this.statistics = null;
34
- // Check if OPFS is available
35
- this.isAvailable =
36
- typeof navigator !== 'undefined' &&
37
- 'storage' in navigator &&
38
- 'getDirectory' in navigator.storage;
39
- }
40
- /**
41
- * Initialize the storage adapter
42
- */
43
- async init() {
44
- if (this.isInitialized) {
45
- return;
46
- }
47
- if (!this.isAvailable) {
48
- throw new Error('Origin Private File System is not available in this environment');
49
- }
50
- try {
51
- // Get the root directory
52
- const root = await navigator.storage.getDirectory();
53
- // Create or get our app's root directory
54
- this.rootDir = await root.getDirectoryHandle(ROOT_DIR, { create: true });
55
- // Create or get nouns directory
56
- this.nounsDir = await this.rootDir.getDirectoryHandle(NOUNS_DIR, {
57
- create: true
58
- });
59
- // Create or get verbs directory
60
- this.verbsDir = await this.rootDir.getDirectoryHandle(VERBS_DIR, {
61
- create: true
62
- });
63
- // Create or get metadata directory
64
- this.metadataDir = await this.rootDir.getDirectoryHandle(METADATA_DIR, {
65
- create: true
66
- });
67
- // Create or get index directory
68
- this.indexDir = await this.rootDir.getDirectoryHandle(INDEX_DIR, {
69
- create: true
70
- });
71
- this.isInitialized = true;
72
- }
73
- catch (error) {
74
- console.error('Failed to initialize OPFS storage:', error);
75
- throw new Error(`Failed to initialize OPFS storage: ${error}`);
76
- }
77
- }
78
- /**
79
- * Check if OPFS is available in the current environment
80
- */
81
- isOPFSAvailable() {
82
- return this.isAvailable;
83
- }
84
- /**
85
- * Request persistent storage permission from the user
86
- * @returns Promise that resolves to true if permission was granted, false otherwise
87
- */
88
- async requestPersistentStorage() {
89
- if (!this.isAvailable) {
90
- console.warn('Cannot request persistent storage: OPFS is not available');
91
- return false;
92
- }
93
- try {
94
- // Check if persistence is already granted
95
- this.isPersistentGranted = await navigator.storage.persisted();
96
- if (!this.isPersistentGranted) {
97
- // Request permission for persistent storage
98
- this.isPersistentGranted = await navigator.storage.persist();
99
- }
100
- this.isPersistentRequested = true;
101
- return this.isPersistentGranted;
102
- }
103
- catch (error) {
104
- console.warn('Failed to request persistent storage:', error);
105
- return false;
106
- }
107
- }
108
- /**
109
- * Check if persistent storage is granted
110
- * @returns Promise that resolves to true if persistent storage is granted, false otherwise
111
- */
112
- async isPersistent() {
113
- if (!this.isAvailable) {
114
- return false;
115
- }
116
- try {
117
- this.isPersistentGranted = await navigator.storage.persisted();
118
- return this.isPersistentGranted;
119
- }
120
- catch (error) {
121
- console.warn('Failed to check persistent storage status:', error);
122
- return false;
123
- }
124
- }
125
- /**
126
- * Save a node to storage
127
- */
128
- async saveNode(node) {
129
- await this.ensureInitialized();
130
- try {
131
- // Convert connections Map to a serializable format
132
- const serializableNode = {
133
- ...node,
134
- connections: this.mapToObject(node.connections, (set) => Array.from(set))
135
- };
136
- // Create or get the file for this noun
137
- const fileHandle = await this.nounsDir.getFileHandle(node.id, {
138
- create: true
139
- });
140
- // Write the noun data to the file
141
- const writable = await fileHandle.createWritable();
142
- await writable.write(JSON.stringify(serializableNode));
143
- await writable.close();
144
- }
145
- catch (error) {
146
- console.error(`Failed to save node ${node.id}:`, error);
147
- throw new Error(`Failed to save node ${node.id}: ${error}`);
148
- }
149
- }
150
- /**
151
- * Get a node from storage
152
- */
153
- async getNode(id) {
154
- await this.ensureInitialized();
155
- try {
156
- // Get the file handle for this node
157
- const fileHandle = await this.nounsDir.getFileHandle(id);
158
- // Read the node data from the file
159
- const file = await fileHandle.getFile();
160
- const text = await file.text();
161
- const data = JSON.parse(text);
162
- // Convert serialized connections back to Map<number, Set<string>>
163
- const connections = new Map();
164
- for (const [level, nodeIds] of Object.entries(data.connections)) {
165
- connections.set(Number(level), new Set(nodeIds));
166
- }
167
- return {
168
- id: data.id,
169
- vector: data.vector,
170
- connections
171
- };
172
- }
173
- catch (error) {
174
- // Node not found or other error
175
- return null;
176
- }
177
- }
178
- /**
179
- * Get all nodes from storage
180
- */
181
- async getAllNodes() {
182
- await this.ensureInitialized();
183
- const allNodes = [];
184
- try {
185
- // Iterate through all files in the nouns directory
186
- for await (const [name, handle] of this.nounsDir.entries()) {
187
- if (handle.kind === 'file') {
188
- try {
189
- // Read the node data from the file
190
- const file = await safeGetFile(handle);
191
- const text = await file.text();
192
- const data = JSON.parse(text);
193
- // Convert serialized connections back to Map<number, Set<string>>
194
- const connections = new Map();
195
- for (const [level, nodeIds] of Object.entries(data.connections)) {
196
- connections.set(Number(level), new Set(nodeIds));
197
- }
198
- allNodes.push({
199
- id: data.id,
200
- vector: data.vector,
201
- connections
202
- });
203
- }
204
- catch (error) {
205
- console.error(`Error reading node file ${name}:`, error);
206
- }
207
- }
208
- }
209
- }
210
- catch (error) {
211
- console.error('Error reading nouns directory:', error);
212
- }
213
- return allNodes;
214
- }
215
- /**
216
- * Get nodes by noun type
217
- * @param nounType The noun type to filter by
218
- * @returns Promise that resolves to an array of nodes of the specified noun type
219
- */
220
- async getNodesByNounType(nounType) {
221
- await this.ensureInitialized();
222
- const nodes = [];
223
- try {
224
- // Iterate through all files in the nouns directory
225
- for await (const [name, handle] of this.nounsDir.entries()) {
226
- if (handle.kind === 'file') {
227
- try {
228
- // Read the node data from the file
229
- const file = await safeGetFile(handle);
230
- const text = await file.text();
231
- const data = JSON.parse(text);
232
- // Get the metadata to check the noun type
233
- const metadata = await this.getMetadata(data.id);
234
- // Include the node if its noun type matches the requested type
235
- if (metadata && metadata.noun === nounType) {
236
- // Convert serialized connections back to Map<number, Set<string>>
237
- const connections = new Map();
238
- for (const [level, nodeIds] of Object.entries(data.connections)) {
239
- connections.set(Number(level), new Set(nodeIds));
240
- }
241
- nodes.push({
242
- id: data.id,
243
- vector: data.vector,
244
- connections
245
- });
246
- }
247
- }
248
- catch (error) {
249
- console.error(`Error reading node file ${name}:`, error);
250
- }
251
- }
252
- }
253
- }
254
- catch (error) {
255
- console.error('Error reading nouns directory:', error);
256
- }
257
- return nodes;
258
- }
259
- /**
260
- * Delete a node from storage
261
- */
262
- async deleteNode(id) {
263
- await this.ensureInitialized();
264
- try {
265
- await this.nounsDir.removeEntry(id);
266
- }
267
- catch (error) {
268
- // Ignore NotFoundError, which means the file doesn't exist
269
- if (error.name !== 'NotFoundError') {
270
- console.error(`Error deleting node ${id}:`, error);
271
- throw error;
272
- }
273
- }
274
- }
275
- /**
276
- * Save an edge to storage
277
- */
278
- async saveEdge(edge) {
279
- await this.ensureInitialized();
280
- try {
281
- // Convert connections Map to a serializable format
282
- const serializableEdge = {
283
- ...edge,
284
- connections: this.mapToObject(edge.connections, (set) => Array.from(set))
285
- };
286
- // Create or get the file for this verb
287
- const fileHandle = await this.verbsDir.getFileHandle(edge.id, {
288
- create: true
289
- });
290
- // Write the verb data to the file
291
- const writable = await fileHandle.createWritable();
292
- await writable.write(JSON.stringify(serializableEdge));
293
- await writable.close();
294
- }
295
- catch (error) {
296
- console.error(`Failed to save edge ${edge.id}:`, error);
297
- throw new Error(`Failed to save edge ${edge.id}: ${error}`);
298
- }
299
- }
300
- /**
301
- * Get an edge from storage
302
- */
303
- async getEdge(id) {
304
- await this.ensureInitialized();
305
- try {
306
- // Get the file handle for this edge
307
- const fileHandle = await this.verbsDir.getFileHandle(id);
308
- // Read the edge data from the file
309
- const file = await fileHandle.getFile();
310
- const text = await file.text();
311
- const data = JSON.parse(text);
312
- // Convert serialized connections back to Map<number, Set<string>>
313
- const connections = new Map();
314
- for (const [level, nodeIds] of Object.entries(data.connections)) {
315
- connections.set(Number(level), new Set(nodeIds));
316
- }
317
- return {
318
- id: data.id,
319
- vector: data.vector,
320
- connections,
321
- sourceId: data.sourceId,
322
- targetId: data.targetId,
323
- type: data.type,
324
- weight: data.weight,
325
- metadata: data.metadata
326
- };
327
- }
328
- catch (error) {
329
- // Edge not found or other error
330
- return null;
331
- }
332
- }
333
- /**
334
- * Get all edges from storage
335
- */
336
- async getAllEdges() {
337
- await this.ensureInitialized();
338
- const allEdges = [];
339
- try {
340
- // Iterate through all files in the verbs directory
341
- for await (const [name, handle] of this.verbsDir.entries()) {
342
- if (handle.kind === 'file') {
343
- try {
344
- // Read the edge data from the file
345
- const file = await safeGetFile(handle);
346
- const text = await file.text();
347
- const data = JSON.parse(text);
348
- // Convert serialized connections back to Map<number, Set<string>>
349
- const connections = new Map();
350
- for (const [level, nodeIds] of Object.entries(data.connections)) {
351
- connections.set(Number(level), new Set(nodeIds));
352
- }
353
- allEdges.push({
354
- id: data.id,
355
- vector: data.vector,
356
- connections,
357
- sourceId: data.sourceId,
358
- targetId: data.targetId,
359
- type: data.type,
360
- weight: data.weight,
361
- metadata: data.metadata
362
- });
363
- }
364
- catch (error) {
365
- console.error(`Error reading edge file ${name}:`, error);
366
- }
367
- }
368
- }
369
- }
370
- catch (error) {
371
- console.error('Error reading verbs directory:', error);
372
- }
373
- return allEdges;
374
- }
375
- /**
376
- * Get edges by source
377
- */
378
- async getEdgesBySource(sourceId) {
379
- const edges = await this.getAllEdges();
380
- return edges.filter((edge) => edge.sourceId === sourceId);
381
- }
382
- /**
383
- * Get edges by target
384
- */
385
- async getEdgesByTarget(targetId) {
386
- const edges = await this.getAllEdges();
387
- return edges.filter((edge) => edge.targetId === targetId);
388
- }
389
- /**
390
- * Get edges by type
391
- */
392
- async getEdgesByType(type) {
393
- const edges = await this.getAllEdges();
394
- return edges.filter((edge) => edge.type === type);
395
- }
396
- /**
397
- * Delete an edge from storage
398
- */
399
- async deleteEdge(id) {
400
- await this.ensureInitialized();
401
- try {
402
- await this.verbsDir.removeEntry(id);
403
- }
404
- catch (error) {
405
- // Ignore NotFoundError, which means the file doesn't exist
406
- if (error.name !== 'NotFoundError') {
407
- console.error(`Error deleting edge ${id}:`, error);
408
- throw error;
409
- }
410
- }
411
- }
412
- /**
413
- * Save metadata to storage
414
- */
415
- async saveMetadata(id, metadata) {
416
- await this.ensureInitialized();
417
- try {
418
- // Create or get the file for this metadata
419
- const fileHandle = await this.metadataDir.getFileHandle(id, {
420
- create: true
421
- });
422
- // Write the metadata to the file
423
- const writable = await fileHandle.createWritable();
424
- await writable.write(JSON.stringify(metadata));
425
- await writable.close();
426
- }
427
- catch (error) {
428
- console.error(`Failed to save metadata ${id}:`, error);
429
- throw new Error(`Failed to save metadata ${id}: ${error}`);
430
- }
431
- }
432
- /**
433
- * Get metadata from storage
434
- */
435
- async getMetadata(id) {
436
- await this.ensureInitialized();
437
- try {
438
- // Get the file handle for this metadata
439
- const fileHandle = await this.metadataDir.getFileHandle(id);
440
- // Read the metadata from the file
441
- const file = await fileHandle.getFile();
442
- const text = await file.text();
443
- return JSON.parse(text);
444
- }
445
- catch (error) {
446
- // Metadata not found or other error
447
- return null;
448
- }
449
- }
450
- /**
451
- * Clear all data from storage
452
- */
453
- async clear() {
454
- await this.ensureInitialized();
455
- // Helper function to remove all files in a directory
456
- const removeDirectoryContents = async (dirHandle) => {
457
- try {
458
- for await (const [name, handle] of dirHandle.entries()) {
459
- await dirHandle.removeEntry(name);
460
- }
461
- }
462
- catch (error) {
463
- console.error(`Error removing directory contents:`, error);
464
- throw error;
465
- }
466
- };
467
- try {
468
- // Remove all files in the nouns directory
469
- await removeDirectoryContents(this.nounsDir);
470
- // Remove all files in the verbs directory
471
- await removeDirectoryContents(this.verbsDir);
472
- // Remove all files in the metadata directory
473
- await removeDirectoryContents(this.metadataDir);
474
- // Remove all files in the index directory
475
- await removeDirectoryContents(this.indexDir);
476
- }
477
- catch (error) {
478
- console.error('Error clearing storage:', error);
479
- throw error;
480
- }
481
- }
482
- /**
483
- * Get information about storage usage and capacity
484
- */
485
- async getStorageStatus() {
486
- await this.ensureInitialized();
487
- try {
488
- // Calculate the total size of all files in the storage directories
489
- let totalSize = 0;
490
- // Helper function to calculate directory size
491
- const calculateDirSize = async (dirHandle) => {
492
- let size = 0;
493
- try {
494
- for await (const [name, handle] of dirHandle.entries()) {
495
- if (handle.kind === 'file') {
496
- const file = await handle.getFile();
497
- size += file.size;
498
- }
499
- else if (handle.kind === 'directory') {
500
- size += await calculateDirSize(handle);
501
- }
502
- }
503
- }
504
- catch (error) {
505
- console.warn(`Error calculating size for directory:`, error);
506
- }
507
- return size;
508
- };
509
- // Helper function to count files in a directory
510
- const countFilesInDirectory = async (dirHandle) => {
511
- let count = 0;
512
- try {
513
- for await (const [name, handle] of dirHandle.entries()) {
514
- if (handle.kind === 'file') {
515
- count++;
516
- }
517
- }
518
- }
519
- catch (error) {
520
- console.warn(`Error counting files in directory:`, error);
521
- }
522
- return count;
523
- };
524
- // Calculate size for each directory
525
- if (this.nounsDir) {
526
- totalSize += await calculateDirSize(this.nounsDir);
527
- }
528
- if (this.verbsDir) {
529
- totalSize += await calculateDirSize(this.verbsDir);
530
- }
531
- if (this.metadataDir) {
532
- totalSize += await calculateDirSize(this.metadataDir);
533
- }
534
- if (this.indexDir) {
535
- totalSize += await calculateDirSize(this.indexDir);
536
- }
537
- // Get storage quota information using the Storage API
538
- let quota = null;
539
- let details = {
540
- isPersistent: await this.isPersistent(),
541
- nounTypes: {}
542
- };
543
- try {
544
- if (navigator.storage && navigator.storage.estimate) {
545
- const estimate = await navigator.storage.estimate();
546
- quota = estimate.quota || null;
547
- details = {
548
- ...details,
549
- usage: estimate.usage,
550
- quota: estimate.quota,
551
- freePercentage: estimate.quota
552
- ? ((estimate.quota - (estimate.usage || 0)) / estimate.quota) *
553
- 100
554
- : null
555
- };
556
- }
557
- }
558
- catch (error) {
559
- console.warn('Unable to get storage estimate:', error);
560
- }
561
- // Count files in each directory
562
- if (this.nounsDir) {
563
- details.nounsCount = await countFilesInDirectory(this.nounsDir);
564
- }
565
- if (this.verbsDir) {
566
- details.verbsCount = await countFilesInDirectory(this.verbsDir);
567
- }
568
- if (this.metadataDir) {
569
- details.metadataCount = await countFilesInDirectory(this.metadataDir);
570
- }
571
- // Count nouns by type using metadata
572
- const nounTypeCounts = {};
573
- if (this.metadataDir) {
574
- for await (const [name, handle] of this.metadataDir.entries()) {
575
- if (handle.kind === 'file') {
576
- try {
577
- const file = await safeGetFile(handle);
578
- const text = await file.text();
579
- const metadata = JSON.parse(text);
580
- if (metadata.noun) {
581
- nounTypeCounts[metadata.noun] = (nounTypeCounts[metadata.noun] || 0) + 1;
582
- }
583
- }
584
- catch (error) {
585
- console.error(`Error reading metadata file ${name}:`, error);
586
- }
587
- }
588
- }
589
- }
590
- details.nounTypes = nounTypeCounts;
591
- return {
592
- type: 'opfs',
593
- used: totalSize,
594
- quota,
595
- details
596
- };
597
- }
598
- catch (error) {
599
- console.error('Failed to get storage status:', error);
600
- return {
601
- type: 'opfs',
602
- used: 0,
603
- quota: null,
604
- details: { error: String(error) }
605
- };
606
- }
607
- }
608
- /**
609
- * Get the statistics key for a specific date
610
- * @param date The date to get the key for
611
- * @returns The statistics key for the specified date
612
- */
613
- getStatisticsKeyForDate(date) {
614
- const year = date.getUTCFullYear();
615
- const month = String(date.getUTCMonth() + 1).padStart(2, '0');
616
- const day = String(date.getUTCDate()).padStart(2, '0');
617
- return `statistics_${year}${month}${day}.json`;
618
- }
619
- /**
620
- * Get the current statistics key
621
- * @returns The current statistics key
622
- */
623
- getCurrentStatisticsKey() {
624
- return this.getStatisticsKeyForDate(new Date());
625
- }
626
- /**
627
- * Get the legacy statistics key (for backward compatibility)
628
- * @returns The legacy statistics key
629
- */
630
- getLegacyStatisticsKey() {
631
- return 'statistics.json';
632
- }
633
- /**
634
- * Save statistics data to storage
635
- * @param statistics The statistics data to save
636
- */
637
- async saveStatisticsData(statistics) {
638
- // Create a deep copy to avoid reference issues
639
- this.statistics = {
640
- nounCount: { ...statistics.nounCount },
641
- verbCount: { ...statistics.verbCount },
642
- metadataCount: { ...statistics.metadataCount },
643
- hnswIndexSize: statistics.hnswIndexSize,
644
- lastUpdated: statistics.lastUpdated
645
- };
646
- try {
647
- // Ensure the root directory is initialized
648
- await this.ensureInitialized();
649
- // Get or create the index directory
650
- if (!this.indexDir) {
651
- throw new Error('Index directory not initialized');
652
- }
653
- // Get the current statistics key
654
- const currentKey = this.getCurrentStatisticsKey();
655
- // Create a file for the statistics data
656
- const fileHandle = await this.indexDir.getFileHandle(currentKey, {
657
- create: true
658
- });
659
- // Create a writable stream
660
- const writable = await fileHandle.createWritable();
661
- // Write the statistics data to the file
662
- await writable.write(JSON.stringify(this.statistics, null, 2));
663
- // Close the stream
664
- await writable.close();
665
- // Also update the legacy key for backward compatibility, but less frequently
666
- if (Math.random() < 0.1) {
667
- const legacyKey = this.getLegacyStatisticsKey();
668
- const legacyFileHandle = await this.indexDir.getFileHandle(legacyKey, {
669
- create: true
670
- });
671
- const legacyWritable = await legacyFileHandle.createWritable();
672
- await legacyWritable.write(JSON.stringify(this.statistics, null, 2));
673
- await legacyWritable.close();
674
- }
675
- }
676
- catch (error) {
677
- console.error('Failed to save statistics data:', error);
678
- throw new Error(`Failed to save statistics data: ${error}`);
679
- }
680
- }
681
- /**
682
- * Get statistics data from storage
683
- * @returns Promise that resolves to the statistics data or null if not found
684
- */
685
- async getStatisticsData() {
686
- // If we have cached statistics, return a deep copy
687
- if (this.statistics) {
688
- return {
689
- nounCount: { ...this.statistics.nounCount },
690
- verbCount: { ...this.statistics.verbCount },
691
- metadataCount: { ...this.statistics.metadataCount },
692
- hnswIndexSize: this.statistics.hnswIndexSize,
693
- lastUpdated: this.statistics.lastUpdated
694
- };
695
- }
696
- try {
697
- // Ensure the root directory is initialized
698
- await this.ensureInitialized();
699
- if (!this.indexDir) {
700
- throw new Error('Index directory not initialized');
701
- }
702
- // First try to get statistics from today's file
703
- const currentKey = this.getCurrentStatisticsKey();
704
- try {
705
- const fileHandle = await this.indexDir.getFileHandle(currentKey, {
706
- create: false
707
- });
708
- const file = await fileHandle.getFile();
709
- const text = await file.text();
710
- this.statistics = JSON.parse(text);
711
- if (this.statistics) {
712
- return {
713
- nounCount: { ...this.statistics.nounCount },
714
- verbCount: { ...this.statistics.verbCount },
715
- metadataCount: { ...this.statistics.metadataCount },
716
- hnswIndexSize: this.statistics.hnswIndexSize,
717
- lastUpdated: this.statistics.lastUpdated
718
- };
719
- }
720
- }
721
- catch (error) {
722
- // If today's file doesn't exist, try yesterday's file
723
- const yesterday = new Date();
724
- yesterday.setDate(yesterday.getDate() - 1);
725
- const yesterdayKey = this.getStatisticsKeyForDate(yesterday);
726
- try {
727
- const fileHandle = await this.indexDir.getFileHandle(yesterdayKey, {
728
- create: false
729
- });
730
- const file = await fileHandle.getFile();
731
- const text = await file.text();
732
- this.statistics = JSON.parse(text);
733
- if (this.statistics) {
734
- return {
735
- nounCount: { ...this.statistics.nounCount },
736
- verbCount: { ...this.statistics.verbCount },
737
- metadataCount: { ...this.statistics.metadataCount },
738
- hnswIndexSize: this.statistics.hnswIndexSize,
739
- lastUpdated: this.statistics.lastUpdated
740
- };
741
- }
742
- }
743
- catch (error) {
744
- // If yesterday's file doesn't exist, try the legacy file
745
- const legacyKey = this.getLegacyStatisticsKey();
746
- try {
747
- const fileHandle = await this.indexDir.getFileHandle(legacyKey, {
748
- create: false
749
- });
750
- const file = await fileHandle.getFile();
751
- const text = await file.text();
752
- this.statistics = JSON.parse(text);
753
- if (this.statistics) {
754
- return {
755
- nounCount: { ...this.statistics.nounCount },
756
- verbCount: { ...this.statistics.verbCount },
757
- metadataCount: { ...this.statistics.metadataCount },
758
- hnswIndexSize: this.statistics.hnswIndexSize,
759
- lastUpdated: this.statistics.lastUpdated
760
- };
761
- }
762
- }
763
- catch (error) {
764
- // If the legacy file doesn't exist either, return null
765
- return null;
766
- }
767
- }
768
- }
769
- // If we get here and statistics is null, return default statistics
770
- return this.statistics ? this.statistics : null;
771
- }
772
- catch (error) {
773
- console.error('Failed to get statistics data:', error);
774
- throw new Error(`Failed to get statistics data: ${error}`);
775
- }
776
- }
777
- }
778
- //# sourceMappingURL=opfsStorage.js.map