@aichatkit/localstorage-adapter
Version:
LocalStorage adapter for Hypermode ChatKit
572 lines (570 loc) • 20.3 kB
JavaScript
;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var index_exports = {};
__export(index_exports, {
LocalStorageAdapter: () => LocalStorageAdapter
});
module.exports = __toCommonJS(index_exports);
var import_storage_adapter = require("@aichatkit/storage-adapter");
var LocalStorageAdapter = class extends import_storage_adapter.StorageAdapter {
constructor(options = {}) {
super();
this.isClient = false;
this.conversationPrefix = options.conversationPrefix || "chatkit_conversation_";
this.conversationIdsKey = options.conversationIdsKey || "chatkit_conversation_ids";
this.activeConversationKey = options.activeConversationKey || "chatkit_active_conversation";
this.agentMappingKey = options.agentMappingKey || "chatkit_agent_mapping";
}
checkClient() {
if (typeof window === "undefined") {
console.warn("[LocalStorageAdapter] Not in browser environment");
return false;
}
if (!window.localStorage) {
console.warn("[LocalStorageAdapter] localStorage not available");
return false;
}
return true;
}
async initialize() {
console.log("[LocalStorageAdapter] Initializing...");
if (typeof window === "undefined") {
console.log("[LocalStorageAdapter] Server-side, skipping initialization");
return;
}
await new Promise((resolve) => setTimeout(resolve, 100));
this.isClient = this.checkClient();
if (!this.isClient) {
throw new Error("localStorage is not available in this environment");
}
try {
const existingIds = localStorage.getItem(this.conversationIdsKey);
if (!existingIds) {
console.log("[LocalStorageAdapter] Initializing conversation IDs");
localStorage.setItem(this.conversationIdsKey, JSON.stringify([]));
}
const existingActive = localStorage.getItem(this.activeConversationKey);
if (!existingActive) {
console.log("[LocalStorageAdapter] Initializing active conversation");
localStorage.setItem(this.activeConversationKey, "");
}
const existingMapping = localStorage.getItem(this.agentMappingKey);
if (!existingMapping) {
console.log("[LocalStorageAdapter] Initializing agent mapping");
localStorage.setItem(this.agentMappingKey, JSON.stringify({}));
}
console.log("[LocalStorageAdapter] Initialized successfully");
} catch (error) {
console.error("[LocalStorageAdapter] Failed to initialize:", error);
throw error;
}
}
getActiveConversationId() {
if (!this.checkClient()) return "";
try {
const active = localStorage.getItem(this.activeConversationKey) || "";
console.log(
`[LocalStorageAdapter] Getting active conversation: ${active}`
);
return active;
} catch (error) {
console.error(
"[LocalStorageAdapter] Failed to get active conversation ID:",
error
);
return "";
}
}
setActiveConversationId(id) {
if (!this.checkClient()) return;
try {
console.log(`[LocalStorageAdapter] Setting active conversation: ${id}`);
localStorage.setItem(this.activeConversationKey, id);
} catch (error) {
console.error(
"[LocalStorageAdapter] Failed to set active conversation ID:",
error
);
}
}
async saveConversation(conversation) {
if (!this.checkClient()) {
throw new Error("localStorage is not available in this environment");
}
try {
const conversationToSave = {
id: conversation.id,
title: conversation.title || "Untitled Conversation",
items: Array.isArray(conversation.items) ? conversation.items : []
};
console.log(
`[LocalStorageAdapter] Saving conversation: ${conversation.id} with ${conversationToSave.items.length} items`
);
const conversationKey = `${this.conversationPrefix}${conversation.id}`;
localStorage.setItem(conversationKey, JSON.stringify(conversationToSave));
const ids = this.getConversationIds();
if (!ids.includes(conversation.id)) {
ids.push(conversation.id);
localStorage.setItem(this.conversationIdsKey, JSON.stringify(ids));
console.log(
`[LocalStorageAdapter] Added conversation ID to list: ${conversation.id}`
);
}
console.log(
`[LocalStorageAdapter] Successfully saved conversation: ${conversation.id}`
);
} catch (error) {
console.error("[LocalStorageAdapter] Failed to save conversation:", error);
throw error;
}
}
async getConversation(id) {
if (!this.checkClient()) {
console.warn(
"[LocalStorageAdapter] Cannot get conversation - not in client environment"
);
return null;
}
if (!id || typeof id !== "string") {
console.warn(
"[LocalStorageAdapter] Invalid conversation ID provided:",
id
);
return null;
}
try {
const conversationKey = `${this.conversationPrefix}${id}`;
const data = localStorage.getItem(conversationKey);
if (!data) {
console.log(`[LocalStorageAdapter] Conversation not found: ${id}`);
return null;
}
const conversation = JSON.parse(data);
const safeConversation = {
id: conversation.id || id,
title: conversation.title || "Untitled Conversation",
items: Array.isArray(conversation.items) ? conversation.items : []
};
console.log(
`[LocalStorageAdapter] Retrieved conversation: ${id} (${safeConversation.items.length} items)`
);
return safeConversation;
} catch (error) {
console.error(
`[LocalStorageAdapter] Failed to retrieve conversation ${id}:`,
error
);
return null;
}
}
async getAllConversations() {
if (!this.checkClient()) {
console.warn(
"[LocalStorageAdapter] Cannot get conversations - not in client environment"
);
return [];
}
try {
const ids = this.getConversationIds();
console.log(
`[LocalStorageAdapter] Getting all conversations for IDs:`,
ids
);
const conversations = [];
for (const id of ids) {
if (!id || typeof id !== "string") {
console.warn(
`[LocalStorageAdapter] Skipping invalid conversation ID:`,
id
);
continue;
}
try {
const conversationKey = `${this.conversationPrefix}${id}`;
const data = localStorage.getItem(conversationKey);
if (data) {
const conversation = JSON.parse(data);
const safeConversation = {
id: conversation.id || id,
title: conversation.title || "Untitled Conversation",
items: Array.isArray(conversation.items) ? conversation.items : []
};
conversations.push(safeConversation);
console.log(
`[LocalStorageAdapter] Loaded conversation: ${id} (${safeConversation.items.length} items)`
);
} else {
console.warn(
`[LocalStorageAdapter] Conversation data not found for ID: ${id}`
);
this.removeConversationId(id);
}
} catch (parseError) {
console.error(
`[LocalStorageAdapter] Failed to parse conversation ${id}:`,
parseError
);
this.removeConversationId(id);
}
}
console.log(
`[LocalStorageAdapter] Retrieved ${conversations.length} conversations`
);
return conversations;
} catch (error) {
console.error(
"[LocalStorageAdapter] Failed to get all conversations:",
error
);
return [];
}
}
async deleteConversation(id) {
if (!this.checkClient()) {
throw new Error("localStorage is not available in this environment");
}
if (!id || typeof id !== "string") {
console.warn(
"[LocalStorageAdapter] Invalid conversation ID for deletion:",
id
);
return false;
}
try {
console.log(`[LocalStorageAdapter] Deleting conversation: ${id}`);
const conversationKey = `${this.conversationPrefix}${id}`;
localStorage.removeItem(conversationKey);
this.removeConversationId(id);
if (this.getActiveConversationId() === id) {
this.setActiveConversationId("");
console.log(`[LocalStorageAdapter] Cleared active conversation`);
}
await this.removeConversationAgent(id);
console.log(
`[LocalStorageAdapter] Successfully deleted conversation: ${id}`
);
return true;
} catch (error) {
console.error(
`[LocalStorageAdapter] Failed to delete conversation ${id}:`,
error
);
return false;
}
}
async addItem(conversationId, item) {
if (!conversationId || typeof conversationId !== "string") {
console.error(
"[LocalStorageAdapter] Invalid conversation ID for adding item:",
conversationId
);
return null;
}
if (!item || typeof item !== "object") {
console.error("[LocalStorageAdapter] Invalid item for adding:", item);
return null;
}
try {
console.log(
`[LocalStorageAdapter] Adding item to conversation: ${conversationId}`
);
let conversation = await this.getConversation(conversationId);
if (!conversation) {
console.log(
`[LocalStorageAdapter] Conversation not found, creating new one: ${conversationId}`
);
conversation = {
id: conversationId,
title: "New Conversation",
items: []
};
await this.saveConversation(conversation);
}
if (!Array.isArray(conversation.items)) {
conversation.items = [];
}
conversation.items.push(item);
await this.saveConversation(conversation);
console.log(
`[LocalStorageAdapter] Added item to conversation: ${conversationId} (now has ${conversation.items.length} items)`
);
return conversation;
} catch (error) {
console.error("[LocalStorageAdapter] Failed to add item:", error);
return null;
}
}
async getConversationItems(conversationId) {
var _a;
if (!conversationId || typeof conversationId !== "string") {
console.warn(
"[LocalStorageAdapter] Invalid conversation ID for getting items:",
conversationId
);
return [];
}
console.log(
`[LocalStorageAdapter] Getting conversation items: ${conversationId}`
);
const agentId = await this.getConversationAgent(conversationId);
if (agentId && ((_a = this.callbacks) == null ? void 0 : _a.getConversationItems)) {
try {
console.log(
`[LocalStorageAdapter] Syncing with backend agent: ${agentId}`
);
const backendItems = await this.callbacks.getConversationItems(agentId);
const safeBackendItems = Array.isArray(backendItems) ? backendItems : [];
const conversation2 = await this.getConversation(conversationId);
if (conversation2) {
conversation2.items = safeBackendItems;
await this.saveConversation(conversation2);
console.log(
`[LocalStorageAdapter] Updated local storage with ${safeBackendItems.length} items from backend`
);
}
return safeBackendItems;
} catch (error) {
console.error(
"[LocalStorageAdapter] Backend sync failed, using local data:",
error
);
}
}
const conversation = await this.getConversation(conversationId);
const localItems = Array.isArray(conversation == null ? void 0 : conversation.items) ? conversation.items : [];
console.log(
`[LocalStorageAdapter] Retrieved ${localItems.length} items from local storage`
);
return localItems;
}
async syncAllConversationsWithBackend() {
var _a;
if (!((_a = this.callbacks) == null ? void 0 : _a.getConversationItems)) {
console.log("[LocalStorageAdapter] No backend sync callback available");
return;
}
try {
const conversations = await this.getAllConversations();
console.log(
`[LocalStorageAdapter] Syncing ${conversations.length} conversations with backend`
);
for (const conversation of conversations) {
if (!conversation || !conversation.id) {
console.warn(
"[LocalStorageAdapter] Skipping invalid conversation during sync"
);
continue;
}
const agentId = await this.getConversationAgent(conversation.id);
if (agentId) {
try {
console.log(
`[LocalStorageAdapter] Syncing conversation ${conversation.id} with agent ${agentId}`
);
const backendItems = await this.callbacks.getConversationItems(agentId);
const safeBackendItems = Array.isArray(backendItems) ? backendItems : [];
conversation.items = safeBackendItems;
await this.saveConversation(conversation);
console.log(
`[LocalStorageAdapter] Successfully synced conversation ${conversation.id}`
);
} catch (error) {
console.error(
`[LocalStorageAdapter] Failed to sync conversation ${conversation.id}:`,
error
);
}
} else {
console.warn(
`[LocalStorageAdapter] No agent ID found for conversation ${conversation.id}`
);
}
}
} catch (error) {
console.error(
"[LocalStorageAdapter] Failed to sync conversations with backend:",
error
);
}
}
async clearConversationHistory(conversationId) {
var _a;
if (!conversationId || typeof conversationId !== "string") {
console.warn(
"[LocalStorageAdapter] Invalid conversation ID for clearing history:",
conversationId
);
return;
}
console.log(
`[LocalStorageAdapter] Clearing conversation history: ${conversationId}`
);
const agentId = await this.getConversationAgent(conversationId);
if (agentId && ((_a = this.callbacks) == null ? void 0 : _a.clearConversationHistory)) {
try {
console.log(
`[LocalStorageAdapter] Clearing backend history for agent: ${agentId}`
);
await this.callbacks.clearConversationHistory(agentId);
} catch (error) {
console.error(
"[LocalStorageAdapter] Failed to clear backend history:",
error
);
}
}
const conversation = await this.getConversation(conversationId);
if (conversation) {
conversation.items = [];
await this.saveConversation(conversation);
console.log(
`[LocalStorageAdapter] Cleared local history for conversation: ${conversationId}`
);
}
}
async setConversationAgent(conversationId, agentId) {
if (!this.checkClient()) {
throw new Error("localStorage is not available in this environment");
}
if (!conversationId || typeof conversationId !== "string") {
throw new Error("Invalid conversation ID");
}
if (!agentId || typeof agentId !== "string") {
throw new Error("Invalid agent ID");
}
try {
console.log(
`[LocalStorageAdapter] Setting agent mapping: ${conversationId} -> ${agentId}`
);
const mappingData = localStorage.getItem(this.agentMappingKey);
const mapping = mappingData ? JSON.parse(mappingData) : {};
mapping[conversationId] = agentId;
localStorage.setItem(this.agentMappingKey, JSON.stringify(mapping));
console.log(`[LocalStorageAdapter] Agent mapping saved successfully`);
} catch (error) {
console.error("[LocalStorageAdapter] Failed to set agent mapping:", error);
throw error;
}
}
async getConversationAgent(conversationId) {
if (!this.checkClient()) {
console.warn(
"[LocalStorageAdapter] Cannot get agent mapping - not in client environment"
);
return null;
}
if (!conversationId || typeof conversationId !== "string") {
console.warn(
"[LocalStorageAdapter] Invalid conversation ID for getting agent:",
conversationId
);
return null;
}
try {
const mappingData = localStorage.getItem(this.agentMappingKey);
const mapping = mappingData ? JSON.parse(mappingData) : {};
const agentId = mapping[conversationId] || null;
console.log(
`[LocalStorageAdapter] Agent for conversation ${conversationId}: ${agentId}`
);
return agentId;
} catch (error) {
console.error("[LocalStorageAdapter] Failed to get agent mapping:", error);
return null;
}
}
async clearAllConversations() {
if (!this.checkClient()) {
throw new Error("localStorage is not available in this environment");
}
try {
console.log("[LocalStorageAdapter] Clearing all conversations");
const ids = this.getConversationIds();
for (const id of ids) {
if (id && typeof id === "string") {
const conversationKey = `${this.conversationPrefix}${id}`;
localStorage.removeItem(conversationKey);
}
}
localStorage.removeItem(this.conversationIdsKey);
localStorage.removeItem(this.activeConversationKey);
localStorage.removeItem(this.agentMappingKey);
console.log("[LocalStorageAdapter] All conversations cleared");
return true;
} catch (error) {
console.error(
"[LocalStorageAdapter] Failed to clear all conversations:",
error
);
return false;
}
}
getConversationIds() {
if (!this.checkClient()) return [];
try {
const data = localStorage.getItem(this.conversationIdsKey);
const parsed = data ? JSON.parse(data) : [];
const ids = Array.isArray(parsed) ? parsed.filter((id) => id && typeof id === "string") : [];
console.log(`[LocalStorageAdapter] Retrieved conversation IDs:`, ids);
return ids;
} catch (error) {
console.error(
"[LocalStorageAdapter] Failed to get conversation IDs:",
error
);
return [];
}
}
removeConversationId(id) {
if (!this.checkClient() || !id || typeof id !== "string") return;
try {
const ids = this.getConversationIds().filter((convId) => convId !== id);
localStorage.setItem(this.conversationIdsKey, JSON.stringify(ids));
console.log(`[LocalStorageAdapter] Removed conversation ID: ${id}`);
} catch (error) {
console.error(
`[LocalStorageAdapter] Failed to remove conversation ID ${id}:`,
error
);
}
}
async removeConversationAgent(conversationId) {
if (!this.checkClient() || !conversationId || typeof conversationId !== "string")
return;
try {
const mappingData = localStorage.getItem(this.agentMappingKey);
const mapping = mappingData ? JSON.parse(mappingData) : {};
delete mapping[conversationId];
localStorage.setItem(this.agentMappingKey, JSON.stringify(mapping));
console.log(
`[LocalStorageAdapter] Removed agent mapping for: ${conversationId}`
);
} catch (error) {
console.error(
`[LocalStorageAdapter] Failed to remove agent mapping for ${conversationId}:`,
error
);
}
}
};
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
LocalStorageAdapter
});