saas-backend-kit 1.0.0 → 1.0.2

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.
Files changed (58) hide show
  1. package/README.md +123 -344
  2. package/copy-dts.js +59 -0
  3. package/dist/auth/index.js +7 -2
  4. package/dist/auth/index.js.map +1 -1
  5. package/dist/auth/index.mjs +7 -2
  6. package/dist/auth/index.mjs.map +1 -1
  7. package/dist/config/index.js +6 -1
  8. package/dist/config/index.js.map +1 -1
  9. package/dist/config/index.mjs +6 -1
  10. package/dist/config/index.mjs.map +1 -1
  11. package/dist/index.d.ts +1 -0
  12. package/dist/index.js +232 -41
  13. package/dist/index.js.map +1 -1
  14. package/dist/index.mjs +231 -42
  15. package/dist/index.mjs.map +1 -1
  16. package/dist/logger/index.js +6 -1
  17. package/dist/logger/index.js.map +1 -1
  18. package/dist/logger/index.mjs +6 -1
  19. package/dist/logger/index.mjs.map +1 -1
  20. package/dist/notifications/index.js +6 -1
  21. package/dist/notifications/index.js.map +1 -1
  22. package/dist/notifications/index.mjs +6 -1
  23. package/dist/notifications/index.mjs.map +1 -1
  24. package/dist/queue/index.js +6 -1
  25. package/dist/queue/index.js.map +1 -1
  26. package/dist/queue/index.mjs +6 -1
  27. package/dist/queue/index.mjs.map +1 -1
  28. package/dist/rate-limit/index.js +7 -1
  29. package/dist/rate-limit/index.js.map +1 -1
  30. package/dist/rate-limit/index.mjs +7 -1
  31. package/dist/rate-limit/index.mjs.map +1 -1
  32. package/dist/response/index.js +51 -40
  33. package/dist/response/index.js.map +1 -1
  34. package/dist/response/index.mjs +51 -40
  35. package/dist/response/index.mjs.map +1 -1
  36. package/dist/upload/index.d.ts +57 -0
  37. package/dist/upload/index.js +344 -0
  38. package/dist/upload/index.js.map +1 -0
  39. package/dist/upload/index.mjs +334 -0
  40. package/dist/upload/index.mjs.map +1 -0
  41. package/jest-output.json +72 -0
  42. package/jest.config.js +19 -0
  43. package/package.json +20 -8
  44. package/saas-banner.svg +239 -0
  45. package/src/auth/jwt.ts +1 -1
  46. package/src/config/index.ts +5 -0
  47. package/src/index.ts +2 -0
  48. package/src/rate-limit/express.ts +1 -0
  49. package/src/response/index.ts +49 -40
  50. package/src/upload/index.ts +268 -0
  51. package/tests/auth.test.ts +134 -0
  52. package/tests/config.test.ts +36 -0
  53. package/tests/logger.test.ts +47 -0
  54. package/tests/notifications.test.ts +19 -0
  55. package/tests/rate-limit.test.ts +50 -0
  56. package/tests/upload.test.ts +33 -0
  57. package/tsconfig.test.json +14 -0
  58. package/tsup.config.ts +2 -1
