@stack0/sdk 0.5.16 → 0.5.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -539,7 +539,12 @@ var CDN = class {
539
539
  return this.http.get(`/cdn/video/${assetId}/stream`);
540
540
  }
541
541
  /**
542
- * Generate a thumbnail from a video at a specific timestamp
542
+ * Get the thumbnail at a specific timestamp, generating it on miss
543
+ *
544
+ * If no thumbnail exists at that timestamp yet, generation is queued
545
+ * automatically and a response with `status: "pending"` (null url) is
546
+ * returned. Poll until `status` is "ready", or use
547
+ * {@link getThumbnailAndWait} to do that for you.
543
548
  *
544
549
  * @example
545
550
  * ```typescript
@@ -549,7 +554,9 @@ var CDN = class {
549
554
  * width: 320,
550
555
  * format: 'webp',
551
556
  * });
552
- * console.log(`Thumbnail URL: ${thumbnail.url}`);
557
+ * if (thumbnail.status === 'ready') {
558
+ * console.log(`Thumbnail URL: ${thumbnail.url}`);
559
+ * }
553
560
  * ```
554
561
  */
555
562
  async getThumbnail(request) {
@@ -559,20 +566,52 @@ var CDN = class {
559
566
  if (request.format) params.set("format", request.format);
560
567
  return this.http.get(`/cdn/video/thumbnail/${request.assetId}?${params.toString()}`);
561
568
  }
569
+ /**
570
+ * Get the thumbnail at a specific timestamp, waiting for generation to complete
571
+ *
572
+ * Calls {@link getThumbnail} and polls until the thumbnail is ready.
573
+ *
574
+ * @example
575
+ * ```typescript
576
+ * const thumbnail = await cdn.getThumbnailAndWait({
577
+ * assetId: 'video-asset-id',
578
+ * timestamp: 3.5,
579
+ * });
580
+ * console.log(`Thumbnail URL: ${thumbnail.url}`);
581
+ * ```
582
+ */
583
+ async getThumbnailAndWait(request, options = {}) {
584
+ const { pollInterval = 1e3, timeout = 6e4 } = options;
585
+ const startTime = Date.now();
586
+ while (true) {
587
+ const thumbnail = await this.getThumbnail(request);
588
+ if (thumbnail.status === "ready") {
589
+ return thumbnail;
590
+ }
591
+ if (Date.now() - startTime >= timeout) {
592
+ throw new Error("Thumbnail generation timed out");
593
+ }
594
+ await new Promise((resolve) => setTimeout(resolve, pollInterval));
595
+ }
596
+ }
562
597
  /**
563
598
  * Regenerate a thumbnail for a video (force regeneration even if one exists)
564
599
  *
565
- * Useful for retrying failed thumbnail generation or regenerating with different settings.
600
+ * Useful for retrying failed thumbnail generation or regenerating with
601
+ * different settings. Regeneration is async: poll {@link getThumbnail} (or
602
+ * use {@link getThumbnailAndWait}) at the same timestamp until the new
603
+ * frame is ready.
566
604
  *
567
605
  * @example
568
606
  * ```typescript
569
- * const result = await cdn.regenerateThumbnail({
607
+ * await cdn.regenerateThumbnail({
570
608
  * assetId: 'video-asset-id',
571
609
  * timestamp: 5, // 5 seconds into the video
572
610
  * width: 1280,
573
611
  * format: 'jpg',
574
612
  * });
575
- * console.log(`Thumbnail regeneration queued: ${result.status}`);
613
+ * const thumbnail = await cdn.getThumbnailAndWait({ assetId: 'video-asset-id', timestamp: 5 });
614
+ * console.log(`Thumbnail URL: ${thumbnail.url}`);
576
615
  * ```
577
616
  */
578
617
  async regenerateThumbnail(request) {
@@ -1023,6 +1062,36 @@ var CDN = class {
1023
1062
  const query = params.toString();
1024
1063
  return this.http.get(`/cdn/usage/storage-breakdown${query ? `?${query}` : ""}`);
1025
1064
  }
1065
+ /**
1066
+ * Get total stored bytes for a project or folder, derived assets included.
1067
+ *
1068
+ * Totals uploads plus everything the pipelines derived from them — video renditions, HLS
1069
+ * segments and manifests, thumbnails, GIFs — in one call. Use this to meter a plan limit:
1070
+ * paging `list()` and summing `size` counts uploads only, and an HLS ladder typically runs
1071
+ * well past the size of the source it came from.
1072
+ *
1073
+ * Check `unmeasuredAssets`. A nonzero value means some assets have derivatives whose bytes
1074
+ * have not been measured, so `totalBytes` is a floor rather than the full number.
1075
+ *
1076
+ * @example
1077
+ * ```typescript
1078
+ * const usage = await cdn.getStorageUsage({
1079
+ * projectSlug: 'my-project',
1080
+ * folder: '/customers/acme',
1081
+ * });
1082
+ * console.log(`${usage.totalFormatted} across ${usage.objectCount} objects`);
1083
+ * console.log(` uploads: ${usage.breakdown.originals.bytesFormatted}`);
1084
+ * console.log(` derived: ${usage.breakdown.derived.bytesFormatted}`);
1085
+ * ```
1086
+ */
1087
+ async getStorageUsage(request = {}) {
1088
+ const params = new URLSearchParams();
1089
+ if (request.projectSlug) params.set("projectSlug", request.projectSlug);
1090
+ if (request.environment) params.set("environment", request.environment);
1091
+ if (request.folder) params.set("folder", request.folder);
1092
+ const query = params.toString();
1093
+ return this.http.get(`/cdn/usage/storage${query ? `?${query}` : ""}`);
1094
+ }
1026
1095
  convertUsageDates(usage) {
1027
1096
  if (typeof usage.periodStart === "string") {
1028
1097
  usage.periodStart = new Date(usage.periodStart);
@@ -1197,6 +1266,33 @@ var CDN = class {
1197
1266
  * });
1198
1267
  * console.log(`Merge job started: ${job.id}`);
1199
1268
  * ```
1269
+ *
1270
+ * @example Composite a screen recording onto a held phone ("POV holding my phone"):
1271
+ * ```typescript
1272
+ * const job = await cdn.createMergeJob({
1273
+ * projectSlug: 'my-project',
1274
+ * inputs: [
1275
+ * { assetId: 'reaction-clip-id' },
1276
+ * {
1277
+ * assetId: 'app-recording-id', // the overlay clip
1278
+ * composite: {
1279
+ * backgroundAssetId: 'holding-phone-shot-id', // image or video
1280
+ * // Corner-pin onto the angled screen (background pixel coords, TL/TR/BL/BR)
1281
+ * quad: {
1282
+ * topLeft: { x: 320, y: 480 },
1283
+ * topRight: { x: 760, y: 500 },
1284
+ * bottomLeft: { x: 300, y: 1400 },
1285
+ * bottomRight: { x: 740, y: 1440 },
1286
+ * },
1287
+ * fit: 'cover',
1288
+ * // Screen area painted #F500FA in the background is keyed out, so the
1289
+ * // recording shows through and fingers over the screen occlude it
1290
+ * chromaKey: { color: '#F500FA', similarity: 0.34, blend: 0.06 },
1291
+ * },
1292
+ * },
1293
+ * ],
1294
+ * });
1295
+ * ```
1200
1296
  */
1201
1297
  async createMergeJob(request) {
1202
1298
  const response = await this.http.post("/cdn/video/merge", request);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/lib/http-client.ts","../../src/cdn/client.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * HTTP client for Stack0 API\n * Handles authentication, request/response formatting, and error handling\n */\n\nexport interface HttpClientConfig {\n apiKey: string;\n baseUrl?: string;\n}\n\nexport class HttpClient {\n private apiKey: string;\n private baseUrl: string;\n\n constructor(config: HttpClientConfig) {\n this.apiKey = config.apiKey;\n this.baseUrl = config.baseUrl || \"https://api.stack0.dev/v1\";\n }\n\n private getHeaders(includeContentType = true): Record<string, string> {\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.apiKey}`,\n };\n if (includeContentType) {\n headers[\"Content-Type\"] = \"application/json\";\n }\n return headers;\n }\n\n async request<T>(method: string, path: string, body?: unknown): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n const bodyString = body === undefined ? undefined : JSON.stringify(body);\n const hasBody = bodyString !== undefined;\n\n try {\n const response = await fetch(url, {\n method,\n headers: this.getHeaders(hasBody),\n body: hasBody ? bodyString : undefined,\n });\n\n if (!response.ok) {\n await this.handleErrorResponse(response);\n }\n\n const data = await response.json();\n return data as T;\n } catch (error) {\n if (error instanceof Error && \"statusCode\" in error) {\n throw error; // Re-throw our custom errors\n }\n throw this.createError(\"Network error\", error);\n }\n }\n\n private async handleErrorResponse(response: Response): Promise<never> {\n let errorBody: { message: string } | undefined;\n try {\n errorBody = (await response.json()) as { message: string };\n } catch {\n errorBody = { message: response.statusText };\n }\n\n const error = new Error(errorBody?.message || `HTTP ${response.status}`) as Error & {\n statusCode: number;\n code: string;\n response: unknown;\n };\n error.statusCode = response.status;\n error.code = (errorBody as unknown as { code: string } | undefined)?.code ?? \"\";\n error.response = errorBody;\n throw error;\n }\n\n private createError(message: string, cause?: unknown): Error {\n const error = new Error(message) as Error & { cause: unknown };\n error.cause = cause;\n return error;\n }\n\n async get<T>(path: string): Promise<T> {\n return this.request<T>(\"GET\", path);\n }\n\n async post<T>(path: string, body: unknown): Promise<T> {\n return this.request<T>(\"POST\", path, body);\n }\n\n async put<T>(path: string, body: unknown): Promise<T> {\n return this.request<T>(\"PUT\", path, body);\n }\n\n async delete<T>(path: string): Promise<T> {\n return this.request<T>(\"DELETE\", path);\n }\n\n async deleteWithBody<T>(path: string, body: unknown): Promise<T> {\n return this.request<T>(\"DELETE\", path, body);\n }\n\n async patch<T>(path: string, body: unknown): Promise<T> {\n return this.request<T>(\"PATCH\", path, body);\n }\n}\n","/**\n * Stack0 CDN Client\n * Upload, manage, and transform assets\n */\n\nimport { HttpClient, type HttpClientConfig } from \"../lib/http-client\";\nimport type {\n Asset,\n UploadUrlRequest,\n UploadUrlResponse,\n UploadFromUrlRequest,\n UpdateAssetRequest,\n DeleteAssetsResponse,\n ListAssetsRequest,\n ListAssetsResponse,\n MoveAssetsRequest,\n MoveAssetsResponse,\n TransformOptions,\n GetFolderTreeRequest,\n FolderTreeNode,\n CreateFolderRequest,\n Folder,\n TranscodeVideoRequest,\n TranscodeJob,\n ListJobsRequest,\n ListJobsResponse,\n StreamingUrls,\n ThumbnailRequest,\n ThumbnailResponse,\n RegenerateThumbnailRequest,\n RegenerateThumbnailResponse,\n ExtractAudioRequest,\n ExtractAudioResponse,\n // Private Files\n PrivateFile,\n PrivateUploadUrlRequest,\n PrivateUploadUrlResponse,\n PrivateDownloadUrlRequest,\n PrivateDownloadUrlResponse,\n ListPrivateFilesRequest,\n ListPrivateFilesResponse,\n UpdatePrivateFileRequest,\n MovePrivateFilesRequest,\n MovePrivateFilesResponse,\n // Bundles\n DownloadBundle,\n CreateBundleRequest,\n CreateBundleResponse,\n ListBundlesRequest,\n ListBundlesResponse,\n BundleDownloadUrlRequest,\n BundleDownloadUrlResponse,\n // Usage\n CdnUsageRequest,\n CdnUsageResponse,\n CdnUsageHistoryRequest,\n CdnUsageHistoryResponse,\n CdnUsageDataPoint,\n CdnStorageBreakdownRequest,\n CdnStorageBreakdownResponse,\n // Additional Folder Types\n UpdateFolderRequest,\n ListFoldersRequest,\n ListFoldersResponse,\n FolderListItem,\n MoveFolderRequest,\n MoveFolderResponse,\n // Additional Video Types\n VideoThumbnail,\n ListThumbnailsResponse,\n // Video Merge Types\n CreateMergeJobRequest,\n MergeJob,\n MergeJobWithOutput,\n ListMergeJobsRequest,\n ListMergeJobsResponse,\n // GIF Generation Types\n GenerateGifRequest,\n VideoGif,\n ListGifsRequest,\n // Image Watermark Types\n ImageWatermarkConfig,\n // Import Types\n CreateImportRequest,\n CreateImportResponse,\n ImportJob,\n ListImportsRequest,\n ListImportsResponse,\n ImportJobSummary,\n CancelImportResponse,\n RetryImportResponse,\n ListImportFilesRequest,\n ListImportFilesResponse,\n ImportFile,\n} from \"./types\";\n\n// Allowed widths that match the CloudFront url-rewriter configuration\nconst ALLOWED_WIDTHS = [256, 384, 640, 750, 828, 1080, 1200, 1920, 2048, 3840];\n\nexport class CDN {\n private http: HttpClient;\n private cdnUrl?: string;\n\n constructor(config: HttpClientConfig, cdnUrl?: string) {\n this.http = new HttpClient(config);\n this.cdnUrl = cdnUrl;\n }\n\n /**\n * Generate a presigned URL for uploading a file\n *\n * @example\n * ```typescript\n * const { uploadUrl, assetId } = await cdn.getUploadUrl({\n * projectSlug: 'my-project',\n * filename: 'image.jpg',\n * mimeType: 'image/jpeg',\n * size: 1024 * 1024,\n * });\n *\n * // Upload file to the presigned URL\n * await fetch(uploadUrl, {\n * method: 'PUT',\n * body: file,\n * headers: { 'Content-Type': 'image/jpeg' },\n * });\n *\n * // Confirm the upload\n * const asset = await cdn.confirmUpload(assetId);\n * ```\n */\n async getUploadUrl(request: UploadUrlRequest): Promise<UploadUrlResponse> {\n const response = await this.http.post<UploadUrlResponse>(\"/cdn/upload\", request);\n\n if (typeof response.expiresAt === \"string\") {\n response.expiresAt = new Date(response.expiresAt);\n }\n\n return response;\n }\n\n /**\n * Confirm that an upload has completed\n */\n async confirmUpload(assetId: string): Promise<Asset> {\n const response = await this.http.post<Asset>(`/cdn/upload/${assetId}/confirm`, {});\n return this.convertAssetDates(response);\n }\n\n /**\n * Upload a file directly (handles presigned URL flow automatically)\n *\n * @example\n * ```typescript\n * const asset = await cdn.upload({\n * projectSlug: 'my-project',\n * file: fileBuffer,\n * filename: 'image.jpg',\n * mimeType: 'image/jpeg',\n * });\n *\n * // With watermark\n * const watermarkedAsset = await cdn.upload({\n * projectSlug: 'my-project',\n * file: fileBuffer,\n * filename: 'photo.jpg',\n * mimeType: 'image/jpeg',\n * watermark: {\n * assetId: 'logo-asset-id', // or url: 'https://example.com/logo.png'\n * position: 'bottom-right',\n * opacity: 50,\n * sizingMode: 'relative',\n * width: 15, // 15% of image width\n * },\n * });\n * ```\n */\n async upload(options: {\n projectSlug: string;\n file: Blob | Buffer | ArrayBuffer;\n filename: string;\n mimeType: string;\n folder?: string;\n metadata?: Record<string, unknown>;\n /** Watermark configuration for images (applied during upload processing) */\n watermark?: ImageWatermarkConfig;\n }): Promise<Asset> {\n const { projectSlug, file, filename, mimeType, folder, metadata, watermark } = options;\n\n // Get file size\n let size: number;\n if (file instanceof Blob) {\n size = file.size;\n } else if (file instanceof ArrayBuffer) {\n size = file.byteLength;\n } else {\n // Buffer\n size = (file as Buffer).length;\n }\n\n // Get presigned URL\n const { uploadUrl, assetId } = await this.getUploadUrl({\n projectSlug,\n filename,\n mimeType,\n size,\n folder,\n metadata,\n watermark,\n });\n\n // Upload file\n const uploadResponse = await fetch(uploadUrl, {\n method: \"PUT\",\n body: file,\n headers: {\n \"Content-Type\": mimeType,\n },\n });\n\n if (!uploadResponse.ok) {\n throw new Error(`Upload failed: ${uploadResponse.statusText}`);\n }\n\n // Confirm upload\n return this.confirmUpload(assetId);\n }\n\n /**\n * Upload a file from a remote URL (server-side fetch).\n * The server streams the file directly from the source URL into storage,\n * so the client never touches the bytes. Ideal for serverless environments\n * with tight memory limits.\n *\n * @example\n * ```typescript\n * const asset = await cdn.uploadFromUrl({\n * projectSlug: 'my-project',\n * sourceUrl: 'https://replicate.delivery/output/video.mp4',\n * filename: 'video.mp4',\n * mimeType: 'video/mp4',\n * });\n * console.log(asset.cdnUrl);\n * ```\n */\n async uploadFromUrl(request: UploadFromUrlRequest): Promise<Asset> {\n const response = await this.http.post<Asset>(\"/cdn/upload-from-url\", request);\n return this.convertAssetDates(response);\n }\n\n /**\n * Get an asset by ID\n *\n * @example\n * ```typescript\n * const asset = await cdn.get('asset-id');\n * console.log(asset.cdnUrl);\n * ```\n */\n async get(id: string): Promise<Asset> {\n const response = await this.http.get<Asset>(`/cdn/assets/${id}`);\n return this.convertAssetDates(response);\n }\n\n /**\n * Update asset metadata\n *\n * @example\n * ```typescript\n * const asset = await cdn.update({\n * id: 'asset-id',\n * alt: 'A beautiful sunset',\n * tags: ['nature', 'sunset'],\n * });\n * ```\n */\n async update(request: UpdateAssetRequest): Promise<Asset> {\n const { id, ...data } = request;\n const response = await this.http.patch<Asset>(`/cdn/assets/${id}`, data);\n return this.convertAssetDates(response);\n }\n\n /**\n * Delete an asset\n *\n * @example\n * ```typescript\n * await cdn.delete('asset-id');\n * ```\n */\n async delete(id: string): Promise<{ success: boolean }> {\n // NOTE: Our OpenAPI adapter parses JSON bodies for non-GET methods.\n // Some Fastify setups will throw if Content-Type is JSON but the body is empty.\n // Sending the id in the body keeps this endpoint compatible across adapters.\n return this.http.deleteWithBody<{ success: boolean }>(`/cdn/assets/${id}`, { id });\n }\n\n /**\n * Delete multiple assets\n *\n * @example\n * ```typescript\n * const result = await cdn.deleteMany(['asset-1', 'asset-2']);\n * console.log(`Deleted ${result.deletedCount} assets`);\n * ```\n */\n async deleteMany(ids: string[]): Promise<DeleteAssetsResponse> {\n return this.http.post<DeleteAssetsResponse>(\"/cdn/assets/delete\", { ids });\n }\n\n /**\n * List assets with filters and pagination\n *\n * @example\n * ```typescript\n * const { assets, total, hasMore } = await cdn.list({\n * projectSlug: 'my-project',\n * type: 'image',\n * limit: 20,\n * });\n * ```\n */\n async list(request: ListAssetsRequest): Promise<ListAssetsResponse> {\n const params = new URLSearchParams();\n\n params.set(\"projectSlug\", request.projectSlug);\n if (request.folder !== undefined) params.set(\"folder\", request.folder ?? \"\");\n if (request.type) params.set(\"type\", request.type);\n if (request.status) params.set(\"status\", request.status);\n if (request.search) params.set(\"search\", request.search);\n if (request.tags) params.set(\"tags\", request.tags.join(\",\"));\n if (request.sortBy) params.set(\"sortBy\", request.sortBy);\n if (request.sortOrder) params.set(\"sortOrder\", request.sortOrder);\n if (request.limit) params.set(\"limit\", request.limit.toString());\n if (request.offset) params.set(\"offset\", request.offset.toString());\n\n const response = await this.http.get<ListAssetsResponse>(`/cdn/assets?${params.toString()}`);\n\n return {\n ...response,\n assets: response.assets.map((asset) => this.convertAssetDates(asset)),\n };\n }\n\n /**\n * Move assets to a different folder\n *\n * @example\n * ```typescript\n * await cdn.move({\n * assetIds: ['asset-1', 'asset-2'],\n * folder: '/images/archive',\n * });\n * ```\n */\n async move(request: MoveAssetsRequest): Promise<MoveAssetsResponse> {\n return this.http.post<MoveAssetsResponse>(\"/cdn/assets/move\", request);\n }\n\n /**\n * Get a transformed image URL (client-side, no API call)\n *\n * @example\n * ```typescript\n * // Using asset's cdnUrl directly\n * const url = cdn.getTransformUrl(asset.cdnUrl, {\n * width: 800,\n * height: 600,\n * fit: 'cover',\n * format: 'webp',\n * quality: 80,\n * });\n *\n * // Or using cdnUrl from SDK config + s3Key\n * const url = cdn.getTransformUrl(asset.s3Key, { width: 400 });\n * ```\n */\n getTransformUrl(assetUrlOrS3Key: string, options: TransformOptions): string {\n // Determine base URL\n let baseUrl: string;\n if (assetUrlOrS3Key.startsWith(\"http://\") || assetUrlOrS3Key.startsWith(\"https://\")) {\n // It's already a full URL - extract base and path\n const url = new URL(assetUrlOrS3Key);\n baseUrl = `${url.protocol}//${url.host}${url.pathname}`;\n } else if (this.cdnUrl) {\n // It's an s3Key, use configured CDN URL\n const cdnBase = this.cdnUrl.endsWith(\"/\") ? this.cdnUrl.slice(0, -1) : this.cdnUrl;\n baseUrl = `${cdnBase}/${assetUrlOrS3Key}`;\n } else {\n throw new Error(\"getTransformUrl requires either a full URL or cdnUrl to be configured in Stack0 options\");\n }\n\n // Build query string\n const params = this.buildTransformQuery(options);\n if (!params) {\n return baseUrl;\n }\n return `${baseUrl}?${params}`;\n }\n\n /**\n * Build transform query parameters\n */\n private buildTransformQuery(options: TransformOptions): string {\n const params = new URLSearchParams();\n\n if (options.format) params.set(\"f\", options.format);\n if (options.quality !== undefined) params.set(\"q\", options.quality.toString());\n\n if (options.width !== undefined) {\n // Snap to nearest allowed width for better caching\n const width = this.getNearestWidth(options.width);\n params.set(\"w\", width.toString());\n }\n if (options.height !== undefined) params.set(\"h\", options.height.toString());\n if (options.fit) params.set(\"fit\", options.fit);\n if (options.crop) params.set(\"crop\", options.crop);\n if (options.cropX !== undefined) params.set(\"crop-x\", options.cropX.toString());\n if (options.cropY !== undefined) params.set(\"crop-y\", options.cropY.toString());\n if (options.cropWidth !== undefined) params.set(\"crop-w\", options.cropWidth.toString());\n if (options.cropHeight !== undefined) params.set(\"crop-h\", options.cropHeight.toString());\n if (options.blur !== undefined) params.set(\"blur\", options.blur.toString());\n if (options.sharpen !== undefined) params.set(\"sharpen\", options.sharpen.toString());\n if (options.brightness !== undefined) params.set(\"brightness\", options.brightness.toString());\n if (options.saturation !== undefined) params.set(\"saturation\", options.saturation.toString());\n if (options.grayscale) params.set(\"grayscale\", \"true\");\n if (options.rotate !== undefined) params.set(\"rotate\", options.rotate.toString());\n if (options.flip) params.set(\"flip\", \"y\");\n if (options.flop) params.set(\"flop\", \"x\");\n\n return params.toString();\n }\n\n /**\n * Find the nearest allowed width for optimal caching\n */\n private getNearestWidth(width: number): number {\n return ALLOWED_WIDTHS.reduce((prev, curr) => (Math.abs(curr - width) < Math.abs(prev - width) ? curr : prev));\n }\n\n /**\n * Get folder tree for navigation\n *\n * @example\n * ```typescript\n * const tree = await cdn.getFolderTree({\n * projectSlug: 'my-project',\n * maxDepth: 3,\n * });\n * ```\n */\n async getFolderTree(request: GetFolderTreeRequest): Promise<FolderTreeNode[]> {\n const params = new URLSearchParams();\n params.set(\"projectSlug\", request.projectSlug);\n if (request.maxDepth) params.set(\"maxDepth\", request.maxDepth.toString());\n\n const response = await this.http.get<{ tree: FolderTreeNode[] }>(`/cdn/folders/tree?${params.toString()}`);\n return response.tree;\n }\n\n /**\n * Create a new folder\n *\n * @example\n * ```typescript\n * const folder = await cdn.createFolder({\n * projectSlug: 'my-project',\n * name: 'images',\n * });\n * ```\n */\n async createFolder(request: CreateFolderRequest): Promise<Folder> {\n const response = await this.http.post<Folder>(\"/cdn/folders\", request);\n return this.convertFolderDates(response);\n }\n\n /**\n * Delete a folder\n *\n * @example\n * ```typescript\n * await cdn.deleteFolder('folder-id');\n * ```\n */\n async deleteFolder(id: string, deleteContents = false): Promise<{ success: boolean }> {\n const params = new URLSearchParams();\n if (deleteContents) params.set(\"deleteContents\", \"true\");\n\n return this.http.deleteWithBody<{ success: boolean }>(`/cdn/folders/${id}?${params.toString()}`, {\n id,\n deleteContents,\n });\n }\n\n private convertAssetDates(asset: Asset): Asset {\n if (typeof asset.createdAt === \"string\") {\n asset.createdAt = new Date(asset.createdAt);\n }\n if (asset.updatedAt && typeof asset.updatedAt === \"string\") {\n asset.updatedAt = new Date(asset.updatedAt);\n }\n return asset;\n }\n\n private convertFolderDates(folder: Folder): Folder {\n if (typeof folder.createdAt === \"string\") {\n folder.createdAt = new Date(folder.createdAt);\n }\n if (folder.updatedAt && typeof folder.updatedAt === \"string\") {\n folder.updatedAt = new Date(folder.updatedAt);\n }\n return folder;\n }\n\n // ============================================================================\n // Video Transcoding Methods\n // ============================================================================\n\n /**\n * Start a video transcoding job\n *\n * @example\n * ```typescript\n * const job = await cdn.transcode({\n * projectSlug: 'my-project',\n * assetId: 'video-asset-id',\n * outputFormat: 'hls',\n * variants: [\n * { quality: '720p', codec: 'h264' },\n * { quality: '1080p', codec: 'h264' },\n * ],\n * webhookUrl: 'https://your-app.com/webhook',\n * });\n * console.log(`Job started: ${job.id}`);\n * ```\n *\n * @example Burn in a logo watermark (same config shape as image watermarks)\n * ```typescript\n * const job = await cdn.transcode({\n * projectSlug: 'my-project',\n * assetId: 'video-asset-id',\n * outputFormat: 'mp4',\n * variants: [{ quality: '1080p', codec: 'h264' }],\n * watermark: {\n * assetId: 'logo-asset-id',\n * position: 'bottom-right',\n * scale: 15, // 15% of the video width\n * opacity: 80,\n * },\n * });\n * ```\n */\n async transcode(request: TranscodeVideoRequest): Promise<TranscodeJob> {\n const response = await this.http.post<TranscodeJob>(\"/cdn/video/transcode\", request);\n return this.convertJobDates(response);\n }\n\n /**\n * Get a transcoding job by ID\n *\n * @example\n * ```typescript\n * const job = await cdn.getJob('job-id');\n * console.log(`Status: ${job.status}, Progress: ${job.progress}%`);\n * if (job.status === 'failed') console.error(job.errorMessage);\n * ```\n */\n async getJob(jobId: string): Promise<TranscodeJob> {\n const response = await this.http.get<TranscodeJob>(`/cdn/video/jobs/${jobId}`);\n return this.convertJobDates(response);\n }\n\n /**\n * List transcoding jobs with filters\n *\n * @example\n * ```typescript\n * const { jobs, total } = await cdn.listJobs({\n * projectSlug: 'my-project',\n * status: 'processing',\n * limit: 20,\n * });\n * ```\n */\n async listJobs(request: ListJobsRequest): Promise<ListJobsResponse> {\n const params = new URLSearchParams();\n params.set(\"projectSlug\", request.projectSlug);\n if (request.assetId) params.set(\"assetId\", request.assetId);\n if (request.status) params.set(\"status\", request.status);\n if (request.limit) params.set(\"limit\", request.limit.toString());\n if (request.offset) params.set(\"offset\", request.offset.toString());\n\n const response = await this.http.get<ListJobsResponse>(`/cdn/video/jobs?${params.toString()}`);\n return {\n ...response,\n jobs: response.jobs.map((job) => this.convertJobDates(job)),\n };\n }\n\n /**\n * Cancel a pending or processing transcoding job\n *\n * @example\n * ```typescript\n * await cdn.cancelJob('job-id');\n * ```\n */\n async cancelJob(jobId: string): Promise<{ success: boolean }> {\n return this.http.post<{ success: boolean }>(`/cdn/video/jobs/${jobId}/cancel`, {});\n }\n\n /**\n * Get streaming URLs for a transcoded video\n *\n * @example\n * ```typescript\n * const urls = await cdn.getStreamingUrls('asset-id');\n * console.log(`HLS URL: ${urls.hlsUrl}`);\n * console.log(`MP4 720p: ${urls.mp4Urls.find(u => u.quality === '720p')?.url}`);\n * ```\n */\n async getStreamingUrls(assetId: string): Promise<StreamingUrls> {\n return this.http.get<StreamingUrls>(`/cdn/video/${assetId}/stream`);\n }\n\n /**\n * Generate a thumbnail from a video at a specific timestamp\n *\n * @example\n * ```typescript\n * const thumbnail = await cdn.getThumbnail({\n * assetId: 'video-asset-id',\n * timestamp: 10.5, // 10.5 seconds into the video\n * width: 320,\n * format: 'webp',\n * });\n * console.log(`Thumbnail URL: ${thumbnail.url}`);\n * ```\n */\n async getThumbnail(request: ThumbnailRequest): Promise<ThumbnailResponse> {\n const params = new URLSearchParams();\n params.set(\"timestamp\", request.timestamp.toString());\n if (request.width) params.set(\"width\", request.width.toString());\n if (request.format) params.set(\"format\", request.format);\n\n return this.http.get<ThumbnailResponse>(`/cdn/video/thumbnail/${request.assetId}?${params.toString()}`);\n }\n\n /**\n * Regenerate a thumbnail for a video (force regeneration even if one exists)\n *\n * Useful for retrying failed thumbnail generation or regenerating with different settings.\n *\n * @example\n * ```typescript\n * const result = await cdn.regenerateThumbnail({\n * assetId: 'video-asset-id',\n * timestamp: 5, // 5 seconds into the video\n * width: 1280,\n * format: 'jpg',\n * });\n * console.log(`Thumbnail regeneration queued: ${result.status}`);\n * ```\n */\n async regenerateThumbnail(request: RegenerateThumbnailRequest): Promise<RegenerateThumbnailResponse> {\n return this.http.post<RegenerateThumbnailResponse>(\"/cdn/video/thumbnail/regenerate\", request);\n }\n\n /**\n * Extract audio from a video file\n *\n * @example\n * ```typescript\n * const { jobId } = await cdn.extractAudio({\n * projectSlug: 'my-project',\n * assetId: 'video-asset-id',\n * format: 'mp3',\n * bitrate: 192,\n * });\n * ```\n */\n async extractAudio(request: ExtractAudioRequest): Promise<ExtractAudioResponse> {\n return this.http.post<ExtractAudioResponse>(\"/cdn/video/extract-audio\", request);\n }\n\n // ============================================================================\n // GIF Generation Methods\n // ============================================================================\n\n /**\n * Generate an animated GIF from a video segment\n *\n * Creates an optimized GIF from a portion of the video. Uses two-pass\n * palette generation by default for smaller file sizes with better quality.\n *\n * @example\n * ```typescript\n * const gif = await cdn.generateGif({\n * projectSlug: 'my-project',\n * assetId: 'video-asset-id',\n * startTime: 5, // Start at 5 seconds\n * duration: 3, // 3 second GIF\n * width: 480, // 480px wide\n * fps: 10, // 10 frames per second\n * });\n *\n * // Poll for completion\n * let result = await cdn.getGif(gif.id);\n * while (result?.status === 'pending' || result?.status === 'processing') {\n * await new Promise(r => setTimeout(r, 1000));\n * result = await cdn.getGif(gif.id);\n * }\n *\n * console.log(`GIF URL: ${result?.url}`);\n * ```\n */\n async generateGif(request: GenerateGifRequest): Promise<VideoGif> {\n const response = await this.http.post<VideoGif>(\"/cdn/video/gif\", request);\n return this.convertGifDates(response);\n }\n\n /**\n * Get a specific GIF by ID\n *\n * @example\n * ```typescript\n * const gif = await cdn.getGif('gif-id');\n * if (gif?.status === 'completed') {\n * console.log(`GIF URL: ${gif.url}`);\n * console.log(`Size: ${gif.sizeBytes} bytes`);\n * }\n * ```\n */\n async getGif(gifId: string): Promise<VideoGif | null> {\n const response = await this.http.get<VideoGif | null>(`/cdn/video/gif/${gifId}`);\n return response ? this.convertGifDates(response) : null;\n }\n\n /**\n * List all GIFs generated for a video asset\n *\n * @example\n * ```typescript\n * const gifs = await cdn.listGifs({ assetId: 'video-asset-id' });\n * for (const gif of gifs) {\n * console.log(`GIF at ${gif.startTime}s: ${gif.url}`);\n * }\n * ```\n */\n async listGifs(request: ListGifsRequest): Promise<VideoGif[]> {\n const response = await this.http.get<VideoGif[]>(`/cdn/video/${request.assetId}/gifs`);\n return response.map((gif) => this.convertGifDates(gif));\n }\n\n private convertGifDates(gif: VideoGif): VideoGif {\n if (typeof gif.createdAt === \"string\") {\n gif.createdAt = new Date(gif.createdAt);\n }\n if (gif.completedAt && typeof gif.completedAt === \"string\") {\n gif.completedAt = new Date(gif.completedAt);\n }\n return gif;\n }\n\n private convertJobDates(job: TranscodeJob): TranscodeJob {\n if (typeof job.createdAt === \"string\") {\n job.createdAt = new Date(job.createdAt);\n }\n if (job.startedAt && typeof job.startedAt === \"string\") {\n job.startedAt = new Date(job.startedAt);\n }\n if (job.completedAt && typeof job.completedAt === \"string\") {\n job.completedAt = new Date(job.completedAt);\n }\n return job;\n }\n\n // ============================================================================\n // Private Files Methods\n // ============================================================================\n\n /**\n * Generate a presigned URL for uploading a private file\n *\n * Private files are stored securely and can only be accessed through\n * authorized download links with configurable expiration.\n *\n * @example\n * ```typescript\n * const { uploadUrl, fileId } = await cdn.getPrivateUploadUrl({\n * projectSlug: 'my-project',\n * filename: 'confidential.pdf',\n * mimeType: 'application/pdf',\n * size: 1024 * 1024,\n * });\n *\n * // Upload file to the presigned URL\n * await fetch(uploadUrl, {\n * method: 'PUT',\n * body: file,\n * headers: { 'Content-Type': 'application/pdf' },\n * });\n *\n * // Confirm the upload\n * const privateFile = await cdn.confirmPrivateUpload(fileId);\n * ```\n */\n async getPrivateUploadUrl(request: PrivateUploadUrlRequest): Promise<PrivateUploadUrlResponse> {\n const response = await this.http.post<PrivateUploadUrlResponse>(\"/cdn/private/upload\", request);\n\n if (typeof response.expiresAt === \"string\") {\n response.expiresAt = new Date(response.expiresAt);\n }\n\n return response;\n }\n\n /**\n * Confirm that a private file upload has completed\n */\n async confirmPrivateUpload(fileId: string): Promise<PrivateFile> {\n const response = await this.http.post<PrivateFile>(`/cdn/private/upload/${fileId}/confirm`, {});\n return this.convertPrivateFileDates(response);\n }\n\n /**\n * Upload a private file directly (handles presigned URL flow automatically)\n *\n * @example\n * ```typescript\n * const privateFile = await cdn.uploadPrivate({\n * projectSlug: 'my-project',\n * file: fileBuffer,\n * filename: 'confidential.pdf',\n * mimeType: 'application/pdf',\n * });\n * ```\n */\n async uploadPrivate(options: {\n projectSlug: string;\n file: Blob | Buffer | ArrayBuffer;\n filename: string;\n mimeType: string;\n folder?: string;\n description?: string;\n metadata?: Record<string, unknown>;\n }): Promise<PrivateFile> {\n const { projectSlug, file, filename, mimeType, folder, description, metadata } = options;\n\n // Get file size\n let size: number;\n if (file instanceof Blob) {\n size = file.size;\n } else if (file instanceof ArrayBuffer) {\n size = file.byteLength;\n } else {\n size = (file as Buffer).length;\n }\n\n // Get presigned URL\n const { uploadUrl, fileId } = await this.getPrivateUploadUrl({\n projectSlug,\n filename,\n mimeType,\n size,\n folder,\n description,\n metadata,\n });\n\n // Upload file\n const uploadResponse = await fetch(uploadUrl, {\n method: \"PUT\",\n body: file,\n headers: {\n \"Content-Type\": mimeType,\n },\n });\n\n if (!uploadResponse.ok) {\n throw new Error(`Upload failed: ${uploadResponse.statusText}`);\n }\n\n // Confirm upload\n return this.confirmPrivateUpload(fileId);\n }\n\n /**\n * Generate a presigned download URL for a private file\n *\n * @example\n * ```typescript\n * const { downloadUrl, expiresAt } = await cdn.getPrivateDownloadUrl({\n * fileId: 'file-id',\n * expiresIn: 86400, // 24 hours\n * });\n * ```\n */\n async getPrivateDownloadUrl(request: PrivateDownloadUrlRequest): Promise<PrivateDownloadUrlResponse> {\n const response = await this.http.post<PrivateDownloadUrlResponse>(`/cdn/private/${request.fileId}/download`, {\n expiresIn: request.expiresIn,\n });\n\n if (typeof response.expiresAt === \"string\") {\n response.expiresAt = new Date(response.expiresAt);\n }\n\n return response;\n }\n\n /**\n * Get a private file by ID\n */\n async getPrivateFile(fileId: string): Promise<PrivateFile> {\n const response = await this.http.get<PrivateFile>(`/cdn/private/${fileId}`);\n return this.convertPrivateFileDates(response);\n }\n\n /**\n * Update a private file's metadata\n */\n async updatePrivateFile(request: UpdatePrivateFileRequest): Promise<PrivateFile> {\n const { fileId, ...data } = request;\n const response = await this.http.patch<PrivateFile>(`/cdn/private/${fileId}`, data);\n return this.convertPrivateFileDates(response);\n }\n\n /**\n * Delete a private file\n */\n async deletePrivateFile(fileId: string): Promise<{ success: boolean }> {\n return this.http.deleteWithBody<{ success: boolean }>(`/cdn/private/${fileId}`, { fileId });\n }\n\n /**\n * Delete multiple private files\n */\n async deletePrivateFiles(fileIds: string[]): Promise<{ success: boolean; deletedCount: number }> {\n return this.http.post<{ success: boolean; deletedCount: number }>(\"/cdn/private/delete\", { fileIds });\n }\n\n /**\n * List private files with filters and pagination\n *\n * @example\n * ```typescript\n * const { files, total, hasMore } = await cdn.listPrivateFiles({\n * projectSlug: 'my-project',\n * limit: 20,\n * });\n * ```\n */\n async listPrivateFiles(request: ListPrivateFilesRequest): Promise<ListPrivateFilesResponse> {\n const params = new URLSearchParams();\n\n params.set(\"projectSlug\", request.projectSlug);\n if (request.folder !== undefined) params.set(\"folder\", request.folder ?? \"\");\n if (request.status) params.set(\"status\", request.status);\n if (request.search) params.set(\"search\", request.search);\n if (request.sortBy) params.set(\"sortBy\", request.sortBy);\n if (request.sortOrder) params.set(\"sortOrder\", request.sortOrder);\n if (request.limit) params.set(\"limit\", request.limit.toString());\n if (request.offset) params.set(\"offset\", request.offset.toString());\n\n const response = await this.http.get<ListPrivateFilesResponse>(`/cdn/private?${params.toString()}`);\n\n return {\n ...response,\n files: response.files.map((file) => this.convertPrivateFileDates(file)),\n };\n }\n\n private convertPrivateFileDates(file: PrivateFile): PrivateFile {\n if (typeof file.createdAt === \"string\") {\n file.createdAt = new Date(file.createdAt);\n }\n if (file.updatedAt && typeof file.updatedAt === \"string\") {\n file.updatedAt = new Date(file.updatedAt);\n }\n return file;\n }\n\n // ============================================================================\n // Download Bundle Methods\n // ============================================================================\n\n /**\n * Create a download bundle from assets and/or private files\n *\n * The bundle will be created asynchronously. Check the status using getBundle().\n *\n * @example\n * ```typescript\n * const { bundle } = await cdn.createBundle({\n * projectSlug: 'my-project',\n * name: 'Project Assets - Dec 2024',\n * assetIds: ['asset-1', 'asset-2'],\n * privateFileIds: ['file-1', 'file-2'],\n * expiresIn: 86400, // 24 hours\n * });\n * console.log(`Bundle ${bundle.id} status: ${bundle.status}`);\n * ```\n */\n async createBundle(request: CreateBundleRequest): Promise<CreateBundleResponse> {\n const response = await this.http.post<CreateBundleResponse>(\"/cdn/bundles\", request);\n return {\n bundle: this.convertBundleDates(response.bundle),\n };\n }\n\n /**\n * Get a download bundle by ID\n */\n async getBundle(bundleId: string): Promise<DownloadBundle> {\n const response = await this.http.get<DownloadBundle>(`/cdn/bundles/${bundleId}`);\n return this.convertBundleDates(response);\n }\n\n /**\n * List download bundles with filters and pagination\n *\n * @example\n * ```typescript\n * const { bundles, total } = await cdn.listBundles({\n * projectSlug: 'my-project',\n * status: 'ready',\n * });\n * ```\n */\n async listBundles(request: ListBundlesRequest): Promise<ListBundlesResponse> {\n const params = new URLSearchParams();\n\n params.set(\"projectSlug\", request.projectSlug);\n if (request.status) params.set(\"status\", request.status);\n if (request.search) params.set(\"search\", request.search);\n if (request.limit) params.set(\"limit\", request.limit.toString());\n if (request.offset) params.set(\"offset\", request.offset.toString());\n\n const response = await this.http.get<ListBundlesResponse>(`/cdn/bundles?${params.toString()}`);\n\n return {\n ...response,\n bundles: response.bundles.map((bundle) => this.convertBundleDates(bundle)),\n };\n }\n\n /**\n * Generate a presigned download URL for a bundle\n *\n * @example\n * ```typescript\n * const { downloadUrl, expiresAt } = await cdn.getBundleDownloadUrl({\n * bundleId: 'bundle-id',\n * expiresIn: 3600, // 1 hour\n * });\n * ```\n */\n async getBundleDownloadUrl(request: BundleDownloadUrlRequest): Promise<BundleDownloadUrlResponse> {\n const response = await this.http.post<BundleDownloadUrlResponse>(`/cdn/bundles/${request.bundleId}/download`, {\n expiresIn: request.expiresIn,\n });\n\n if (typeof response.expiresAt === \"string\") {\n response.expiresAt = new Date(response.expiresAt);\n }\n\n return response;\n }\n\n /**\n * Delete a download bundle\n */\n async deleteBundle(bundleId: string): Promise<{ success: boolean }> {\n return this.http.deleteWithBody<{ success: boolean }>(`/cdn/bundles/${bundleId}`, { bundleId });\n }\n\n private convertBundleDates(bundle: DownloadBundle): DownloadBundle {\n if (typeof bundle.createdAt === \"string\") {\n bundle.createdAt = new Date(bundle.createdAt);\n }\n if (bundle.completedAt && typeof bundle.completedAt === \"string\") {\n bundle.completedAt = new Date(bundle.completedAt);\n }\n if (bundle.expiresAt && typeof bundle.expiresAt === \"string\") {\n bundle.expiresAt = new Date(bundle.expiresAt);\n }\n return bundle;\n }\n\n // ============================================================================\n // Usage Methods\n // ============================================================================\n\n /**\n * Get current usage stats for the billing period\n *\n * @example\n * ```typescript\n * const usage = await cdn.getUsage({\n * projectSlug: 'my-project',\n * });\n * console.log(`Bandwidth: ${usage.bandwidthFormatted}`);\n * console.log(`Estimated cost: ${usage.estimatedCostFormatted}`);\n * ```\n */\n async getUsage(request: CdnUsageRequest = {}): Promise<CdnUsageResponse> {\n const params = new URLSearchParams();\n if (request.projectSlug) params.set(\"projectSlug\", request.projectSlug);\n if (request.environment) params.set(\"environment\", request.environment);\n if (request.periodStart) {\n const date = request.periodStart instanceof Date ? request.periodStart.toISOString() : request.periodStart;\n params.set(\"periodStart\", date);\n }\n if (request.periodEnd) {\n const date = request.periodEnd instanceof Date ? request.periodEnd.toISOString() : request.periodEnd;\n params.set(\"periodEnd\", date);\n }\n\n const query = params.toString();\n const response = await this.http.get<CdnUsageResponse>(`/cdn/usage${query ? `?${query}` : \"\"}`);\n return this.convertUsageDates(response);\n }\n\n /**\n * Get usage history (time series data for charts)\n *\n * @example\n * ```typescript\n * const history = await cdn.getUsageHistory({\n * projectSlug: 'my-project',\n * days: 30,\n * });\n * console.log(`Total requests: ${history.totals.requests}`);\n * ```\n */\n async getUsageHistory(request: CdnUsageHistoryRequest = {}): Promise<CdnUsageHistoryResponse> {\n const params = new URLSearchParams();\n if (request.projectSlug) params.set(\"projectSlug\", request.projectSlug);\n if (request.environment) params.set(\"environment\", request.environment);\n if (request.days) params.set(\"days\", request.days.toString());\n if (request.granularity) params.set(\"granularity\", request.granularity);\n\n const query = params.toString();\n const response = await this.http.get<CdnUsageHistoryResponse>(`/cdn/usage/history${query ? `?${query}` : \"\"}`);\n\n return {\n ...response,\n data: response.data.map((point) => this.convertUsageDataPointDates(point)),\n };\n }\n\n /**\n * Get storage breakdown by type or folder\n *\n * @example\n * ```typescript\n * const breakdown = await cdn.getStorageBreakdown({\n * projectSlug: 'my-project',\n * groupBy: 'type',\n * });\n * breakdown.items.forEach(item => {\n * console.log(`${item.key}: ${item.sizeFormatted} (${item.percentage}%)`);\n * });\n * ```\n */\n async getStorageBreakdown(request: CdnStorageBreakdownRequest = {}): Promise<CdnStorageBreakdownResponse> {\n const params = new URLSearchParams();\n if (request.projectSlug) params.set(\"projectSlug\", request.projectSlug);\n if (request.environment) params.set(\"environment\", request.environment);\n if (request.groupBy) params.set(\"groupBy\", request.groupBy);\n\n const query = params.toString();\n return this.http.get<CdnStorageBreakdownResponse>(`/cdn/usage/storage-breakdown${query ? `?${query}` : \"\"}`);\n }\n\n private convertUsageDates(usage: CdnUsageResponse): CdnUsageResponse {\n if (typeof usage.periodStart === \"string\") {\n usage.periodStart = new Date(usage.periodStart);\n }\n if (typeof usage.periodEnd === \"string\") {\n usage.periodEnd = new Date(usage.periodEnd);\n }\n return usage;\n }\n\n private convertUsageDataPointDates(point: CdnUsageDataPoint): CdnUsageDataPoint {\n if (typeof point.timestamp === \"string\") {\n point.timestamp = new Date(point.timestamp);\n }\n return point;\n }\n\n // ============================================================================\n // Additional Folder Methods\n // ============================================================================\n\n /**\n * Get a folder by ID\n *\n * @example\n * ```typescript\n * const folder = await cdn.getFolder('folder-id');\n * console.log(`Folder: ${folder.name}, Assets: ${folder.assetCount}`);\n * ```\n */\n async getFolder(id: string): Promise<Folder> {\n const response = await this.http.get<Folder>(`/cdn/folders/${id}`);\n return this.convertFolderDates(response);\n }\n\n /**\n * Get a folder by its path\n *\n * @example\n * ```typescript\n * const folder = await cdn.getFolderByPath('/images/avatars');\n * ```\n */\n async getFolderByPath(path: string): Promise<Folder> {\n const encodedPath = encodeURIComponent(path);\n const response = await this.http.get<Folder>(`/cdn/folders/path/${encodedPath}`);\n return this.convertFolderDates(response);\n }\n\n /**\n * Update a folder's name\n *\n * @example\n * ```typescript\n * const folder = await cdn.updateFolder({\n * id: 'folder-id',\n * name: 'New Folder Name',\n * });\n * ```\n */\n async updateFolder(request: UpdateFolderRequest): Promise<Folder> {\n const { id, ...data } = request;\n const response = await this.http.patch<Folder>(`/cdn/folders/${id}`, data);\n return this.convertFolderDates(response);\n }\n\n /**\n * List folders with optional filters\n *\n * @example\n * ```typescript\n * const { folders, total } = await cdn.listFolders({\n * parentId: null, // root level\n * limit: 50,\n * });\n * ```\n */\n async listFolders(request: ListFoldersRequest = {}): Promise<ListFoldersResponse> {\n const params = new URLSearchParams();\n if (request.parentId !== undefined) params.set(\"parentId\", request.parentId ?? \"\");\n if (request.limit) params.set(\"limit\", request.limit.toString());\n if (request.offset) params.set(\"offset\", request.offset.toString());\n if (request.search) params.set(\"search\", request.search);\n\n const query = params.toString();\n const response = await this.http.get<ListFoldersResponse>(`/cdn/folders${query ? `?${query}` : \"\"}`);\n\n return {\n ...response,\n folders: response.folders.map((folder) => this.convertFolderListItemDates(folder)),\n };\n }\n\n /**\n * Move a folder to a new parent\n *\n * @example\n * ```typescript\n * await cdn.moveFolder({\n * id: 'folder-id',\n * newParentId: 'new-parent-id', // or null for root\n * });\n * ```\n */\n async moveFolder(request: MoveFolderRequest): Promise<MoveFolderResponse> {\n return this.http.post<MoveFolderResponse>(\"/cdn/folders/move\", request);\n }\n\n private convertFolderListItemDates(folder: FolderListItem): FolderListItem {\n if (typeof folder.createdAt === \"string\") {\n folder.createdAt = new Date(folder.createdAt);\n }\n return folder;\n }\n\n // ============================================================================\n // Additional Video Methods\n // ============================================================================\n\n /**\n * List all thumbnails for a video asset\n *\n * @example\n * ```typescript\n * const { thumbnails } = await cdn.listThumbnails('video-asset-id');\n * thumbnails.forEach(thumb => {\n * console.log(`${thumb.timestamp}s: ${thumb.url}`);\n * });\n * ```\n */\n async listThumbnails(assetId: string): Promise<ListThumbnailsResponse> {\n const response = await this.http.get<ListThumbnailsResponse>(`/cdn/video/${assetId}/thumbnails`);\n return response;\n }\n\n // ============================================================================\n // Additional Private Files Methods\n // ============================================================================\n\n /**\n * Move private files to a different folder\n *\n * @example\n * ```typescript\n * const result = await cdn.movePrivateFiles({\n * fileIds: ['file-1', 'file-2'],\n * folder: '/confidential/archive',\n * });\n * console.log(`Moved ${result.movedCount} files`);\n * ```\n */\n async movePrivateFiles(request: MovePrivateFilesRequest): Promise<MovePrivateFilesResponse> {\n return this.http.post<MovePrivateFilesResponse>(\"/cdn/private/move\", request);\n }\n\n // ============================================================================\n // Video Merge Methods\n // ============================================================================\n\n /**\n * Create a merge job to combine multiple videos/images with optional audio overlay\n *\n * Merge jobs combine multiple assets (videos, images) in sequence and can\n * optionally overlay an audio track. Images require a duration to be specified.\n *\n * @example\n * ```typescript\n * const job = await cdn.createMergeJob({\n * projectSlug: 'my-project',\n * inputs: [\n * { assetId: 'intro-video-id' },\n * { assetId: 'image-id', duration: 5 }, // Show image for 5 seconds\n * { assetId: 'main-video-id', startTime: 10, endTime: 60 }, // Trim to 50 seconds\n * ],\n * audioTrack: {\n * assetId: 'background-music-id',\n * loop: true,\n * fadeIn: 2,\n * fadeOut: 3,\n * },\n * output: {\n * format: 'mp4',\n * quality: '1080p',\n * aspectRatio: 'auto', // match first input's orientation ('9:16' forces vertical)\n * filename: 'final-video.mp4',\n * },\n * webhookUrl: 'https://your-app.com/webhook',\n * });\n * console.log(`Merge job started: ${job.id}`);\n * ```\n */\n async createMergeJob(request: CreateMergeJobRequest): Promise<MergeJob> {\n const response = await this.http.post<MergeJob>(\"/cdn/video/merge\", request);\n return this.convertMergeJobDates(response);\n }\n\n /**\n * Get a merge job by ID with output asset details\n *\n * @example\n * ```typescript\n * const job = await cdn.getMergeJob('job-id');\n * if (job.status === 'completed' && job.outputAsset) {\n * console.log(`Output video: ${job.outputAsset.cdnUrl}`);\n * }\n * ```\n */\n async getMergeJob(jobId: string): Promise<MergeJobWithOutput> {\n const response = await this.http.get<MergeJobWithOutput>(`/cdn/video/merge/${jobId}`);\n return this.convertMergeJobWithOutputDates(response);\n }\n\n /**\n * List merge jobs with optional filters\n *\n * @example\n * ```typescript\n * const { jobs, total, hasMore } = await cdn.listMergeJobs({\n * projectSlug: 'my-project',\n * status: 'completed',\n * limit: 20,\n * });\n * ```\n */\n async listMergeJobs(request: ListMergeJobsRequest): Promise<ListMergeJobsResponse> {\n const params = new URLSearchParams();\n params.set(\"projectSlug\", request.projectSlug);\n if (request.status) params.set(\"status\", request.status);\n if (request.limit) params.set(\"limit\", request.limit.toString());\n if (request.offset) params.set(\"offset\", request.offset.toString());\n\n const response = await this.http.get<ListMergeJobsResponse>(`/cdn/video/merge?${params.toString()}`);\n return {\n ...response,\n jobs: response.jobs.map((job) => this.convertMergeJobDates(job)),\n };\n }\n\n /**\n * Cancel a pending or processing merge job\n *\n * @example\n * ```typescript\n * await cdn.cancelMergeJob('job-id');\n * console.log('Merge job cancelled');\n * ```\n */\n async cancelMergeJob(jobId: string): Promise<{ success: boolean }> {\n return this.http.post<{ success: boolean }>(`/cdn/video/merge/${jobId}/cancel`, {});\n }\n\n private convertMergeJobDates(job: MergeJob): MergeJob {\n if (typeof job.createdAt === \"string\") {\n job.createdAt = new Date(job.createdAt);\n }\n if (job.updatedAt && typeof job.updatedAt === \"string\") {\n job.updatedAt = new Date(job.updatedAt);\n }\n if (job.startedAt && typeof job.startedAt === \"string\") {\n job.startedAt = new Date(job.startedAt);\n }\n if (job.completedAt && typeof job.completedAt === \"string\") {\n job.completedAt = new Date(job.completedAt);\n }\n return job;\n }\n\n private convertMergeJobWithOutputDates(job: MergeJobWithOutput): MergeJobWithOutput {\n return this.convertMergeJobDates(job) as MergeJobWithOutput;\n }\n\n // ============================================================================\n // S3 Import Methods\n // ============================================================================\n\n /**\n * Create an S3 import job to bulk import files from an external S3 bucket.\n * Requires Pro plan or higher.\n *\n * @example\n * ```typescript\n * // Using IAM credentials\n * const job = await cdn.createImport({\n * projectSlug: 'my-project',\n * sourceBucket: 'my-external-bucket',\n * sourceRegion: 'us-east-1',\n * sourcePrefix: 'images/',\n * authType: 'iam_credentials',\n * accessKeyId: 'AKIA...',\n * secretAccessKey: 'secret...',\n * pathMode: 'flatten',\n * notifyEmail: 'admin@example.com',\n * });\n *\n * // Using role assumption\n * const job = await cdn.createImport({\n * projectSlug: 'my-project',\n * sourceBucket: 'partner-bucket',\n * sourceRegion: 'eu-west-1',\n * authType: 'role_assumption',\n * roleArn: 'arn:aws:iam::123456789012:role/Stack0ImportRole',\n * externalId: 'optional-external-id',\n * pathMode: 'preserve',\n * targetFolder: '/imported',\n * });\n *\n * console.log(`Import job started: ${job.importId}`);\n * ```\n */\n async createImport(request: CreateImportRequest): Promise<CreateImportResponse> {\n const response = await this.http.post<CreateImportResponse>(\"/cdn/imports\", request);\n return this.convertCreateImportDates(response);\n }\n\n /**\n * Get an import job by ID\n *\n * @example\n * ```typescript\n * const job = await cdn.getImport('import-id');\n * console.log(`Status: ${job.status}`);\n * console.log(`Progress: ${job.processedFiles}/${job.totalFiles} files`);\n * console.log(`Bytes: ${job.processedBytes}/${job.totalBytes}`);\n * ```\n */\n async getImport(importId: string): Promise<ImportJob | null> {\n const response = await this.http.get<ImportJob | null>(`/cdn/imports/${importId}`);\n return response ? this.convertImportJobDates(response) : null;\n }\n\n /**\n * List import jobs with pagination and filters\n *\n * @example\n * ```typescript\n * const { imports, total, hasMore } = await cdn.listImports({\n * projectSlug: 'my-project',\n * status: 'importing',\n * limit: 20,\n * });\n *\n * for (const job of imports) {\n * console.log(`${job.sourceBucket}: ${job.processedFiles}/${job.totalFiles}`);\n * }\n * ```\n */\n async listImports(request: ListImportsRequest): Promise<ListImportsResponse> {\n const params = new URLSearchParams();\n\n params.set(\"projectSlug\", request.projectSlug);\n if (request.environment) params.set(\"environment\", request.environment);\n if (request.status) params.set(\"status\", request.status);\n if (request.sortBy) params.set(\"sortBy\", request.sortBy);\n if (request.sortOrder) params.set(\"sortOrder\", request.sortOrder);\n if (request.limit) params.set(\"limit\", request.limit.toString());\n if (request.offset) params.set(\"offset\", request.offset.toString());\n\n const response = await this.http.get<ListImportsResponse>(`/cdn/imports?${params.toString()}`);\n\n return {\n ...response,\n imports: response.imports.map((job) => this.convertImportJobSummaryDates(job)),\n };\n }\n\n /**\n * Cancel a running import job\n *\n * Files already imported will remain. Only pending/validating/importing jobs can be cancelled.\n *\n * @example\n * ```typescript\n * const result = await cdn.cancelImport('import-id');\n * console.log(`Cancelled: ${result.success}`);\n * ```\n */\n async cancelImport(importId: string): Promise<CancelImportResponse> {\n return this.http.post<CancelImportResponse>(`/cdn/imports/${importId}/cancel`, {});\n }\n\n /**\n * Retry failed files in a completed or failed import job\n *\n * This resets failed files to pending and re-queues the import for processing.\n *\n * @example\n * ```typescript\n * const result = await cdn.retryImport('import-id');\n * console.log(`Retrying ${result.retriedCount} files`);\n * ```\n */\n async retryImport(importId: string): Promise<RetryImportResponse> {\n return this.http.post<RetryImportResponse>(`/cdn/imports/${importId}/retry`, {});\n }\n\n /**\n * List files in an import job with optional status filter\n *\n * @example\n * ```typescript\n * // List all files\n * const { files, total } = await cdn.listImportFiles({\n * importId: 'import-id',\n * limit: 100,\n * });\n *\n * // List only failed files\n * const { files: failedFiles } = await cdn.listImportFiles({\n * importId: 'import-id',\n * status: 'failed',\n * });\n *\n * for (const file of failedFiles) {\n * console.log(`${file.sourceKey}: ${file.errorMessage}`);\n * }\n * ```\n */\n async listImportFiles(request: ListImportFilesRequest): Promise<ListImportFilesResponse> {\n const params = new URLSearchParams();\n\n if (request.status) params.set(\"status\", request.status);\n if (request.sortBy) params.set(\"sortBy\", request.sortBy);\n if (request.sortOrder) params.set(\"sortOrder\", request.sortOrder);\n if (request.limit) params.set(\"limit\", request.limit.toString());\n if (request.offset) params.set(\"offset\", request.offset.toString());\n\n const query = params.toString();\n const response = await this.http.get<ListImportFilesResponse>(\n `/cdn/imports/${request.importId}/files${query ? `?${query}` : \"\"}`,\n );\n\n return {\n ...response,\n files: response.files.map((file) => this.convertImportFileDates(file)),\n };\n }\n\n private convertCreateImportDates(response: CreateImportResponse): CreateImportResponse {\n if (typeof response.createdAt === \"string\") {\n response.createdAt = new Date(response.createdAt);\n }\n return response;\n }\n\n private convertImportJobDates(job: ImportJob): ImportJob {\n if (typeof job.createdAt === \"string\") {\n job.createdAt = new Date(job.createdAt);\n }\n if (job.updatedAt && typeof job.updatedAt === \"string\") {\n job.updatedAt = new Date(job.updatedAt);\n }\n if (job.startedAt && typeof job.startedAt === \"string\") {\n job.startedAt = new Date(job.startedAt);\n }\n if (job.completedAt && typeof job.completedAt === \"string\") {\n job.completedAt = new Date(job.completedAt);\n }\n return job;\n }\n\n private convertImportJobSummaryDates(job: ImportJobSummary): ImportJobSummary {\n if (typeof job.createdAt === \"string\") {\n job.createdAt = new Date(job.createdAt);\n }\n if (job.startedAt && typeof job.startedAt === \"string\") {\n job.startedAt = new Date(job.startedAt);\n }\n if (job.completedAt && typeof job.completedAt === \"string\") {\n job.completedAt = new Date(job.completedAt);\n }\n return job;\n }\n\n private convertImportFileDates(file: ImportFile): ImportFile {\n if (typeof file.createdAt === \"string\") {\n file.createdAt = new Date(file.createdAt);\n }\n if (file.completedAt && typeof file.completedAt === \"string\") {\n file.completedAt = new Date(file.completedAt);\n }\n if (file.lastAttemptAt && typeof file.lastAttemptAt === \"string\") {\n file.lastAttemptAt = new Date(file.lastAttemptAt);\n }\n return file;\n }\n}\n"]}
1
+ {"version":3,"sources":["../../src/lib/http-client.ts","../../src/cdn/client.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * HTTP client for Stack0 API\n * Handles authentication, request/response formatting, and error handling\n */\n\nexport interface HttpClientConfig {\n apiKey: string;\n baseUrl?: string;\n}\n\nexport class HttpClient {\n private apiKey: string;\n private baseUrl: string;\n\n constructor(config: HttpClientConfig) {\n this.apiKey = config.apiKey;\n this.baseUrl = config.baseUrl || \"https://api.stack0.dev/v1\";\n }\n\n private getHeaders(includeContentType = true): Record<string, string> {\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.apiKey}`,\n };\n if (includeContentType) {\n headers[\"Content-Type\"] = \"application/json\";\n }\n return headers;\n }\n\n async request<T>(method: string, path: string, body?: unknown): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n const bodyString = body === undefined ? undefined : JSON.stringify(body);\n const hasBody = bodyString !== undefined;\n\n try {\n const response = await fetch(url, {\n method,\n headers: this.getHeaders(hasBody),\n body: hasBody ? bodyString : undefined,\n });\n\n if (!response.ok) {\n await this.handleErrorResponse(response);\n }\n\n const data = await response.json();\n return data as T;\n } catch (error) {\n if (error instanceof Error && \"statusCode\" in error) {\n throw error; // Re-throw our custom errors\n }\n throw this.createError(\"Network error\", error);\n }\n }\n\n private async handleErrorResponse(response: Response): Promise<never> {\n let errorBody: { message: string } | undefined;\n try {\n errorBody = (await response.json()) as { message: string };\n } catch {\n errorBody = { message: response.statusText };\n }\n\n const error = new Error(errorBody?.message || `HTTP ${response.status}`) as Error & {\n statusCode: number;\n code: string;\n response: unknown;\n };\n error.statusCode = response.status;\n error.code = (errorBody as unknown as { code: string } | undefined)?.code ?? \"\";\n error.response = errorBody;\n throw error;\n }\n\n private createError(message: string, cause?: unknown): Error {\n const error = new Error(message) as Error & { cause: unknown };\n error.cause = cause;\n return error;\n }\n\n async get<T>(path: string): Promise<T> {\n return this.request<T>(\"GET\", path);\n }\n\n async post<T>(path: string, body: unknown): Promise<T> {\n return this.request<T>(\"POST\", path, body);\n }\n\n async put<T>(path: string, body: unknown): Promise<T> {\n return this.request<T>(\"PUT\", path, body);\n }\n\n async delete<T>(path: string): Promise<T> {\n return this.request<T>(\"DELETE\", path);\n }\n\n async deleteWithBody<T>(path: string, body: unknown): Promise<T> {\n return this.request<T>(\"DELETE\", path, body);\n }\n\n async patch<T>(path: string, body: unknown): Promise<T> {\n return this.request<T>(\"PATCH\", path, body);\n }\n}\n","/**\n * Stack0 CDN Client\n * Upload, manage, and transform assets\n */\n\nimport { HttpClient, type HttpClientConfig } from \"../lib/http-client\";\nimport type {\n Asset,\n UploadUrlRequest,\n UploadUrlResponse,\n UploadFromUrlRequest,\n UpdateAssetRequest,\n DeleteAssetsResponse,\n ListAssetsRequest,\n ListAssetsResponse,\n MoveAssetsRequest,\n MoveAssetsResponse,\n TransformOptions,\n GetFolderTreeRequest,\n FolderTreeNode,\n CreateFolderRequest,\n Folder,\n TranscodeVideoRequest,\n TranscodeJob,\n ListJobsRequest,\n ListJobsResponse,\n StreamingUrls,\n ThumbnailRequest,\n ThumbnailResponse,\n RegenerateThumbnailRequest,\n RegenerateThumbnailResponse,\n ExtractAudioRequest,\n ExtractAudioResponse,\n // Private Files\n PrivateFile,\n PrivateUploadUrlRequest,\n PrivateUploadUrlResponse,\n PrivateDownloadUrlRequest,\n PrivateDownloadUrlResponse,\n ListPrivateFilesRequest,\n ListPrivateFilesResponse,\n UpdatePrivateFileRequest,\n MovePrivateFilesRequest,\n MovePrivateFilesResponse,\n // Bundles\n DownloadBundle,\n CreateBundleRequest,\n CreateBundleResponse,\n ListBundlesRequest,\n ListBundlesResponse,\n BundleDownloadUrlRequest,\n BundleDownloadUrlResponse,\n // Usage\n CdnUsageRequest,\n CdnUsageResponse,\n CdnUsageHistoryRequest,\n CdnUsageHistoryResponse,\n CdnUsageDataPoint,\n CdnStorageBreakdownRequest,\n CdnStorageBreakdownResponse,\n CdnStorageUsageRequest,\n CdnStorageUsageResponse,\n // Additional Folder Types\n UpdateFolderRequest,\n ListFoldersRequest,\n ListFoldersResponse,\n FolderListItem,\n MoveFolderRequest,\n MoveFolderResponse,\n // Additional Video Types\n VideoThumbnail,\n ListThumbnailsResponse,\n // Video Merge Types\n CreateMergeJobRequest,\n MergeJob,\n MergeJobWithOutput,\n ListMergeJobsRequest,\n ListMergeJobsResponse,\n // GIF Generation Types\n GenerateGifRequest,\n VideoGif,\n ListGifsRequest,\n // Image Watermark Types\n ImageWatermarkConfig,\n // Import Types\n CreateImportRequest,\n CreateImportResponse,\n ImportJob,\n ListImportsRequest,\n ListImportsResponse,\n ImportJobSummary,\n CancelImportResponse,\n RetryImportResponse,\n ListImportFilesRequest,\n ListImportFilesResponse,\n ImportFile,\n} from \"./types\";\n\n// Allowed widths that match the CloudFront url-rewriter configuration\nconst ALLOWED_WIDTHS = [256, 384, 640, 750, 828, 1080, 1200, 1920, 2048, 3840];\n\nexport class CDN {\n private http: HttpClient;\n private cdnUrl?: string;\n\n constructor(config: HttpClientConfig, cdnUrl?: string) {\n this.http = new HttpClient(config);\n this.cdnUrl = cdnUrl;\n }\n\n /**\n * Generate a presigned URL for uploading a file\n *\n * @example\n * ```typescript\n * const { uploadUrl, assetId } = await cdn.getUploadUrl({\n * projectSlug: 'my-project',\n * filename: 'image.jpg',\n * mimeType: 'image/jpeg',\n * size: 1024 * 1024,\n * });\n *\n * // Upload file to the presigned URL\n * await fetch(uploadUrl, {\n * method: 'PUT',\n * body: file,\n * headers: { 'Content-Type': 'image/jpeg' },\n * });\n *\n * // Confirm the upload\n * const asset = await cdn.confirmUpload(assetId);\n * ```\n */\n async getUploadUrl(request: UploadUrlRequest): Promise<UploadUrlResponse> {\n const response = await this.http.post<UploadUrlResponse>(\"/cdn/upload\", request);\n\n if (typeof response.expiresAt === \"string\") {\n response.expiresAt = new Date(response.expiresAt);\n }\n\n return response;\n }\n\n /**\n * Confirm that an upload has completed\n */\n async confirmUpload(assetId: string): Promise<Asset> {\n const response = await this.http.post<Asset>(`/cdn/upload/${assetId}/confirm`, {});\n return this.convertAssetDates(response);\n }\n\n /**\n * Upload a file directly (handles presigned URL flow automatically)\n *\n * @example\n * ```typescript\n * const asset = await cdn.upload({\n * projectSlug: 'my-project',\n * file: fileBuffer,\n * filename: 'image.jpg',\n * mimeType: 'image/jpeg',\n * });\n *\n * // With watermark\n * const watermarkedAsset = await cdn.upload({\n * projectSlug: 'my-project',\n * file: fileBuffer,\n * filename: 'photo.jpg',\n * mimeType: 'image/jpeg',\n * watermark: {\n * assetId: 'logo-asset-id', // or url: 'https://example.com/logo.png'\n * position: 'bottom-right',\n * opacity: 50,\n * sizingMode: 'relative',\n * width: 15, // 15% of image width\n * },\n * });\n * ```\n */\n async upload(options: {\n projectSlug: string;\n file: Blob | Buffer | ArrayBuffer;\n filename: string;\n mimeType: string;\n folder?: string;\n metadata?: Record<string, unknown>;\n /** Watermark configuration for images (applied during upload processing) */\n watermark?: ImageWatermarkConfig;\n }): Promise<Asset> {\n const { projectSlug, file, filename, mimeType, folder, metadata, watermark } = options;\n\n // Get file size\n let size: number;\n if (file instanceof Blob) {\n size = file.size;\n } else if (file instanceof ArrayBuffer) {\n size = file.byteLength;\n } else {\n // Buffer\n size = (file as Buffer).length;\n }\n\n // Get presigned URL\n const { uploadUrl, assetId } = await this.getUploadUrl({\n projectSlug,\n filename,\n mimeType,\n size,\n folder,\n metadata,\n watermark,\n });\n\n // Upload file\n const uploadResponse = await fetch(uploadUrl, {\n method: \"PUT\",\n body: file,\n headers: {\n \"Content-Type\": mimeType,\n },\n });\n\n if (!uploadResponse.ok) {\n throw new Error(`Upload failed: ${uploadResponse.statusText}`);\n }\n\n // Confirm upload\n return this.confirmUpload(assetId);\n }\n\n /**\n * Upload a file from a remote URL (server-side fetch).\n * The server streams the file directly from the source URL into storage,\n * so the client never touches the bytes. Ideal for serverless environments\n * with tight memory limits.\n *\n * @example\n * ```typescript\n * const asset = await cdn.uploadFromUrl({\n * projectSlug: 'my-project',\n * sourceUrl: 'https://replicate.delivery/output/video.mp4',\n * filename: 'video.mp4',\n * mimeType: 'video/mp4',\n * });\n * console.log(asset.cdnUrl);\n * ```\n */\n async uploadFromUrl(request: UploadFromUrlRequest): Promise<Asset> {\n const response = await this.http.post<Asset>(\"/cdn/upload-from-url\", request);\n return this.convertAssetDates(response);\n }\n\n /**\n * Get an asset by ID\n *\n * @example\n * ```typescript\n * const asset = await cdn.get('asset-id');\n * console.log(asset.cdnUrl);\n * ```\n */\n async get(id: string): Promise<Asset> {\n const response = await this.http.get<Asset>(`/cdn/assets/${id}`);\n return this.convertAssetDates(response);\n }\n\n /**\n * Update asset metadata\n *\n * @example\n * ```typescript\n * const asset = await cdn.update({\n * id: 'asset-id',\n * alt: 'A beautiful sunset',\n * tags: ['nature', 'sunset'],\n * });\n * ```\n */\n async update(request: UpdateAssetRequest): Promise<Asset> {\n const { id, ...data } = request;\n const response = await this.http.patch<Asset>(`/cdn/assets/${id}`, data);\n return this.convertAssetDates(response);\n }\n\n /**\n * Delete an asset\n *\n * @example\n * ```typescript\n * await cdn.delete('asset-id');\n * ```\n */\n async delete(id: string): Promise<{ success: boolean }> {\n // NOTE: Our OpenAPI adapter parses JSON bodies for non-GET methods.\n // Some Fastify setups will throw if Content-Type is JSON but the body is empty.\n // Sending the id in the body keeps this endpoint compatible across adapters.\n return this.http.deleteWithBody<{ success: boolean }>(`/cdn/assets/${id}`, { id });\n }\n\n /**\n * Delete multiple assets\n *\n * @example\n * ```typescript\n * const result = await cdn.deleteMany(['asset-1', 'asset-2']);\n * console.log(`Deleted ${result.deletedCount} assets`);\n * ```\n */\n async deleteMany(ids: string[]): Promise<DeleteAssetsResponse> {\n return this.http.post<DeleteAssetsResponse>(\"/cdn/assets/delete\", { ids });\n }\n\n /**\n * List assets with filters and pagination\n *\n * @example\n * ```typescript\n * const { assets, total, hasMore } = await cdn.list({\n * projectSlug: 'my-project',\n * type: 'image',\n * limit: 20,\n * });\n * ```\n */\n async list(request: ListAssetsRequest): Promise<ListAssetsResponse> {\n const params = new URLSearchParams();\n\n params.set(\"projectSlug\", request.projectSlug);\n if (request.folder !== undefined) params.set(\"folder\", request.folder ?? \"\");\n if (request.type) params.set(\"type\", request.type);\n if (request.status) params.set(\"status\", request.status);\n if (request.search) params.set(\"search\", request.search);\n if (request.tags) params.set(\"tags\", request.tags.join(\",\"));\n if (request.sortBy) params.set(\"sortBy\", request.sortBy);\n if (request.sortOrder) params.set(\"sortOrder\", request.sortOrder);\n if (request.limit) params.set(\"limit\", request.limit.toString());\n if (request.offset) params.set(\"offset\", request.offset.toString());\n\n const response = await this.http.get<ListAssetsResponse>(`/cdn/assets?${params.toString()}`);\n\n return {\n ...response,\n assets: response.assets.map((asset) => this.convertAssetDates(asset)),\n };\n }\n\n /**\n * Move assets to a different folder\n *\n * @example\n * ```typescript\n * await cdn.move({\n * assetIds: ['asset-1', 'asset-2'],\n * folder: '/images/archive',\n * });\n * ```\n */\n async move(request: MoveAssetsRequest): Promise<MoveAssetsResponse> {\n return this.http.post<MoveAssetsResponse>(\"/cdn/assets/move\", request);\n }\n\n /**\n * Get a transformed image URL (client-side, no API call)\n *\n * @example\n * ```typescript\n * // Using asset's cdnUrl directly\n * const url = cdn.getTransformUrl(asset.cdnUrl, {\n * width: 800,\n * height: 600,\n * fit: 'cover',\n * format: 'webp',\n * quality: 80,\n * });\n *\n * // Or using cdnUrl from SDK config + s3Key\n * const url = cdn.getTransformUrl(asset.s3Key, { width: 400 });\n * ```\n */\n getTransformUrl(assetUrlOrS3Key: string, options: TransformOptions): string {\n // Determine base URL\n let baseUrl: string;\n if (assetUrlOrS3Key.startsWith(\"http://\") || assetUrlOrS3Key.startsWith(\"https://\")) {\n // It's already a full URL - extract base and path\n const url = new URL(assetUrlOrS3Key);\n baseUrl = `${url.protocol}//${url.host}${url.pathname}`;\n } else if (this.cdnUrl) {\n // It's an s3Key, use configured CDN URL\n const cdnBase = this.cdnUrl.endsWith(\"/\") ? this.cdnUrl.slice(0, -1) : this.cdnUrl;\n baseUrl = `${cdnBase}/${assetUrlOrS3Key}`;\n } else {\n throw new Error(\"getTransformUrl requires either a full URL or cdnUrl to be configured in Stack0 options\");\n }\n\n // Build query string\n const params = this.buildTransformQuery(options);\n if (!params) {\n return baseUrl;\n }\n return `${baseUrl}?${params}`;\n }\n\n /**\n * Build transform query parameters\n */\n private buildTransformQuery(options: TransformOptions): string {\n const params = new URLSearchParams();\n\n if (options.format) params.set(\"f\", options.format);\n if (options.quality !== undefined) params.set(\"q\", options.quality.toString());\n\n if (options.width !== undefined) {\n // Snap to nearest allowed width for better caching\n const width = this.getNearestWidth(options.width);\n params.set(\"w\", width.toString());\n }\n if (options.height !== undefined) params.set(\"h\", options.height.toString());\n if (options.fit) params.set(\"fit\", options.fit);\n if (options.crop) params.set(\"crop\", options.crop);\n if (options.cropX !== undefined) params.set(\"crop-x\", options.cropX.toString());\n if (options.cropY !== undefined) params.set(\"crop-y\", options.cropY.toString());\n if (options.cropWidth !== undefined) params.set(\"crop-w\", options.cropWidth.toString());\n if (options.cropHeight !== undefined) params.set(\"crop-h\", options.cropHeight.toString());\n if (options.blur !== undefined) params.set(\"blur\", options.blur.toString());\n if (options.sharpen !== undefined) params.set(\"sharpen\", options.sharpen.toString());\n if (options.brightness !== undefined) params.set(\"brightness\", options.brightness.toString());\n if (options.saturation !== undefined) params.set(\"saturation\", options.saturation.toString());\n if (options.grayscale) params.set(\"grayscale\", \"true\");\n if (options.rotate !== undefined) params.set(\"rotate\", options.rotate.toString());\n if (options.flip) params.set(\"flip\", \"y\");\n if (options.flop) params.set(\"flop\", \"x\");\n\n return params.toString();\n }\n\n /**\n * Find the nearest allowed width for optimal caching\n */\n private getNearestWidth(width: number): number {\n return ALLOWED_WIDTHS.reduce((prev, curr) => (Math.abs(curr - width) < Math.abs(prev - width) ? curr : prev));\n }\n\n /**\n * Get folder tree for navigation\n *\n * @example\n * ```typescript\n * const tree = await cdn.getFolderTree({\n * projectSlug: 'my-project',\n * maxDepth: 3,\n * });\n * ```\n */\n async getFolderTree(request: GetFolderTreeRequest): Promise<FolderTreeNode[]> {\n const params = new URLSearchParams();\n params.set(\"projectSlug\", request.projectSlug);\n if (request.maxDepth) params.set(\"maxDepth\", request.maxDepth.toString());\n\n const response = await this.http.get<{ tree: FolderTreeNode[] }>(`/cdn/folders/tree?${params.toString()}`);\n return response.tree;\n }\n\n /**\n * Create a new folder\n *\n * @example\n * ```typescript\n * const folder = await cdn.createFolder({\n * projectSlug: 'my-project',\n * name: 'images',\n * });\n * ```\n */\n async createFolder(request: CreateFolderRequest): Promise<Folder> {\n const response = await this.http.post<Folder>(\"/cdn/folders\", request);\n return this.convertFolderDates(response);\n }\n\n /**\n * Delete a folder\n *\n * @example\n * ```typescript\n * await cdn.deleteFolder('folder-id');\n * ```\n */\n async deleteFolder(id: string, deleteContents = false): Promise<{ success: boolean }> {\n const params = new URLSearchParams();\n if (deleteContents) params.set(\"deleteContents\", \"true\");\n\n return this.http.deleteWithBody<{ success: boolean }>(`/cdn/folders/${id}?${params.toString()}`, {\n id,\n deleteContents,\n });\n }\n\n private convertAssetDates(asset: Asset): Asset {\n if (typeof asset.createdAt === \"string\") {\n asset.createdAt = new Date(asset.createdAt);\n }\n if (asset.updatedAt && typeof asset.updatedAt === \"string\") {\n asset.updatedAt = new Date(asset.updatedAt);\n }\n return asset;\n }\n\n private convertFolderDates(folder: Folder): Folder {\n if (typeof folder.createdAt === \"string\") {\n folder.createdAt = new Date(folder.createdAt);\n }\n if (folder.updatedAt && typeof folder.updatedAt === \"string\") {\n folder.updatedAt = new Date(folder.updatedAt);\n }\n return folder;\n }\n\n // ============================================================================\n // Video Transcoding Methods\n // ============================================================================\n\n /**\n * Start a video transcoding job\n *\n * @example\n * ```typescript\n * const job = await cdn.transcode({\n * projectSlug: 'my-project',\n * assetId: 'video-asset-id',\n * outputFormat: 'hls',\n * variants: [\n * { quality: '720p', codec: 'h264' },\n * { quality: '1080p', codec: 'h264' },\n * ],\n * webhookUrl: 'https://your-app.com/webhook',\n * });\n * console.log(`Job started: ${job.id}`);\n * ```\n *\n * @example Burn in a logo watermark (same config shape as image watermarks)\n * ```typescript\n * const job = await cdn.transcode({\n * projectSlug: 'my-project',\n * assetId: 'video-asset-id',\n * outputFormat: 'mp4',\n * variants: [{ quality: '1080p', codec: 'h264' }],\n * watermark: {\n * assetId: 'logo-asset-id',\n * position: 'bottom-right',\n * scale: 15, // 15% of the video width\n * opacity: 80,\n * },\n * });\n * ```\n */\n async transcode(request: TranscodeVideoRequest): Promise<TranscodeJob> {\n const response = await this.http.post<TranscodeJob>(\"/cdn/video/transcode\", request);\n return this.convertJobDates(response);\n }\n\n /**\n * Get a transcoding job by ID\n *\n * @example\n * ```typescript\n * const job = await cdn.getJob('job-id');\n * console.log(`Status: ${job.status}, Progress: ${job.progress}%`);\n * if (job.status === 'failed') console.error(job.errorMessage);\n * ```\n */\n async getJob(jobId: string): Promise<TranscodeJob> {\n const response = await this.http.get<TranscodeJob>(`/cdn/video/jobs/${jobId}`);\n return this.convertJobDates(response);\n }\n\n /**\n * List transcoding jobs with filters\n *\n * @example\n * ```typescript\n * const { jobs, total } = await cdn.listJobs({\n * projectSlug: 'my-project',\n * status: 'processing',\n * limit: 20,\n * });\n * ```\n */\n async listJobs(request: ListJobsRequest): Promise<ListJobsResponse> {\n const params = new URLSearchParams();\n params.set(\"projectSlug\", request.projectSlug);\n if (request.assetId) params.set(\"assetId\", request.assetId);\n if (request.status) params.set(\"status\", request.status);\n if (request.limit) params.set(\"limit\", request.limit.toString());\n if (request.offset) params.set(\"offset\", request.offset.toString());\n\n const response = await this.http.get<ListJobsResponse>(`/cdn/video/jobs?${params.toString()}`);\n return {\n ...response,\n jobs: response.jobs.map((job) => this.convertJobDates(job)),\n };\n }\n\n /**\n * Cancel a pending or processing transcoding job\n *\n * @example\n * ```typescript\n * await cdn.cancelJob('job-id');\n * ```\n */\n async cancelJob(jobId: string): Promise<{ success: boolean }> {\n return this.http.post<{ success: boolean }>(`/cdn/video/jobs/${jobId}/cancel`, {});\n }\n\n /**\n * Get streaming URLs for a transcoded video\n *\n * @example\n * ```typescript\n * const urls = await cdn.getStreamingUrls('asset-id');\n * console.log(`HLS URL: ${urls.hlsUrl}`);\n * console.log(`MP4 720p: ${urls.mp4Urls.find(u => u.quality === '720p')?.url}`);\n * ```\n */\n async getStreamingUrls(assetId: string): Promise<StreamingUrls> {\n return this.http.get<StreamingUrls>(`/cdn/video/${assetId}/stream`);\n }\n\n /**\n * Get the thumbnail at a specific timestamp, generating it on miss\n *\n * If no thumbnail exists at that timestamp yet, generation is queued\n * automatically and a response with `status: \"pending\"` (null url) is\n * returned. Poll until `status` is \"ready\", or use\n * {@link getThumbnailAndWait} to do that for you.\n *\n * @example\n * ```typescript\n * const thumbnail = await cdn.getThumbnail({\n * assetId: 'video-asset-id',\n * timestamp: 10.5, // 10.5 seconds into the video\n * width: 320,\n * format: 'webp',\n * });\n * if (thumbnail.status === 'ready') {\n * console.log(`Thumbnail URL: ${thumbnail.url}`);\n * }\n * ```\n */\n async getThumbnail(request: ThumbnailRequest): Promise<ThumbnailResponse> {\n const params = new URLSearchParams();\n params.set(\"timestamp\", request.timestamp.toString());\n if (request.width) params.set(\"width\", request.width.toString());\n if (request.format) params.set(\"format\", request.format);\n\n return this.http.get<ThumbnailResponse>(`/cdn/video/thumbnail/${request.assetId}?${params.toString()}`);\n }\n\n /**\n * Get the thumbnail at a specific timestamp, waiting for generation to complete\n *\n * Calls {@link getThumbnail} and polls until the thumbnail is ready.\n *\n * @example\n * ```typescript\n * const thumbnail = await cdn.getThumbnailAndWait({\n * assetId: 'video-asset-id',\n * timestamp: 3.5,\n * });\n * console.log(`Thumbnail URL: ${thumbnail.url}`);\n * ```\n */\n async getThumbnailAndWait(\n request: ThumbnailRequest,\n options: { pollInterval?: number; timeout?: number } = {},\n ): Promise<ThumbnailResponse> {\n const { pollInterval = 1000, timeout = 60000 } = options;\n const startTime = Date.now();\n\n while (true) {\n const thumbnail = await this.getThumbnail(request);\n if (thumbnail.status === \"ready\") {\n return thumbnail;\n }\n if (Date.now() - startTime >= timeout) {\n throw new Error(\"Thumbnail generation timed out\");\n }\n await new Promise((resolve) => setTimeout(resolve, pollInterval));\n }\n }\n\n /**\n * Regenerate a thumbnail for a video (force regeneration even if one exists)\n *\n * Useful for retrying failed thumbnail generation or regenerating with\n * different settings. Regeneration is async: poll {@link getThumbnail} (or\n * use {@link getThumbnailAndWait}) at the same timestamp until the new\n * frame is ready.\n *\n * @example\n * ```typescript\n * await cdn.regenerateThumbnail({\n * assetId: 'video-asset-id',\n * timestamp: 5, // 5 seconds into the video\n * width: 1280,\n * format: 'jpg',\n * });\n * const thumbnail = await cdn.getThumbnailAndWait({ assetId: 'video-asset-id', timestamp: 5 });\n * console.log(`Thumbnail URL: ${thumbnail.url}`);\n * ```\n */\n async regenerateThumbnail(request: RegenerateThumbnailRequest): Promise<RegenerateThumbnailResponse> {\n return this.http.post<RegenerateThumbnailResponse>(\"/cdn/video/thumbnail/regenerate\", request);\n }\n\n /**\n * Extract audio from a video file\n *\n * @example\n * ```typescript\n * const { jobId } = await cdn.extractAudio({\n * projectSlug: 'my-project',\n * assetId: 'video-asset-id',\n * format: 'mp3',\n * bitrate: 192,\n * });\n * ```\n */\n async extractAudio(request: ExtractAudioRequest): Promise<ExtractAudioResponse> {\n return this.http.post<ExtractAudioResponse>(\"/cdn/video/extract-audio\", request);\n }\n\n // ============================================================================\n // GIF Generation Methods\n // ============================================================================\n\n /**\n * Generate an animated GIF from a video segment\n *\n * Creates an optimized GIF from a portion of the video. Uses two-pass\n * palette generation by default for smaller file sizes with better quality.\n *\n * @example\n * ```typescript\n * const gif = await cdn.generateGif({\n * projectSlug: 'my-project',\n * assetId: 'video-asset-id',\n * startTime: 5, // Start at 5 seconds\n * duration: 3, // 3 second GIF\n * width: 480, // 480px wide\n * fps: 10, // 10 frames per second\n * });\n *\n * // Poll for completion\n * let result = await cdn.getGif(gif.id);\n * while (result?.status === 'pending' || result?.status === 'processing') {\n * await new Promise(r => setTimeout(r, 1000));\n * result = await cdn.getGif(gif.id);\n * }\n *\n * console.log(`GIF URL: ${result?.url}`);\n * ```\n */\n async generateGif(request: GenerateGifRequest): Promise<VideoGif> {\n const response = await this.http.post<VideoGif>(\"/cdn/video/gif\", request);\n return this.convertGifDates(response);\n }\n\n /**\n * Get a specific GIF by ID\n *\n * @example\n * ```typescript\n * const gif = await cdn.getGif('gif-id');\n * if (gif?.status === 'completed') {\n * console.log(`GIF URL: ${gif.url}`);\n * console.log(`Size: ${gif.sizeBytes} bytes`);\n * }\n * ```\n */\n async getGif(gifId: string): Promise<VideoGif | null> {\n const response = await this.http.get<VideoGif | null>(`/cdn/video/gif/${gifId}`);\n return response ? this.convertGifDates(response) : null;\n }\n\n /**\n * List all GIFs generated for a video asset\n *\n * @example\n * ```typescript\n * const gifs = await cdn.listGifs({ assetId: 'video-asset-id' });\n * for (const gif of gifs) {\n * console.log(`GIF at ${gif.startTime}s: ${gif.url}`);\n * }\n * ```\n */\n async listGifs(request: ListGifsRequest): Promise<VideoGif[]> {\n const response = await this.http.get<VideoGif[]>(`/cdn/video/${request.assetId}/gifs`);\n return response.map((gif) => this.convertGifDates(gif));\n }\n\n private convertGifDates(gif: VideoGif): VideoGif {\n if (typeof gif.createdAt === \"string\") {\n gif.createdAt = new Date(gif.createdAt);\n }\n if (gif.completedAt && typeof gif.completedAt === \"string\") {\n gif.completedAt = new Date(gif.completedAt);\n }\n return gif;\n }\n\n private convertJobDates(job: TranscodeJob): TranscodeJob {\n if (typeof job.createdAt === \"string\") {\n job.createdAt = new Date(job.createdAt);\n }\n if (job.startedAt && typeof job.startedAt === \"string\") {\n job.startedAt = new Date(job.startedAt);\n }\n if (job.completedAt && typeof job.completedAt === \"string\") {\n job.completedAt = new Date(job.completedAt);\n }\n return job;\n }\n\n // ============================================================================\n // Private Files Methods\n // ============================================================================\n\n /**\n * Generate a presigned URL for uploading a private file\n *\n * Private files are stored securely and can only be accessed through\n * authorized download links with configurable expiration.\n *\n * @example\n * ```typescript\n * const { uploadUrl, fileId } = await cdn.getPrivateUploadUrl({\n * projectSlug: 'my-project',\n * filename: 'confidential.pdf',\n * mimeType: 'application/pdf',\n * size: 1024 * 1024,\n * });\n *\n * // Upload file to the presigned URL\n * await fetch(uploadUrl, {\n * method: 'PUT',\n * body: file,\n * headers: { 'Content-Type': 'application/pdf' },\n * });\n *\n * // Confirm the upload\n * const privateFile = await cdn.confirmPrivateUpload(fileId);\n * ```\n */\n async getPrivateUploadUrl(request: PrivateUploadUrlRequest): Promise<PrivateUploadUrlResponse> {\n const response = await this.http.post<PrivateUploadUrlResponse>(\"/cdn/private/upload\", request);\n\n if (typeof response.expiresAt === \"string\") {\n response.expiresAt = new Date(response.expiresAt);\n }\n\n return response;\n }\n\n /**\n * Confirm that a private file upload has completed\n */\n async confirmPrivateUpload(fileId: string): Promise<PrivateFile> {\n const response = await this.http.post<PrivateFile>(`/cdn/private/upload/${fileId}/confirm`, {});\n return this.convertPrivateFileDates(response);\n }\n\n /**\n * Upload a private file directly (handles presigned URL flow automatically)\n *\n * @example\n * ```typescript\n * const privateFile = await cdn.uploadPrivate({\n * projectSlug: 'my-project',\n * file: fileBuffer,\n * filename: 'confidential.pdf',\n * mimeType: 'application/pdf',\n * });\n * ```\n */\n async uploadPrivate(options: {\n projectSlug: string;\n file: Blob | Buffer | ArrayBuffer;\n filename: string;\n mimeType: string;\n folder?: string;\n description?: string;\n metadata?: Record<string, unknown>;\n }): Promise<PrivateFile> {\n const { projectSlug, file, filename, mimeType, folder, description, metadata } = options;\n\n // Get file size\n let size: number;\n if (file instanceof Blob) {\n size = file.size;\n } else if (file instanceof ArrayBuffer) {\n size = file.byteLength;\n } else {\n size = (file as Buffer).length;\n }\n\n // Get presigned URL\n const { uploadUrl, fileId } = await this.getPrivateUploadUrl({\n projectSlug,\n filename,\n mimeType,\n size,\n folder,\n description,\n metadata,\n });\n\n // Upload file\n const uploadResponse = await fetch(uploadUrl, {\n method: \"PUT\",\n body: file,\n headers: {\n \"Content-Type\": mimeType,\n },\n });\n\n if (!uploadResponse.ok) {\n throw new Error(`Upload failed: ${uploadResponse.statusText}`);\n }\n\n // Confirm upload\n return this.confirmPrivateUpload(fileId);\n }\n\n /**\n * Generate a presigned download URL for a private file\n *\n * @example\n * ```typescript\n * const { downloadUrl, expiresAt } = await cdn.getPrivateDownloadUrl({\n * fileId: 'file-id',\n * expiresIn: 86400, // 24 hours\n * });\n * ```\n */\n async getPrivateDownloadUrl(request: PrivateDownloadUrlRequest): Promise<PrivateDownloadUrlResponse> {\n const response = await this.http.post<PrivateDownloadUrlResponse>(`/cdn/private/${request.fileId}/download`, {\n expiresIn: request.expiresIn,\n });\n\n if (typeof response.expiresAt === \"string\") {\n response.expiresAt = new Date(response.expiresAt);\n }\n\n return response;\n }\n\n /**\n * Get a private file by ID\n */\n async getPrivateFile(fileId: string): Promise<PrivateFile> {\n const response = await this.http.get<PrivateFile>(`/cdn/private/${fileId}`);\n return this.convertPrivateFileDates(response);\n }\n\n /**\n * Update a private file's metadata\n */\n async updatePrivateFile(request: UpdatePrivateFileRequest): Promise<PrivateFile> {\n const { fileId, ...data } = request;\n const response = await this.http.patch<PrivateFile>(`/cdn/private/${fileId}`, data);\n return this.convertPrivateFileDates(response);\n }\n\n /**\n * Delete a private file\n */\n async deletePrivateFile(fileId: string): Promise<{ success: boolean }> {\n return this.http.deleteWithBody<{ success: boolean }>(`/cdn/private/${fileId}`, { fileId });\n }\n\n /**\n * Delete multiple private files\n */\n async deletePrivateFiles(fileIds: string[]): Promise<{ success: boolean; deletedCount: number }> {\n return this.http.post<{ success: boolean; deletedCount: number }>(\"/cdn/private/delete\", { fileIds });\n }\n\n /**\n * List private files with filters and pagination\n *\n * @example\n * ```typescript\n * const { files, total, hasMore } = await cdn.listPrivateFiles({\n * projectSlug: 'my-project',\n * limit: 20,\n * });\n * ```\n */\n async listPrivateFiles(request: ListPrivateFilesRequest): Promise<ListPrivateFilesResponse> {\n const params = new URLSearchParams();\n\n params.set(\"projectSlug\", request.projectSlug);\n if (request.folder !== undefined) params.set(\"folder\", request.folder ?? \"\");\n if (request.status) params.set(\"status\", request.status);\n if (request.search) params.set(\"search\", request.search);\n if (request.sortBy) params.set(\"sortBy\", request.sortBy);\n if (request.sortOrder) params.set(\"sortOrder\", request.sortOrder);\n if (request.limit) params.set(\"limit\", request.limit.toString());\n if (request.offset) params.set(\"offset\", request.offset.toString());\n\n const response = await this.http.get<ListPrivateFilesResponse>(`/cdn/private?${params.toString()}`);\n\n return {\n ...response,\n files: response.files.map((file) => this.convertPrivateFileDates(file)),\n };\n }\n\n private convertPrivateFileDates(file: PrivateFile): PrivateFile {\n if (typeof file.createdAt === \"string\") {\n file.createdAt = new Date(file.createdAt);\n }\n if (file.updatedAt && typeof file.updatedAt === \"string\") {\n file.updatedAt = new Date(file.updatedAt);\n }\n return file;\n }\n\n // ============================================================================\n // Download Bundle Methods\n // ============================================================================\n\n /**\n * Create a download bundle from assets and/or private files\n *\n * The bundle will be created asynchronously. Check the status using getBundle().\n *\n * @example\n * ```typescript\n * const { bundle } = await cdn.createBundle({\n * projectSlug: 'my-project',\n * name: 'Project Assets - Dec 2024',\n * assetIds: ['asset-1', 'asset-2'],\n * privateFileIds: ['file-1', 'file-2'],\n * expiresIn: 86400, // 24 hours\n * });\n * console.log(`Bundle ${bundle.id} status: ${bundle.status}`);\n * ```\n */\n async createBundle(request: CreateBundleRequest): Promise<CreateBundleResponse> {\n const response = await this.http.post<CreateBundleResponse>(\"/cdn/bundles\", request);\n return {\n bundle: this.convertBundleDates(response.bundle),\n };\n }\n\n /**\n * Get a download bundle by ID\n */\n async getBundle(bundleId: string): Promise<DownloadBundle> {\n const response = await this.http.get<DownloadBundle>(`/cdn/bundles/${bundleId}`);\n return this.convertBundleDates(response);\n }\n\n /**\n * List download bundles with filters and pagination\n *\n * @example\n * ```typescript\n * const { bundles, total } = await cdn.listBundles({\n * projectSlug: 'my-project',\n * status: 'ready',\n * });\n * ```\n */\n async listBundles(request: ListBundlesRequest): Promise<ListBundlesResponse> {\n const params = new URLSearchParams();\n\n params.set(\"projectSlug\", request.projectSlug);\n if (request.status) params.set(\"status\", request.status);\n if (request.search) params.set(\"search\", request.search);\n if (request.limit) params.set(\"limit\", request.limit.toString());\n if (request.offset) params.set(\"offset\", request.offset.toString());\n\n const response = await this.http.get<ListBundlesResponse>(`/cdn/bundles?${params.toString()}`);\n\n return {\n ...response,\n bundles: response.bundles.map((bundle) => this.convertBundleDates(bundle)),\n };\n }\n\n /**\n * Generate a presigned download URL for a bundle\n *\n * @example\n * ```typescript\n * const { downloadUrl, expiresAt } = await cdn.getBundleDownloadUrl({\n * bundleId: 'bundle-id',\n * expiresIn: 3600, // 1 hour\n * });\n * ```\n */\n async getBundleDownloadUrl(request: BundleDownloadUrlRequest): Promise<BundleDownloadUrlResponse> {\n const response = await this.http.post<BundleDownloadUrlResponse>(`/cdn/bundles/${request.bundleId}/download`, {\n expiresIn: request.expiresIn,\n });\n\n if (typeof response.expiresAt === \"string\") {\n response.expiresAt = new Date(response.expiresAt);\n }\n\n return response;\n }\n\n /**\n * Delete a download bundle\n */\n async deleteBundle(bundleId: string): Promise<{ success: boolean }> {\n return this.http.deleteWithBody<{ success: boolean }>(`/cdn/bundles/${bundleId}`, { bundleId });\n }\n\n private convertBundleDates(bundle: DownloadBundle): DownloadBundle {\n if (typeof bundle.createdAt === \"string\") {\n bundle.createdAt = new Date(bundle.createdAt);\n }\n if (bundle.completedAt && typeof bundle.completedAt === \"string\") {\n bundle.completedAt = new Date(bundle.completedAt);\n }\n if (bundle.expiresAt && typeof bundle.expiresAt === \"string\") {\n bundle.expiresAt = new Date(bundle.expiresAt);\n }\n return bundle;\n }\n\n // ============================================================================\n // Usage Methods\n // ============================================================================\n\n /**\n * Get current usage stats for the billing period\n *\n * @example\n * ```typescript\n * const usage = await cdn.getUsage({\n * projectSlug: 'my-project',\n * });\n * console.log(`Bandwidth: ${usage.bandwidthFormatted}`);\n * console.log(`Estimated cost: ${usage.estimatedCostFormatted}`);\n * ```\n */\n async getUsage(request: CdnUsageRequest = {}): Promise<CdnUsageResponse> {\n const params = new URLSearchParams();\n if (request.projectSlug) params.set(\"projectSlug\", request.projectSlug);\n if (request.environment) params.set(\"environment\", request.environment);\n if (request.periodStart) {\n const date = request.periodStart instanceof Date ? request.periodStart.toISOString() : request.periodStart;\n params.set(\"periodStart\", date);\n }\n if (request.periodEnd) {\n const date = request.periodEnd instanceof Date ? request.periodEnd.toISOString() : request.periodEnd;\n params.set(\"periodEnd\", date);\n }\n\n const query = params.toString();\n const response = await this.http.get<CdnUsageResponse>(`/cdn/usage${query ? `?${query}` : \"\"}`);\n return this.convertUsageDates(response);\n }\n\n /**\n * Get usage history (time series data for charts)\n *\n * @example\n * ```typescript\n * const history = await cdn.getUsageHistory({\n * projectSlug: 'my-project',\n * days: 30,\n * });\n * console.log(`Total requests: ${history.totals.requests}`);\n * ```\n */\n async getUsageHistory(request: CdnUsageHistoryRequest = {}): Promise<CdnUsageHistoryResponse> {\n const params = new URLSearchParams();\n if (request.projectSlug) params.set(\"projectSlug\", request.projectSlug);\n if (request.environment) params.set(\"environment\", request.environment);\n if (request.days) params.set(\"days\", request.days.toString());\n if (request.granularity) params.set(\"granularity\", request.granularity);\n\n const query = params.toString();\n const response = await this.http.get<CdnUsageHistoryResponse>(`/cdn/usage/history${query ? `?${query}` : \"\"}`);\n\n return {\n ...response,\n data: response.data.map((point) => this.convertUsageDataPointDates(point)),\n };\n }\n\n /**\n * Get storage breakdown by type or folder\n *\n * @example\n * ```typescript\n * const breakdown = await cdn.getStorageBreakdown({\n * projectSlug: 'my-project',\n * groupBy: 'type',\n * });\n * breakdown.items.forEach(item => {\n * console.log(`${item.key}: ${item.sizeFormatted} (${item.percentage}%)`);\n * });\n * ```\n */\n async getStorageBreakdown(request: CdnStorageBreakdownRequest = {}): Promise<CdnStorageBreakdownResponse> {\n const params = new URLSearchParams();\n if (request.projectSlug) params.set(\"projectSlug\", request.projectSlug);\n if (request.environment) params.set(\"environment\", request.environment);\n if (request.groupBy) params.set(\"groupBy\", request.groupBy);\n\n const query = params.toString();\n return this.http.get<CdnStorageBreakdownResponse>(`/cdn/usage/storage-breakdown${query ? `?${query}` : \"\"}`);\n }\n\n /**\n * Get total stored bytes for a project or folder, derived assets included.\n *\n * Totals uploads plus everything the pipelines derived from them — video renditions, HLS\n * segments and manifests, thumbnails, GIFs — in one call. Use this to meter a plan limit:\n * paging `list()` and summing `size` counts uploads only, and an HLS ladder typically runs\n * well past the size of the source it came from.\n *\n * Check `unmeasuredAssets`. A nonzero value means some assets have derivatives whose bytes\n * have not been measured, so `totalBytes` is a floor rather than the full number.\n *\n * @example\n * ```typescript\n * const usage = await cdn.getStorageUsage({\n * projectSlug: 'my-project',\n * folder: '/customers/acme',\n * });\n * console.log(`${usage.totalFormatted} across ${usage.objectCount} objects`);\n * console.log(` uploads: ${usage.breakdown.originals.bytesFormatted}`);\n * console.log(` derived: ${usage.breakdown.derived.bytesFormatted}`);\n * ```\n */\n async getStorageUsage(request: CdnStorageUsageRequest = {}): Promise<CdnStorageUsageResponse> {\n const params = new URLSearchParams();\n if (request.projectSlug) params.set(\"projectSlug\", request.projectSlug);\n if (request.environment) params.set(\"environment\", request.environment);\n if (request.folder) params.set(\"folder\", request.folder);\n\n const query = params.toString();\n return this.http.get<CdnStorageUsageResponse>(`/cdn/usage/storage${query ? `?${query}` : \"\"}`);\n }\n\n private convertUsageDates(usage: CdnUsageResponse): CdnUsageResponse {\n if (typeof usage.periodStart === \"string\") {\n usage.periodStart = new Date(usage.periodStart);\n }\n if (typeof usage.periodEnd === \"string\") {\n usage.periodEnd = new Date(usage.periodEnd);\n }\n return usage;\n }\n\n private convertUsageDataPointDates(point: CdnUsageDataPoint): CdnUsageDataPoint {\n if (typeof point.timestamp === \"string\") {\n point.timestamp = new Date(point.timestamp);\n }\n return point;\n }\n\n // ============================================================================\n // Additional Folder Methods\n // ============================================================================\n\n /**\n * Get a folder by ID\n *\n * @example\n * ```typescript\n * const folder = await cdn.getFolder('folder-id');\n * console.log(`Folder: ${folder.name}, Assets: ${folder.assetCount}`);\n * ```\n */\n async getFolder(id: string): Promise<Folder> {\n const response = await this.http.get<Folder>(`/cdn/folders/${id}`);\n return this.convertFolderDates(response);\n }\n\n /**\n * Get a folder by its path\n *\n * @example\n * ```typescript\n * const folder = await cdn.getFolderByPath('/images/avatars');\n * ```\n */\n async getFolderByPath(path: string): Promise<Folder> {\n const encodedPath = encodeURIComponent(path);\n const response = await this.http.get<Folder>(`/cdn/folders/path/${encodedPath}`);\n return this.convertFolderDates(response);\n }\n\n /**\n * Update a folder's name\n *\n * @example\n * ```typescript\n * const folder = await cdn.updateFolder({\n * id: 'folder-id',\n * name: 'New Folder Name',\n * });\n * ```\n */\n async updateFolder(request: UpdateFolderRequest): Promise<Folder> {\n const { id, ...data } = request;\n const response = await this.http.patch<Folder>(`/cdn/folders/${id}`, data);\n return this.convertFolderDates(response);\n }\n\n /**\n * List folders with optional filters\n *\n * @example\n * ```typescript\n * const { folders, total } = await cdn.listFolders({\n * parentId: null, // root level\n * limit: 50,\n * });\n * ```\n */\n async listFolders(request: ListFoldersRequest = {}): Promise<ListFoldersResponse> {\n const params = new URLSearchParams();\n if (request.parentId !== undefined) params.set(\"parentId\", request.parentId ?? \"\");\n if (request.limit) params.set(\"limit\", request.limit.toString());\n if (request.offset) params.set(\"offset\", request.offset.toString());\n if (request.search) params.set(\"search\", request.search);\n\n const query = params.toString();\n const response = await this.http.get<ListFoldersResponse>(`/cdn/folders${query ? `?${query}` : \"\"}`);\n\n return {\n ...response,\n folders: response.folders.map((folder) => this.convertFolderListItemDates(folder)),\n };\n }\n\n /**\n * Move a folder to a new parent\n *\n * @example\n * ```typescript\n * await cdn.moveFolder({\n * id: 'folder-id',\n * newParentId: 'new-parent-id', // or null for root\n * });\n * ```\n */\n async moveFolder(request: MoveFolderRequest): Promise<MoveFolderResponse> {\n return this.http.post<MoveFolderResponse>(\"/cdn/folders/move\", request);\n }\n\n private convertFolderListItemDates(folder: FolderListItem): FolderListItem {\n if (typeof folder.createdAt === \"string\") {\n folder.createdAt = new Date(folder.createdAt);\n }\n return folder;\n }\n\n // ============================================================================\n // Additional Video Methods\n // ============================================================================\n\n /**\n * List all thumbnails for a video asset\n *\n * @example\n * ```typescript\n * const { thumbnails } = await cdn.listThumbnails('video-asset-id');\n * thumbnails.forEach(thumb => {\n * console.log(`${thumb.timestamp}s: ${thumb.url}`);\n * });\n * ```\n */\n async listThumbnails(assetId: string): Promise<ListThumbnailsResponse> {\n const response = await this.http.get<ListThumbnailsResponse>(`/cdn/video/${assetId}/thumbnails`);\n return response;\n }\n\n // ============================================================================\n // Additional Private Files Methods\n // ============================================================================\n\n /**\n * Move private files to a different folder\n *\n * @example\n * ```typescript\n * const result = await cdn.movePrivateFiles({\n * fileIds: ['file-1', 'file-2'],\n * folder: '/confidential/archive',\n * });\n * console.log(`Moved ${result.movedCount} files`);\n * ```\n */\n async movePrivateFiles(request: MovePrivateFilesRequest): Promise<MovePrivateFilesResponse> {\n return this.http.post<MovePrivateFilesResponse>(\"/cdn/private/move\", request);\n }\n\n // ============================================================================\n // Video Merge Methods\n // ============================================================================\n\n /**\n * Create a merge job to combine multiple videos/images with optional audio overlay\n *\n * Merge jobs combine multiple assets (videos, images) in sequence and can\n * optionally overlay an audio track. Images require a duration to be specified.\n *\n * @example\n * ```typescript\n * const job = await cdn.createMergeJob({\n * projectSlug: 'my-project',\n * inputs: [\n * { assetId: 'intro-video-id' },\n * { assetId: 'image-id', duration: 5 }, // Show image for 5 seconds\n * { assetId: 'main-video-id', startTime: 10, endTime: 60 }, // Trim to 50 seconds\n * ],\n * audioTrack: {\n * assetId: 'background-music-id',\n * loop: true,\n * fadeIn: 2,\n * fadeOut: 3,\n * },\n * output: {\n * format: 'mp4',\n * quality: '1080p',\n * aspectRatio: 'auto', // match first input's orientation ('9:16' forces vertical)\n * filename: 'final-video.mp4',\n * },\n * webhookUrl: 'https://your-app.com/webhook',\n * });\n * console.log(`Merge job started: ${job.id}`);\n * ```\n *\n * @example Composite a screen recording onto a held phone (\"POV holding my phone\"):\n * ```typescript\n * const job = await cdn.createMergeJob({\n * projectSlug: 'my-project',\n * inputs: [\n * { assetId: 'reaction-clip-id' },\n * {\n * assetId: 'app-recording-id', // the overlay clip\n * composite: {\n * backgroundAssetId: 'holding-phone-shot-id', // image or video\n * // Corner-pin onto the angled screen (background pixel coords, TL/TR/BL/BR)\n * quad: {\n * topLeft: { x: 320, y: 480 },\n * topRight: { x: 760, y: 500 },\n * bottomLeft: { x: 300, y: 1400 },\n * bottomRight: { x: 740, y: 1440 },\n * },\n * fit: 'cover',\n * // Screen area painted #F500FA in the background is keyed out, so the\n * // recording shows through and fingers over the screen occlude it\n * chromaKey: { color: '#F500FA', similarity: 0.34, blend: 0.06 },\n * },\n * },\n * ],\n * });\n * ```\n */\n async createMergeJob(request: CreateMergeJobRequest): Promise<MergeJob> {\n const response = await this.http.post<MergeJob>(\"/cdn/video/merge\", request);\n return this.convertMergeJobDates(response);\n }\n\n /**\n * Get a merge job by ID with output asset details\n *\n * @example\n * ```typescript\n * const job = await cdn.getMergeJob('job-id');\n * if (job.status === 'completed' && job.outputAsset) {\n * console.log(`Output video: ${job.outputAsset.cdnUrl}`);\n * }\n * ```\n */\n async getMergeJob(jobId: string): Promise<MergeJobWithOutput> {\n const response = await this.http.get<MergeJobWithOutput>(`/cdn/video/merge/${jobId}`);\n return this.convertMergeJobWithOutputDates(response);\n }\n\n /**\n * List merge jobs with optional filters\n *\n * @example\n * ```typescript\n * const { jobs, total, hasMore } = await cdn.listMergeJobs({\n * projectSlug: 'my-project',\n * status: 'completed',\n * limit: 20,\n * });\n * ```\n */\n async listMergeJobs(request: ListMergeJobsRequest): Promise<ListMergeJobsResponse> {\n const params = new URLSearchParams();\n params.set(\"projectSlug\", request.projectSlug);\n if (request.status) params.set(\"status\", request.status);\n if (request.limit) params.set(\"limit\", request.limit.toString());\n if (request.offset) params.set(\"offset\", request.offset.toString());\n\n const response = await this.http.get<ListMergeJobsResponse>(`/cdn/video/merge?${params.toString()}`);\n return {\n ...response,\n jobs: response.jobs.map((job) => this.convertMergeJobDates(job)),\n };\n }\n\n /**\n * Cancel a pending or processing merge job\n *\n * @example\n * ```typescript\n * await cdn.cancelMergeJob('job-id');\n * console.log('Merge job cancelled');\n * ```\n */\n async cancelMergeJob(jobId: string): Promise<{ success: boolean }> {\n return this.http.post<{ success: boolean }>(`/cdn/video/merge/${jobId}/cancel`, {});\n }\n\n private convertMergeJobDates(job: MergeJob): MergeJob {\n if (typeof job.createdAt === \"string\") {\n job.createdAt = new Date(job.createdAt);\n }\n if (job.updatedAt && typeof job.updatedAt === \"string\") {\n job.updatedAt = new Date(job.updatedAt);\n }\n if (job.startedAt && typeof job.startedAt === \"string\") {\n job.startedAt = new Date(job.startedAt);\n }\n if (job.completedAt && typeof job.completedAt === \"string\") {\n job.completedAt = new Date(job.completedAt);\n }\n return job;\n }\n\n private convertMergeJobWithOutputDates(job: MergeJobWithOutput): MergeJobWithOutput {\n return this.convertMergeJobDates(job) as MergeJobWithOutput;\n }\n\n // ============================================================================\n // S3 Import Methods\n // ============================================================================\n\n /**\n * Create an S3 import job to bulk import files from an external S3 bucket.\n * Requires Pro plan or higher.\n *\n * @example\n * ```typescript\n * // Using IAM credentials\n * const job = await cdn.createImport({\n * projectSlug: 'my-project',\n * sourceBucket: 'my-external-bucket',\n * sourceRegion: 'us-east-1',\n * sourcePrefix: 'images/',\n * authType: 'iam_credentials',\n * accessKeyId: 'AKIA...',\n * secretAccessKey: 'secret...',\n * pathMode: 'flatten',\n * notifyEmail: 'admin@example.com',\n * });\n *\n * // Using role assumption\n * const job = await cdn.createImport({\n * projectSlug: 'my-project',\n * sourceBucket: 'partner-bucket',\n * sourceRegion: 'eu-west-1',\n * authType: 'role_assumption',\n * roleArn: 'arn:aws:iam::123456789012:role/Stack0ImportRole',\n * externalId: 'optional-external-id',\n * pathMode: 'preserve',\n * targetFolder: '/imported',\n * });\n *\n * console.log(`Import job started: ${job.importId}`);\n * ```\n */\n async createImport(request: CreateImportRequest): Promise<CreateImportResponse> {\n const response = await this.http.post<CreateImportResponse>(\"/cdn/imports\", request);\n return this.convertCreateImportDates(response);\n }\n\n /**\n * Get an import job by ID\n *\n * @example\n * ```typescript\n * const job = await cdn.getImport('import-id');\n * console.log(`Status: ${job.status}`);\n * console.log(`Progress: ${job.processedFiles}/${job.totalFiles} files`);\n * console.log(`Bytes: ${job.processedBytes}/${job.totalBytes}`);\n * ```\n */\n async getImport(importId: string): Promise<ImportJob | null> {\n const response = await this.http.get<ImportJob | null>(`/cdn/imports/${importId}`);\n return response ? this.convertImportJobDates(response) : null;\n }\n\n /**\n * List import jobs with pagination and filters\n *\n * @example\n * ```typescript\n * const { imports, total, hasMore } = await cdn.listImports({\n * projectSlug: 'my-project',\n * status: 'importing',\n * limit: 20,\n * });\n *\n * for (const job of imports) {\n * console.log(`${job.sourceBucket}: ${job.processedFiles}/${job.totalFiles}`);\n * }\n * ```\n */\n async listImports(request: ListImportsRequest): Promise<ListImportsResponse> {\n const params = new URLSearchParams();\n\n params.set(\"projectSlug\", request.projectSlug);\n if (request.environment) params.set(\"environment\", request.environment);\n if (request.status) params.set(\"status\", request.status);\n if (request.sortBy) params.set(\"sortBy\", request.sortBy);\n if (request.sortOrder) params.set(\"sortOrder\", request.sortOrder);\n if (request.limit) params.set(\"limit\", request.limit.toString());\n if (request.offset) params.set(\"offset\", request.offset.toString());\n\n const response = await this.http.get<ListImportsResponse>(`/cdn/imports?${params.toString()}`);\n\n return {\n ...response,\n imports: response.imports.map((job) => this.convertImportJobSummaryDates(job)),\n };\n }\n\n /**\n * Cancel a running import job\n *\n * Files already imported will remain. Only pending/validating/importing jobs can be cancelled.\n *\n * @example\n * ```typescript\n * const result = await cdn.cancelImport('import-id');\n * console.log(`Cancelled: ${result.success}`);\n * ```\n */\n async cancelImport(importId: string): Promise<CancelImportResponse> {\n return this.http.post<CancelImportResponse>(`/cdn/imports/${importId}/cancel`, {});\n }\n\n /**\n * Retry failed files in a completed or failed import job\n *\n * This resets failed files to pending and re-queues the import for processing.\n *\n * @example\n * ```typescript\n * const result = await cdn.retryImport('import-id');\n * console.log(`Retrying ${result.retriedCount} files`);\n * ```\n */\n async retryImport(importId: string): Promise<RetryImportResponse> {\n return this.http.post<RetryImportResponse>(`/cdn/imports/${importId}/retry`, {});\n }\n\n /**\n * List files in an import job with optional status filter\n *\n * @example\n * ```typescript\n * // List all files\n * const { files, total } = await cdn.listImportFiles({\n * importId: 'import-id',\n * limit: 100,\n * });\n *\n * // List only failed files\n * const { files: failedFiles } = await cdn.listImportFiles({\n * importId: 'import-id',\n * status: 'failed',\n * });\n *\n * for (const file of failedFiles) {\n * console.log(`${file.sourceKey}: ${file.errorMessage}`);\n * }\n * ```\n */\n async listImportFiles(request: ListImportFilesRequest): Promise<ListImportFilesResponse> {\n const params = new URLSearchParams();\n\n if (request.status) params.set(\"status\", request.status);\n if (request.sortBy) params.set(\"sortBy\", request.sortBy);\n if (request.sortOrder) params.set(\"sortOrder\", request.sortOrder);\n if (request.limit) params.set(\"limit\", request.limit.toString());\n if (request.offset) params.set(\"offset\", request.offset.toString());\n\n const query = params.toString();\n const response = await this.http.get<ListImportFilesResponse>(\n `/cdn/imports/${request.importId}/files${query ? `?${query}` : \"\"}`,\n );\n\n return {\n ...response,\n files: response.files.map((file) => this.convertImportFileDates(file)),\n };\n }\n\n private convertCreateImportDates(response: CreateImportResponse): CreateImportResponse {\n if (typeof response.createdAt === \"string\") {\n response.createdAt = new Date(response.createdAt);\n }\n return response;\n }\n\n private convertImportJobDates(job: ImportJob): ImportJob {\n if (typeof job.createdAt === \"string\") {\n job.createdAt = new Date(job.createdAt);\n }\n if (job.updatedAt && typeof job.updatedAt === \"string\") {\n job.updatedAt = new Date(job.updatedAt);\n }\n if (job.startedAt && typeof job.startedAt === \"string\") {\n job.startedAt = new Date(job.startedAt);\n }\n if (job.completedAt && typeof job.completedAt === \"string\") {\n job.completedAt = new Date(job.completedAt);\n }\n return job;\n }\n\n private convertImportJobSummaryDates(job: ImportJobSummary): ImportJobSummary {\n if (typeof job.createdAt === \"string\") {\n job.createdAt = new Date(job.createdAt);\n }\n if (job.startedAt && typeof job.startedAt === \"string\") {\n job.startedAt = new Date(job.startedAt);\n }\n if (job.completedAt && typeof job.completedAt === \"string\") {\n job.completedAt = new Date(job.completedAt);\n }\n return job;\n }\n\n private convertImportFileDates(file: ImportFile): ImportFile {\n if (typeof file.createdAt === \"string\") {\n file.createdAt = new Date(file.createdAt);\n }\n if (file.completedAt && typeof file.completedAt === \"string\") {\n file.completedAt = new Date(file.completedAt);\n }\n if (file.lastAttemptAt && typeof file.lastAttemptAt === \"string\") {\n file.lastAttemptAt = new Date(file.lastAttemptAt);\n }\n return file;\n }\n}\n"]}