{"version":3,"file":"storage/FileStorageProvider.mjs","sources":["webpack://@agent-tars/server/./src/storage/FileStorageProvider.ts"],"sourcesContent":["/*\n * Copyright (c) 2025 Bytedance, Inc. and its affiliates.\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport path from 'path';\nimport fs from 'fs';\nimport { Low } from 'lowdb';\nimport { JSONFile } from 'lowdb/node';\nimport { AgentEventStream } from '@agent-tars/core';\nimport { StorageProvider, SessionMetadata } from './types';\n\n/**\n * Data structure for lowdb\n */\ninterface DbSchema {\n  sessions: Record<string, SessionMetadata>;\n  events: Record<string, AgentEventStream.Event[]>;\n}\n\n/**\n * File-based storage provider using lowdb\n * Stores data in a JSON file for persistence\n * Suitable for local development and small-scale deployments\n */\nexport class FileStorageProvider implements StorageProvider {\n  private db: Low<DbSchema>;\n  private initialized = false;\n  public readonly dbPath: string;\n\n  constructor(storagePath?: string) {\n    // Default to the user's home directory\n    const defaultPath = process.env.HOME || process.env.USERPROFILE || '.';\n    const baseDir = storagePath || path.join(defaultPath, '.agent-tars');\n\n    // Create the directory if it doesn't exist\n    if (!fs.existsSync(baseDir)) {\n      fs.mkdirSync(baseDir, { recursive: true });\n    }\n\n    this.dbPath = path.join(baseDir, 'storage.json');\n    const adapter = new JSONFile<DbSchema>(this.dbPath);\n    this.db = new Low<DbSchema>(adapter, { sessions: {}, events: {} });\n  }\n\n  async initialize(): Promise<void> {\n    if (!this.initialized) {\n      try {\n        await this.db.read();\n        // Initialize if file was empty or new\n        this.db.data = this.db.data || { sessions: {}, events: {} };\n        this.initialized = true;\n      } catch (error) {\n        // If file doesn't exist or is invalid JSON, create a new one\n        this.db.data = { sessions: {}, events: {} };\n        await this.db.write();\n        this.initialized = true;\n      }\n    }\n  }\n\n  async createSession(metadata: SessionMetadata): Promise<SessionMetadata> {\n    await this.ensureInitialized();\n\n    const sessionData = {\n      ...metadata,\n      createdAt: metadata.createdAt || Date.now(),\n      updatedAt: metadata.updatedAt || Date.now(),\n    };\n\n    this.db.data.sessions[metadata.id] = sessionData;\n    this.db.data.events[metadata.id] = [];\n\n    await this.db.write();\n    return sessionData;\n  }\n\n  async updateSessionMetadata(\n    sessionId: string,\n    metadata: Partial<Omit<SessionMetadata, 'id'>>,\n  ): Promise<SessionMetadata> {\n    await this.ensureInitialized();\n\n    const session = this.db.data.sessions[sessionId];\n    if (!session) {\n      throw new Error(`Session not found: ${sessionId}`);\n    }\n\n    const updatedSession = {\n      ...session,\n      ...metadata,\n      updatedAt: Date.now(),\n    };\n\n    this.db.data.sessions[sessionId] = updatedSession;\n    await this.db.write();\n\n    return updatedSession;\n  }\n\n  async getSessionMetadata(sessionId: string): Promise<SessionMetadata | null> {\n    await this.ensureInitialized();\n    return this.db.data.sessions[sessionId] || null;\n  }\n\n  async getAllSessions(): Promise<SessionMetadata[]> {\n    await this.ensureInitialized();\n    return Object.values(this.db.data.sessions);\n  }\n\n  async deleteSession(sessionId: string): Promise<boolean> {\n    await this.ensureInitialized();\n\n    if (!this.db.data.sessions[sessionId]) {\n      return false;\n    }\n\n    delete this.db.data.sessions[sessionId];\n    delete this.db.data.events[sessionId];\n\n    await this.db.write();\n    return true;\n  }\n\n  async saveEvent(sessionId: string, event: AgentEventStream.Event): Promise<void> {\n    await this.ensureInitialized();\n\n    if (!this.db.data.sessions[sessionId]) {\n      throw new Error(`Session not found: ${sessionId}`);\n    }\n\n    if (!this.db.data.events[sessionId]) {\n      this.db.data.events[sessionId] = [];\n    }\n\n    this.db.data.events[sessionId].push(event);\n\n    // Update session timestamp\n    this.db.data.sessions[sessionId].updatedAt = Date.now();\n\n    await this.db.write();\n  }\n\n  async getSessionEvents(sessionId: string): Promise<AgentEventStream.Event[]> {\n    await this.ensureInitialized();\n\n    if (!this.db.data.sessions[sessionId]) {\n      throw new Error(`Session not found: ${sessionId}`);\n    }\n\n    return this.db.data.events[sessionId] || [];\n  }\n\n  async close(): Promise<void> {\n    // Make sure any pending writes are flushed\n    if (this.initialized) {\n      await this.db.write();\n    }\n  }\n\n  private async ensureInitialized(): Promise<void> {\n    if (!this.initialized) {\n      await this.initialize();\n    }\n  }\n}\n"],"names":["FileStorageProvider","error","metadata","sessionData","Date","sessionId","session","Error","updatedSession","Object","event","storagePath","defaultPath","process","baseDir","path","fs","adapter","JSONFile","Low"],"mappings":"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"}