@@ -0,0 +1,268 @@
1
+ import { S3Client, PutObjectCommand, DeleteObjectCommand, GetObjectCommand, ListObjectsV2Command } from '@aws-sdk/client-s3';
2
+ import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
3
+ import { config } from '../config';
4
+ import { logger } from '../logger';
5
+
6
+ export interface S3Config {
7
+ region?: string;
8
+ accessKeyId?: string;
9
+ secretAccessKey?: string;
10
+ bucket: string;
11
+ endpoint?: string;
12
+ forcePathStyle?: boolean;
13
+ }
14
+
15
+ export interface UploadOptions {
16
+ key?: string;
17
+ contentType?: string;
18
+ expiresIn?: number;
19
+ metadata?: Record<string, string>;
20
+ }
21
+
22
+ export interface UploadResult {
23
+ key: string;
24
+ url: string;
25
+ bucket: string;
26
+ contentType?: string;
27
+ size?: number;
28
+ }
29
+
30
+ export interface SignedUrlOptions {
31
+ expiresIn?: number;
32
+ }
33
+
34
+ export interface FileObject {
35
+ key: string;
36
+ lastModified?: Date;
37
+ size?: number;
38
+ contentType?: string;
39
+ }
40
+
41
+ class S3Service {
42
+ private client: S3Client | null = null;
43
+ private bucket: string;
44
+ private initialized: boolean = false;
45
+
46
+ constructor() {
47
+ this.bucket = '';
48
+ }
49
+
50
+ initialize(config: S3Config): void {
51
+ this.client = new S3Client({
52
+ region: config.region || 'us-east-1',
53
+ credentials: config.accessKeyId && config.secretAccessKey
54
+ ? {
55
+ accessKeyId: config.accessKeyId,
56
+ secretAccessKey: config.secretAccessKey,
57
+ }
58
+ : undefined,
59
+ endpoint: config.endpoint,
60
+ forcePathStyle: config.forcePathStyle || false,
61
+ });
62
+
63
+ this.bucket = config.bucket;
64
+ this.initialized = true;
65
+ logger.info('S3 service initialized', { bucket: this.bucket });
66
+ }
67
+
68
+ isInitialized(): boolean {
69
+ return this.initialized;
70
+ }
71
+
72
+ private ensureInitialized(): void {
73
+ if (!this.initialized) {
74
+ const region = config.get('AWS_REGION') || 'us-east-1';
75
+ const bucket = config.get('AWS_S3_BUCKET') || '';
76
+
77
+ this.initialize({
78
+ region,
79
+ accessKeyId: config.get('AWS_ACCESS_KEY_ID'),
80
+ secretAccessKey: config.get('AWS_SECRET_ACCESS_KEY'),
81
+ bucket,
82
+ endpoint: config.get('AWS_ENDPOINT'),
83
+ });
84
+ }
85
+ }
86
+
87
+ async upload(
88
+ file: Buffer | Uint8Array | string,
89
+ options: UploadOptions = {}
90
+ ): Promise<UploadResult> {
91
+ this.ensureInitialized();
92
+
93
+ const key = options.key || this.generateKey();
94
+ const contentType = options.contentType || this.guessContentType(key);
95
+
96
+ const command = new PutObjectCommand({
97
+ Bucket: this.bucket,
98
+ Key: key,
99
+ Body: file,
100
+ ContentType: contentType,
101
+ Metadata: options.metadata,
102
+ });
103
+
104
+ await this.client!.send(command);
105
+
106
+ const url = await this.getSignedUrl(key, { expiresIn: options.expiresIn || 3600 });
107
+
108
+ logger.info('File uploaded to S3', { key, bucket: this.bucket, contentType });
109
+
110
+ return {
111
+ key,
112
+ url,
113
+ bucket: this.bucket,
114
+ contentType,
115
+ };
116
+ }
117
+
118
+ async uploadImage(
119
+ file: Buffer | Uint8Array | string,
120
+ filename: string,
121
+ options: UploadOptions = {}
122
+ ): Promise<UploadResult> {
123
+ const key = options.key || `images/${Date.now()}-${filename}`;
124
+
125
+ return this.upload(file, {
126
+ ...options,
127
+ key,
128
+ contentType: options.contentType || this.getImageContentType(filename),
129
+ });
130
+ }
131
+
132
+ async uploadVideo(
133
+ file: Buffer | Uint8Array | string,
134
+ filename: string,
135
+ options: UploadOptions = {}
136
+ ): Promise<UploadResult> {
137
+ const key = options.key || `videos/${Date.now()}-${filename}`;
138
+
139
+ return this.upload(file, {
140
+ ...options,
141
+ key,
142
+ contentType: options.contentType || this.getVideoContentType(filename),
143
+ });
144
+ }
145
+
146
+ async delete(key: string): Promise<void> {
147
+ this.ensureInitialized();
148
+
149
+ const command = new DeleteObjectCommand({
150
+ Bucket: this.bucket,
151
+ Key: key,
152
+ });
153
+
154
+ await this.client!.send(command);
155
+ logger.info('File deleted from S3', { key, bucket: this.bucket });
156
+ }
157
+
158
+ async getSignedUrl(key: string, options: SignedUrlOptions = {}): Promise<string> {
159
+ this.ensureInitialized();
160
+
161
+ const command = new GetObjectCommand({
162
+ Bucket: this.bucket,
163
+ Key: key,
164
+ });
165
+
166
+ return getSignedUrl(this.client!, command, {
167
+ expiresIn: options.expiresIn || 3600,
168
+ });
169
+ }
170
+
171
+ async getPublicUrl(key: string): Promise<string> {
172
+ return `https://${this.bucket}.s3.${config.get('AWS_REGION') || 'us-east-1'}.amazonaws.com/${key}`;
173
+ }
174
+
175
+ async listFiles(prefix?: string, maxKeys: number = 1000): Promise<FileObject[]> {
176
+ this.ensureInitialized();
177
+
178
+ const command = new ListObjectsV2Command({
179
+ Bucket: this.bucket,
180
+ Prefix: prefix,
181
+ MaxKeys: maxKeys,
182
+ });
183
+
184
+ const response = await this.client!.send(command);
185
+
186
+ return (response.Contents || []).map((item) => ({
187
+ key: item.Key || '',
188
+ lastModified: item.LastModified,
189
+ size: item.Size,
190
+ }));
191
+ }
192
+
193
+ private generateKey(): string {
194
+ const timestamp = Date.now();
195
+ const random = Math.random().toString(36).substring(2, 15);
196
+ return `uploads/${timestamp}-${random}`;
197
+ }
198
+
199
+ private guessContentType(key: string): string {
200
+ const ext = key.split('.').pop()?.toLowerCase();
201
+
202
+ const contentTypes: Record<string, string> = {
203
+ jpg: 'image/jpeg',
204
+ jpeg: 'image/jpeg',
205
+ png: 'image/png',
206
+ gif: 'image/gif',
207
+ webp: 'image/webp',
208
+ svg: 'image/svg+xml',
209
+ mp4: 'video/mp4',
210
+ webm: 'video/webm',
211
+ mov: 'video/quicktime',
212
+ avi: 'video/x-msvideo',
213
+ pdf: 'application/pdf',
214
+ json: 'application/json',
215
+ txt: 'text/plain',
216
+ };
217
+
218
+ return contentTypes[ext || ''] || 'application/octet-stream';
219
+ }
220
+
221
+ private getImageContentType(filename: string): string {
222
+ const ext = filename.split('.').pop()?.toLowerCase();
223
+ const imageTypes: Record<string, string> = {
224
+ jpg: 'image/jpeg',
225
+ jpeg: 'image/jpeg',
226
+ png: 'image/png',
227
+ gif: 'image/gif',
228
+ webp: 'image/webp',
229
+ svg: 'image/svg+xml',
230
+ };
231
+ return imageTypes[ext || ''] || 'image/jpeg';
232
+ }
233
+
234
+ private getVideoContentType(filename: string): string {
235
+ const ext = filename.split('.').pop()?.toLowerCase();
236
+ const videoTypes: Record<string, string> = {
237
+ mp4: 'video/mp4',
238
+ webm: 'video/webm',
239
+ mov: 'video/quicktime',
240
+ avi: 'video/x-msvideo',
241
+ mkv: 'video/x-matroska',
242
+ ogv: 'video/ogg',
243
+ };
244
+ return videoTypes[ext || ''] || 'video/mp4';
245
+ }
246
+ }
247
+
248
+ export const s3Service = new S3Service();
249
+
250
+ export const upload = {
251
+ initialize: (config: S3Config) => s3Service.initialize(config),
252
+
253
+ file: (file: Buffer | Uint8Array | string, options?: UploadOptions) =>
254
+ s3Service.upload(file, options),
255
+
256
+ image: (file: Buffer | Uint8Array | string, filename: string, options?: UploadOptions) =>
257
+ s3Service.uploadImage(file, filename, options),
258
+
259
+ video: (file: Buffer | Uint8Array | string, filename: string, options?: UploadOptions) =>
260
+ s3Service.uploadVideo(file, filename, options),
261
+
262
+ delete: (key: string) => s3Service.delete(key),
263
+ getSignedUrl: (key: string, options?: SignedUrlOptions) => s3Service.getSignedUrl(key, options),
264
+ getPublicUrl: (key: string) => s3Service.getPublicUrl(key),
265
+ listFiles: (prefix?: string, maxKeys?: number) => s3Service.listFiles(prefix, maxKeys),
266
+ };
267
+
268
+ export default upload;
@@ -0,0 +1,134 @@
1
+ describe('Auth Module', () => {
2
+ const mockUserStore = {
3
+ users: new Map(),
4
+
5
+ async findByEmail(email: string) {
6
+ for (const user of this.users.values()) {
7
+ if (user.email === email) return user;
8
+ }
9
+ return null;
10
+ },
11
+
12
+ async findById(id: string) {
13
+ return this.users.get(id) || null;
14
+ },
15
+
16
+ async create(data: any) {
17
+ const bcrypt = require('bcryptjs');
18
+ const id = Math.random().toString(36).substr(2, 9);
19
+ const hashedPassword = await bcrypt.hash(data.password, 10);
20
+ const user = { id, email: data.email, role: data.role || 'user', ...data, password: hashedPassword };
21
+ this.users.set(id, user);
22
+ return user;
23
+ },
24
+
25
+ async update(id: string, data: any) {
26
+ const user = this.users.get(id);
27
+ if (!user) throw new Error('User not found');
28
+ const updated = { ...user, ...data };
29
+ this.users.set(id, updated);
30
+ return updated;
31
+ }
32
+ };
33
+
34
+ test('should create auth service', () => {
35
+ const { createAuth } = require('../dist/auth');
36
+ const auth = createAuth({ jwtSecret: 'test-secret-key-that-is-at-least-32-chars' }, mockUserStore);
37
+
38
+ expect(auth).toBeDefined();
39
+ expect(auth.initialize).toBeDefined();
40
+ expect(auth.register).toBeDefined();
41
+ expect(auth.login).toBeDefined();
42
+ });
43
+
44
+ test('should register a new user', async () => {
45
+ const { createAuth } = require('../dist/auth');
46
+ const auth = createAuth({ jwtSecret: 'test-secret-key-that-is-at-least-32-chars' }, mockUserStore);
47
+
48
+ const result = await auth.register({
49
+ email: 'test@example.com',
50
+ password: 'password123',
51
+ name: 'Test User'
52
+ });
53
+
54
+ expect(result.user).toBeDefined();
55
+ expect(result.user.email).toBe('test@example.com');
56
+ expect(result.tokens).toHaveProperty('accessToken');
57
+ expect(result.tokens).toHaveProperty('refreshToken');
58
+ });
59
+
60
+ test('should login with valid credentials', async () => {
61
+ const { createAuth } = require('../dist/auth');
62
+ const auth = createAuth({ jwtSecret: 'test-secret-key-that-is-at-least-32-chars' }, mockUserStore);
63
+
64
+ await auth.register({
65
+ email: 'login@test.com',
66
+ password: 'password123'
67
+ });
68
+
69
+ const result = await auth.login({
70
+ email: 'login@test.com',
71
+ password: 'password123'
72
+ });
73
+
74
+ expect(result.user).toBeDefined();
75
+ expect(result.tokens).toHaveProperty('accessToken');
76
+ });
77
+
78
+ test('should fail login with invalid credentials', async () => {
79
+ const { createAuth } = require('../dist/auth');
80
+ const auth = createAuth({ jwtSecret: 'test-secret-key-that-is-at-least-32-chars' }, mockUserStore);
81
+
82
+ await auth.register({
83
+ email: 'fail@test.com',
84
+ password: 'password123'
85
+ });
86
+
87
+ await expect(auth.login({
88
+ email: 'fail@test.com',
89
+ password: 'wrongpassword'
90
+ })).rejects.toThrow('Invalid credentials');
91
+ });
92
+
93
+ test('should throw error for duplicate registration', async () => {
94
+ const { createAuth } = require('../dist/auth');
95
+ const auth = createAuth({ jwtSecret: 'test-secret-key-that-is-at-least-32-chars' }, mockUserStore);
96
+
97
+ await auth.register({
98
+ email: 'duplicate@test.com',
99
+ password: 'password123'
100
+ });
101
+
102
+ await expect(auth.register({
103
+ email: 'duplicate@test.com',
104
+ password: 'password123'
105
+ })).rejects.toThrow('User already exists');
106
+ });
107
+
108
+ test('should generate middleware', () => {
109
+ const { createAuth } = require('../dist/auth');
110
+ const auth = createAuth({ jwtSecret: 'test-secret-key-that-is-at-least-32-chars' }, mockUserStore);
111
+
112
+ const middleware = auth.getMiddleware();
113
+ expect(middleware).toBeDefined();
114
+ expect(typeof middleware).toBe('function');
115
+ });
116
+
117
+ test('should create requireUser middleware', () => {
118
+ const { createAuth } = require('../dist/auth');
119
+ const auth = createAuth({ jwtSecret: 'test-secret-key-that-is-at-least-32-chars' }, mockUserStore);
120
+
121
+ const middleware = auth.requireUser();
122
+ expect(middleware).toBeDefined();
123
+ expect(typeof middleware).toBe('function');
124
+ });
125
+
126
+ test('should create requireRole middleware', () => {
127
+ const { createAuth } = require('../dist/auth');
128
+ const auth = createAuth({ jwtSecret: 'test-secret-key-that-is-at-least-32-chars' }, mockUserStore);
129
+
130
+ const middleware = auth.requireRole('admin');
131
+ expect(middleware).toBeDefined();
132
+ expect(typeof middleware).toBe('function');
133
+ });
134
+ });
@@ -0,0 +1,36 @@
1
+ describe('Config Module', () => {
2
+ test('should load config with defaults', async () => {
3
+ const { config } = require('../dist/config');
4
+ const cfg = config.load();
5
+
6
+ expect(cfg.NODE_ENV).toBe('test');
7
+ expect(cfg.PORT).toBe('3000');
8
+ expect(cfg.REDIS_URL).toBe('redis://localhost:6379');
9
+ });
10
+
11
+ test('should get config value', async () => {
12
+ const { config } = require('../dist/config');
13
+ config.load();
14
+
15
+ const port = config.int('PORT');
16
+ expect(port).toBe(3000);
17
+ });
18
+
19
+ test('should check environment', async () => {
20
+ const { config } = require('../dist/config');
21
+ config.load();
22
+
23
+ expect(config.isTest()).toBe(true);
24
+ expect(config.isProduction()).toBe(false);
25
+ expect(config.isDevelopment()).toBe(false);
26
+ });
27
+
28
+ test('should get all config', async () => {
29
+ const { config } = require('../dist/config');
30
+ const cfg = config.getAll();
31
+
32
+ expect(cfg).toHaveProperty('NODE_ENV');
33
+ expect(cfg).toHaveProperty('PORT');
34
+ expect(cfg).toHaveProperty('AWS_REGION');
35
+ });
36
+ });
@@ -0,0 +1,47 @@
1
+ describe('Logger Module', () => {
2
+ test('should create logger', () => {
3
+ const { logger } = require('../dist/logger');
4
+
5
+ expect(logger).toBeDefined();
6
+ expect(logger.info).toBeDefined();
7
+ expect(logger.error).toBeDefined();
8
+ expect(logger.warn).toBeDefined();
9
+ expect(logger.debug).toBeDefined();
10
+ });
11
+
12
+ test('should log info message', () => {
13
+ const { logger } = require('../dist/logger');
14
+
15
+ expect(() => logger.info('test message')).not.toThrow();
16
+ });
17
+
18
+ test('should log error with metadata', () => {
19
+ const { logger } = require('../dist/logger');
20
+
21
+ expect(() => logger.error('error occurred', { code: 500 })).not.toThrow();
22
+ });
23
+
24
+ test('should create child logger', () => {
25
+ const { logger } = require('../dist/logger');
26
+
27
+ const child = logger.child({ module: 'auth' });
28
+ expect(child).toBeDefined();
29
+ expect(child.info).toBeDefined();
30
+ });
31
+
32
+ test('should create named logger', () => {
33
+ const { logger } = require('../dist/logger');
34
+
35
+ const named = logger.create({ name: 'test-logger' });
36
+ expect(named).toBeDefined();
37
+ expect(named.info).toBeDefined();
38
+ });
39
+
40
+ test('should get logger by name', () => {
41
+ const { logger } = require('../dist/logger');
42
+
43
+ logger.create({ name: 'custom-logger' });
44
+ const custom = logger.get('custom-logger');
45
+ expect(custom).toBeDefined();
46
+ });
47
+ });
@@ -0,0 +1,19 @@
1
+ describe('Notifications Module', () => {
2
+ test('should have notify object defined', () => {
3
+ const { notify } = require('../dist/notifications');
4
+
5
+ expect(notify).toBeDefined();
6
+ expect(notify.email).toBeDefined();
7
+ expect(notify.sms).toBeDefined();
8
+ expect(notify.webhook).toBeDefined();
9
+ expect(notify.slack).toBeDefined();
10
+ });
11
+
12
+ test('should have notification export', () => {
13
+ const { notification } = require('../dist/notifications');
14
+
15
+ expect(notification).toBeDefined();
16
+ expect(notification.email).toBeDefined();
17
+ expect(notification.sms).toBeDefined();
18
+ });
19
+ });
@@ -0,0 +1,50 @@
1
+ describe('Rate Limit Module', () => {
2
+ test('should create rate limiter middleware', () => {
3
+ const { rateLimit } = require('../src/rate-limit');
4
+
5
+ const middleware = rateLimit({ window: '1m', limit: 100 });
6
+ expect(middleware).toBeDefined();
7
+ expect(typeof middleware).toBe('function');
8
+ });
9
+
10
+ test('should create rate limiter with defaults', () => {
11
+ const { rateLimit } = require('../src/rate-limit');
12
+
13
+ const middleware = rateLimit();
14
+ expect(middleware).toBeDefined();
15
+ expect(typeof middleware).toBe('function');
16
+ });
17
+
18
+ test('should create custom rate limiter', () => {
19
+ const { createRateLimiter } = require('../src/rate-limit');
20
+
21
+ const limiter = createRateLimiter({ window: '1m', limit: 10 });
22
+ expect(limiter).toBeDefined();
23
+ expect(limiter.middleware).toBeDefined();
24
+ expect(limiter.destroy).toBeDefined();
25
+ });
26
+
27
+ test('should use custom key generator', () => {
28
+ const { rateLimit } = require('../src/rate-limit');
29
+
30
+ const middleware = rateLimit({
31
+ window: '1m',
32
+ limit: 100,
33
+ keyGenerator: (req: any) => req.userId || 'anonymous'
34
+ });
35
+
36
+ expect(middleware).toBeDefined();
37
+ });
38
+
39
+ test('should use custom skip function', () => {
40
+ const { rateLimit } = require('../src/rate-limit');
41
+
42
+ const middleware = rateLimit({
43
+ window: '1m',
44
+ limit: 100,
45
+ skip: (req: any) => req.skipRateLimit === true
46
+ });
47
+
48
+ expect(middleware).toBeDefined();
49
+ });
50
+ });
@@ -0,0 +1,33 @@
1
+ describe('Upload Module (S3)', () => {
2
+ test('should have upload functions defined', () => {
3
+ const { upload } = require('../dist/upload');
4
+
5
+ expect(upload).toBeDefined();
6
+ expect(upload.initialize).toBeDefined();
7
+ expect(upload.file).toBeDefined();
8
+ expect(upload.image).toBeDefined();
9
+ expect(upload.video).toBeDefined();
10
+ expect(upload.delete).toBeDefined();
11
+ expect(upload.getSignedUrl).toBeDefined();
12
+ expect(upload.getPublicUrl).toBeDefined();
13
+ });
14
+
15
+ test('should initialize S3 service', () => {
16
+ const { upload } = require('../dist/upload');
17
+
18
+ expect(() => {
19
+ upload.initialize({
20
+ region: 'us-east-1',
21
+ accessKeyId: 'test-key',
22
+ secretAccessKey: 'test-secret',
23
+ bucket: 'test-bucket'
24
+ });
25
+ }).not.toThrow();
26
+ });
27
+
28
+ test('should have s3Service defined', () => {
29
+ const { s3Service } = require('../dist/upload');
30
+
31
+ expect(s3Service).toBeDefined();
32
+ });
33
+ });
@@ -0,0 +1,14 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "rootDir": ".",
5
+ "types": ["jest", "node"],
6
+ "composite": false,
7
+ "declaration": false,
8
+ "declarationMap": false,
9
+ "sourceMap": false,
10
+ "noUnusedLocals": false,
11
+ "noUnusedParameters": false
12
+ },
13
+ "include": ["src/**/*", "tests/**/*"]
14
+ }
package/tsup.config.ts CHANGED
@@ -10,13 +10,14 @@ export default defineConfig({
10
10
  'rate-limit/index': 'src/rate-limit/index.ts',
11
11
  'config/index': 'src/config/index.ts',
12
12
  'response/index': 'src/response/index.ts',
13
+ 'upload/index': 'src/upload/index.ts',
13
14
  },
14
15
  format: ['cjs', 'esm'],
15
16
  dts: false,
16
17
  splitting: false,
17
18
  sourcemap: true,
18
19
  clean: false,
19
- external: ['express', 'fastify', 'ioredis', 'bullmq'],
20
+ external: ['express', 'fastify', 'ioredis', 'bullmq', '@aws-sdk/client-s3', '@aws-sdk/s3-request-presigner'],
20
21
  treeshake: true,
21
22
  exports: {
22
23
  namedExports: true,