speedly 1.2.39 → 1.2.42
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/dist/cjs/auth/auth.js +12 -8
- package/dist/cjs/db/db.d.ts +3 -3
- package/dist/cjs/db/db.js +158 -49
- package/dist/cjs/document/document.d.ts +2 -0
- package/dist/cjs/document/document.js +185 -0
- package/dist/cjs/index.d.ts +6 -5
- package/dist/cjs/index.js +4 -2
- package/dist/cjs/uploader/uploader.js +0 -5
- package/dist/cjs/validator/validator.js +29 -24
- package/dist/esm/auth/auth.js +12 -8
- package/dist/esm/db/db.d.ts +3 -3
- package/dist/esm/db/db.js +158 -49
- package/dist/esm/document/document.d.ts +2 -0
- package/dist/esm/document/document.js +185 -0
- package/dist/esm/index.d.ts +6 -5
- package/dist/esm/index.js +4 -2
- package/dist/esm/uploader/uploader.js +0 -5
- package/dist/esm/validator/validator.js +29 -24
- package/package.json +4 -1
package/dist/cjs/auth/auth.js
CHANGED
|
@@ -12,20 +12,24 @@ const gConfig = {
|
|
|
12
12
|
},
|
|
13
13
|
...(0, getConfig_1.default)("auth"),
|
|
14
14
|
};
|
|
15
|
-
const executer = (authType) =>
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
15
|
+
const executer = (authType) => {
|
|
16
|
+
const mw = async (req, res, next) => {
|
|
17
|
+
const accessResult = await gConfig?.customValidator?.(req, authType);
|
|
18
|
+
if (accessResult == null)
|
|
19
|
+
return next({ status: 401, json: { message: "Unauthorized" } });
|
|
20
|
+
if (!accessResult)
|
|
21
|
+
return next({ status: 403, json: { message: "Forbidden" } });
|
|
22
|
+
return next();
|
|
23
|
+
};
|
|
24
|
+
Object.defineProperty(mw, "name", { value: `auth:${authType}` });
|
|
25
|
+
return mw;
|
|
22
26
|
};
|
|
23
27
|
const auth = {
|
|
24
28
|
user: () => {
|
|
25
29
|
return executer("user");
|
|
26
30
|
},
|
|
27
31
|
admin: (config) => {
|
|
28
|
-
return executer(`admin${config?.permission ? `:${config.permission}` :
|
|
32
|
+
return executer(`admin${config?.permission ? `:${config.permission}` : ""}`);
|
|
29
33
|
},
|
|
30
34
|
any: () => {
|
|
31
35
|
return executer("any");
|
package/dist/cjs/db/db.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Request, Response, NextFunction } from
|
|
2
|
-
declare module
|
|
1
|
+
import { Request, Response, NextFunction } from "express";
|
|
2
|
+
declare module "express-serve-static-core" {
|
|
3
3
|
interface Request {
|
|
4
4
|
document?: any;
|
|
5
5
|
user?: any;
|
|
@@ -13,7 +13,7 @@ type ConfigsType = {
|
|
|
13
13
|
dbType?: string;
|
|
14
14
|
path?: string;
|
|
15
15
|
dbEnv?: string;
|
|
16
|
-
type:
|
|
16
|
+
type: "internal" | "external";
|
|
17
17
|
pagination?: {
|
|
18
18
|
quantity?: number;
|
|
19
19
|
detailed?: boolean;
|
package/dist/cjs/db/db.js
CHANGED
|
@@ -11,88 +11,129 @@ const translator_1 = __importDefault(require("../util/translator"));
|
|
|
11
11
|
let configs = {
|
|
12
12
|
dbType: "mongodb",
|
|
13
13
|
path: "../models",
|
|
14
|
-
type:
|
|
14
|
+
type: "external",
|
|
15
15
|
dbEnv: "DB_URL",
|
|
16
16
|
...(0, getConfig_1.default)("db"),
|
|
17
17
|
};
|
|
18
|
-
const usingMongoDb = (collectionName, config = { type:
|
|
18
|
+
const usingMongoDb = (collectionName, config = { type: "external" }) => {
|
|
19
19
|
let model;
|
|
20
20
|
let queryState = {
|
|
21
21
|
queries: [],
|
|
22
22
|
};
|
|
23
23
|
if (config?.path)
|
|
24
24
|
__path = config.path;
|
|
25
|
-
model = require(path_1.default.join(...(config.type ==
|
|
25
|
+
model = require(path_1.default.join(...(config.type == "external"
|
|
26
|
+
? [require.main?.filename || "./", __path]
|
|
27
|
+
: ["../model"]), collectionName));
|
|
26
28
|
if (model.default)
|
|
27
29
|
model = model.default;
|
|
28
30
|
const actionHandler = {
|
|
29
31
|
find: (match = {}) => {
|
|
30
32
|
queryState.action = "find";
|
|
31
33
|
queryState.match = match;
|
|
34
|
+
Object.defineProperty(handler, "name", {
|
|
35
|
+
value: `model:${queryState.action}:${collectionName}`,
|
|
36
|
+
});
|
|
32
37
|
return handler;
|
|
33
38
|
},
|
|
34
39
|
create: (body = {}) => {
|
|
35
40
|
queryState.action = "create";
|
|
36
41
|
queryState.body = body;
|
|
42
|
+
Object.defineProperty(handler, "name", {
|
|
43
|
+
value: `model:${queryState.action}:${collectionName}`,
|
|
44
|
+
});
|
|
37
45
|
return handler;
|
|
38
46
|
},
|
|
39
47
|
updateOne: (match = {}, body = {}) => {
|
|
40
48
|
queryState.action = "updateOne";
|
|
41
49
|
queryState.match = match;
|
|
42
50
|
queryState.body = body;
|
|
51
|
+
Object.defineProperty(handler, "name", {
|
|
52
|
+
value: `model:${queryState.action}:${collectionName}`,
|
|
53
|
+
});
|
|
43
54
|
return handler;
|
|
44
55
|
},
|
|
45
56
|
updateMany: (match = {}, body = {}) => {
|
|
46
57
|
queryState.action = "updateMany";
|
|
47
58
|
queryState.match = match;
|
|
48
59
|
queryState.body = body;
|
|
60
|
+
Object.defineProperty(handler, "name", {
|
|
61
|
+
value: `model:${queryState.action}:${collectionName}`,
|
|
62
|
+
});
|
|
49
63
|
return handler;
|
|
50
64
|
},
|
|
51
65
|
deleteOne: (match = {}) => {
|
|
52
66
|
queryState.action = "deleteOne";
|
|
53
67
|
queryState.match = match;
|
|
68
|
+
Object.defineProperty(handler, "name", {
|
|
69
|
+
value: `model:${queryState.action}:${collectionName}`,
|
|
70
|
+
});
|
|
54
71
|
return handler;
|
|
55
72
|
},
|
|
56
73
|
deleteMany: (match = {}) => {
|
|
57
74
|
queryState.action = "deleteMany";
|
|
58
75
|
queryState.match = match;
|
|
76
|
+
Object.defineProperty(handler, "name", {
|
|
77
|
+
value: `model:${queryState.action}:${collectionName}`,
|
|
78
|
+
});
|
|
59
79
|
return handler;
|
|
60
80
|
},
|
|
61
81
|
findOne: (match = {}) => {
|
|
62
82
|
queryState.action = "findOne";
|
|
63
83
|
queryState.match = match;
|
|
84
|
+
Object.defineProperty(handler, "name", {
|
|
85
|
+
value: `model:${queryState.action}:${collectionName}`,
|
|
86
|
+
});
|
|
64
87
|
return handler;
|
|
65
88
|
},
|
|
66
89
|
findOneAndUpdate: (match = {}, body = {}) => {
|
|
67
90
|
queryState.action = "findOneAndUpdate";
|
|
68
91
|
queryState.match = match;
|
|
69
92
|
queryState.body = body;
|
|
93
|
+
Object.defineProperty(handler, "name", {
|
|
94
|
+
value: `model:${queryState.action}:${collectionName}`,
|
|
95
|
+
});
|
|
70
96
|
return handler;
|
|
71
97
|
},
|
|
72
98
|
aggregate: (pipeline = []) => {
|
|
73
99
|
queryState.action = "aggregate";
|
|
74
100
|
queryState.pipeline = pipeline;
|
|
101
|
+
Object.defineProperty(handler, "name", {
|
|
102
|
+
value: `model:${queryState.action}:${collectionName}`,
|
|
103
|
+
});
|
|
75
104
|
return handler;
|
|
76
105
|
},
|
|
77
106
|
findOneAndDelete: (match = {}) => {
|
|
78
107
|
queryState.action = "findOneAndDelete";
|
|
79
108
|
queryState.match = match;
|
|
109
|
+
Object.defineProperty(handler, "name", {
|
|
110
|
+
value: `model:${queryState.action}:${collectionName}`,
|
|
111
|
+
});
|
|
80
112
|
return handler;
|
|
81
113
|
},
|
|
82
114
|
findById: (id = "") => {
|
|
83
115
|
queryState.action = "findById";
|
|
84
116
|
queryState.id = id;
|
|
117
|
+
Object.defineProperty(handler, "name", {
|
|
118
|
+
value: `model:${queryState.action}:${collectionName}`,
|
|
119
|
+
});
|
|
85
120
|
return handler;
|
|
86
121
|
},
|
|
87
122
|
findByIdAndUpdate: (id = "", body = {}) => {
|
|
88
123
|
queryState.action = "findByIdAndUpdate";
|
|
89
124
|
queryState.id = id;
|
|
90
125
|
queryState.body = body;
|
|
126
|
+
Object.defineProperty(handler, "name", {
|
|
127
|
+
value: `model:${queryState.action}:${collectionName}`,
|
|
128
|
+
});
|
|
91
129
|
return handler;
|
|
92
130
|
},
|
|
93
131
|
findByIdAndDelete: (id = "") => {
|
|
94
132
|
queryState.action = "findByIdAndDelete";
|
|
95
133
|
queryState.id = id;
|
|
134
|
+
Object.defineProperty(handler, "name", {
|
|
135
|
+
value: `model:${queryState.action}:${collectionName}`,
|
|
136
|
+
});
|
|
96
137
|
return handler;
|
|
97
138
|
},
|
|
98
139
|
};
|
|
@@ -137,7 +178,7 @@ const usingMongoDb = (collectionName, config = { type: 'external' }) => {
|
|
|
137
178
|
match = { ...match, ...queryState.match };
|
|
138
179
|
{
|
|
139
180
|
if (req.query.sort && queryState.action !== "aggregate") {
|
|
140
|
-
const sortQueryIndex = realTimeQueries.findIndex((q) =>
|
|
181
|
+
const sortQueryIndex = realTimeQueries.findIndex((q) => "type" in q && q.type == "sort");
|
|
141
182
|
const sortStr = Array.isArray(req.query.sort)
|
|
142
183
|
? req.query.sort[0]
|
|
143
184
|
: req.query.sort;
|
|
@@ -151,63 +192,110 @@ const usingMongoDb = (collectionName, config = { type: 'external' }) => {
|
|
|
151
192
|
realTimeQueries.splice(sortQueryIndex, 1, {
|
|
152
193
|
type: "sort",
|
|
153
194
|
value: {
|
|
154
|
-
...(
|
|
195
|
+
...(realTimeQueries[sortQueryIndex] &&
|
|
196
|
+
"value" in realTimeQueries[sortQueryIndex] &&
|
|
197
|
+
typeof realTimeQueries[sortQueryIndex].value === "object" &&
|
|
198
|
+
realTimeQueries[sortQueryIndex].value !== null
|
|
199
|
+
? realTimeQueries[sortQueryIndex].value
|
|
200
|
+
: {}),
|
|
155
201
|
...sortObject,
|
|
156
202
|
_id: 1,
|
|
157
203
|
},
|
|
158
204
|
});
|
|
159
205
|
}
|
|
160
206
|
if (req.query.page && queryState.action !== "aggregate") {
|
|
161
|
-
const pageStr = Array.isArray(req.query.page)
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
207
|
+
const pageStr = Array.isArray(req.query.page)
|
|
208
|
+
? req.query.page[0]
|
|
209
|
+
: typeof req.query.page === "string"
|
|
210
|
+
? req.query.page
|
|
211
|
+
: "";
|
|
212
|
+
const limitStr = Array.isArray(req.query.limit)
|
|
213
|
+
? req.query.limit[0]
|
|
214
|
+
: typeof req.query.limit === "string"
|
|
215
|
+
? req.query.limit
|
|
216
|
+
: "";
|
|
217
|
+
const pageNum = parseInt(typeof pageStr === "string" ? pageStr : "") || 1;
|
|
218
|
+
const limitNum = parseInt(typeof limitStr === "string" ? limitStr : "") ||
|
|
219
|
+
configs?.pagination?.quantity ||
|
|
220
|
+
20;
|
|
221
|
+
if (realTimeQueries.findIndex((q) => "type" in q && q.type == "skip") ==
|
|
222
|
+
-1)
|
|
166
223
|
realTimeQueries.push({
|
|
167
224
|
type: "skip",
|
|
168
225
|
value: (pageNum - 1) * limitNum,
|
|
169
226
|
});
|
|
170
|
-
if (realTimeQueries.findIndex((q) =>
|
|
227
|
+
if (realTimeQueries.findIndex((q) => "type" in q && q.type == "limit") ==
|
|
228
|
+
-1)
|
|
171
229
|
realTimeQueries.push({
|
|
172
230
|
type: "limit",
|
|
173
231
|
value: limitNum,
|
|
174
232
|
});
|
|
175
233
|
}
|
|
176
234
|
else if (req.query.limit && queryState.action !== "aggregate") {
|
|
177
|
-
const pageStrAgg = Array.isArray(req.query.page)
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
235
|
+
const pageStrAgg = Array.isArray(req.query.page)
|
|
236
|
+
? req.query.page[0]
|
|
237
|
+
: typeof req.query.page === "string"
|
|
238
|
+
? req.query.page
|
|
239
|
+
: "";
|
|
240
|
+
const limitStrAgg = Array.isArray(req.query.limit)
|
|
241
|
+
? req.query.limit[0]
|
|
242
|
+
: typeof req.query.limit === "string"
|
|
243
|
+
? req.query.limit
|
|
244
|
+
: "";
|
|
245
|
+
const pageNumAgg = parseInt(typeof pageStrAgg === "string" ? pageStrAgg : "") || 1;
|
|
246
|
+
const limitNumAgg = parseInt(typeof limitStrAgg === "string" ? limitStrAgg : "") || 20;
|
|
247
|
+
realTimeQueries.push({ $skip: (pageNumAgg - 1) * limitNumAgg }, {
|
|
248
|
+
$limit: parseInt(Array.isArray(req.query.limit)
|
|
182
249
|
? String(req.query.limit[0])
|
|
183
|
-
: typeof req.query.limit ===
|
|
250
|
+
: typeof req.query.limit === "string"
|
|
184
251
|
? req.query.limit
|
|
185
252
|
: req.query.limit !== undefined
|
|
186
253
|
? String(req.query.limit)
|
|
187
|
-
:
|
|
254
|
+
: ""),
|
|
255
|
+
});
|
|
188
256
|
}
|
|
189
257
|
else if (req.query.limit && queryState.action == "aggregate") {
|
|
190
258
|
realTimeQueries.push({ $limit: parseInt(String(req.query.limit)) });
|
|
191
259
|
}
|
|
192
260
|
if (req.query.select && queryState.action !== "aggregate") {
|
|
193
|
-
const selectQueryIndex = realTimeQueries.findIndex((q) =>
|
|
261
|
+
const selectQueryIndex = realTimeQueries.findIndex((q) => "type" in q && q.type == "select");
|
|
194
262
|
if (selectQueryIndex == -1)
|
|
195
263
|
realTimeQueries.push({ type: "select", value: req.query.select });
|
|
196
264
|
}
|
|
197
265
|
}
|
|
198
266
|
try {
|
|
199
|
-
const page = parseInt(Array.isArray(req.query.page)
|
|
200
|
-
|
|
267
|
+
const page = parseInt(Array.isArray(req.query.page)
|
|
268
|
+
? String(req.query.page[0])
|
|
269
|
+
: typeof req.query.page === "string"
|
|
270
|
+
? req.query.page
|
|
271
|
+
: "") || 1;
|
|
272
|
+
const limit = parseInt(Array.isArray(req.query.limit)
|
|
273
|
+
? String(req.query.limit[0])
|
|
274
|
+
: typeof req.query.limit === "string"
|
|
275
|
+
? req.query.limit
|
|
276
|
+
: req.query.limit !== undefined
|
|
277
|
+
? String(req.query.limit)
|
|
278
|
+
: "") ||
|
|
201
279
|
configs.pagination?.quantity ||
|
|
202
280
|
20;
|
|
203
281
|
switch (queryState.action) {
|
|
204
282
|
case "find":
|
|
205
283
|
if (configs.pagination?.detailed && req.query.page) {
|
|
206
|
-
const page = parseInt(Array.isArray(req.query.page)
|
|
207
|
-
|
|
284
|
+
const page = parseInt(Array.isArray(req.query.page)
|
|
285
|
+
? String(req.query.page[0])
|
|
286
|
+
: typeof req.query.page === "string"
|
|
287
|
+
? req.query.page
|
|
288
|
+
: "") || 1;
|
|
289
|
+
const limit = parseInt(Array.isArray(req.query.limit)
|
|
290
|
+
? String(req.query.limit[0])
|
|
291
|
+
: typeof req.query.limit === "string"
|
|
292
|
+
? req.query.limit
|
|
293
|
+
: req.query.limit !== undefined
|
|
294
|
+
? String(req.query.limit)
|
|
295
|
+
: "") ||
|
|
208
296
|
configs.pagination?.quantity ||
|
|
209
297
|
20;
|
|
210
|
-
console.log(
|
|
298
|
+
console.log("db", 261, model, config.path);
|
|
211
299
|
const totalPages = Math.ceil((await model.countDocuments(match)) / limit);
|
|
212
300
|
detail = {
|
|
213
301
|
...detail,
|
|
@@ -291,17 +379,19 @@ const usingMongoDb = (collectionName, config = { type: 'external' }) => {
|
|
|
291
379
|
{
|
|
292
380
|
$addFields: {
|
|
293
381
|
totalPages: { $ceil: { $divide: ["$count", limit] } },
|
|
294
|
-
page,
|
|
382
|
+
page,
|
|
383
|
+
limit,
|
|
295
384
|
},
|
|
296
385
|
},
|
|
297
386
|
{
|
|
298
|
-
$unset: [
|
|
299
|
-
}
|
|
387
|
+
$unset: ["_id", "count"],
|
|
388
|
+
},
|
|
300
389
|
],
|
|
301
390
|
},
|
|
302
|
-
},
|
|
303
|
-
|
|
304
|
-
|
|
391
|
+
},
|
|
392
|
+
{
|
|
393
|
+
$unwind: "$detail",
|
|
394
|
+
},
|
|
305
395
|
];
|
|
306
396
|
}
|
|
307
397
|
else {
|
|
@@ -309,16 +399,22 @@ const usingMongoDb = (collectionName, config = { type: 'external' }) => {
|
|
|
309
399
|
{
|
|
310
400
|
$facet: {
|
|
311
401
|
content: [...realTimeQueries],
|
|
312
|
-
}
|
|
313
|
-
}
|
|
402
|
+
},
|
|
403
|
+
},
|
|
314
404
|
];
|
|
315
405
|
}
|
|
316
406
|
// res.status(200).json([...queryState.pipeline , ...realTimeQueries])
|
|
317
407
|
if (typeof queryState.pipeline == "function") {
|
|
318
|
-
data = model?.[queryState.action]?.call(model, [
|
|
408
|
+
data = model?.[queryState.action]?.call(model, [
|
|
409
|
+
...queryState.pipeline(req),
|
|
410
|
+
...realTimeQueries,
|
|
411
|
+
]);
|
|
319
412
|
}
|
|
320
413
|
else {
|
|
321
|
-
data = model?.[queryState.action]?.call(model, [
|
|
414
|
+
data = model?.[queryState.action]?.call(model, [
|
|
415
|
+
...(queryState.pipeline || []),
|
|
416
|
+
...realTimeQueries,
|
|
417
|
+
]);
|
|
322
418
|
}
|
|
323
419
|
break;
|
|
324
420
|
case "findByIdAndUpdate":
|
|
@@ -341,7 +437,7 @@ const usingMongoDb = (collectionName, config = { type: 'external' }) => {
|
|
|
341
437
|
}
|
|
342
438
|
if (queryState.action != "aggregate")
|
|
343
439
|
realTimeQueries.forEach((q) => {
|
|
344
|
-
if (
|
|
440
|
+
if ("type" in q && typeof data?.[q.type] === "function") {
|
|
345
441
|
data = data[q.type].call(data, q.value);
|
|
346
442
|
}
|
|
347
443
|
});
|
|
@@ -357,13 +453,19 @@ const usingMongoDb = (collectionName, config = { type: 'external' }) => {
|
|
|
357
453
|
}
|
|
358
454
|
else {
|
|
359
455
|
if (res.logger && req.user) {
|
|
360
|
-
if (queryState.action &&
|
|
456
|
+
if (queryState.action &&
|
|
457
|
+
queryState.action.match(/create|update|delete/i)?.[0]) {
|
|
361
458
|
res.logger(`${{ log: "لاگها" }[collectionName] ||
|
|
362
459
|
(await (0, translator_1.default)(`${collectionName}`))} ${data.name || data.title || data.id || data._id || ""} توسط ${(req.user?.firstName ? req.user?.firstName + " " : "") +
|
|
363
460
|
(req.user?.lastName || "") ||
|
|
364
|
-
`ادمین با شماره ${req.user.phoneNumber}`} ${{
|
|
461
|
+
`ادمین با شماره ${req.user.phoneNumber}`} ${{
|
|
462
|
+
create: "ایجاد",
|
|
463
|
+
update: "بروزرسانی",
|
|
464
|
+
delete: "حذف",
|
|
465
|
+
nothing: "",
|
|
466
|
+
}[queryState.action
|
|
365
467
|
.match(/create|update|delete/i)?.[0]
|
|
366
|
-
?.toLowerCase() ||
|
|
468
|
+
?.toLowerCase() || "nothing"] || queryState.action} شد`, queryState.action.match(/update/i)?.[0]
|
|
367
469
|
? (await Promise.all(Object.entries(data._doc)
|
|
368
470
|
.filter(([key, value]) => ["_id", "__v", "updatedAt"].includes(key)
|
|
369
471
|
? false
|
|
@@ -390,20 +492,27 @@ const usingMongoDb = (collectionName, config = { type: 'external' }) => {
|
|
|
390
492
|
}
|
|
391
493
|
}
|
|
392
494
|
const action = queryState.action?.match(/create|update|delet/i)?.[0] || "find";
|
|
393
|
-
const resBody = queryState.action ==
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
495
|
+
const resBody = queryState.action == "aggregate"
|
|
496
|
+
? {
|
|
497
|
+
message: config?.message ||
|
|
498
|
+
`the ${collectionName} was found successfully`,
|
|
499
|
+
content: [],
|
|
500
|
+
...data[0],
|
|
501
|
+
}
|
|
502
|
+
: {
|
|
503
|
+
content: data,
|
|
504
|
+
...{ detail: Object.keys(detail).length ? detail : undefined },
|
|
505
|
+
message: config?.message ||
|
|
506
|
+
`the ${collectionName} was ${action == "find" ? "found" : action + "ed"}`,
|
|
507
|
+
};
|
|
402
508
|
res.success ? res.success(200, resBody) : res.status(200).json(resBody);
|
|
403
509
|
}
|
|
404
510
|
}
|
|
405
511
|
catch (err) {
|
|
406
|
-
if (err &&
|
|
512
|
+
if (err &&
|
|
513
|
+
typeof err === "object" &&
|
|
514
|
+
"errorResponse" in err &&
|
|
515
|
+
err.errorResponse?.code == 11000)
|
|
407
516
|
return next({
|
|
408
517
|
status: 405,
|
|
409
518
|
json: {
|
|
@@ -474,7 +583,7 @@ const db = (collectionName, config = configs) => {
|
|
|
474
583
|
dbType: "mongodb",
|
|
475
584
|
path: "../models",
|
|
476
585
|
dbEnv: "DB_URL",
|
|
477
|
-
type:
|
|
586
|
+
type: "external",
|
|
478
587
|
...(0, getConfig_1.default)("db"),
|
|
479
588
|
};
|
|
480
589
|
Object.entries(config).forEach(([key, value]) => {
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.default = swaggerLoader;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const swagger_ui_express_1 = __importDefault(require("swagger-ui-express"));
|
|
10
|
+
const swagger_themes_1 = require("swagger-themes");
|
|
11
|
+
const METHODS_WITH_BODY = ["post", "put", "patch"];
|
|
12
|
+
/* ===================== HELPERS ======================= */
|
|
13
|
+
function extractPath(layer) {
|
|
14
|
+
if (layer.regexp && layer.regexp.source !== "^\\/?$") {
|
|
15
|
+
return layer.regexp.source
|
|
16
|
+
.replace("^\\/", "/")
|
|
17
|
+
.replace("\\/?(?=\\/|$)", "")
|
|
18
|
+
.replace(/\\\//g, "/");
|
|
19
|
+
}
|
|
20
|
+
return "";
|
|
21
|
+
}
|
|
22
|
+
function splitRouteByMethod(route) {
|
|
23
|
+
const result = {};
|
|
24
|
+
route.stack.forEach((layer, idx) => {
|
|
25
|
+
if (layer.method) {
|
|
26
|
+
const method = layer.method.toLowerCase();
|
|
27
|
+
const middlewares = [];
|
|
28
|
+
for (let i = 0; i < idx; i++) {
|
|
29
|
+
if (route.stack[i].name !== "bound dispatch")
|
|
30
|
+
middlewares.push(route.stack[i]);
|
|
31
|
+
}
|
|
32
|
+
result[method] = { middlewares, handler: layer };
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
return result;
|
|
36
|
+
}
|
|
37
|
+
/* ================== YUP → OPENAPI ==================== */
|
|
38
|
+
function resolveYupSchema(schema) {
|
|
39
|
+
if (!schema)
|
|
40
|
+
return null;
|
|
41
|
+
if (schema?.type === "lazy" && typeof schema._resolve === "function") {
|
|
42
|
+
return schema._resolve({});
|
|
43
|
+
}
|
|
44
|
+
return schema;
|
|
45
|
+
}
|
|
46
|
+
function translateField(field) {
|
|
47
|
+
if (!field)
|
|
48
|
+
return { type: "string" };
|
|
49
|
+
return {
|
|
50
|
+
type: field.type === "array" ? "array" : field.type || "string",
|
|
51
|
+
nullable: field.nullable || false,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function translateYupSchema(schema) {
|
|
55
|
+
schema = resolveYupSchema(schema);
|
|
56
|
+
if (!schema)
|
|
57
|
+
return null;
|
|
58
|
+
const described = schema.describe();
|
|
59
|
+
const properties = Object.entries(described.fields ?? {}).reduce((acc, [name, field]) => {
|
|
60
|
+
acc[name] = translateField(field);
|
|
61
|
+
return acc;
|
|
62
|
+
}, {});
|
|
63
|
+
return {
|
|
64
|
+
type: "object",
|
|
65
|
+
properties,
|
|
66
|
+
required: Object.entries(described.fields ?? {})
|
|
67
|
+
.filter(([_, f]) => !(f.optional || f.nullable))
|
|
68
|
+
.map(([name]) => name),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
function getAuthStatus(middlewares) {
|
|
72
|
+
for (const mw of middlewares) {
|
|
73
|
+
if (!mw.name)
|
|
74
|
+
continue;
|
|
75
|
+
if (mw.name.startsWith("auth")) {
|
|
76
|
+
const parts = mw.name.split(":");
|
|
77
|
+
if (parts[1] === "any")
|
|
78
|
+
return { type: "any", raw: mw.name };
|
|
79
|
+
return { type: "required", raw: mw.name };
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return { type: "none", raw: null };
|
|
83
|
+
}
|
|
84
|
+
/* ==================== ROUTER SCANNER ==================== */
|
|
85
|
+
function scanRouter(router, base = "") {
|
|
86
|
+
const routes = [];
|
|
87
|
+
router.stack.forEach((layer) => {
|
|
88
|
+
if (layer.route) {
|
|
89
|
+
routes.push({
|
|
90
|
+
path: base + layer.route.path,
|
|
91
|
+
methods: splitRouteByMethod(layer.route),
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
else if (layer.name === "router" && layer.handle?.stack) {
|
|
95
|
+
routes.push(...scanRouter(layer.handle, base + extractPath(layer)));
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
return routes;
|
|
99
|
+
}
|
|
100
|
+
/* ================== MAIN ANALYZER ===================== */
|
|
101
|
+
function routeAnalyzer(route, routerName) {
|
|
102
|
+
const routerDetails = {};
|
|
103
|
+
const scanned = scanRouter(route);
|
|
104
|
+
const paramsRegex = /:[^/]+/g;
|
|
105
|
+
scanned.forEach((route) => {
|
|
106
|
+
const fullPath = `/${routerName}${route.path
|
|
107
|
+
.replace(/^\/$/, "")
|
|
108
|
+
.replaceAll(paramsRegex, (r) => `{${r.slice(1)}}`)}`;
|
|
109
|
+
routerDetails[fullPath] = {};
|
|
110
|
+
Object.entries(route.methods).forEach(([method, detail]) => {
|
|
111
|
+
const doc = {
|
|
112
|
+
tags: [routerName.replace("_", " ")],
|
|
113
|
+
description: "Public route",
|
|
114
|
+
};
|
|
115
|
+
const validation = detail.middlewares.find((mw) => mw.handle?.__validationSchema)?.handle.__validationSchema;
|
|
116
|
+
// If body exists
|
|
117
|
+
if (METHODS_WITH_BODY.includes(method)) {
|
|
118
|
+
if (validation?.body) {
|
|
119
|
+
doc.requestBody = {
|
|
120
|
+
required: true,
|
|
121
|
+
content: {
|
|
122
|
+
"application/json": {
|
|
123
|
+
schema: translateYupSchema(validation.body),
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
// Auth
|
|
130
|
+
const auth = getAuthStatus(detail.middlewares);
|
|
131
|
+
if (auth.type === "required") {
|
|
132
|
+
doc.security = [{ bearerAuth: [] }];
|
|
133
|
+
doc.description = `Requires authentication (${auth.raw})`;
|
|
134
|
+
}
|
|
135
|
+
else if (auth.type === "any") {
|
|
136
|
+
doc.description = "Optional login route";
|
|
137
|
+
}
|
|
138
|
+
routerDetails[fullPath][method] = doc;
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
return routerDetails;
|
|
142
|
+
}
|
|
143
|
+
/* =================== LOAD MODULES ==================== */
|
|
144
|
+
function RouterFetcher(baseDir) {
|
|
145
|
+
const modules = fs_1.default.readdirSync(baseDir);
|
|
146
|
+
let paths = {};
|
|
147
|
+
const tags = [];
|
|
148
|
+
modules.forEach((mf) => {
|
|
149
|
+
const routerPath = path_1.default.join(baseDir, mf, `${mf}.routes.js`);
|
|
150
|
+
try {
|
|
151
|
+
const router = require(routerPath);
|
|
152
|
+
paths = { ...paths, ...routeAnalyzer(router, mf) };
|
|
153
|
+
tags.push({
|
|
154
|
+
name: mf.replace("_", " "),
|
|
155
|
+
description: `${mf} operations`,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
catch (err) {
|
|
159
|
+
console.error("Swagger loading error:", err.message);
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
return {
|
|
163
|
+
openapi: "3.0.3",
|
|
164
|
+
info: {
|
|
165
|
+
title: `${require(path_1.default.join(process.cwd(), "package.json")).name} APIs`,
|
|
166
|
+
version: "1.0.0",
|
|
167
|
+
},
|
|
168
|
+
servers: [{ url: "/api/v1" }],
|
|
169
|
+
paths,
|
|
170
|
+
tags,
|
|
171
|
+
components: {
|
|
172
|
+
securitySchemes: {
|
|
173
|
+
bearerAuth: { type: "http", scheme: "bearer", bearerFormat: "JWT" },
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
/* ==================== EXPORT HOOK ==================== */
|
|
179
|
+
function swaggerLoader(app, baseDir = path_1.default.join(process.cwd(), "src/module")) {
|
|
180
|
+
const doc = RouterFetcher(baseDir);
|
|
181
|
+
const theme = new swagger_themes_1.SwaggerTheme();
|
|
182
|
+
app.use("/docs", swagger_ui_express_1.default.serve, swagger_ui_express_1.default.setup(doc, {
|
|
183
|
+
customCss: theme.getBuffer(swagger_themes_1.SwaggerThemeNameEnum.DARK),
|
|
184
|
+
}));
|
|
185
|
+
}
|
package/dist/cjs/index.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import auth from
|
|
2
|
-
import db from
|
|
3
|
-
import uploader from
|
|
4
|
-
import validator from
|
|
1
|
+
import auth from "./auth/auth";
|
|
2
|
+
import db from "./db/db";
|
|
3
|
+
import uploader from "./uploader/uploader";
|
|
4
|
+
import validator from "./validator/validator";
|
|
5
|
+
import document from "./document/document";
|
|
5
6
|
declare const utils: {
|
|
6
7
|
translator: (text?: string, lang?: string) => Promise<unknown>;
|
|
7
8
|
};
|
|
@@ -67,4 +68,4 @@ declare const models: {
|
|
|
67
68
|
declare const modules: {
|
|
68
69
|
translation: import("express-serve-static-core").Router;
|
|
69
70
|
};
|
|
70
|
-
export { auth, db, uploader, validator, models, modules, utils };
|
|
71
|
+
export { auth, db, uploader, validator, models, modules, utils, document };
|