@rytass/storages-adapter-gcs 0.2.5 → 0.2.6
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/README.md +51 -56
- package/index.cjs.js +1 -1
- package/package.json +4 -4
- package/storages-adapter-gcs.js +1 -1
- package/typings.d.ts +1 -0
package/README.md
CHANGED
|
@@ -34,8 +34,8 @@ const storage = new StorageGCSService({
|
|
|
34
34
|
projectId: 'your-gcp-project-id',
|
|
35
35
|
credentials: {
|
|
36
36
|
client_email: 'your-service-account@project.iam.gserviceaccount.com',
|
|
37
|
-
private_key: '-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n'
|
|
38
|
-
}
|
|
37
|
+
private_key: '-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n',
|
|
38
|
+
},
|
|
39
39
|
});
|
|
40
40
|
```
|
|
41
41
|
|
|
@@ -48,7 +48,7 @@ import { readFileSync, createReadStream } from 'fs';
|
|
|
48
48
|
const imageBuffer = readFileSync('photo.jpg');
|
|
49
49
|
const result = await storage.write(imageBuffer, {
|
|
50
50
|
filename: 'uploads/photo.jpg',
|
|
51
|
-
contentType: 'image/jpeg'
|
|
51
|
+
contentType: 'image/jpeg',
|
|
52
52
|
});
|
|
53
53
|
console.log('Uploaded:', result.key);
|
|
54
54
|
|
|
@@ -56,7 +56,7 @@ console.log('Uploaded:', result.key);
|
|
|
56
56
|
const fileStream = createReadStream('document.pdf');
|
|
57
57
|
const streamResult = await storage.write(fileStream, {
|
|
58
58
|
filename: 'documents/document.pdf',
|
|
59
|
-
contentType: 'application/pdf'
|
|
59
|
+
contentType: 'application/pdf',
|
|
60
60
|
});
|
|
61
61
|
console.log('Uploaded:', streamResult.key);
|
|
62
62
|
|
|
@@ -91,10 +91,7 @@ const url = await storage.url('uploads/photo.jpg');
|
|
|
91
91
|
console.log('Signed URL:', url);
|
|
92
92
|
|
|
93
93
|
// Custom expiration (1 hour from now)
|
|
94
|
-
const customUrl = await storage.url(
|
|
95
|
-
'uploads/photo.jpg',
|
|
96
|
-
Date.now() + 1000 * 60 * 60
|
|
97
|
-
);
|
|
94
|
+
const customUrl = await storage.url('uploads/photo.jpg', Date.now() + 1000 * 60 * 60);
|
|
98
95
|
console.log('1-hour URL:', customUrl);
|
|
99
96
|
|
|
100
97
|
// Use in HTML
|
|
@@ -116,11 +113,7 @@ await storage.remove('uploads/old-file.jpg');
|
|
|
116
113
|
console.log('File removed');
|
|
117
114
|
|
|
118
115
|
// Batch upload
|
|
119
|
-
const files = [
|
|
120
|
-
readFileSync('file1.jpg'),
|
|
121
|
-
readFileSync('file2.png'),
|
|
122
|
-
createReadStream('file3.pdf')
|
|
123
|
-
];
|
|
116
|
+
const files = [readFileSync('file1.jpg'), readFileSync('file2.png'), createReadStream('file3.pdf')];
|
|
124
117
|
|
|
125
118
|
const batchResults = await storage.batchWrite(files);
|
|
126
119
|
batchResults.forEach(result => {
|
|
@@ -146,8 +139,8 @@ const storage = new StorageGCSService({
|
|
|
146
139
|
projectId: process.env.GCS_PROJECT_ID!,
|
|
147
140
|
credentials: {
|
|
148
141
|
client_email: process.env.GCS_CLIENT_EMAIL!,
|
|
149
|
-
private_key: process.env.GCS_PRIVATE_KEY!.replace(/\\n/g, '\n')
|
|
150
|
-
}
|
|
142
|
+
private_key: process.env.GCS_PRIVATE_KEY!.replace(/\\n/g, '\n'),
|
|
143
|
+
},
|
|
151
144
|
});
|
|
152
145
|
```
|
|
153
146
|
|
|
@@ -157,17 +150,15 @@ const storage = new StorageGCSService({
|
|
|
157
150
|
import { readFileSync } from 'fs';
|
|
158
151
|
|
|
159
152
|
// Load service account key from JSON file
|
|
160
|
-
const serviceAccount = JSON.parse(
|
|
161
|
-
readFileSync('path/to/service-account-key.json', 'utf8')
|
|
162
|
-
);
|
|
153
|
+
const serviceAccount = JSON.parse(readFileSync('path/to/service-account-key.json', 'utf8'));
|
|
163
154
|
|
|
164
155
|
const storage = new StorageGCSService({
|
|
165
156
|
bucket: 'your-bucket-name',
|
|
166
157
|
projectId: serviceAccount.project_id,
|
|
167
158
|
credentials: {
|
|
168
159
|
client_email: serviceAccount.client_email,
|
|
169
|
-
private_key: serviceAccount.private_key
|
|
170
|
-
}
|
|
160
|
+
private_key: serviceAccount.private_key,
|
|
161
|
+
},
|
|
171
162
|
});
|
|
172
163
|
```
|
|
173
164
|
|
|
@@ -177,7 +168,7 @@ const storage = new StorageGCSService({
|
|
|
177
168
|
// Upload with custom metadata
|
|
178
169
|
const result = await storage.write(fileBuffer, {
|
|
179
170
|
filename: 'uploads/document.pdf',
|
|
180
|
-
contentType: 'application/pdf'
|
|
171
|
+
contentType: 'application/pdf',
|
|
181
172
|
});
|
|
182
173
|
|
|
183
174
|
// The service automatically sets:
|
|
@@ -196,15 +187,15 @@ async function processLargeFile(inputPath: string, outputKey: string) {
|
|
|
196
187
|
// Upload large file as stream
|
|
197
188
|
const inputStream = createReadStream(inputPath);
|
|
198
189
|
const uploadResult = await storage.write(inputStream, {
|
|
199
|
-
filename: outputKey
|
|
190
|
+
filename: outputKey,
|
|
200
191
|
});
|
|
201
|
-
|
|
192
|
+
|
|
202
193
|
console.log('Large file uploaded:', uploadResult.key);
|
|
203
|
-
|
|
194
|
+
|
|
204
195
|
// Download large file as stream
|
|
205
196
|
const downloadStream = await storage.read(outputKey);
|
|
206
197
|
const outputStream = createWriteStream('downloaded-large-file');
|
|
207
|
-
|
|
198
|
+
|
|
208
199
|
await pipeline(downloadStream, outputStream);
|
|
209
200
|
console.log('Large file downloaded');
|
|
210
201
|
}
|
|
@@ -261,8 +252,8 @@ const storage = new StorageGCSService({
|
|
|
261
252
|
projectId: 'your-project',
|
|
262
253
|
credentials: {
|
|
263
254
|
client_email: process.env.GCS_CLIENT_EMAIL!,
|
|
264
|
-
private_key: process.env.GCS_PRIVATE_KEY
|
|
265
|
-
}
|
|
255
|
+
private_key: process.env.GCS_PRIVATE_KEY!,
|
|
256
|
+
},
|
|
266
257
|
});
|
|
267
258
|
|
|
268
259
|
app.post('/upload', upload.single('file'), async (req, res) => {
|
|
@@ -273,7 +264,7 @@ app.post('/upload', upload.single('file'), async (req, res) => {
|
|
|
273
264
|
|
|
274
265
|
const result = await storage.write(req.file.buffer, {
|
|
275
266
|
filename: `uploads/${Date.now()}-${req.file.originalname}`,
|
|
276
|
-
contentType: req.file.mimetype
|
|
267
|
+
contentType: req.file.mimetype,
|
|
277
268
|
});
|
|
278
269
|
|
|
279
270
|
const publicUrl = await storage.url(result.key);
|
|
@@ -281,7 +272,7 @@ app.post('/upload', upload.single('file'), async (req, res) => {
|
|
|
281
272
|
res.json({
|
|
282
273
|
success: true,
|
|
283
274
|
key: result.key,
|
|
284
|
-
url: publicUrl
|
|
275
|
+
url: publicUrl,
|
|
285
276
|
});
|
|
286
277
|
} catch (error) {
|
|
287
278
|
res.status(500).json({ error: 'Upload failed' });
|
|
@@ -305,8 +296,8 @@ export class FileService {
|
|
|
305
296
|
projectId: process.env.GCS_PROJECT_ID!,
|
|
306
297
|
credentials: {
|
|
307
298
|
client_email: process.env.GCS_CLIENT_EMAIL!,
|
|
308
|
-
private_key: process.env.GCS_PRIVATE_KEY!.replace(/\\n/g, '\n')
|
|
309
|
-
}
|
|
299
|
+
private_key: process.env.GCS_PRIVATE_KEY!.replace(/\\n/g, '\n'),
|
|
300
|
+
},
|
|
310
301
|
});
|
|
311
302
|
}
|
|
312
303
|
|
|
@@ -340,12 +331,12 @@ import { ImageTranscoder } from '@rytass/file-converter-adapter-image-transcoder
|
|
|
340
331
|
class ImageProcessor {
|
|
341
332
|
constructor(
|
|
342
333
|
private storage: StorageGCSService,
|
|
343
|
-
private converter: ConverterManager
|
|
334
|
+
private converter: ConverterManager,
|
|
344
335
|
) {}
|
|
345
336
|
|
|
346
337
|
async processAndUpload(
|
|
347
338
|
imageBuffer: Buffer,
|
|
348
|
-
sizes: { width: number; height: number; suffix: string }[]
|
|
339
|
+
sizes: { width: number; height: number; suffix: string }[],
|
|
349
340
|
): Promise<{ [key: string]: string }> {
|
|
350
341
|
const results: { [key: string]: string } = {};
|
|
351
342
|
|
|
@@ -355,12 +346,12 @@ class ImageProcessor {
|
|
|
355
346
|
new ImageResizer({
|
|
356
347
|
maxWidth: size.width,
|
|
357
348
|
maxHeight: size.height,
|
|
358
|
-
keepAspectRatio: true
|
|
349
|
+
keepAspectRatio: true,
|
|
359
350
|
}),
|
|
360
351
|
new ImageTranscoder({
|
|
361
352
|
format: 'webp',
|
|
362
|
-
quality: 85
|
|
363
|
-
})
|
|
353
|
+
quality: 85,
|
|
354
|
+
}),
|
|
364
355
|
]);
|
|
365
356
|
|
|
366
357
|
// Process image
|
|
@@ -369,7 +360,7 @@ class ImageProcessor {
|
|
|
369
360
|
// Upload to GCS
|
|
370
361
|
const uploadResult = await this.storage.write(processedImage, {
|
|
371
362
|
filename: `images/processed-${size.suffix}.webp`,
|
|
372
|
-
contentType: 'image/webp'
|
|
363
|
+
contentType: 'image/webp',
|
|
373
364
|
});
|
|
374
365
|
|
|
375
366
|
// Generate public URL
|
|
@@ -385,7 +376,7 @@ const processor = new ImageProcessor(storage, converter);
|
|
|
385
376
|
const urls = await processor.processAndUpload(originalImage, [
|
|
386
377
|
{ width: 150, height: 150, suffix: 'thumbnail' },
|
|
387
378
|
{ width: 800, height: 600, suffix: 'medium' },
|
|
388
|
-
{ width: 1920, height: 1080, suffix: 'large' }
|
|
379
|
+
{ width: 1920, height: 1080, suffix: 'large' },
|
|
389
380
|
]);
|
|
390
381
|
|
|
391
382
|
console.log('Generated URLs:', urls);
|
|
@@ -395,54 +386,58 @@ console.log('Generated URLs:', urls);
|
|
|
395
386
|
|
|
396
387
|
### GCSOptions
|
|
397
388
|
|
|
398
|
-
| Option
|
|
399
|
-
|
|
400
|
-
| `bucket`
|
|
401
|
-
| `projectId`
|
|
402
|
-
| `credentials`
|
|
403
|
-
| `credentials.client_email` | `string` | Yes
|
|
404
|
-
| `credentials.private_key`
|
|
389
|
+
| Option | Type | Required | Description |
|
|
390
|
+
| -------------------------- | -------- | -------- | -------------------------------- |
|
|
391
|
+
| `bucket` | `string` | Yes | Google Cloud Storage bucket name |
|
|
392
|
+
| `projectId` | `string` | Yes | Google Cloud Project ID |
|
|
393
|
+
| `credentials` | `object` | Yes | Service account credentials |
|
|
394
|
+
| `credentials.client_email` | `string` | Yes | Service account email |
|
|
395
|
+
| `credentials.private_key` | `string` | Yes | Service account private key |
|
|
405
396
|
|
|
406
397
|
### WriteFileOptions
|
|
407
398
|
|
|
408
|
-
| Option
|
|
409
|
-
|
|
410
|
-
| `filename`
|
|
411
|
-
| `contentType` | `string` | auto-detected
|
|
399
|
+
| Option | Type | Default | Description |
|
|
400
|
+
| ------------- | -------- | -------------- | ------------------------------------- |
|
|
401
|
+
| `filename` | `string` | auto-generated | Custom filename for the uploaded file |
|
|
402
|
+
| `contentType` | `string` | auto-detected | MIME type of the file |
|
|
412
403
|
|
|
413
404
|
### ReadBufferFileOptions
|
|
414
405
|
|
|
415
|
-
| Option
|
|
416
|
-
|
|
417
|
-
| `format` | `'buffer'` | -
|
|
406
|
+
| Option | Type | Default | Description |
|
|
407
|
+
| -------- | ---------- | ------- | --------------------- |
|
|
408
|
+
| `format` | `'buffer'` | - | Return file as Buffer |
|
|
418
409
|
|
|
419
410
|
### ReadStreamFileOptions
|
|
420
411
|
|
|
421
|
-
| Option
|
|
422
|
-
|
|
423
|
-
| `format` | `'stream'` | -
|
|
412
|
+
| Option | Type | Default | Description |
|
|
413
|
+
| -------- | ---------- | ------- | ------------------------------ |
|
|
414
|
+
| `format` | `'stream'` | - | Return file as Readable stream |
|
|
424
415
|
|
|
425
416
|
## Best Practices
|
|
426
417
|
|
|
427
418
|
### Security
|
|
419
|
+
|
|
428
420
|
- Store service account credentials securely using environment variables
|
|
429
421
|
- Use IAM roles with minimal required permissions
|
|
430
422
|
- Regularly rotate service account keys
|
|
431
423
|
- Enable audit logging for storage access
|
|
432
424
|
|
|
433
425
|
### Performance
|
|
426
|
+
|
|
434
427
|
- Use streams for large files to reduce memory usage
|
|
435
428
|
- Leverage GZIP compression for text-based files
|
|
436
429
|
- Implement proper error handling and retry logic
|
|
437
430
|
- Use batch operations for multiple file uploads
|
|
438
431
|
|
|
439
432
|
### Cost Optimization
|
|
433
|
+
|
|
440
434
|
- Choose appropriate storage classes for your use case
|
|
441
435
|
- Set up lifecycle policies for automatic data management
|
|
442
436
|
- Monitor storage usage and optimize file sizes
|
|
443
437
|
- Use signed URLs to reduce bandwidth costs
|
|
444
438
|
|
|
445
439
|
### File Organization
|
|
440
|
+
|
|
446
441
|
- Use consistent naming conventions
|
|
447
442
|
- Organize files in logical folder structures
|
|
448
443
|
- Implement proper versioning strategies
|
|
@@ -473,4 +468,4 @@ try {
|
|
|
473
468
|
|
|
474
469
|
## License
|
|
475
470
|
|
|
476
|
-
MIT
|
|
471
|
+
MIT
|
package/index.cjs.js
CHANGED
|
@@ -33,7 +33,7 @@ class StorageGCSService extends storages.Storage {
|
|
|
33
33
|
}
|
|
34
34
|
return file.createReadStream();
|
|
35
35
|
} catch (ex) {
|
|
36
|
-
if (/No such object/.test(ex.message)) {
|
|
36
|
+
if (ex && typeof ex === 'object' && 'message' in ex && /No such object/.test(ex.message)) {
|
|
37
37
|
throw new storages.StorageError(storages.ErrorCode.READ_FILE_ERROR, 'File not found');
|
|
38
38
|
}
|
|
39
39
|
throw ex;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rytass/storages-adapter-gcs",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.6",
|
|
4
4
|
"description": "Google Cloud Storage Adapter for @rytass/storages",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"gcp",
|
|
@@ -21,9 +21,9 @@
|
|
|
21
21
|
"url": "https://github.com/Rytass/Utils/issues"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@google-cloud/storage": "^7.
|
|
25
|
-
"@rytass/storages": "^0.2.
|
|
26
|
-
"uuid": "^11.0
|
|
24
|
+
"@google-cloud/storage": "^7.17.0",
|
|
25
|
+
"@rytass/storages": "^0.2.3",
|
|
26
|
+
"uuid": "^11.1.0"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@types/uuid": "^10.0.0"
|
package/storages-adapter-gcs.js
CHANGED
|
@@ -31,7 +31,7 @@ class StorageGCSService extends Storage {
|
|
|
31
31
|
}
|
|
32
32
|
return file.createReadStream();
|
|
33
33
|
} catch (ex) {
|
|
34
|
-
if (/No such object/.test(ex.message)) {
|
|
34
|
+
if (ex && typeof ex === 'object' && 'message' in ex && /No such object/.test(ex.message)) {
|
|
35
35
|
throw new StorageError(ErrorCode.READ_FILE_ERROR, 'File not found');
|
|
36
36
|
}
|
|
37
37
|
throw ex;
|