feat: add persistent storage support for OPFS

Introduced an optional `requestPersistentStorage` flag to enable persistent storage permission requests in the browser. Updated `OPFSStorage` to include methods for requesting and checking persistent storage status, and modified `createStorage` to handle the new flag.
This commit is contained in:
David Snelling 2025-05-28 11:37:28 -07:00
parent 5f4e6ccc70
commit ac5955a922
2 changed files with 74 additions and 2 deletions

View file

@ -29,6 +29,12 @@ export interface BrainyDataConfig {
* Embedding function to convert data to vectors
*/
embeddingFunction?: EmbeddingFunction
/**
* Request persistent storage when running in a browser
* This will prompt the user for permission to use persistent storage
*/
requestPersistentStorage?: boolean
}
export class BrainyData<T = any> {
@ -36,6 +42,7 @@ export class BrainyData<T = any> {
private storage: StorageAdapter | null = null
private isInitialized = false
private embeddingFunction: EmbeddingFunction
private requestPersistentStorage: boolean
/**
* Create a new vector database
@ -52,6 +59,9 @@ export class BrainyData<T = any> {
// Set embedding function if provided, otherwise use default
this.embeddingFunction = config.embeddingFunction || defaultEmbeddingFunction
// Set persistent storage request flag
this.requestPersistentStorage = config.requestPersistentStorage || false
}
/**
@ -66,7 +76,9 @@ export class BrainyData<T = any> {
try {
// Initialize storage if not provided in constructor
if (!this.storage) {
this.storage = await createStorage()
this.storage = await createStorage({
requestPersistentStorage: this.requestPersistentStorage
})
}
// Initialize storage

View file

@ -19,6 +19,8 @@ export class OPFSStorage implements StorageAdapter {
private metadataDir: FileSystemDirectoryHandle | null = null
private isInitialized = false
private isAvailable = false
private isPersistentRequested = false
private isPersistentGranted = false
constructor() {
// Check if OPFS is available
@ -78,6 +80,51 @@ export class OPFSStorage implements StorageAdapter {
return this.isAvailable
}
/**
* Request persistent storage permission from the user
* @returns Promise that resolves to true if permission was granted, false otherwise
*/
public async requestPersistentStorage(): Promise<boolean> {
if (!this.isAvailable) {
console.warn('Cannot request persistent storage: OPFS is not available')
return false
}
try {
// Check if persistence is already granted
this.isPersistentGranted = await navigator.storage.persisted()
if (!this.isPersistentGranted) {
// Request permission for persistent storage
this.isPersistentGranted = await navigator.storage.persist()
}
this.isPersistentRequested = true
return this.isPersistentGranted
} catch (error) {
console.warn('Failed to request persistent storage:', error)
return false
}
}
/**
* Check if persistent storage is granted
* @returns Promise that resolves to true if persistent storage is granted, false otherwise
*/
public async isPersistent(): Promise<boolean> {
if (!this.isAvailable) {
return false
}
try {
this.isPersistentGranted = await navigator.storage.persisted()
return this.isPersistentGranted
} catch (error) {
console.warn('Failed to check persistent storage status:', error)
return false
}
}
/**
* Save a node to storage
*/
@ -650,8 +697,12 @@ export class MemoryStorage implements StorageAdapter {
/**
* Factory function to create the appropriate storage adapter based on the environment
* @param options Configuration options for storage
* @returns Promise that resolves to a StorageAdapter instance
*/
export async function createStorage(): Promise<StorageAdapter> {
export async function createStorage(options: {
requestPersistentStorage?: boolean
} = {}): Promise<StorageAdapter> {
// Check if we're in a Node.js environment
const isNode = typeof process !== 'undefined' &&
process.versions != null &&
@ -671,6 +722,15 @@ export async function createStorage(): Promise<StorageAdapter> {
const opfsStorage = new OPFSStorage()
if (opfsStorage.isOPFSAvailable()) {
// Request persistent storage if specified
if (options.requestPersistentStorage) {
const isPersistentGranted = await opfsStorage.requestPersistentStorage()
if (isPersistentGranted) {
console.log('Persistent storage permission granted')
} else {
console.warn('Persistent storage permission denied')
}
}
return opfsStorage
} else {
console.warn('OPFS is not available, falling back to in-memory storage')