{"version":3,"sources":["../../../src/storage/providers/dropbox.ts"],"sourcesContent":["/**\n * Dropbox Storage Provider for Vana SDK\n *\n * Implements the storage interface for Dropbox using its API.\n */\n\nimport {\n  StorageError,\n  type StorageProvider,\n  type StorageUploadResult,\n  type StorageFile,\n  type StorageListOptions,\n  type StorageProviderConfig,\n} from \"../index\";\n\nexport interface DropboxConfig {\n  /** OAuth2 access token */\n  accessToken: string;\n  /** Optional refresh token for token renewal */\n  refreshToken?: string;\n  /** OAuth2 client ID */\n  clientId?: string;\n  /** OAuth2 client secret */\n  clientSecret?: string;\n  /** Root path for uploads (defaults to '/Vana Data') */\n  rootPath?: string;\n}\n\ninterface DropboxUploadResponse {\n  name: string;\n  path_lower: string;\n  path_display: string;\n  id: string;\n  size: number;\n}\n\ninterface DropboxSharedLinkResponse {\n  url: string;\n}\n\ninterface DropboxListResponse {\n  entries: Array<{\n    \".tag\": \"file\" | \"folder\";\n    name: string;\n    path_lower: string;\n    id: string;\n    server_modified: string;\n    size: number;\n  }>;\n  has_more: boolean;\n  cursor: string;\n}\n\n/**\n * Dropbox Storage Provider\n *\n * @remarks\n * Implements the storage interface for Dropbox. Requires OAuth2 authentication.\n *\n * @category Storage\n */\nexport class DropboxStorage implements StorageProvider {\n  private readonly apiUrl = \"https://api.dropboxapi.com/2\";\n  private readonly contentUrl = \"https://content.dropboxapi.com/2\";\n  private readonly rootPath: string;\n\n  constructor(private config: DropboxConfig) {\n    if (!config.accessToken) {\n      throw new StorageError(\n        \"Dropbox access token is required\",\n        \"MISSING_ACCESS_TOKEN\",\n        \"dropbox\",\n      );\n    }\n    this.rootPath = config.rootPath ?? \"/Vana Data\";\n  }\n\n  async upload(file: Blob, filename?: string): Promise<StorageUploadResult> {\n    try {\n      const fileName = filename ?? `vana-file-${Date.now()}.dat`;\n      const path = `${this.rootPath}/${fileName}`;\n\n      const response = await fetch(`${this.contentUrl}/files/upload`, {\n        method: \"POST\",\n        headers: {\n          Authorization: `Bearer ${this.config.accessToken}`,\n          \"Content-Type\": \"application/octet-stream\",\n          \"Dropbox-API-Arg\": JSON.stringify({\n            path,\n            mode: \"add\",\n            autorename: true,\n            mute: false,\n          }),\n        },\n        body: file,\n      });\n\n      if (!response.ok) {\n        const error = await response.text();\n        throw new StorageError(\n          `Failed to upload to Dropbox: ${error}`,\n          \"UPLOAD_FAILED\",\n          \"dropbox\",\n        );\n      }\n\n      const result = (await response.json()) as DropboxUploadResponse;\n      const sharedLinkUrl = await this.createSharedLink(result.path_lower);\n\n      // Convert the shareable URL to a direct download URL before returning.\n      // This ensures the correct, raw-content URL is stored on-chain.\n      const directDownloadUrl = sharedLinkUrl\n        .replace(\"www.dropbox.com\", \"dl.dropboxusercontent.com\")\n        .replace(\"?dl=1\", \"\");\n\n      return {\n        url: directDownloadUrl,\n        size: file.size,\n        contentType: file.type || \"application/octet-stream\",\n        metadata: {\n          id: result.id,\n          path: result.path_display,\n        },\n      };\n    } catch (error) {\n      if (error instanceof StorageError) throw error;\n      throw new StorageError(\n        `Dropbox upload error: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n        \"UPLOAD_ERROR\",\n        \"dropbox\",\n      );\n    }\n  }\n\n  async download(url: string): Promise<Blob> {\n    // URL to force a direct download instead of showing the preview page.\n    // This is done by changing the hostname from 'www.dropbox.com' to 'dl.dropboxusercontent.com'.\n    const downloadUrl = url.replace(\n      \"www.dropbox.com\",\n      \"dl.dropboxusercontent.com\",\n    );\n    try {\n      const response = await fetch(downloadUrl);\n\n      if (!response.ok) {\n        throw new StorageError(\n          `Failed to download from Dropbox: ${response.statusText}`,\n          \"DOWNLOAD_FAILED\",\n          \"dropbox\",\n        );\n      }\n      return response.blob();\n    } catch (error) {\n      if (error instanceof StorageError) throw error;\n      throw new StorageError(\n        `Dropbox download error: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n        \"DOWNLOAD_ERROR\",\n        \"dropbox\",\n      );\n    }\n  }\n\n  async list(options?: StorageListOptions): Promise<StorageFile[]> {\n    if (!this.config.accessToken) {\n      throw new StorageError(\n        \"Access token not provided\",\n        \"AUTH_ERROR\",\n        \"dropbox\",\n      );\n    }\n\n    try {\n      const response = await fetch(`${this.apiUrl}/files/list_folder`, {\n        method: \"POST\",\n        headers: {\n          Authorization: `Bearer ${this.config.accessToken}`,\n          \"Content-Type\": \"application/json\",\n        },\n        body: JSON.stringify({\n          path: this.rootPath,\n          limit: options?.limit ?? 100,\n          include_deleted: false,\n        }),\n      });\n\n      if (!response.ok) {\n        throw new StorageError(\n          `Failed to list Dropbox files: ${await response.text()}`,\n          \"LIST_FAILED\",\n          \"dropbox\",\n        );\n      }\n\n      const result = (await response.json()) as DropboxListResponse;\n\n      return result.entries\n        .filter((entry) => entry[\".tag\"] === \"file\")\n        .map((file) => ({\n          id: file.id,\n          name: file.name,\n          url: `dropbox://${file.path_lower}`, // Placeholder URL\n          size: file.size,\n          contentType: \"application/octet-stream\", // Dropbox API doesn't provide this in list\n          createdAt: new Date(file.server_modified),\n        }));\n    } catch (error) {\n      if (error instanceof StorageError) throw error;\n      throw new StorageError(\n        `Dropbox list error: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n        \"LIST_ERROR\",\n        \"dropbox\",\n      );\n    }\n  }\n\n  async delete(url: string): Promise<boolean> {\n    try {\n      const path = new URL(url).pathname; // Assuming a direct URL format that includes the path\n      const response = await fetch(`${this.apiUrl}/files/delete_v2`, {\n        method: \"POST\",\n        headers: {\n          Authorization: `Bearer ${this.config.accessToken}`,\n          \"Content-Type\": \"application/json\",\n        },\n        body: JSON.stringify({ path }),\n      });\n\n      if (!response.ok && response.status !== 404) {\n        const error = await response.text();\n        throw new StorageError(\n          `Failed to delete from Dropbox: ${error}`,\n          \"DELETE_FAILED\",\n          \"dropbox\",\n        );\n      }\n\n      return true;\n    } catch (error) {\n      if (error instanceof StorageError) throw error;\n      throw new StorageError(\n        `Dropbox delete error: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n        \"DELETE_ERROR\",\n        \"dropbox\",\n      );\n    }\n  }\n\n  getConfig(): StorageProviderConfig {\n    return {\n      name: \"Dropbox\",\n      type: \"dropbox\",\n      requiresAuth: true,\n      features: {\n        upload: true,\n        download: true,\n        list: true,\n        delete: true,\n      },\n    };\n  }\n\n  private async createSharedLink(path: string): Promise<string> {\n    const response = await fetch(\n      `${this.apiUrl}/sharing/create_shared_link_with_settings`,\n      {\n        method: \"POST\",\n        headers: {\n          Authorization: `Bearer ${this.config.accessToken}`,\n          \"Content-Type\": \"application/json\",\n        },\n        body: JSON.stringify({\n          path,\n          settings: {\n            requested_visibility: \"public\",\n          },\n        }),\n      },\n    );\n\n    if (!response.ok) {\n      const errorData = await response.json();\n      // If link already exists, Dropbox returns a 409 with the existing link\n      if (\n        response.status === 409 &&\n        errorData.error?.shared_link_already_exists\n      ) {\n        return errorData.error.shared_link_already_exists.metadata.url;\n      }\n      throw new StorageError(\n        `Failed to create shared link: ${JSON.stringify(errorData)}`,\n        \"LINK_CREATION_FAILED\",\n        \"dropbox\",\n      );\n    }\n\n    const result = (await response.json()) as DropboxSharedLinkResponse;\n    // Modify URL for direct download\n    return result.url.replace(\"?dl=0\", \"?dl=1\");\n  }\n}\n"],"mappings":"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","names":[]}