saas-backend-kit 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.
Files changed (67) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/PUBLISHING.md +133 -0
  3. package/README.md +459 -0
  4. package/copy-dts.js +255 -0
  5. package/dist/auth/index.d.ts +58 -0
  6. package/dist/auth/index.js +584 -0
  7. package/dist/auth/index.js.map +1 -0
  8. package/dist/auth/index.mjs +569 -0
  9. package/dist/auth/index.mjs.map +1 -0
  10. package/dist/config/index.d.ts +22 -0
  11. package/dist/config/index.js +106 -0
  12. package/dist/config/index.js.map +1 -0
  13. package/dist/config/index.mjs +100 -0
  14. package/dist/config/index.mjs.map +1 -0
  15. package/dist/index.d.ts +25 -0
  16. package/dist/index.js +1303 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/index.mjs +1281 -0
  19. package/dist/index.mjs.map +1 -0
  20. package/dist/logger/index.d.ts +18 -0
  21. package/dist/logger/index.js +188 -0
  22. package/dist/logger/index.js.map +1 -0
  23. package/dist/logger/index.mjs +178 -0
  24. package/dist/logger/index.mjs.map +1 -0
  25. package/dist/notifications/index.d.ts +35 -0
  26. package/dist/notifications/index.js +339 -0
  27. package/dist/notifications/index.js.map +1 -0
  28. package/dist/notifications/index.mjs +328 -0
  29. package/dist/notifications/index.mjs.map +1 -0
  30. package/dist/queue/index.d.ts +33 -0
  31. package/dist/queue/index.js +306 -0
  32. package/dist/queue/index.js.map +1 -0
  33. package/dist/queue/index.mjs +293 -0
  34. package/dist/queue/index.mjs.map +1 -0
  35. package/dist/rate-limit/index.d.ts +11 -0
  36. package/dist/rate-limit/index.js +290 -0
  37. package/dist/rate-limit/index.js.map +1 -0
  38. package/dist/rate-limit/index.mjs +286 -0
  39. package/dist/rate-limit/index.mjs.map +1 -0
  40. package/dist/response/index.d.ts +29 -0
  41. package/dist/response/index.js +120 -0
  42. package/dist/response/index.js.map +1 -0
  43. package/dist/response/index.mjs +114 -0
  44. package/dist/response/index.mjs.map +1 -0
  45. package/examples/express/.env.example +41 -0
  46. package/examples/express/app.ts +203 -0
  47. package/package.json +109 -0
  48. package/src/auth/express.ts +250 -0
  49. package/src/auth/fastify.ts +65 -0
  50. package/src/auth/index.ts +6 -0
  51. package/src/auth/jwt.ts +47 -0
  52. package/src/auth/oauth.ts +117 -0
  53. package/src/auth/rbac.ts +82 -0
  54. package/src/auth/types.ts +69 -0
  55. package/src/config/index.ts +120 -0
  56. package/src/index.ts +16 -0
  57. package/src/logger/index.ts +110 -0
  58. package/src/notifications/index.ts +262 -0
  59. package/src/plugin.ts +192 -0
  60. package/src/queue/index.ts +208 -0
  61. package/src/rate-limit/express.ts +144 -0
  62. package/src/rate-limit/fastify.ts +47 -0
  63. package/src/rate-limit/index.ts +2 -0
  64. package/src/response/index.ts +197 -0
  65. package/src/utils/index.ts +180 -0
  66. package/tsconfig.json +30 -0
  67. package/tsup.config.ts +24 -0
