mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-17 01:04:36 +00:00
Storage Architecture:
- New pluggable storage system with backends (LocalStorage, ChromeStorage, IndexedDB)
- SettingsRepository for app settings (proxy config, etc.)
- ProviderKeysRepository for API key management
- AppStorage with global accessors (getAppStorage, setAppStorage, initAppStorage)
Transport Refactoring:
- Renamed DirectTransport → ProviderTransport (calls LLM providers with optional CORS proxy)
- Renamed ProxyTransport → AppTransport (uses app server with user auth)
- Updated TransportMode: "direct" → "provider", "proxy" → "app"
CORS Proxy Integration:
- ProviderTransport checks proxy.enabled/proxy.url from storage
- When enabled, modifies model baseUrl to route through proxy: {proxyUrl}/?url={originalBaseUrl}
- ProviderKeyInput test function also honors proxy settings
- Settings dialog with Proxy tab (Switch toggle, URL input, explanatory description)
Anthropic Prompt Caching:
- System prompt cached with cache_control markers (both OAuth and regular API keys)
- Last user message cached to cache conversation history
- Saves 90% on input tokens for cached content (10x cost reduction)
Settings Dialog Improvements:
- Configurable tab system with SettingsTab base class
- ApiKeysTab and ProxyTab as custom elements
- Switch toggle for proxy enable (instead of Checkbox)
- Explanatory paragraphs for each tab
- ApiKeyPromptDialog reuses ProviderKeyInput component
Removed:
- Deprecated ApiKeysDialog (replaced by ProviderKeyInput in SettingsDialog)
- Old storage-adapter and key-store (replaced by new storage architecture)
82 lines
2.2 KiB
TypeScript
82 lines
2.2 KiB
TypeScript
import type { StorageBackend } from "../types.js";
|
|
|
|
// Chrome extension API types (optional)
|
|
declare const chrome: any;
|
|
|
|
/**
|
|
* Storage backend using chrome.storage.local.
|
|
* Good for: Browser extensions, syncing across devices (with chrome.storage.sync).
|
|
* Limits: ~10MB for local, ~100KB for sync, async API.
|
|
*/
|
|
export class ChromeStorageBackend implements StorageBackend {
|
|
constructor(private prefix: string = "") {}
|
|
|
|
private getKey(key: string): string {
|
|
return this.prefix ? `${this.prefix}:${key}` : key;
|
|
}
|
|
|
|
async get<T = unknown>(key: string): Promise<T | null> {
|
|
if (!chrome?.storage?.local) {
|
|
throw new Error("chrome.storage.local is not available");
|
|
}
|
|
|
|
const fullKey = this.getKey(key);
|
|
const result = await chrome.storage.local.get([fullKey]);
|
|
return result[fullKey] !== undefined ? (result[fullKey] as T) : null;
|
|
}
|
|
|
|
async set<T = unknown>(key: string, value: T): Promise<void> {
|
|
if (!chrome?.storage?.local) {
|
|
throw new Error("chrome.storage.local is not available");
|
|
}
|
|
|
|
const fullKey = this.getKey(key);
|
|
await chrome.storage.local.set({ [fullKey]: value });
|
|
}
|
|
|
|
async delete(key: string): Promise<void> {
|
|
if (!chrome?.storage?.local) {
|
|
throw new Error("chrome.storage.local is not available");
|
|
}
|
|
|
|
const fullKey = this.getKey(key);
|
|
await chrome.storage.local.remove(fullKey);
|
|
}
|
|
|
|
async keys(): Promise<string[]> {
|
|
if (!chrome?.storage?.local) {
|
|
throw new Error("chrome.storage.local is not available");
|
|
}
|
|
|
|
const allData = await chrome.storage.local.get(null);
|
|
const allKeys = Object.keys(allData);
|
|
const prefixWithColon = this.prefix ? `${this.prefix}:` : "";
|
|
|
|
if (this.prefix) {
|
|
return allKeys
|
|
.filter((key) => key.startsWith(prefixWithColon))
|
|
.map((key) => key.substring(prefixWithColon.length));
|
|
}
|
|
|
|
return allKeys;
|
|
}
|
|
|
|
async clear(): Promise<void> {
|
|
if (!chrome?.storage?.local) {
|
|
throw new Error("chrome.storage.local is not available");
|
|
}
|
|
|
|
if (this.prefix) {
|
|
const keysToRemove = await this.keys();
|
|
const fullKeys = keysToRemove.map((key) => this.getKey(key));
|
|
await chrome.storage.local.remove(fullKeys);
|
|
} else {
|
|
await chrome.storage.local.clear();
|
|
}
|
|
}
|
|
|
|
async has(key: string): Promise<boolean> {
|
|
const value = await this.get(key);
|
|
return value !== null;
|
|
}
|
|
}
|