@groundbrick/storage-service 1.1.1
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 +260 -0
- package/package.json +83 -0
package/README.md
ADDED
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
# @groundbrick/storage-service
|
|
2
|
+
|
|
3
|
+
Serviço de storage plugável e type-safe para Node.js com suporte a múltiplos provedores (Local, S3, GCS, Azure).
|
|
4
|
+
|
|
5
|
+
## 🚀 Características
|
|
6
|
+
|
|
7
|
+
- ✅ **Type-Safe**: Totalmente tipado com TypeScript
|
|
8
|
+
- ✅ **Múltiplos Provedores**: Local, AWS S3, Google Cloud Storage, Azure (fácil adicionar novos)
|
|
9
|
+
- ✅ **Interface Única**: Mesma API para todos os provedores
|
|
10
|
+
- ✅ **Zero Vendor Lock-in**: Troque de provedor apenas alterando configuração
|
|
11
|
+
- ✅ **Singleton Pattern**: Controle de instância único
|
|
12
|
+
- ✅ **Pronto para Produção**: Testado e otimizado
|
|
13
|
+
|
|
14
|
+
## 📦 Instalação
|
|
15
|
+
```bash
|
|
16
|
+
npm install @groundbrick/storage-service
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### Dependências Opcionais
|
|
20
|
+
|
|
21
|
+
Para usar S3:
|
|
22
|
+
```bash
|
|
23
|
+
npm install @aws-sdk/client-s3 @aws-sdk/s3-request-presigner
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## 🔧 Uso Básico
|
|
27
|
+
|
|
28
|
+
### Storage Local
|
|
29
|
+
```typescript
|
|
30
|
+
import { StorageService } from '@groundbrick/storage-service';
|
|
31
|
+
|
|
32
|
+
const storage = StorageService.getInstance({
|
|
33
|
+
provider: 'local',
|
|
34
|
+
config: {
|
|
35
|
+
basePath: './uploads',
|
|
36
|
+
baseUrl: 'http://localhost:3000/uploads'
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// Upload
|
|
41
|
+
const result = await storage.upload(
|
|
42
|
+
fileBuffer,
|
|
43
|
+
'pets/123/photo.jpg',
|
|
44
|
+
{
|
|
45
|
+
contentType: 'image/jpeg',
|
|
46
|
+
isPublic: true
|
|
47
|
+
}
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
console.log(result.url); // http://localhost:3000/uploads/pets/123/photo.jpg
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### AWS S3
|
|
54
|
+
```typescript
|
|
55
|
+
import { StorageService } from '@groundbrick/storage-service';
|
|
56
|
+
|
|
57
|
+
const storage = StorageService.getInstance({
|
|
58
|
+
provider: 's3',
|
|
59
|
+
config: {
|
|
60
|
+
bucket: 'my-bucket',
|
|
61
|
+
region: 'us-east-1',
|
|
62
|
+
accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
|
|
63
|
+
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
const result = await storage.upload(
|
|
68
|
+
fileBuffer,
|
|
69
|
+
'pets/123/photo.jpg',
|
|
70
|
+
{
|
|
71
|
+
contentType: 'image/jpeg',
|
|
72
|
+
metadata: { petId: '123' },
|
|
73
|
+
isPublic: true
|
|
74
|
+
}
|
|
75
|
+
);
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## 🎯 API
|
|
79
|
+
|
|
80
|
+
### StorageService
|
|
81
|
+
|
|
82
|
+
#### `getInstance(config?: StorageConfig): StorageService`
|
|
83
|
+
|
|
84
|
+
Obtém a instância singleton do serviço.
|
|
85
|
+
|
|
86
|
+
#### `upload(file: Buffer, path: string, options?: UploadOptions): Promise<StorageResult>`
|
|
87
|
+
|
|
88
|
+
Faz upload de um arquivo.
|
|
89
|
+
|
|
90
|
+
**Parâmetros:**
|
|
91
|
+
- `file`: Buffer do arquivo
|
|
92
|
+
- `path`: Caminho relativo onde salvar
|
|
93
|
+
- `options`: Opções de upload (contentType, metadata, isPublic)
|
|
94
|
+
|
|
95
|
+
**Retorna:** `StorageResult` com url, path, size e contentType
|
|
96
|
+
|
|
97
|
+
#### `download(path: string): Promise<Buffer>`
|
|
98
|
+
|
|
99
|
+
Baixa um arquivo.
|
|
100
|
+
|
|
101
|
+
#### `delete(path: string): Promise<void>`
|
|
102
|
+
|
|
103
|
+
Deleta um arquivo.
|
|
104
|
+
|
|
105
|
+
#### `getUrl(path: string): Promise<string>`
|
|
106
|
+
|
|
107
|
+
Obtém a URL de um arquivo.
|
|
108
|
+
|
|
109
|
+
#### `exists(path: string): Promise<boolean>`
|
|
110
|
+
|
|
111
|
+
Verifica se um arquivo existe.
|
|
112
|
+
|
|
113
|
+
## 🔌 Provedores Disponíveis
|
|
114
|
+
|
|
115
|
+
### Local
|
|
116
|
+
```typescript
|
|
117
|
+
{
|
|
118
|
+
provider: 'local',
|
|
119
|
+
config: {
|
|
120
|
+
basePath: string; // Caminho físico no servidor
|
|
121
|
+
baseUrl: string; // URL base para acessar os arquivos
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### AWS S3
|
|
127
|
+
```typescript
|
|
128
|
+
{
|
|
129
|
+
provider: 's3',
|
|
130
|
+
config: {
|
|
131
|
+
bucket: string;
|
|
132
|
+
region: string;
|
|
133
|
+
accessKeyId: string;
|
|
134
|
+
secretAccessKey: string;
|
|
135
|
+
endpoint?: string; // Para S3-compatible services
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## 📝 Exemplos Práticos
|
|
141
|
+
|
|
142
|
+
### Integrando com SvelteKit
|
|
143
|
+
```typescript
|
|
144
|
+
// src/lib/server/storage.ts
|
|
145
|
+
import { StorageService } from '@groundbrick/storage-service';
|
|
146
|
+
import { env } from '$env/dynamic/private';
|
|
147
|
+
|
|
148
|
+
export const storage = StorageService.getInstance({
|
|
149
|
+
provider: env.STORAGE_PROVIDER as any || 'local',
|
|
150
|
+
config: env.STORAGE_PROVIDER === 's3'
|
|
151
|
+
? {
|
|
152
|
+
bucket: env.S3_BUCKET!,
|
|
153
|
+
region: env.S3_REGION!,
|
|
154
|
+
accessKeyId: env.S3_ACCESS_KEY_ID!,
|
|
155
|
+
secretAccessKey: env.S3_SECRET_ACCESS_KEY!
|
|
156
|
+
}
|
|
157
|
+
: {
|
|
158
|
+
basePath: './static/uploads',
|
|
159
|
+
baseUrl: '/uploads'
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
```
|
|
163
|
+
```typescript
|
|
164
|
+
// src/routes/api/upload/+server.ts
|
|
165
|
+
import { storage } from '$lib/server/storage';
|
|
166
|
+
import { json } from '@sveltejs/kit';
|
|
167
|
+
|
|
168
|
+
export async function POST({ request }) {
|
|
169
|
+
const formData = await request.formData();
|
|
170
|
+
const file = formData.get('file') as File;
|
|
171
|
+
|
|
172
|
+
const buffer = Buffer.from(await file.arrayBuffer());
|
|
173
|
+
const path = `uploads/${Date.now()}-${file.name}`;
|
|
174
|
+
|
|
175
|
+
const result = await storage.upload(buffer, path, {
|
|
176
|
+
contentType: file.type,
|
|
177
|
+
isPublic: true
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
return json(result);
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Service Layer Pattern
|
|
185
|
+
```typescript
|
|
186
|
+
// services/PetPhotoService.ts
|
|
187
|
+
import { StorageService } from '@groundbrick/storage-service';
|
|
188
|
+
|
|
189
|
+
export class PetPhotoService {
|
|
190
|
+
private storage = StorageService.getInstance();
|
|
191
|
+
|
|
192
|
+
async uploadPhoto(petId: string, photo: Buffer, mimeType: string) {
|
|
193
|
+
const fileName = `pets/${petId}/${Date.now()}.${this.getExt(mimeType)}`;
|
|
194
|
+
return await this.storage.upload(photo, fileName, {
|
|
195
|
+
contentType: mimeType,
|
|
196
|
+
metadata: { petId },
|
|
197
|
+
isPublic: true
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
async deletePhoto(path: string) {
|
|
202
|
+
await this.storage.delete(path);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
private getExt(mimeType: string): string {
|
|
206
|
+
const map: Record = {
|
|
207
|
+
'image/jpeg': 'jpg',
|
|
208
|
+
'image/png': 'png',
|
|
209
|
+
'image/webp': 'webp'
|
|
210
|
+
};
|
|
211
|
+
return map[mimeType] || 'jpg';
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## 🧪 Testes
|
|
217
|
+
```bash
|
|
218
|
+
npm test # Roda os testes
|
|
219
|
+
npm run test:watch # Modo watch
|
|
220
|
+
npm run test:coverage # Cobertura de testes
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
## 🏗️ Desenvolvimento
|
|
224
|
+
```bash
|
|
225
|
+
# Clonar o repositório
|
|
226
|
+
git clone https://github.com/groundbrick/storage-service.git
|
|
227
|
+
cd storage-service
|
|
228
|
+
|
|
229
|
+
# Instalar dependências
|
|
230
|
+
npm install
|
|
231
|
+
|
|
232
|
+
# Build
|
|
233
|
+
npm run build
|
|
234
|
+
|
|
235
|
+
# Watch mode
|
|
236
|
+
npm run build:watch
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
## 📄 Licença
|
|
240
|
+
|
|
241
|
+
MIT
|
|
242
|
+
|
|
243
|
+
## 🤝 Contribuindo
|
|
244
|
+
|
|
245
|
+
Contribuições são bem-vindas! Por favor:
|
|
246
|
+
|
|
247
|
+
1. Fork o projeto
|
|
248
|
+
2. Crie sua feature branch (`git checkout -b feature/NovaFeature`)
|
|
249
|
+
3. Commit suas mudanças (`git commit -m 'Add: nova feature'`)
|
|
250
|
+
4. Push para a branch (`git push origin feature/NovaFeature`)
|
|
251
|
+
5. Abra um Pull Request
|
|
252
|
+
|
|
253
|
+
## 🗺️ Roadmap
|
|
254
|
+
|
|
255
|
+
- [ ] Suporte a Google Cloud Storage
|
|
256
|
+
- [ ] Suporte a Azure Blob Storage
|
|
257
|
+
- [ ] Suporte a Cloudflare R2
|
|
258
|
+
- [ ] Suporte a upload multipart para arquivos grandes
|
|
259
|
+
- [ ] Cache de URLs
|
|
260
|
+
- [ ] Compressão automática de imagens
|
package/package.json
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@groundbrick/storage-service",
|
|
3
|
+
"version": "1.1.1",
|
|
4
|
+
"description": "Serviço de storage plugável com suporte a múltiplos provedores (Local, S3, GCS, Azure)",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist",
|
|
10
|
+
"README.md",
|
|
11
|
+
"LICENSE"
|
|
12
|
+
],
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"import": "./dist/index.js",
|
|
16
|
+
"require": "./dist/index.js",
|
|
17
|
+
"types": "./dist/index.d.ts"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsc -p tsconfig.build.json",
|
|
22
|
+
"build:watch": "tsc -p tsconfig.build.json --watch",
|
|
23
|
+
"clean": "rm -rf dist",
|
|
24
|
+
"prepublishOnly": "npm run clean && npm run build",
|
|
25
|
+
"lint": "eslint src --ext .ts",
|
|
26
|
+
"format": "prettier --write \"src/**/*.ts\"",
|
|
27
|
+
"prepare": "npm run build"
|
|
28
|
+
},
|
|
29
|
+
"keywords": [
|
|
30
|
+
"storage",
|
|
31
|
+
"s3",
|
|
32
|
+
"azure",
|
|
33
|
+
"gcs",
|
|
34
|
+
"file-upload",
|
|
35
|
+
"cloud-storage",
|
|
36
|
+
"typescript"
|
|
37
|
+
],
|
|
38
|
+
"author": "GroundBrick",
|
|
39
|
+
"license": "MIT",
|
|
40
|
+
"repository": {
|
|
41
|
+
"type": "git",
|
|
42
|
+
"url": "https://github.com/groundbrick/storage-service.git"
|
|
43
|
+
},
|
|
44
|
+
"bugs": {
|
|
45
|
+
"url": "https://github.com/groundbrick/storage-service/issues"
|
|
46
|
+
},
|
|
47
|
+
"homepage": "https://github.com/groundbrick/storage-service#readme",
|
|
48
|
+
"publishConfig": {
|
|
49
|
+
"access": "public"
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@types/jest": "^29.5.11",
|
|
53
|
+
"@types/mime-types": "^3.0.1",
|
|
54
|
+
"@types/node": "^20.19.9",
|
|
55
|
+
"@typescript-eslint/eslint-plugin": "^6.17.0",
|
|
56
|
+
"@typescript-eslint/parser": "^6.17.0",
|
|
57
|
+
"eslint": "^8.56.0",
|
|
58
|
+
"jest": "^29.7.0",
|
|
59
|
+
"prettier": "^3.1.1",
|
|
60
|
+
"ts-jest": "^29.1.1",
|
|
61
|
+
"typescript": "^5.3.3"
|
|
62
|
+
},
|
|
63
|
+
"dependencies": {
|
|
64
|
+
"@aws-sdk/client-s3": "^3.484.0",
|
|
65
|
+
"@aws-sdk/s3-request-presigner": "^3.484.0",
|
|
66
|
+
"mime-types": "^2.1.35"
|
|
67
|
+
},
|
|
68
|
+
"peerDependencies": {
|
|
69
|
+
"@aws-sdk/client-s3": "^3.0.0",
|
|
70
|
+
"@aws-sdk/s3-request-presigner": "^3.0.0"
|
|
71
|
+
},
|
|
72
|
+
"peerDependenciesMeta": {
|
|
73
|
+
"@aws-sdk/client-s3": {
|
|
74
|
+
"optional": true
|
|
75
|
+
},
|
|
76
|
+
"@aws-sdk/s3-request-presigner": {
|
|
77
|
+
"optional": true
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
"engines": {
|
|
81
|
+
"node": ">=16.0.0"
|
|
82
|
+
}
|
|
83
|
+
}
|