@opendatalabs/vana-sdk
Version:
A TypeScript library for interacting with Vana Network smart contracts.
1 lines • 23.4 kB
Source Map (JSON)
{"version":3,"sources":["../../../src/storage/providers/r2.ts"],"sourcesContent":["import { hmac } from \"@noble/hashes/hmac\";\nimport { sha256 } from \"@noble/hashes/sha2\";\n\nimport {\n StorageError,\n type StorageProvider,\n type StorageUploadResult,\n type StorageFile,\n type StorageListOptions,\n type StorageProviderConfig,\n} from \"../index\";\n\n/**\n * Configuration for {@link R2Storage}.\n *\n * @category Storage\n */\nexport interface R2Config {\n /** Cloudflare account ID. Used to derive the S3 endpoint when `endpoint` is not given. */\n accountId?: string;\n /**\n * Full S3 endpoint URL. Overrides `accountId`.\n *\n * Defaults to `https://{accountId}.r2.cloudflarestorage.com`.\n */\n endpoint?: string;\n /** R2 access key ID. */\n accessKeyId: string;\n /** R2 secret access key. */\n secretAccessKey: string;\n /** Bucket name. */\n bucket: string;\n /**\n * Public URL prefix used when constructing the URL returned by {@link R2Storage.upload}.\n *\n * If unset, defaults to `https://{bucket}.{accountId}.r2.dev` (R2's default public hostname).\n * Set this to a custom domain bound to the bucket if you have one.\n */\n publicUrl?: string;\n /**\n * S3 region. R2 expects `auto`; consumers can override for compatibility with other\n * S3-compatible stores reachable through the same code path.\n */\n region?: string;\n}\n\ninterface SignedRequest {\n url: string;\n headers: Record<string, string>;\n}\n\nconst SERVICE = \"s3\";\nconst DEFAULT_REGION = \"auto\";\n\n/**\n * Cloudflare R2 storage provider.\n *\n * @remarks\n * Uses R2's S3-compatible API with SigV4 signed `fetch` requests, so the same\n * implementation runs in browsers, Node.js, and Workers without pulling in\n * `@aws-sdk/client-s3`. Treats blobs as opaque - encryption, access control,\n * and per-tenant prefixing are out of scope and live in higher layers.\n *\n * The SDK exposes R2 as the recommended default backend. Other providers\n * (Pinata, IPFS, Google Drive, Dropbox, CallbackStorage) remain available for\n * teams that need IPFS semantics or user-owned storage.\n *\n * @category Storage\n *\n * @example\n * ```typescript\n * import { R2Storage, StorageManager } from \"@opendatalabs/vana-sdk/node\";\n *\n * const storage = new StorageManager();\n * storage.register(\n * \"r2\",\n * new R2Storage({\n * accountId: process.env.R2_ACCOUNT_ID!,\n * accessKeyId: process.env.R2_ACCESS_KEY_ID!,\n * secretAccessKey: process.env.R2_SECRET_ACCESS_KEY!,\n * bucket: process.env.R2_BUCKET!,\n * publicUrl: \"https://files.example.com\",\n * }),\n * true,\n * );\n *\n * const result = await storage.upload(myBlob, \"report.json\");\n * console.log(result.url);\n * ```\n */\nexport class R2Storage implements StorageProvider {\n private readonly endpoint: string;\n private readonly publicUrl: string;\n private readonly region: string;\n private readonly bucket: string;\n\n constructor(private readonly config: R2Config) {\n if (!config.accessKeyId) {\n throw new StorageError(\n \"R2 accessKeyId is required\",\n \"MISSING_ACCESS_KEY\",\n \"r2\",\n );\n }\n if (!config.secretAccessKey) {\n throw new StorageError(\n \"R2 secretAccessKey is required\",\n \"MISSING_SECRET_KEY\",\n \"r2\",\n );\n }\n if (!config.bucket) {\n throw new StorageError(\"R2 bucket is required\", \"MISSING_BUCKET\", \"r2\");\n }\n if (!config.endpoint && !config.accountId) {\n throw new StorageError(\n \"R2 endpoint or accountId is required\",\n \"MISSING_ENDPOINT\",\n \"r2\",\n );\n }\n if (!config.publicUrl && !config.accountId) {\n throw new StorageError(\n \"R2 publicUrl is required when accountId is not provided\",\n \"MISSING_PUBLIC_URL\",\n \"r2\",\n );\n }\n\n this.bucket = config.bucket;\n this.region = config.region ?? DEFAULT_REGION;\n this.endpoint = (\n config.endpoint ?? `https://${config.accountId}.r2.cloudflarestorage.com`\n ).replace(/\\/$/, \"\");\n this.publicUrl = (\n config.publicUrl ?? `https://${config.bucket}.${config.accountId}.r2.dev`\n ).replace(/\\/$/, \"\");\n }\n\n async upload(file: Blob, filename?: string): Promise<StorageUploadResult> {\n const key = filename ?? `vana-${Date.now()}-${randomSuffix()}.dat`;\n const body = new Uint8Array(await file.arrayBuffer());\n const contentType =\n file.type !== \"\" ? file.type : \"application/octet-stream\";\n\n try {\n const signed = await this.signRequest({\n method: \"PUT\",\n path: `/${this.bucket}/${encodePath(key)}`,\n body,\n extraHeaders: { \"content-type\": contentType },\n });\n\n const response = await fetch(signed.url, {\n method: \"PUT\",\n headers: signed.headers,\n body,\n });\n\n if (!response.ok) {\n throw new StorageError(\n `R2 upload failed: ${response.status} ${response.statusText} - ${await safeText(response)}`,\n \"UPLOAD_FAILED\",\n \"r2\",\n );\n }\n\n return {\n url: `${this.publicUrl}/${encodePath(key)}`,\n size: file.size,\n contentType,\n };\n } catch (error) {\n throw wrapError(error, \"UPLOAD_ERROR\", \"r2\");\n }\n }\n\n async download(url: string): Promise<Blob> {\n const key = this.extractKey(url);\n if (!key) {\n throw new StorageError(\n `Could not extract object key from URL: ${url}`,\n \"INVALID_URL\",\n \"r2\",\n );\n }\n\n try {\n const signed = await this.signRequest({\n method: \"GET\",\n path: `/${this.bucket}/${encodePath(key)}`,\n });\n\n const response = await fetch(signed.url, {\n method: \"GET\",\n headers: signed.headers,\n });\n\n if (!response.ok) {\n throw new StorageError(\n `R2 download failed: ${response.status} ${response.statusText}`,\n \"DOWNLOAD_FAILED\",\n \"r2\",\n );\n }\n\n return await response.blob();\n } catch (error) {\n throw wrapError(error, \"DOWNLOAD_ERROR\", \"r2\");\n }\n }\n\n async list(options?: StorageListOptions): Promise<StorageFile[]> {\n try {\n const params = new URLSearchParams({ \"list-type\": \"2\" });\n if (options?.namePattern) {\n params.set(\"prefix\", options.namePattern);\n }\n if (options?.limit !== undefined) {\n params.set(\"max-keys\", String(options.limit));\n }\n if (options?.offset !== undefined) {\n params.set(\"continuation-token\", String(options.offset));\n }\n\n const signed = await this.signRequest({\n method: \"GET\",\n path: `/${this.bucket}`,\n query: params,\n });\n\n const response = await fetch(signed.url, {\n method: \"GET\",\n headers: signed.headers,\n });\n\n if (!response.ok) {\n throw new StorageError(\n `R2 list failed: ${response.status} ${response.statusText}`,\n \"LIST_FAILED\",\n \"r2\",\n );\n }\n\n const xml = await response.text();\n return parseListObjects(xml).map((obj) => ({\n id: obj.key,\n name: obj.key,\n url: `${this.publicUrl}/${encodePath(obj.key)}`,\n size: obj.size,\n contentType: \"application/octet-stream\",\n createdAt: obj.lastModified,\n }));\n } catch (error) {\n throw wrapError(error, \"LIST_ERROR\", \"r2\");\n }\n }\n\n async delete(url: string): Promise<boolean> {\n const key = this.extractKey(url);\n if (!key) {\n throw new StorageError(\n `Could not extract object key from URL: ${url}`,\n \"INVALID_URL\",\n \"r2\",\n );\n }\n\n try {\n const signed = await this.signRequest({\n method: \"DELETE\",\n path: `/${this.bucket}/${encodePath(key)}`,\n });\n\n const response = await fetch(signed.url, {\n method: \"DELETE\",\n headers: signed.headers,\n });\n\n if (!response.ok && response.status !== 204) {\n throw new StorageError(\n `R2 delete failed: ${response.status} ${response.statusText}`,\n \"DELETE_FAILED\",\n \"r2\",\n );\n }\n\n return true;\n } catch (error) {\n throw wrapError(error, \"DELETE_ERROR\", \"r2\");\n }\n }\n\n getConfig(): StorageProviderConfig {\n return {\n name: \"Cloudflare R2\",\n type: \"r2\",\n requiresAuth: true,\n features: {\n upload: true,\n download: true,\n list: true,\n delete: true,\n },\n };\n }\n\n /**\n * Extract the object key from a URL. Accepts public URLs minted by `upload()`\n * as well as raw keys for callers that already track them out-of-band.\n *\n * @internal\n */\n private extractKey(urlOrKey: string): string | null {\n if (urlOrKey.startsWith(this.publicUrl + \"/\")) {\n return decodeURIComponent(urlOrKey.slice(this.publicUrl.length + 1));\n }\n if (urlOrKey.startsWith(this.endpoint + \"/\")) {\n const rest = urlOrKey.slice(this.endpoint.length + 1);\n const slash = rest.indexOf(\"/\");\n return slash === -1 ? null : decodeURIComponent(rest.slice(slash + 1));\n }\n if (!urlOrKey.includes(\"://\")) {\n return urlOrKey;\n }\n return null;\n }\n\n private async signRequest(req: {\n method: string;\n path: string;\n query?: URLSearchParams;\n body?: Uint8Array;\n extraHeaders?: Record<string, string>;\n }): Promise<SignedRequest> {\n // SigV4's host header must include the port for non-default ports\n // (e.g. localhost:9000 for S3-compatible test endpoints). URL.host keeps\n // the port; URL.hostname strips it.\n const { host } = new URL(this.endpoint);\n const now = new Date();\n const amzDate = formatAmzDate(now);\n const dateStamp = amzDate.slice(0, 8);\n\n const payloadHash = req.body ? toHex(sha256(req.body)) : EMPTY_PAYLOAD_HASH;\n\n const canonicalQuery = req.query ? canonicalizeQuery(req.query) : \"\";\n\n const headers: Record<string, string> = {\n host,\n \"x-amz-content-sha256\": payloadHash,\n \"x-amz-date\": amzDate,\n ...(req.extraHeaders ?? {}),\n };\n\n const sortedHeaderNames = Object.keys(headers)\n .map((h) => h.toLowerCase())\n .sort();\n const canonicalHeaders =\n sortedHeaderNames\n .map((h) => `${h}:${headers[h].trim().replace(/\\s+/g, \" \")}`)\n .join(\"\\n\") + \"\\n\";\n const signedHeaders = sortedHeaderNames.join(\";\");\n\n const canonicalRequest = [\n req.method,\n req.path,\n canonicalQuery,\n canonicalHeaders,\n signedHeaders,\n payloadHash,\n ].join(\"\\n\");\n\n const credentialScope = `${dateStamp}/${this.region}/${SERVICE}/aws4_request`;\n const stringToSign = [\n \"AWS4-HMAC-SHA256\",\n amzDate,\n credentialScope,\n toHex(sha256(new TextEncoder().encode(canonicalRequest))),\n ].join(\"\\n\");\n\n const signingKey = deriveSigningKey(\n this.config.secretAccessKey,\n dateStamp,\n this.region,\n SERVICE,\n );\n const signature = toHex(\n hmac(sha256, signingKey, new TextEncoder().encode(stringToSign)),\n );\n\n headers.authorization = `AWS4-HMAC-SHA256 Credential=${this.config.accessKeyId}/${credentialScope}, SignedHeaders=${signedHeaders}, Signature=${signature}`;\n\n const url =\n this.endpoint +\n req.path +\n (canonicalQuery !== \"\" ? `?${canonicalQuery}` : \"\");\n\n return { url, headers };\n }\n}\n\nconst EMPTY_PAYLOAD_HASH =\n \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\";\n\nfunction deriveSigningKey(\n secret: string,\n dateStamp: string,\n region: string,\n service: string,\n): Uint8Array {\n const enc = new TextEncoder();\n const kDate = hmac(\n sha256,\n enc.encode(`AWS4${secret}`),\n enc.encode(dateStamp),\n );\n const kRegion = hmac(sha256, kDate, enc.encode(region));\n const kService = hmac(sha256, kRegion, enc.encode(service));\n return hmac(sha256, kService, enc.encode(\"aws4_request\"));\n}\n\nfunction formatAmzDate(date: Date): string {\n // YYYYMMDDTHHMMSSZ\n const iso = date.toISOString();\n return iso.replace(/[-:]/g, \"\").replace(/\\.\\d+/, \"\");\n}\n\nfunction toHex(bytes: Uint8Array): string {\n let s = \"\";\n for (let i = 0; i < bytes.length; i++) {\n s += bytes[i].toString(16).padStart(2, \"0\");\n }\n return s;\n}\n\n/**\n * RFC 3986-compliant percent-encoding. `encodeURIComponent` leaves `! ' ( ) *`\n * unescaped, but AWS SigV4 (and RFC 3986 reserved sub-delims) require them\n * encoded. Used for both path segments and query keys/values.\n */\nfunction rfc3986Encode(value: string): string {\n return encodeURIComponent(value).replace(\n /[!'()*]/g,\n (c) => \"%\" + c.charCodeAt(0).toString(16).toUpperCase(),\n );\n}\n\n/**\n * Encode each path segment per AWS canonical-URI rules. Slashes between segments\n * are preserved; everything else (including `+`, `=`, etc.) is percent-encoded.\n */\nfunction encodePath(key: string): string {\n return key.split(\"/\").map(rfc3986Encode).join(\"/\");\n}\n\nfunction canonicalizeQuery(params: URLSearchParams): string {\n const entries: [string, string][] = [];\n for (const [k, v] of params.entries()) {\n entries.push([k, v]);\n }\n entries.sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0));\n return entries\n .map(([k, v]) => `${rfc3986Encode(k)}=${rfc3986Encode(v)}`)\n .join(\"&\");\n}\n\ninterface ListObject {\n key: string;\n size: number;\n lastModified: Date;\n}\n\nfunction parseListObjects(xml: string): ListObject[] {\n const out: ListObject[] = [];\n const contentsRe = /<Contents>([\\s\\S]*?)<\\/Contents>/g;\n let match: RegExpExecArray | null;\n while ((match = contentsRe.exec(xml)) !== null) {\n const block = match[1];\n const key = matchTag(block, \"Key\");\n const size = matchTag(block, \"Size\");\n const lastModified = matchTag(block, \"LastModified\");\n if (key === null) {\n continue;\n }\n out.push({\n key: decodeXmlEntities(key),\n size: size !== null ? parseInt(size, 10) || 0 : 0,\n lastModified:\n lastModified !== null ? new Date(lastModified) : new Date(0),\n });\n }\n return out;\n}\n\nfunction matchTag(block: string, tag: string): string | null {\n const re = new RegExp(`<${tag}>([\\\\s\\\\S]*?)<\\\\/${tag}>`);\n const m = re.exec(block);\n return m === null ? null : m[1];\n}\n\nfunction decodeXmlEntities(s: string): string {\n return s\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/"/g, '\"')\n .replace(/'/g, \"'\");\n}\n\nfunction randomSuffix(): string {\n return Math.random().toString(36).slice(2, 10);\n}\n\nasync function safeText(response: Response): Promise<string> {\n try {\n return await response.text();\n } catch {\n return \"\";\n }\n}\n\nfunction wrapError(error: unknown, code: string, provider: string): Error {\n if (error instanceof StorageError) {\n return error;\n }\n return new StorageError(\n `R2 error: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n code,\n provider,\n );\n}\n"],"mappings":"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","names":[]}