StorageSettings.utils.ts97 lines · main
1import { StorageSizeUnits } from './StorageSettings.constants'
2
3const k = 1024
4
5export const BUCKET_LIMIT_ERROR_PREFIX = 'bucketLimit:'
6
7type BucketLimitErrorBucket = { name: string; limit: number }
8
9export const convertFromBytes = (bytes: number, unit?: StorageSizeUnits) => {
10 // Up to GB since that's our storage upload limit
11 if (bytes <= 0) return { value: 0, unit: StorageSizeUnits.BYTES }
12
13 const i =
14 unit !== undefined
15 ? Object.values(StorageSizeUnits).indexOf(unit)
16 : Math.floor(Math.log(bytes) / Math.log(k))
17
18 const formattedIdx = unit !== undefined ? (i < 0 ? 0 : i) : i > 3 ? 3 : i
19
20 const formattedUnit = Object.values(StorageSizeUnits)[formattedIdx]
21 const value = bytes / Math.pow(k, formattedIdx)
22 return { value, unit: formattedUnit }
23}
24
25export const convertToBytes = (size: number, unit: StorageSizeUnits = StorageSizeUnits.BYTES) => {
26 const i = Object.values(StorageSizeUnits).indexOf(unit)
27 if (size < 0 || i < 0) return 0
28
29 return size * Math.pow(k, i)
30}
31
32function getStorageURL(projectRef: string, protocol: string, endpoint?: string) {
33 const projUrl = endpoint
34 ? `${protocol}://${endpoint}`
35 : `https://${projectRef}.storage.supabase.co`
36 const url = new URL(projUrl)
37 return url
38}
39
40export function getConnectionURL(projectRef: string, protocol: string, endpoint?: string) {
41 const url = getStorageURL(projectRef, protocol, endpoint)
42 url.pathname = '/storage/v1/s3'
43 return url.toString()
44}
45
46export function getCatalogURI(projectRef: string, protocol: string, endpoint?: string) {
47 const url = getStorageURL(projectRef, protocol, endpoint)
48 url.pathname = '/storage/v1/iceberg'
49 return url.toString()
50}
51
52export function getVectorURI(projectRef: string, protocol: string, endpoint?: string) {
53 const url = getStorageURL(projectRef, protocol, endpoint)
54 url.pathname = '/storage/v1/vector'
55 return url.toString()
56}
57
58export const formatBytesForDisplay = (bytes: number) => {
59 const { value, unit } = convertFromBytes(bytes)
60 return `${value.toLocaleString(undefined, { maximumFractionDigits: 2 })} ${unit}`
61}
62
63export const encodeBucketLimitErrorMessage = (buckets: BucketLimitErrorBucket[]) => {
64 const encodedBuckets = buckets
65 .map(({ name, limit }) => `${encodeURIComponent(name)}|${limit}`)
66 .join(',')
67 return `${BUCKET_LIMIT_ERROR_PREFIX}${encodedBuckets}`
68}
69
70export const isBucketLimitErrorMessage = (message?: string) => {
71 return message?.startsWith(BUCKET_LIMIT_ERROR_PREFIX)
72}
73
74export const decodeBucketLimitErrorMessage = (message?: string): BucketLimitErrorBucket[] => {
75 if (!isBucketLimitErrorMessage(message)) return []
76
77 const payload = message?.slice(BUCKET_LIMIT_ERROR_PREFIX.length) ?? ''
78 if (payload.length === 0) return []
79
80 return payload
81 .split(',')
82 .filter(Boolean)
83 .map((entry) => {
84 const parts = entry.split('|')
85 if (parts.length !== 2) return undefined
86
87 const name = decodeURIComponent(parts[0])
88 if (!name) return undefined
89
90 const limitString = parts[1]
91 const limit = Number(limitString ?? 0)
92 if (Number.isNaN(limit)) return undefined
93
94 return { name, limit }
95 })
96 .filter((entry) => entry !== undefined)
97}