saas-backend-kit 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/README.md +123 -344
  2. package/copy-dts.js +59 -0
  3. package/dist/auth/index.js +7 -2
  4. package/dist/auth/index.js.map +1 -1
  5. package/dist/auth/index.mjs +7 -2
  6. package/dist/auth/index.mjs.map +1 -1
  7. package/dist/config/index.js +6 -1
  8. package/dist/config/index.js.map +1 -1
  9. package/dist/config/index.mjs +6 -1
  10. package/dist/config/index.mjs.map +1 -1
  11. package/dist/index.d.ts +1 -0
  12. package/dist/index.js +232 -41
  13. package/dist/index.js.map +1 -1
  14. package/dist/index.mjs +231 -42
  15. package/dist/index.mjs.map +1 -1
  16. package/dist/logger/index.js +6 -1
  17. package/dist/logger/index.js.map +1 -1
  18. package/dist/logger/index.mjs +6 -1
  19. package/dist/logger/index.mjs.map +1 -1
  20. package/dist/notifications/index.js +6 -1
  21. package/dist/notifications/index.js.map +1 -1
  22. package/dist/notifications/index.mjs +6 -1
  23. package/dist/notifications/index.mjs.map +1 -1
  24. package/dist/queue/index.js +6 -1
  25. package/dist/queue/index.js.map +1 -1
  26. package/dist/queue/index.mjs +6 -1
  27. package/dist/queue/index.mjs.map +1 -1
  28. package/dist/rate-limit/index.js +7 -1
  29. package/dist/rate-limit/index.js.map +1 -1
  30. package/dist/rate-limit/index.mjs +7 -1
  31. package/dist/rate-limit/index.mjs.map +1 -1
  32. package/dist/response/index.js +51 -40
  33. package/dist/response/index.js.map +1 -1
  34. package/dist/response/index.mjs +51 -40
  35. package/dist/response/index.mjs.map +1 -1
  36. package/dist/upload/index.d.ts +57 -0
  37. package/dist/upload/index.js +344 -0
  38. package/dist/upload/index.js.map +1 -0
  39. package/dist/upload/index.mjs +334 -0
  40. package/dist/upload/index.mjs.map +1 -0
  41. package/jest-output.json +72 -0
  42. package/jest.config.js +19 -0
  43. package/package.json +20 -8
  44. package/saas-banner.svg +239 -0
  45. package/src/auth/jwt.ts +1 -1
  46. package/src/config/index.ts +5 -0
  47. package/src/index.ts +2 -0
  48. package/src/rate-limit/express.ts +1 -0
  49. package/src/response/index.ts +49 -40
  50. package/src/upload/index.ts +268 -0
  51. package/tests/auth.test.ts +134 -0
  52. package/tests/config.test.ts +36 -0
  53. package/tests/logger.test.ts +47 -0
  54. package/tests/notifications.test.ts +19 -0
  55. package/tests/rate-limit.test.ts +50 -0
  56. package/tests/upload.test.ts +33 -0
  57. package/tsconfig.test.json +14 -0
  58. package/tsup.config.ts +2 -1
package/dist/index.mjs CHANGED
@@ -4,7 +4,8 @@ import { Queue, Worker } from 'bullmq';
4
4
  import jwt from 'jsonwebtoken';
5
5
  import bcrypt from 'bcryptjs';
6
6
  import nodemailer from 'nodemailer';
7
- import { Response } from 'express';
7
+ import { S3Client, PutObjectCommand, DeleteObjectCommand, GetObjectCommand, ListObjectsV2Command } from '@aws-sdk/client-s3';
8
+ import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
8
9
 
9
10
  var __defProp = Object.defineProperty;
10
11
  var __getOwnPropNames = Object.getOwnPropertyNames;
@@ -59,7 +60,12 @@ var init_config = __esm({
59
60
  SLACK_WEBHOOK_URL: z.string().optional(),
60
61
  RATE_LIMIT_WINDOW: z.string().default("1m"),
61
62
  RATE_LIMIT_LIMIT: z.string().default("100"),
62
- LOG_LEVEL: z.enum(["fatal", "error", "warn", "info", "debug", "trace"]).default("info")
63
+ LOG_LEVEL: z.enum(["fatal", "error", "warn", "info", "debug", "trace"]).default("info"),
64
+ AWS_REGION: z.string().default("us-east-1"),
65
+ AWS_ACCESS_KEY_ID: z.string().optional(),
66
+ AWS_SECRET_ACCESS_KEY: z.string().optional(),
67
+ AWS_S3_BUCKET: z.string().optional(),
68
+ AWS_ENDPOINT: z.string().optional()
63
69
  });
