|
| 1 | +--- |
| 2 | +name: cloud-storage-web |
| 3 | +description: Complete guide for CloudBase cloud storage using Web SDK (@cloudbase/js-sdk) - upload, download, temporary URLs, file management, and best practices. |
| 4 | +alwaysApply: false |
| 5 | +--- |
| 6 | + |
| 7 | +# Cloud Storage Web SDK |
| 8 | + |
| 9 | +Use this skill when building web applications that need to upload, download, or manage files using CloudBase cloud storage via the `@cloudbase/js-sdk` (Web SDK). |
| 10 | + |
| 11 | +## When to use this skill |
| 12 | + |
| 13 | +Use this skill for **file storage operations** in web applications when you need to: |
| 14 | + |
| 15 | +- Upload files from web browsers to CloudBase cloud storage |
| 16 | +- Generate temporary download URLs for stored files |
| 17 | +- Delete files from cloud storage |
| 18 | +- Download files from cloud storage to local browser |
| 19 | + |
| 20 | +**Do NOT use for:** |
| 21 | +- Mini-program file operations (use mini-program specific skills) |
| 22 | +- Backend file operations (use Node SDK skills) |
| 23 | +- Database operations (use database skills) |
| 24 | + |
| 25 | +## How to use this skill (for a coding agent) |
| 26 | + |
| 27 | +1. **Initialize CloudBase SDK** |
| 28 | + - Ask the user for their CloudBase environment ID |
| 29 | + - Always use the standard initialization pattern shown below |
| 30 | + |
| 31 | +2. **Choose the right storage method** |
| 32 | + - `uploadFile` - For uploading files from browser to cloud storage |
| 33 | + - `getTempFileURL` - For generating temporary download links |
| 34 | + - `deleteFile` - For deleting files from storage |
| 35 | + - `downloadFile` - For downloading files to browser |
| 36 | + |
| 37 | +3. **Handle CORS requirements** |
| 38 | + - Remind users to add their domain to CloudBase console security domains |
| 39 | + - This prevents CORS errors during file operations |
| 40 | + |
| 41 | +4. **Follow file path rules** |
| 42 | + - Use valid characters: `[0-9a-zA-Z]`, `/`, `!`, `-`, `_`, `.`, ` `, `*`, Chinese characters |
| 43 | + - Use `/` for folder structure (e.g., `folder/file.jpg`) |
| 44 | + |
| 45 | +--- |
| 46 | + |
| 47 | +## SDK Initialization |
| 48 | + |
| 49 | +```javascript |
| 50 | +import cloudbase from "@cloudbase/js-sdk"; |
| 51 | + |
| 52 | +const app = cloudbase.init({ |
| 53 | + env: "your-env-id", // Replace with your CloudBase environment ID |
| 54 | +}); |
| 55 | +``` |
| 56 | + |
| 57 | +**Initialization rules:** |
| 58 | +- Always use synchronous initialization with the pattern above |
| 59 | +- Do not lazy-load the SDK with dynamic imports |
| 60 | +- Keep a single shared `app` instance across your application |
| 61 | + |
| 62 | +## File Upload (uploadFile) |
| 63 | + |
| 64 | +### Basic Usage |
| 65 | + |
| 66 | +```javascript |
| 67 | +const result = await app.uploadFile({ |
| 68 | + cloudPath: "folder/filename.jpg", // File path in cloud storage |
| 69 | + filePath: fileInput.files[0], // HTML file input element |
| 70 | +}); |
| 71 | + |
| 72 | +// Result contains: |
| 73 | +{ |
| 74 | + fileID: "cloud://env-id/folder/filename.jpg", // Unique file identifier |
| 75 | + // ... other metadata |
| 76 | +} |
| 77 | +``` |
| 78 | + |
| 79 | +### Advanced Upload with Progress |
| 80 | + |
| 81 | +```javascript |
| 82 | +const result = await app.uploadFile({ |
| 83 | + cloudPath: "uploads/avatar.jpg", |
| 84 | + filePath: selectedFile, |
| 85 | + method: "put", // "post" or "put" (default: "put") |
| 86 | + onUploadProgress: (progressEvent) => { |
| 87 | + const percent = Math.round( |
| 88 | + (progressEvent.loaded * 100) / progressEvent.total |
| 89 | + ); |
| 90 | + console.log(`Upload progress: ${percent}%`); |
| 91 | + // Update UI progress bar here |
| 92 | + } |
| 93 | +}); |
| 94 | +``` |
| 95 | + |
| 96 | +### Parameters |
| 97 | + |
| 98 | +| Parameter | Type | Required | Description | |
| 99 | +|-----------|------|----------|-------------| |
| 100 | +| `cloudPath` | string | Yes | Absolute path with filename (e.g., "folder/file.jpg") | |
| 101 | +| `filePath` | File | Yes | HTML file input object | |
| 102 | +| `method` | "post" \| "put" | No | Upload method (default: "put") | |
| 103 | +| `onUploadProgress` | function | No | Progress callback function | |
| 104 | + |
| 105 | +### Cloud Path Rules |
| 106 | + |
| 107 | +- **Valid characters**: `[0-9a-zA-Z]`, `/`, `!`, `-`, `_`, `.`, ` `, `*`, Chinese characters |
| 108 | +- **Invalid characters**: Other special characters |
| 109 | +- **Structure**: Use `/` to create folder hierarchy |
| 110 | +- **Examples**: |
| 111 | + - `"avatar.jpg"` |
| 112 | + - `"uploads/avatar.jpg"` |
| 113 | + - `"user/123/avatar.jpg"` |
| 114 | + |
| 115 | +### CORS Configuration |
| 116 | + |
| 117 | +**⚠️ IMPORTANT:** To prevent CORS errors, add your domain to CloudBase console: |
| 118 | + |
| 119 | +1. Go to CloudBase Console → Environment → Security Sources → Security Domains |
| 120 | +2. Add your frontend domain (e.g., `https://your-app.com`, `http://localhost:3000`) |
| 121 | +3. If CORS errors occur, remove and re-add the domain |
| 122 | + |
| 123 | +## Temporary Download URLs (getTempFileURL) |
| 124 | + |
| 125 | +### Basic Usage |
| 126 | + |
| 127 | +```javascript |
| 128 | +const result = await app.getTempFileURL({ |
| 129 | + fileList: [ |
| 130 | + { |
| 131 | + fileID: "cloud://env-id/folder/filename.jpg", |
| 132 | + maxAge: 3600 // URL valid for 1 hour (seconds) |
| 133 | + } |
| 134 | + ] |
| 135 | +}); |
| 136 | + |
| 137 | +// Access the download URL |
| 138 | +result.fileList.forEach(file => { |
| 139 | + if (file.code === "SUCCESS") { |
| 140 | + console.log("Download URL:", file.tempFileURL); |
| 141 | + // Use this URL to download or display the file |
| 142 | + } |
| 143 | +}); |
| 144 | +``` |
| 145 | + |
| 146 | +### Multiple Files |
| 147 | + |
| 148 | +```javascript |
| 149 | +const result = await app.getTempFileURL({ |
| 150 | + fileList: [ |
| 151 | + { |
| 152 | + fileID: "cloud://env-id/image1.jpg", |
| 153 | + maxAge: 7200 // 2 hours |
| 154 | + }, |
| 155 | + { |
| 156 | + fileID: "cloud://env-id/document.pdf", |
| 157 | + maxAge: 86400 // 24 hours |
| 158 | + } |
| 159 | + ] |
| 160 | +}); |
| 161 | +``` |
| 162 | + |
| 163 | +### Parameters |
| 164 | + |
| 165 | +| Parameter | Type | Required | Description | |
| 166 | +|-----------|------|----------|-------------| |
| 167 | +| `fileList` | Array | Yes | Array of file objects | |
| 168 | + |
| 169 | +#### fileList Item Structure |
| 170 | + |
| 171 | +| Parameter | Type | Required | Description | |
| 172 | +|-----------|------|----------|-------------| |
| 173 | +| `fileID` | string | Yes | Cloud storage file ID | |
| 174 | +| `maxAge` | number | Yes | URL validity period in seconds | |
| 175 | + |
| 176 | +### Response Structure |
| 177 | + |
| 178 | +```javascript |
| 179 | +{ |
| 180 | + code: "SUCCESS", |
| 181 | + fileList: [ |
| 182 | + { |
| 183 | + code: "SUCCESS", |
| 184 | + fileID: "cloud://env-id/folder/filename.jpg", |
| 185 | + tempFileURL: "https://temporary-download-url" |
| 186 | + } |
| 187 | + ] |
| 188 | +} |
| 189 | +``` |
| 190 | + |
| 191 | +### Best Practices |
| 192 | + |
| 193 | +- Set appropriate `maxAge` based on use case (1 hour to 24 hours) |
| 194 | +- Handle `SUCCESS`/`ERROR` codes in response |
| 195 | +- Use temporary URLs for private file access |
| 196 | +- Cache URLs if needed, but respect expiration time |
| 197 | + |
| 198 | +## File Deletion (deleteFile) |
| 199 | + |
| 200 | +### Basic Usage |
| 201 | + |
| 202 | +```javascript |
| 203 | +const result = await app.deleteFile({ |
| 204 | + fileList: [ |
| 205 | + "cloud://env-id/folder/filename.jpg" |
| 206 | + ] |
| 207 | +}); |
| 208 | + |
| 209 | +// Check deletion results |
| 210 | +result.fileList.forEach(file => { |
| 211 | + if (file.code === "SUCCESS") { |
| 212 | + console.log("File deleted:", file.fileID); |
| 213 | + } else { |
| 214 | + console.error("Failed to delete:", file.fileID); |
| 215 | + } |
| 216 | +}); |
| 217 | +``` |
| 218 | + |
| 219 | +### Multiple Files |
| 220 | + |
| 221 | +```javascript |
| 222 | +const result = await app.deleteFile({ |
| 223 | + fileList: [ |
| 224 | + "cloud://env-id/old-avatar.jpg", |
| 225 | + "cloud://env-id/temp-upload.jpg", |
| 226 | + "cloud://env-id/cache-file.dat" |
| 227 | + ] |
| 228 | +}); |
| 229 | +``` |
| 230 | + |
| 231 | +### Parameters |
| 232 | + |
| 233 | +| Parameter | Type | Required | Description | |
| 234 | +|-----------|------|----------|-------------| |
| 235 | +| `fileList` | Array<string> | Yes | Array of file IDs to delete | |
| 236 | + |
| 237 | +### Response Structure |
| 238 | + |
| 239 | +```javascript |
| 240 | +{ |
| 241 | + fileList: [ |
| 242 | + { |
| 243 | + code: "SUCCESS", |
| 244 | + fileID: "cloud://env-id/folder/filename.jpg" |
| 245 | + } |
| 246 | + ] |
| 247 | +} |
| 248 | +``` |
| 249 | + |
| 250 | +### Best Practices |
| 251 | + |
| 252 | +- Always check response codes before assuming deletion success |
| 253 | +- Use this for cleanup operations (old avatars, temp files, etc.) |
| 254 | +- Consider batching multiple deletions for efficiency |
| 255 | + |
| 256 | +## File Download (downloadFile) |
| 257 | + |
| 258 | +### Basic Usage |
| 259 | + |
| 260 | +```javascript |
| 261 | +const result = await app.downloadFile({ |
| 262 | + fileID: "cloud://env-id/folder/filename.jpg" |
| 263 | +}); |
| 264 | + |
| 265 | +// File is downloaded to browser default download location |
| 266 | +``` |
| 267 | + |
| 268 | +### Parameters |
| 269 | + |
| 270 | +| Parameter | Type | Required | Description | |
| 271 | +|-----------|------|----------|-------------| |
| 272 | +| `fileID` | string | Yes | Cloud storage file ID | |
| 273 | + |
| 274 | +### Response Structure |
| 275 | + |
| 276 | +```javascript |
| 277 | +{ |
| 278 | + // Success response (no specific data returned) |
| 279 | + // File is downloaded to browser |
| 280 | +} |
| 281 | +``` |
| 282 | + |
| 283 | +### Best Practices |
| 284 | + |
| 285 | +- Use for user-initiated downloads (save file dialogs) |
| 286 | +- For programmatic file access, use `getTempFileURL` instead |
| 287 | +- Handle download errors appropriately |
| 288 | + |
| 289 | +## Error Handling |
| 290 | + |
| 291 | +All storage operations should include proper error handling: |
| 292 | + |
| 293 | +```javascript |
| 294 | +try { |
| 295 | + const result = await app.uploadFile({ |
| 296 | + cloudPath: "uploads/file.jpg", |
| 297 | + filePath: selectedFile |
| 298 | + }); |
| 299 | + |
| 300 | + if (result.code) { |
| 301 | + // Handle error |
| 302 | + console.error("Upload failed:", result.message); |
| 303 | + } else { |
| 304 | + // Success |
| 305 | + console.log("File uploaded:", result.fileID); |
| 306 | + } |
| 307 | +} catch (error) { |
| 308 | + console.error("Storage operation failed:", error); |
| 309 | +} |
| 310 | +``` |
| 311 | + |
| 312 | +### Common Error Codes |
| 313 | + |
| 314 | +- `INVALID_PARAM` - Invalid parameters |
| 315 | +- `PERMISSION_DENIED` - Insufficient permissions |
| 316 | +- `RESOURCE_NOT_FOUND` - File not found |
| 317 | +- `SYS_ERR` - System error |
| 318 | + |
| 319 | + |
| 320 | +## Best Practices |
| 321 | + |
| 322 | +1. **File Organization**: Use consistent folder structures (`uploads/`, `avatars/`, `documents/`) |
| 323 | +2. **Naming Conventions**: Use descriptive filenames with timestamps if needed |
| 324 | +3. **Progress Feedback**: Show upload progress for better UX |
| 325 | +4. **Cleanup**: Delete temporary/unused files to save storage costs |
| 326 | +5. **Security**: Validate file types and sizes before upload |
| 327 | +6. **Caching**: Cache download URLs appropriately but respect expiration |
| 328 | +7. **Batch Operations**: Use arrays for multiple file operations when possible |
| 329 | + |
| 330 | +## Performance Considerations |
| 331 | + |
| 332 | +1. **File Size Limits**: Be aware of CloudBase file size limits |
| 333 | +2. **Concurrent Uploads**: Limit concurrent uploads to prevent browser overload |
| 334 | +3. **Progress Monitoring**: Use progress callbacks for large file uploads |
| 335 | +4. **Temporary URLs**: Generate URLs only when needed, with appropriate expiration |
| 336 | + |
| 337 | +## Security Considerations |
| 338 | + |
| 339 | +1. **Domain Whitelisting**: Always configure security domains to prevent CORS issues |
| 340 | +2. **Access Control**: Use appropriate file permissions (public vs private) |
| 341 | +3. **URL Expiration**: Set reasonable expiration times for temporary URLs |
| 342 | +4. **User Permissions**: Ensure users can only access their own files when appropriate |
| 343 | + |
0 commit comments