vintasend-aws-s3-attachments 0.4.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/README.md +93 -0
- package/dist/aws-s3-attachment-manager.d.ts +100 -0
- package/dist/aws-s3-attachment-manager.js +225 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +5 -0
- package/package.json +29 -0
package/README.md
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# VintaSend AWS S3 Attachments
|
|
2
|
+
|
|
3
|
+
AWS S3 attachment manager for VintaSend notifications. Provides production-ready file storage with presigned URLs and streaming support.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install vintasend-aws-s3-attachments
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- ✅ Upload attachments to AWS S3
|
|
14
|
+
- ✅ Generate presigned URLs for secure access
|
|
15
|
+
- ✅ Stream large files efficiently
|
|
16
|
+
- ✅ Automatic content type detection
|
|
17
|
+
- ✅ SHA-256 checksum calculation
|
|
18
|
+
- ✅ Works with S3-compatible services (MinIO, DigitalOcean Spaces, etc.)
|
|
19
|
+
- ✅ TypeScript support with full type safety
|
|
20
|
+
|
|
21
|
+
## Quick Start
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
import { S3AttachmentManager } from 'vintasend-aws-s3-attachments';
|
|
25
|
+
import { PrismaNotificationBackend } from 'vintasend-prisma';
|
|
26
|
+
import { VintaSendFactory } from 'vintasend';
|
|
27
|
+
|
|
28
|
+
// Create S3 attachment manager
|
|
29
|
+
const attachmentManager = new S3AttachmentManager({
|
|
30
|
+
bucket: 'my-app-notifications',
|
|
31
|
+
region: 'us-east-1',
|
|
32
|
+
keyPrefix: 'attachments/',
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// Create backend with attachment manager
|
|
36
|
+
const backend = new PrismaNotificationBackend(prisma, attachmentManager);
|
|
37
|
+
|
|
38
|
+
// Create VintaSend instance
|
|
39
|
+
const vintaSend = factory.create(
|
|
40
|
+
adapters,
|
|
41
|
+
backend,
|
|
42
|
+
contextGeneratorsMap,
|
|
43
|
+
logger,
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
// Send notification with attachment
|
|
47
|
+
await vintaSend.sendNotification({
|
|
48
|
+
userId: 'user-123',
|
|
49
|
+
notificationType: 'email',
|
|
50
|
+
title: 'Welcome!',
|
|
51
|
+
bodyTemplate: 'Welcome to our service',
|
|
52
|
+
contextName: 'welcome',
|
|
53
|
+
contextParameters: {},
|
|
54
|
+
sendAfter: null,
|
|
55
|
+
subjectTemplate: 'Welcome',
|
|
56
|
+
extraParams: null,
|
|
57
|
+
attachments: [
|
|
58
|
+
{
|
|
59
|
+
file: Buffer.from('PDF content here'),
|
|
60
|
+
filename: 'welcome.pdf',
|
|
61
|
+
contentType: 'application/pdf',
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
});
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Configuration
|
|
68
|
+
|
|
69
|
+
### S3AttachmentManagerConfig
|
|
70
|
+
|
|
71
|
+
| Option | Type | Required | Description |
|
|
72
|
+
|--------|------|----------|-------------|
|
|
73
|
+
| `bucket` | `string` | Yes | S3 bucket name where attachments will be stored |
|
|
74
|
+
| `region` | `string` | Yes | AWS region for the S3 bucket |
|
|
75
|
+
| `keyPrefix` | `string` | No | Optional prefix for all S3 keys (e.g., 'attachments/') |
|
|
76
|
+
| `credentials` | `object` | No | AWS credentials (accessKeyId, secretAccessKey) |
|
|
77
|
+
| `endpoint` | `string` | No | Custom endpoint for S3-compatible services |
|
|
78
|
+
| `s3ClientConfig` | `object` | No | Additional S3 client configuration |
|
|
79
|
+
|
|
80
|
+
### AWS Credentials
|
|
81
|
+
|
|
82
|
+
The manager uses the standard AWS SDK credential chain:
|
|
83
|
+
|
|
84
|
+
1. **Environment variables**: `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`
|
|
85
|
+
2. **IAM roles**: Recommended for EC2/ECS/Lambda deployments
|
|
86
|
+
3. **Constructor credentials**: Passed directly to the manager
|
|
87
|
+
4. **AWS credentials file**: `~/.aws/credentials`
|
|
88
|
+
|
|
89
|
+
For more details, see the full README in the repository.
|
|
90
|
+
|
|
91
|
+
## License
|
|
92
|
+
|
|
93
|
+
MIT
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { BaseAttachmentManager } from 'vintasend/dist/services/attachment-manager/base-attachment-manager';
|
|
2
|
+
import type { AttachmentFileRecord, AttachmentFile, FileAttachment } from 'vintasend/dist/types/attachment';
|
|
3
|
+
export interface S3AttachmentManagerConfig {
|
|
4
|
+
/**
|
|
5
|
+
* S3 bucket name where attachments will be stored
|
|
6
|
+
*/
|
|
7
|
+
bucket: string;
|
|
8
|
+
/**
|
|
9
|
+
* AWS region for the S3 bucket
|
|
10
|
+
*/
|
|
11
|
+
region: string;
|
|
12
|
+
/**
|
|
13
|
+
* Optional prefix for all S3 keys (e.g., 'attachments/')
|
|
14
|
+
* Helps organize files within the bucket
|
|
15
|
+
*/
|
|
16
|
+
keyPrefix?: string;
|
|
17
|
+
/**
|
|
18
|
+
* Optional AWS credentials
|
|
19
|
+
* If not provided, uses default credential chain (env vars, IAM roles, etc.)
|
|
20
|
+
*/
|
|
21
|
+
credentials?: {
|
|
22
|
+
accessKeyId: string;
|
|
23
|
+
secretAccessKey: string;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Optional custom endpoint for S3-compatible services
|
|
27
|
+
* (e.g., MinIO, DigitalOcean Spaces)
|
|
28
|
+
*/
|
|
29
|
+
endpoint?: string;
|
|
30
|
+
/**
|
|
31
|
+
* Optional S3 client configuration
|
|
32
|
+
*/
|
|
33
|
+
s3ClientConfig?: Record<string, unknown>;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* AWS S3 AttachmentManager implementation for VintaSend.
|
|
37
|
+
*
|
|
38
|
+
* Provides production-ready file storage with:
|
|
39
|
+
* - Secure presigned URLs for file access
|
|
40
|
+
* - Streaming support for large files
|
|
41
|
+
* - Works with S3-compatible services (MinIO, DigitalOcean Spaces, etc.)
|
|
42
|
+
*
|
|
43
|
+
* Note: This manager handles S3 storage only. File metadata (AttachmentFileRecord)
|
|
44
|
+
* is stored by the Backend in its database. The Backend calls this manager's
|
|
45
|
+
* uploadFile() method and stores the returned metadata.
|
|
46
|
+
*/
|
|
47
|
+
export declare class S3AttachmentManager extends BaseAttachmentManager {
|
|
48
|
+
private s3Client;
|
|
49
|
+
private bucket;
|
|
50
|
+
private keyPrefix;
|
|
51
|
+
constructor(config: S3AttachmentManagerConfig);
|
|
52
|
+
/**
|
|
53
|
+
* Upload a file to S3 and return metadata.
|
|
54
|
+
*
|
|
55
|
+
* @param file - The file data (Buffer, ReadableStream, or file path)
|
|
56
|
+
* @param filename - The filename to use for storage
|
|
57
|
+
* @param contentType - Optional MIME type (auto-detected if not provided)
|
|
58
|
+
* @returns AttachmentFileRecord with S3 storage metadata
|
|
59
|
+
*/
|
|
60
|
+
uploadFile(file: FileAttachment, filename: string, contentType?: string): Promise<AttachmentFileRecord>;
|
|
61
|
+
/**
|
|
62
|
+
* Reconstruct an AttachmentFile accessor from storage metadata.
|
|
63
|
+
*
|
|
64
|
+
* This allows the system to recreate file access objects when loading
|
|
65
|
+
* notifications from the database.
|
|
66
|
+
*
|
|
67
|
+
* @param storageMetadata - S3 storage metadata (bucket, key, region)
|
|
68
|
+
* @returns An S3AttachmentFile instance for accessing the file
|
|
69
|
+
*/
|
|
70
|
+
reconstructAttachmentFile(storageMetadata: Record<string, unknown>): AttachmentFile;
|
|
71
|
+
/**
|
|
72
|
+
* Delete a file from S3.
|
|
73
|
+
*
|
|
74
|
+
* Note: This implementation requires the Backend to pass full storage metadata
|
|
75
|
+
* through a separate deleteFileWithMetadata() method, since the fileId alone
|
|
76
|
+
* doesn't contain the S3 key needed for deletion.
|
|
77
|
+
*
|
|
78
|
+
* For S3, the Backend should call deleteFileWithMetadata() instead.
|
|
79
|
+
*
|
|
80
|
+
* @param fileId - The unique identifier of the file
|
|
81
|
+
*/
|
|
82
|
+
deleteFile(fileId: string): Promise<void>;
|
|
83
|
+
/**
|
|
84
|
+
* Delete a file from S3 using storage metadata.
|
|
85
|
+
*
|
|
86
|
+
* The Backend should call this method instead of deleteFile() for S3.
|
|
87
|
+
*
|
|
88
|
+
* @param fileId - The unique identifier of the file
|
|
89
|
+
* @param storageMetadata - The storage metadata containing S3 key
|
|
90
|
+
*/
|
|
91
|
+
deleteFileWithMetadata(fileId: string, storageMetadata: Record<string, unknown>): Promise<void>;
|
|
92
|
+
/**
|
|
93
|
+
* Build the S3 key for a file.
|
|
94
|
+
*
|
|
95
|
+
* @param fileId - The unique file identifier
|
|
96
|
+
* @param filename - The original filename
|
|
97
|
+
* @returns The full S3 key including prefix
|
|
98
|
+
*/
|
|
99
|
+
private buildS3Key;
|
|
100
|
+
}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.S3AttachmentManager = void 0;
|
|
4
|
+
const base_attachment_manager_1 = require("vintasend/dist/services/attachment-manager/base-attachment-manager");
|
|
5
|
+
const client_s3_1 = require("@aws-sdk/client-s3");
|
|
6
|
+
const s3_request_presigner_1 = require("@aws-sdk/s3-request-presigner");
|
|
7
|
+
const node_stream_1 = require("node:stream");
|
|
8
|
+
const node_crypto_1 = require("node:crypto");
|
|
9
|
+
/**
|
|
10
|
+
* AWS S3 AttachmentManager implementation for VintaSend.
|
|
11
|
+
*
|
|
12
|
+
* Provides production-ready file storage with:
|
|
13
|
+
* - Secure presigned URLs for file access
|
|
14
|
+
* - Streaming support for large files
|
|
15
|
+
* - Works with S3-compatible services (MinIO, DigitalOcean Spaces, etc.)
|
|
16
|
+
*
|
|
17
|
+
* Note: This manager handles S3 storage only. File metadata (AttachmentFileRecord)
|
|
18
|
+
* is stored by the Backend in its database. The Backend calls this manager's
|
|
19
|
+
* uploadFile() method and stores the returned metadata.
|
|
20
|
+
*/
|
|
21
|
+
class S3AttachmentManager extends base_attachment_manager_1.BaseAttachmentManager {
|
|
22
|
+
constructor(config) {
|
|
23
|
+
super();
|
|
24
|
+
this.bucket = config.bucket;
|
|
25
|
+
this.keyPrefix = config.keyPrefix || '';
|
|
26
|
+
this.s3Client = new client_s3_1.S3Client({
|
|
27
|
+
region: config.region,
|
|
28
|
+
credentials: config.credentials,
|
|
29
|
+
endpoint: config.endpoint,
|
|
30
|
+
...config.s3ClientConfig,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Upload a file to S3 and return metadata.
|
|
35
|
+
*
|
|
36
|
+
* @param file - The file data (Buffer, ReadableStream, or file path)
|
|
37
|
+
* @param filename - The filename to use for storage
|
|
38
|
+
* @param contentType - Optional MIME type (auto-detected if not provided)
|
|
39
|
+
* @returns AttachmentFileRecord with S3 storage metadata
|
|
40
|
+
*/
|
|
41
|
+
async uploadFile(file, filename, contentType) {
|
|
42
|
+
// Convert file to Buffer
|
|
43
|
+
const buffer = await this.fileToBuffer(file);
|
|
44
|
+
// Calculate checksum
|
|
45
|
+
const checksum = this.calculateChecksum(buffer);
|
|
46
|
+
// Detect content type if not provided
|
|
47
|
+
const finalContentType = contentType || this.detectContentType(filename);
|
|
48
|
+
// Generate unique S3 key
|
|
49
|
+
const fileId = (0, node_crypto_1.randomUUID)();
|
|
50
|
+
const key = this.buildS3Key(fileId, filename);
|
|
51
|
+
// Upload to S3
|
|
52
|
+
const putCommand = new client_s3_1.PutObjectCommand({
|
|
53
|
+
Bucket: this.bucket,
|
|
54
|
+
Key: key,
|
|
55
|
+
Body: buffer,
|
|
56
|
+
ContentType: finalContentType,
|
|
57
|
+
Metadata: {
|
|
58
|
+
originalFilename: filename,
|
|
59
|
+
checksum: checksum,
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
await this.s3Client.send(putCommand);
|
|
63
|
+
// Return file record with S3 metadata
|
|
64
|
+
return {
|
|
65
|
+
id: fileId,
|
|
66
|
+
filename,
|
|
67
|
+
contentType: finalContentType,
|
|
68
|
+
size: buffer.length,
|
|
69
|
+
checksum,
|
|
70
|
+
storageMetadata: {
|
|
71
|
+
bucket: this.bucket,
|
|
72
|
+
key,
|
|
73
|
+
region: this.s3Client.config.region,
|
|
74
|
+
},
|
|
75
|
+
createdAt: new Date(),
|
|
76
|
+
updatedAt: new Date(),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Reconstruct an AttachmentFile accessor from storage metadata.
|
|
81
|
+
*
|
|
82
|
+
* This allows the system to recreate file access objects when loading
|
|
83
|
+
* notifications from the database.
|
|
84
|
+
*
|
|
85
|
+
* @param storageMetadata - S3 storage metadata (bucket, key, region)
|
|
86
|
+
* @returns An S3AttachmentFile instance for accessing the file
|
|
87
|
+
*/
|
|
88
|
+
reconstructAttachmentFile(storageMetadata) {
|
|
89
|
+
if (!storageMetadata.key || !storageMetadata.bucket) {
|
|
90
|
+
throw new Error('Storage metadata must contain bucket and key for S3 files');
|
|
91
|
+
}
|
|
92
|
+
return new S3AttachmentFile(this.s3Client, storageMetadata.bucket, storageMetadata.key);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Delete a file from S3.
|
|
96
|
+
*
|
|
97
|
+
* Note: This implementation requires the Backend to pass full storage metadata
|
|
98
|
+
* through a separate deleteFileWithMetadata() method, since the fileId alone
|
|
99
|
+
* doesn't contain the S3 key needed for deletion.
|
|
100
|
+
*
|
|
101
|
+
* For S3, the Backend should call deleteFileWithMetadata() instead.
|
|
102
|
+
*
|
|
103
|
+
* @param fileId - The unique identifier of the file
|
|
104
|
+
*/
|
|
105
|
+
async deleteFile(fileId) {
|
|
106
|
+
throw new Error('deleteFile() requires storage metadata for S3. Use deleteFileWithMetadata() or delete directly via AttachmentFile.delete()');
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Delete a file from S3 using storage metadata.
|
|
110
|
+
*
|
|
111
|
+
* The Backend should call this method instead of deleteFile() for S3.
|
|
112
|
+
*
|
|
113
|
+
* @param fileId - The unique identifier of the file
|
|
114
|
+
* @param storageMetadata - The storage metadata containing S3 key
|
|
115
|
+
*/
|
|
116
|
+
async deleteFileWithMetadata(fileId, storageMetadata) {
|
|
117
|
+
if (!storageMetadata.key) {
|
|
118
|
+
throw new Error('Storage metadata must contain key for S3 file deletion');
|
|
119
|
+
}
|
|
120
|
+
const deleteCommand = new client_s3_1.DeleteObjectCommand({
|
|
121
|
+
Bucket: this.bucket,
|
|
122
|
+
Key: storageMetadata.key,
|
|
123
|
+
});
|
|
124
|
+
await this.s3Client.send(deleteCommand);
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Build the S3 key for a file.
|
|
128
|
+
*
|
|
129
|
+
* @param fileId - The unique file identifier
|
|
130
|
+
* @param filename - The original filename
|
|
131
|
+
* @returns The full S3 key including prefix
|
|
132
|
+
*/
|
|
133
|
+
buildS3Key(fileId, filename) {
|
|
134
|
+
// Use fileId as the primary key component to ensure uniqueness
|
|
135
|
+
// Include original filename for better organization and debugging
|
|
136
|
+
const sanitizedFilename = filename.replace(/[^a-zA-Z0-9.-]/g, '_');
|
|
137
|
+
return `${this.keyPrefix}${fileId}/${sanitizedFilename}`;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
exports.S3AttachmentManager = S3AttachmentManager;
|
|
141
|
+
/**
|
|
142
|
+
* S3 AttachmentFile implementation.
|
|
143
|
+
*
|
|
144
|
+
* Provides access to files stored in AWS S3 with support for:
|
|
145
|
+
* - Reading entire files into memory
|
|
146
|
+
* - Streaming large files
|
|
147
|
+
* - Generating presigned URLs for secure access
|
|
148
|
+
*/
|
|
149
|
+
class S3AttachmentFile {
|
|
150
|
+
constructor(s3Client, bucket, key) {
|
|
151
|
+
this.s3Client = s3Client;
|
|
152
|
+
this.bucket = bucket;
|
|
153
|
+
this.key = key;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Read the entire file into memory as a Buffer.
|
|
157
|
+
*
|
|
158
|
+
* Use this for small files. For large files, prefer streaming.
|
|
159
|
+
*/
|
|
160
|
+
async read() {
|
|
161
|
+
const getCommand = new client_s3_1.GetObjectCommand({
|
|
162
|
+
Bucket: this.bucket,
|
|
163
|
+
Key: this.key,
|
|
164
|
+
});
|
|
165
|
+
const response = await this.s3Client.send(getCommand);
|
|
166
|
+
if (!response.Body) {
|
|
167
|
+
throw new Error('S3 object has no body');
|
|
168
|
+
}
|
|
169
|
+
// Convert stream to buffer
|
|
170
|
+
return this.streamToBuffer(response.Body);
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Get a readable stream for the file.
|
|
174
|
+
*
|
|
175
|
+
* Use this for large files to avoid loading everything into memory.
|
|
176
|
+
*/
|
|
177
|
+
async stream() {
|
|
178
|
+
const getCommand = new client_s3_1.GetObjectCommand({
|
|
179
|
+
Bucket: this.bucket,
|
|
180
|
+
Key: this.key,
|
|
181
|
+
});
|
|
182
|
+
const response = await this.s3Client.send(getCommand);
|
|
183
|
+
if (!response.Body) {
|
|
184
|
+
throw new Error('S3 object has no body');
|
|
185
|
+
}
|
|
186
|
+
// Convert Node.js Readable to Web ReadableStream
|
|
187
|
+
const nodeStream = response.Body;
|
|
188
|
+
return node_stream_1.Readable.toWeb(nodeStream);
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Generate a presigned URL for accessing the file.
|
|
192
|
+
*
|
|
193
|
+
* @param expiresIn - Seconds until the URL expires (default: 3600 = 1 hour)
|
|
194
|
+
* @returns A presigned URL for secure file access
|
|
195
|
+
*/
|
|
196
|
+
async url(expiresIn = 3600) {
|
|
197
|
+
const getCommand = new client_s3_1.GetObjectCommand({
|
|
198
|
+
Bucket: this.bucket,
|
|
199
|
+
Key: this.key,
|
|
200
|
+
});
|
|
201
|
+
return (0, s3_request_presigner_1.getSignedUrl)(this.s3Client, getCommand, { expiresIn });
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Delete this file from S3.
|
|
205
|
+
*
|
|
206
|
+
* Note: This is typically called by the AttachmentManager, not directly.
|
|
207
|
+
*/
|
|
208
|
+
async delete() {
|
|
209
|
+
const deleteCommand = new client_s3_1.DeleteObjectCommand({
|
|
210
|
+
Bucket: this.bucket,
|
|
211
|
+
Key: this.key,
|
|
212
|
+
});
|
|
213
|
+
await this.s3Client.send(deleteCommand);
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Convert a Node.js Readable stream to a Buffer.
|
|
217
|
+
*/
|
|
218
|
+
async streamToBuffer(stream) {
|
|
219
|
+
const chunks = [];
|
|
220
|
+
for await (const chunk of stream) {
|
|
221
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
222
|
+
}
|
|
223
|
+
return Buffer.concat(chunks);
|
|
224
|
+
}
|
|
225
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { S3AttachmentManager, type S3AttachmentManagerConfig, } from './aws-s3-attachment-manager';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.S3AttachmentManager = void 0;
|
|
4
|
+
var aws_s3_attachment_manager_1 = require("./aws-s3-attachment-manager");
|
|
5
|
+
Object.defineProperty(exports, "S3AttachmentManager", { enumerable: true, get: function () { return aws_s3_attachment_manager_1.S3AttachmentManager; } });
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "vintasend-aws-s3-attachments",
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "Implementation of AWS S3 Attachments for VintaSend",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "tsc",
|
|
8
|
+
"prepublishOnly": "npm run build",
|
|
9
|
+
"test": "jest",
|
|
10
|
+
"test:watch": "jest --watch",
|
|
11
|
+
"test:coverage": "jest --coverage"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist"
|
|
15
|
+
],
|
|
16
|
+
"author": "Hugo Bessa",
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"@aws-sdk/client-s3": "^3.967.0",
|
|
20
|
+
"@aws-sdk/s3-request-presigner": "^3.967.0",
|
|
21
|
+
"vintasend": "^0.4.0"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@types/jest": "^29.5.14",
|
|
25
|
+
"jest": "^29.7.0",
|
|
26
|
+
"ts-jest": "^29.2.6",
|
|
27
|
+
"typescript": "^5.8.2"
|
|
28
|
+
}
|
|
29
|
+
}
|