saas-backend-kit 1.0.1 → 1.0.3
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 +205 -6
- package/dist/auth/index.js +2 -1
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/index.mjs +2 -1
- package/dist/auth/index.mjs.map +1 -1
- package/dist/config/index.js +1 -0
- package/dist/config/index.js.map +1 -1
- package/dist/config/index.mjs +1 -0
- package/dist/config/index.mjs.map +1 -1
- package/dist/index.js +124 -41
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +122 -42
- package/dist/index.mjs.map +1 -1
- package/dist/logger/index.js +1 -0
- package/dist/logger/index.js.map +1 -1
- package/dist/logger/index.mjs +1 -0
- package/dist/logger/index.mjs.map +1 -1
- package/dist/notifications/index.js +1 -0
- package/dist/notifications/index.js.map +1 -1
- package/dist/notifications/index.mjs +1 -0
- package/dist/notifications/index.mjs.map +1 -1
- package/dist/queue/index.js +1 -0
- package/dist/queue/index.js.map +1 -1
- package/dist/queue/index.mjs +1 -0
- package/dist/queue/index.mjs.map +1 -1
- package/dist/rate-limit/index.js +2 -0
- package/dist/rate-limit/index.js.map +1 -1
- package/dist/rate-limit/index.mjs +2 -0
- package/dist/rate-limit/index.mjs.map +1 -1
- package/dist/response/index.js +51 -40
- package/dist/response/index.js.map +1 -1
- package/dist/response/index.mjs +51 -40
- package/dist/response/index.mjs.map +1 -1
- package/dist/upload/index.js +1 -0
- package/dist/upload/index.js.map +1 -1
- package/dist/upload/index.mjs +1 -0
- package/dist/upload/index.mjs.map +1 -1
- package/examples/express/.env.example +4 -1
- package/jest-output.json +72 -0
- package/jest.config.js +19 -0
- package/package.json +10 -7
- package/src/auth/jwt.ts +1 -1
- package/src/config/index.ts +1 -0
- package/src/database/index.ts +102 -0
- package/src/index.ts +1 -0
- package/src/rate-limit/express.ts +1 -0
- package/src/response/index.ts +49 -40
- package/tests/auth.test.ts +134 -0
- package/tests/config.test.ts +36 -0
- package/tests/logger.test.ts +47 -0
- package/tests/notifications.test.ts +19 -0
- package/tests/rate-limit.test.ts +50 -0
- package/tests/upload.test.ts +33 -0
- package/tsconfig.test.json +14 -0
- package/tsup.config.ts +2 -1
package/dist/response/index.mjs
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
2
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
3
|
+
}) : x)(function(x) {
|
|
4
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
5
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
6
|
+
});
|
|
2
7
|
|
|
3
8
|
// src/response/index.ts
|
|
4
9
|
var ResponseHelper = class {
|
|
@@ -67,45 +72,51 @@ var ResponseHelper = class {
|
|
|
67
72
|
return res.status(204).send();
|
|
68
73
|
}
|
|
69
74
|
};
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
};
|
|
75
|
+
try {
|
|
76
|
+
const proto = __require("express").response;
|
|
77
|
+
if (proto) {
|
|
78
|
+
proto.success = function(data, message, statusCode = 200) {
|
|
79
|
+
return ResponseHelper.success(this, data, message, statusCode);
|
|
80
|
+
};
|
|
81
|
+
proto.created = function(data, message) {
|
|
82
|
+
return ResponseHelper.created(this, data, message);
|
|
83
|
+
};
|
|
84
|
+
proto.updated = function(data, message) {
|
|
85
|
+
return ResponseHelper.updated(this, data, message);
|
|
86
|
+
};
|
|
87
|
+
proto.deleted = function(message) {
|
|
88
|
+
return ResponseHelper.deleted(this, message);
|
|
89
|
+
};
|
|
90
|
+
proto.error = function(error, statusCode = 400, code, details) {
|
|
91
|
+
return ResponseHelper.error(this, error, statusCode, code, details);
|
|
92
|
+
};
|
|
93
|
+
proto.badRequest = function(error, code) {
|
|
94
|
+
return ResponseHelper.badRequest(this, error, code);
|
|
95
|
+
};
|
|
96
|
+
proto.unauthorized = function(error, code) {
|
|
97
|
+
return ResponseHelper.unauthorized(this, error, code);
|
|
98
|
+
};
|
|
99
|
+
proto.forbidden = function(error, code) {
|
|
100
|
+
return ResponseHelper.forbidden(this, error, code);
|
|
101
|
+
};
|
|
102
|
+
proto.notFound = function(error, code) {
|
|
103
|
+
return ResponseHelper.notFound(this, error, code);
|
|
104
|
+
};
|
|
105
|
+
proto.conflict = function(error, code) {
|
|
106
|
+
return ResponseHelper.conflict(this, error, code);
|
|
107
|
+
};
|
|
108
|
+
proto.validationError = function(error, details) {
|
|
109
|
+
return ResponseHelper.validationError(this, error, details);
|
|
110
|
+
};
|
|
111
|
+
proto.internalError = function(error) {
|
|
112
|
+
return ResponseHelper.internalError(this, error);
|
|
113
|
+
};
|
|
114
|
+
proto.paginated = function(data, page, limit, total) {
|
|
115
|
+
return ResponseHelper.paginated(this, data, page, limit, total);
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
} catch {
|
|
119
|
+
}
|
|
109
120
|
var response = ResponseHelper;
|
|
110
121
|
var response_default = ResponseHelper;
|
|
111
122
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/response/index.ts"],"names":["response"],"mappings":"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","file":"index.mjs","sourcesContent":["import { Response } from 'express';\n\nexport interface ApiResponse<T = unknown> {\n success: boolean;\n data?: T;\n error?: string;\n message?: string;\n meta?: {\n page?: number;\n limit?: number;\n total?: number;\n totalPages?: number;\n };\n}\n\nexport interface PaginatedResponse<T> extends ApiResponse<T> {\n meta: {\n page: number;\n limit: number;\n total: number;\n totalPages: number;\n };\n}\n\nexport interface ErrorResponse {\n success: false;\n error: string;\n code?: string;\n details?: Record<string, unknown>;\n}\n\nexport class ResponseHelper {\n static success<T>(res: Response, data?: T, message?: string, statusCode: number = 200): Response {\n const response: ApiResponse<T> = {\n success: true,\n data,\n message,\n };\n return res.status(statusCode).json(response);\n }\n\n static created<T>(res: Response, data?: T, message: string = 'Resource created'): Response {\n return this.success(res, data, message, 201);\n }\n\n static updated<T>(res: Response, data?: T, message: string = 'Resource updated'): Response {\n return this.success(res, data, message, 200);\n }\n\n static deleted(res: Response, message: string = 'Resource deleted'): Response {\n return this.success(res, null, message, 200);\n }\n\n static error(\n res: Response,\n error: string,\n statusCode: number = 400,\n code?: string,\n details?: Record<string, unknown>\n ): Response {\n const response: ErrorResponse = {\n success: false,\n error,\n code,\n ...(details && { details }),\n };\n return res.status(statusCode).json(response);\n }\n\n static badRequest(res: Response, error: string = 'Bad request', code?: string): Response {\n return this.error(res, error, 400, code);\n }\n\n static unauthorized(res: Response, error: string = 'Unauthorized', code?: string): Response {\n return this.error(res, error, 401, code);\n }\n\n static forbidden(res: Response, error: string = 'Forbidden', code?: string): Response {\n return this.error(res, error, 403, code);\n }\n\n static notFound(res: Response, error: string = 'Resource not found', code?: string): Response {\n return this.error(res, error, 404, code);\n }\n\n static conflict(res: Response, error: string = 'Conflict', code?: string): Response {\n return this.error(res, error, 409, code);\n }\n\n static validationError(res: Response, error: string, details?: Record<string, unknown>): Response {\n return this.error(res, error, 422, 'VALIDATION_ERROR', details);\n }\n\n static internalError(res: Response, error: string = 'Internal server error'): Response {\n return this.error(res, error, 500, 'INTERNAL_ERROR');\n }\n\n static paginated<T>(\n res: Response,\n data: T[],\n page: number,\n limit: number,\n total: number\n ): Response<PaginatedResponse<T>> {\n const totalPages = Math.ceil(total / limit);\n const response: PaginatedResponse<T> = {\n success: true,\n data,\n meta: {\n page,\n limit,\n total,\n totalPages,\n },\n };\n return res.status(200).json(response);\n }\n\n static noContent(res: Response): Response {\n return res.status(204).send();\n }\n}\n\ndeclare global {\n namespace Express {\n interface Response {\n success<T>(data?: T, message?: string, statusCode?: number): Response;\n created<T>(data?: T, message?: string): Response;\n updated<T>(data?: T, message?: string): Response;\n deleted(message?: string): Response;\n error(error: string, statusCode?: number, code?: string, details?: Record<string, unknown>): Response;\n badRequest(error?: string, code?: string): Response;\n unauthorized(error?: string, code?: string): Response;\n forbidden(error?: string, code?: string): Response;\n notFound(error?: string, code?: string): Response;\n conflict(error?: string, code?: string): Response;\n validationError(error: string, details?: Record<string, unknown>): Response;\n internalError(error?: string): Response;\n paginated<T>(data: T[], page: number, limit: number, total: number): Response;\n }\n }\n}\n\nResponse.prototype.success = function <T>(data?: T, message?: string, statusCode: number = 200) {\n return ResponseHelper.success(this, data, message, statusCode);\n};\n\nResponse.prototype.created = function <T>(data?: T, message?: string) {\n return ResponseHelper.created(this, data, message);\n};\n\nResponse.prototype.updated = function <T>(data?: T, message?: string) {\n return ResponseHelper.updated(this, data, message);\n};\n\nResponse.prototype.deleted = function (message?: string) {\n return ResponseHelper.deleted(this, message);\n};\n\nResponse.prototype.error = function (error: string, statusCode: number = 400, code?: string, details?: Record<string, unknown>) {\n return ResponseHelper.error(this, error, statusCode, code, details);\n};\n\nResponse.prototype.badRequest = function (error?: string, code?: string) {\n return ResponseHelper.badRequest(this, error, code);\n};\n\nResponse.prototype.unauthorized = function (error?: string, code?: string) {\n return ResponseHelper.unauthorized(this, error, code);\n};\n\nResponse.prototype.forbidden = function (error?: string, code?: string) {\n return ResponseHelper.forbidden(this, error, code);\n};\n\nResponse.prototype.notFound = function (error?: string, code?: string) {\n return ResponseHelper.notFound(this, error, code);\n};\n\nResponse.prototype.conflict = function (error?: string, code?: string) {\n return ResponseHelper.conflict(this, error, code);\n};\n\nResponse.prototype.validationError = function (error: string, details?: Record<string, unknown>) {\n return ResponseHelper.validationError(this, error, details);\n};\n\nResponse.prototype.internalError = function (error?: string) {\n return ResponseHelper.internalError(this, error);\n};\n\nResponse.prototype.paginated = function <T>(data: T[], page: number, limit: number, total: number) {\n return ResponseHelper.paginated(this, data, page, limit, total);\n};\n\nexport const response = ResponseHelper;\nexport default ResponseHelper;\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/response/index.ts"],"names":["response"],"mappings":"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","file":"index.mjs","sourcesContent":["import { Response } from 'express';\n\nexport interface ApiResponse<T = unknown> {\n success: boolean;\n data?: T;\n error?: string;\n message?: string;\n meta?: {\n page?: number;\n limit?: number;\n total?: number;\n totalPages?: number;\n };\n}\n\nexport interface PaginatedResponse<T> extends Omit<ApiResponse<T[]>, 'data'> {\n data: T[];\n meta: {\n page: number;\n limit: number;\n total: number;\n totalPages: number;\n };\n}\n\nexport interface ErrorResponse {\n success: false;\n error: string;\n code?: string;\n details?: Record<string, unknown>;\n}\n\nexport class ResponseHelper {\n static success<T>(res: Response, data?: T, message?: string, statusCode: number = 200): Response {\n const response: ApiResponse<T> = {\n success: true,\n data,\n message,\n };\n return res.status(statusCode).json(response);\n }\n\n static created<T>(res: Response, data?: T, message: string = 'Resource created'): Response {\n return this.success(res, data, message, 201);\n }\n\n static updated<T>(res: Response, data?: T, message: string = 'Resource updated'): Response {\n return this.success(res, data, message, 200);\n }\n\n static deleted(res: Response, message: string = 'Resource deleted'): Response {\n return this.success(res, null, message, 200);\n }\n\n static error(\n res: Response,\n error: string,\n statusCode: number = 400,\n code?: string,\n details?: Record<string, unknown>\n ): Response {\n const response: ErrorResponse = {\n success: false,\n error,\n code,\n ...(details && { details }),\n };\n return res.status(statusCode).json(response);\n }\n\n static badRequest(res: Response, error: string = 'Bad request', code?: string): Response {\n return this.error(res, error, 400, code);\n }\n\n static unauthorized(res: Response, error: string = 'Unauthorized', code?: string): Response {\n return this.error(res, error, 401, code);\n }\n\n static forbidden(res: Response, error: string = 'Forbidden', code?: string): Response {\n return this.error(res, error, 403, code);\n }\n\n static notFound(res: Response, error: string = 'Resource not found', code?: string): Response {\n return this.error(res, error, 404, code);\n }\n\n static conflict(res: Response, error: string = 'Conflict', code?: string): Response {\n return this.error(res, error, 409, code);\n }\n\n static validationError(res: Response, error: string, details?: Record<string, unknown>): Response {\n return this.error(res, error, 422, 'VALIDATION_ERROR', details);\n }\n\n static internalError(res: Response, error: string = 'Internal server error'): Response {\n return this.error(res, error, 500, 'INTERNAL_ERROR');\n }\n\n static paginated<T>(\n res: Response,\n data: T[],\n page: number,\n limit: number,\n total: number\n ): Response<PaginatedResponse<T>> {\n const totalPages = Math.ceil(total / limit);\n const response: PaginatedResponse<T> = {\n success: true,\n data,\n meta: {\n page,\n limit,\n total,\n totalPages,\n },\n };\n return res.status(200).json(response);\n }\n\n static noContent(res: Response): Response {\n return res.status(204).send();\n }\n}\n\ndeclare global {\n namespace Express {\n interface Response {\n success<T>(data?: T, message?: string, statusCode?: number): Response;\n created<T>(data?: T, message?: string): Response;\n updated<T>(data?: T, message?: string): Response;\n deleted(message?: string): Response;\n error(error: string, statusCode?: number, code?: string, details?: Record<string, unknown>): Response;\n badRequest(error?: string, code?: string): Response;\n unauthorized(error?: string, code?: string): Response;\n forbidden(error?: string, code?: string): Response;\n notFound(error?: string, code?: string): Response;\n conflict(error?: string, code?: string): Response;\n validationError(error: string, details?: Record<string, unknown>): Response;\n internalError(error?: string): Response;\n paginated<T>(data: T[], page: number, limit: number, total: number): Response;\n }\n }\n}\n\ntry {\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n const proto = require('express').response;\n if (proto) {\n proto.success = function <T>(this: Response, data?: T, message?: string, statusCode: number = 200) {\n return ResponseHelper.success(this, data, message, statusCode);\n };\n\n proto.created = function <T>(this: Response, data?: T, message?: string) {\n return ResponseHelper.created(this, data, message);\n };\n\n proto.updated = function <T>(this: Response, data?: T, message?: string) {\n return ResponseHelper.updated(this, data, message);\n };\n\n proto.deleted = function (this: Response, message?: string) {\n return ResponseHelper.deleted(this, message);\n };\n\n proto.error = function (this: Response, error: string, statusCode: number = 400, code?: string, details?: Record<string, unknown>) {\n return ResponseHelper.error(this, error, statusCode, code, details);\n };\n\n proto.badRequest = function (this: Response, error?: string, code?: string) {\n return ResponseHelper.badRequest(this, error, code);\n };\n\n proto.unauthorized = function (this: Response, error?: string, code?: string) {\n return ResponseHelper.unauthorized(this, error, code);\n };\n\n proto.forbidden = function (this: Response, error?: string, code?: string) {\n return ResponseHelper.forbidden(this, error, code);\n };\n\n proto.notFound = function (this: Response, error?: string, code?: string) {\n return ResponseHelper.notFound(this, error, code);\n };\n\n proto.conflict = function (this: Response, error?: string, code?: string) {\n return ResponseHelper.conflict(this, error, code);\n };\n\n proto.validationError = function (this: Response, error: string, details?: Record<string, unknown>) {\n return ResponseHelper.validationError(this, error, details);\n };\n\n proto.internalError = function (this: Response, error?: string) {\n return ResponseHelper.internalError(this, error);\n };\n\n proto.paginated = function <T>(this: Response, data: T[], page: number, limit: number, total: number) {\n return ResponseHelper.paginated(this, data, page, limit, total);\n };\n }\n} catch {\n // express not available at runtime\n}\n\nexport const response = ResponseHelper;\nexport default ResponseHelper;\n"]}
|
package/dist/upload/index.js
CHANGED
|
@@ -16,6 +16,7 @@ var envSchema = zod.z.object({
|
|
|
16
16
|
NODE_ENV: zod.z.enum(["development", "production", "test"]).default("development"),
|
|
17
17
|
PORT: zod.z.string().default("3000"),
|
|
18
18
|
DATABASE_URL: zod.z.string().optional(),
|
|
19
|
+
MONGODB_URL: zod.z.string().optional(),
|
|
19
20
|
REDIS_URL: zod.z.string().default("redis://localhost:6379"),
|
|
20
21
|
JWT_SECRET: zod.z.string().min(32).optional(),
|
|
21
22
|
JWT_EXPIRES_IN: zod.z.string().default("7d"),
|
package/dist/upload/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/config/index.ts","../../src/logger/index.ts","../../src/upload/index.ts"],"names":["z","pino","logger","config","S3Client","PutObjectCommand","DeleteObjectCommand","GetObjectCommand","getSignedUrl","ListObjectsV2Command"],"mappings":"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","file":"index.js","sourcesContent":["import { z } from 'zod';\n\nexport const envSchema = z.object({\n NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),\n PORT: z.string().default('3000'),\n DATABASE_URL: z.string().optional(),\n REDIS_URL: z.string().default('redis://localhost:6379'),\n JWT_SECRET: z.string().min(32).optional(),\n JWT_EXPIRES_IN: z.string().default('7d'),\n JWT_REFRESH_SECRET: z.string().min(32).optional(),\n JWT_REFRESH_EXPIRES_IN: z.string().default('30d'),\n GOOGLE_CLIENT_ID: z.string().optional(),\n GOOGLE_CLIENT_SECRET: z.string().optional(),\n GOOGLE_REDIRECT_URI: z.string().optional(),\n SMTP_HOST: z.string().optional(),\n SMTP_PORT: z.string().default('587'),\n SMTP_USER: z.string().optional(),\n SMTP_PASS: z.string().optional(),\n SMTP_FROM: z.string().optional(),\n TWILIO_ACCOUNT_SID: z.string().optional(),\n TWILIO_AUTH_TOKEN: z.string().optional(),\n TWILIO_PHONE_NUMBER: z.string().optional(),\n SLACK_WEBHOOK_URL: z.string().optional(),\n RATE_LIMIT_WINDOW: z.string().default('1m'),\n RATE_LIMIT_LIMIT: z.string().default('100'),\n LOG_LEVEL: z.enum(['fatal', 'error', 'warn', 'info', 'debug', 'trace']).default('info'),\n AWS_REGION: z.string().default('us-east-1'),\n AWS_ACCESS_KEY_ID: z.string().optional(),\n AWS_SECRET_ACCESS_KEY: z.string().optional(),\n AWS_S3_BUCKET: z.string().optional(),\n AWS_ENDPOINT: z.string().optional(),\n});\n\nexport type EnvConfig = z.infer<typeof envSchema>;\n\nexport interface ConfigOptions {\n schema?: z.ZodSchema;\n envPath?: string;\n validate?: boolean;\n}\n\nclass ConfigManager {\n private config: EnvConfig | null = null;\n private schema: z.ZodSchema;\n private validate: boolean;\n\n constructor(options: ConfigOptions = {}) {\n this.schema = options.schema || envSchema;\n this.validate = options.validate ?? true;\n }\n\n load(): EnvConfig {\n if (this.config) return this.config;\n\n const env: Record<string, string | undefined> = {};\n \n for (const key of Object.keys(this.schema.shape)) {\n env[key] = process.env[key];\n }\n\n if (this.validate) {\n const result = this.schema.safeParse(env);\n if (!result.success) {\n const errors = result.error.errors.map(e => `${e.path.join('.')}: ${e.message}`).join(', ');\n throw new Error(`Config validation failed: ${errors}`);\n }\n this.config = result.data;\n } else {\n this.config = env as EnvConfig;\n }\n\n return this.config;\n }\n\n get<K extends keyof EnvConfig>(key: K): EnvConfig[K] {\n if (!this.config) this.load();\n return this.config![key];\n }\n\n int(key: keyof EnvConfig): number {\n const value = this.get(key);\n if (typeof value === 'string') return parseInt(value, 10);\n return Number(value);\n }\n\n bool(key: keyof EnvConfig): boolean {\n const value = this.get(key);\n if (typeof value === 'boolean') return value;\n if (typeof value === 'string') return value.toLowerCase() === 'true';\n return Boolean(value);\n }\n\n isProduction(): boolean {\n return this.get('NODE_ENV') === 'production';\n }\n\n isDevelopment(): boolean {\n return this.get('NODE_ENV') === 'development';\n }\n\n isTest(): boolean {\n return this.get('NODE_ENV') === 'test';\n }\n\n getAll(): EnvConfig {\n if (!this.config) this.load();\n return this.config!;\n }\n}\n\nconst globalConfig = new ConfigManager();\n\nexport const config = {\n load: () => globalConfig.load(),\n get: <K extends keyof EnvConfig>(key: K) => globalConfig.get(key),\n int: (key: keyof EnvConfig) => globalConfig.int(key),\n bool: (key: keyof EnvConfig) => globalConfig.bool(key),\n isProduction: () => globalConfig.isProduction(),\n isDevelopment: () => globalConfig.isDevelopment(),\n isTest: () => globalConfig.isTest(),\n getAll: () => globalConfig.getAll(),\n create: (options?: ConfigOptions) => new ConfigManager(options),\n};\n\nexport default config;\n","import pino, { Logger, LoggerOptions, Bindings } from 'pino';\nimport { config } from '../config';\n\nexport type LogLevel = 'fatal' | 'error' | 'warn' | 'info' | 'debug' | 'trace';\n\nexport interface LoggerConfig extends Partial<LoggerOptions> {\n level?: LogLevel;\n name?: string;\n prettyPrint?: boolean;\n}\n\nexport interface RequestLoggerOptions {\n logLevel?: LogLevel;\n autoLogging?: boolean;\n}\n\nclass LoggerManager {\n private loggers: Map<string, Logger> = new Map();\n private defaultLogger: Logger;\n\n constructor() {\n const level = (config.get('LOG_LEVEL') as LogLevel) || 'info';\n this.defaultLogger = pino({\n level,\n name: 'saas-backend-kit',\n formatters: {\n bindings: (bindings: Bindings) => ({\n ...bindings,\n service: 'saas-backend-kit',\n }),\n },\n });\n }\n\n createLogger(options: LoggerConfig = {}): Logger {\n const name = options.name || 'default';\n \n if (this.loggers.has(name)) {\n return this.loggers.get(name)!;\n }\n\n const level = options.level || (config.get('LOG_LEVEL') as LogLevel) || 'info';\n \n const logger = pino({\n level,\n name: options.name,\n ...options,\n });\n\n this.loggers.set(name, logger);\n return logger;\n }\n\n getLogger(name?: string): Logger {\n if (name) {\n return this.loggers.get(name) || this.defaultLogger;\n }\n return this.defaultLogger;\n }\n\n child(bindings: Bindings, options?: { name?: string }): Logger {\n const name = options?.name || 'child';\n const parent = options?.name ? this.getLogger(name) : this.defaultLogger;\n return parent.child(bindings);\n }\n}\n\nconst loggerManager = new LoggerManager();\n\nexport const logger = {\n info: (message: string, ...args: unknown[]) => loggerManager.getLogger().info(message, ...args),\n warn: (message: string, ...args: unknown[]) => loggerManager.getLogger().warn(message, ...args),\n error: (message: string, ...args: unknown[]) => loggerManager.getLogger().error(message, ...args),\n debug: (message: string, ...args: unknown[]) => loggerManager.getLogger().debug(message, ...args),\n trace: (message: string, ...args: unknown[]) => loggerManager.getLogger().trace(message, ...args),\n fatal: (message: string, ...args: unknown[]) => loggerManager.getLogger().fatal(message, ...args),\n child: (bindings: Bindings, options?: { name?: string }) => loggerManager.child(bindings, options),\n create: (options?: LoggerConfig) => loggerManager.createLogger(options),\n get: (name?: string) => loggerManager.getLogger(name),\n};\n\nexport function createRequestLogger(options: RequestLoggerOptions = {}) {\n const logLevel = options.logLevel || 'info';\n const logger = loggerManager.getLogger('http');\n\n return function requestLogger(\n req: { method: string; url: string; headers: Record<string, string | string[] | undefined> },\n res: { statusCode: number; statusMessage?: string },\n elapsed: number\n ) {\n const log = logger.child({\n method: req.method,\n url: req.url,\n status: res.statusCode,\n responseTime: elapsed,\n ip: req.headers['x-forwarded-for'] || req.headers['x-real-ip'] || 'unknown',\n userAgent: req.headers['user-agent'],\n });\n\n if (res.statusCode >= 500) {\n log.error(`Request completed`);\n } else if (res.statusCode >= 400) {\n log.warn(`Request completed`);\n } else {\n log.info(`Request completed`);\n }\n };\n}\n\nexport default logger;\n","import { S3Client, PutObjectCommand, DeleteObjectCommand, GetObjectCommand, ListObjectsV2Command } from '@aws-sdk/client-s3';\nimport { getSignedUrl } from '@aws-sdk/s3-request-presigner';\nimport { config } from '../config';\nimport { logger } from '../logger';\n\nexport interface S3Config {\n region?: string;\n accessKeyId?: string;\n secretAccessKey?: string;\n bucket: string;\n endpoint?: string;\n forcePathStyle?: boolean;\n}\n\nexport interface UploadOptions {\n key?: string;\n contentType?: string;\n expiresIn?: number;\n metadata?: Record<string, string>;\n}\n\nexport interface UploadResult {\n key: string;\n url: string;\n bucket: string;\n contentType?: string;\n size?: number;\n}\n\nexport interface SignedUrlOptions {\n expiresIn?: number;\n}\n\nexport interface FileObject {\n key: string;\n lastModified?: Date;\n size?: number;\n contentType?: string;\n}\n\nclass S3Service {\n private client: S3Client | null = null;\n private bucket: string;\n private initialized: boolean = false;\n\n constructor() {\n this.bucket = '';\n }\n\n initialize(config: S3Config): void {\n this.client = new S3Client({\n region: config.region || 'us-east-1',\n credentials: config.accessKeyId && config.secretAccessKey\n ? {\n accessKeyId: config.accessKeyId,\n secretAccessKey: config.secretAccessKey,\n }\n : undefined,\n endpoint: config.endpoint,\n forcePathStyle: config.forcePathStyle || false,\n });\n\n this.bucket = config.bucket;\n this.initialized = true;\n logger.info('S3 service initialized', { bucket: this.bucket });\n }\n\n isInitialized(): boolean {\n return this.initialized;\n }\n\n private ensureInitialized(): void {\n if (!this.initialized) {\n const region = config.get('AWS_REGION') || 'us-east-1';\n const bucket = config.get('AWS_S3_BUCKET') || '';\n \n this.initialize({\n region,\n accessKeyId: config.get('AWS_ACCESS_KEY_ID'),\n secretAccessKey: config.get('AWS_SECRET_ACCESS_KEY'),\n bucket,\n endpoint: config.get('AWS_ENDPOINT'),\n });\n }\n }\n\n async upload(\n file: Buffer | Uint8Array | string,\n options: UploadOptions = {}\n ): Promise<UploadResult> {\n this.ensureInitialized();\n\n const key = options.key || this.generateKey();\n const contentType = options.contentType || this.guessContentType(key);\n\n const command = new PutObjectCommand({\n Bucket: this.bucket,\n Key: key,\n Body: file,\n ContentType: contentType,\n Metadata: options.metadata,\n });\n\n await this.client!.send(command);\n\n const url = await this.getSignedUrl(key, { expiresIn: options.expiresIn || 3600 });\n\n logger.info('File uploaded to S3', { key, bucket: this.bucket, contentType });\n\n return {\n key,\n url,\n bucket: this.bucket,\n contentType,\n };\n }\n\n async uploadImage(\n file: Buffer | Uint8Array | string,\n filename: string,\n options: UploadOptions = {}\n ): Promise<UploadResult> {\n const key = options.key || `images/${Date.now()}-${filename}`;\n \n return this.upload(file, {\n ...options,\n key,\n contentType: options.contentType || this.getImageContentType(filename),\n });\n }\n\n async uploadVideo(\n file: Buffer | Uint8Array | string,\n filename: string,\n options: UploadOptions = {}\n ): Promise<UploadResult> {\n const key = options.key || `videos/${Date.now()}-${filename}`;\n \n return this.upload(file, {\n ...options,\n key,\n contentType: options.contentType || this.getVideoContentType(filename),\n });\n }\n\n async delete(key: string): Promise<void> {\n this.ensureInitialized();\n\n const command = new DeleteObjectCommand({\n Bucket: this.bucket,\n Key: key,\n });\n\n await this.client!.send(command);\n logger.info('File deleted from S3', { key, bucket: this.bucket });\n }\n\n async getSignedUrl(key: string, options: SignedUrlOptions = {}): Promise<string> {\n this.ensureInitialized();\n\n const command = new GetObjectCommand({\n Bucket: this.bucket,\n Key: key,\n });\n\n return getSignedUrl(this.client!, command, {\n expiresIn: options.expiresIn || 3600,\n });\n }\n\n async getPublicUrl(key: string): Promise<string> {\n return `https://${this.bucket}.s3.${config.get('AWS_REGION') || 'us-east-1'}.amazonaws.com/${key}`;\n }\n\n async listFiles(prefix?: string, maxKeys: number = 1000): Promise<FileObject[]> {\n this.ensureInitialized();\n\n const command = new ListObjectsV2Command({\n Bucket: this.bucket,\n Prefix: prefix,\n MaxKeys: maxKeys,\n });\n\n const response = await this.client!.send(command);\n \n return (response.Contents || []).map((item) => ({\n key: item.Key || '',\n lastModified: item.LastModified,\n size: item.Size,\n }));\n }\n\n private generateKey(): string {\n const timestamp = Date.now();\n const random = Math.random().toString(36).substring(2, 15);\n return `uploads/${timestamp}-${random}`;\n }\n\n private guessContentType(key: string): string {\n const ext = key.split('.').pop()?.toLowerCase();\n \n const contentTypes: Record<string, string> = {\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n png: 'image/png',\n gif: 'image/gif',\n webp: 'image/webp',\n svg: 'image/svg+xml',\n mp4: 'video/mp4',\n webm: 'video/webm',\n mov: 'video/quicktime',\n avi: 'video/x-msvideo',\n pdf: 'application/pdf',\n json: 'application/json',\n txt: 'text/plain',\n };\n\n return contentTypes[ext || ''] || 'application/octet-stream';\n }\n\n private getImageContentType(filename: string): string {\n const ext = filename.split('.').pop()?.toLowerCase();\n const imageTypes: Record<string, string> = {\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n png: 'image/png',\n gif: 'image/gif',\n webp: 'image/webp',\n svg: 'image/svg+xml',\n };\n return imageTypes[ext || ''] || 'image/jpeg';\n }\n\n private getVideoContentType(filename: string): string {\n const ext = filename.split('.').pop()?.toLowerCase();\n const videoTypes: Record<string, string> = {\n mp4: 'video/mp4',\n webm: 'video/webm',\n mov: 'video/quicktime',\n avi: 'video/x-msvideo',\n mkv: 'video/x-matroska',\n ogv: 'video/ogg',\n };\n return videoTypes[ext || ''] || 'video/mp4';\n }\n}\n\nexport const s3Service = new S3Service();\n\nexport const upload = {\n initialize: (config: S3Config) => s3Service.initialize(config),\n \n file: (file: Buffer | Uint8Array | string, options?: UploadOptions) => \n s3Service.upload(file, options),\n \n image: (file: Buffer | Uint8Array | string, filename: string, options?: UploadOptions) =>\n s3Service.uploadImage(file, filename, options),\n \n video: (file: Buffer | Uint8Array | string, filename: string, options?: UploadOptions) =>\n s3Service.uploadVideo(file, filename, options),\n \n delete: (key: string) => s3Service.delete(key),\n getSignedUrl: (key: string, options?: SignedUrlOptions) => s3Service.getSignedUrl(key, options),\n getPublicUrl: (key: string) => s3Service.getPublicUrl(key),\n listFiles: (prefix?: string, maxKeys?: number) => s3Service.listFiles(prefix, maxKeys),\n};\n\nexport default upload;\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/config/index.ts","../../src/logger/index.ts","../../src/upload/index.ts"],"names":["z","pino","logger","config","S3Client","PutObjectCommand","DeleteObjectCommand","GetObjectCommand","getSignedUrl","ListObjectsV2Command"],"mappings":"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","file":"index.js","sourcesContent":["import { z } from 'zod';\n\nexport const envSchema = z.object({\n NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),\n PORT: z.string().default('3000'),\n DATABASE_URL: z.string().optional(),\n MONGODB_URL: z.string().optional(),\n REDIS_URL: z.string().default('redis://localhost:6379'),\n JWT_SECRET: z.string().min(32).optional(),\n JWT_EXPIRES_IN: z.string().default('7d'),\n JWT_REFRESH_SECRET: z.string().min(32).optional(),\n JWT_REFRESH_EXPIRES_IN: z.string().default('30d'),\n GOOGLE_CLIENT_ID: z.string().optional(),\n GOOGLE_CLIENT_SECRET: z.string().optional(),\n GOOGLE_REDIRECT_URI: z.string().optional(),\n SMTP_HOST: z.string().optional(),\n SMTP_PORT: z.string().default('587'),\n SMTP_USER: z.string().optional(),\n SMTP_PASS: z.string().optional(),\n SMTP_FROM: z.string().optional(),\n TWILIO_ACCOUNT_SID: z.string().optional(),\n TWILIO_AUTH_TOKEN: z.string().optional(),\n TWILIO_PHONE_NUMBER: z.string().optional(),\n SLACK_WEBHOOK_URL: z.string().optional(),\n RATE_LIMIT_WINDOW: z.string().default('1m'),\n RATE_LIMIT_LIMIT: z.string().default('100'),\n LOG_LEVEL: z.enum(['fatal', 'error', 'warn', 'info', 'debug', 'trace']).default('info'),\n AWS_REGION: z.string().default('us-east-1'),\n AWS_ACCESS_KEY_ID: z.string().optional(),\n AWS_SECRET_ACCESS_KEY: z.string().optional(),\n AWS_S3_BUCKET: z.string().optional(),\n AWS_ENDPOINT: z.string().optional(),\n});\n\nexport type EnvConfig = z.infer<typeof envSchema>;\n\nexport interface ConfigOptions {\n schema?: z.ZodSchema;\n envPath?: string;\n validate?: boolean;\n}\n\nclass ConfigManager {\n private config: EnvConfig | null = null;\n private schema: z.ZodSchema;\n private validate: boolean;\n\n constructor(options: ConfigOptions = {}) {\n this.schema = options.schema || envSchema;\n this.validate = options.validate ?? true;\n }\n\n load(): EnvConfig {\n if (this.config) return this.config;\n\n const env: Record<string, string | undefined> = {};\n \n for (const key of Object.keys(this.schema.shape)) {\n env[key] = process.env[key];\n }\n\n if (this.validate) {\n const result = this.schema.safeParse(env);\n if (!result.success) {\n const errors = result.error.errors.map(e => `${e.path.join('.')}: ${e.message}`).join(', ');\n throw new Error(`Config validation failed: ${errors}`);\n }\n this.config = result.data;\n } else {\n this.config = env as EnvConfig;\n }\n\n return this.config;\n }\n\n get<K extends keyof EnvConfig>(key: K): EnvConfig[K] {\n if (!this.config) this.load();\n return this.config![key];\n }\n\n int(key: keyof EnvConfig): number {\n const value = this.get(key);\n if (typeof value === 'string') return parseInt(value, 10);\n return Number(value);\n }\n\n bool(key: keyof EnvConfig): boolean {\n const value = this.get(key);\n if (typeof value === 'boolean') return value;\n if (typeof value === 'string') return value.toLowerCase() === 'true';\n return Boolean(value);\n }\n\n isProduction(): boolean {\n return this.get('NODE_ENV') === 'production';\n }\n\n isDevelopment(): boolean {\n return this.get('NODE_ENV') === 'development';\n }\n\n isTest(): boolean {\n return this.get('NODE_ENV') === 'test';\n }\n\n getAll(): EnvConfig {\n if (!this.config) this.load();\n return this.config!;\n }\n}\n\nconst globalConfig = new ConfigManager();\n\nexport const config = {\n load: () => globalConfig.load(),\n get: <K extends keyof EnvConfig>(key: K) => globalConfig.get(key),\n int: (key: keyof EnvConfig) => globalConfig.int(key),\n bool: (key: keyof EnvConfig) => globalConfig.bool(key),\n isProduction: () => globalConfig.isProduction(),\n isDevelopment: () => globalConfig.isDevelopment(),\n isTest: () => globalConfig.isTest(),\n getAll: () => globalConfig.getAll(),\n create: (options?: ConfigOptions) => new ConfigManager(options),\n};\n\nexport default config;\n","import pino, { Logger, LoggerOptions, Bindings } from 'pino';\nimport { config } from '../config';\n\nexport type LogLevel = 'fatal' | 'error' | 'warn' | 'info' | 'debug' | 'trace';\n\nexport interface LoggerConfig extends Partial<LoggerOptions> {\n level?: LogLevel;\n name?: string;\n prettyPrint?: boolean;\n}\n\nexport interface RequestLoggerOptions {\n logLevel?: LogLevel;\n autoLogging?: boolean;\n}\n\nclass LoggerManager {\n private loggers: Map<string, Logger> = new Map();\n private defaultLogger: Logger;\n\n constructor() {\n const level = (config.get('LOG_LEVEL') as LogLevel) || 'info';\n this.defaultLogger = pino({\n level,\n name: 'saas-backend-kit',\n formatters: {\n bindings: (bindings: Bindings) => ({\n ...bindings,\n service: 'saas-backend-kit',\n }),\n },\n });\n }\n\n createLogger(options: LoggerConfig = {}): Logger {\n const name = options.name || 'default';\n \n if (this.loggers.has(name)) {\n return this.loggers.get(name)!;\n }\n\n const level = options.level || (config.get('LOG_LEVEL') as LogLevel) || 'info';\n \n const logger = pino({\n level,\n name: options.name,\n ...options,\n });\n\n this.loggers.set(name, logger);\n return logger;\n }\n\n getLogger(name?: string): Logger {\n if (name) {\n return this.loggers.get(name) || this.defaultLogger;\n }\n return this.defaultLogger;\n }\n\n child(bindings: Bindings, options?: { name?: string }): Logger {\n const name = options?.name || 'child';\n const parent = options?.name ? this.getLogger(name) : this.defaultLogger;\n return parent.child(bindings);\n }\n}\n\nconst loggerManager = new LoggerManager();\n\nexport const logger = {\n info: (message: string, ...args: unknown[]) => loggerManager.getLogger().info(message, ...args),\n warn: (message: string, ...args: unknown[]) => loggerManager.getLogger().warn(message, ...args),\n error: (message: string, ...args: unknown[]) => loggerManager.getLogger().error(message, ...args),\n debug: (message: string, ...args: unknown[]) => loggerManager.getLogger().debug(message, ...args),\n trace: (message: string, ...args: unknown[]) => loggerManager.getLogger().trace(message, ...args),\n fatal: (message: string, ...args: unknown[]) => loggerManager.getLogger().fatal(message, ...args),\n child: (bindings: Bindings, options?: { name?: string }) => loggerManager.child(bindings, options),\n create: (options?: LoggerConfig) => loggerManager.createLogger(options),\n get: (name?: string) => loggerManager.getLogger(name),\n};\n\nexport function createRequestLogger(options: RequestLoggerOptions = {}) {\n const logLevel = options.logLevel || 'info';\n const logger = loggerManager.getLogger('http');\n\n return function requestLogger(\n req: { method: string; url: string; headers: Record<string, string | string[] | undefined> },\n res: { statusCode: number; statusMessage?: string },\n elapsed: number\n ) {\n const log = logger.child({\n method: req.method,\n url: req.url,\n status: res.statusCode,\n responseTime: elapsed,\n ip: req.headers['x-forwarded-for'] || req.headers['x-real-ip'] || 'unknown',\n userAgent: req.headers['user-agent'],\n });\n\n if (res.statusCode >= 500) {\n log.error(`Request completed`);\n } else if (res.statusCode >= 400) {\n log.warn(`Request completed`);\n } else {\n log.info(`Request completed`);\n }\n };\n}\n\nexport default logger;\n","import { S3Client, PutObjectCommand, DeleteObjectCommand, GetObjectCommand, ListObjectsV2Command } from '@aws-sdk/client-s3';\nimport { getSignedUrl } from '@aws-sdk/s3-request-presigner';\nimport { config } from '../config';\nimport { logger } from '../logger';\n\nexport interface S3Config {\n region?: string;\n accessKeyId?: string;\n secretAccessKey?: string;\n bucket: string;\n endpoint?: string;\n forcePathStyle?: boolean;\n}\n\nexport interface UploadOptions {\n key?: string;\n contentType?: string;\n expiresIn?: number;\n metadata?: Record<string, string>;\n}\n\nexport interface UploadResult {\n key: string;\n url: string;\n bucket: string;\n contentType?: string;\n size?: number;\n}\n\nexport interface SignedUrlOptions {\n expiresIn?: number;\n}\n\nexport interface FileObject {\n key: string;\n lastModified?: Date;\n size?: number;\n contentType?: string;\n}\n\nclass S3Service {\n private client: S3Client | null = null;\n private bucket: string;\n private initialized: boolean = false;\n\n constructor() {\n this.bucket = '';\n }\n\n initialize(config: S3Config): void {\n this.client = new S3Client({\n region: config.region || 'us-east-1',\n credentials: config.accessKeyId && config.secretAccessKey\n ? {\n accessKeyId: config.accessKeyId,\n secretAccessKey: config.secretAccessKey,\n }\n : undefined,\n endpoint: config.endpoint,\n forcePathStyle: config.forcePathStyle || false,\n });\n\n this.bucket = config.bucket;\n this.initialized = true;\n logger.info('S3 service initialized', { bucket: this.bucket });\n }\n\n isInitialized(): boolean {\n return this.initialized;\n }\n\n private ensureInitialized(): void {\n if (!this.initialized) {\n const region = config.get('AWS_REGION') || 'us-east-1';\n const bucket = config.get('AWS_S3_BUCKET') || '';\n \n this.initialize({\n region,\n accessKeyId: config.get('AWS_ACCESS_KEY_ID'),\n secretAccessKey: config.get('AWS_SECRET_ACCESS_KEY'),\n bucket,\n endpoint: config.get('AWS_ENDPOINT'),\n });\n }\n }\n\n async upload(\n file: Buffer | Uint8Array | string,\n options: UploadOptions = {}\n ): Promise<UploadResult> {\n this.ensureInitialized();\n\n const key = options.key || this.generateKey();\n const contentType = options.contentType || this.guessContentType(key);\n\n const command = new PutObjectCommand({\n Bucket: this.bucket,\n Key: key,\n Body: file,\n ContentType: contentType,\n Metadata: options.metadata,\n });\n\n await this.client!.send(command);\n\n const url = await this.getSignedUrl(key, { expiresIn: options.expiresIn || 3600 });\n\n logger.info('File uploaded to S3', { key, bucket: this.bucket, contentType });\n\n return {\n key,\n url,\n bucket: this.bucket,\n contentType,\n };\n }\n\n async uploadImage(\n file: Buffer | Uint8Array | string,\n filename: string,\n options: UploadOptions = {}\n ): Promise<UploadResult> {\n const key = options.key || `images/${Date.now()}-${filename}`;\n \n return this.upload(file, {\n ...options,\n key,\n contentType: options.contentType || this.getImageContentType(filename),\n });\n }\n\n async uploadVideo(\n file: Buffer | Uint8Array | string,\n filename: string,\n options: UploadOptions = {}\n ): Promise<UploadResult> {\n const key = options.key || `videos/${Date.now()}-${filename}`;\n \n return this.upload(file, {\n ...options,\n key,\n contentType: options.contentType || this.getVideoContentType(filename),\n });\n }\n\n async delete(key: string): Promise<void> {\n this.ensureInitialized();\n\n const command = new DeleteObjectCommand({\n Bucket: this.bucket,\n Key: key,\n });\n\n await this.client!.send(command);\n logger.info('File deleted from S3', { key, bucket: this.bucket });\n }\n\n async getSignedUrl(key: string, options: SignedUrlOptions = {}): Promise<string> {\n this.ensureInitialized();\n\n const command = new GetObjectCommand({\n Bucket: this.bucket,\n Key: key,\n });\n\n return getSignedUrl(this.client!, command, {\n expiresIn: options.expiresIn || 3600,\n });\n }\n\n async getPublicUrl(key: string): Promise<string> {\n return `https://${this.bucket}.s3.${config.get('AWS_REGION') || 'us-east-1'}.amazonaws.com/${key}`;\n }\n\n async listFiles(prefix?: string, maxKeys: number = 1000): Promise<FileObject[]> {\n this.ensureInitialized();\n\n const command = new ListObjectsV2Command({\n Bucket: this.bucket,\n Prefix: prefix,\n MaxKeys: maxKeys,\n });\n\n const response = await this.client!.send(command);\n \n return (response.Contents || []).map((item) => ({\n key: item.Key || '',\n lastModified: item.LastModified,\n size: item.Size,\n }));\n }\n\n private generateKey(): string {\n const timestamp = Date.now();\n const random = Math.random().toString(36).substring(2, 15);\n return `uploads/${timestamp}-${random}`;\n }\n\n private guessContentType(key: string): string {\n const ext = key.split('.').pop()?.toLowerCase();\n \n const contentTypes: Record<string, string> = {\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n png: 'image/png',\n gif: 'image/gif',\n webp: 'image/webp',\n svg: 'image/svg+xml',\n mp4: 'video/mp4',\n webm: 'video/webm',\n mov: 'video/quicktime',\n avi: 'video/x-msvideo',\n pdf: 'application/pdf',\n json: 'application/json',\n txt: 'text/plain',\n };\n\n return contentTypes[ext || ''] || 'application/octet-stream';\n }\n\n private getImageContentType(filename: string): string {\n const ext = filename.split('.').pop()?.toLowerCase();\n const imageTypes: Record<string, string> = {\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n png: 'image/png',\n gif: 'image/gif',\n webp: 'image/webp',\n svg: 'image/svg+xml',\n };\n return imageTypes[ext || ''] || 'image/jpeg';\n }\n\n private getVideoContentType(filename: string): string {\n const ext = filename.split('.').pop()?.toLowerCase();\n const videoTypes: Record<string, string> = {\n mp4: 'video/mp4',\n webm: 'video/webm',\n mov: 'video/quicktime',\n avi: 'video/x-msvideo',\n mkv: 'video/x-matroska',\n ogv: 'video/ogg',\n };\n return videoTypes[ext || ''] || 'video/mp4';\n }\n}\n\nexport const s3Service = new S3Service();\n\nexport const upload = {\n initialize: (config: S3Config) => s3Service.initialize(config),\n \n file: (file: Buffer | Uint8Array | string, options?: UploadOptions) => \n s3Service.upload(file, options),\n \n image: (file: Buffer | Uint8Array | string, filename: string, options?: UploadOptions) =>\n s3Service.uploadImage(file, filename, options),\n \n video: (file: Buffer | Uint8Array | string, filename: string, options?: UploadOptions) =>\n s3Service.uploadVideo(file, filename, options),\n \n delete: (key: string) => s3Service.delete(key),\n getSignedUrl: (key: string, options?: SignedUrlOptions) => s3Service.getSignedUrl(key, options),\n getPublicUrl: (key: string) => s3Service.getPublicUrl(key),\n listFiles: (prefix?: string, maxKeys?: number) => s3Service.listFiles(prefix, maxKeys),\n};\n\nexport default upload;\n"]}
|
package/dist/upload/index.mjs
CHANGED
|
@@ -8,6 +8,7 @@ var envSchema = z.object({
|
|
|
8
8
|
NODE_ENV: z.enum(["development", "production", "test"]).default("development"),
|
|
9
9
|
PORT: z.string().default("3000"),
|
|
10
10
|
DATABASE_URL: z.string().optional(),
|
|
11
|
+
MONGODB_URL: z.string().optional(),
|
|
11
12
|
REDIS_URL: z.string().default("redis://localhost:6379"),
|
|
12
13
|
JWT_SECRET: z.string().min(32).optional(),
|
|
13
14
|
JWT_EXPIRES_IN: z.string().default("7d"),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/config/index.ts","../../src/logger/index.ts","../../src/upload/index.ts"],"names":["logger","config"],"mappings":"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","file":"index.mjs","sourcesContent":["import { z } from 'zod';\n\nexport const envSchema = z.object({\n NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),\n PORT: z.string().default('3000'),\n DATABASE_URL: z.string().optional(),\n REDIS_URL: z.string().default('redis://localhost:6379'),\n JWT_SECRET: z.string().min(32).optional(),\n JWT_EXPIRES_IN: z.string().default('7d'),\n JWT_REFRESH_SECRET: z.string().min(32).optional(),\n JWT_REFRESH_EXPIRES_IN: z.string().default('30d'),\n GOOGLE_CLIENT_ID: z.string().optional(),\n GOOGLE_CLIENT_SECRET: z.string().optional(),\n GOOGLE_REDIRECT_URI: z.string().optional(),\n SMTP_HOST: z.string().optional(),\n SMTP_PORT: z.string().default('587'),\n SMTP_USER: z.string().optional(),\n SMTP_PASS: z.string().optional(),\n SMTP_FROM: z.string().optional(),\n TWILIO_ACCOUNT_SID: z.string().optional(),\n TWILIO_AUTH_TOKEN: z.string().optional(),\n TWILIO_PHONE_NUMBER: z.string().optional(),\n SLACK_WEBHOOK_URL: z.string().optional(),\n RATE_LIMIT_WINDOW: z.string().default('1m'),\n RATE_LIMIT_LIMIT: z.string().default('100'),\n LOG_LEVEL: z.enum(['fatal', 'error', 'warn', 'info', 'debug', 'trace']).default('info'),\n AWS_REGION: z.string().default('us-east-1'),\n AWS_ACCESS_KEY_ID: z.string().optional(),\n AWS_SECRET_ACCESS_KEY: z.string().optional(),\n AWS_S3_BUCKET: z.string().optional(),\n AWS_ENDPOINT: z.string().optional(),\n});\n\nexport type EnvConfig = z.infer<typeof envSchema>;\n\nexport interface ConfigOptions {\n schema?: z.ZodSchema;\n envPath?: string;\n validate?: boolean;\n}\n\nclass ConfigManager {\n private config: EnvConfig | null = null;\n private schema: z.ZodSchema;\n private validate: boolean;\n\n constructor(options: ConfigOptions = {}) {\n this.schema = options.schema || envSchema;\n this.validate = options.validate ?? true;\n }\n\n load(): EnvConfig {\n if (this.config) return this.config;\n\n const env: Record<string, string | undefined> = {};\n \n for (const key of Object.keys(this.schema.shape)) {\n env[key] = process.env[key];\n }\n\n if (this.validate) {\n const result = this.schema.safeParse(env);\n if (!result.success) {\n const errors = result.error.errors.map(e => `${e.path.join('.')}: ${e.message}`).join(', ');\n throw new Error(`Config validation failed: ${errors}`);\n }\n this.config = result.data;\n } else {\n this.config = env as EnvConfig;\n }\n\n return this.config;\n }\n\n get<K extends keyof EnvConfig>(key: K): EnvConfig[K] {\n if (!this.config) this.load();\n return this.config![key];\n }\n\n int(key: keyof EnvConfig): number {\n const value = this.get(key);\n if (typeof value === 'string') return parseInt(value, 10);\n return Number(value);\n }\n\n bool(key: keyof EnvConfig): boolean {\n const value = this.get(key);\n if (typeof value === 'boolean') return value;\n if (typeof value === 'string') return value.toLowerCase() === 'true';\n return Boolean(value);\n }\n\n isProduction(): boolean {\n return this.get('NODE_ENV') === 'production';\n }\n\n isDevelopment(): boolean {\n return this.get('NODE_ENV') === 'development';\n }\n\n isTest(): boolean {\n return this.get('NODE_ENV') === 'test';\n }\n\n getAll(): EnvConfig {\n if (!this.config) this.load();\n return this.config!;\n }\n}\n\nconst globalConfig = new ConfigManager();\n\nexport const config = {\n load: () => globalConfig.load(),\n get: <K extends keyof EnvConfig>(key: K) => globalConfig.get(key),\n int: (key: keyof EnvConfig) => globalConfig.int(key),\n bool: (key: keyof EnvConfig) => globalConfig.bool(key),\n isProduction: () => globalConfig.isProduction(),\n isDevelopment: () => globalConfig.isDevelopment(),\n isTest: () => globalConfig.isTest(),\n getAll: () => globalConfig.getAll(),\n create: (options?: ConfigOptions) => new ConfigManager(options),\n};\n\nexport default config;\n","import pino, { Logger, LoggerOptions, Bindings } from 'pino';\nimport { config } from '../config';\n\nexport type LogLevel = 'fatal' | 'error' | 'warn' | 'info' | 'debug' | 'trace';\n\nexport interface LoggerConfig extends Partial<LoggerOptions> {\n level?: LogLevel;\n name?: string;\n prettyPrint?: boolean;\n}\n\nexport interface RequestLoggerOptions {\n logLevel?: LogLevel;\n autoLogging?: boolean;\n}\n\nclass LoggerManager {\n private loggers: Map<string, Logger> = new Map();\n private defaultLogger: Logger;\n\n constructor() {\n const level = (config.get('LOG_LEVEL') as LogLevel) || 'info';\n this.defaultLogger = pino({\n level,\n name: 'saas-backend-kit',\n formatters: {\n bindings: (bindings: Bindings) => ({\n ...bindings,\n service: 'saas-backend-kit',\n }),\n },\n });\n }\n\n createLogger(options: LoggerConfig = {}): Logger {\n const name = options.name || 'default';\n \n if (this.loggers.has(name)) {\n return this.loggers.get(name)!;\n }\n\n const level = options.level || (config.get('LOG_LEVEL') as LogLevel) || 'info';\n \n const logger = pino({\n level,\n name: options.name,\n ...options,\n });\n\n this.loggers.set(name, logger);\n return logger;\n }\n\n getLogger(name?: string): Logger {\n if (name) {\n return this.loggers.get(name) || this.defaultLogger;\n }\n return this.defaultLogger;\n }\n\n child(bindings: Bindings, options?: { name?: string }): Logger {\n const name = options?.name || 'child';\n const parent = options?.name ? this.getLogger(name) : this.defaultLogger;\n return parent.child(bindings);\n }\n}\n\nconst loggerManager = new LoggerManager();\n\nexport const logger = {\n info: (message: string, ...args: unknown[]) => loggerManager.getLogger().info(message, ...args),\n warn: (message: string, ...args: unknown[]) => loggerManager.getLogger().warn(message, ...args),\n error: (message: string, ...args: unknown[]) => loggerManager.getLogger().error(message, ...args),\n debug: (message: string, ...args: unknown[]) => loggerManager.getLogger().debug(message, ...args),\n trace: (message: string, ...args: unknown[]) => loggerManager.getLogger().trace(message, ...args),\n fatal: (message: string, ...args: unknown[]) => loggerManager.getLogger().fatal(message, ...args),\n child: (bindings: Bindings, options?: { name?: string }) => loggerManager.child(bindings, options),\n create: (options?: LoggerConfig) => loggerManager.createLogger(options),\n get: (name?: string) => loggerManager.getLogger(name),\n};\n\nexport function createRequestLogger(options: RequestLoggerOptions = {}) {\n const logLevel = options.logLevel || 'info';\n const logger = loggerManager.getLogger('http');\n\n return function requestLogger(\n req: { method: string; url: string; headers: Record<string, string | string[] | undefined> },\n res: { statusCode: number; statusMessage?: string },\n elapsed: number\n ) {\n const log = logger.child({\n method: req.method,\n url: req.url,\n status: res.statusCode,\n responseTime: elapsed,\n ip: req.headers['x-forwarded-for'] || req.headers['x-real-ip'] || 'unknown',\n userAgent: req.headers['user-agent'],\n });\n\n if (res.statusCode >= 500) {\n log.error(`Request completed`);\n } else if (res.statusCode >= 400) {\n log.warn(`Request completed`);\n } else {\n log.info(`Request completed`);\n }\n };\n}\n\nexport default logger;\n","import { S3Client, PutObjectCommand, DeleteObjectCommand, GetObjectCommand, ListObjectsV2Command } from '@aws-sdk/client-s3';\nimport { getSignedUrl } from '@aws-sdk/s3-request-presigner';\nimport { config } from '../config';\nimport { logger } from '../logger';\n\nexport interface S3Config {\n region?: string;\n accessKeyId?: string;\n secretAccessKey?: string;\n bucket: string;\n endpoint?: string;\n forcePathStyle?: boolean;\n}\n\nexport interface UploadOptions {\n key?: string;\n contentType?: string;\n expiresIn?: number;\n metadata?: Record<string, string>;\n}\n\nexport interface UploadResult {\n key: string;\n url: string;\n bucket: string;\n contentType?: string;\n size?: number;\n}\n\nexport interface SignedUrlOptions {\n expiresIn?: number;\n}\n\nexport interface FileObject {\n key: string;\n lastModified?: Date;\n size?: number;\n contentType?: string;\n}\n\nclass S3Service {\n private client: S3Client | null = null;\n private bucket: string;\n private initialized: boolean = false;\n\n constructor() {\n this.bucket = '';\n }\n\n initialize(config: S3Config): void {\n this.client = new S3Client({\n region: config.region || 'us-east-1',\n credentials: config.accessKeyId && config.secretAccessKey\n ? {\n accessKeyId: config.accessKeyId,\n secretAccessKey: config.secretAccessKey,\n }\n : undefined,\n endpoint: config.endpoint,\n forcePathStyle: config.forcePathStyle || false,\n });\n\n this.bucket = config.bucket;\n this.initialized = true;\n logger.info('S3 service initialized', { bucket: this.bucket });\n }\n\n isInitialized(): boolean {\n return this.initialized;\n }\n\n private ensureInitialized(): void {\n if (!this.initialized) {\n const region = config.get('AWS_REGION') || 'us-east-1';\n const bucket = config.get('AWS_S3_BUCKET') || '';\n \n this.initialize({\n region,\n accessKeyId: config.get('AWS_ACCESS_KEY_ID'),\n secretAccessKey: config.get('AWS_SECRET_ACCESS_KEY'),\n bucket,\n endpoint: config.get('AWS_ENDPOINT'),\n });\n }\n }\n\n async upload(\n file: Buffer | Uint8Array | string,\n options: UploadOptions = {}\n ): Promise<UploadResult> {\n this.ensureInitialized();\n\n const key = options.key || this.generateKey();\n const contentType = options.contentType || this.guessContentType(key);\n\n const command = new PutObjectCommand({\n Bucket: this.bucket,\n Key: key,\n Body: file,\n ContentType: contentType,\n Metadata: options.metadata,\n });\n\n await this.client!.send(command);\n\n const url = await this.getSignedUrl(key, { expiresIn: options.expiresIn || 3600 });\n\n logger.info('File uploaded to S3', { key, bucket: this.bucket, contentType });\n\n return {\n key,\n url,\n bucket: this.bucket,\n contentType,\n };\n }\n\n async uploadImage(\n file: Buffer | Uint8Array | string,\n filename: string,\n options: UploadOptions = {}\n ): Promise<UploadResult> {\n const key = options.key || `images/${Date.now()}-${filename}`;\n \n return this.upload(file, {\n ...options,\n key,\n contentType: options.contentType || this.getImageContentType(filename),\n });\n }\n\n async uploadVideo(\n file: Buffer | Uint8Array | string,\n filename: string,\n options: UploadOptions = {}\n ): Promise<UploadResult> {\n const key = options.key || `videos/${Date.now()}-${filename}`;\n \n return this.upload(file, {\n ...options,\n key,\n contentType: options.contentType || this.getVideoContentType(filename),\n });\n }\n\n async delete(key: string): Promise<void> {\n this.ensureInitialized();\n\n const command = new DeleteObjectCommand({\n Bucket: this.bucket,\n Key: key,\n });\n\n await this.client!.send(command);\n logger.info('File deleted from S3', { key, bucket: this.bucket });\n }\n\n async getSignedUrl(key: string, options: SignedUrlOptions = {}): Promise<string> {\n this.ensureInitialized();\n\n const command = new GetObjectCommand({\n Bucket: this.bucket,\n Key: key,\n });\n\n return getSignedUrl(this.client!, command, {\n expiresIn: options.expiresIn || 3600,\n });\n }\n\n async getPublicUrl(key: string): Promise<string> {\n return `https://${this.bucket}.s3.${config.get('AWS_REGION') || 'us-east-1'}.amazonaws.com/${key}`;\n }\n\n async listFiles(prefix?: string, maxKeys: number = 1000): Promise<FileObject[]> {\n this.ensureInitialized();\n\n const command = new ListObjectsV2Command({\n Bucket: this.bucket,\n Prefix: prefix,\n MaxKeys: maxKeys,\n });\n\n const response = await this.client!.send(command);\n \n return (response.Contents || []).map((item) => ({\n key: item.Key || '',\n lastModified: item.LastModified,\n size: item.Size,\n }));\n }\n\n private generateKey(): string {\n const timestamp = Date.now();\n const random = Math.random().toString(36).substring(2, 15);\n return `uploads/${timestamp}-${random}`;\n }\n\n private guessContentType(key: string): string {\n const ext = key.split('.').pop()?.toLowerCase();\n \n const contentTypes: Record<string, string> = {\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n png: 'image/png',\n gif: 'image/gif',\n webp: 'image/webp',\n svg: 'image/svg+xml',\n mp4: 'video/mp4',\n webm: 'video/webm',\n mov: 'video/quicktime',\n avi: 'video/x-msvideo',\n pdf: 'application/pdf',\n json: 'application/json',\n txt: 'text/plain',\n };\n\n return contentTypes[ext || ''] || 'application/octet-stream';\n }\n\n private getImageContentType(filename: string): string {\n const ext = filename.split('.').pop()?.toLowerCase();\n const imageTypes: Record<string, string> = {\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n png: 'image/png',\n gif: 'image/gif',\n webp: 'image/webp',\n svg: 'image/svg+xml',\n };\n return imageTypes[ext || ''] || 'image/jpeg';\n }\n\n private getVideoContentType(filename: string): string {\n const ext = filename.split('.').pop()?.toLowerCase();\n const videoTypes: Record<string, string> = {\n mp4: 'video/mp4',\n webm: 'video/webm',\n mov: 'video/quicktime',\n avi: 'video/x-msvideo',\n mkv: 'video/x-matroska',\n ogv: 'video/ogg',\n };\n return videoTypes[ext || ''] || 'video/mp4';\n }\n}\n\nexport const s3Service = new S3Service();\n\nexport const upload = {\n initialize: (config: S3Config) => s3Service.initialize(config),\n \n file: (file: Buffer | Uint8Array | string, options?: UploadOptions) => \n s3Service.upload(file, options),\n \n image: (file: Buffer | Uint8Array | string, filename: string, options?: UploadOptions) =>\n s3Service.uploadImage(file, filename, options),\n \n video: (file: Buffer | Uint8Array | string, filename: string, options?: UploadOptions) =>\n s3Service.uploadVideo(file, filename, options),\n \n delete: (key: string) => s3Service.delete(key),\n getSignedUrl: (key: string, options?: SignedUrlOptions) => s3Service.getSignedUrl(key, options),\n getPublicUrl: (key: string) => s3Service.getPublicUrl(key),\n listFiles: (prefix?: string, maxKeys?: number) => s3Service.listFiles(prefix, maxKeys),\n};\n\nexport default upload;\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/config/index.ts","../../src/logger/index.ts","../../src/upload/index.ts"],"names":["logger","config"],"mappings":"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","file":"index.mjs","sourcesContent":["import { z } from 'zod';\n\nexport const envSchema = z.object({\n NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),\n PORT: z.string().default('3000'),\n DATABASE_URL: z.string().optional(),\n MONGODB_URL: z.string().optional(),\n REDIS_URL: z.string().default('redis://localhost:6379'),\n JWT_SECRET: z.string().min(32).optional(),\n JWT_EXPIRES_IN: z.string().default('7d'),\n JWT_REFRESH_SECRET: z.string().min(32).optional(),\n JWT_REFRESH_EXPIRES_IN: z.string().default('30d'),\n GOOGLE_CLIENT_ID: z.string().optional(),\n GOOGLE_CLIENT_SECRET: z.string().optional(),\n GOOGLE_REDIRECT_URI: z.string().optional(),\n SMTP_HOST: z.string().optional(),\n SMTP_PORT: z.string().default('587'),\n SMTP_USER: z.string().optional(),\n SMTP_PASS: z.string().optional(),\n SMTP_FROM: z.string().optional(),\n TWILIO_ACCOUNT_SID: z.string().optional(),\n TWILIO_AUTH_TOKEN: z.string().optional(),\n TWILIO_PHONE_NUMBER: z.string().optional(),\n SLACK_WEBHOOK_URL: z.string().optional(),\n RATE_LIMIT_WINDOW: z.string().default('1m'),\n RATE_LIMIT_LIMIT: z.string().default('100'),\n LOG_LEVEL: z.enum(['fatal', 'error', 'warn', 'info', 'debug', 'trace']).default('info'),\n AWS_REGION: z.string().default('us-east-1'),\n AWS_ACCESS_KEY_ID: z.string().optional(),\n AWS_SECRET_ACCESS_KEY: z.string().optional(),\n AWS_S3_BUCKET: z.string().optional(),\n AWS_ENDPOINT: z.string().optional(),\n});\n\nexport type EnvConfig = z.infer<typeof envSchema>;\n\nexport interface ConfigOptions {\n schema?: z.ZodSchema;\n envPath?: string;\n validate?: boolean;\n}\n\nclass ConfigManager {\n private config: EnvConfig | null = null;\n private schema: z.ZodSchema;\n private validate: boolean;\n\n constructor(options: ConfigOptions = {}) {\n this.schema = options.schema || envSchema;\n this.validate = options.validate ?? true;\n }\n\n load(): EnvConfig {\n if (this.config) return this.config;\n\n const env: Record<string, string | undefined> = {};\n \n for (const key of Object.keys(this.schema.shape)) {\n env[key] = process.env[key];\n }\n\n if (this.validate) {\n const result = this.schema.safeParse(env);\n if (!result.success) {\n const errors = result.error.errors.map(e => `${e.path.join('.')}: ${e.message}`).join(', ');\n throw new Error(`Config validation failed: ${errors}`);\n }\n this.config = result.data;\n } else {\n this.config = env as EnvConfig;\n }\n\n return this.config;\n }\n\n get<K extends keyof EnvConfig>(key: K): EnvConfig[K] {\n if (!this.config) this.load();\n return this.config![key];\n }\n\n int(key: keyof EnvConfig): number {\n const value = this.get(key);\n if (typeof value === 'string') return parseInt(value, 10);\n return Number(value);\n }\n\n bool(key: keyof EnvConfig): boolean {\n const value = this.get(key);\n if (typeof value === 'boolean') return value;\n if (typeof value === 'string') return value.toLowerCase() === 'true';\n return Boolean(value);\n }\n\n isProduction(): boolean {\n return this.get('NODE_ENV') === 'production';\n }\n\n isDevelopment(): boolean {\n return this.get('NODE_ENV') === 'development';\n }\n\n isTest(): boolean {\n return this.get('NODE_ENV') === 'test';\n }\n\n getAll(): EnvConfig {\n if (!this.config) this.load();\n return this.config!;\n }\n}\n\nconst globalConfig = new ConfigManager();\n\nexport const config = {\n load: () => globalConfig.load(),\n get: <K extends keyof EnvConfig>(key: K) => globalConfig.get(key),\n int: (key: keyof EnvConfig) => globalConfig.int(key),\n bool: (key: keyof EnvConfig) => globalConfig.bool(key),\n isProduction: () => globalConfig.isProduction(),\n isDevelopment: () => globalConfig.isDevelopment(),\n isTest: () => globalConfig.isTest(),\n getAll: () => globalConfig.getAll(),\n create: (options?: ConfigOptions) => new ConfigManager(options),\n};\n\nexport default config;\n","import pino, { Logger, LoggerOptions, Bindings } from 'pino';\nimport { config } from '../config';\n\nexport type LogLevel = 'fatal' | 'error' | 'warn' | 'info' | 'debug' | 'trace';\n\nexport interface LoggerConfig extends Partial<LoggerOptions> {\n level?: LogLevel;\n name?: string;\n prettyPrint?: boolean;\n}\n\nexport interface RequestLoggerOptions {\n logLevel?: LogLevel;\n autoLogging?: boolean;\n}\n\nclass LoggerManager {\n private loggers: Map<string, Logger> = new Map();\n private defaultLogger: Logger;\n\n constructor() {\n const level = (config.get('LOG_LEVEL') as LogLevel) || 'info';\n this.defaultLogger = pino({\n level,\n name: 'saas-backend-kit',\n formatters: {\n bindings: (bindings: Bindings) => ({\n ...bindings,\n service: 'saas-backend-kit',\n }),\n },\n });\n }\n\n createLogger(options: LoggerConfig = {}): Logger {\n const name = options.name || 'default';\n \n if (this.loggers.has(name)) {\n return this.loggers.get(name)!;\n }\n\n const level = options.level || (config.get('LOG_LEVEL') as LogLevel) || 'info';\n \n const logger = pino({\n level,\n name: options.name,\n ...options,\n });\n\n this.loggers.set(name, logger);\n return logger;\n }\n\n getLogger(name?: string): Logger {\n if (name) {\n return this.loggers.get(name) || this.defaultLogger;\n }\n return this.defaultLogger;\n }\n\n child(bindings: Bindings, options?: { name?: string }): Logger {\n const name = options?.name || 'child';\n const parent = options?.name ? this.getLogger(name) : this.defaultLogger;\n return parent.child(bindings);\n }\n}\n\nconst loggerManager = new LoggerManager();\n\nexport const logger = {\n info: (message: string, ...args: unknown[]) => loggerManager.getLogger().info(message, ...args),\n warn: (message: string, ...args: unknown[]) => loggerManager.getLogger().warn(message, ...args),\n error: (message: string, ...args: unknown[]) => loggerManager.getLogger().error(message, ...args),\n debug: (message: string, ...args: unknown[]) => loggerManager.getLogger().debug(message, ...args),\n trace: (message: string, ...args: unknown[]) => loggerManager.getLogger().trace(message, ...args),\n fatal: (message: string, ...args: unknown[]) => loggerManager.getLogger().fatal(message, ...args),\n child: (bindings: Bindings, options?: { name?: string }) => loggerManager.child(bindings, options),\n create: (options?: LoggerConfig) => loggerManager.createLogger(options),\n get: (name?: string) => loggerManager.getLogger(name),\n};\n\nexport function createRequestLogger(options: RequestLoggerOptions = {}) {\n const logLevel = options.logLevel || 'info';\n const logger = loggerManager.getLogger('http');\n\n return function requestLogger(\n req: { method: string; url: string; headers: Record<string, string | string[] | undefined> },\n res: { statusCode: number; statusMessage?: string },\n elapsed: number\n ) {\n const log = logger.child({\n method: req.method,\n url: req.url,\n status: res.statusCode,\n responseTime: elapsed,\n ip: req.headers['x-forwarded-for'] || req.headers['x-real-ip'] || 'unknown',\n userAgent: req.headers['user-agent'],\n });\n\n if (res.statusCode >= 500) {\n log.error(`Request completed`);\n } else if (res.statusCode >= 400) {\n log.warn(`Request completed`);\n } else {\n log.info(`Request completed`);\n }\n };\n}\n\nexport default logger;\n","import { S3Client, PutObjectCommand, DeleteObjectCommand, GetObjectCommand, ListObjectsV2Command } from '@aws-sdk/client-s3';\nimport { getSignedUrl } from '@aws-sdk/s3-request-presigner';\nimport { config } from '../config';\nimport { logger } from '../logger';\n\nexport interface S3Config {\n region?: string;\n accessKeyId?: string;\n secretAccessKey?: string;\n bucket: string;\n endpoint?: string;\n forcePathStyle?: boolean;\n}\n\nexport interface UploadOptions {\n key?: string;\n contentType?: string;\n expiresIn?: number;\n metadata?: Record<string, string>;\n}\n\nexport interface UploadResult {\n key: string;\n url: string;\n bucket: string;\n contentType?: string;\n size?: number;\n}\n\nexport interface SignedUrlOptions {\n expiresIn?: number;\n}\n\nexport interface FileObject {\n key: string;\n lastModified?: Date;\n size?: number;\n contentType?: string;\n}\n\nclass S3Service {\n private client: S3Client | null = null;\n private bucket: string;\n private initialized: boolean = false;\n\n constructor() {\n this.bucket = '';\n }\n\n initialize(config: S3Config): void {\n this.client = new S3Client({\n region: config.region || 'us-east-1',\n credentials: config.accessKeyId && config.secretAccessKey\n ? {\n accessKeyId: config.accessKeyId,\n secretAccessKey: config.secretAccessKey,\n }\n : undefined,\n endpoint: config.endpoint,\n forcePathStyle: config.forcePathStyle || false,\n });\n\n this.bucket = config.bucket;\n this.initialized = true;\n logger.info('S3 service initialized', { bucket: this.bucket });\n }\n\n isInitialized(): boolean {\n return this.initialized;\n }\n\n private ensureInitialized(): void {\n if (!this.initialized) {\n const region = config.get('AWS_REGION') || 'us-east-1';\n const bucket = config.get('AWS_S3_BUCKET') || '';\n \n this.initialize({\n region,\n accessKeyId: config.get('AWS_ACCESS_KEY_ID'),\n secretAccessKey: config.get('AWS_SECRET_ACCESS_KEY'),\n bucket,\n endpoint: config.get('AWS_ENDPOINT'),\n });\n }\n }\n\n async upload(\n file: Buffer | Uint8Array | string,\n options: UploadOptions = {}\n ): Promise<UploadResult> {\n this.ensureInitialized();\n\n const key = options.key || this.generateKey();\n const contentType = options.contentType || this.guessContentType(key);\n\n const command = new PutObjectCommand({\n Bucket: this.bucket,\n Key: key,\n Body: file,\n ContentType: contentType,\n Metadata: options.metadata,\n });\n\n await this.client!.send(command);\n\n const url = await this.getSignedUrl(key, { expiresIn: options.expiresIn || 3600 });\n\n logger.info('File uploaded to S3', { key, bucket: this.bucket, contentType });\n\n return {\n key,\n url,\n bucket: this.bucket,\n contentType,\n };\n }\n\n async uploadImage(\n file: Buffer | Uint8Array | string,\n filename: string,\n options: UploadOptions = {}\n ): Promise<UploadResult> {\n const key = options.key || `images/${Date.now()}-${filename}`;\n \n return this.upload(file, {\n ...options,\n key,\n contentType: options.contentType || this.getImageContentType(filename),\n });\n }\n\n async uploadVideo(\n file: Buffer | Uint8Array | string,\n filename: string,\n options: UploadOptions = {}\n ): Promise<UploadResult> {\n const key = options.key || `videos/${Date.now()}-${filename}`;\n \n return this.upload(file, {\n ...options,\n key,\n contentType: options.contentType || this.getVideoContentType(filename),\n });\n }\n\n async delete(key: string): Promise<void> {\n this.ensureInitialized();\n\n const command = new DeleteObjectCommand({\n Bucket: this.bucket,\n Key: key,\n });\n\n await this.client!.send(command);\n logger.info('File deleted from S3', { key, bucket: this.bucket });\n }\n\n async getSignedUrl(key: string, options: SignedUrlOptions = {}): Promise<string> {\n this.ensureInitialized();\n\n const command = new GetObjectCommand({\n Bucket: this.bucket,\n Key: key,\n });\n\n return getSignedUrl(this.client!, command, {\n expiresIn: options.expiresIn || 3600,\n });\n }\n\n async getPublicUrl(key: string): Promise<string> {\n return `https://${this.bucket}.s3.${config.get('AWS_REGION') || 'us-east-1'}.amazonaws.com/${key}`;\n }\n\n async listFiles(prefix?: string, maxKeys: number = 1000): Promise<FileObject[]> {\n this.ensureInitialized();\n\n const command = new ListObjectsV2Command({\n Bucket: this.bucket,\n Prefix: prefix,\n MaxKeys: maxKeys,\n });\n\n const response = await this.client!.send(command);\n \n return (response.Contents || []).map((item) => ({\n key: item.Key || '',\n lastModified: item.LastModified,\n size: item.Size,\n }));\n }\n\n private generateKey(): string {\n const timestamp = Date.now();\n const random = Math.random().toString(36).substring(2, 15);\n return `uploads/${timestamp}-${random}`;\n }\n\n private guessContentType(key: string): string {\n const ext = key.split('.').pop()?.toLowerCase();\n \n const contentTypes: Record<string, string> = {\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n png: 'image/png',\n gif: 'image/gif',\n webp: 'image/webp',\n svg: 'image/svg+xml',\n mp4: 'video/mp4',\n webm: 'video/webm',\n mov: 'video/quicktime',\n avi: 'video/x-msvideo',\n pdf: 'application/pdf',\n json: 'application/json',\n txt: 'text/plain',\n };\n\n return contentTypes[ext || ''] || 'application/octet-stream';\n }\n\n private getImageContentType(filename: string): string {\n const ext = filename.split('.').pop()?.toLowerCase();\n const imageTypes: Record<string, string> = {\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n png: 'image/png',\n gif: 'image/gif',\n webp: 'image/webp',\n svg: 'image/svg+xml',\n };\n return imageTypes[ext || ''] || 'image/jpeg';\n }\n\n private getVideoContentType(filename: string): string {\n const ext = filename.split('.').pop()?.toLowerCase();\n const videoTypes: Record<string, string> = {\n mp4: 'video/mp4',\n webm: 'video/webm',\n mov: 'video/quicktime',\n avi: 'video/x-msvideo',\n mkv: 'video/x-matroska',\n ogv: 'video/ogg',\n };\n return videoTypes[ext || ''] || 'video/mp4';\n }\n}\n\nexport const s3Service = new S3Service();\n\nexport const upload = {\n initialize: (config: S3Config) => s3Service.initialize(config),\n \n file: (file: Buffer | Uint8Array | string, options?: UploadOptions) => \n s3Service.upload(file, options),\n \n image: (file: Buffer | Uint8Array | string, filename: string, options?: UploadOptions) =>\n s3Service.uploadImage(file, filename, options),\n \n video: (file: Buffer | Uint8Array | string, filename: string, options?: UploadOptions) =>\n s3Service.uploadVideo(file, filename, options),\n \n delete: (key: string) => s3Service.delete(key),\n getSignedUrl: (key: string, options?: SignedUrlOptions) => s3Service.getSignedUrl(key, options),\n getPublicUrl: (key: string) => s3Service.getPublicUrl(key),\n listFiles: (prefix?: string, maxKeys?: number) => s3Service.listFiles(prefix, maxKeys),\n};\n\nexport default upload;\n"]}
|
|
@@ -10,9 +10,12 @@ JWT_REFRESH_EXPIRES_IN=30d
|
|
|
10
10
|
# Redis
|
|
11
11
|
REDIS_URL=redis://localhost:6379
|
|
12
12
|
|
|
13
|
-
# Database (
|
|
13
|
+
# Database (PostgreSQL)
|
|
14
14
|
DATABASE_URL=postgresql://user:password@localhost:5432/mydb
|
|
15
15
|
|
|
16
|
+
# Database (MongoDB)
|
|
17
|
+
MONGODB_URL=mongodb://user:password@localhost:27017/mydb
|
|
18
|
+
|
|
16
19
|
# Google OAuth (optional)
|
|
17
20
|
GOOGLE_CLIENT_ID=
|
|
18
21
|
GOOGLE_CLIENT_SECRET=
|
package/jest-output.json
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
FAIL tests/utils.test.ts (7.974 s)
|
|
2
|
+
Utils Module
|
|
3
|
+
× should generate random ID (464 ms)
|
|
4
|
+
× should generate ID with custom length (330 ms)
|
|
5
|
+
× should hash string (18 ms)
|
|
6
|
+
× should generate token (18 ms)
|
|
7
|
+
× should generate API key with prefix (61 ms)
|
|
8
|
+
× should sleep (25 ms)
|
|
9
|
+
× should retry on failure (14 ms)
|
|
10
|
+
× should parse query int (14 ms)
|
|
11
|
+
× should parse query bool (17 ms)
|
|
12
|
+
|
|
13
|
+
● Utils Module › should generate random ID
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
● Utils Module › should generate ID with custom length
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
● Utils Module › should hash string
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
● Utils Module › should generate token
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
● Utils Module › should generate API key with prefix
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
● Utils Module › should sleep
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
● Utils Module › should retry on failure
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
● Utils Module › should parse query int
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
● Utils Module › should parse query bool
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
Test Suites: 1 failed, 1 total
|
|
68
|
+
Tests: 9 failed, 9 total
|
|
69
|
+
Snapshots: 0 total
|
|
70
|
+
Time: 8.281 s
|
|
71
|
+
Ran all test suites matching /tests\\utils.test.ts/i.
|
|
72
|
+
{"numFailedTestSuites":1,"numFailedTests":9,"numPassedTestSuites":0,"numPassedTests":0,"numPendingTestSuites":0,"numPendingTests":0,"numRuntimeErrorTestSuites":0,"numTodoTests":0,"numTotalTestSuites":1,"numTotalTests":9,"openHandles":[],"snapshot":{"added":0,"didUpdate":false,"failure":false,"filesAdded":0,"filesRemoved":0,"filesRemovedList":[],"filesUnmatched":0,"filesUpdated":0,"matched":0,"total":0,"unchecked":0,"uncheckedKeysByFile":[],"unmatched":0,"updated":0},"startTime":1772702813609,"success":false,"testResults":[{"assertionResults":[{"ancestorTitles":["Utils Module"],"duration":464,"failureDetails":[{"name":"TSError","diagnosticText":"\u001b[96msrc/utils/index.ts\u001b[0m:\u001b[93m151\u001b[0m:\u001b[93m7\u001b[0m - \u001b[91merror\u001b[0m\u001b[90m TS2322: \u001b[0mType 'unknown' is not assignable to type 'T[keyof T] | undefined'.\n\n\u001b[7m151\u001b[0m sanitized[key as keyof T] = obj[key];\n\u001b[7m \u001b[0m \u001b[91m ~~~~~~~~~~~~~~~~~~~~~~~~~\u001b[0m\n","diagnosticCodes":[2322]}],"failureMessages":[""],"fullName":"Utils Module should generate random ID","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"failed","title":"should generate random ID"},{"ancestorTitles":["Utils Module"],"duration":330,"failureDetails":[{"name":"TSError","diagnosticText":"\u001b[96msrc/utils/index.ts\u001b[0m:\u001b[93m151\u001b[0m:\u001b[93m7\u001b[0m - \u001b[91merror\u001b[0m\u001b[90m TS2322: \u001b[0mType 'unknown' is not assignable to type 'T[keyof T] | undefined'.\n\n\u001b[7m151\u001b[0m sanitized[key as keyof T] = obj[key];\n\u001b[7m \u001b[0m \u001b[91m ~~~~~~~~~~~~~~~~~~~~~~~~~\u001b[0m\n","diagnosticCodes":[2322]}],"failureMessages":[""],"fullName":"Utils Module should generate ID with custom length","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"failed","title":"should generate ID with custom length"},{"ancestorTitles":["Utils Module"],"duration":18,"failureDetails":[{"name":"TSError","diagnosticText":"\u001b[96msrc/utils/index.ts\u001b[0m:\u001b[93m151\u001b[0m:\u001b[93m7\u001b[0m - \u001b[91merror\u001b[0m\u001b[90m TS2322: \u001b[0mType 'unknown' is not assignable to type 'T[keyof T] | undefined'.\n\n\u001b[7m151\u001b[0m sanitized[key as keyof T] = obj[key];\n\u001b[7m \u001b[0m \u001b[91m ~~~~~~~~~~~~~~~~~~~~~~~~~\u001b[0m\n","diagnosticCodes":[2322]}],"failureMessages":[""],"fullName":"Utils Module should hash string","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"failed","title":"should hash string"},{"ancestorTitles":["Utils Module"],"duration":18,"failureDetails":[{"name":"TSError","diagnosticText":"\u001b[96msrc/utils/index.ts\u001b[0m:\u001b[93m151\u001b[0m:\u001b[93m7\u001b[0m - \u001b[91merror\u001b[0m\u001b[90m TS2322: \u001b[0mType 'unknown' is not assignable to type 'T[keyof T] | undefined'.\n\n\u001b[7m151\u001b[0m sanitized[key as keyof T] = obj[key];\n\u001b[7m \u001b[0m \u001b[91m ~~~~~~~~~~~~~~~~~~~~~~~~~\u001b[0m\n","diagnosticCodes":[2322]}],"failureMessages":[""],"fullName":"Utils Module should generate token","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"failed","title":"should generate token"},{"ancestorTitles":["Utils Module"],"duration":61,"failureDetails":[{"name":"TSError","diagnosticText":"\u001b[96msrc/utils/index.ts\u001b[0m:\u001b[93m151\u001b[0m:\u001b[93m7\u001b[0m - \u001b[91merror\u001b[0m\u001b[90m TS2322: \u001b[0mType 'unknown' is not assignable to type 'T[keyof T] | undefined'.\n\n\u001b[7m151\u001b[0m sanitized[key as keyof T] = obj[key];\n\u001b[7m \u001b[0m \u001b[91m ~~~~~~~~~~~~~~~~~~~~~~~~~\u001b[0m\n","diagnosticCodes":[2322]}],"failureMessages":[""],"fullName":"Utils Module should generate API key with prefix","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"failed","title":"should generate API key with prefix"},{"ancestorTitles":["Utils Module"],"duration":25,"failureDetails":[{"name":"TSError","diagnosticText":"\u001b[96msrc/utils/index.ts\u001b[0m:\u001b[93m151\u001b[0m:\u001b[93m7\u001b[0m - \u001b[91merror\u001b[0m\u001b[90m TS2322: \u001b[0mType 'unknown' is not assignable to type 'T[keyof T] | undefined'.\n\n\u001b[7m151\u001b[0m sanitized[key as keyof T] = obj[key];\n\u001b[7m \u001b[0m \u001b[91m ~~~~~~~~~~~~~~~~~~~~~~~~~\u001b[0m\n","diagnosticCodes":[2322]}],"failureMessages":[""],"fullName":"Utils Module should sleep","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"failed","title":"should sleep"},{"ancestorTitles":["Utils Module"],"duration":14,"failureDetails":[{"name":"TSError","diagnosticText":"\u001b[96msrc/utils/index.ts\u001b[0m:\u001b[93m151\u001b[0m:\u001b[93m7\u001b[0m - \u001b[91merror\u001b[0m\u001b[90m TS2322: \u001b[0mType 'unknown' is not assignable to type 'T[keyof T] | undefined'.\n\n\u001b[7m151\u001b[0m sanitized[key as keyof T] = obj[key];\n\u001b[7m \u001b[0m \u001b[91m ~~~~~~~~~~~~~~~~~~~~~~~~~\u001b[0m\n","diagnosticCodes":[2322]}],"failureMessages":[""],"fullName":"Utils Module should retry on failure","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"failed","title":"should retry on failure"},{"ancestorTitles":["Utils Module"],"duration":14,"failureDetails":[{"name":"TSError","diagnosticText":"\u001b[96msrc/utils/index.ts\u001b[0m:\u001b[93m151\u001b[0m:\u001b[93m7\u001b[0m - \u001b[91merror\u001b[0m\u001b[90m TS2322: \u001b[0mType 'unknown' is not assignable to type 'T[keyof T] | undefined'.\n\n\u001b[7m151\u001b[0m sanitized[key as keyof T] = obj[key];\n\u001b[7m \u001b[0m \u001b[91m ~~~~~~~~~~~~~~~~~~~~~~~~~\u001b[0m\n","diagnosticCodes":[2322]}],"failureMessages":[""],"fullName":"Utils Module should parse query int","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"failed","title":"should parse query int"},{"ancestorTitles":["Utils Module"],"duration":17,"failureDetails":[{"name":"TSError","diagnosticText":"\u001b[96msrc/utils/index.ts\u001b[0m:\u001b[93m151\u001b[0m:\u001b[93m7\u001b[0m - \u001b[91merror\u001b[0m\u001b[90m TS2322: \u001b[0mType 'unknown' is not assignable to type 'T[keyof T] | undefined'.\n\n\u001b[7m151\u001b[0m sanitized[key as keyof T] = obj[key];\n\u001b[7m \u001b[0m \u001b[91m ~~~~~~~~~~~~~~~~~~~~~~~~~\u001b[0m\n","diagnosticCodes":[2322]}],"failureMessages":[""],"fullName":"Utils Module should parse query bool","invocations":1,"location":null,"numPassingAsserts":0,"retryReasons":[],"status":"failed","title":"should parse query bool"}],"endTime":1772702821883,"message":" ● Utils Module › should generate random ID\n\n\n\n\n\n ● Utils Module › should generate ID with custom length\n\n\n\n\n\n ● Utils Module › should hash string\n\n\n\n\n\n ● Utils Module › should generate token\n\n\n\n\n\n ● Utils Module › should generate API key with prefix\n\n\n\n\n\n ● Utils Module › should sleep\n\n\n\n\n\n ● Utils Module › should retry on failure\n\n\n\n\n\n ● Utils Module › should parse query int\n\n\n\n\n\n ● Utils Module › should parse query bool\n\n\n\n\n","name":"C:\\Users\\ashis\\OneDrive\\Desktop\\test\\open\\saas-backend-kit\\tests\\utils.test.ts","startTime":1772702813909,"status":"failed","summary":""}],"wasInterrupted":false}
|
package/jest.config.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
preset: 'ts-jest',
|
|
3
|
+
testEnvironment: 'node',
|
|
4
|
+
roots: ['<rootDir>/tests'],
|
|
5
|
+
testMatch: ['**/*.test.ts'],
|
|
6
|
+
collectCoverageFrom: [
|
|
7
|
+
'src/**/*.ts',
|
|
8
|
+
'!src/**/*.d.ts'
|
|
9
|
+
],
|
|
10
|
+
coverageDirectory: 'coverage',
|
|
11
|
+
verbose: true,
|
|
12
|
+
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
|
|
13
|
+
transform: {
|
|
14
|
+
'^.+\\.tsx?$': ['ts-jest', {
|
|
15
|
+
tsconfig: 'tsconfig.test.json',
|
|
16
|
+
diagnostics: false
|
|
17
|
+
}]
|
|
18
|
+
}
|
|
19
|
+
};
|