@withvlibe/storage-sdk 1.0.0 → 1.1.0

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.
package/dist/index.mjs ADDED
@@ -0,0 +1,445 @@
1
+ // src/VlibeStorage.ts
2
+ var DEFAULT_BASE_URL = "https://vlibe.app";
3
+ var VlibeStorage = class {
4
+ constructor(config) {
5
+ this.authToken = null;
6
+ this.storageConfig = null;
7
+ this.appId = config.appId;
8
+ this.appSecret = config.appSecret;
9
+ this.baseUrl = config.baseUrl?.replace(/\/$/, "") || DEFAULT_BASE_URL;
10
+ }
11
+ /**
12
+ * Set the user's auth token (required for authenticated requests)
13
+ */
14
+ setAuthToken(token) {
15
+ this.authToken = token;
16
+ }
17
+ /**
18
+ * Clear the auth token
19
+ */
20
+ clearAuthToken() {
21
+ this.authToken = null;
22
+ }
23
+ /**
24
+ * Get storage configuration from the server
25
+ * This fetches the current storage provider and public URL base
26
+ */
27
+ async getStorageConfig() {
28
+ if (this.storageConfig) {
29
+ return this.storageConfig;
30
+ }
31
+ try {
32
+ const response = await this.request("/storage/config");
33
+ if (response.success && response.data) {
34
+ this.storageConfig = response.data;
35
+ return response.data;
36
+ }
37
+ } catch {
38
+ }
39
+ return {
40
+ provider: "wasabi",
41
+ publicUrlBase: "https://s3.eu-central-2.wasabisys.com/vlibe.com"
42
+ };
43
+ }
44
+ /**
45
+ * Clear cached storage config (call if config might have changed)
46
+ */
47
+ clearStorageConfigCache() {
48
+ this.storageConfig = null;
49
+ }
50
+ /**
51
+ * Make an authenticated API request
52
+ */
53
+ async request(path, options = {}) {
54
+ const url = `${this.baseUrl}/api${path}`;
55
+ const headers = {
56
+ "X-App-Id": this.appId,
57
+ "X-App-Secret": this.appSecret,
58
+ ...options.headers || {}
59
+ };
60
+ if (this.authToken) {
61
+ headers["Authorization"] = `Bearer ${this.authToken}`;
62
+ }
63
+ const response = await fetch(url, {
64
+ ...options,
65
+ headers
66
+ });
67
+ const data = await response.json();
68
+ if (!response.ok && !data.error) {
69
+ return {
70
+ success: false,
71
+ error: `HTTP ${response.status}: ${response.statusText}`
72
+ };
73
+ }
74
+ return data;
75
+ }
76
+ // ============================================
77
+ // UPLOAD METHODS
78
+ // ============================================
79
+ /**
80
+ * Upload a file directly
81
+ */
82
+ async upload(file, options = {}) {
83
+ const formData = new FormData();
84
+ formData.append("file", file);
85
+ if (options.folder) {
86
+ formData.append("folder", options.folder);
87
+ }
88
+ if (options.isPublic) {
89
+ formData.append("isPublic", "true");
90
+ }
91
+ const response = await this.request("/storage", {
92
+ method: "POST",
93
+ body: formData
94
+ });
95
+ if (!response.success || !response.data) {
96
+ throw new Error(response.error || "Upload failed");
97
+ }
98
+ return response.data;
99
+ }
100
+ /**
101
+ * Get a presigned URL for direct upload to storage
102
+ * Useful for large files or when you want upload progress
103
+ */
104
+ async getUploadUrl(filename, mimeType, size, options = {}) {
105
+ const response = await this.request("/storage/upload-url", {
106
+ method: "POST",
107
+ headers: {
108
+ "Content-Type": "application/json"
109
+ },
110
+ body: JSON.stringify({
111
+ filename,
112
+ mimeType,
113
+ size,
114
+ folder: options.folder,
115
+ isPublic: options.isPublic
116
+ })
117
+ });
118
+ if (!response.success || !response.data) {
119
+ throw new Error(response.error || "Failed to get upload URL");
120
+ }
121
+ return response.data;
122
+ }
123
+ /**
124
+ * Upload a file using presigned URL (for progress tracking)
125
+ */
126
+ async uploadWithProgress(file, options = {}) {
127
+ const { uploadUrl, key, expiresIn } = await this.getUploadUrl(
128
+ file.name,
129
+ file.type,
130
+ file.size,
131
+ options
132
+ );
133
+ await new Promise((resolve, reject) => {
134
+ const xhr = new XMLHttpRequest();
135
+ if (options.onProgress) {
136
+ xhr.upload.addEventListener("progress", (e) => {
137
+ if (e.lengthComputable) {
138
+ const percent = Math.round(e.loaded / e.total * 100);
139
+ options.onProgress(percent);
140
+ }
141
+ });
142
+ }
143
+ xhr.addEventListener("load", () => {
144
+ if (xhr.status >= 200 && xhr.status < 300) {
145
+ resolve();
146
+ } else {
147
+ reject(new Error(`Upload failed with status ${xhr.status}`));
148
+ }
149
+ });
150
+ xhr.addEventListener("error", () => {
151
+ reject(new Error("Upload failed"));
152
+ });
153
+ xhr.open("PUT", uploadUrl);
154
+ xhr.setRequestHeader("Content-Type", file.type);
155
+ xhr.send(file);
156
+ });
157
+ const response = await this.request("/storage/upload-url", {
158
+ method: "PUT",
159
+ headers: {
160
+ "Content-Type": "application/json"
161
+ },
162
+ body: JSON.stringify({
163
+ key,
164
+ filename: file.name,
165
+ mimeType: file.type,
166
+ size: file.size,
167
+ folder: options.folder,
168
+ isPublic: options.isPublic
169
+ })
170
+ });
171
+ if (!response.success || !response.data) {
172
+ throw new Error(response.error || "Failed to confirm upload");
173
+ }
174
+ return response.data;
175
+ }
176
+ // ============================================
177
+ // DOWNLOAD METHODS
178
+ // ============================================
179
+ /**
180
+ * Get a signed download URL for a file
181
+ */
182
+ async getDownloadUrl(fileId, expiresIn) {
183
+ const params = new URLSearchParams({ download: "true" });
184
+ if (expiresIn) {
185
+ params.set("expiresIn", expiresIn.toString());
186
+ }
187
+ const response = await this.request(
188
+ `/storage/${fileId}?${params}`
189
+ );
190
+ if (!response.success || !response.data) {
191
+ throw new Error(response.error || "Failed to get download URL");
192
+ }
193
+ return response.data.url;
194
+ }
195
+ /**
196
+ * Get a public URL for a file (only works for public files in the public path)
197
+ * Returns the direct URL based on the configured storage provider
198
+ *
199
+ * Note: This is a sync method that uses cached config. Call getStorageConfig()
200
+ * first to ensure the config is loaded, or use getPublicUrlAsync() for a
201
+ * guaranteed fresh URL.
202
+ */
203
+ getPublicUrl(key) {
204
+ if (this.storageConfig) {
205
+ const base = this.storageConfig.publicUrlBase.replace(/\/$/, "");
206
+ return `${base}/${key}`;
207
+ }
208
+ const region = "eu-central-2";
209
+ const bucket = "vlibe.com";
210
+ return `https://s3.${region}.wasabisys.com/${bucket}/${key}`;
211
+ }
212
+ /**
213
+ * Get a public URL for a file (async version that ensures fresh config)
214
+ * Returns the direct URL based on the configured storage provider
215
+ */
216
+ async getPublicUrlAsync(key) {
217
+ const config = await this.getStorageConfig();
218
+ const base = config.publicUrlBase.replace(/\/$/, "");
219
+ return `${base}/${key}`;
220
+ }
221
+ /**
222
+ * Check if a storage key is in the public path
223
+ */
224
+ isPublicKey(key) {
225
+ return key.startsWith("vlibe-storage/public/");
226
+ }
227
+ // ============================================
228
+ // FILE MANAGEMENT
229
+ // ============================================
230
+ /**
231
+ * List files
232
+ */
233
+ async list(options = {}) {
234
+ const params = new URLSearchParams();
235
+ if (options.folder !== void 0) {
236
+ params.set("folder", options.folder);
237
+ }
238
+ if (options.limit) {
239
+ params.set("limit", options.limit.toString());
240
+ }
241
+ if (options.offset) {
242
+ params.set("offset", options.offset.toString());
243
+ }
244
+ const response = await this.request(
245
+ `/storage?${params}`
246
+ );
247
+ if (!response.success || !response.data) {
248
+ throw new Error(response.error || "Failed to list files");
249
+ }
250
+ return response.data;
251
+ }
252
+ /**
253
+ * Get a single file's metadata
254
+ */
255
+ async get(fileId) {
256
+ const response = await this.request(`/storage/${fileId}`);
257
+ if (!response.success) {
258
+ if (response.error?.includes("not found")) {
259
+ return null;
260
+ }
261
+ throw new Error(response.error || "Failed to get file");
262
+ }
263
+ return response.data || null;
264
+ }
265
+ /**
266
+ * Delete a file
267
+ */
268
+ async delete(fileId) {
269
+ const response = await this.request(`/storage/${fileId}`, {
270
+ method: "DELETE"
271
+ });
272
+ if (!response.success) {
273
+ if (response.error?.includes("not found")) {
274
+ return false;
275
+ }
276
+ throw new Error(response.error || "Failed to delete file");
277
+ }
278
+ return true;
279
+ }
280
+ /**
281
+ * Delete multiple files
282
+ */
283
+ async deleteMany(fileIds) {
284
+ const deleted = [];
285
+ const failed = [];
286
+ const batchSize = 10;
287
+ for (let i = 0; i < fileIds.length; i += batchSize) {
288
+ const batch = fileIds.slice(i, i + batchSize);
289
+ const results = await Promise.allSettled(
290
+ batch.map((id) => this.delete(id))
291
+ );
292
+ results.forEach((result, index) => {
293
+ const id = batch[index];
294
+ if (result.status === "fulfilled" && result.value) {
295
+ deleted.push(id);
296
+ } else {
297
+ failed.push(id);
298
+ }
299
+ });
300
+ }
301
+ return { deleted, failed };
302
+ }
303
+ // ============================================
304
+ // USAGE & LIMITS
305
+ // ============================================
306
+ /**
307
+ * Get storage usage statistics
308
+ */
309
+ async getUsage() {
310
+ const response = await this.request("/storage/usage");
311
+ if (!response.success || !response.data) {
312
+ throw new Error(response.error || "Failed to get usage");
313
+ }
314
+ return response.data;
315
+ }
316
+ /**
317
+ * Check if a file of given size can be uploaded
318
+ */
319
+ async canUpload(size) {
320
+ const response = await this.request("/storage/usage", {
321
+ method: "POST",
322
+ headers: {
323
+ "Content-Type": "application/json"
324
+ },
325
+ body: JSON.stringify({ size })
326
+ });
327
+ if (!response.success || !response.data) {
328
+ throw new Error(response.error || "Failed to check upload");
329
+ }
330
+ return response.data;
331
+ }
332
+ // ============================================
333
+ // FOLDER MANAGEMENT
334
+ // ============================================
335
+ /**
336
+ * List folders
337
+ */
338
+ async listFolders(options = {}) {
339
+ const params = new URLSearchParams();
340
+ if (options.parentId !== void 0) {
341
+ params.set("parentId", options.parentId === null ? "null" : options.parentId);
342
+ }
343
+ if (options.projectId) {
344
+ params.set("projectId", options.projectId);
345
+ }
346
+ const response = await this.request(`/storage/folders?${params}`);
347
+ if (!response.success || !response.data) {
348
+ throw new Error(response.error || "Failed to list folders");
349
+ }
350
+ return response.data;
351
+ }
352
+ /**
353
+ * Create a folder
354
+ */
355
+ async createFolder(name, options = {}) {
356
+ const response = await this.request("/storage/folders", {
357
+ method: "POST",
358
+ headers: {
359
+ "Content-Type": "application/json"
360
+ },
361
+ body: JSON.stringify({
362
+ name,
363
+ parentId: options.parentId,
364
+ projectId: options.projectId,
365
+ isProjectRoot: options.isProjectRoot
366
+ })
367
+ });
368
+ if (!response.success || !response.data) {
369
+ throw new Error(response.error || "Failed to create folder");
370
+ }
371
+ return response.data;
372
+ }
373
+ /**
374
+ * Rename a folder
375
+ */
376
+ async renameFolder(folderId, name) {
377
+ const response = await this.request(`/storage/folders/${folderId}`, {
378
+ method: "PATCH",
379
+ headers: {
380
+ "Content-Type": "application/json"
381
+ },
382
+ body: JSON.stringify({ name })
383
+ });
384
+ if (!response.success || !response.data) {
385
+ throw new Error(response.error || "Failed to rename folder");
386
+ }
387
+ return response.data;
388
+ }
389
+ /**
390
+ * Delete a folder (must be empty)
391
+ */
392
+ async deleteFolder(folderId) {
393
+ const response = await this.request(`/storage/folders/${folderId}`, {
394
+ method: "DELETE"
395
+ });
396
+ if (!response.success) {
397
+ if (response.error?.includes("not found")) {
398
+ return false;
399
+ }
400
+ throw new Error(response.error || "Failed to delete folder");
401
+ }
402
+ return true;
403
+ }
404
+ // ============================================
405
+ // FILE COPY & REFERENCE
406
+ // ============================================
407
+ /**
408
+ * Copy a file to another project
409
+ * Creates a new database record pointing to the same S3 object
410
+ */
411
+ async copyFileToProject(fileId, targetProjectId) {
412
+ const response = await this.request("/storage/files/copy", {
413
+ method: "POST",
414
+ headers: {
415
+ "Content-Type": "application/json"
416
+ },
417
+ body: JSON.stringify({ fileId, targetProjectId })
418
+ });
419
+ if (!response.success || !response.data) {
420
+ throw new Error(response.error || "Failed to copy file");
421
+ }
422
+ return response.data;
423
+ }
424
+ /**
425
+ * Create a file reference (link file to another project without copying)
426
+ * Does not count against storage quota
427
+ */
428
+ async createFileReference(fileId, targetProjectId) {
429
+ const response = await this.request("/storage/files/reference", {
430
+ method: "POST",
431
+ headers: {
432
+ "Content-Type": "application/json"
433
+ },
434
+ body: JSON.stringify({ fileId, targetProjectId })
435
+ });
436
+ if (!response.success || !response.data) {
437
+ throw new Error(response.error || "Failed to create file reference");
438
+ }
439
+ return response.data;
440
+ }
441
+ };
442
+ export {
443
+ VlibeStorage
444
+ };
445
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/VlibeStorage.ts"],"sourcesContent":["/**\n * VlibeStorage - Main SDK class\n */\nimport type {\n VlibeStorageConfig,\n StorageFile,\n UploadOptions,\n UploadResult,\n ListOptions,\n ListResult,\n StorageStats,\n CanUploadResult,\n PresignedUpload,\n ApiResponse,\n Folder,\n CreateFolderOptions,\n ListFoldersOptions,\n FileReference,\n FileCopyResult,\n StorageConfig,\n} from './types';\n\nconst DEFAULT_BASE_URL = 'https://vlibe.app';\n\nexport class VlibeStorage {\n private appId: string;\n private appSecret: string;\n private baseUrl: string;\n private authToken: string | null = null;\n private storageConfig: StorageConfig | null = null;\n\n constructor(config: VlibeStorageConfig) {\n this.appId = config.appId;\n this.appSecret = config.appSecret;\n this.baseUrl = config.baseUrl?.replace(/\\/$/, '') || DEFAULT_BASE_URL;\n }\n\n /**\n * Set the user's auth token (required for authenticated requests)\n */\n setAuthToken(token: string): void {\n this.authToken = token;\n }\n\n /**\n * Clear the auth token\n */\n clearAuthToken(): void {\n this.authToken = null;\n }\n\n /**\n * Get storage configuration from the server\n * This fetches the current storage provider and public URL base\n */\n async getStorageConfig(): Promise<StorageConfig> {\n // Return cached config if available\n if (this.storageConfig) {\n return this.storageConfig;\n }\n\n try {\n const response = await this.request<StorageConfig>('/storage/config');\n if (response.success && response.data) {\n this.storageConfig = response.data;\n return response.data;\n }\n } catch {\n // Fall through to default\n }\n\n // Fallback to legacy Wasabi configuration\n return {\n provider: 'wasabi',\n publicUrlBase: 'https://s3.eu-central-2.wasabisys.com/vlibe.com',\n };\n }\n\n /**\n * Clear cached storage config (call if config might have changed)\n */\n clearStorageConfigCache(): void {\n this.storageConfig = null;\n }\n\n /**\n * Make an authenticated API request\n */\n private async request<T>(\n path: string,\n options: RequestInit = {}\n ): Promise<ApiResponse<T>> {\n const url = `${this.baseUrl}/api${path}`;\n\n const headers: Record<string, string> = {\n 'X-App-Id': this.appId,\n 'X-App-Secret': this.appSecret,\n ...((options.headers as Record<string, string>) || {}),\n };\n\n if (this.authToken) {\n headers['Authorization'] = `Bearer ${this.authToken}`;\n }\n\n const response = await fetch(url, {\n ...options,\n headers,\n });\n\n const data = await response.json();\n\n if (!response.ok && !data.error) {\n return {\n success: false,\n error: `HTTP ${response.status}: ${response.statusText}`,\n };\n }\n\n return data;\n }\n\n // ============================================\n // UPLOAD METHODS\n // ============================================\n\n /**\n * Upload a file directly\n */\n async upload(\n file: File | Blob,\n options: UploadOptions = {}\n ): Promise<UploadResult> {\n const formData = new FormData();\n formData.append('file', file);\n\n if (options.folder) {\n formData.append('folder', options.folder);\n }\n if (options.isPublic) {\n formData.append('isPublic', 'true');\n }\n\n const response = await this.request<UploadResult>('/storage', {\n method: 'POST',\n body: formData,\n });\n\n if (!response.success || !response.data) {\n throw new Error(response.error || 'Upload failed');\n }\n\n return response.data;\n }\n\n /**\n * Get a presigned URL for direct upload to storage\n * Useful for large files or when you want upload progress\n */\n async getUploadUrl(\n filename: string,\n mimeType: string,\n size: number,\n options: Omit<UploadOptions, 'onProgress'> = {}\n ): Promise<PresignedUpload> {\n const response = await this.request<PresignedUpload>('/storage/upload-url', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n filename,\n mimeType,\n size,\n folder: options.folder,\n isPublic: options.isPublic,\n }),\n });\n\n if (!response.success || !response.data) {\n throw new Error(response.error || 'Failed to get upload URL');\n }\n\n return response.data;\n }\n\n /**\n * Upload a file using presigned URL (for progress tracking)\n */\n async uploadWithProgress(\n file: File,\n options: UploadOptions = {}\n ): Promise<UploadResult> {\n // Get presigned URL\n const { uploadUrl, key, expiresIn } = await this.getUploadUrl(\n file.name,\n file.type,\n file.size,\n options\n );\n\n // Upload directly to S3 with progress\n await new Promise<void>((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n\n if (options.onProgress) {\n xhr.upload.addEventListener('progress', (e) => {\n if (e.lengthComputable) {\n const percent = Math.round((e.loaded / e.total) * 100);\n options.onProgress!(percent);\n }\n });\n }\n\n xhr.addEventListener('load', () => {\n if (xhr.status >= 200 && xhr.status < 300) {\n resolve();\n } else {\n reject(new Error(`Upload failed with status ${xhr.status}`));\n }\n });\n\n xhr.addEventListener('error', () => {\n reject(new Error('Upload failed'));\n });\n\n xhr.open('PUT', uploadUrl);\n xhr.setRequestHeader('Content-Type', file.type);\n xhr.send(file);\n });\n\n // Confirm upload\n const response = await this.request<UploadResult>('/storage/upload-url', {\n method: 'PUT',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n key,\n filename: file.name,\n mimeType: file.type,\n size: file.size,\n folder: options.folder,\n isPublic: options.isPublic,\n }),\n });\n\n if (!response.success || !response.data) {\n throw new Error(response.error || 'Failed to confirm upload');\n }\n\n return response.data;\n }\n\n // ============================================\n // DOWNLOAD METHODS\n // ============================================\n\n /**\n * Get a signed download URL for a file\n */\n async getDownloadUrl(fileId: string, expiresIn?: number): Promise<string> {\n const params = new URLSearchParams({ download: 'true' });\n if (expiresIn) {\n params.set('expiresIn', expiresIn.toString());\n }\n\n const response = await this.request<{ url: string; expiresIn: number }>(\n `/storage/${fileId}?${params}`\n );\n\n if (!response.success || !response.data) {\n throw new Error(response.error || 'Failed to get download URL');\n }\n\n return response.data.url;\n }\n\n /**\n * Get a public URL for a file (only works for public files in the public path)\n * Returns the direct URL based on the configured storage provider\n *\n * Note: This is a sync method that uses cached config. Call getStorageConfig()\n * first to ensure the config is loaded, or use getPublicUrlAsync() for a\n * guaranteed fresh URL.\n */\n getPublicUrl(key: string): string {\n // Use cached config if available\n if (this.storageConfig) {\n const base = this.storageConfig.publicUrlBase.replace(/\\/$/, '');\n return `${base}/${key}`;\n }\n\n // Fallback to legacy Wasabi URL\n const region = 'eu-central-2';\n const bucket = 'vlibe.com';\n return `https://s3.${region}.wasabisys.com/${bucket}/${key}`;\n }\n\n /**\n * Get a public URL for a file (async version that ensures fresh config)\n * Returns the direct URL based on the configured storage provider\n */\n async getPublicUrlAsync(key: string): Promise<string> {\n const config = await this.getStorageConfig();\n const base = config.publicUrlBase.replace(/\\/$/, '');\n return `${base}/${key}`;\n }\n\n /**\n * Check if a storage key is in the public path\n */\n isPublicKey(key: string): boolean {\n return key.startsWith('vlibe-storage/public/');\n }\n\n // ============================================\n // FILE MANAGEMENT\n // ============================================\n\n /**\n * List files\n */\n async list(options: ListOptions = {}): Promise<ListResult> {\n const params = new URLSearchParams();\n if (options.folder !== undefined) {\n params.set('folder', options.folder);\n }\n if (options.limit) {\n params.set('limit', options.limit.toString());\n }\n if (options.offset) {\n params.set('offset', options.offset.toString());\n }\n\n const response = await this.request<ListResult>(\n `/storage?${params}`\n );\n\n if (!response.success || !response.data) {\n throw new Error(response.error || 'Failed to list files');\n }\n\n return response.data;\n }\n\n /**\n * Get a single file's metadata\n */\n async get(fileId: string): Promise<StorageFile | null> {\n const response = await this.request<StorageFile>(`/storage/${fileId}`);\n\n if (!response.success) {\n if (response.error?.includes('not found')) {\n return null;\n }\n throw new Error(response.error || 'Failed to get file');\n }\n\n return response.data || null;\n }\n\n /**\n * Delete a file\n */\n async delete(fileId: string): Promise<boolean> {\n const response = await this.request<void>(`/storage/${fileId}`, {\n method: 'DELETE',\n });\n\n if (!response.success) {\n if (response.error?.includes('not found')) {\n return false;\n }\n throw new Error(response.error || 'Failed to delete file');\n }\n\n return true;\n }\n\n /**\n * Delete multiple files\n */\n async deleteMany(fileIds: string[]): Promise<{ deleted: string[]; failed: string[] }> {\n const deleted: string[] = [];\n const failed: string[] = [];\n\n // Delete in parallel batches\n const batchSize = 10;\n for (let i = 0; i < fileIds.length; i += batchSize) {\n const batch = fileIds.slice(i, i + batchSize);\n const results = await Promise.allSettled(\n batch.map((id) => this.delete(id))\n );\n\n results.forEach((result, index) => {\n const id = batch[index];\n if (result.status === 'fulfilled' && result.value) {\n deleted.push(id);\n } else {\n failed.push(id);\n }\n });\n }\n\n return { deleted, failed };\n }\n\n // ============================================\n // USAGE & LIMITS\n // ============================================\n\n /**\n * Get storage usage statistics\n */\n async getUsage(): Promise<StorageStats> {\n const response = await this.request<StorageStats>('/storage/usage');\n\n if (!response.success || !response.data) {\n throw new Error(response.error || 'Failed to get usage');\n }\n\n return response.data;\n }\n\n /**\n * Check if a file of given size can be uploaded\n */\n async canUpload(size: number): Promise<CanUploadResult> {\n const response = await this.request<CanUploadResult>('/storage/usage', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ size }),\n });\n\n if (!response.success || !response.data) {\n throw new Error(response.error || 'Failed to check upload');\n }\n\n return response.data;\n }\n\n // ============================================\n // FOLDER MANAGEMENT\n // ============================================\n\n /**\n * List folders\n */\n async listFolders(options: ListFoldersOptions = {}): Promise<Folder[]> {\n const params = new URLSearchParams();\n if (options.parentId !== undefined) {\n params.set('parentId', options.parentId === null ? 'null' : options.parentId);\n }\n if (options.projectId) {\n params.set('projectId', options.projectId);\n }\n\n const response = await this.request<Folder[]>(`/storage/folders?${params}`);\n\n if (!response.success || !response.data) {\n throw new Error(response.error || 'Failed to list folders');\n }\n\n return response.data;\n }\n\n /**\n * Create a folder\n */\n async createFolder(name: string, options: CreateFolderOptions = {}): Promise<Folder> {\n const response = await this.request<Folder>('/storage/folders', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n name,\n parentId: options.parentId,\n projectId: options.projectId,\n isProjectRoot: options.isProjectRoot,\n }),\n });\n\n if (!response.success || !response.data) {\n throw new Error(response.error || 'Failed to create folder');\n }\n\n return response.data;\n }\n\n /**\n * Rename a folder\n */\n async renameFolder(folderId: string, name: string): Promise<Folder> {\n const response = await this.request<Folder>(`/storage/folders/${folderId}`, {\n method: 'PATCH',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ name }),\n });\n\n if (!response.success || !response.data) {\n throw new Error(response.error || 'Failed to rename folder');\n }\n\n return response.data;\n }\n\n /**\n * Delete a folder (must be empty)\n */\n async deleteFolder(folderId: string): Promise<boolean> {\n const response = await this.request<void>(`/storage/folders/${folderId}`, {\n method: 'DELETE',\n });\n\n if (!response.success) {\n if (response.error?.includes('not found')) {\n return false;\n }\n throw new Error(response.error || 'Failed to delete folder');\n }\n\n return true;\n }\n\n // ============================================\n // FILE COPY & REFERENCE\n // ============================================\n\n /**\n * Copy a file to another project\n * Creates a new database record pointing to the same S3 object\n */\n async copyFileToProject(fileId: string, targetProjectId: string): Promise<FileCopyResult> {\n const response = await this.request<FileCopyResult>('/storage/files/copy', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ fileId, targetProjectId }),\n });\n\n if (!response.success || !response.data) {\n throw new Error(response.error || 'Failed to copy file');\n }\n\n return response.data;\n }\n\n /**\n * Create a file reference (link file to another project without copying)\n * Does not count against storage quota\n */\n async createFileReference(fileId: string, targetProjectId: string): Promise<FileReference> {\n const response = await this.request<FileReference>('/storage/files/reference', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ fileId, targetProjectId }),\n });\n\n if (!response.success || !response.data) {\n throw new Error(response.error || 'Failed to create file reference');\n }\n\n return response.data;\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,68 @@
1
+ import { VlibeStorage, StorageFile, UploadOptions, UploadResult, StorageStats } from './index.mjs';
2
+ export { CanUploadResult, ListOptions, ListResult, PresignedUpload, VlibeStorageConfig } from './index.mjs';
3
+
4
+ interface UseStorageOptions {
5
+ /** Initial folder to list files from */
6
+ folder?: string;
7
+ /** Auto-fetch files on mount */
8
+ autoFetch?: boolean;
9
+ /** Pagination limit */
10
+ limit?: number;
11
+ }
12
+ interface UseStorageReturn {
13
+ /** List of files */
14
+ files: StorageFile[];
15
+ /** Total file count */
16
+ total: number;
17
+ /** Loading state */
18
+ loading: boolean;
19
+ /** Error message if any */
20
+ error: string | null;
21
+ /** Upload a file */
22
+ upload: (file: File, options?: UploadOptions) => Promise<UploadResult>;
23
+ /** Upload with progress tracking */
24
+ uploadWithProgress: (file: File, options?: UploadOptions) => Promise<UploadResult>;
25
+ /** Current upload progress (0-100) */
26
+ uploadProgress: number;
27
+ /** Uploading state */
28
+ uploading: boolean;
29
+ /** Delete a file */
30
+ remove: (fileId: string) => Promise<boolean>;
31
+ /** Refresh the file list */
32
+ refresh: () => Promise<void>;
33
+ /** Load more files (pagination) */
34
+ loadMore: () => Promise<void>;
35
+ /** Whether there are more files to load */
36
+ hasMore: boolean;
37
+ }
38
+ declare function useStorage(client: VlibeStorage, options?: UseStorageOptions): UseStorageReturn;
39
+
40
+ interface UseStorageUsageOptions {
41
+ /** Auto-fetch usage on mount */
42
+ autoFetch?: boolean;
43
+ /** Refresh interval in milliseconds (0 = disabled) */
44
+ refreshInterval?: number;
45
+ }
46
+ interface UseStorageUsageReturn {
47
+ /** Storage usage statistics */
48
+ usage: StorageStats | null;
49
+ /** Loading state */
50
+ loading: boolean;
51
+ /** Error message if any */
52
+ error: string | null;
53
+ /** Check if a file of given size can be uploaded */
54
+ canUpload: (size: number) => boolean;
55
+ /** Refresh usage data */
56
+ refresh: () => Promise<void>;
57
+ /** Usage percentage (0-100) */
58
+ usagePercent: number;
59
+ /** Formatted usage string (e.g., "1.5 GB of 5 GB") */
60
+ usageFormatted: string;
61
+ /** Whether storage limit is reached */
62
+ isLimitReached: boolean;
63
+ /** Whether usage is above 80% */
64
+ isNearLimit: boolean;
65
+ }
66
+ declare function useStorageUsage(client: VlibeStorage, options?: UseStorageUsageOptions): UseStorageUsageReturn;
67
+
68
+ export { StorageFile, StorageStats, UploadOptions, UploadResult, type UseStorageOptions, type UseStorageReturn, type UseStorageUsageOptions, type UseStorageUsageReturn, VlibeStorage, useStorage, useStorageUsage };
@@ -0,0 +1,68 @@
1
+ import { VlibeStorage, StorageFile, UploadOptions, UploadResult, StorageStats } from './index.js';
2
+ export { CanUploadResult, ListOptions, ListResult, PresignedUpload, VlibeStorageConfig } from './index.js';
3
+
4
+ interface UseStorageOptions {
5
+ /** Initial folder to list files from */
6
+ folder?: string;
7
+ /** Auto-fetch files on mount */
8
+ autoFetch?: boolean;
9
+ /** Pagination limit */
10
+ limit?: number;
11
+ }
12
+ interface UseStorageReturn {
13
+ /** List of files */
14
+ files: StorageFile[];
15
+ /** Total file count */
16
+ total: number;
17
+ /** Loading state */
18
+ loading: boolean;
19
+ /** Error message if any */
20
+ error: string | null;
21
+ /** Upload a file */
22
+ upload: (file: File, options?: UploadOptions) => Promise<UploadResult>;
23
+ /** Upload with progress tracking */
24
+ uploadWithProgress: (file: File, options?: UploadOptions) => Promise<UploadResult>;
25
+ /** Current upload progress (0-100) */
26
+ uploadProgress: number;
27
+ /** Uploading state */
28
+ uploading: boolean;
29
+ /** Delete a file */
30
+ remove: (fileId: string) => Promise<boolean>;
31
+ /** Refresh the file list */
32
+ refresh: () => Promise<void>;
33
+ /** Load more files (pagination) */
34
+ loadMore: () => Promise<void>;
35
+ /** Whether there are more files to load */
36
+ hasMore: boolean;
37
+ }
38
+ declare function useStorage(client: VlibeStorage, options?: UseStorageOptions): UseStorageReturn;
39
+
40
+ interface UseStorageUsageOptions {
41
+ /** Auto-fetch usage on mount */
42
+ autoFetch?: boolean;
43
+ /** Refresh interval in milliseconds (0 = disabled) */
44
+ refreshInterval?: number;
45
+ }
46
+ interface UseStorageUsageReturn {
47
+ /** Storage usage statistics */
48
+ usage: StorageStats | null;
49
+ /** Loading state */
50
+ loading: boolean;
51
+ /** Error message if any */
52
+ error: string | null;
53
+ /** Check if a file of given size can be uploaded */
54
+ canUpload: (size: number) => boolean;
55
+ /** Refresh usage data */
56
+ refresh: () => Promise<void>;
57
+ /** Usage percentage (0-100) */
58
+ usagePercent: number;
59
+ /** Formatted usage string (e.g., "1.5 GB of 5 GB") */
60
+ usageFormatted: string;
61
+ /** Whether storage limit is reached */
62
+ isLimitReached: boolean;
63
+ /** Whether usage is above 80% */
64
+ isNearLimit: boolean;
65
+ }
66
+ declare function useStorageUsage(client: VlibeStorage, options?: UseStorageUsageOptions): UseStorageUsageReturn;
67
+
68
+ export { StorageFile, StorageStats, UploadOptions, UploadResult, type UseStorageOptions, type UseStorageReturn, type UseStorageUsageOptions, type UseStorageUsageReturn, VlibeStorage, useStorage, useStorageUsage };