solobase-js
Version:
A 100% drop-in replacement for the Supabase JavaScript client. Self-hosted Supabase alternative with complete API compatibility.
424 lines • 13.4 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SolobaseStorageClient = exports.SolobaseStorageFileApi = void 0;
class SolobaseStorageFileApi {
constructor(fetch, bucketId) {
this.fetch = fetch;
this.bucketId = bucketId;
}
/**
* Upload a file to the bucket
*/
async upload(path, file, options = {}) {
const formData = new FormData();
let fileBlob;
if (file instanceof ArrayBuffer) {
fileBlob = new Blob([file], { type: options.contentType || 'application/octet-stream' });
}
else if (file instanceof Blob) {
fileBlob = file;
}
else {
fileBlob = file;
}
formData.append('file', fileBlob, path.split('/').pop());
if (path.includes('/')) {
formData.append('path', path.substring(0, path.lastIndexOf('/')));
}
const headers = {};
if (options.cacheControl) {
headers['Cache-Control'] = options.cacheControl;
}
const response = await this.fetch.post(`/storage/v1/object/${this.bucketId}`, {
body: formData,
headers,
});
if (response.error) {
return {
data: null,
error: { message: response.error.message },
};
}
return {
data: { path },
error: null,
};
}
/**
* Download a file from the bucket
*/
async download(path) {
const response = await this.fetch.get(`/storage/v1/object/${this.bucketId}/${path}`);
if (response.error) {
return {
data: null,
error: { message: response.error.message },
};
}
return {
data: response.data,
error: null,
};
}
/**
* List files in the bucket
*/
async list(path = '', options = {}) {
var _a;
const query = {};
if (path) {
query.path = path;
}
if (options.limit) {
query.limit = options.limit;
}
if (options.offset) {
query.offset = options.offset;
}
if (options.sortBy) {
query.sortBy = `${options.sortBy.column}:${options.sortBy.order}`;
}
const response = await this.fetch.get(`/storage/v1/object/list/${this.bucketId}`, {
query,
});
if (response.error) {
return {
data: null,
error: { message: response.error.message },
};
}
// Transform the response data to match Supabase format
const files = ((_a = response.data) === null || _a === void 0 ? void 0 : _a.data) || response.data || [];
return {
data: files.map((file) => ({
name: file.name,
id: file.id,
updated_at: file.updated_at,
created_at: file.created_at,
last_accessed_at: file.last_accessed_at,
metadata: file.metadata,
})),
error: null,
};
}
/**
* Update/replace a file in the bucket
*/
async update(path, file, options = {}) {
// For update, we use upsert: true
return this.upload(path, file, { ...options, upsert: true });
}
/**
* Move a file within the bucket
*/
async move(fromPath, toPath) {
const response = await this.fetch.post(`/storage/object/move`, {
body: {
bucketId: this.bucketId,
sourceKey: fromPath,
destinationKey: toPath,
},
});
if (response.error) {
return {
data: null,
error: { message: response.error.message },
};
}
return {
data: { message: 'Successfully moved' },
error: null,
};
}
/**
* Copy a file within the bucket
*/
async copy(fromPath, toPath) {
const response = await this.fetch.post(`/storage/object/copy`, {
body: {
bucketId: this.bucketId,
sourceKey: fromPath,
destinationKey: toPath,
},
});
if (response.error) {
return {
data: null,
error: { message: response.error.message },
};
}
return {
data: { path: toPath },
error: null,
};
}
/**
* Remove files from the bucket
*/
async remove(paths) {
const promises = paths.map(async (path) => {
// First get the file info
const fileInfo = await this.list(path);
if (fileInfo.error || !fileInfo.data) {
return null;
}
const file = fileInfo.data.find(f => f.name === path.split('/').pop());
if (!file)
return null;
// Delete the file
const response = await this.fetch.delete(`/storage/v1/object/${this.bucketId}/${path}`);
if (response.error) {
throw new Error(response.error.message);
}
return file;
});
try {
const results = await Promise.all(promises);
const deletedFiles = results.filter(Boolean);
return {
data: deletedFiles,
error: null,
};
}
catch (error) {
return {
data: null,
error: { message: error instanceof Error ? error.message : 'Delete failed' },
};
}
}
/**
* Create a signed URL for a file
*/
async createSignedUrl(path, expiresIn = 3600) {
const response = await this.fetch.post(`/storage/object/sign/${this.bucketId}/${path}`, {
body: { expiresIn },
});
if (response.error) {
return {
data: null,
error: { message: response.error.message },
};
}
return {
data: { signedUrl: response.data.signedUrl },
error: null,
};
}
/**
* Create signed URLs for multiple files
*/
async createSignedUrls(paths, expiresIn = 3600) {
const promises = paths.map(async (path) => {
const result = await this.createSignedUrl(path, expiresIn);
if (result.error) {
throw new Error(result.error.message);
}
return {
path,
signedUrl: result.data.signedUrl,
};
});
try {
const signedUrls = await Promise.all(promises);
return {
data: { signedUrls },
error: null,
};
}
catch (error) {
return {
data: null,
error: { message: error instanceof Error ? error.message : 'Failed to create signed URLs' },
};
}
}
/**
* Get the public URL for a file (if bucket is public)
*/
getPublicUrl(path) {
const publicUrl = `${this.fetch['baseUrl']}/storage/v1/object/public/${this.bucketId}/${path}`;
return {
data: { publicUrl },
};
}
}
exports.SolobaseStorageFileApi = SolobaseStorageFileApi;
class SolobaseStorageClient {
constructor(fetch) {
this.fetch = fetch;
}
/**
* Get a reference to a storage bucket
*/
from(bucketId) {
return new SolobaseStorageFileApi(this.fetch, bucketId);
}
/**
* List all buckets
*/
async listBuckets() {
var _a;
const response = await this.fetch.get('/dashboard/storage');
if (response.error) {
return {
data: null,
error: { message: response.error.message },
};
}
const buckets = ((_a = response.data) === null || _a === void 0 ? void 0 : _a.buckets) || [];
return {
data: buckets.map((bucket) => {
var _a;
return ({
id: bucket.id,
name: bucket.name,
owner: bucket.owner_id,
created_at: bucket.created_at,
updated_at: bucket.updated_at,
public: bucket.public,
file_size_limit: bucket.file_size_limit,
allowed_mime_types: ((_a = bucket.allowed_mime_types) === null || _a === void 0 ? void 0 : _a.split(',').map((type) => type.trim())) || null,
});
}),
error: null,
};
}
/**
* Get bucket details
*/
async getBucket(bucketId) {
var _a;
const response = await this.fetch.get(`/dashboard/storage/buckets/${bucketId}`);
if (response.error) {
return {
data: null,
error: { message: response.error.message },
};
}
const bucket = response.data;
return {
data: {
id: bucket.id,
name: bucket.name,
owner: bucket.owner_id,
created_at: bucket.created_at,
updated_at: bucket.updated_at,
public: bucket.public,
file_size_limit: bucket.file_size_limit,
allowed_mime_types: ((_a = bucket.allowed_mime_types) === null || _a === void 0 ? void 0 : _a.split(',').map((type) => type.trim())) || null,
},
error: null,
};
}
/**
* Create a new bucket
*/
async createBucket(bucketId, options = {}) {
var _a, _b;
const response = await this.fetch.post('/dashboard/storage/buckets', {
body: {
name: bucketId,
public: options.public || false,
file_size_limit: options.fileSizeLimit,
allowed_mime_types: (_a = options.allowedMimeTypes) === null || _a === void 0 ? void 0 : _a.join(','),
},
});
if (response.error) {
return {
data: null,
error: { message: response.error.message },
};
}
const bucket = response.data;
return {
data: {
id: bucket.id,
name: bucket.name,
owner: bucket.owner_id,
created_at: bucket.created_at,
updated_at: bucket.updated_at,
public: bucket.public,
file_size_limit: bucket.file_size_limit,
allowed_mime_types: ((_b = bucket.allowed_mime_types) === null || _b === void 0 ? void 0 : _b.split(',').map((type) => type.trim())) || null,
},
error: null,
};
}
/**
* Update bucket configuration
*/
async updateBucket(bucketId, options) {
var _a;
const response = await this.fetch.put(`/dashboard/storage/buckets/${bucketId}`, {
body: {
public: options.public,
file_size_limit: options.fileSizeLimit,
allowed_mime_types: (_a = options.allowedMimeTypes) === null || _a === void 0 ? void 0 : _a.join(','),
},
});
if (response.error) {
return {
data: null,
error: { message: response.error.message },
};
}
return {
data: { message: 'Successfully updated' },
error: null,
};
}
/**
* Delete a bucket
*/
async deleteBucket(bucketId) {
const response = await this.fetch.delete(`/dashboard/storage/buckets/${bucketId}`, {
body: { confirmation: 'DELETE' },
});
if (response.error) {
return {
data: null,
error: { message: response.error.message },
};
}
return {
data: { message: 'Successfully deleted' },
error: null,
};
}
/**
* Empty a bucket (delete all files)
*/
async emptyBucket(bucketId) {
// First list all files
const fileApi = this.from(bucketId);
const listResult = await fileApi.list();
if (listResult.error) {
return {
data: null,
error: listResult.error,
};
}
if (!listResult.data || listResult.data.length === 0) {
return {
data: { message: 'Bucket is already empty' },
error: null,
};
}
// Delete all files
const filePaths = listResult.data.map(file => file.name);
const deleteResult = await fileApi.remove(filePaths);
if (deleteResult.error) {
return {
data: null,
error: deleteResult.error,
};
}
return {
data: { message: `Successfully deleted ${filePaths.length} files` },
error: null,
};
}
}
exports.SolobaseStorageClient = SolobaseStorageClient;
//# sourceMappingURL=SolobaseStorageClient.js.map