@xenterprises/fastify-xstorage 1.0.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/QUICK_START.md ADDED
@@ -0,0 +1,345 @@
1
+ # Quick Start Guide
2
+
3
+ Get up and running with xStorage in 5 minutes.
4
+
5
+ ## 1. Install
6
+
7
+ ```bash
8
+ npm install @xenterprises/fastify-xstorage @aws-sdk/client-s3 @aws-sdk/s3-request-presigner @fastify/multipart
9
+ ```
10
+
11
+ **For image processing** (optional), also install [@xenterprises/fastify-ximagepipeline](https://github.com/x-enterprises/fastify-plugins/tree/main/fastify-ximagepipeline)
12
+
13
+ ## 2. Setup Storage Provider
14
+
15
+ ### Digital Ocean Spaces
16
+
17
+ 1. Go to https://cloud.digitalocean.com/spaces
18
+ 2. Create a new Space
19
+ 3. Go to API → Tokens/Keys
20
+ 4. Generate new Spaces access key
21
+ 5. Configure CORS in your Space settings
22
+
23
+ ### AWS S3
24
+
25
+ 1. Go to https://console.aws.amazon.com/s3
26
+ 2. Create new bucket
27
+ 3. Go to IAM → Users → Create user
28
+ 4. Attach policy: `AmazonS3FullAccess`
29
+ 5. Create access keys
30
+
31
+ ### Cloudflare R2
32
+
33
+ 1. Go to https://dash.cloudflare.com/r2
34
+ 2. Create new bucket
35
+ 3. Create API token with R2 edit permissions
36
+ 4. Set up custom domain (optional)
37
+
38
+ ## 3. Configure Environment
39
+
40
+ Create `.env`:
41
+
42
+ ```bash
43
+ # Digital Ocean Spaces
44
+ STORAGE_ENDPOINT=https://nyc3.digitaloceanspaces.com
45
+ STORAGE_REGION=us-east-1
46
+ STORAGE_ACCESS_KEY_ID=your_access_key_here
47
+ STORAGE_SECRET_ACCESS_KEY=your_secret_key_here
48
+ STORAGE_BUCKET=your-bucket-name
49
+ STORAGE_PUBLIC_URL=https://your-bucket-name.nyc3.digitaloceanspaces.com
50
+
51
+ PORT=3000
52
+ ```
53
+
54
+ ## 4. Basic Setup
55
+
56
+ ```javascript
57
+ import Fastify from "fastify";
58
+ import multipart from "@fastify/multipart";
59
+ import xStorage from "@xenterprises/fastify-xstorage";
60
+
61
+ const fastify = Fastify({ logger: true });
62
+
63
+ // Register multipart for file uploads
64
+ await fastify.register(multipart, {
65
+ limits: {
66
+ fileSize: 10 * 1024 * 1024, // 10MB
67
+ },
68
+ });
69
+
70
+ // Register xStorage
71
+ await fastify.register(xStorage, {
72
+ endpoint: process.env.STORAGE_ENDPOINT,
73
+ region: process.env.STORAGE_REGION,
74
+ accessKeyId: process.env.STORAGE_ACCESS_KEY_ID,
75
+ secretAccessKey: process.env.STORAGE_SECRET_ACCESS_KEY,
76
+ bucket: process.env.STORAGE_BUCKET,
77
+ publicUrl: process.env.STORAGE_PUBLIC_URL,
78
+ });
79
+
80
+ await fastify.listen({ port: 3000 });
81
+ ```
82
+
83
+ ## 5. Upload Files
84
+
85
+ ```javascript
86
+ fastify.post("/upload", async (request, reply) => {
87
+ const data = await request.file();
88
+ const buffer = await data.toBuffer();
89
+
90
+ const result = await fastify.xStorage.upload(buffer, data.filename, {
91
+ folder: "uploads",
92
+ });
93
+
94
+ // Store in your database
95
+ return {
96
+ success: true,
97
+ file: {
98
+ storageKey: result.key, // Store for deletion
99
+ url: result.url,
100
+ size: result.size,
101
+ contentType: result.contentType,
102
+ },
103
+ };
104
+ });
105
+ ```
106
+
107
+ **For image uploads with processing**, use [@xenterprises/fastify-ximagepipeline](https://github.com/x-enterprises/fastify-plugins/tree/main/fastify-ximagepipeline) for:
108
+ - Automatic optimization and format conversion
109
+ - Thumbnail generation
110
+ - EXIF stripping
111
+ - Multiple variant generation (WebP, AVIF)
112
+
113
+ ## 6. Store in Database
114
+
115
+ Example with Prisma:
116
+
117
+ ```javascript
118
+ fastify.post("/upload", async (request, reply) => {
119
+ const data = await request.file();
120
+ const buffer = await data.toBuffer();
121
+
122
+ // Upload to storage
123
+ const result = await fastify.xStorage.upload(buffer, data.filename, {
124
+ folder: "uploads",
125
+ });
126
+
127
+ // Save to database
128
+ const file = await fastify.prisma.file.create({
129
+ data: {
130
+ filename: data.filename,
131
+ storageKey: result.key, // Store for deletion
132
+ size: result.size,
133
+ contentType: result.contentType,
134
+ userId: request.user.id,
135
+ },
136
+ });
137
+
138
+ return { success: true, file };
139
+ });
140
+ ```
141
+
142
+ ## 7. Delete Files
143
+
144
+ ```javascript
145
+ fastify.delete("/files/:id", async (request, reply) => {
146
+ const { id } = request.params;
147
+
148
+ // Get file from database
149
+ const file = await fastify.prisma.file.findUnique({
150
+ where: { id },
151
+ });
152
+
153
+ // Delete from storage
154
+ await fastify.xStorage.delete(file.storageKey);
155
+
156
+ // Delete from database
157
+ await fastify.prisma.file.delete({
158
+ where: { id },
159
+ });
160
+
161
+ return { success: true };
162
+ });
163
+ ```
164
+
165
+ ## 8. Test Locally
166
+
167
+ ```bash
168
+ # Start server
169
+ npm run dev
170
+
171
+ # Upload a file
172
+ curl -X POST http://localhost:3000/upload \
173
+ -F "file=@./test-image.jpg"
174
+
175
+ # You'll get back:
176
+ {
177
+ "success": true,
178
+ "file": {
179
+ "url": "https://your-bucket.nyc3.digitaloceanspaces.com/uploads/test-image-a1b2c3d4.jpg",
180
+ "key": "uploads/test-image-a1b2c3d4.jpg",
181
+ "size": 245678
182
+ }
183
+ }
184
+
185
+ # Visit the URL in your browser to verify it works!
186
+ ```
187
+
188
+ ## Common Use Cases
189
+
190
+ ### Document Upload with Validation
191
+
192
+ ```javascript
193
+ import { helpers } from "@xenterprises/fastify-xstorage";
194
+
195
+ fastify.post("/documents", async (request, reply) => {
196
+ const data = await request.file();
197
+
198
+ // Validate file type
199
+ if (!helpers.isPdf(data.filename) && !helpers.isImage(data.filename)) {
200
+ return reply.code(400).send({ error: "Only PDF and images allowed" });
201
+ }
202
+
203
+ const buffer = await data.toBuffer();
204
+
205
+ // Upload file
206
+ const result = await fastify.xStorage.upload(buffer, data.filename, {
207
+ folder: "documents",
208
+ });
209
+
210
+ // For images, use xImagePipeline for processing
211
+ // For PDFs, store as-is
212
+
213
+ await fastify.prisma.document.create({
214
+ data: {
215
+ filename: data.filename,
216
+ storageKey: result.key,
217
+ size: result.size,
218
+ contentType: result.contentType,
219
+ },
220
+ });
221
+
222
+ return { success: true, document: result };
223
+ });
224
+ ```
225
+
226
+ ### Generate Signed URLs for Private Files
227
+
228
+ ```javascript
229
+ // Get download URL for private file
230
+ fastify.get("/documents/:id/download", async (request, reply) => {
231
+ const { id } = request.params;
232
+
233
+ const document = await fastify.prisma.document.findUnique({ where: { id } });
234
+
235
+ // Generate signed URL valid for 1 hour
236
+ const signedUrl = await fastify.xStorage.getSignedUrl(
237
+ document.storageKey,
238
+ 3600
239
+ );
240
+
241
+ return { download: signedUrl };
242
+ });
243
+ ```
244
+
245
+ ### Batch Upload
246
+
247
+ ```javascript
248
+ fastify.post("/batch-upload", async (request, reply) => {
249
+ const parts = request.parts();
250
+ const files = [];
251
+
252
+ for await (const part of parts) {
253
+ if (part.type === "file") {
254
+ const buffer = await part.toBuffer();
255
+ files.push({ file: buffer, filename: part.filename });
256
+ }
257
+ }
258
+
259
+ const results = await fastify.xStorage.uploadMultiple(files, {
260
+ folder: "batch-uploads",
261
+ });
262
+
263
+ return { success: true, files: results };
264
+ });
265
+ ```
266
+
267
+ ### Image Processing
268
+
269
+ For user avatars, product images, and other image processing needs, use **[@xenterprises/fastify-ximagepipeline](https://github.com/x-enterprises/fastify-plugins/tree/main/fastify-ximagepipeline)** which handles:
270
+ - Automatic optimization and resizing
271
+ - WebP/AVIF conversion
272
+ - Thumbnail generation with multiple sizes
273
+ - EXIF stripping
274
+ - Blur hash generation
275
+
276
+ ## Tips
277
+
278
+ 1. **Always store the storage key** in your database
279
+ - `storageKey` - For deleting or accessing files later
280
+ - Store reference to key, not just the URL
281
+
282
+ 2. **Use folders** to organize files logically
283
+ ```javascript
284
+ folder: "users/123/documents"
285
+ folder: "invoices/2024/january"
286
+ folder: "receipts/2024"
287
+ ```
288
+
289
+ 3. **Use signed URLs for private files**
290
+ ```javascript
291
+ const signedUrl = await fastify.xStorage.getSignedUrl(key, 3600);
292
+ // Expires in 1 hour
293
+ ```
294
+
295
+ 4. **Validate file types** before uploading
296
+ ```javascript
297
+ import { helpers } from "@xenterprises/fastify-xstorage";
298
+
299
+ if (!helpers.isPdf(filename)) {
300
+ return reply.code(400).send({ error: "Only PDFs allowed" });
301
+ }
302
+ ```
303
+
304
+ 5. **Delete old files** when replacing
305
+ ```javascript
306
+ if (oldFile.storageKey) {
307
+ await fastify.xStorage.delete(oldFile.storageKey);
308
+ }
309
+ ```
310
+
311
+ 6. **Use batch operations** for better performance
312
+ ```javascript
313
+ await fastify.xStorage.uploadMultiple(files, { folder: "uploads" });
314
+ await fastify.xStorage.deleteMultiple(keys);
315
+ ```
316
+
317
+ ## Next Steps
318
+
319
+ - [Full Documentation](./README.md)
320
+ - [Testing Guide](./TESTING.md)
321
+ - [Complete Examples](./EXAMPLES.md)
322
+
323
+ ## Troubleshooting
324
+
325
+ ### Files not uploading?
326
+
327
+ 1. Check credentials are correct
328
+ 2. Verify bucket exists and is accessible
329
+ 3. Check IAM permissions (should allow S3 operations)
330
+ 4. Ensure CORS is configured on bucket
331
+ 5. Check file size limits
332
+
333
+ ### Signed URLs not working?
334
+
335
+ 1. Verify credentials are correct
336
+ 2. Check file actually exists in bucket
337
+ 3. Check URL hasn't expired
338
+ 4. Try with longer expiration time
339
+
340
+ ### Connection issues?
341
+
342
+ 1. Verify `endpoint` URL is correct
343
+ 2. Check network connectivity to S3 provider
344
+ 3. Ensure credentials haven't expired
345
+ 4. Verify region is correct for AWS S3