{"version":3,"sources":["../../../src/storage/providers/vana-storage.ts"],"sourcesContent":["import {\n  StorageError,\n  type StorageProvider,\n  type StorageUploadResult,\n  type StorageFile,\n  type StorageListOptions,\n  type StorageProviderConfig,\n} from \"../index\";\nimport {\n  buildWeb3SignedHeader,\n  type Web3SignedSignFn,\n} from \"../../auth/web3-signed-builder\";\nimport {\n  getProtocolNetworkChainId,\n  isProtocolNetwork,\n  type ProtocolNetwork,\n} from \"../../protocol/networks\";\nimport { readJsonObject } from \"../../utils/response-body\";\n\nconst DEFAULT_ENDPOINT = \"https://storage.vana.org\";\nconst LEGACY_BLOB_PATH_PREFIX = \"/v1/blobs\";\nconst DEFAULT_TOKEN_TTL_SECONDS = 300;\nconst MAX_UPLOAD_ATTEMPTS = 4;\nconst MAX_RATE_LIMIT_DELAY_MS = 30_000;\n\n/**\n * Wallet-style signer used by {@link VanaStorage} to authenticate every\n * request. For Personal Server flows this can be a registered server wallet\n * signing requests for the owner's storage namespace.\n *\n * @category Storage\n */\nexport interface VanaStorageSigner {\n  /** EIP-191 address (`0x...`). */\n  address: `0x${string}`;\n  /** EIP-191 personal_sign callback (e.g. viem `account.signMessage`). */\n  signMessage: Web3SignedSignFn;\n}\n\n/**\n * Configuration for {@link VanaStorage}.\n *\n * @category Storage\n */\nexport interface VanaStorageConfig {\n  /**\n   * Base URL of the vana-storage Worker. Defaults to `https://storage.vana.org`.\n   *\n   * This selects the storage endpoint and is independent of {@link network} /\n   * {@link chainId}.\n   */\n  endpoint?: string;\n  /**\n   * Named Vana protocol network that scopes blob paths. Prefer this for known\n   * Vana networks because it keeps callers on the SDK's typed network registry.\n   *\n   * When set, uploads use chain-scoped routes derived from the network's chain\n   * ID (`/v1/chains/1480/...` for mainnet, `/v1/chains/14800/...` for Moksha).\n   */\n  network?: ProtocolNetwork;\n  /**\n   * Explicit numeric chain ID for custom or future networks not yet represented\n   * by {@link ProtocolNetwork}.\n   *\n   * When set, uploads use chain-scoped routes\n   * (`/v1/chains/{chainId}/blobs/...`) so data for different chains under the\n   * same owner/scope/timestamp never collides. Reads and deletes must use the\n   * same chain-scoped namespace; legacy blobs should be migrated or re-collected\n   * rather than read through an ambiguous fallback. When omitted, the provider\n   * preserves the legacy `/v1/blobs/...` routes and behavior.\n   *\n   * `chainId` and {@link network} are mutually consistent ways to select the\n   * namespace. If both are provided, they must resolve to the same chain ID.\n   * `endpoint` remains orthogonal: it picks the storage host, not the protocol\n   * namespace.\n   */\n  chainId?: number;\n  /**\n   * Wallet signer used to authenticate writes and reads.\n   */\n  signer: VanaStorageSigner;\n  /**\n   * Owner namespace under which blobs are stored. Defaults to the signer address.\n   */\n  ownerAddress?: `0x${string}`;\n  /**\n   * Optional `fetch` implementation. Defaults to the global `fetch`.\n   * Useful for tests and for environments that need a custom HTTP client.\n   */\n  fetchImpl?: typeof fetch;\n}\n\ninterface VanaStorageUploadResponse {\n  key: string;\n  url: string;\n  etag: string;\n  size: number;\n}\n\n/**\n * Response of {@link VanaStorage.deleteScope} -- the worker's\n * `DELETE /:owner/:scope` body. `count` is the number of blobs removed (0 is\n * a success: nothing was stored under that scope).\n *\n * @category Storage\n */\nexport interface VanaStorageScopeDeleteResult {\n  deleted: boolean;\n  scope: string;\n  count: number;\n  totalBytes: number;\n}\n\n/**\n * Storage provider that talks to the vana-storage Worker\n * (`https://storage.vana.org` by default). All requests are authenticated\n * with Web3Signed headers signed by the configured wallet.\n *\n * @remarks\n * Filenames passed to {@link VanaStorage.upload} must be of the form\n * `\"{scope}/{collectedAt}\"` (e.g. `\"instagram.profile/2026-05-08T20:00:00.000Z\"`).\n * The owner address is prepended automatically to produce the canonical\n * blob path `/v1/blobs/{owner}/{scope}/{collectedAt}`.\n *\n * When {@link VanaStorageConfig.network} or {@link VanaStorageConfig.chainId}\n * is set, paths are chain-scoped as\n * `/v1/chains/{chainId}/blobs/{owner}/{scope}/{collectedAt}` so different chains\n * never collide on the same host. The Web3Signed audience remains the endpoint\n * origin regardless of network.\n *\n * @category Storage\n *\n * @example\n * ```typescript\n * import { privateKeyToAccount } from \"viem/accounts\";\n * import { VanaStorage } from \"@opendatalabs/vana-sdk/node\";\n *\n * const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);\n * const storage = new VanaStorage({\n *   signer: {\n *     address: account.address,\n *     signMessage: (msg) => account.signMessage({ message: msg }),\n *   },\n * });\n *\n * const result = await storage.upload(\n *   new Blob([ciphertext]),\n *   \"instagram.profile/2026-05-08T20:00:00.000Z\",\n * );\n * ```\n */\nexport class VanaStorage implements StorageProvider {\n  private readonly endpoint: string;\n  private readonly network?: ProtocolNetwork;\n  private readonly chainId?: number;\n  private readonly blobPathPrefix: string;\n  private readonly signer: VanaStorageSigner;\n  private readonly ownerAddress: string;\n  private readonly fetchImpl: typeof fetch;\n\n  constructor(config: VanaStorageConfig) {\n    if (!config?.signer?.address || !config?.signer?.signMessage) {\n      throw new StorageError(\n        \"VanaStorage requires a signer with address and signMessage\",\n        \"MISSING_SIGNER\",\n        \"vana-storage\",\n      );\n    }\n    this.endpoint = (config.endpoint ?? DEFAULT_ENDPOINT).replace(/\\/+$/, \"\");\n    const resolved = resolveStorageNamespace(config);\n    this.network = resolved.network;\n    this.chainId = resolved.chainId;\n    this.blobPathPrefix =\n      this.chainId !== undefined\n        ? `/v1/chains/${this.chainId}/blobs`\n        : LEGACY_BLOB_PATH_PREFIX;\n    this.signer = config.signer;\n    this.ownerAddress = (\n      config.ownerAddress ?? config.signer.address\n    ).toLowerCase();\n    this.fetchImpl = config.fetchImpl ?? globalThis.fetch.bind(globalThis);\n  }\n\n  /**\n   * Upload an encrypted blob to vana-storage.\n   *\n   * @param file - The blob to upload.\n   * @param filename - Required relative key in the form `\"{scope}/{collectedAt}\"`.\n   *   The owner address is prepended automatically.\n   */\n  async upload(file: Blob, filename?: string): Promise<StorageUploadResult> {\n    if (!filename) {\n      throw new StorageError(\n        \"VanaStorage.upload requires a filename of the form '{scope}/{collectedAt}'\",\n        \"MISSING_FILENAME\",\n        \"vana-storage\",\n      );\n    }\n\n    const subpath = encodeRelativePath(filename);\n    const path = `${this.blobPathPrefix}/${this.ownerAddress}/${subpath}`;\n    const body = new Uint8Array(await file.arrayBuffer());\n    const contentType =\n      file.type !== \"\" ? file.type : \"application/octet-stream\";\n\n    const header = await this.signRequest(\"PUT\", path, body);\n\n    let response: Response | null = null;\n    let responseText = \"\";\n    for (let attempt = 1; attempt <= MAX_UPLOAD_ATTEMPTS; attempt++) {\n      try {\n        response = await this.fetchImpl(`${this.endpoint}${path}`, {\n          method: \"PUT\",\n          headers: {\n            authorization: header,\n            \"content-type\": contentType,\n          },\n          body,\n        });\n      } catch (cause) {\n        throw new StorageError(\n          `vana-storage upload network error: ${describe(cause)}`,\n          \"UPLOAD_ERROR\",\n          \"vana-storage\",\n          { cause: cause instanceof Error ? cause : undefined },\n        );\n      }\n\n      if (response.ok) {\n        break;\n      }\n\n      responseText = await safeText(response);\n      if (response.status === 429 && attempt < MAX_UPLOAD_ATTEMPTS) {\n        const delayMs = retryDelayMs(response, responseText);\n        if (delayMs > 0) {\n          await sleep(delayMs);\n        }\n        continue;\n      }\n\n      throw new StorageError(\n        `vana-storage upload failed: ${response.status} ${response.statusText} - ${responseText}`,\n        \"UPLOAD_FAILED\",\n        \"vana-storage\",\n      );\n    }\n\n    if (!response?.ok) {\n      throw new StorageError(\n        `vana-storage upload failed after ${MAX_UPLOAD_ATTEMPTS} attempts - ${responseText}`,\n        \"UPLOAD_FAILED\",\n        \"vana-storage\",\n      );\n    }\n\n    const result = (await response.json()) as VanaStorageUploadResponse;\n    return {\n      url: result.url,\n      size: result.size,\n      contentType,\n      metadata: { key: result.key, etag: result.etag },\n    };\n  }\n\n  /**\n   * Download a blob by URL. The URL must point at a path under this\n   * provider's endpoint.\n   */\n  async download(url: string): Promise<Blob> {\n    const path = this.pathFromUrl(url);\n    const header = await this.signRequest(\"GET\", path);\n\n    let response: Response;\n    try {\n      response = await this.fetchImpl(`${this.endpoint}${path}`, {\n        method: \"GET\",\n        headers: { authorization: header },\n      });\n    } catch (cause) {\n      throw new StorageError(\n        `vana-storage download network error: ${describe(cause)}`,\n        \"DOWNLOAD_ERROR\",\n        \"vana-storage\",\n        { cause: cause instanceof Error ? cause : undefined },\n      );\n    }\n\n    if (!response.ok) {\n      throw new StorageError(\n        `vana-storage download failed: ${response.status} ${response.statusText}`,\n        \"DOWNLOAD_FAILED\",\n        \"vana-storage\",\n      );\n    }\n\n    return await response.blob();\n  }\n\n  /**\n   * Listing is not supported by vana-storage — file discovery is handled by\n   * the Gateway DataRegistry, not the storage layer.\n   */\n  async list(_options?: StorageListOptions): Promise<StorageFile[]> {\n    throw new StorageError(\n      \"list is not supported by vana-storage; query the Gateway DataRegistry instead\",\n      \"NOT_IMPLEMENTED\",\n      \"vana-storage\",\n    );\n  }\n\n  async delete(url: string): Promise<boolean> {\n    const path = this.pathFromUrl(url);\n    const header = await this.signRequest(\"DELETE\", path);\n\n    let response: Response;\n    try {\n      response = await this.fetchImpl(`${this.endpoint}${path}`, {\n        method: \"DELETE\",\n        headers: { authorization: header },\n      });\n    } catch (cause) {\n      throw new StorageError(\n        `vana-storage delete network error: ${describe(cause)}`,\n        \"DELETE_ERROR\",\n        \"vana-storage\",\n        { cause: cause instanceof Error ? cause : undefined },\n      );\n    }\n\n    if (response.status === 404) return false;\n    if (!response.ok) {\n      throw new StorageError(\n        `vana-storage delete failed: ${response.status} ${response.statusText}`,\n        \"DELETE_FAILED\",\n        \"vana-storage\",\n      );\n    }\n    return true;\n  }\n\n  /**\n   * Delete every version's blob under `(owner, scope)` --\n   * `DELETE {prefix}/{owner}/{scope}` on vana-storage, signed with the same\n   * Web3Signed header as uploads (aud = endpoint origin, empty bodyHash).\n   * The worker accepts the owner's own signature or a personal server the\n   * owner registered with the gateway.\n   *\n   * @param ownerAddress - Must equal the provider's configured owner; a\n   *   mismatch throws before anything is signed so this wallet can never be\n   *   induced to sign a delete for another namespace.\n   * @param scope - The scope segment, e.g. `\"instagram.profile\"`.\n   */\n  async deleteScope(\n    ownerAddress: `0x${string}`,\n    scope: string,\n  ): Promise<VanaStorageScopeDeleteResult> {\n    if (ownerAddress.toLowerCase() !== this.ownerAddress) {\n      throw new StorageError(\n        `deleteScope owner '${ownerAddress}' does not match the configured owner '${this.ownerAddress}'`,\n        \"INVALID_OWNER\",\n        \"vana-storage\",\n      );\n    }\n    if (\n      scope.length === 0 ||\n      scope.includes(\"/\") ||\n      isTraversalSegment(scope)\n    ) {\n      throw new StorageError(\n        `scope must be a single non-empty path segment, got '${scope}'`,\n        \"INVALID_SCOPE\",\n        \"vana-storage\",\n      );\n    }\n\n    const path = `${this.blobPathPrefix}/${this.ownerAddress}/${encodeURIComponent(scope)}`;\n    const header = await this.signRequest(\"DELETE\", path);\n\n    let response: Response;\n    try {\n      response = await this.fetchImpl(`${this.endpoint}${path}`, {\n        method: \"DELETE\",\n        headers: { authorization: header },\n      });\n    } catch (cause) {\n      throw new StorageError(\n        `vana-storage scope delete network error: ${describe(cause)}`,\n        \"DELETE_ERROR\",\n        \"vana-storage\",\n        { cause: cause instanceof Error ? cause : undefined },\n      );\n    }\n\n    if (!response.ok) {\n      const responseText = await safeText(response);\n      throw new StorageError(\n        `vana-storage scope delete failed: ${response.status} ${response.statusText} - ${responseText}`,\n        \"DELETE_FAILED\",\n        \"vana-storage\",\n      );\n    }\n\n    // A 2xx is the success signal; the body is informational. Tolerate an\n    // empty 204, a non-JSON body, or a JSON `null`/array, and only trust\n    // fields that carry the documented type.\n    const body = await readJsonObject(response);\n    return {\n      deleted: typeof body[\"deleted\"] === \"boolean\" ? body[\"deleted\"] : true,\n      scope: typeof body[\"scope\"] === \"string\" ? body[\"scope\"] : scope,\n      count: nonNegativeInteger(body[\"count\"]) ?? 0,\n      totalBytes: nonNegativeInteger(body[\"totalBytes\"]) ?? 0,\n    };\n  }\n\n  getConfig(): StorageProviderConfig {\n    return {\n      name: \"vana-storage\",\n      type: \"vana-storage\",\n      requiresAuth: true,\n      features: {\n        upload: true,\n        download: true,\n        list: false,\n        delete: true,\n      },\n    };\n  }\n\n  private async signRequest(\n    method: \"GET\" | \"PUT\" | \"DELETE\",\n    path: string,\n    body?: Uint8Array,\n  ): Promise<string> {\n    const now = Math.floor(Date.now() / 1000);\n    return buildWeb3SignedHeader({\n      signMessage: this.signer.signMessage,\n      aud: this.endpoint,\n      method,\n      uri: path,\n      iat: now,\n      exp: now + DEFAULT_TOKEN_TTL_SECONDS,\n      ...(body !== undefined && body.length > 0 && { body }),\n    });\n  }\n\n  private pathFromUrl(url: string): string {\n    let parsed: URL;\n    try {\n      parsed = new URL(url);\n    } catch {\n      throw new StorageError(\n        `Invalid URL: ${url}`,\n        \"INVALID_URL\",\n        \"vana-storage\",\n      );\n    }\n    const expectedHost = new URL(this.endpoint).host;\n    if (parsed.host !== expectedHost) {\n      throw new StorageError(\n        `URL host '${parsed.host}' does not match storage endpoint '${expectedHost}'`,\n        \"INVALID_URL\",\n        \"vana-storage\",\n      );\n    }\n    // Restrict to a blob path for this owner so a caller cannot induce this\n    // wallet to sign arbitrary same-host paths.\n    const route = parseBlobPath(parsed.pathname);\n    if (!route || route.owner.toLowerCase() !== this.ownerAddress) {\n      throw new StorageError(\n        `URL path '${parsed.pathname}' must be ${this.blobPathPrefix}/${this.ownerAddress}/{scope}/{collectedAt}`,\n        \"INVALID_URL\",\n        \"vana-storage\",\n      );\n    }\n    // A provider must only sign requests for its configured namespace. Chain\n    // mode is strict: old legacy blobs should be migrated or re-collected\n    // rather than read through a second ambiguous path.\n    if (route.chainId !== this.chainId) {\n      throw new StorageError(\n        `URL chainId '${route.chainId ?? \"legacy\"}' does not match provider namespace '${this.namespaceDescription()}'`,\n        \"INVALID_URL\",\n        \"vana-storage\",\n      );\n    }\n    return parsed.pathname;\n  }\n\n  private namespaceDescription(): string {\n    if (this.network !== undefined) {\n      return `${this.network} (${this.chainId})`;\n    }\n    return this.chainId === undefined ? \"legacy\" : String(this.chainId);\n  }\n}\n\ninterface ParsedBlobRoute {\n  chainId?: number;\n  owner: string;\n  scope: string;\n  collectedAt: string;\n}\n\nfunction isValidChainId(value: unknown): value is number {\n  return typeof value === \"number\" && Number.isInteger(value) && value > 0;\n}\n\nfunction resolveStorageNamespace(\n  config: Pick<VanaStorageConfig, \"network\" | \"chainId\">,\n): {\n  chainId?: number;\n  network?: ProtocolNetwork;\n} {\n  if (config.network !== undefined && !isProtocolNetwork(config.network)) {\n    throw new StorageError(\n      `Unsupported vana-storage network '${String(config.network)}'`,\n      \"INVALID_NETWORK\",\n      \"vana-storage\",\n    );\n  }\n\n  if (config.chainId !== undefined && !isValidChainId(config.chainId)) {\n    throw new StorageError(\n      `Unsupported vana-storage chainId '${String(config.chainId)}'`,\n      \"INVALID_CHAIN_ID\",\n      \"vana-storage\",\n    );\n  }\n\n  if (config.network === undefined) {\n    return { chainId: config.chainId };\n  }\n\n  const networkChainId = getProtocolNetworkChainId(config.network);\n  if (config.chainId !== undefined && config.chainId !== networkChainId) {\n    throw new StorageError(\n      `vana-storage network '${config.network}' resolves to chainId '${networkChainId}', not '${config.chainId}'`,\n      \"INVALID_CHAIN_ID\",\n      \"vana-storage\",\n    );\n  }\n\n  return { chainId: networkChainId, network: config.network };\n}\n\n/**\n * Parse a storage blob pathname into structured route info, or `null` when the\n * path is neither the legacy nor the chain-scoped blob shape. Traversal\n * segments (`.` / `..`) are rejected as invalid.\n */\nfunction parseBlobPath(pathname: string): ParsedBlobRoute | null {\n  const segments = pathname.split(\"/\").filter((s) => s.length > 0);\n  const isTraversal = (s: string): boolean => s === \".\" || s === \"..\";\n\n  // Legacy: /v1/blobs/{owner}/{scope}/{collectedAt}\n  if (\n    segments.length === 5 &&\n    segments[0] === \"v1\" &&\n    segments[1] === \"blobs\"\n  ) {\n    const [, , owner, scope, collectedAt] = segments as [\n      string,\n      string,\n      string,\n      string,\n      string,\n    ];\n    if (isTraversal(scope) || isTraversal(collectedAt)) return null;\n    return { owner, scope, collectedAt };\n  }\n\n  // Chain-scoped: /v1/chains/{chainId}/blobs/{owner}/{scope}/{collectedAt}\n  if (\n    segments.length === 7 &&\n    segments[0] === \"v1\" &&\n    segments[1] === \"chains\" &&\n    segments[3] === \"blobs\"\n  ) {\n    const [, , chainIdSegment, , owner, scope, collectedAt] = segments as [\n      string,\n      string,\n      string,\n      string,\n      string,\n      string,\n      string,\n    ];\n    if (!/^[0-9]+$/.test(chainIdSegment)) return null;\n    const chainId = Number(chainIdSegment);\n    if (!isValidChainId(chainId)) return null;\n    if (isTraversal(scope) || isTraversal(collectedAt)) return null;\n    return { chainId, owner, scope, collectedAt };\n  }\n\n  return null;\n}\n\nfunction encodeRelativePath(filename: string): string {\n  const parts = filename.split(\"/\");\n  if (\n    parts.length !== 2 ||\n    parts.some((p) => p.length === 0 || p === \".\" || p === \"..\")\n  ) {\n    throw new StorageError(\n      `filename must be exactly '{scope}/{collectedAt}' with non-empty segments, got '${filename}'`,\n      \"INVALID_FILENAME\",\n      \"vana-storage\",\n    );\n  }\n  return parts.map((p) => encodeURIComponent(p)).join(\"/\");\n}\n\nfunction isTraversalSegment(segment: string): boolean {\n  return segment === \".\" || segment === \"..\";\n}\n\nfunction nonNegativeInteger(value: unknown): number | undefined {\n  return typeof value === \"number\" && Number.isInteger(value) && value >= 0\n    ? value\n    : undefined;\n}\n\nfunction describe(value: unknown): string {\n  if (value instanceof Error) return value.message;\n  return String(value);\n}\n\nfunction retryDelayMs(response: Response, responseText: string): number {\n  const headerDelayMs = parseRetryAfterHeaderMs(\n    response.headers.get(\"retry-after\"),\n  );\n  if (headerDelayMs !== null) {\n    return clampRateLimitDelay(headerDelayMs);\n  }\n\n  return clampRateLimitDelay(parseRetryAfterBodyMs(responseText) ?? 0);\n}\n\nfunction parseRetryAfterHeaderMs(value: string | null): number | null {\n  if (!value) return null;\n\n  const seconds = Number(value);\n  if (Number.isFinite(seconds)) {\n    return seconds * 1000;\n  }\n\n  const dateMs = Date.parse(value);\n  if (Number.isFinite(dateMs)) {\n    return Math.max(0, dateMs - Date.now());\n  }\n\n  return null;\n}\n\nfunction parseRetryAfterBodyMs(responseText: string): number | null {\n  if (!responseText) return null;\n\n  try {\n    const parsed = JSON.parse(responseText) as { retryAfter?: unknown };\n    const seconds = Number(parsed.retryAfter);\n    return Number.isFinite(seconds) ? seconds * 1000 : null;\n  } catch {\n    return null;\n  }\n}\n\nfunction clampRateLimitDelay(delayMs: number): number {\n  return Math.min(Math.max(0, delayMs), MAX_RATE_LIMIT_DELAY_MS);\n}\n\nfunction sleep(ms: number): Promise<void> {\n  return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nasync function safeText(response: Response): Promise<string> {\n  try {\n    return await response.text();\n  } catch {\n    return \"\";\n  }\n}\n"],"mappings":"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","names":[]}