speedly 2.0.38 → 2.0.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/README.md +470 -171
- package/dist/cjs/config/init.js +2 -2
- package/dist/cjs/kit/db/db.js +16 -0
- package/dist/cjs/model/translation.d.ts +37 -25
- package/dist/cjs/util/translator.d.ts +1 -1
- package/dist/config/init.d.ts +23 -0
- package/dist/config/init.js +93 -0
- package/dist/document/document.d.ts +5 -0
- package/dist/document/document.js +270 -0
- package/dist/document/index.d.ts +2 -0
- package/dist/document/index.js +7 -0
- package/dist/document/parser.d.ts +1 -0
- package/dist/document/parser.js +11 -0
- package/dist/esm/config/init.js +2 -2
- package/dist/esm/kit/db/db.js +16 -0
- package/dist/esm/model/translation.d.ts +37 -25
- package/dist/esm/util/translator.d.ts +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.js +13 -0
- package/dist/{cjs → kit}/auth/auth.js +1 -1
- package/dist/{cjs → kit}/db/db.d.ts +15 -0
- package/dist/{cjs → kit}/db/db.js +44 -19
- package/dist/kit/index.d.ts +5 -0
- package/dist/kit/index.js +14 -0
- package/dist/{cjs → kit}/uploader/uploader.d.ts +2 -2
- package/dist/{esm → kit}/uploader/uploader.js +22 -17
- package/dist/model/index.d.ts +2 -0
- package/dist/model/index.js +8 -0
- package/dist/model/translation.d.ts +71 -0
- package/dist/model/translation.js +13 -0
- package/dist/modules/index.d.ts +2 -0
- package/dist/modules/index.js +8 -0
- package/dist/modules/translation/translation.routes.d.ts +2 -0
- package/dist/modules/translation/translation.routes.js +24 -0
- package/dist/modules/translation/translation.validator.d.ts +15 -0
- package/dist/modules/translation/translation.validator.js +22 -0
- package/dist/util/getConfig.d.ts +4 -0
- package/dist/util/getConfig.js +40 -0
- package/dist/util/index.d.ts +2 -0
- package/dist/util/index.js +8 -0
- package/dist/util/makeOptional.d.ts +10 -0
- package/dist/util/makeOptional.js +47 -0
- package/dist/util/strToObj.d.ts +2 -0
- package/dist/util/strToObj.js +9 -0
- package/dist/util/translator.d.ts +2 -0
- package/dist/util/translator.js +74 -0
- package/examples/blog-routes/blog/blog.routes.js +15 -0
- package/examples/blog-routes/blog/blog.validator.js +35 -0
- package/examples/blog-routes/role/role.routes.js +14 -0
- package/examples/blog-routes/role/role.validator.js +28 -0
- package/examples/blog-routes/user/user.controller.js +97 -0
- package/examples/blog-routes/user/user.routes.js +18 -0
- package/examples/blog-routes/user/user.validator.js +53 -0
- package/package.json +65 -66
- package/dist/cjs/auth/auth2.d.ts +0 -18
- package/dist/cjs/auth/auth2.js +0 -93
- package/dist/cjs/uploader/uploader.js +0 -145
- package/dist/cjs/yup.config.d.ts +0 -2
- package/dist/cjs/yup.config.js +0 -24
- package/dist/esm/auth/auth.d.ts +0 -3
- package/dist/esm/auth/auth.js +0 -38
- package/dist/esm/auth/types.d.ts +0 -19
- package/dist/esm/auth/types.js +0 -2
- package/dist/esm/db/db.d.ts +0 -182
- package/dist/esm/db/db.js +0 -594
- package/dist/esm/db/utils.d.ts +0 -3
- package/dist/esm/db/utils.js +0 -15
- package/dist/esm/uploader/uploader.d.ts +0 -24
- package/dist/esm/validator/validator.d.ts +0 -9
- package/dist/esm/validator/validator.js +0 -36
- /package/dist/{cjs → kit}/auth/auth.d.ts +0 -0
- /package/dist/{cjs → kit}/auth/types.d.ts +0 -0
- /package/dist/{cjs → kit}/auth/types.js +0 -0
- /package/dist/{cjs → kit}/db/utils.d.ts +0 -0
- /package/dist/{cjs → kit}/db/utils.js +0 -0
- /package/dist/{cjs → kit}/validator/validator.d.ts +0 -0
- /package/dist/{cjs → kit}/validator/validator.js +0 -0
package/dist/cjs/kit/db/db.js
CHANGED
|
@@ -236,6 +236,22 @@ const usingMongoDb = (collectionName, config = { type: "external" }) => {
|
|
|
236
236
|
});
|
|
237
237
|
}
|
|
238
238
|
else if (req.query.limit && queryState.action !== "aggregate") {
|
|
239
|
+
const limitStr = Array.isArray(req.query.limit)
|
|
240
|
+
? req.query.limit[0]
|
|
241
|
+
: typeof req.query.limit === "string"
|
|
242
|
+
? req.query.limit
|
|
243
|
+
: "";
|
|
244
|
+
const limitNum = parseInt(typeof limitStr === "string" ? limitStr : "") ||
|
|
245
|
+
configs?.pagination?.quantity ||
|
|
246
|
+
20;
|
|
247
|
+
if (realTimeQueries.findIndex((q) => "type" in q && q.type == "limit") ==
|
|
248
|
+
-1)
|
|
249
|
+
realTimeQueries.push({
|
|
250
|
+
type: "limit",
|
|
251
|
+
value: limitNum,
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
else if (req.query.page && queryState.action == "aggregate") {
|
|
239
255
|
const pageStrAgg = Array.isArray(req.query.page)
|
|
240
256
|
? req.query.page[0]
|
|
241
257
|
: typeof req.query.page === "string"
|
|
@@ -1,59 +1,71 @@
|
|
|
1
1
|
import mongoose from 'mongoose';
|
|
2
2
|
declare const model: mongoose.Model<{
|
|
3
|
-
createdAt: NativeDate;
|
|
4
|
-
updatedAt: NativeDate;
|
|
5
|
-
} & {
|
|
6
3
|
text: string;
|
|
7
4
|
lang: string;
|
|
8
5
|
translatedText: string;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
} & {
|
|
6
|
+
} & mongoose.DefaultTimestampProps, {}, {}, {
|
|
7
|
+
id: string;
|
|
8
|
+
}, mongoose.Document<unknown, {}, {
|
|
13
9
|
text: string;
|
|
14
10
|
lang: string;
|
|
15
11
|
translatedText: string;
|
|
16
|
-
}
|
|
12
|
+
} & mongoose.DefaultTimestampProps, {
|
|
13
|
+
id: string;
|
|
14
|
+
}, {
|
|
17
15
|
timestamps: true;
|
|
18
|
-
}> & {
|
|
19
|
-
createdAt: NativeDate;
|
|
20
|
-
updatedAt: NativeDate;
|
|
21
|
-
} & {
|
|
16
|
+
}> & Omit<{
|
|
22
17
|
text: string;
|
|
23
18
|
lang: string;
|
|
24
19
|
translatedText: string;
|
|
25
|
-
} & {
|
|
20
|
+
} & mongoose.DefaultTimestampProps & {
|
|
26
21
|
_id: mongoose.Types.ObjectId;
|
|
27
22
|
} & {
|
|
28
23
|
__v: number;
|
|
29
|
-
},
|
|
24
|
+
}, "id"> & {
|
|
25
|
+
id: string;
|
|
26
|
+
}, mongoose.Schema<any, mongoose.Model<any, any, any, any, any, any, any>, {}, {}, {}, {}, {
|
|
30
27
|
timestamps: true;
|
|
31
28
|
}, {
|
|
32
|
-
createdAt: NativeDate;
|
|
33
|
-
updatedAt: NativeDate;
|
|
34
|
-
} & {
|
|
35
29
|
text: string;
|
|
36
30
|
lang: string;
|
|
37
31
|
translatedText: string;
|
|
38
|
-
}, mongoose.Document<unknown, {},
|
|
39
|
-
createdAt: NativeDate;
|
|
40
|
-
updatedAt: NativeDate;
|
|
41
|
-
} & {
|
|
32
|
+
} & mongoose.DefaultTimestampProps, mongoose.Document<unknown, {}, {
|
|
42
33
|
text: string;
|
|
43
34
|
lang: string;
|
|
44
35
|
translatedText: string;
|
|
45
|
-
}
|
|
36
|
+
} & mongoose.DefaultTimestampProps, {
|
|
37
|
+
id: string;
|
|
38
|
+
}, Omit<mongoose.DefaultSchemaOptions, "timestamps"> & {
|
|
46
39
|
timestamps: true;
|
|
47
|
-
}
|
|
40
|
+
}> & Omit<{
|
|
41
|
+
text: string;
|
|
42
|
+
lang: string;
|
|
43
|
+
translatedText: string;
|
|
44
|
+
} & mongoose.DefaultTimestampProps & {
|
|
45
|
+
_id: mongoose.Types.ObjectId;
|
|
46
|
+
} & {
|
|
47
|
+
__v: number;
|
|
48
|
+
}, "id"> & {
|
|
49
|
+
id: string;
|
|
50
|
+
}, unknown, {
|
|
51
|
+
text: string;
|
|
52
|
+
lang: string;
|
|
53
|
+
translatedText: string;
|
|
48
54
|
createdAt: NativeDate;
|
|
49
55
|
updatedAt: NativeDate;
|
|
50
56
|
} & {
|
|
57
|
+
_id: mongoose.Types.ObjectId;
|
|
58
|
+
} & {
|
|
59
|
+
__v: number;
|
|
60
|
+
}>, {
|
|
51
61
|
text: string;
|
|
52
62
|
lang: string;
|
|
53
63
|
translatedText: string;
|
|
54
|
-
|
|
64
|
+
createdAt: NativeDate;
|
|
65
|
+
updatedAt: NativeDate;
|
|
66
|
+
} & {
|
|
55
67
|
_id: mongoose.Types.ObjectId;
|
|
56
68
|
} & {
|
|
57
69
|
__v: number;
|
|
58
|
-
}
|
|
70
|
+
}>;
|
|
59
71
|
export default model;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare const _default: (text?: string, lang?: string) => Promise<
|
|
1
|
+
declare const _default: (text?: string, lang?: string) => Promise<string>;
|
|
2
2
|
export default _default;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import express from "express";
|
|
2
|
+
type InitConfig = {
|
|
3
|
+
notFoundHandler?: boolean;
|
|
4
|
+
homeHandler?: boolean;
|
|
5
|
+
errorHandler?: boolean;
|
|
6
|
+
jsonParser?: boolean;
|
|
7
|
+
documentation?: boolean | {
|
|
8
|
+
servers: {
|
|
9
|
+
url: string;
|
|
10
|
+
description?: string;
|
|
11
|
+
}[];
|
|
12
|
+
};
|
|
13
|
+
urlEncodedParser?: boolean;
|
|
14
|
+
cookieParser?: boolean;
|
|
15
|
+
staticFiles?: boolean;
|
|
16
|
+
[key: string]: any;
|
|
17
|
+
};
|
|
18
|
+
export type InitFunction = (config?: InitConfig) => express.Express;
|
|
19
|
+
export type { InitConfig };
|
|
20
|
+
export default function speedly(config?: InitConfig): express.Express & {
|
|
21
|
+
speedlyConfig: InitConfig;
|
|
22
|
+
registerFallbacks: () => void;
|
|
23
|
+
};
|
|
@@ -0,0 +1,93 @@
|
|
|
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 = speedly;
|
|
7
|
+
const express_1 = __importDefault(require("express"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const fs_1 = __importDefault(require("fs"));
|
|
10
|
+
const util_1 = require("../util");
|
|
11
|
+
const document_1 = __importDefault(require("../document"));
|
|
12
|
+
const defaultConfig = {
|
|
13
|
+
notFoundHandler: true,
|
|
14
|
+
errorHandler: true,
|
|
15
|
+
homeHandler: true,
|
|
16
|
+
jsonParser: true,
|
|
17
|
+
documentation: true,
|
|
18
|
+
urlEncodedParser: true,
|
|
19
|
+
cookieParser: true,
|
|
20
|
+
staticFiles: true,
|
|
21
|
+
};
|
|
22
|
+
function speedly(config = {}) {
|
|
23
|
+
const finalConfig = { ...defaultConfig, ...config };
|
|
24
|
+
const app = (0, express_1.default)();
|
|
25
|
+
if (finalConfig.jsonParser)
|
|
26
|
+
app.use(express_1.default.json());
|
|
27
|
+
if (finalConfig.urlEncodedParser)
|
|
28
|
+
app.use(express_1.default.urlencoded({ extended: true }));
|
|
29
|
+
if (finalConfig.cookieParser) {
|
|
30
|
+
try {
|
|
31
|
+
const cookieParser = require("cookie-parser");
|
|
32
|
+
app.use(cookieParser());
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
if (error.code === "MODULE_NOT_FOUND") {
|
|
36
|
+
console.warn("cookie-parser module not founds. Please reinstall it to use cookieParser middleware.");
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
console.log("init", 48, fs_1.default.existsSync(path_1.default.join(process.cwd(), "src/module")));
|
|
41
|
+
if (finalConfig.documentation &&
|
|
42
|
+
fs_1.default.existsSync(path_1.default.join(process.cwd(), "src/module")))
|
|
43
|
+
(0, document_1.default)(app, path_1.default.join(process.cwd(), "src/module"), finalConfig.documentation === true
|
|
44
|
+
? undefined
|
|
45
|
+
: finalConfig.documentation.servers);
|
|
46
|
+
if (finalConfig.staticFiles)
|
|
47
|
+
app.use("/static", express_1.default.static("public"));
|
|
48
|
+
if (finalConfig.homeHandler) {
|
|
49
|
+
app.get("/", (req, res) => {
|
|
50
|
+
res.send(`<h1>Welcome to ${require(path_1.default.join(process.cwd(), "package.json")).name} App</h1>
|
|
51
|
+
<p>Your app is running successfully.</p>
|
|
52
|
+
${finalConfig.documentation
|
|
53
|
+
? '<p>Visit <a href="/docs">/docs</a> for API documentation.</p>'
|
|
54
|
+
: ""}`);
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
// user can call this manually if needed
|
|
58
|
+
const registerFallbacks = () => {
|
|
59
|
+
if (finalConfig.notFoundHandler) {
|
|
60
|
+
app.use((req, res) => res.status(404).json({ message: "Not Found" }));
|
|
61
|
+
}
|
|
62
|
+
if (finalConfig.errorHandler) {
|
|
63
|
+
app.use(async (err, req, res, _next) => {
|
|
64
|
+
console.log("app", 39, err);
|
|
65
|
+
const config = { translate: true, ...(err.config || {}) };
|
|
66
|
+
const body = err.json || {
|
|
67
|
+
message: err.message || "internal error",
|
|
68
|
+
};
|
|
69
|
+
if (err?.status == 401)
|
|
70
|
+
return res.status(err.status).json(body);
|
|
71
|
+
if (body.message && req.query.lang !== "en" && config.translate)
|
|
72
|
+
try {
|
|
73
|
+
body.message = await (0, util_1.translator)(body.message, (typeof req.query.lang === "string" ? req.query.lang : "fa") ||
|
|
74
|
+
"fa");
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
console.error("Translation error:", error);
|
|
78
|
+
}
|
|
79
|
+
res.status(err.status || 500).json(body);
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
// ⛔ we intercept listen, add fallback before server starts
|
|
84
|
+
const originalListen = app.listen.bind(app);
|
|
85
|
+
app.listen = (...args) => {
|
|
86
|
+
registerFallbacks();
|
|
87
|
+
return originalListen(...args);
|
|
88
|
+
};
|
|
89
|
+
// 🔓 expose config + extend points for override
|
|
90
|
+
app.speedlyConfig = finalConfig;
|
|
91
|
+
app.registerFallbacks = registerFallbacks;
|
|
92
|
+
return app;
|
|
93
|
+
}
|
|
@@ -0,0 +1,270 @@
|
|
|
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 parser_1 = require("./parser");
|
|
12
|
+
const METHODS_WITH_BODY = ["post", "put", "patch"];
|
|
13
|
+
/* ===================== HELPERS ======================= */
|
|
14
|
+
function extractPath(layer) {
|
|
15
|
+
if (layer.regexp && layer.regexp.source !== "^\\/?$") {
|
|
16
|
+
return layer.regexp.source
|
|
17
|
+
.replace("^\\/", "/")
|
|
18
|
+
.replace("\\/?(?=\\/|$)", "")
|
|
19
|
+
.replace(/\\\//g, "/");
|
|
20
|
+
}
|
|
21
|
+
return "";
|
|
22
|
+
}
|
|
23
|
+
function splitRouteByMethod(route) {
|
|
24
|
+
const result = {};
|
|
25
|
+
route.stack.forEach((layer, idx) => {
|
|
26
|
+
if (layer.method) {
|
|
27
|
+
const method = layer.method.toLowerCase();
|
|
28
|
+
const middlewares = [];
|
|
29
|
+
for (let i = 0; i < idx; i++) {
|
|
30
|
+
if (route.stack[i].name !== "bound dispatch")
|
|
31
|
+
middlewares.push(route.stack[i]);
|
|
32
|
+
}
|
|
33
|
+
result[method] = { middlewares, handler: layer };
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
return result;
|
|
37
|
+
}
|
|
38
|
+
/* ================== YUP → OPENAPI ==================== */
|
|
39
|
+
function resolveYupSchema(schema) {
|
|
40
|
+
if (!schema)
|
|
41
|
+
return null;
|
|
42
|
+
if (schema?.type === "lazy" && typeof schema._resolve === "function") {
|
|
43
|
+
return schema._resolve({});
|
|
44
|
+
}
|
|
45
|
+
return schema;
|
|
46
|
+
}
|
|
47
|
+
function translateField(field) {
|
|
48
|
+
if (!field)
|
|
49
|
+
return { type: "string" };
|
|
50
|
+
return {
|
|
51
|
+
type: field.type === "array" ? "array" : field.type || "string",
|
|
52
|
+
nullable: field.nullable || false,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function translateYupSchema(schema) {
|
|
56
|
+
schema = resolveYupSchema(schema);
|
|
57
|
+
if (!schema)
|
|
58
|
+
return null;
|
|
59
|
+
const described = schema.describe();
|
|
60
|
+
const properties = Object.entries(described.fields ?? {}).reduce((acc, [name, field]) => {
|
|
61
|
+
acc[name] = translateField(field);
|
|
62
|
+
return acc;
|
|
63
|
+
}, {});
|
|
64
|
+
return {
|
|
65
|
+
type: "object",
|
|
66
|
+
properties,
|
|
67
|
+
required: Object.entries(described.fields ?? {})
|
|
68
|
+
.filter(([_, f]) => !(f.optional || f.nullable))
|
|
69
|
+
.map(([name]) => name),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function getAuthStatus(middlewares) {
|
|
73
|
+
for (const mw of middlewares) {
|
|
74
|
+
if (!mw.name)
|
|
75
|
+
continue;
|
|
76
|
+
if (mw.name.startsWith("auth")) {
|
|
77
|
+
const parts = mw.name.split(":");
|
|
78
|
+
if (parts[1] === "any")
|
|
79
|
+
return { type: "any", raw: mw.name };
|
|
80
|
+
return { type: "required", raw: mw.name };
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return { type: "none", raw: null };
|
|
84
|
+
}
|
|
85
|
+
/* ==================== ROUTER SCANNER ==================== */
|
|
86
|
+
function scanRouter(router, base = "") {
|
|
87
|
+
const routes = [];
|
|
88
|
+
router.stack.forEach((layer) => {
|
|
89
|
+
if (layer.route) {
|
|
90
|
+
routes.push({
|
|
91
|
+
path: base + layer.route.path,
|
|
92
|
+
methods: splitRouteByMethod(layer.route),
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
else if (layer.name === "router" && layer.handle?.stack) {
|
|
96
|
+
routes.push(...scanRouter(layer.handle, base + extractPath(layer)));
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
return routes;
|
|
100
|
+
}
|
|
101
|
+
/* ================== MAIN ANALYZER ===================== */
|
|
102
|
+
function routeAnalyzer(route, routerName) {
|
|
103
|
+
const routerDetails = {};
|
|
104
|
+
const scanned = scanRouter(route);
|
|
105
|
+
scanned.forEach((route) => {
|
|
106
|
+
const fullPath = `/${routerName}${(0, parser_1.expressToSwagger)(route.path)}`;
|
|
107
|
+
routerDetails[fullPath] = {};
|
|
108
|
+
Object.entries(route.methods).forEach(([method, detail]) => {
|
|
109
|
+
const doc = {
|
|
110
|
+
tags: [routerName.replace("_", " ")],
|
|
111
|
+
description: "Public route",
|
|
112
|
+
};
|
|
113
|
+
const validation = detail.middlewares.find((mw) => mw.handle?.__validationSchema)?.handle.__validationSchema;
|
|
114
|
+
const pathParams = [...fullPath.matchAll(/{([^}]+)}/g)].map((m) => m[1]);
|
|
115
|
+
if (pathParams.length) {
|
|
116
|
+
doc.parameters = pathParams.map((name) => ({
|
|
117
|
+
name,
|
|
118
|
+
in: "path",
|
|
119
|
+
required: validation?.params?.fields?.[name]?.spec?.optional == false ||
|
|
120
|
+
!new RegExp(`\\{[^\\}]*${name}[^\\}]*\\}`).test(route.path),
|
|
121
|
+
schema: { type: "string" },
|
|
122
|
+
}));
|
|
123
|
+
}
|
|
124
|
+
// If body exists
|
|
125
|
+
if (METHODS_WITH_BODY.includes(method)) {
|
|
126
|
+
if (validation?.body) {
|
|
127
|
+
doc.requestBody = {
|
|
128
|
+
required: true,
|
|
129
|
+
content: {
|
|
130
|
+
"application/json": {
|
|
131
|
+
schema: translateYupSchema(validation.body),
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
// Response
|
|
138
|
+
doc.responses = {
|
|
139
|
+
"200": {
|
|
140
|
+
content: {
|
|
141
|
+
"application/json": {
|
|
142
|
+
schema: {
|
|
143
|
+
type: "object",
|
|
144
|
+
properties: {
|
|
145
|
+
message: { type: "string", example: "find successfully" },
|
|
146
|
+
content: {
|
|
147
|
+
oneOf: [
|
|
148
|
+
{
|
|
149
|
+
type: "array",
|
|
150
|
+
items: {
|
|
151
|
+
type: "object",
|
|
152
|
+
properties: {
|
|
153
|
+
id: { type: "string" },
|
|
154
|
+
name: { type: "string" },
|
|
155
|
+
},
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
type: "object",
|
|
160
|
+
properties: {
|
|
161
|
+
id: { type: "string" },
|
|
162
|
+
name: { type: "string" },
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
],
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
"400": {
|
|
173
|
+
content: {
|
|
174
|
+
"application/json": {
|
|
175
|
+
schema: {
|
|
176
|
+
type: "object",
|
|
177
|
+
properties: {
|
|
178
|
+
message: { type: "string", example: "module not found" },
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
|
+
},
|
|
184
|
+
};
|
|
185
|
+
// Auth
|
|
186
|
+
const auth = getAuthStatus(detail.middlewares);
|
|
187
|
+
if (auth.type === "required") {
|
|
188
|
+
doc.security = [{ bearerAuth: [] }];
|
|
189
|
+
doc.description = `Requires authentication (${auth.raw})`;
|
|
190
|
+
}
|
|
191
|
+
else if (auth.type === "any") {
|
|
192
|
+
doc.description = "Optional login route";
|
|
193
|
+
}
|
|
194
|
+
routerDetails[fullPath][method] = doc;
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
return routerDetails;
|
|
198
|
+
}
|
|
199
|
+
/* =================== LOAD MODULES ==================== */
|
|
200
|
+
function findRoutersInDir(dir) {
|
|
201
|
+
const entries = fs_1.default.readdirSync(dir, { withFileTypes: true });
|
|
202
|
+
const routers = [];
|
|
203
|
+
for (const entry of entries) {
|
|
204
|
+
const fullPath = path_1.default.join(dir, entry.name);
|
|
205
|
+
if (entry.isDirectory()) {
|
|
206
|
+
routers.push(...findRoutersInDir(fullPath));
|
|
207
|
+
}
|
|
208
|
+
else if (entry.isFile() &&
|
|
209
|
+
entry.name.match(/\.route(rs|r|s)?\.(js|ts)$/)) {
|
|
210
|
+
try {
|
|
211
|
+
if (require(fullPath)) {
|
|
212
|
+
routers.push(fullPath);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
catch (err) { }
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
return routers;
|
|
219
|
+
}
|
|
220
|
+
function RouterFetcher(baseDir, servers) {
|
|
221
|
+
const modules = findRoutersInDir(baseDir);
|
|
222
|
+
let paths = {};
|
|
223
|
+
const tags = [];
|
|
224
|
+
// Load each router and analyze
|
|
225
|
+
modules.forEach((routerPath) => {
|
|
226
|
+
const mf = [
|
|
227
|
+
...new Set(path_1.default
|
|
228
|
+
.relative(baseDir, routerPath)
|
|
229
|
+
.replaceAll(path_1.default.sep, "/")
|
|
230
|
+
.replaceAll(/\.[^/]+/g, "")
|
|
231
|
+
.split("/")),
|
|
232
|
+
]
|
|
233
|
+
.join("/")
|
|
234
|
+
.split(".")[0] || "default";
|
|
235
|
+
try {
|
|
236
|
+
const router = require(routerPath);
|
|
237
|
+
paths = { ...paths, ...routeAnalyzer(router, mf) };
|
|
238
|
+
tags.push({
|
|
239
|
+
name: mf.replace("_", " "),
|
|
240
|
+
description: `${mf} operations`,
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
catch (err) {
|
|
244
|
+
console.error("Swagger loading error:", err.message);
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
return {
|
|
248
|
+
openapi: "3.0.3",
|
|
249
|
+
info: {
|
|
250
|
+
title: `${require(path_1.default.join(process.cwd(), "package.json")).name} Documentation`,
|
|
251
|
+
version: "1.0.0",
|
|
252
|
+
},
|
|
253
|
+
servers,
|
|
254
|
+
paths,
|
|
255
|
+
tags,
|
|
256
|
+
components: {
|
|
257
|
+
securitySchemes: {
|
|
258
|
+
bearerAuth: { type: "http", scheme: "bearer", bearerFormat: "JWT" },
|
|
259
|
+
},
|
|
260
|
+
},
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
/* ==================== EXPORT HOOK ==================== */
|
|
264
|
+
function swaggerLoader(app, baseDir = path_1.default.join(process.cwd(), "src/module"), servers = [{ url: "/api/v1" }]) {
|
|
265
|
+
const doc = RouterFetcher(baseDir, servers);
|
|
266
|
+
const theme = new swagger_themes_1.SwaggerTheme();
|
|
267
|
+
app.use("/docs", swagger_ui_express_1.default.serve, swagger_ui_express_1.default.setup(doc, {
|
|
268
|
+
customCss: theme.getBuffer(swagger_themes_1.SwaggerThemeNameEnum.DARK),
|
|
269
|
+
}));
|
|
270
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
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
|
+
const document_1 = __importDefault(require("./document"));
|
|
7
|
+
exports.default = document_1.default;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function expressToSwagger(path: string): string;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.expressToSwagger = expressToSwagger;
|
|
4
|
+
function expressToSwagger(path) {
|
|
5
|
+
// مرحله 1: optional group ها رو unwrap کن
|
|
6
|
+
// {/:newName} -> /:newName
|
|
7
|
+
let normalized = path.replace(/\{([^}]+)\}/g, "$1");
|
|
8
|
+
// مرحله 2: :param رو تبدیل کن به {param}
|
|
9
|
+
normalized = normalized.replace(/:([A-Za-z0-9_]+)/g, "{$1}");
|
|
10
|
+
return normalized;
|
|
11
|
+
}
|
package/dist/esm/config/init.js
CHANGED
|
@@ -47,8 +47,8 @@ function speedly(config = {}) {
|
|
|
47
47
|
app.use("/static", express_1.default.static("public"));
|
|
48
48
|
if (finalConfig.homeHandler) {
|
|
49
49
|
app.get("/", (req, res) => {
|
|
50
|
-
res.send(`<h1>Welcome to ${require(path_1.default.join(process.cwd(), "package.json")).name} App</h1>
|
|
51
|
-
<p>Your app is running successfully.</p>
|
|
50
|
+
res.send(`<h1>Welcome to ${require(path_1.default.join(process.cwd(), "package.json")).name} App</h1>
|
|
51
|
+
<p>Your app is running successfully.</p>
|
|
52
52
|
${finalConfig.documentation
|
|
53
53
|
? '<p>Visit <a href="/docs">/docs</a> for API documentation.</p>'
|
|
54
54
|
: ""}`);
|
package/dist/esm/kit/db/db.js
CHANGED
|
@@ -236,6 +236,22 @@ const usingMongoDb = (collectionName, config = { type: "external" }) => {
|
|
|
236
236
|
});
|
|
237
237
|
}
|
|
238
238
|
else if (req.query.limit && queryState.action !== "aggregate") {
|
|
239
|
+
const limitStr = Array.isArray(req.query.limit)
|
|
240
|
+
? req.query.limit[0]
|
|
241
|
+
: typeof req.query.limit === "string"
|
|
242
|
+
? req.query.limit
|
|
243
|
+
: "";
|
|
244
|
+
const limitNum = parseInt(typeof limitStr === "string" ? limitStr : "") ||
|
|
245
|
+
configs?.pagination?.quantity ||
|
|
246
|
+
20;
|
|
247
|
+
if (realTimeQueries.findIndex((q) => "type" in q && q.type == "limit") ==
|
|
248
|
+
-1)
|
|
249
|
+
realTimeQueries.push({
|
|
250
|
+
type: "limit",
|
|
251
|
+
value: limitNum,
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
else if (req.query.page && queryState.action == "aggregate") {
|
|
239
255
|
const pageStrAgg = Array.isArray(req.query.page)
|
|
240
256
|
? req.query.page[0]
|
|
241
257
|
: typeof req.query.page === "string"
|
|
@@ -1,59 +1,71 @@
|
|
|
1
1
|
import mongoose from 'mongoose';
|
|
2
2
|
declare const model: mongoose.Model<{
|
|
3
|
-
createdAt: NativeDate;
|
|
4
|
-
updatedAt: NativeDate;
|
|
5
|
-
} & {
|
|
6
3
|
text: string;
|
|
7
4
|
lang: string;
|
|
8
5
|
translatedText: string;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
} & {
|
|
6
|
+
} & mongoose.DefaultTimestampProps, {}, {}, {
|
|
7
|
+
id: string;
|
|
8
|
+
}, mongoose.Document<unknown, {}, {
|
|
13
9
|
text: string;
|
|
14
10
|
lang: string;
|
|
15
11
|
translatedText: string;
|
|
16
|
-
}
|
|
12
|
+
} & mongoose.DefaultTimestampProps, {
|
|
13
|
+
id: string;
|
|
14
|
+
}, {
|
|
17
15
|
timestamps: true;
|
|
18
|
-
}> & {
|
|
19
|
-
createdAt: NativeDate;
|
|
20
|
-
updatedAt: NativeDate;
|
|
21
|
-
} & {
|
|
16
|
+
}> & Omit<{
|
|
22
17
|
text: string;
|
|
23
18
|
lang: string;
|
|
24
19
|
translatedText: string;
|
|
25
|
-
} & {
|
|
20
|
+
} & mongoose.DefaultTimestampProps & {
|
|
26
21
|
_id: mongoose.Types.ObjectId;
|
|
27
22
|
} & {
|
|
28
23
|
__v: number;
|
|
29
|
-
},
|
|
24
|
+
}, "id"> & {
|
|
25
|
+
id: string;
|
|
26
|
+
}, mongoose.Schema<any, mongoose.Model<any, any, any, any, any, any, any>, {}, {}, {}, {}, {
|
|
30
27
|
timestamps: true;
|
|
31
28
|
}, {
|
|
32
|
-
createdAt: NativeDate;
|
|
33
|
-
updatedAt: NativeDate;
|
|
34
|
-
} & {
|
|
35
29
|
text: string;
|
|
36
30
|
lang: string;
|
|
37
31
|
translatedText: string;
|
|
38
|
-
}, mongoose.Document<unknown, {},
|
|
39
|
-
createdAt: NativeDate;
|
|
40
|
-
updatedAt: NativeDate;
|
|
41
|
-
} & {
|
|
32
|
+
} & mongoose.DefaultTimestampProps, mongoose.Document<unknown, {}, {
|
|
42
33
|
text: string;
|
|
43
34
|
lang: string;
|
|
44
35
|
translatedText: string;
|
|
45
|
-
}
|
|
36
|
+
} & mongoose.DefaultTimestampProps, {
|
|
37
|
+
id: string;
|
|
38
|
+
}, Omit<mongoose.DefaultSchemaOptions, "timestamps"> & {
|
|
46
39
|
timestamps: true;
|
|
47
|
-
}
|
|
40
|
+
}> & Omit<{
|
|
41
|
+
text: string;
|
|
42
|
+
lang: string;
|
|
43
|
+
translatedText: string;
|
|
44
|
+
} & mongoose.DefaultTimestampProps & {
|
|
45
|
+
_id: mongoose.Types.ObjectId;
|
|
46
|
+
} & {
|
|
47
|
+
__v: number;
|
|
48
|
+
}, "id"> & {
|
|
49
|
+
id: string;
|
|
50
|
+
}, unknown, {
|
|
51
|
+
text: string;
|
|
52
|
+
lang: string;
|
|
53
|
+
translatedText: string;
|
|
48
54
|
createdAt: NativeDate;
|
|
49
55
|
updatedAt: NativeDate;
|
|
50
56
|
} & {
|
|
57
|
+
_id: mongoose.Types.ObjectId;
|
|
58
|
+
} & {
|
|
59
|
+
__v: number;
|
|
60
|
+
}>, {
|
|
51
61
|
text: string;
|
|
52
62
|
lang: string;
|
|
53
63
|
translatedText: string;
|
|
54
|
-
|
|
64
|
+
createdAt: NativeDate;
|
|
65
|
+
updatedAt: NativeDate;
|
|
66
|
+
} & {
|
|
55
67
|
_id: mongoose.Types.ObjectId;
|
|
56
68
|
} & {
|
|
57
69
|
__v: number;
|
|
58
|
-
}
|
|
70
|
+
}>;
|
|
59
71
|
export default model;
|