@@ -0,0 +1,144 @@
1
+ import { Request, Response, NextFunction, RequestHandler } from 'express';
2
+ import { config } from '../config';
3
+
4
+ export interface RateLimitOptions {
5
+ window?: string;
6
+ limit?: number;
7
+ keyGenerator?: (req: Request) => string;
8
+ handler?: (req: Request, res: Response) => void;
9
+ skipSuccessfulRequests?: boolean;
10
+ skipFailedRequests?: boolean;
11
+ skip?: (req: Request) => boolean;
12
+ }
13
+
14
+ interface RateLimitRecord {
15
+ count: number;
16
+ resetTime: number;
17
+ }
18
+
19
+ class InMemoryRateLimiter {
20
+ private store: Map<string, RateLimitRecord> = new Map();
21
+ private cleanupInterval: NodeJS.Timeout;
22
+
23
+ constructor() {
24
+ this.cleanupInterval = setInterval(() => this.cleanup(), 60000);
25
+ }
26
+
27
+ private cleanup(): void {
28
+ const now = Date.now();
29
+ for (const [key, record] of this.store.entries()) {
30
+ if (record.resetTime < now) {
31
+ this.store.delete(key);
32
+ }
33
+ }
34
+ }
35
+
36
+ increment(key: string, windowMs: number): RateLimitRecord {
37
+ const now = Date.now();
38
+ const record = this.store.get(key);
39
+
40
+ if (!record || record.resetTime < now) {
41
+ const resetTime = now + windowMs;
42
+ this.store.set(key, { count: 1, resetTime });
43
+ return { count: 1, resetTime };
44
+ }
45
+
46
+ record.count++;
47
+ return record;
48
+ }
49
+
50
+ get(key: string): RateLimitRecord | undefined {
51
+ return this.store.get(key);
52
+ }
53
+
54
+ destroy(): void {
55
+ clearInterval(this.cleanupInterval);
56
+ }
57
+ }
58
+
59
+ class RateLimiter {
60
+ private options: Required<RateLimitOptions>;
61
+ private store: InMemoryRateLimiter;
62
+
63
+ constructor(options: RateLimitOptions = {}) {
64
+ const defaultWindow = config.get('RATE_LIMIT_WINDOW') || '1m';
65
+ const defaultLimit = parseInt(config.get('RATE_LIMIT_LIMIT') || '100', 10);
66
+
67
+ this.options = {
68
+ window: options.window || defaultWindow,
69
+ limit: options.limit || defaultLimit,
70
+ keyGenerator: options.keyGenerator || ((req: Request) => req.ip || 'unknown'),
71
+ handler: options.handler || this.defaultHandler,
72
+ skipSuccessfulRequests: options.skipSuccessfulRequests || false,
73
+ skipFailedRequests: options.skipFailedRequests || false,
74
+ skip: options.skip || (() => false),
75
+ };
76
+
77
+ this.store = new InMemoryRateLimiter();
78
+ }
79
+
80
+ private getWindowMs(): number {
81
+ const window = this.options.window;
82
+ const match = window.match(/^(\d+)(s|m|h|d)$/);
83
+ if (!match) return 60000;
84
+
85
+ const value = parseInt(match[1], 10);
86
+ const unit = match[2];
87
+
88
+ switch (unit) {
89
+ case 's': return value * 1000;
90
+ case 'm': return value * 60 * 1000;
91
+ case 'h': return value * 60 * 60 * 1000;
92
+ case 'd': return value * 24 * 60 * 60 * 1000;
93
+ default: return 60000;
94
+ }
95
+ }
96
+
97
+ private defaultHandler(req: Request, res: Response): void {
98
+ res.status(429).json({
99
+ error: 'Too many requests',
100
+ message: `Rate limit exceeded. Please try again later.`,
101
+ });
102
+ }
103
+
104
+ middleware(): RequestHandler {
105
+ const windowMs = this.getWindowMs();
106
+
107
+ return (req: Request, res: Response, next: NextFunction) => {
108
+ if (this.options.skip(req)) {
109
+ return next();
110
+ }
111
+
112
+ const key = this.options.keyGenerator(req);
113
+ const record = this.store.increment(key, windowMs);
114
+
115
+ const remaining = Math.max(0, this.options.limit - record.count);
116
+ const resetTime = new Date(record.resetTime);
117
+
118
+ res.setHeader('X-RateLimit-Limit', this.options.limit);
119
+ res.setHeader('X-RateLimit-Remaining', remaining);
120
+ res.setHeader('X-RateLimit-Reset', Math.ceil(record.resetTime / 1000));
121
+
122
+ if (record.count > this.options.limit) {
123
+ return this.options.handler(req, res);
124
+ }
125
+
126
+ next();
127
+ };
128
+ }
129
+
130
+ destroy(): void {
131
+ this.store.destroy();
132
+ }
133
+ }
134
+
135
+ export function rateLimit(options: RateLimitOptions = {}): RequestHandler {
136
+ const limiter = new RateLimiter(options);
137
+ return limiter.middleware();
138
+ }
139
+
140
+ export function createRateLimiter(options: RateLimitOptions): RateLimiter {
141
+ return new RateLimiter(options);
142
+ }
143
+
144
+ export default rateLimit;
@@ -0,0 +1,47 @@
1
+ import { FastifyInstance, FastifyRequest, FastifyReply, HookHandlerDoneFunction } from 'fastify';
2
+ import { RateLimitOptions, InMemoryRateLimiter } from './express';
3
+
4
+ export function registerRateLimitPlugin(fastify: FastifyInstance, options: RateLimitOptions = {}, done: HookHandlerDoneFunction) {
5
+ const limiter = new (require('./express').createRateLimiter.constructor)(options);
6
+
7
+ fastify.addHook('onRequest', async (request: FastifyRequest, reply: FastifyReply) => {
8
+ const key = options.keyGenerator
9
+ ? options.keyGenerator(request.raw as any)
10
+ : request.ip || 'unknown';
11
+
12
+ const windowMs = parseWindowMs(options.window || '1m');
13
+ const record = (limiter as any).store.increment(key, windowMs);
14
+ const limit = options.limit || 100;
15
+ const remaining = Math.max(0, limit - record.count);
16
+
17
+ reply.header('X-RateLimit-Limit', limit);
18
+ reply.header('X-RateLimit-Remaining', remaining);
19
+ reply.header('X-RateLimit-Reset', Math.ceil(record.resetTime / 1000));
20
+
21
+ if (record.count > limit) {
22
+ reply.status(429).send({
23
+ error: 'Too many requests',
24
+ message: 'Rate limit exceeded. Please try again later.',
25
+ });
26
+ return reply;
27
+ }
28
+ });
29
+
30
+ done();
31
+ }
32
+
33
+ function parseWindowMs(window: string): number {
34
+ const match = window.match(/^(\d+)(s|m|h|d)$/);
35
+ if (!match) return 60000;
36
+
37
+ const value = parseInt(match[1], 10);
38
+ const unit = match[2];
39
+
40
+ switch (unit) {
41
+ case 's': return value * 1000;
42
+ case 'm': return value * 60 * 1000;
43
+ case 'h': return value * 60 * 60 * 1000;
44
+ case 'd': return value * 24 * 60 * 60 * 1000;
45
+ default: return 60000;
46
+ }
47
+ }
@@ -0,0 +1,2 @@
1
+ export * from './express';
2
+ export * from './fastify';
@@ -0,0 +1,197 @@
1
+ import { Response } from 'express';
2
+
3
+ export interface ApiResponse<T = unknown> {
4
+ success: boolean;
5
+ data?: T;
6
+ error?: string;
7
+ message?: string;
8
+ meta?: {
9
+ page?: number;
10
+ limit?: number;
11
+ total?: number;
12
+ totalPages?: number;
13
+ };
14
+ }
15
+
16
+ export interface PaginatedResponse<T> extends ApiResponse<T> {
17
+ meta: {
18
+ page: number;
19
+ limit: number;
20
+ total: number;
21
+ totalPages: number;
22
+ };
23
+ }
24
+
25
+ export interface ErrorResponse {
26
+ success: false;
27
+ error: string;
28
+ code?: string;
29
+ details?: Record<string, unknown>;
30
+ }
31
+
32
+ export class ResponseHelper {
33
+ static success<T>(res: Response, data?: T, message?: string, statusCode: number = 200): Response {
34
+ const response: ApiResponse<T> = {
35
+ success: true,
36
+ data,
37
+ message,
38
+ };
39
+ return res.status(statusCode).json(response);
40
+ }
41
+
42
+ static created<T>(res: Response, data?: T, message: string = 'Resource created'): Response {
43
+ return this.success(res, data, message, 201);
44
+ }
45
+
46
+ static updated<T>(res: Response, data?: T, message: string = 'Resource updated'): Response {
47
+ return this.success(res, data, message, 200);
48
+ }
49
+
50
+ static deleted(res: Response, message: string = 'Resource deleted'): Response {
51
+ return this.success(res, null, message, 200);
52
+ }
53
+
54
+ static error(
55
+ res: Response,
56
+ error: string,
57
+ statusCode: number = 400,
58
+ code?: string,
59
+ details?: Record<string, unknown>
60
+ ): Response {
61
+ const response: ErrorResponse = {
62
+ success: false,
63
+ error,
64
+ code,
65
+ ...(details && { details }),
66
+ };
67
+ return res.status(statusCode).json(response);
68
+ }
69
+
70
+ static badRequest(res: Response, error: string = 'Bad request', code?: string): Response {
71
+ return this.error(res, error, 400, code);
72
+ }
73
+
74
+ static unauthorized(res: Response, error: string = 'Unauthorized', code?: string): Response {
75
+ return this.error(res, error, 401, code);
76
+ }
77
+
78
+ static forbidden(res: Response, error: string = 'Forbidden', code?: string): Response {
79
+ return this.error(res, error, 403, code);
80
+ }
81
+
82
+ static notFound(res: Response, error: string = 'Resource not found', code?: string): Response {
83
+ return this.error(res, error, 404, code);
84
+ }
85
+
86
+ static conflict(res: Response, error: string = 'Conflict', code?: string): Response {
87
+ return this.error(res, error, 409, code);
88
+ }
89
+
90
+ static validationError(res: Response, error: string, details?: Record<string, unknown>): Response {
91
+ return this.error(res, error, 422, 'VALIDATION_ERROR', details);
92
+ }
93
+
94
+ static internalError(res: Response, error: string = 'Internal server error'): Response {
95
+ return this.error(res, error, 500, 'INTERNAL_ERROR');
96
+ }
97
+
98
+ static paginated<T>(
99
+ res: Response,
100
+ data: T[],
101
+ page: number,
102
+ limit: number,
103
+ total: number
104
+ ): Response<PaginatedResponse<T>> {
105
+ const totalPages = Math.ceil(total / limit);
106
+ const response: PaginatedResponse<T> = {
107
+ success: true,
108
+ data,
109
+ meta: {
110
+ page,
111
+ limit,
112
+ total,
113
+ totalPages,
114
+ },
115
+ };
116
+ return res.status(200).json(response);
117
+ }
118
+
119
+ static noContent(res: Response): Response {
120
+ return res.status(204).send();
121
+ }
122
+ }
123
+
124
+ declare global {
125
+ namespace Express {
126
+ interface Response {
127
+ success<T>(data?: T, message?: string, statusCode?: number): Response;
128
+ created<T>(data?: T, message?: string): Response;
129
+ updated<T>(data?: T, message?: string): Response;
130
+ deleted(message?: string): Response;
131
+ error(error: string, statusCode?: number, code?: string, details?: Record<string, unknown>): Response;
132
+ badRequest(error?: string, code?: string): Response;
133
+ unauthorized(error?: string, code?: string): Response;
134
+ forbidden(error?: string, code?: string): Response;
135
+ notFound(error?: string, code?: string): Response;
136
+ conflict(error?: string, code?: string): Response;
137
+ validationError(error: string, details?: Record<string, unknown>): Response;
138
+ internalError(error?: string): Response;
139
+ paginated<T>(data: T[], page: number, limit: number, total: number): Response;
140
+ }
141
+ }
142
+ }
143
+
144
+ Response.prototype.success = function <T>(data?: T, message?: string, statusCode: number = 200) {
145
+ return ResponseHelper.success(this, data, message, statusCode);
146
+ };
147
+
148
+ Response.prototype.created = function <T>(data?: T, message?: string) {
149
+ return ResponseHelper.created(this, data, message);
150
+ };
151
+
152
+ Response.prototype.updated = function <T>(data?: T, message?: string) {
153
+ return ResponseHelper.updated(this, data, message);
154
+ };
155
+
156
+ Response.prototype.deleted = function (message?: string) {
157
+ return ResponseHelper.deleted(this, message);
158
+ };
159
+
160
+ Response.prototype.error = function (error: string, statusCode: number = 400, code?: string, details?: Record<string, unknown>) {
161
+ return ResponseHelper.error(this, error, statusCode, code, details);
162
+ };
163
+
164
+ Response.prototype.badRequest = function (error?: string, code?: string) {
165
+ return ResponseHelper.badRequest(this, error, code);
166
+ };
167
+
168
+ Response.prototype.unauthorized = function (error?: string, code?: string) {
169
+ return ResponseHelper.unauthorized(this, error, code);
170
+ };
171
+
172
+ Response.prototype.forbidden = function (error?: string, code?: string) {
173
+ return ResponseHelper.forbidden(this, error, code);
174
+ };
175
+
176
+ Response.prototype.notFound = function (error?: string, code?: string) {
177
+ return ResponseHelper.notFound(this, error, code);
178
+ };
179
+
180
+ Response.prototype.conflict = function (error?: string, code?: string) {
181
+ return ResponseHelper.conflict(this, error, code);
182
+ };
183
+
184
+ Response.prototype.validationError = function (error: string, details?: Record<string, unknown>) {
185
+ return ResponseHelper.validationError(this, error, details);
186
+ };
187
+
188
+ Response.prototype.internalError = function (error?: string) {
189
+ return ResponseHelper.internalError(this, error);
190
+ };
191
+
192
+ Response.prototype.paginated = function <T>(data: T[], page: number, limit: number, total: number) {
193
+ return ResponseHelper.paginated(this, data, page, limit, total);
194
+ };
195
+
196
+ export const response = ResponseHelper;
197
+ export default ResponseHelper;
@@ -0,0 +1,180 @@
1
+ import crypto from 'crypto';
2
+
3
+ export function generateId(length: number = 16): string {
4
+ return crypto.randomBytes(length).toString('hex');
5
+ }
6
+
7
+ export function hashString(input: string, algorithm: string = 'sha256'): string {
8
+ return crypto.createHash(algorithm).update(input).digest('hex');
9
+ }
10
+
11
+ export function timingSafeEqual(a: string, b: string): boolean {
12
+ const bufA = Buffer.from(a);
13
+ const bufB = Buffer.from(b);
14
+
15
+ if (bufA.length !== bufB.length) {
16
+ return false;
17
+ }
18
+
19
+ return crypto.timingSafeEqual(bufA, bufB);
20
+ }
21
+
22
+ export function generateToken(length: number = 32): string {
23
+ return crypto.randomBytes(length).toString('base64url');
24
+ }
25
+
26
+ export function generateApiKey(prefix: string = 'sk'): string {
27
+ const timestamp = Date.now().toString(36);
28
+ const random = crypto.randomBytes(24).toString('hex');
29
+ return `${prefix}_${timestamp}_${random}`;
30
+ }
31
+
32
+ export class Cache<T> {
33
+ private store: Map<string, { value: T; expiresAt: number }> = new Map();
34
+
35
+ set(key: string, value: T, ttlMs: number = 60000): void {
36
+ const expiresAt = Date.now() + ttlMs;
37
+ this.store.set(key, { value, expiresAt });
38
+ }
39
+
40
+ get(key: string): T | undefined {
41
+ const entry = this.store.get(key);
42
+ if (!entry) return undefined;
43
+
44
+ if (Date.now() > entry.expiresAt) {
45
+ this.store.delete(key);
46
+ return undefined;
47
+ }
48
+
49
+ return entry.value;
50
+ }
51
+
52
+ has(key: string): boolean {
53
+ return this.get(key) !== undefined;
54
+ }
55
+
56
+ delete(key: string): boolean {
57
+ return this.store.delete(key);
58
+ }
59
+
60
+ clear(): void {
61
+ this.store.clear();
62
+ }
63
+
64
+ cleanup(): void {
65
+ const now = Date.now();
66
+ for (const [key, entry] of this.store.entries()) {
67
+ if (now > entry.expiresAt) {
68
+ this.store.delete(key);
69
+ }
70
+ }
71
+ }
72
+ }
73
+
74
+ export function sleep(ms: number): Promise<void> {
75
+ return new Promise(resolve => setTimeout(resolve, ms));
76
+ }
77
+
78
+ export function retry<T>(
79
+ fn: () => Promise<T>,
80
+ options: { maxAttempts?: number; delayMs?: number; backoff?: boolean } = {}
81
+ ): Promise<T> {
82
+ const { maxAttempts = 3, delayMs = 1000, backoff = true } = options;
83
+
84
+ return new Promise(async (resolve, reject) => {
85
+ let lastError: Error | undefined;
86
+
87
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
88
+ try {
89
+ const result = await fn();
90
+ return resolve(result);
91
+ } catch (error) {
92
+ lastError = error as Error;
93
+
94
+ if (attempt < maxAttempts) {
95
+ const delay = backoff ? delayMs * Math.pow(2, attempt - 1) : delayMs;
96
+ await sleep(delay);
97
+ }
98
+ }
99
+ }
100
+
101
+ reject(lastError);
102
+ });
103
+ }
104
+
105
+ export function debounce<T extends (...args: unknown[]) => unknown>(
106
+ fn: T,
107
+ delayMs: number
108
+ ): (...args: Parameters<T>) => void {
109
+ let timeoutId: NodeJS.Timeout;
110
+
111
+ return (...args: Parameters<T>) => {
112
+ clearTimeout(timeoutId);
113
+ timeoutId = setTimeout(() => fn(...args), delayMs);
114
+ };
115
+ }
116
+
117
+ export function throttle<T extends (...args: unknown[]) => unknown>(
118
+ fn: T,
119
+ limitMs: number
120
+ ): (...args: Parameters<T>) => void {
121
+ let lastRun = 0;
122
+
123
+ return (...args: Parameters<T>) => {
124
+ const now = Date.now();
125
+ if (now - lastRun >= limitMs) {
126
+ lastRun = now;
127
+ fn(...args);
128
+ }
129
+ };
130
+ }
131
+
132
+ export function parseQueryInt(value: string | undefined, defaultValue: number): number {
133
+ if (!value) return defaultValue;
134
+ const parsed = parseInt(value, 10);
135
+ return isNaN(parsed) ? defaultValue : parsed;
136
+ }
137
+
138
+ export function parseQueryBool(value: string | undefined, defaultValue: boolean): boolean {
139
+ if (!value) return defaultValue;
140
+ return value.toLowerCase() === 'true';
141
+ }
142
+
143
+ export function sanitizeObject<T extends Record<string, unknown>>(
144
+ obj: T,
145
+ allowedKeys: string[]
146
+ ): Partial<T> {
147
+ const sanitized: Partial<T> = {};
148
+
149
+ for (const key of allowedKeys) {
150
+ if (key in obj) {
151
+ sanitized[key as keyof T] = obj[key];
152
+ }
153
+ }
154
+
155
+ return sanitized;
156
+ }
157
+
158
+ export function omit<T extends Record<string, unknown>, K extends keyof T>(
159
+ obj: T,
160
+ keys: K[]
161
+ ): Omit<T, K> {
162
+ const result = { ...obj };
163
+ for (const key of keys) {
164
+ delete result[key];
165
+ }
166
+ return result;
167
+ }
168
+
169
+ export function pick<T extends Record<string, unknown>, K extends keyof T>(
170
+ obj: T,
171
+ keys: K[]
172
+ ): Pick<T, K> {
173
+ const result = {} as Pick<T, K>;
174
+ for (const key of keys) {
175
+ if (key in obj) {
176
+ result[key] = obj[key];
177
+ }
178
+ }
179
+ return result;
180
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "lib": ["ES2022"],
6
+ "moduleResolution": "bundler",
7
+ "declaration": true,
8
+ "declarationMap": true,
9
+ "sourceMap": true,
10
+ "outDir": "./dist",
11
+ "rootDir": "./src",
12
+ "strict": true,
13
+ "esModuleInterop": true,
14
+ "skipLibCheck": true,
15
+ "forceConsistentCasingInFileNames": true,
16
+ "resolveJsonModule": true,
17
+ "allowSyntheticDefaultImports": true,
18
+ "noImplicitAny": true,
19
+ "noUnusedLocals": true,
20
+ "noUnusedParameters": true,
21
+ "noImplicitReturns": true,
22
+ "noFallthroughCasesInSwitch": true,
23
+ "composite": true,
24
+ "paths": {
25
+ "@/*": ["./src/*"]
26
+ }
27
+ },
28
+ "include": ["src/**/*"],
29
+ "exclude": ["node_modules", "dist", "examples"]
30
+ }
package/tsup.config.ts ADDED
@@ -0,0 +1,24 @@
1
+ import { defineConfig } from 'tsup';
2
+
3
+ export default defineConfig({
4
+ entry: {
5
+ 'index': 'src/index.ts',
6
+ 'auth/index': 'src/auth/index.ts',
7
+ 'queue/index': 'src/queue/index.ts',
8
+ 'notifications/index': 'src/notifications/index.ts',
9
+ 'logger/index': 'src/logger/index.ts',
10
+ 'rate-limit/index': 'src/rate-limit/index.ts',
11
+ 'config/index': 'src/config/index.ts',
12
+ 'response/index': 'src/response/index.ts',
13
+ },
14
+ format: ['cjs', 'esm'],
15
+ dts: false,
16
+ splitting: false,
17
+ sourcemap: true,
18
+ clean: false,
19
+ external: ['express', 'fastify', 'ioredis', 'bullmq'],
20
+ treeshake: true,
21
+ exports: {
22
+ namedExports: true,
23
+ },
24
+ });