arkos 1.0.1-beta → 1.0.2-alpha
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 +2 -2
- package/dist/cjs/app.js +1 -1
- package/dist/cjs/app.js.map +1 -1
- package/dist/cjs/exports/services/index.js +3 -3
- package/dist/cjs/exports/services/index.js.map +1 -1
- package/dist/cjs/modules/auth/__tests__/auth.controller.test.js +0 -1
- package/dist/cjs/modules/auth/__tests__/auth.controller.test.js.map +1 -1
- package/dist/cjs/modules/auth/__tests__/auth.service.test.js +470 -0
- package/dist/cjs/modules/auth/__tests__/auth.service.test.js.map +1 -0
- package/dist/cjs/modules/auth/auth.service.js +30 -9
- package/dist/cjs/modules/auth/auth.service.js.map +1 -1
- package/dist/cjs/modules/email/email.service.js +12 -7
- package/dist/cjs/modules/email/email.service.js.map +1 -1
- package/dist/cjs/modules/file-uploader/__tests__/file-uploader.service.test.js +402 -0
- package/dist/cjs/modules/file-uploader/__tests__/file-uploader.service.test.js.map +1 -0
- package/dist/cjs/modules/file-uploader/file-uploader.controller.js +226 -0
- package/dist/cjs/modules/file-uploader/file-uploader.controller.js.map +1 -0
- package/dist/cjs/modules/file-uploader/file-uploader.router.js +50 -0
- package/dist/cjs/modules/file-uploader/file-uploader.router.js.map +1 -0
- package/dist/cjs/modules/file-uploader/file-uploader.service.js +299 -0
- package/dist/cjs/modules/file-uploader/file-uploader.service.js.map +1 -0
- package/dist/cjs/modules/file-uploader/utils/helpers/__tests__/file-uploader.helpers.test.js +164 -0
- package/dist/cjs/modules/file-uploader/utils/helpers/__tests__/file-uploader.helpers.test.js.map +1 -0
- package/dist/cjs/modules/file-uploader/utils/helpers/file-uploader.helpers.js +85 -0
- package/dist/cjs/modules/file-uploader/utils/helpers/file-uploader.helpers.js.map +1 -0
- package/dist/cjs/server.js +1 -1
- package/dist/cjs/server.js.map +1 -1
- package/dist/cjs/types/arkos-config.js.map +1 -1
- package/dist/cjs/types/auth.js.map +1 -1
- package/dist/cjs/types/index.js.map +1 -1
- package/dist/cjs/utils/helpers/models.helpers.js +19 -6
- package/dist/cjs/utils/helpers/models.helpers.js.map +1 -1
- package/dist/es2020/app.js +1 -1
- package/dist/es2020/app.js.map +1 -1
- package/dist/es2020/exports/services/index.js +1 -1
- package/dist/es2020/exports/services/index.js.map +1 -1
- package/dist/es2020/modules/auth/auth.service.js +30 -9
- package/dist/es2020/modules/auth/auth.service.js.map +1 -1
- package/dist/es2020/modules/email/email.service.js +12 -7
- package/dist/es2020/modules/email/email.service.js.map +1 -1
- package/dist/es2020/modules/file-uploader/file-uploader.controller.js +220 -0
- package/dist/es2020/modules/file-uploader/file-uploader.controller.js.map +1 -0
- package/dist/es2020/modules/file-uploader/file-uploader.router.js +44 -0
- package/dist/es2020/modules/file-uploader/file-uploader.router.js.map +1 -0
- package/dist/es2020/modules/file-uploader/file-uploader.service.js +291 -0
- package/dist/es2020/modules/file-uploader/file-uploader.service.js.map +1 -0
- package/dist/es2020/modules/file-uploader/utils/helpers/file-uploader.helpers.js +77 -0
- package/dist/es2020/modules/file-uploader/utils/helpers/file-uploader.helpers.js.map +1 -0
- package/dist/es2020/server.js +1 -1
- package/dist/es2020/server.js.map +1 -1
- package/dist/es2020/types/arkos-config.js.map +1 -1
- package/dist/es2020/types/auth.js.map +1 -1
- package/dist/es2020/types/index.js.map +1 -1
- package/dist/es2020/utils/helpers/models.helpers.js +19 -6
- package/dist/es2020/utils/helpers/models.helpers.js.map +1 -1
- package/dist/types/exports/services/index.d.ts +1 -1
- package/dist/types/modules/email/email.service.d.ts +1 -2
- package/dist/types/modules/file-uploader/file-uploader.controller.d.ts +3 -0
- package/dist/types/modules/file-uploader/file-uploader.router.d.ts +3 -0
- package/dist/types/modules/file-uploader/file-uploader.service.d.ts +30 -0
- package/dist/types/modules/file-uploader/utils/helpers/file-uploader.helpers.d.ts +2 -0
- package/dist/types/types/arkos-config.d.ts +8 -1
- package/dist/types/types/auth.d.ts +2 -2
- package/dist/types/types/index.d.ts +1 -0
- package/package.json +6 -7
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import multer from "multer";
|
|
11
|
+
import path from "path";
|
|
12
|
+
import fs from "fs";
|
|
13
|
+
import AppError from "../error-handler/utils/app-error";
|
|
14
|
+
import { promisify } from "util";
|
|
15
|
+
import { getArkosConfig } from "../../server";
|
|
16
|
+
import deepmerge from "../../utils/helpers/deepmerge.helper";
|
|
17
|
+
import { processFile, processImage, } from "./utils/helpers/file-uploader.helpers";
|
|
18
|
+
export class FileUploaderService {
|
|
19
|
+
constructor(uploadDir, fileSizeLimit = 1024 * 1024 * 5, allowedFileTypes = /.*/, maxCount = 30) {
|
|
20
|
+
this.fileFilter = (req, file, cb) => {
|
|
21
|
+
const extName = this.allowedFileTypes.test(path.extname(file.originalname).toLowerCase());
|
|
22
|
+
const mimeType = this.allowedFileTypes.test(file.mimetype);
|
|
23
|
+
if (mimeType && extName) {
|
|
24
|
+
cb(null, true);
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
cb(new AppError("Invalid file type", 400));
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
uploadDir = uploadDir.startsWith("/") ? uploadDir.substring(1) : uploadDir;
|
|
31
|
+
uploadDir = uploadDir.endsWith("/") ? uploadDir.slice(0, -1) : uploadDir;
|
|
32
|
+
this.uploadDir = path.join(".", `${uploadDir}/`);
|
|
33
|
+
this.fileSizeLimit = fileSizeLimit;
|
|
34
|
+
this.allowedFileTypes = allowedFileTypes;
|
|
35
|
+
this.maxCount = maxCount;
|
|
36
|
+
if (!fs.existsSync(this.uploadDir)) {
|
|
37
|
+
fs.mkdirSync(this.uploadDir, { recursive: true });
|
|
38
|
+
}
|
|
39
|
+
this.storage = multer.diskStorage({
|
|
40
|
+
destination: (req, file, cb) => {
|
|
41
|
+
cb(null, this.uploadDir);
|
|
42
|
+
},
|
|
43
|
+
filename: (req, file, cb) => {
|
|
44
|
+
const uniqueSuffix = Date.now() + "-" + Math.round(Math.random() * 1e9);
|
|
45
|
+
cb(null, `${uniqueSuffix}${path.extname(file.originalname)}`);
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
getUploader() {
|
|
50
|
+
return multer({
|
|
51
|
+
storage: this.storage,
|
|
52
|
+
fileFilter: this.fileFilter,
|
|
53
|
+
limits: { fileSize: this.fileSizeLimit },
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
handleSingleUpload(oldFilePath) {
|
|
57
|
+
return (req, res, next) => {
|
|
58
|
+
const upload = this.getUploader().single(this.getFieldName());
|
|
59
|
+
upload(req, res, (err) => __awaiter(this, void 0, void 0, function* () {
|
|
60
|
+
if (err instanceof multer.MulterError) {
|
|
61
|
+
return next(err);
|
|
62
|
+
}
|
|
63
|
+
else if (err) {
|
|
64
|
+
return next(err);
|
|
65
|
+
}
|
|
66
|
+
if (oldFilePath) {
|
|
67
|
+
const filePath = path.join(oldFilePath);
|
|
68
|
+
try {
|
|
69
|
+
const stats = yield promisify(fs.stat)(filePath);
|
|
70
|
+
if (stats)
|
|
71
|
+
yield promisify(fs.unlink)(filePath);
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
console.error(err);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
next();
|
|
78
|
+
}));
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
handleMultipleUpload() {
|
|
82
|
+
return (req, res, next) => {
|
|
83
|
+
const upload = this.getUploader().array(this.getFieldName(), this.maxCount);
|
|
84
|
+
upload(req, res, (err) => {
|
|
85
|
+
if (err instanceof multer.MulterError)
|
|
86
|
+
return next(err);
|
|
87
|
+
else if (err)
|
|
88
|
+
return next(err);
|
|
89
|
+
next();
|
|
90
|
+
});
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
handleDeleteSingleFile(oldFilePath) {
|
|
94
|
+
return (req, res, next) => __awaiter(this, void 0, void 0, function* () {
|
|
95
|
+
const filePath = path.join(oldFilePath);
|
|
96
|
+
try {
|
|
97
|
+
const stats = yield promisify(fs.stat)(filePath);
|
|
98
|
+
if (stats) {
|
|
99
|
+
yield promisify(fs.unlink)(filePath);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
catch (err) {
|
|
103
|
+
console.error(err);
|
|
104
|
+
}
|
|
105
|
+
next();
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
deleteFileByUrl(fileUrl) {
|
|
109
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
110
|
+
try {
|
|
111
|
+
const { fileUpload } = getArkosConfig();
|
|
112
|
+
const baseRoute = (fileUpload === null || fileUpload === void 0 ? void 0 : fileUpload.baseRoute) || "/api/uploads";
|
|
113
|
+
let urlPath;
|
|
114
|
+
if (fileUrl.startsWith("http")) {
|
|
115
|
+
const url = new URL(fileUrl);
|
|
116
|
+
urlPath = url.pathname;
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
urlPath = fileUrl;
|
|
120
|
+
}
|
|
121
|
+
const baseRouteIndex = urlPath.indexOf(baseRoute);
|
|
122
|
+
if (baseRouteIndex === -1) {
|
|
123
|
+
throw new AppError("Invalid file URL: base route not found", 400);
|
|
124
|
+
}
|
|
125
|
+
const pathAfterBaseRoute = urlPath.substring(baseRouteIndex + baseRoute.length);
|
|
126
|
+
const cleanPath = pathAfterBaseRoute.startsWith("/")
|
|
127
|
+
? pathAfterBaseRoute.substring(1)
|
|
128
|
+
: pathAfterBaseRoute;
|
|
129
|
+
const fileTypes = ["images", "videos", "documents", "files"];
|
|
130
|
+
let fileType = null;
|
|
131
|
+
let fileName = null;
|
|
132
|
+
for (const type of fileTypes) {
|
|
133
|
+
const typeIndex = cleanPath.indexOf(type + "/");
|
|
134
|
+
if (typeIndex !== -1) {
|
|
135
|
+
fileType = type;
|
|
136
|
+
fileName = cleanPath.substring(typeIndex + type.length + 1);
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if (!fileType || !fileName) {
|
|
141
|
+
throw new AppError("Unable to determine file type or file name from URL", 400);
|
|
142
|
+
}
|
|
143
|
+
const { documentUploaderService, fileUploaderService, imageUploaderService, videoUploaderService, } = getFileUploaderServices();
|
|
144
|
+
let filePath;
|
|
145
|
+
switch (fileType) {
|
|
146
|
+
case "images":
|
|
147
|
+
filePath = path.join(imageUploaderService.uploadDir, fileName);
|
|
148
|
+
break;
|
|
149
|
+
case "videos":
|
|
150
|
+
filePath = path.join(videoUploaderService.uploadDir, fileName);
|
|
151
|
+
break;
|
|
152
|
+
case "documents":
|
|
153
|
+
filePath = path.join(documentUploaderService.uploadDir, fileName);
|
|
154
|
+
break;
|
|
155
|
+
case "files":
|
|
156
|
+
filePath = path.join(fileUploaderService.uploadDir, fileName);
|
|
157
|
+
break;
|
|
158
|
+
default:
|
|
159
|
+
throw new AppError(`Unsupported file type: ${fileType}`, 400);
|
|
160
|
+
}
|
|
161
|
+
yield promisify(fs.stat)(filePath);
|
|
162
|
+
yield promisify(fs.unlink)(filePath);
|
|
163
|
+
return true;
|
|
164
|
+
}
|
|
165
|
+
catch (error) {
|
|
166
|
+
if (error instanceof AppError) {
|
|
167
|
+
throw error;
|
|
168
|
+
}
|
|
169
|
+
if (error.code === "ENOENT") {
|
|
170
|
+
throw new AppError("File not found", 404);
|
|
171
|
+
}
|
|
172
|
+
throw new AppError(`Failed to delete file: ${error.message}`, 500);
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
getFieldName() {
|
|
177
|
+
let fieldName = "files";
|
|
178
|
+
if (this.uploadDir.endsWith("images") || this.uploadDir.endsWith("images/"))
|
|
179
|
+
fieldName === "images";
|
|
180
|
+
if (this.uploadDir.endsWith("videos") || this.uploadDir.endsWith("videos/"))
|
|
181
|
+
fieldName === "videos";
|
|
182
|
+
if (this.uploadDir.endsWith("documents") ||
|
|
183
|
+
this.uploadDir.endsWith("documents/"))
|
|
184
|
+
fieldName === "documents";
|
|
185
|
+
if (this.uploadDir.endsWith("files") || this.uploadDir.endsWith("files/"))
|
|
186
|
+
fieldName === "files";
|
|
187
|
+
return fieldName;
|
|
188
|
+
}
|
|
189
|
+
upload(req_1, res_1) {
|
|
190
|
+
return __awaiter(this, arguments, void 0, function* (req, res, options = {}) {
|
|
191
|
+
const { fileUpload } = getArkosConfig();
|
|
192
|
+
const baseRoute = (fileUpload === null || fileUpload === void 0 ? void 0 : fileUpload.baseRoute) || "/api/uploads";
|
|
193
|
+
return new Promise((resolve, reject) => {
|
|
194
|
+
const isMultiple = Array.isArray(req.query.multiple)
|
|
195
|
+
? req.query.multiple[0] == "true"
|
|
196
|
+
: req.query.multiple == "true";
|
|
197
|
+
const uploadHandler = isMultiple
|
|
198
|
+
? this.getUploader().array(this.getFieldName(), this.maxCount)
|
|
199
|
+
: this.getUploader().single(this.getFieldName());
|
|
200
|
+
uploadHandler(req, res, (err) => __awaiter(this, void 0, void 0, function* () {
|
|
201
|
+
var _a;
|
|
202
|
+
if (err)
|
|
203
|
+
return reject(err);
|
|
204
|
+
try {
|
|
205
|
+
const protocol = ((_a = req.get("host")) === null || _a === void 0 ? void 0 : _a.includes("localhost"))
|
|
206
|
+
? "http"
|
|
207
|
+
: "https";
|
|
208
|
+
const baseURL = `${protocol}://${req.get("host")}`;
|
|
209
|
+
const dirParts = this.uploadDir.split("/");
|
|
210
|
+
const fileType = (this.uploadDir.endsWith("/")
|
|
211
|
+
? dirParts[dirParts.length - 2]
|
|
212
|
+
: dirParts[dirParts.length - 1]) || "files";
|
|
213
|
+
let data;
|
|
214
|
+
if (req.files && Array.isArray(req.files) && req.files.length > 0) {
|
|
215
|
+
const isImageUploader = this.uploadDir.includes("/images");
|
|
216
|
+
if (isImageUploader) {
|
|
217
|
+
data = yield Promise.all(req.files.map((file) => processImage(file.path, baseURL, baseRoute, options, fileType)));
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
data = yield Promise.all(req.files.map((file) => processFile(file.path, baseURL, baseRoute, fileType)));
|
|
221
|
+
}
|
|
222
|
+
data = data.filter((url) => url !== null);
|
|
223
|
+
}
|
|
224
|
+
else if (req.file) {
|
|
225
|
+
const isImageUploader = this.uploadDir.includes("/images");
|
|
226
|
+
if (isImageUploader) {
|
|
227
|
+
data = yield processImage(req.file.path, baseURL, baseRoute, options, fileType);
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
230
|
+
data = yield processFile(req.file.path, baseURL, baseRoute, fileType);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
return reject(new AppError("No file uploaded", 400));
|
|
235
|
+
}
|
|
236
|
+
resolve(data);
|
|
237
|
+
}
|
|
238
|
+
catch (error) {
|
|
239
|
+
reject(error);
|
|
240
|
+
}
|
|
241
|
+
}));
|
|
242
|
+
});
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
export const getFileUploaderServices = () => {
|
|
247
|
+
const { fileUpload } = getArkosConfig();
|
|
248
|
+
const baseUploadDir = (fileUpload === null || fileUpload === void 0 ? void 0 : fileUpload.baseUploadDir) || "/uploads";
|
|
249
|
+
const defaultRegexPatterns = {
|
|
250
|
+
image: /jpeg|jpg|png|gif|webp|svg|bmp|tiff|heif|heic|ico|jfif|raw|cr2|nef|orf|sr2|arw|dng|pef|raf|rw2|psd|ai|eps|xcf|jxr|wdp|hdp|jp2|j2k|jpf|jpx|jpm|mj2|avif/,
|
|
251
|
+
video: /mp4|avi|mov|mkv|flv|wmv|webm|mpg|mpeg|3gp|m4v|ts|rm|rmvb|vob|ogv|dv|qt|asf|m2ts|mts|divx|f4v|swf|mxf|roq|nsv|mvb|svi|mpe|m2v|mp2|mpv|h264|h265|hevc/,
|
|
252
|
+
document: /pdf|doc|docx|xls|xlsx|ppt|pptx|odt|ods|odg|odp|txt|rtf|csv|epub|md|tex|pages|numbers|key|xml|json|yaml|yml|ini|cfg|conf|log|html|htm|xhtml|djvu|mobi|azw|azw3|fb2|lit|ps|wpd|wps|dot|dotx|xlt|xltx|pot|potx|oft|one|onetoc2|opf|oxps|hwp/,
|
|
253
|
+
other: /.*/,
|
|
254
|
+
};
|
|
255
|
+
const defaultRestrictions = {
|
|
256
|
+
images: {
|
|
257
|
+
maxCount: 30,
|
|
258
|
+
maxSize: 1024 * 1024 * 15,
|
|
259
|
+
supportedFilesRegex: defaultRegexPatterns.image,
|
|
260
|
+
},
|
|
261
|
+
videos: {
|
|
262
|
+
maxCount: 10,
|
|
263
|
+
maxSize: 1024 * 1024 * 5096,
|
|
264
|
+
supportedFilesRegex: defaultRegexPatterns.video,
|
|
265
|
+
},
|
|
266
|
+
documents: {
|
|
267
|
+
maxCount: 30,
|
|
268
|
+
maxSize: 1024 * 1024 * 50,
|
|
269
|
+
supportedFilesRegex: defaultRegexPatterns.document,
|
|
270
|
+
},
|
|
271
|
+
others: {
|
|
272
|
+
maxCount: 10,
|
|
273
|
+
maxSize: 1024 * 1024 * 5096,
|
|
274
|
+
supportedFilesRegex: defaultRegexPatterns.other,
|
|
275
|
+
},
|
|
276
|
+
};
|
|
277
|
+
const restrictions = (fileUpload === null || fileUpload === void 0 ? void 0 : fileUpload.restrictions)
|
|
278
|
+
? deepmerge(defaultRestrictions, fileUpload.restrictions)
|
|
279
|
+
: defaultRestrictions;
|
|
280
|
+
const imageUploaderService = new FileUploaderService(`${baseUploadDir}/images`, restrictions.images.maxSize, restrictions.images.supportedFilesRegex, restrictions.images.maxCount);
|
|
281
|
+
const videoUploaderService = new FileUploaderService(`${baseUploadDir}/videos`, restrictions.videos.maxSize, restrictions.videos.supportedFilesRegex, restrictions.videos.maxCount);
|
|
282
|
+
const documentUploaderService = new FileUploaderService(`${baseUploadDir}/documents`, restrictions.documents.maxSize, restrictions.documents.supportedFilesRegex, restrictions.documents.maxCount);
|
|
283
|
+
const fileUploaderService = new FileUploaderService(`${baseUploadDir}/files`, restrictions.others.maxSize, restrictions.others.supportedFilesRegex, restrictions.others.maxCount);
|
|
284
|
+
return {
|
|
285
|
+
imageUploaderService,
|
|
286
|
+
videoUploaderService,
|
|
287
|
+
documentUploaderService,
|
|
288
|
+
fileUploaderService,
|
|
289
|
+
};
|
|
290
|
+
};
|
|
291
|
+
//# sourceMappingURL=file-uploader.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-uploader.service.js","sourceRoot":"","sources":["../../../../src/modules/file-uploader/file-uploader.service.ts"],"names":[],"mappings":"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","sourcesContent":["import multer, { StorageEngine } from \"multer\";\nimport path from \"path\";\nimport fs from \"fs\";\nimport { NextFunction } from \"express\";\nimport AppError from \"../error-handler/utils/app-error\";\nimport { promisify } from \"util\";\nimport { getArkosConfig } from \"../../server\";\nimport deepmerge from \"../../utils/helpers/deepmerge.helper\";\nimport { ArkosRequest, ArkosResponse } from \"../../types\";\nimport {\n processFile,\n processImage,\n} from \"./utils/helpers/file-uploader.helpers\";\n\n/**\n * Service to handle file uploads, including single and multiple file uploads,\n * file validation (type, size), and file deletion.\n */\nexport class FileUploaderService {\n private uploadDir: string;\n private fileSizeLimit: number;\n private allowedFileTypes: RegExp;\n private storage: StorageEngine;\n private maxCount: number;\n\n /**\n * Constructor to initialize the file uploader service.\n * @param {string} uploadDir - The directory where files will be uploaded.\n * @param {number} fileSizeLimit - The maximum allowed file size.\n * @param {RegExp} allowedFileTypes - The regular expression for allowed file types.\n */\n constructor(\n uploadDir: string,\n fileSizeLimit: number = 1024 * 1024 * 5,\n allowedFileTypes: RegExp = /.*/,\n maxCount: number = 30\n ) {\n uploadDir = uploadDir.startsWith(\"/\") ? uploadDir.substring(1) : uploadDir;\n uploadDir = uploadDir.endsWith(\"/\") ? uploadDir.slice(0, -1) : uploadDir;\n\n this.uploadDir = path.join(\".\", `${uploadDir}/`);\n this.fileSizeLimit = fileSizeLimit;\n this.allowedFileTypes = allowedFileTypes;\n this.maxCount = maxCount;\n\n if (!fs.existsSync(this.uploadDir)) {\n fs.mkdirSync(this.uploadDir, { recursive: true });\n }\n\n this.storage = multer.diskStorage({\n destination: (req, file, cb) => {\n cb(null, this.uploadDir);\n },\n filename: (req, file, cb) => {\n const uniqueSuffix = Date.now() + \"-\" + Math.round(Math.random() * 1e9);\n cb(null, `${uniqueSuffix}${path.extname(file.originalname)}`);\n },\n });\n }\n\n /**\n * Validates the file's type and MIME type.\n * @param {Request} req - The Express request object.\n * @param {Express.Multer.File} file - The uploaded file.\n * @param {Function} cb - The callback function to indicate if file is valid.\n */\n private fileFilter = (req: any, file: any, cb: any) => {\n const extName = this.allowedFileTypes.test(\n path.extname(file.originalname).toLowerCase()\n );\n const mimeType = this.allowedFileTypes.test(file.mimetype);\n\n if (mimeType && extName) {\n cb(null, true);\n } else {\n cb(new AppError(\"Invalid file type\", 400));\n }\n };\n\n /**\n * Returns the multer upload configuration.\n * @returns {multer.Instance} The multer instance configured for file uploads.\n */\n public getUploader() {\n return multer({\n storage: this.storage,\n fileFilter: this.fileFilter,\n limits: { fileSize: this.fileSizeLimit },\n });\n }\n\n /**\n * Middleware to handle single file upload.\n * @param {string} [oldFilePath] - The path to the file to delete before uploading.\n * @returns {Function} Middleware function for handling file upload.\n */\n public handleSingleUpload(oldFilePath?: string) {\n return (req: ArkosRequest, res: ArkosResponse, next: NextFunction) => {\n const upload = this.getUploader().single(this.getFieldName());\n upload(req, res, async (err) => {\n if (err instanceof multer.MulterError) {\n return next(err);\n } else if (err) {\n return next(err);\n }\n\n if (oldFilePath) {\n const filePath = path.join(oldFilePath);\n try {\n const stats = await promisify(fs.stat)(filePath);\n if (stats) await promisify(fs.unlink)(filePath);\n } catch (err) {\n console.error(err);\n }\n }\n\n next();\n });\n };\n }\n\n /**\n * Middleware to handle multiple file uploads.\n * @param {number} maxCount - The maximum number of files allowed for upload.\n * @returns {Function} Middleware function for handling multiple file uploads.\n */\n public handleMultipleUpload() {\n return (req: ArkosRequest, res: ArkosResponse, next: NextFunction) => {\n const upload = this.getUploader().array(\n this.getFieldName(),\n this.maxCount\n );\n upload(req, res, (err) => {\n if (err instanceof multer.MulterError) return next(err);\n else if (err) return next(err);\n next();\n });\n };\n }\n\n /**\n * Middleware to handle deletion of a single file from the filesystem.\n * @param {string} oldFilePath - The path to the file to be deleted.\n * @returns {Function} Middleware function for handling file deletion.\n */\n public handleDeleteSingleFile(oldFilePath: string) {\n return async (\n req: ArkosRequest,\n res: ArkosResponse,\n next: NextFunction\n ) => {\n const filePath = path.join(oldFilePath);\n try {\n const stats = await promisify(fs.stat)(filePath);\n if (stats) {\n await promisify(fs.unlink)(filePath);\n }\n } catch (err) {\n console.error(err);\n }\n\n next();\n };\n }\n\n /**\n * Deletes a file based on its URL by identifying the appropriate uploader service\n * @param {string} fileUrl - The URL of the file to delete\n * @returns {Promise<boolean>} - True if deletion successful, false otherwise\n */\n public async deleteFileByUrl(fileUrl: string): Promise<boolean> {\n try {\n // Get configuration values\n const { fileUpload } = getArkosConfig();\n const baseRoute = fileUpload?.baseRoute || \"/api/uploads\";\n\n // Parse the URL to get the path\n let urlPath: string;\n if (fileUrl.startsWith(\"http\")) {\n const url = new URL(fileUrl);\n urlPath = url.pathname;\n } else {\n urlPath = fileUrl;\n }\n\n // Extract the path after the base route\n const baseRouteIndex = urlPath.indexOf(baseRoute);\n if (baseRouteIndex === -1) {\n throw new AppError(\"Invalid file URL: base route not found\", 400);\n }\n\n const pathAfterBaseRoute = urlPath.substring(\n baseRouteIndex + baseRoute.length\n );\n const cleanPath = pathAfterBaseRoute.startsWith(\"/\")\n ? pathAfterBaseRoute.substring(1)\n : pathAfterBaseRoute;\n\n // Determine file type and file name\n const fileTypes = [\"images\", \"videos\", \"documents\", \"files\"];\n let fileType: string | null = null;\n let fileName: string | null = null;\n\n for (const type of fileTypes) {\n const typeIndex = cleanPath.indexOf(type + \"/\");\n if (typeIndex !== -1) {\n fileType = type;\n fileName = cleanPath.substring(typeIndex + type.length + 1);\n break;\n }\n }\n\n if (!fileType || !fileName) {\n throw new AppError(\n \"Unable to determine file type or file name from URL\",\n 400\n );\n }\n\n // Get the appropriate uploader service based on file type\n const {\n documentUploaderService,\n fileUploaderService,\n imageUploaderService,\n videoUploaderService,\n } = getFileUploaderServices();\n\n let filePath: string;\n switch (fileType) {\n case \"images\":\n filePath = path.join(imageUploaderService.uploadDir, fileName);\n break;\n case \"videos\":\n filePath = path.join(videoUploaderService.uploadDir, fileName);\n break;\n case \"documents\":\n filePath = path.join(documentUploaderService.uploadDir, fileName);\n break;\n case \"files\":\n filePath = path.join(fileUploaderService.uploadDir, fileName);\n break;\n default:\n throw new AppError(`Unsupported file type: ${fileType}`, 400);\n }\n\n // Delete the file\n\n await promisify(fs.stat)(filePath);\n await promisify(fs.unlink)(filePath);\n\n return true;\n } catch (error: any) {\n if (error instanceof AppError) {\n throw error;\n }\n\n if (error.code === \"ENOENT\") {\n throw new AppError(\"File not found\", 404);\n }\n\n throw new AppError(`Failed to delete file: ${error.message}`, 500);\n }\n }\n\n private getFieldName() {\n let fieldName = \"files\";\n if (this.uploadDir.endsWith(\"images\") || this.uploadDir.endsWith(\"images/\"))\n fieldName === \"images\";\n if (this.uploadDir.endsWith(\"videos\") || this.uploadDir.endsWith(\"videos/\"))\n fieldName === \"videos\";\n if (\n this.uploadDir.endsWith(\"documents\") ||\n this.uploadDir.endsWith(\"documents/\")\n )\n fieldName === \"documents\";\n if (this.uploadDir.endsWith(\"files\") || this.uploadDir.endsWith(\"files/\"))\n fieldName === \"files\";\n return fieldName;\n }\n\n /**\n * Handles the upload process and returns the full URLs of uploaded files\n * @param {ArkosRequest} req - Arkos request object containing the files\n * @param {ArkosResponse} res - Arkos response object\n * @param {object} options - Optional parameters for image processing\n * @returns {Promise<string|string[]>} URL or array of URLs to the uploaded files\n */\n public async upload(\n req: ArkosRequest,\n res: ArkosResponse,\n options: {\n format?: string;\n width?: number;\n height?: number;\n resizeTo?: number;\n } = {}\n ): Promise<string | string[] | null> {\n const { fileUpload } = getArkosConfig();\n const baseRoute = fileUpload?.baseRoute || \"/api/uploads\";\n\n return new Promise((resolve, reject) => {\n // Determine if it's a single or multiple file upload\n const isMultiple = Array.isArray(req.query.multiple)\n ? req.query.multiple[0] == \"true\"\n : req.query.multiple == \"true\";\n\n // Use appropriate upload handler\n const uploadHandler = isMultiple\n ? this.getUploader().array(this.getFieldName(), this.maxCount)\n : this.getUploader().single(this.getFieldName());\n\n uploadHandler(req, res, async (err) => {\n if (err) return reject(err);\n\n try {\n // Determine the base URL for file access\n const protocol = req.get(\"host\")?.includes(\"localhost\")\n ? \"http\"\n : \"https\";\n const baseURL = `${protocol}://${req.get(\"host\")}`;\n\n // Get file type from uploadDir path\n const dirParts = this.uploadDir.split(\"/\");\n const fileType =\n (this.uploadDir.endsWith(\"/\")\n ? dirParts[dirParts.length - 2]\n : dirParts[dirParts.length - 1]) || \"files\";\n\n // Process all uploaded files\n let data;\n if (req.files && Array.isArray(req.files) && req.files.length > 0) {\n // Process multiple files\n const isImageUploader = this.uploadDir.includes(\"/images\");\n if (isImageUploader) {\n data = await Promise.all(\n req.files.map((file) =>\n processImage(file.path, baseURL, baseRoute, options, fileType)\n )\n );\n } else {\n data = await Promise.all(\n req.files.map((file) =>\n processFile(file.path, baseURL, baseRoute, fileType)\n )\n );\n }\n // Filter out any null values from failed processing\n data = data.filter((url) => url !== null);\n } else if (req.file) {\n // Process a single file\n const isImageUploader = this.uploadDir.includes(\"/images\");\n // console.log(req.file.path, baseURL, baseRoute, options, fileType);\n if (isImageUploader) {\n data = await processImage(\n req.file.path,\n baseURL,\n baseRoute,\n options,\n fileType\n );\n } else {\n data = await processFile(\n req.file.path,\n baseURL,\n baseRoute,\n fileType\n );\n }\n } else {\n return reject(new AppError(\"No file uploaded\", 400));\n }\n\n resolve(data);\n } catch (error) {\n reject(error);\n }\n });\n });\n }\n}\n\n/**\n * Creates and returns all file uploader services based on config\n * @returns Object containing all specialized file uploader services\n */\nexport const getFileUploaderServices = () => {\n const { fileUpload } = getArkosConfig();\n const baseUploadDir = fileUpload?.baseUploadDir || \"/uploads\";\n\n // Default regex patterns for each file type\n const defaultRegexPatterns = {\n image:\n /jpeg|jpg|png|gif|webp|svg|bmp|tiff|heif|heic|ico|jfif|raw|cr2|nef|orf|sr2|arw|dng|pef|raf|rw2|psd|ai|eps|xcf|jxr|wdp|hdp|jp2|j2k|jpf|jpx|jpm|mj2|avif/,\n video:\n /mp4|avi|mov|mkv|flv|wmv|webm|mpg|mpeg|3gp|m4v|ts|rm|rmvb|vob|ogv|dv|qt|asf|m2ts|mts|divx|f4v|swf|mxf|roq|nsv|mvb|svi|mpe|m2v|mp2|mpv|h264|h265|hevc/,\n document:\n /pdf|doc|docx|xls|xlsx|ppt|pptx|odt|ods|odg|odp|txt|rtf|csv|epub|md|tex|pages|numbers|key|xml|json|yaml|yml|ini|cfg|conf|log|html|htm|xhtml|djvu|mobi|azw|azw3|fb2|lit|ps|wpd|wps|dot|dotx|xlt|xltx|pot|potx|oft|one|onetoc2|opf|oxps|hwp/,\n other: /.*/,\n };\n\n // Default upload restrictions\n const defaultRestrictions = {\n images: {\n maxCount: 30,\n maxSize: 1024 * 1024 * 15, // 15 MB\n supportedFilesRegex: defaultRegexPatterns.image,\n },\n videos: {\n maxCount: 10,\n maxSize: 1024 * 1024 * 5096, // 5 GB\n supportedFilesRegex: defaultRegexPatterns.video,\n },\n documents: {\n maxCount: 30,\n maxSize: 1024 * 1024 * 50, // 50 MB\n supportedFilesRegex: defaultRegexPatterns.document,\n },\n others: {\n maxCount: 10,\n maxSize: 1024 * 1024 * 5096, // 5 GB\n supportedFilesRegex: defaultRegexPatterns.other,\n },\n };\n\n // Merge with user configuration (if any)\n const restrictions = fileUpload?.restrictions\n ? deepmerge(defaultRestrictions, fileUpload.restrictions)\n : defaultRestrictions;\n\n /**\n * Specialized file uploader service for handling image uploads.\n */\n const imageUploaderService = new FileUploaderService(\n `${baseUploadDir}/images`,\n restrictions.images.maxSize,\n restrictions.images.supportedFilesRegex,\n restrictions.images.maxCount\n );\n\n /**\n * Specialized file uploader service for handling video uploads.\n */\n const videoUploaderService = new FileUploaderService(\n `${baseUploadDir}/videos`,\n restrictions.videos.maxSize,\n restrictions.videos.supportedFilesRegex,\n restrictions.videos.maxCount\n );\n\n /**\n * Specialized file uploader service for handling document uploads.\n */\n const documentUploaderService = new FileUploaderService(\n `${baseUploadDir}/documents`,\n restrictions.documents.maxSize,\n restrictions.documents.supportedFilesRegex,\n restrictions.documents.maxCount\n );\n\n /**\n * Generic file uploader service for handling all file uploads.\n */\n const fileUploaderService = new FileUploaderService(\n `${baseUploadDir}/files`,\n restrictions.others.maxSize,\n restrictions.others.supportedFilesRegex,\n restrictions.others.maxCount\n );\n\n return {\n imageUploaderService,\n videoUploaderService,\n documentUploaderService,\n fileUploaderService,\n };\n};\n"]}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import fs from "fs";
|
|
11
|
+
import path from "path";
|
|
12
|
+
import sharp from "sharp";
|
|
13
|
+
import { promisify } from "util";
|
|
14
|
+
import { getArkosConfig } from "../../../../server";
|
|
15
|
+
import mimetype from "mimetype";
|
|
16
|
+
const generateRelativePath = (filePath, fileType) => {
|
|
17
|
+
const { fileUpload } = getArkosConfig();
|
|
18
|
+
const baseUploadDir = (fileUpload === null || fileUpload === void 0 ? void 0 : fileUpload.baseUploadDir) || "/uploads";
|
|
19
|
+
if (baseUploadDir.startsWith("..")) {
|
|
20
|
+
return path.join(fileType, path.basename(filePath));
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
return (`${fileType}/` + filePath.replace(`${process.cwd()}${baseUploadDir}/`, ""));
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
export const processFile = (filePath, baseURL, baseRoute, fileType) => __awaiter(void 0, void 0, void 0, function* () {
|
|
27
|
+
const relativePath = generateRelativePath(filePath, fileType);
|
|
28
|
+
return `${baseURL}${baseRoute}/${relativePath}`;
|
|
29
|
+
});
|
|
30
|
+
export const processImage = (filePath, baseURL, baseRoute, options, fileType) => __awaiter(void 0, void 0, void 0, function* () {
|
|
31
|
+
var _a;
|
|
32
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
33
|
+
const originalFormat = ext.replace(".", "");
|
|
34
|
+
const outputFormat = options.format || originalFormat;
|
|
35
|
+
if (!((_a = mimetype.lookup(ext)) === null || _a === void 0 ? void 0 : _a.includes("image"))) {
|
|
36
|
+
const relativePath = generateRelativePath(filePath, fileType);
|
|
37
|
+
return `${baseURL}${baseRoute}/${relativePath}`;
|
|
38
|
+
}
|
|
39
|
+
const tempName = `${path.basename(filePath, ext)}_${Date.now()}${ext}`;
|
|
40
|
+
const tempPath = path.join(path.dirname(filePath), tempName);
|
|
41
|
+
try {
|
|
42
|
+
let transformer = sharp(filePath);
|
|
43
|
+
const metadata = yield transformer.metadata();
|
|
44
|
+
if (options.resizeTo && metadata.width && metadata.height) {
|
|
45
|
+
const targetSize = options.resizeTo;
|
|
46
|
+
const scaleFactor = targetSize / Math.min(metadata.width, metadata.height);
|
|
47
|
+
const newWidth = Math.round(metadata.width * scaleFactor);
|
|
48
|
+
const newHeight = Math.round(metadata.height * scaleFactor);
|
|
49
|
+
transformer = transformer.resize(newWidth, newHeight);
|
|
50
|
+
}
|
|
51
|
+
else if (options.width || options.height) {
|
|
52
|
+
transformer = transformer.resize(options.width || null, options.height || null, {
|
|
53
|
+
fit: "inside",
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
if (outputFormat === "webp") {
|
|
57
|
+
transformer = transformer.toFormat("webp");
|
|
58
|
+
}
|
|
59
|
+
else if (outputFormat === "jpeg" || outputFormat === "jpg") {
|
|
60
|
+
transformer = transformer.toFormat("jpeg");
|
|
61
|
+
}
|
|
62
|
+
yield transformer.toFile(tempPath);
|
|
63
|
+
yield promisify(fs.rename)(tempPath, filePath);
|
|
64
|
+
const relativePath = generateRelativePath(filePath, fileType);
|
|
65
|
+
return `${baseURL}${baseRoute}/${relativePath}`;
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
try {
|
|
69
|
+
yield promisify(fs.stat)(tempPath);
|
|
70
|
+
yield promisify(fs.unlink)(tempPath);
|
|
71
|
+
}
|
|
72
|
+
catch (err) {
|
|
73
|
+
}
|
|
74
|
+
throw error;
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
//# sourceMappingURL=file-uploader.helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-uploader.helpers.js","sourceRoot":"","sources":["../../../../../../src/modules/file-uploader/utils/helpers/file-uploader.helpers.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AACjC,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,QAAQ,MAAM,UAAU,CAAC;AAKhC,MAAM,oBAAoB,GAAG,CAAC,QAAgB,EAAE,QAAgB,EAAE,EAAE;IAClE,MAAM,EAAE,UAAU,EAAE,GAAG,cAAc,EAAE,CAAC;IAExC,MAAM,aAAa,GAAG,CAAA,UAAU,aAAV,UAAU,uBAAV,UAAU,CAAE,aAAa,KAAI,UAAU,CAAC;IAC9D,IAAI,aAAa,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QAEnC,OAAO,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;IACtD,CAAC;SAAM,CAAC;QAEN,OAAO,CACL,GAAG,QAAQ,GAAG,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,GAAG,EAAE,GAAG,aAAa,GAAG,EAAE,EAAE,CAAC,CAC3E,CAAC;IACJ,CAAC;AACH,CAAC,CAAC;AAKF,MAAM,CAAC,MAAM,WAAW,GAAG,CACzB,QAAgB,EAChB,OAAe,EACf,SAAiB,EACjB,QAAgB,EACC,EAAE;IACnB,MAAM,YAAY,GAAG,oBAAoB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC9D,OAAO,GAAG,OAAO,GAAG,SAAS,IAAI,YAAY,EAAE,CAAC;AAClD,CAAC,CAAA,CAAC;AAKF,MAAM,CAAC,MAAM,YAAY,GAAG,CAC1B,QAAgB,EAChB,OAAe,EACf,SAAiB,EACjB,OAA4B,EAC5B,QAAgB,EACQ,EAAE;;IAC1B,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;IACjD,MAAM,cAAc,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IAC5C,MAAM,YAAY,GAAG,OAAO,CAAC,MAAM,IAAI,cAAc,CAAC;IAEtD,IAAI,CAAC,CAAA,MAAA,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,0CAAE,QAAQ,CAAC,OAAO,CAAC,CAAA,EAAE,CAAC;QAC7C,MAAM,YAAY,GAAG,oBAAoB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAC9D,OAAO,GAAG,OAAO,GAAG,SAAS,IAAI,YAAY,EAAE,CAAC;IAClD,CAAC;IAGD,MAAM,QAAQ,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,GAAG,CAAC,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,GAAG,EAAE,CAAC;IACvE,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,CAAC;IAE7D,IAAI,CAAC;QACH,IAAI,WAAW,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC;QAClC,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,QAAQ,EAAE,CAAC;QAG9C,IAAI,OAAO,CAAC,QAAQ,IAAI,QAAQ,CAAC,KAAK,IAAI,QAAQ,CAAC,MAAM,EAAE,CAAC;YAC1D,MAAM,UAAU,GAAG,OAAO,CAAC,QAAQ,CAAC;YACpC,MAAM,WAAW,GACf,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;YACzD,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,GAAG,WAAW,CAAC,CAAC;YAC1D,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,GAAG,WAAW,CAAC,CAAC;YAC5D,WAAW,GAAG,WAAW,CAAC,MAAM,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QACxD,CAAC;aAAM,IAAI,OAAO,CAAC,KAAK,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YAC3C,WAAW,GAAG,WAAW,CAAC,MAAM,CAC9B,OAAO,CAAC,KAAK,IAAI,IAAI,EACrB,OAAO,CAAC,MAAM,IAAI,IAAI,EACtB;gBACE,GAAG,EAAE,QAAQ;aACd,CACF,CAAC;QACJ,CAAC;QAGD,IAAI,YAAY,KAAK,MAAM,EAAE,CAAC;YAC5B,WAAW,GAAG,WAAW,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC7C,CAAC;aAAM,IAAI,YAAY,KAAK,MAAM,IAAI,YAAY,KAAK,KAAK,EAAE,CAAC;YAC7D,WAAW,GAAG,WAAW,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC7C,CAAC;QAGD,MAAM,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAGnC,MAAM,SAAS,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAG/C,MAAM,YAAY,GAAG,oBAAoB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAG9D,OAAO,GAAG,OAAO,GAAG,SAAS,IAAI,YAAY,EAAE,CAAC;IAClD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAEf,IAAI,CAAC;YACH,MAAM,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC;YACnC,MAAM,SAAS,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC;QACvC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;QAEf,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC,CAAA,CAAC","sourcesContent":["import fs from \"fs\";\nimport path from \"path\";\nimport sharp from \"sharp\";\nimport { promisify } from \"util\";\nimport { getArkosConfig } from \"../../../../server\";\nimport mimetype from \"mimetype\";\n\n/**\n * Generates the correct relative path regardless of upload directory location\n */\nconst generateRelativePath = (filePath: string, fileType: string) => {\n const { fileUpload } = getArkosConfig();\n\n const baseUploadDir = fileUpload?.baseUploadDir || \"/uploads\";\n if (baseUploadDir.startsWith(\"..\")) {\n // For paths outside project directory\n return path.join(fileType, path.basename(filePath));\n } else {\n // For paths within project\n return (\n `${fileType}/` + filePath.replace(`${process.cwd()}${baseUploadDir}/`, \"\")\n );\n }\n};\n\n/**\n * Handles basic file processing for non-image files\n */\nexport const processFile = async (\n filePath: string,\n baseURL: string,\n baseRoute: string,\n fileType: string\n): Promise<string> => {\n const relativePath = generateRelativePath(filePath, fileType);\n return `${baseURL}${baseRoute}/${relativePath}`;\n};\n\n/**\n * Processes image files using Sharp for resizing and format conversion\n */\nexport const processImage = async (\n filePath: string,\n baseURL: string,\n baseRoute: string,\n options: Record<string, any>,\n fileType: string\n): Promise<string | null> => {\n const ext = path.extname(filePath).toLowerCase();\n const originalFormat = ext.replace(\".\", \"\");\n const outputFormat = options.format || originalFormat;\n\n if (!mimetype.lookup(ext)?.includes(\"image\")) {\n const relativePath = generateRelativePath(filePath, fileType);\n return `${baseURL}${baseRoute}/${relativePath}`;\n }\n\n // Create a temp filename with original name + random string\n const tempName = `${path.basename(filePath, ext)}_${Date.now()}${ext}`;\n const tempPath = path.join(path.dirname(filePath), tempName);\n\n try {\n let transformer = sharp(filePath);\n const metadata = await transformer.metadata();\n\n // Apply resize transformations if requested\n if (options.resizeTo && metadata.width && metadata.height) {\n const targetSize = options.resizeTo;\n const scaleFactor =\n targetSize / Math.min(metadata.width, metadata.height);\n const newWidth = Math.round(metadata.width * scaleFactor);\n const newHeight = Math.round(metadata.height * scaleFactor);\n transformer = transformer.resize(newWidth, newHeight);\n } else if (options.width || options.height) {\n transformer = transformer.resize(\n options.width || null,\n options.height || null,\n {\n fit: \"inside\",\n }\n );\n }\n\n // Apply format transformations if requested\n if (outputFormat === \"webp\") {\n transformer = transformer.toFormat(\"webp\");\n } else if (outputFormat === \"jpeg\" || outputFormat === \"jpg\") {\n transformer = transformer.toFormat(\"jpeg\");\n }\n\n // Save to temp file first\n await transformer.toFile(tempPath);\n\n // Rename temp file to original filename\n await promisify(fs.rename)(tempPath, filePath);\n\n // Return the public URL for the file\n const relativePath = generateRelativePath(filePath, fileType);\n\n // console.log(`${baseURL}${baseRoute}/${relativePath}`);\n return `${baseURL}${baseRoute}/${relativePath}`;\n } catch (error) {\n // Clean up temp file if it exists\n try {\n await promisify(fs.stat)(tempPath);\n await promisify(fs.unlink)(tempPath);\n } catch (err) {\n // If temp file doesn't exist, no need to clean up\n }\n throw error;\n }\n};\n"]}
|
package/dist/es2020/server.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var x=function(e,o,n,i){function a(r){return r instanceof n?r:new n(function(c){c(r)})}return new(n||(n=Promise))(function(r,c){function f(t){try{
|
|
1
|
+
"use strict";var x=function(e,o,n,i){function a(r){return r instanceof n?r:new n(function(c){c(r)})}return new(n||(n=Promise))(function(r,c){function f(t){try{l(i.next(t))}catch(u){c(u)}}function d(t){try{l(i.throw(t))}catch(u){c(u)}}function l(t){t.done?r(t.value):a(t.value).then(f,d)}l((i=i.apply(e,o||[])).next())})};import{bootstrap as E}from"./app";import h from"./utils/helpers/deepmerge.helper";process.on("uncaughtException",e=>{console.error("UNCAUGHT EXCEPTION! SHUTTING DOWN..."),console.error(e.name,e.message),console.error(e),process.exit(1)});let m,p,s={welcomeMessage:"Welcome to our RESTful API generated by Arkos, find out more about Arkos at www.arkosjs.com",port:8e3};function N(){return x(this,arguments,void 0,function*(e={}){s=h(s,e);const o=s.port;return p=yield E(s),o&&(m=p.listen(e?.host?[o,e?.host]:o,()=>{const n=new Date().toTimeString().split(" ")[0];console.info(`[\x1B[32mREADY\x1B[0m] \x1B[90m${n}\x1B[0m App running on port \x1B[33m${o}\x1B[0m, server waiting on http://localhost:${o}`),process.env.NODE_ENV&&console.log(`${`Environment: ${process.env.NODE_ENV}`}`)})),p})}process.on("unhandledRejection",e=>{console.error("UNHANDLED REJECTION! SHUTTING DOWN..."),console.error(e.name,e.message),m.close(()=>{process.exit(1)})});export function getArkosConfig(){return s}export function getExpressApp(){return p}export{m as server,N as initApp};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/server.ts"],"names":[],"mappings":";;;;;;;;;AAGA,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAElC,OAAO,SAAS,MAAM,kCAAkC,CAAC;AAEzD,OAAO,CAAC,EAAE,CAAC,mBAAmB,EAAE,CAAC,GAAG,EAAE,EAAE;IACtC,OAAO,CAAC,KAAK,CAAC,sCAAsC,CAAC,CAAC;IACtD,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;IACrC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACnB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC;AAEH,IAAI,MAA6D,CAAC;AAClE,IAAI,IAAa,CAAC;AAClB,IAAI,YAAY,GAAgB;IAC9B,cAAc,EACZ,6FAA6F;IAC/F,IAAI,EAAE,
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/server.ts"],"names":[],"mappings":";;;;;;;;;AAGA,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAElC,OAAO,SAAS,MAAM,kCAAkC,CAAC;AAEzD,OAAO,CAAC,EAAE,CAAC,mBAAmB,EAAE,CAAC,GAAG,EAAE,EAAE;IACtC,OAAO,CAAC,KAAK,CAAC,sCAAsC,CAAC,CAAC;IACtD,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;IACrC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACnB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC;AAEH,IAAI,MAA6D,CAAC;AAClE,IAAI,IAAa,CAAC;AAClB,IAAI,YAAY,GAAgB;IAC9B,cAAc,EACZ,6FAA6F;IAC/F,IAAI,EAAE,IAAI;CACX,CAAC;AAeF,SAAe,OAAO;yDAAC,cAA2B,EAAE;QAClD,YAAY,GAAG,SAAS,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC;QAEpD,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,CAAC;QAC/B,IAAI,GAAG,MAAM,SAAS,CAAC,YAAY,CAAC,CAAC;QAErC,IAAI,IAAI;YACN,MAAM,GAAG,IAAI,CAAC,MAAM,CAClB,CAAA,WAAW,aAAX,WAAW,uBAAX,WAAW,CAAE,IAAI,EAAC,CAAC,CAAC,CAAC,IAAI,EAAE,WAAW,aAAX,WAAW,uBAAX,WAAW,CAAE,IAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EACrD,GAAG,EAAE;gBACH,MAAM,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC,YAAY,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;gBACrD,OAAO,CAAC,IAAI,CACV,kCAAkC,IAAI,uCAAuC,IAAI,+CAA+C,IAAI,EAAE,CACvI,CAAC;gBAEF,IAAI,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ;oBACxB,OAAO,CAAC,GAAG,CAAC,GAAG,gBAAgB,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;YAC7D,CAAC,CACF,CAAC;QAEJ,OAAO,IAAI,CAAC;IACd,CAAC;CAAA;AAED,OAAO,CAAC,EAAE,CAAC,oBAAoB,EAAE,CAAC,GAAa,EAAE,EAAE;IACjD,OAAO,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAC;IACvD,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;IACrC,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE;QAChB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,MAAM,UAAU,cAAc;IAC5B,OAAO,YAAY,CAAC;AACtB,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,OAAO,IAAI,CAAC;AACd,CAAC;AAED,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC","sourcesContent":["import { IncomingMessage, Server, ServerResponse } from \"http\";\nimport AppError from \"./modules/error-handler/utils/app-error\";\nimport { Express } from \"express\";\nimport { bootstrap } from \"./app\";\nimport { ArkosConfig } from \"./types/arkos-config\";\nimport deepmerge from \"./utils/helpers/deepmerge.helper\";\n\nprocess.on(\"uncaughtException\", (err) => {\n console.error(\"UNCAUGHT EXCEPTION! SHUTTING DOWN...\");\n console.error(err.name, err.message);\n console.error(err);\n process.exit(1);\n});\n\nlet server: Server<typeof IncomingMessage, typeof ServerResponse>;\nlet _app: Express;\nlet _arkosConfig: ArkosConfig = {\n welcomeMessage:\n \"Welcome to our RESTful API generated by Arkos, find out more about Arkos at www.arkosjs.com\",\n port: 8000,\n};\n\n/**\n * Initializes the application server.\n *\n * This function starts the server by listening on a specified port.\n * The port is determined by the following order of precedence:\n * 1. The `port` argument passed to the function.\n * 2. Defaults to `8000` if neither is provided.\n *\n * @param {ArkosConfig} arkosConfig - initial configs for the api ( authentication, port).\n * @returns {Promise<Express>} This function returns the Express App after all middlewares configurations.\n * You can prevent it from listen py passing port as undefined\n *\n */\nasync function initApp(arkosConfig: ArkosConfig = {}): Promise<Express> {\n _arkosConfig = deepmerge(_arkosConfig, arkosConfig);\n\n const port = _arkosConfig.port;\n _app = await bootstrap(_arkosConfig);\n\n if (port)\n server = _app.listen(\n arkosConfig?.host ? [port, arkosConfig?.host!] : port,\n () => {\n const time = new Date().toTimeString().split(\" \")[0];\n console.info(\n `[\\x1b[32mREADY\\x1b[0m] \\x1b[90m${time}\\x1b[0m App running on port \\x1b[33m${port}\\x1b[0m, server waiting on http://localhost:${port}`\n );\n\n if (!!process.env.NODE_ENV)\n console.log(`${`Environment: ${process.env.NODE_ENV}`}`);\n }\n );\n\n return _app;\n}\n\nprocess.on(\"unhandledRejection\", (err: AppError) => {\n console.error(\"UNHANDLED REJECTION! SHUTTING DOWN...\");\n console.error(err.name, err.message);\n server.close(() => {\n process.exit(1);\n });\n});\n\nexport function getArkosConfig() {\n return _arkosConfig;\n}\n\nexport function getExpressApp() {\n return _app;\n}\n\nexport { server, initApp };\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"arkos-config.js","sourceRoot":"","sources":["../../../src/types/arkos-config.ts"],"names":[],"mappings":"","sourcesContent":["import cors from \"cors\";\nimport express from \"express\";\nimport { Options as RateLimitOptions } from \"express-rate-limit\";\nimport cookieParser from \"cookie-parser\";\nimport compression from \"compression\";\nimport { Options as QueryParserOptions } from \"../utils/helpers/query-parser.helpers\";\nimport { ValidatorOptions } from \"class-validator\";\n\n/**\n * Defines the initial configs of the api to be loaded at startup when arkos.init() is called.\n */\nexport type ArkosConfig = {\n /** Message you would like to send, as Json and 200 response when\n * ```\n * GET /api\n * ```\n * ```json\n * { \"message\": \"Welcome to YourAppName\" }\n * ```\n *\n * default message is: Welcome to our Rest API generated by Arkos, find more about Arkos at www.arkosjs.com,\n *\n *\n * */\n welcomeMessage?: string;\n /**\n * Port where the application will run, can be set in 3 ways:\n *\n * 1. default is 8000\n * 2. PORT under environment variables (Lower precedence)\n * 3. this config option (Higher precedence)\n */\n port?: number | undefined;\n /**\n * Allows to listen on a different host than localhost only\n */\n host?: string;\n /**\n * Defines authentication related configurations, by default is undefined.\n *\n * See [www.arkosjs.com/docs/core-concepts/built-in-authentication-system](https://www.arkosjs.com/docs/core-concepts/built-in-authentication-system) for details.\n */\n authentication?: {\n /**\n * Defines whether to use Static or Dynamic Role-Based Acess Control\n *\n * Visit [www.arkosjs.com/docs/core-concepts/built-in-authentication-system](https://www.arkosjs.com/docs/core-concepts/built-in-authentication-system) for more details.\n */\n mode: \"static\" | \"dynamic\";\n /**\n * Defines auth login related configurations to customize the api.\n */\n login?: {\n /** Defines wether to send the access token in response after login or only send as cookie, defeault is both.*/\n sendAccessTokenThrough?: \"cookie-only\" | \"response-only\" | \"both\";\n };\n /** Defines the field that will be used as username by the built-in auth system, by default arkos will look for the field \"username\" in your model User, hence when making login for example you must send:\n *\n * ```json\n * {\n * \"username\": \"johndoe\",\n * \"password\": \"somePassword123\"\n * }\n * ```\n *\n * **Note:** You can also modify the usernameField on the fly by passing it to the request query parameters. example:\n *\n * ```curl\n * POST /api/auth/login?usernameField=email\n * ```\n *\n * By specifing here another field for username, for example passing \"email\", \"companyCode\" or something else your json will be like:\n *\n * **Example with email**\n *\n * ```json\n * {\n * \"email\": \"john.doe@example.com\",\n * \"password\": \"somePassword123\"\n * }\n * ```\n */\n usernameField?: string;\n /**\n * Specifies the regex pattern used by the authentication system to enforce password strength requirements.\n *\n * **Important**: If using validation libraries like Zod or class-validator, this will be completely overwritten.\n *\n * **Default**: ```/^(?=.*[A-Z])(?=.*[a-z])(?=.*\\d).+$/``` - Ensures the password contains at least one uppercase letter, one lowercase letter, and one numeric digit.\n *\n * **message**: (Optional) A custom error message to display when the password does not meet the required strength criteria.\n */\n passwordValidation?: { regex: RegExp; message?: string };\n /**\n * Allows to specify the request rate limit for all authentication endpoints but `/api/users/me`.\n * \n * #### Default\n *{\n windowMs: 5000,\n limit: 10,\n standardHeaders: \"draft-7\",\n legacyHeaders: false,\n }\n * \n * Passing an object not overriding all the default options will only\n * cause it to be deepmerged and not actually replace with empty fields\n * \n * This is are the options used on the `express-rate-limit` npm package used on epxress. read more about [https://www.npmjs.com/package/express-rate-limit](https://www.npmjs.com/package/express-rate-limit)\n */\n requestRateLimitOptions?: RateLimitOptions;\n /**\n * Defines jwt configurations for secret, expiresIn, cookieExpiresIn\n *\n * Can be pass also through env variables:\n * - jwt.secret => JWT_SECRET: If not passed production auth will not work\n * - jwt.expiresIn => JWT_EXPIRES_IN: default 30d\n * - jwt.cookieExpiresIn => JWT_COOKIE_EXPIRES_IN: default 90\n */\n jwt?: {\n /** Secret to sign and decode jwt tokens */\n secret?: string;\n /** */\n expiresIn?: string;\n /** Days in which the cookie must be kept before expire*/\n cookieExpiresIn?: number;\n };\n };\n /** Allows to customize and toggle the built-in validation, by default it is set to `false`. If true is passed it will use validation with the default resolver set to `class-validator` if you intend to change the resolver to `zod` do the following:\n *\n *```ts\n * // src/app.ts\n * import arkos from 'arkos'\n *\n * arkos.init({\n * validation: {\n * resolver: \"zod\"\n * }\n * })\n * ```\n *\n * See [www.arkosjs.com/docs/core-concepts/request-data-validation](https://www.arkosjs.com/docs/core-concepts/request-data-validation) for more details.\n */\n validation?:\n | {\n resolver?: \"class-validator\";\n validationOptions?: ValidatorOptions;\n }\n | {\n resolver?: \"zod\";\n validationOptions?: Record<string, any>;\n };\n /**\n * Defines file upload configurations\n *\n * See [www.arkosjs.com/docs/core-concepts/file-upload#costum-configurations](https://www.arkosjs.com/docs/core-concepts/file-upload#costum-configurations)\n */\n fileUpload?: {\n /**\n * Defiens the base file upload directory, default is set to /uploads (on root directory)\n *\n * When setting up a path dir always now that root directory will be the starting reference.\n *\n * #### Example\n * passing `../my-arkos-uploaded-files`\n *\n * Will save uploaded files one level outside the root dir inside `my-arkos-uploaded-files`\n *\n * NB: You must be aware of permissions on your server to acess files outside your project directory.\n *\n */\n baseUploadDir?: string;\n /**\n * Changes the default `/api/uploads` base route for accessing file upload route.\n *\n * #### IMPORTANT\n * Changing this will not affect the `baseUploadDir` folder. You can\n * pass here `/api/files/my-user-files` and `baseUploadDir` be `/uploaded-files`.\n *\n */\n baseRoute?: string;\n /**\n * Defines options for `express.static(somePath, someOptions)`\n *\n * #### Default:\n *\n * ```ts\n *{\n maxAge: \"1y\",\n etag: true,\n lastModified: true,\n dotfiles: \"ignore\",\n fallthrough: true,\n index: false,\n cacheControl: true,\n }\n * ```\n * \n * By passing your custom options have in mind that it\n * will be deepmerged with the default.\n * \n * Visit [https://expressjs.com/en/4x/api.html#express.static](https://expressjs.com/en/4x/api.html#express.static) for more understanding.\n * \n */\n expressStaticOptions?: Parameters<typeof express.static>[1];\n /**\n * Defines upload restrictions for each file type: image, video, document or other.\n *\n * #### Important:\n * Passing an object without overriding everything will only cause it\n * to be deepmerged with the default options.\n *\n * See [www.arkosjs.com/docs/api-reference/default-supported-upload-files](https://www.arkosjs.com/docs/api-reference/default-supported-upload-files) for detailed explanation about default values.\n * ```\n */\n uploadRestrictions?: {\n images?: {\n maxCount?: number;\n maxSize?: number;\n supportedFilesRegex?: RegExp;\n };\n videos?: {\n maxCount?: number;\n maxSize?: number;\n supportedFilesRegex?: RegExp;\n };\n documents?: {\n maxCount?: number;\n maxSize?: number;\n supportedFilesRegex?: RegExp;\n };\n others?: {\n maxCount?: number;\n maxSize?: number;\n supportedFilesRegex?: RegExp;\n };\n };\n };\n /**\n * Allows to specify the request rate limit for all endpoints.\n * \n * #### Default\n *\n windowMs: 60 * 1000,\n limit: 1000,\n standardHeaders: \"draft-7\",\n legacyHeaders: false,\n }\n * \n * Passing an object not overriding all the default options will only\n * cause it to be deepmerged and not actually replace with empty fields\n * \n * This is are the options used on the `express-rate-limit` npm package used on epxress. read more about [https://www.npmjs.com/package/express-rate-limit](https://www.npmjs.com/package/express-rate-limit)\n */\n globalRequestRateLimitOptions?: RateLimitOptions;\n /**\n * Defines options for the built-in express.json() middleware\n * Nothing is passed by default.\n */\n jsonBodyParserOptions?: Parameters<typeof express.json>[0];\n /**\n * Allows to pass paremeters to cookieParser from npm package cookie-parser\n * Nothing is passed by default.\n *\n * See [www.npmjs.com/package/cookie-parser](https://www.npmjs.com/package/cookie-parser) for further details.\n */\n cookieParserParameters?: Parameters<typeof cookieParser>;\n /**\n * Allows to define options for npm package compression\n * Nothing is passed by default.\n *\n * See [www.npmjs.com/package/compression](https://www.npmjs.com/package/compression) for further details.\n */\n compressionOptions?: compression.CompressionOptions;\n /**\n * Options to define how query must be parsed.\n *\n * #### for example:\n * ```\n * GET /api/product?saleId=null\n * ```\n *\n * Normally would parsed to { saleId: \"null\" } so query parser\n * trough setting option `parseNull` will transform { saleId: null }\n * \n * #### Default:\n * \n * {\n parseNull: true,\n parseUndefined: true,\n parseBoolean: true,\n }\n * \n * parseNumber may convert fields that are string but you only passed\n * numbers to query pay attention to this.\n * \n * Soon a feature to converted the query to the end prisma type will be added.\n */\n queryParserOptions?: QueryParserOptions;\n /**\n * Configuration for CORS (Cross-Origin Resource Sharing).\n *\n * @property {string | string[] | \"all\"} [allowedOrigins] - List of allowed origins. If set to `\"all\"`, all origins are accepted.\n * @property {import('cors').CorsOptions} [options] - Additional CORS options passed directly to the `cors` middleware.\n * @property {import('cors').CorsOptionsDelegate} [customMiddleware] - A custom middleware function that overrides the default behavior.\n *\n * @remarks\n * If `customMiddleware` is provided, both `allowedOrigins` and `options` will be ignored in favor of the custom logic.\n *\n * See https://www.npmjs.com/package/cors\n */\n cors?: {\n allowedOrigins?: string | string[] | \"*\";\n options?: cors.CorsOptions;\n /**\n * If you would like to override the entire middleware\n *\n * see\n */\n customHandler?: cors.CorsOptionsDelegate;\n };\n /**\n * Defines express/arkos middlewares configurations\n */\n middlewares?: {\n /**\n * Allows to add an array of custom express middlewares into the default middleware stack.\n *\n * **Tip**: If you would like to acess the express app before everthing use `configureApp` and pass a function.\n *\n * **Where will these be placed?**: see [www.arkosjs.com/docs/advanced-guide/replace-or-disable-built-in-middlewares#middleware-execution-order](https://www.arkosjs.com/docs/advanced-guide/replace-or-disable-built-in-middlewares#middleware-execution-order)\n *\n * **Note**: If you want to use custom global error handler middleware use `middlewares.replace.globalErrorHandler`.\n *\n * Read more about The Arkos Middleware Stack at [www.arkosjs.com/docs/the-middleware-stack](https://www.arkosjs.com/docs/the-middleware-stack) for in-depth details.\n */\n additionals?: express.RequestHandler[];\n /**\n * An array containing a list of defaults middlewares to be disabled\n *\n * **Caution**: Be careful with this because you may endup breaking your entire application.\n */\n disable?: (\n | \"compression\"\n | \"global-rate-limit\"\n | \"auth-rate-limit\"\n | \"cors\"\n | \"express-json\"\n | \"cookie-parser\"\n | \"query-parser\"\n | \"database-connection\"\n | \"request-logger\"\n | \"global-error-handler\"\n )[];\n /**\n * Allows you to replace each of the built-in middlewares with your own implementation\n *\n * **Caution**: Be careful with this because you may endup breaking your entire application.\n */\n replace?: {\n /**\n * Replace the default compression middleware\n */\n compression?: express.RequestHandler;\n /**\n * Replace the default global rate limit middleware\n */\n globalRateLimit?: express.RequestHandler;\n /**\n * Replace the default authentication rate limit middleware\n */\n authRateLimit?: express.RequestHandler;\n /**\n * Replace the default CORS middleware\n */\n cors?: express.RequestHandler;\n /**\n * Replace the default JSON body parser middleware\n */\n expressJson?: express.RequestHandler;\n /**\n * Replace the default cookie parser middleware\n */\n cookieParser?: express.RequestHandler;\n /**\n * Replace the default query parser middleware\n */\n queryParser?: express.RequestHandler;\n /**\n * Replace the default database connection check middleware\n */\n databaseConnection?: express.RequestHandler;\n /**\n * Replace the default request logger middleware\n */\n requestLogger?: express.RequestHandler;\n /**\n * Replace the default global error handler middleware\n */\n globalErrorHandler?: express.ErrorRequestHandler;\n };\n };\n /**\n * Defines express/arkos routers configurations\n */\n routers?: {\n /**\n * Allows to add an array of custom express routers into the default middleware/router stack.\n *\n * **Where will these be placed?**: see [www.arkosjs.com/docs/advanced-guide/adding-custom-routers](https://www.arkosjs.com/docs/advanced-guide/adding-custom-routers)\n *\n *\n * Read more about The Arkos Middleware Stack at [www.arkosjs.com/docs/the-middleware-stack](https://www.arkosjs.com/docs/the-middleware-stack) for in-depth details.\n */\n additionals?: express.Router[];\n disable?: (\n | \"auth-router\"\n | \"prisma-models-router\"\n | \"file-uploader\"\n | \"welcome-endpoint\"\n )[];\n /**\n * Allows you to replace each of the built-in routers with your own implementation.\n *\n * **Note**: Doing this you will lose all default middleware chaining, auth control, handlers from the specific router.\n *\n * **Tip**: I you want to disable some prisma models specific endpoint\n * see [www.arkosjs.com/docs/advanced-guide/customizing-prisma-models-routers#disabling-endpoints](https://www.arkosjs.com/docs/advanced-guide/customizing-prisma-models-routers#disabling-endpoints)\n *\n * **Caution**: Be careful with this because you may endup breaking your entire application.\n */\n replace?: {\n /**\n * Replace the default authentication router\n * @param config The original Arkos configuration\n * @returns A router handling authentication endpoints\n */\n authRouter?: (\n config: ArkosConfig\n ) => express.Router | Promise<express.Router>;\n /**\n * Replace the default Prisma models router\n * @param config The original Arkos configuration\n * @returns A router handling Prisma model endpoints\n */\n prismaModelsRouter?: (\n config: ArkosConfig\n ) => express.Router | Promise<express.Router>;\n /**\n * Replace the default file uploader router\n * @param config The original Arkos configuration\n * @returns A router handling file upload endpoints\n */\n fileUploader?: (\n config: ArkosConfig\n ) => express.Router | Promise<express.Router>;\n /**\n * Replace the default welcome endpoint handler\n * @param req Express request object\n * @param res Express response object\n * @param next Express next function\n */\n welcomeEndpoint?: express.RequestHandler;\n };\n };\n /**\n * Gives acess to the underlying express app so that you can add custom configurations beyong **Arkos** customization capabilities\n *\n * **Note**: In the end **Arkos** will call `app.listen` for you.\n *\n * If you want to call `app.listen` by yourself pass port as `undefined` and then use the return app from `arkos.init()`.\n *\n * See how to call `app.listen` correctly [www.arkosjs.com/docs/accessing-the-express-app#calling-applisten-by-yourself](https://www.arkosjs.com/docs/accessing-the-express-app#calling-applisten-by-yourself)\n *\n * See [www.arkosjs.com/docs/accessing-the-express-app](https://www.arkosjs.com/docs/accessing-the-express-app) for further details on the method configureApp.\n *\n * @param {express.Express} app\n * @returns {any}\n */\n configureApp?: (app: express.Express) => Promise<any> | any;\n};\n"]}
|
|
1
|
+
{"version":3,"file":"arkos-config.js","sourceRoot":"","sources":["../../../src/types/arkos-config.ts"],"names":[],"mappings":"","sourcesContent":["import cors from \"cors\";\nimport express from \"express\";\nimport { Options as RateLimitOptions } from \"express-rate-limit\";\nimport cookieParser from \"cookie-parser\";\nimport compression from \"compression\";\nimport { Options as QueryParserOptions } from \"../utils/helpers/query-parser.helpers\";\nimport { ValidatorOptions } from \"class-validator\";\n\n/**\n * Defines the initial configs of the api to be loaded at startup when arkos.init() is called.\n */\nexport type ArkosConfig = {\n /** Message you would like to send, as Json and 200 response when\n * ```\n * GET /api\n * ```\n * ```json\n * { \"message\": \"Welcome to YourAppName\" }\n * ```\n *\n * default message is: Welcome to our Rest API generated by Arkos, find more about Arkos at www.arkosjs.com,\n *\n *\n * */\n welcomeMessage?: string;\n /**\n * Port where the application will run, can be set in 3 ways:\n *\n * 1. default is 8000\n * 2. PORT under environment variables (Lower precedence)\n * 3. this config option (Higher precedence)\n */\n port?: number | undefined;\n /**\n * Allows to listen on a different host than localhost only\n */\n host?: string;\n /**\n * Defines authentication related configurations, by default is undefined.\n *\n * See [www.arkosjs.com/docs/core-concepts/built-in-authentication-system](https://www.arkosjs.com/docs/core-concepts/built-in-authentication-system) for details.\n */\n authentication?: {\n /**\n * Defines whether to use Static or Dynamic Role-Based Acess Control\n *\n * Visit [www.arkosjs.com/docs/core-concepts/built-in-authentication-system](https://www.arkosjs.com/docs/core-concepts/built-in-authentication-system) for more details.\n */\n mode: \"static\" | \"dynamic\";\n /**\n * Defines auth login related configurations to customize the api.\n */\n login?: {\n /** Defines wether to send the access token in response after login or only send as cookie, defeault is both.*/\n sendAccessTokenThrough?: \"cookie-only\" | \"response-only\" | \"both\";\n };\n /** Defines the field that will be used as username by the built-in auth system, by default arkos will look for the field \"username\" in your model User, hence when making login for example you must send:\n *\n * ```json\n * {\n * \"username\": \"johndoe\",\n * \"password\": \"somePassword123\"\n * }\n * ```\n *\n * **Note:** You can also modify the usernameField on the fly by passing it to the request query parameters. example:\n *\n * ```curl\n * POST /api/auth/login?usernameField=email\n * ```\n *\n * By specifing here another field for username, for example passing \"email\", \"companyCode\" or something else your json will be like:\n *\n * **Example with email**\n *\n * ```json\n * {\n * \"email\": \"john.doe@example.com\",\n * \"password\": \"somePassword123\"\n * }\n * ```\n */\n usernameField?: string;\n /**\n * Specifies the regex pattern used by the authentication system to enforce password strength requirements.\n *\n * **Important**: If using validation libraries like Zod or class-validator, this will be completely overwritten.\n *\n * **Default**: ```/^(?=.*[A-Z])(?=.*[a-z])(?=.*\\d).+$/``` - Ensures the password contains at least one uppercase letter, one lowercase letter, and one numeric digit.\n *\n * **message**: (Optional) A custom error message to display when the password does not meet the required strength criteria.\n */\n passwordValidation?: { regex: RegExp; message?: string };\n /**\n * Allows to specify the request rate limit for all authentication endpoints but `/api/users/me`.\n * \n * #### Default\n *{\n windowMs: 5000,\n limit: 10,\n standardHeaders: \"draft-7\",\n legacyHeaders: false,\n }\n * \n * Passing an object not overriding all the default options will only\n * cause it to be deepmerged and not actually replace with empty fields\n * \n * This is are the options used on the `express-rate-limit` npm package used on epxress. read more about [https://www.npmjs.com/package/express-rate-limit](https://www.npmjs.com/package/express-rate-limit)\n */\n requestRateLimitOptions?: RateLimitOptions;\n /**\n * Defines jwt configurations for secret, expiresIn, cookieExpiresIn\n *\n * Can be pass also through env variables:\n * - jwt.secret => JWT_SECRET: If not passed production auth will not work\n * - jwt.expiresIn => JWT_EXPIRES_IN: default 30d\n * - jwt.cookieExpiresIn => JWT_COOKIE_EXPIRES_IN: default 90\n */\n jwt?: {\n /** Secret to sign and decode jwt tokens */\n secret?: string;\n /** */\n expiresIn?: string;\n /** Days in which the cookie must be kept before expire*/\n cookieExpiresIn?: number;\n };\n };\n /** Allows to customize and toggle the built-in validation, by default it is set to `false`. If true is passed it will use validation with the default resolver set to `class-validator` if you intend to change the resolver to `zod` do the following:\n *\n *```ts\n * // src/app.ts\n * import arkos from 'arkos'\n *\n * arkos.init({\n * validation: {\n * resolver: \"zod\"\n * }\n * })\n * ```\n *\n * See [www.arkosjs.com/docs/core-concepts/request-data-validation](https://www.arkosjs.com/docs/core-concepts/request-data-validation) for more details.\n */\n validation?:\n | {\n resolver?: \"class-validator\";\n /**\n * ValidatorOptions to used while validating request data.\n *\n * **Default**:\n * ```ts\n * {\n * whitelist: true\n * }\n * ```\n */\n validationOptions?: ValidatorOptions;\n }\n | {\n resolver?: \"zod\";\n validationOptions?: Record<string, any>;\n };\n /**\n * Defines file upload configurations\n *\n * See [www.arkosjs.com/docs/core-concepts/file-upload#costum-configurations](https://www.arkosjs.com/docs/core-concepts/file-upload#costum-configurations)\n */\n fileUpload?: {\n /**\n * Defiens the base file upload directory, default is set to /uploads (on root directory)\n *\n * When setting up a path dir always now that root directory will be the starting reference.\n *\n * #### Example\n * passing `../my-arkos-uploaded-files`\n *\n * Will save uploaded files one level outside the root dir inside `my-arkos-uploaded-files`\n *\n * NB: You must be aware of permissions on your server to acess files outside your project directory.\n *\n */\n baseUploadDir?: string;\n /**\n * Changes the default `/api/uploads` base route for accessing file upload route.\n *\n * #### IMPORTANT\n * Changing this will not affect the `baseUploadDir` folder. You can\n * pass here `/api/files/my-user-files` and `baseUploadDir` be `/uploaded-files`.\n *\n */\n baseRoute?: string;\n /**\n * Defines options for `express.static(somePath, someOptions)`\n *\n * #### Default:\n *\n * ```ts\n *{\n maxAge: \"1y\",\n etag: true,\n lastModified: true,\n dotfiles: \"ignore\",\n fallthrough: true,\n index: false,\n cacheControl: true,\n }\n * ```\n * \n * By passing your custom options have in mind that it\n * will be deepmerged with the default.\n * \n * Visit [https://expressjs.com/en/4x/api.html#express.static](https://expressjs.com/en/4x/api.html#express.static) for more understanding.\n * \n */\n expressStaticOptions?: Parameters<typeof express.static>[1];\n /**\n * Defines upload restrictions for each file type: image, video, document or other.\n *\n * #### Important:\n * Passing an object without overriding everything will only cause it\n * to be deepmerged with the default options.\n *\n * See [www.arkosjs.com/docs/api-reference/default-supported-upload-files](https://www.arkosjs.com/docs/api-reference/default-supported-upload-files) for detailed explanation about default values.\n * ```\n */\n restrictions?: {\n images?: {\n maxCount?: number;\n maxSize?: number;\n supportedFilesRegex?: RegExp;\n };\n videos?: {\n maxCount?: number;\n maxSize?: number;\n supportedFilesRegex?: RegExp;\n };\n documents?: {\n maxCount?: number;\n maxSize?: number;\n supportedFilesRegex?: RegExp;\n };\n others?: {\n maxCount?: number;\n maxSize?: number;\n supportedFilesRegex?: RegExp;\n };\n };\n };\n /**\n * Allows to specify the request rate limit for all endpoints.\n * \n * #### Default\n *\n windowMs: 60 * 1000,\n limit: 1000,\n standardHeaders: \"draft-7\",\n legacyHeaders: false,\n }\n * \n * Passing an object not overriding all the default options will only\n * cause it to be deepmerged and not actually replace with empty fields\n * \n * This is are the options used on the `express-rate-limit` npm package used on epxress. read more about [https://www.npmjs.com/package/express-rate-limit](https://www.npmjs.com/package/express-rate-limit)\n */\n globalRequestRateLimitOptions?: RateLimitOptions;\n /**\n * Defines options for the built-in express.json() middleware\n * Nothing is passed by default.\n */\n jsonBodyParserOptions?: Parameters<typeof express.json>[0];\n /**\n * Allows to pass paremeters to cookieParser from npm package cookie-parser\n * Nothing is passed by default.\n *\n * See [www.npmjs.com/package/cookie-parser](https://www.npmjs.com/package/cookie-parser) for further details.\n */\n cookieParserParameters?: Parameters<typeof cookieParser>;\n /**\n * Allows to define options for npm package compression\n * Nothing is passed by default.\n *\n * See [www.npmjs.com/package/compression](https://www.npmjs.com/package/compression) for further details.\n */\n compressionOptions?: compression.CompressionOptions;\n /**\n * Options to define how query must be parsed.\n *\n * #### for example:\n * ```\n * GET /api/product?saleId=null\n * ```\n *\n * Normally would parsed to { saleId: \"null\" } so query parser\n * trough setting option `parseNull` will transform { saleId: null }\n * \n * #### Default:\n * \n * {\n parseNull: true,\n parseUndefined: true,\n parseBoolean: true,\n }\n * \n * parseNumber may convert fields that are string but you only passed\n * numbers to query pay attention to this.\n * \n * Soon a feature to converted the query to the end prisma type will be added.\n */\n queryParserOptions?: QueryParserOptions;\n /**\n * Configuration for CORS (Cross-Origin Resource Sharing).\n *\n * @property {string | string[] | \"all\"} [allowedOrigins] - List of allowed origins. If set to `\"all\"`, all origins are accepted.\n * @property {import('cors').CorsOptions} [options] - Additional CORS options passed directly to the `cors` middleware.\n * @property {import('cors').CorsOptionsDelegate} [customMiddleware] - A custom middleware function that overrides the default behavior.\n *\n * @remarks\n * If `customMiddleware` is provided, both `allowedOrigins` and `options` will be ignored in favor of the custom logic.\n *\n * See https://www.npmjs.com/package/cors\n */\n cors?: {\n allowedOrigins?: string | string[] | \"*\";\n options?: cors.CorsOptions;\n /**\n * If you would like to override the entire middleware\n *\n * see\n */\n customHandler?: cors.CorsOptionsDelegate;\n };\n /**\n * Defines express/arkos middlewares configurations\n */\n middlewares?: {\n /**\n * Allows to add an array of custom express middlewares into the default middleware stack.\n *\n * **Tip**: If you would like to acess the express app before everthing use `configureApp` and pass a function.\n *\n * **Where will these be placed?**: see [www.arkosjs.com/docs/advanced-guide/replace-or-disable-built-in-middlewares#middleware-execution-order](https://www.arkosjs.com/docs/advanced-guide/replace-or-disable-built-in-middlewares#middleware-execution-order)\n *\n * **Note**: If you want to use custom global error handler middleware use `middlewares.replace.globalErrorHandler`.\n *\n * Read more about The Arkos Middleware Stack at [www.arkosjs.com/docs/the-middleware-stack](https://www.arkosjs.com/docs/the-middleware-stack) for in-depth details.\n */\n additionals?: express.RequestHandler[];\n /**\n * An array containing a list of defaults middlewares to be disabled\n *\n * **Caution**: Be careful with this because you may endup breaking your entire application.\n */\n disable?: (\n | \"compression\"\n | \"global-rate-limit\"\n | \"auth-rate-limit\"\n | \"cors\"\n | \"express-json\"\n | \"cookie-parser\"\n | \"query-parser\"\n | \"database-connection\"\n | \"request-logger\"\n | \"global-error-handler\"\n )[];\n /**\n * Allows you to replace each of the built-in middlewares with your own implementation\n *\n * **Caution**: Be careful with this because you may endup breaking your entire application.\n */\n replace?: {\n /**\n * Replace the default compression middleware\n */\n compression?: express.RequestHandler;\n /**\n * Replace the default global rate limit middleware\n */\n globalRateLimit?: express.RequestHandler;\n /**\n * Replace the default authentication rate limit middleware\n */\n authRateLimit?: express.RequestHandler;\n /**\n * Replace the default CORS middleware\n */\n cors?: express.RequestHandler;\n /**\n * Replace the default JSON body parser middleware\n */\n expressJson?: express.RequestHandler;\n /**\n * Replace the default cookie parser middleware\n */\n cookieParser?: express.RequestHandler;\n /**\n * Replace the default query parser middleware\n */\n queryParser?: express.RequestHandler;\n /**\n * Replace the default database connection check middleware\n */\n databaseConnection?: express.RequestHandler;\n /**\n * Replace the default request logger middleware\n */\n requestLogger?: express.RequestHandler;\n /**\n * Replace the default global error handler middleware\n */\n globalErrorHandler?: express.ErrorRequestHandler;\n };\n };\n /**\n * Defines express/arkos routers configurations\n */\n routers?: {\n /**\n * Allows to add an array of custom express routers into the default middleware/router stack.\n *\n * **Where will these be placed?**: see [www.arkosjs.com/docs/advanced-guide/adding-custom-routers](https://www.arkosjs.com/docs/advanced-guide/adding-custom-routers)\n *\n *\n * Read more about The Arkos Middleware Stack at [www.arkosjs.com/docs/the-middleware-stack](https://www.arkosjs.com/docs/the-middleware-stack) for in-depth details.\n */\n additionals?: express.Router[];\n disable?: (\n | \"auth-router\"\n | \"prisma-models-router\"\n | \"file-uploader\"\n | \"welcome-endpoint\"\n )[];\n /**\n * Allows you to replace each of the built-in routers with your own implementation.\n *\n * **Note**: Doing this you will lose all default middleware chaining, auth control, handlers from the specific router.\n *\n * **Tip**: I you want to disable some prisma models specific endpoint\n * see [www.arkosjs.com/docs/advanced-guide/customizing-prisma-models-routers#disabling-endpoints](https://www.arkosjs.com/docs/advanced-guide/customizing-prisma-models-routers#disabling-endpoints)\n *\n * **Caution**: Be careful with this because you may endup breaking your entire application.\n */\n replace?: {\n /**\n * Replace the default authentication router\n * @param config The original Arkos configuration\n * @returns A router handling authentication endpoints\n */\n authRouter?: (\n config: ArkosConfig\n ) => express.Router | Promise<express.Router>;\n /**\n * Replace the default Prisma models router\n * @param config The original Arkos configuration\n * @returns A router handling Prisma model endpoints\n */\n prismaModelsRouter?: (\n config: ArkosConfig\n ) => express.Router | Promise<express.Router>;\n /**\n * Replace the default file uploader router\n * @param config The original Arkos configuration\n * @returns A router handling file upload endpoints\n */\n fileUploader?: (\n config: ArkosConfig\n ) => express.Router | Promise<express.Router>;\n /**\n * Replace the default welcome endpoint handler\n * @param req Express request object\n * @param res Express response object\n * @param next Express next function\n */\n welcomeEndpoint?: express.RequestHandler;\n };\n };\n /**\n * Gives acess to the underlying express app so that you can add custom configurations beyong **Arkos** customization capabilities\n *\n * **Note**: In the end **Arkos** will call `app.listen` for you.\n *\n * If you want to call `app.listen` by yourself pass port as `undefined` and then use the return app from `arkos.init()`.\n *\n * See how to call `app.listen` correctly [www.arkosjs.com/docs/accessing-the-express-app#calling-applisten-by-yourself](https://www.arkosjs.com/docs/accessing-the-express-app#calling-applisten-by-yourself)\n *\n * See [www.arkosjs.com/docs/accessing-the-express-app](https://www.arkosjs.com/docs/accessing-the-express-app) for further details on the method configureApp.\n *\n * @param {express.Express} app\n * @returns {any}\n */\n configureApp?: (app: express.Express) => Promise<any> | any;\n /**\n * Allows to configure email configurations for sending emails through `emailService`\n *\n * See [www.arkosjs.com/docs/core-concepts/sending-emails](https://www.arkosjs.com/docs/core-concepts/sending-emails)\n */\n email?: {\n /**\n * Your email provider url\n */\n host: string;\n /**\n * Email provider SMTP port, Default is `465`\n */\n port?: number;\n /**\n * Email used for auth as well as sending emails\n */\n from: string;\n /**\n * Your SMTP password\n */\n password: string;\n /**\n * Email name to used like:\n *\n * John Doe\\<john.doe@gmail.com>\n */\n name?: string;\n };\n};\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../src/types/auth.ts"],"names":[],"mappings":"","sourcesContent":["import { JwtPayload } from \"jsonwebtoken\";\n\n/**\n * Possible actions that can be performed by a controller.\n */\nexport type ControllerActions = \"create\" | \"update\" | \"delete\" | \"view\";\n\n/**\n * Rules defining access control for different controller actions.\n *\n * @typeParam key - One of the `ControllerActions`.\n * @typeParam Role - A type representing a role or set of roles allowed to perform the action.\n */\nexport type AccessControlRules = {\n /**\n * Maps each `ControllerAction` to the roles allowed to perform it.\n */\n [key in ControllerActions]: any
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../src/types/auth.ts"],"names":[],"mappings":"","sourcesContent":["import { JwtPayload } from \"jsonwebtoken\";\n\n/**\n * Possible actions that can be performed by a controller.\n */\nexport type ControllerActions = \"create\" | \"update\" | \"delete\" | \"view\";\n\n/**\n * Rules defining access control for different controller actions.\n *\n * @typeParam key - One of the `ControllerActions`.\n * @typeParam Role - A type representing a role or set of roles allowed to perform the action.\n */\nexport type AccessControlRules = {\n /**\n * Maps each `ControllerAction` to the roles allowed to perform it.\n */\n [key in ControllerActions]: any[];\n};\n\n/**\n * Rules defining access control for different controller actions.\n *\n * @typeParam key - One of the `ControllerActions`.\n * @typeParam Role - A type representing a role or set of roles allowed to perform the action.\n */\nexport type AuthenticationControlRules = {\n /**\n * Maps each `ControllerAction` to the actions that requires authentication to perform it.\n */\n [key in ControllerActions]: boolean;\n};\n\n/**\n * Configuration for authentication and access control.\n */\nexport type AuthConfigs = {\n /**\n * Defines access control rules for roles or actions.\n *\n * @type {Role | Role[] | AccessControlRules}\n */\n authenticationControl?: boolean | Partial<AuthenticationControlRules>;\n /**\n * List of user roles, or restricted by actions\n */\n accessControl?: any[] | Partial<AccessControlRules>;\n};\n\n/**\n * Payload structure for JWT-based authentication, extending the standard `JwtPayload`.\n */\nexport interface AuthJwtPayload extends JwtPayload {\n /**\n * The unique identifier of the authenticated user.\n *\n * @type {number | string}\n */\n id?: number | string;\n\n /**\n * The username of the authenticated user.\n *\n * @type {string}\n */\n username?: string;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/types/index.ts"],"names":[],"mappings":"AAuCA,MAAM,CAAN,IAAY,oBAKX;AALD,WAAY,oBAAoB;IAC9B,yCAAiB,CAAA;IACjB,qCAAa,CAAA;IACb,yCAAiB,CAAA;IACjB,yCAAiB,CAAA;AACnB,CAAC,EALW,oBAAoB,KAApB,oBAAoB,QAK/B","sourcesContent":["import { Prisma } from \"@prisma/client\";\nimport { NextFunction, Request, RequestHandler, Response } from \"express\";\n\nexport type PrismaOperations = \"findMany\";\n\nexport type PrismaQueryOptions<T> = {\n queryOptions?: Omit<\n Prisma.Args<T, \"findMany\">,\n \"where\" | \"cursor\" | \"take\" | \"skip\" | \"orderBy\"\n >;\n findOne?: Partial<Partial<Prisma.Args<T, \"findUnique\">>>;\n findMany?: Partial<Prisma.Args<T, \"findMany\">>;\n deleteMany?: Partial<Prisma.Args<T, \"deleteMany\">>;\n updateMany?: Partial<Prisma.Args<T, \"updateMany\">>;\n createMany?: Partial<Prisma.Args<T, \"createMany\">>;\n createOne?: Partial<Prisma.Args<T, \"create\">>;\n updateOne?: Partial<Prisma.Args<T, \"update\">>;\n deleteOne?: Partial<Prisma.Args<T, \"delete\">>;\n};\n\nexport interface UserRole {\n id: string;\n createdAt: Date;\n deletedAt?: Date;\n roleId: string;\n role: AuthRole;\n user: User;\n userId: string;\n}\n\nexport interface AuthRole {\n id: string;\n createdAt: Date;\n deletedAt?: Date;\n name: string;\n permissions: AuthPermission[];\n userRoles: UserRole[];\n}\n\nexport enum AuthPermissionAction {\n create = \"create\",\n view = \"view\",\n update = \"update\",\n delete = \"delete\",\n}\n\nexport interface AuthPermission {\n id: string;\n createdAt: Date;\n deletedAt?: Date;\n resource: string;\n action: AuthPermissionAction;\n roleId: string;\n role: AuthRole;\n}\n\nexport interface User {\n id: string;\n isStaff: boolean;\n password: string;\n passwordChangedAt?: Date;\n deletedSelfAccountAt: Date;\n isActive: boolean;\n roles?: UserRole[] | any[];\n role?: UserRole | any;\n}\n\nexport interface ArkosRequest extends Request {\n user?: User & Record<string, any>;\n relationFields?: Record<string, boolean>;\n include?: Record<string, any>;\n responseData?: Record<string, any> | null | undefined;\n additionalData?: Record<string, any> | null | undefined;\n responseStatus?: number | string | null | undefined;\n}\n\nexport interface ArkosResponse extends Response {}\nexport interface ArkosNextFunction extends NextFunction {}\nexport interface ArkosRequestHandler extends RequestHandler {}\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/types/index.ts"],"names":[],"mappings":"AAuCA,MAAM,CAAN,IAAY,oBAKX;AALD,WAAY,oBAAoB;IAC9B,yCAAiB,CAAA;IACjB,qCAAa,CAAA;IACb,yCAAiB,CAAA;IACjB,yCAAiB,CAAA;AACnB,CAAC,EALW,oBAAoB,KAApB,oBAAoB,QAK/B","sourcesContent":["import { Prisma } from \"@prisma/client\";\nimport { NextFunction, Request, RequestHandler, Response } from \"express\";\n\nexport type PrismaOperations = \"findMany\";\n\nexport type PrismaQueryOptions<T> = {\n queryOptions?: Omit<\n Prisma.Args<T, \"findMany\">,\n \"where\" | \"cursor\" | \"take\" | \"skip\" | \"orderBy\"\n >;\n findOne?: Partial<Partial<Prisma.Args<T, \"findUnique\">>>;\n findMany?: Partial<Prisma.Args<T, \"findMany\">>;\n deleteMany?: Partial<Prisma.Args<T, \"deleteMany\">>;\n updateMany?: Partial<Prisma.Args<T, \"updateMany\">>;\n createMany?: Partial<Prisma.Args<T, \"createMany\">>;\n createOne?: Partial<Prisma.Args<T, \"create\">>;\n updateOne?: Partial<Prisma.Args<T, \"update\">>;\n deleteOne?: Partial<Prisma.Args<T, \"delete\">>;\n};\n\nexport interface UserRole {\n id: string;\n createdAt: Date;\n deletedAt?: Date;\n roleId: string;\n role: AuthRole;\n user: User;\n userId: string;\n}\n\nexport interface AuthRole {\n id: string;\n createdAt: Date;\n deletedAt?: Date;\n name: string;\n permissions: AuthPermission[];\n userRoles: UserRole[];\n}\n\nexport enum AuthPermissionAction {\n create = \"create\",\n view = \"view\",\n update = \"update\",\n delete = \"delete\",\n}\n\nexport interface AuthPermission {\n id: string;\n createdAt: Date;\n deletedAt?: Date;\n resource: string;\n action: AuthPermissionAction;\n roleId: string;\n role: AuthRole;\n}\n\nexport interface User {\n id: string;\n isStaff: boolean;\n isSuperUser: boolean;\n password: string;\n passwordChangedAt?: Date;\n deletedSelfAccountAt: Date;\n isActive: boolean;\n roles?: UserRole[] | any[];\n role?: UserRole | any;\n}\n\nexport interface ArkosRequest extends Request {\n user?: User & Record<string, any>;\n relationFields?: Record<string, boolean>;\n include?: Record<string, any>;\n responseData?: Record<string, any> | null | undefined;\n additionalData?: Record<string, any> | null | undefined;\n responseStatus?: number | string | null | undefined;\n}\n\nexport interface ArkosResponse extends Response {}\nexport interface ArkosNextFunction extends NextFunction {}\nexport interface ArkosRequestHandler extends RequestHandler {}\n"]}
|