1+ import { DEFAULT_HEADERS } from '../lib/constants'
2+ import { isStorageError , StorageError } from '../lib/errors'
3+ import { Fetch , get , post , remove } from '../lib/fetch'
4+ import { resolveFetch } from '../lib/helpers'
5+ import { AnalyticBucket , Bucket } from '../lib/types'
6+
7+ /**
8+ * API class for managing Analytics Buckets using Iceberg tables
9+ * Provides methods for creating, listing, and deleting analytics buckets
10+ */
11+ export default class StorageAnalyticsApi {
12+ protected url : string
13+ protected headers : { [ key : string ] : string }
14+ protected fetch : Fetch
15+ protected shouldThrowOnError = false
16+
17+ constructor ( url : string , headers : { [ key : string ] : string } = { } , fetch ?: Fetch ) {
18+ this . url = url . replace ( / \/ $ / , '' )
19+ this . headers = { ...DEFAULT_HEADERS , ...headers }
20+ this . fetch = resolveFetch ( fetch )
21+ }
22+
23+ /**
24+ * Enable throwing errors instead of returning them in the response
25+ * When enabled, failed operations will throw instead of returning { data: null, error }
26+ *
27+ * @returns This instance for method chaining
28+ */
29+ public throwOnError ( ) : this {
30+ this . shouldThrowOnError = true
31+ return this
32+ }
33+
34+ /**
35+ * Creates a new analytics bucket using Iceberg tables
36+ * Analytics buckets are optimized for analytical queries and data processing
37+ *
38+ * @param name A unique name for the bucket you are creating
39+ * @returns Promise with newly created bucket name or error
40+ *
41+ * @example
42+ * ```typescript
43+ * const { data, error } = await storage.analytics.createBucket('analytics-data')
44+ * if (error) {
45+ * console.error('Failed to create analytics bucket:', error.message)
46+ * } else {
47+ * console.log('Created bucket:', data.name)
48+ * }
49+ * ```
50+ */
51+ async createBucket (
52+ name : string
53+ ) : Promise <
54+ | {
55+ data : AnalyticBucket ,
56+ error : null
57+ }
58+ | {
59+ data : null
60+ error : StorageError
61+ }
62+ > {
63+ try {
64+ const data = await post (
65+ this . fetch ,
66+ `${ this . url } /bucket` ,
67+ { name } ,
68+ { headers : this . headers }
69+ )
70+ return { data, error : null }
71+ } catch ( error ) {
72+ if ( this . shouldThrowOnError ) {
73+ throw error
74+ }
75+ if ( isStorageError ( error ) ) {
76+ return { data : null , error }
77+ }
78+
79+ throw error
80+ }
81+ }
82+
83+ /**
84+ * Retrieves the details of all Analytics Storage buckets within an existing project
85+ * Only returns buckets of type 'ANALYTICS'
86+ *
87+ * @param options Query parameters for listing buckets
88+ * @param options.limit Maximum number of buckets to return
89+ * @param options.offset Number of buckets to skip
90+ * @param options.sortColumn Column to sort by ('id', 'name', 'created_at', 'updated_at')
91+ * @param options.sortOrder Sort order ('asc' or 'desc')
92+ * @param options.search Search term to filter bucket names
93+ * @returns Promise with list of analytics buckets or error
94+ *
95+ * @example
96+ * ```typescript
97+ * const { data, error } = await storage.analytics.listBuckets({
98+ * limit: 10,
99+ * offset: 0,
100+ * sortColumn: 'created_at',
101+ * sortOrder: 'desc',
102+ * search: 'analytics'
103+ * })
104+ * if (data) {
105+ * console.log('Found analytics buckets:', data.length)
106+ * data.forEach(bucket => console.log(`- ${bucket.name}`))
107+ * }
108+ * ```
109+ */
110+ async listBuckets ( options ?: {
111+ limit ?: number
112+ offset ?: number
113+ sortColumn ?: 'id' | 'name' | 'created_at' | 'updated_at'
114+ sortOrder ?: 'asc' | 'desc'
115+ search ?: string
116+ } ) : Promise <
117+ | {
118+ data : AnalyticBucket [ ]
119+ error : null
120+ }
121+ | {
122+ data : null
123+ error : StorageError
124+ }
125+ > {
126+ try {
127+ // Build query string from options
128+ const queryParams = new URLSearchParams ( )
129+ if ( options ?. limit !== undefined ) queryParams . set ( 'limit' , options . limit . toString ( ) )
130+ if ( options ?. offset !== undefined ) queryParams . set ( 'offset' , options . offset . toString ( ) )
131+ if ( options ?. sortColumn ) queryParams . set ( 'sortColumn' , options . sortColumn )
132+ if ( options ?. sortOrder ) queryParams . set ( 'sortOrder' , options . sortOrder )
133+ if ( options ?. search ) queryParams . set ( 'search' , options . search )
134+
135+ const queryString = queryParams . toString ( )
136+ const url = queryString ? `${ this . url } /bucket?${ queryString } ` : `${ this . url } /bucket`
137+
138+ const data = await get ( this . fetch , url , { headers : this . headers } )
139+ // Filter to only return analytics buckets
140+ const analyticsBuckets = Array . isArray ( data )
141+ ? data . filter ( ( bucket : Bucket ) => bucket . type === 'ANALYTICS' )
142+ : [ ]
143+ return { data : analyticsBuckets , error : null }
144+ } catch ( error ) {
145+ if ( this . shouldThrowOnError ) {
146+ throw error
147+ }
148+ if ( isStorageError ( error ) ) {
149+ return { data : null , error }
150+ }
151+
152+ throw error
153+ }
154+ }
155+
156+ /**
157+ * Deletes an existing analytics bucket
158+ * A bucket can't be deleted with existing objects inside it
159+ * You must first empty the bucket before deletion
160+ *
161+ * @param bucketId The unique identifier of the bucket you would like to delete
162+ * @returns Promise with success message or error
163+ *
164+ * @example
165+ * ```typescript
166+ * const { data, error } = await analyticsApi.deleteBucket('old-analytics-bucket')
167+ * if (error) {
168+ * console.error('Failed to delete bucket:', error.message)
169+ * } else {
170+ * console.log('Bucket deleted successfully:', data.message)
171+ * }
172+ * ```
173+ */
174+ async deleteBucket ( bucketId : string ) : Promise <
175+ | {
176+ data : { message : string }
177+ error : null
178+ }
179+ | {
180+ data : null
181+ error : StorageError
182+ }
183+ > {
184+ try {
185+ const data = await remove (
186+ this . fetch ,
187+ `${ this . url } /bucket/${ bucketId } ` ,
188+ { } ,
189+ { headers : this . headers }
190+ )
191+ return { data, error : null }
192+ } catch ( error ) {
193+ if ( this . shouldThrowOnError ) {
194+ throw error
195+ }
196+ if ( isStorageError ( error ) ) {
197+ return { data : null , error }
198+ }
199+
200+ throw error
201+ }
202+ }
203+ }
0 commit comments