64
70
  ConfigManager = class {
65
71
  config = null;
@@ -431,6 +437,7 @@ var init_express = __esm({
431
437
  cleanupInterval;
432
438
  constructor() {
433
439
  this.cleanupInterval = setInterval(() => this.cleanup(), 6e4);
440
+ this.cleanupInterval.unref();
434
441
  }
435
442
  cleanup() {
436
443
  const now = Date.now();
@@ -561,7 +568,7 @@ var JWTService = class {
561
568
  return jwt.verify(token, this.refreshSecret);
562
569
  }
563
570
  refreshTokens(refreshToken) {
564
- const payload = this.verifyRefreshToken(refreshToken);
571
+ const { iat, exp, nbf, ...payload } = this.verifyRefreshToken(refreshToken);
565
572
  return this.generateTokenPair(payload);
566
573
  }
567
574
  };
@@ -1038,6 +1045,8 @@ init_express();
1038
1045
 
1039
1046
  // src/index.ts
1040
1047
  init_config();
1048
+
1049
+ // src/response/index.ts
1041
1050
  var ResponseHelper = class {
1042
1051
  static success(res, data, message, statusCode = 200) {
1043
1052
  const response2 = {
@@ -1104,46 +1113,226 @@ var ResponseHelper = class {
1104
1113
  return res.status(204).send();
1105
1114
  }
1106
1115
  };
1107
- Response.prototype.success = function(data, message, statusCode = 200) {
1108
- return ResponseHelper.success(this, data, message, statusCode);
1109
- };
1110
- Response.prototype.created = function(data, message) {
1111
- return ResponseHelper.created(this, data, message);
1112
- };
1113
- Response.prototype.updated = function(data, message) {
1114
- return ResponseHelper.updated(this, data, message);
1115
- };
1116
- Response.prototype.deleted = function(message) {
1117
- return ResponseHelper.deleted(this, message);
1118
- };
1119
- Response.prototype.error = function(error, statusCode = 400, code, details) {
1120
- return ResponseHelper.error(this, error, statusCode, code, details);
1121
- };
1122
- Response.prototype.badRequest = function(error, code) {
1123
- return ResponseHelper.badRequest(this, error, code);
1124
- };
1125
- Response.prototype.unauthorized = function(error, code) {
1126
- return ResponseHelper.unauthorized(this, error, code);
1127
- };
1128
- Response.prototype.forbidden = function(error, code) {
1129
- return ResponseHelper.forbidden(this, error, code);
1130
- };
1131
- Response.prototype.notFound = function(error, code) {
1132
- return ResponseHelper.notFound(this, error, code);
1133
- };
1134
- Response.prototype.conflict = function(error, code) {
1135
- return ResponseHelper.conflict(this, error, code);
1136
- };
1137
- Response.prototype.validationError = function(error, details) {
1138
- return ResponseHelper.validationError(this, error, details);
1139
- };
1140
- Response.prototype.internalError = function(error) {
1141
- return ResponseHelper.internalError(this, error);
1116
+ try {
1117
+ const proto = __require("express").response;
1118
+ if (proto) {
1119
+ proto.success = function(data, message, statusCode = 200) {
1120
+ return ResponseHelper.success(this, data, message, statusCode);
1121
+ };
1122
+ proto.created = function(data, message) {
1123
+ return ResponseHelper.created(this, data, message);
1124
+ };
1125
+ proto.updated = function(data, message) {
1126
+ return ResponseHelper.updated(this, data, message);
1127
+ };
1128
+ proto.deleted = function(message) {
1129
+ return ResponseHelper.deleted(this, message);
1130
+ };
1131
+ proto.error = function(error, statusCode = 400, code, details) {
1132
+ return ResponseHelper.error(this, error, statusCode, code, details);
1133
+ };
1134
+ proto.badRequest = function(error, code) {
1135
+ return ResponseHelper.badRequest(this, error, code);
1136
+ };
1137
+ proto.unauthorized = function(error, code) {
1138
+ return ResponseHelper.unauthorized(this, error, code);
1139
+ };
1140
+ proto.forbidden = function(error, code) {
1141
+ return ResponseHelper.forbidden(this, error, code);
1142
+ };
1143
+ proto.notFound = function(error, code) {
1144
+ return ResponseHelper.notFound(this, error, code);
1145
+ };
1146
+ proto.conflict = function(error, code) {
1147
+ return ResponseHelper.conflict(this, error, code);
1148
+ };
1149
+ proto.validationError = function(error, details) {
1150
+ return ResponseHelper.validationError(this, error, details);
1151
+ };
1152
+ proto.internalError = function(error) {
1153
+ return ResponseHelper.internalError(this, error);
1154
+ };
1155
+ proto.paginated = function(data, page, limit, total) {
1156
+ return ResponseHelper.paginated(this, data, page, limit, total);
1157
+ };
1158
+ }
1159
+ } catch {
1160
+ }
1161
+ var response = ResponseHelper;
1162
+
1163
+ // src/upload/index.ts
1164
+ init_config();
1165
+ init_logger();
1166
+ var S3Service = class {
1167
+ client = null;
1168
+ bucket;
1169
+ initialized = false;
1170
+ constructor() {
1171
+ this.bucket = "";
1172
+ }
1173
+ initialize(config2) {
1174
+ this.client = new S3Client({
1175
+ region: config2.region || "us-east-1",
1176
+ credentials: config2.accessKeyId && config2.secretAccessKey ? {
1177
+ accessKeyId: config2.accessKeyId,
1178
+ secretAccessKey: config2.secretAccessKey
1179
+ } : void 0,
1180
+ endpoint: config2.endpoint,
1181
+ forcePathStyle: config2.forcePathStyle || false
1182
+ });
1183
+ this.bucket = config2.bucket;
1184
+ this.initialized = true;
1185
+ logger.info("S3 service initialized", { bucket: this.bucket });
1186
+ }
1187
+ isInitialized() {
1188
+ return this.initialized;
1189
+ }
1190
+ ensureInitialized() {
1191
+ if (!this.initialized) {
1192
+ const region = config.get("AWS_REGION") || "us-east-1";
1193
+ const bucket = config.get("AWS_S3_BUCKET") || "";
1194
+ this.initialize({
1195
+ region,
1196
+ accessKeyId: config.get("AWS_ACCESS_KEY_ID"),
1197
+ secretAccessKey: config.get("AWS_SECRET_ACCESS_KEY"),
1198
+ bucket,
1199
+ endpoint: config.get("AWS_ENDPOINT")
1200
+ });
1201
+ }
1202
+ }
1203
+ async upload(file, options = {}) {
1204
+ this.ensureInitialized();
1205
+ const key = options.key || this.generateKey();
1206
+ const contentType = options.contentType || this.guessContentType(key);
1207
+ const command = new PutObjectCommand({
1208
+ Bucket: this.bucket,
1209
+ Key: key,
1210
+ Body: file,
1211
+ ContentType: contentType,
1212
+ Metadata: options.metadata
1213
+ });
1214
+ await this.client.send(command);
1215
+ const url = await this.getSignedUrl(key, { expiresIn: options.expiresIn || 3600 });
1216
+ logger.info("File uploaded to S3", { key, bucket: this.bucket, contentType });
1217
+ return {
1218
+ key,
1219
+ url,
1220
+ bucket: this.bucket,
1221
+ contentType
1222
+ };
1223
+ }
1224
+ async uploadImage(file, filename, options = {}) {
1225
+ const key = options.key || `images/${Date.now()}-${filename}`;
1226
+ return this.upload(file, {
1227
+ ...options,
1228
+ key,
1229
+ contentType: options.contentType || this.getImageContentType(filename)
1230
+ });
1231
+ }
1232
+ async uploadVideo(file, filename, options = {}) {
1233
+ const key = options.key || `videos/${Date.now()}-${filename}`;
1234
+ return this.upload(file, {
1235
+ ...options,
1236
+ key,
1237
+ contentType: options.contentType || this.getVideoContentType(filename)
1238
+ });
1239
+ }
1240
+ async delete(key) {
1241
+ this.ensureInitialized();
1242
+ const command = new DeleteObjectCommand({
1243
+ Bucket: this.bucket,
1244
+ Key: key
1245
+ });
1246
+ await this.client.send(command);
1247
+ logger.info("File deleted from S3", { key, bucket: this.bucket });
1248
+ }
1249
+ async getSignedUrl(key, options = {}) {
1250
+ this.ensureInitialized();
1251
+ const command = new GetObjectCommand({
1252
+ Bucket: this.bucket,
1253
+ Key: key
1254
+ });
1255
+ return getSignedUrl(this.client, command, {
1256
+ expiresIn: options.expiresIn || 3600
1257
+ });
1258
+ }
1259
+ async getPublicUrl(key) {
1260
+ return `https://${this.bucket}.s3.${config.get("AWS_REGION") || "us-east-1"}.amazonaws.com/${key}`;
1261
+ }
1262
+ async listFiles(prefix, maxKeys = 1e3) {
1263
+ this.ensureInitialized();
1264
+ const command = new ListObjectsV2Command({
1265
+ Bucket: this.bucket,
1266
+ Prefix: prefix,
1267
+ MaxKeys: maxKeys
1268
+ });
1269
+ const response2 = await this.client.send(command);
1270
+ return (response2.Contents || []).map((item) => ({
1271
+ key: item.Key || "",
1272
+ lastModified: item.LastModified,
1273
+ size: item.Size
1274
+ }));
1275
+ }
1276
+ generateKey() {
1277
+ const timestamp = Date.now();
1278
+ const random = Math.random().toString(36).substring(2, 15);
1279
+ return `uploads/${timestamp}-${random}`;
1280
+ }
1281
+ guessContentType(key) {
1282
+ const ext = key.split(".").pop()?.toLowerCase();
1283
+ const contentTypes = {
1284
+ jpg: "image/jpeg",
1285
+ jpeg: "image/jpeg",
1286
+ png: "image/png",
1287
+ gif: "image/gif",
1288
+ webp: "image/webp",
1289
+ svg: "image/svg+xml",
1290
+ mp4: "video/mp4",
1291
+ webm: "video/webm",
1292
+ mov: "video/quicktime",
1293
+ avi: "video/x-msvideo",
1294
+ pdf: "application/pdf",
1295
+ json: "application/json",
1296
+ txt: "text/plain"
1297
+ };
1298
+ return contentTypes[ext || ""] || "application/octet-stream";
1299
+ }
1300
+ getImageContentType(filename) {
1301
+ const ext = filename.split(".").pop()?.toLowerCase();
1302
+ const imageTypes = {
1303
+ jpg: "image/jpeg",
1304
+ jpeg: "image/jpeg",
1305
+ png: "image/png",
1306
+ gif: "image/gif",
1307
+ webp: "image/webp",
1308
+ svg: "image/svg+xml"
1309
+ };
1310
+ return imageTypes[ext || ""] || "image/jpeg";
1311
+ }
1312
+ getVideoContentType(filename) {
1313
+ const ext = filename.split(".").pop()?.toLowerCase();
1314
+ const videoTypes = {
1315
+ mp4: "video/mp4",
1316
+ webm: "video/webm",
1317
+ mov: "video/quicktime",
1318
+ avi: "video/x-msvideo",
1319
+ mkv: "video/x-matroska",
1320
+ ogv: "video/ogg"
1321
+ };
1322
+ return videoTypes[ext || ""] || "video/mp4";
1323
+ }
1142
1324
  };
1143
- Response.prototype.paginated = function(data, page, limit, total) {
1144
- return ResponseHelper.paginated(this, data, page, limit, total);
1325
+ var s3Service = new S3Service();
1326
+ var upload = {
1327
+ initialize: (config2) => s3Service.initialize(config2),
1328
+ file: (file, options) => s3Service.upload(file, options),
1329
+ image: (file, filename, options) => s3Service.uploadImage(file, filename, options),
1330
+ video: (file, filename, options) => s3Service.uploadVideo(file, filename, options),
1331
+ delete: (key) => s3Service.delete(key),
1332
+ getSignedUrl: (key, options) => s3Service.getSignedUrl(key, options),
1333
+ getPublicUrl: (key) => s3Service.getPublicUrl(key),
1334
+ listFiles: (prefix, maxKeys) => s3Service.listFiles(prefix, maxKeys)
1145
1335
  };
1146
- var response = ResponseHelper;
1147
1336
 
1148
1337
  // src/plugin.ts
1149
1338
  init_logger();
@@ -1276,6 +1465,6 @@ init_queue();
1276
1465
  init_logger();
1277
1466
  init_config();
1278
1467
 
1279
- export { Auth, AuthService, PluginManager, QueueManager, ResponseHelper, SaaSAppBuilder, auth, config, createApp, createAuth, createExpressApp, createQueue, createRateLimiter, logger, notification, notify, queue, rateLimit, response };
1468
+ export { Auth, AuthService, PluginManager, QueueManager, ResponseHelper, SaaSAppBuilder, auth, config, createApp, createAuth, createExpressApp, createQueue, createRateLimiter, logger, notification, notify, queue, rateLimit, response, s3Service, upload };
1280
1469
  //# sourceMappingURL=index.mjs.map
1281
1470
  //# sourceMappingURL=index.mjs.map