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:
parent
5f4e6ccc70
commit
ac5955a922
2 changed files with 74 additions and 2 deletions
|
|
@ -29,6 +29,12 @@ export interface BrainyDataConfig {
|
||||||
* Embedding function to convert data to vectors
|
* Embedding function to convert data to vectors
|
||||||
*/
|
*/
|
||||||
embeddingFunction?: EmbeddingFunction
|
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> {
|
export class BrainyData<T = any> {
|
||||||
|
|
@ -36,6 +42,7 @@ export class BrainyData<T = any> {
|
||||||
private storage: StorageAdapter | null = null
|
private storage: StorageAdapter | null = null
|
||||||
private isInitialized = false
|
private isInitialized = false
|
||||||
private embeddingFunction: EmbeddingFunction
|
private embeddingFunction: EmbeddingFunction
|
||||||
|
private requestPersistentStorage: boolean
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new vector database
|
* Create a new vector database
|
||||||
|
|
@ -52,6 +59,9 @@ export class BrainyData<T = any> {
|
||||||
|
|
||||||
// Set embedding function if provided, otherwise use default
|
// Set embedding function if provided, otherwise use default
|
||||||
this.embeddingFunction = config.embeddingFunction || defaultEmbeddingFunction
|
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 {
|
try {
|
||||||
// Initialize storage if not provided in constructor
|
// Initialize storage if not provided in constructor
|
||||||
if (!this.storage) {
|
if (!this.storage) {
|
||||||
this.storage = await createStorage()
|
this.storage = await createStorage({
|
||||||
|
requestPersistentStorage: this.requestPersistentStorage
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize storage
|
// Initialize storage
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,8 @@ export class OPFSStorage implements StorageAdapter {
|
||||||
private metadataDir: FileSystemDirectoryHandle | null = null
|
private metadataDir: FileSystemDirectoryHandle | null = null
|
||||||
private isInitialized = false
|
private isInitialized = false
|
||||||
private isAvailable = false
|
private isAvailable = false
|
||||||
|
private isPersistentRequested = false
|
||||||
|
private isPersistentGranted = false
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
// Check if OPFS is available
|
// Check if OPFS is available
|
||||||
|
|
@ -78,6 +80,51 @@ export class OPFSStorage implements StorageAdapter {
|
||||||
return this.isAvailable
|
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
|
* 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
|
* 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
|
// Check if we're in a Node.js environment
|
||||||
const isNode = typeof process !== 'undefined' &&
|
const isNode = typeof process !== 'undefined' &&
|
||||||
process.versions != null &&
|
process.versions != null &&
|
||||||
|
|
@ -671,6 +722,15 @@ export async function createStorage(): Promise<StorageAdapter> {
|
||||||
const opfsStorage = new OPFSStorage()
|
const opfsStorage = new OPFSStorage()
|
||||||
|
|
||||||
if (opfsStorage.isOPFSAvailable()) {
|
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
|
return opfsStorage
|
||||||
} else {
|
} else {
|
||||||
console.warn('OPFS is not available, falling back to in-memory storage')
|
console.warn('OPFS is not available, falling back to in-memory storage')
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue