Custom Storage ​
Learn how to create custom storage adapters for Flowfull Clients.
Storage Adapter Interface ​
All storage adapters must implement the StorageAdapter interface:
typescript
interface StorageAdapter {
getItem(key: string): Promise<string | null>;
setItem(key: string, value: string): Promise<void>;
removeItem(key: string): Promise<void>;
clear(): Promise<void>;
}Creating a Custom Adapter ​
Example: IndexedDB Adapter ​
typescript
// storage/IndexedDBAdapter.ts
import { StorageAdapter } from '@pubflow/core';
export class IndexedDBAdapter implements StorageAdapter {
private dbName: string;
private storeName: string;
private db: IDBDatabase | null = null;
constructor(dbName: string = 'pubflow', storeName: string = 'storage') {
this.dbName = dbName;
this.storeName = storeName;
}
private async getDB(): Promise<IDBDatabase> {
if (this.db) return this.db;
return new Promise((resolve, reject) => {
const request = indexedDB.open(this.dbName, 1);
request.onerror = () => reject(request.error);
request.onsuccess = () => {
this.db = request.result;
resolve(this.db);
};
request.onupgradeneeded = (event) => {
const db = (event.target as IDBOpenDBRequest).result;
if (!db.objectStoreNames.contains(this.storeName)) {
db.createObjectStore(this.storeName);
}
};
});
}
async getItem(key: string): Promise<string | null> {
const db = await this.getDB();
return new Promise((resolve, reject) => {
const transaction = db.transaction([this.storeName], 'readonly');
const store = transaction.objectStore(this.storeName);
const request = store.get(key);
request.onerror = () => reject(request.error);
request.onsuccess = () => resolve(request.result || null);
});
}
async setItem(key: string, value: string): Promise<void> {
const db = await this.getDB();
return new Promise((resolve, reject) => {
const transaction = db.transaction([this.storeName], 'readwrite');
const store = transaction.objectStore(this.storeName);
const request = store.put(value, key);
request.onerror = () => reject(request.error);
request.onsuccess = () => resolve();
});
}
async removeItem(key: string): Promise<void> {
const db = await this.getDB();
return new Promise((resolve, reject) => {
const transaction = db.transaction([this.storeName], 'readwrite');
const store = transaction.objectStore(this.storeName);
const request = store.delete(key);
request.onerror = () => reject(request.error);
request.onsuccess = () => resolve();
});
}
async clear(): Promise<void> {
const db = await this.getDB();
return new Promise((resolve, reject) => {
const transaction = db.transaction([this.storeName], 'readwrite');
const store = transaction.objectStore(this.storeName);
const request = store.clear();
request.onerror = () => reject(request.error);
request.onsuccess = () => resolve();
});
}
}Example: Redis Adapter (Node.js) ​
typescript
// storage/RedisAdapter.ts
import { StorageAdapter } from '@pubflow/core';
import Redis from 'ioredis';
export class RedisAdapter implements StorageAdapter {
private client: Redis;
private prefix: string;
constructor(redisUrl: string, prefix: string = 'pubflow:') {
this.client = new Redis(redisUrl);
this.prefix = prefix;
}
private getKey(key: string): string {
return `${this.prefix}${key}`;
}
async getItem(key: string): Promise<string | null> {
return await this.client.get(this.getKey(key));
}
async setItem(key: string, value: string): Promise<void> {
await this.client.set(this.getKey(key), value);
}
async removeItem(key: string): Promise<void> {
await this.client.del(this.getKey(key));
}
async clear(): Promise<void> {
const keys = await this.client.keys(`${this.prefix}*`);
if (keys.length > 0) {
await this.client.del(...keys);
}
}
async disconnect(): Promise<void> {
await this.client.quit();
}
}Using Custom Storage ​
With PubflowProvider ​
typescript
import { PubflowProvider } from '@pubflow/react';
import { IndexedDBAdapter } from './storage/IndexedDBAdapter';
const storage = new IndexedDBAdapter('myapp', 'storage');
function App() {
return (
<PubflowProvider
config={{
baseUrl: 'https://api.example.com',
storageConfig: {
adapter: storage
}
}}
>
<YourApp />
</PubflowProvider>
);
}With Core Services ​
typescript
import { ApiClient, AuthService } from '@pubflow/core';
import { RedisAdapter } from './storage/RedisAdapter';
const storage = new RedisAdapter('redis://localhost:6379');
const apiClient = new ApiClient({
baseUrl: 'https://api.example.com',
storage
});
const authService = new AuthService({
baseUrl: 'https://api.example.com',
storage
});Best Practices ​
- Error Handling: Always handle errors gracefully
- Async Operations: All methods should be async
- Key Prefixing: Use prefixes to avoid key collisions
- Cleanup: Implement proper cleanup methods
- Testing: Test all storage operations thoroughly
Next Steps ​
- Multi-Instance - Multi-instance configuration
- Performance - Performance optimization