turbo-express-js 1.0.11 → 1.0.12

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/changelog.md CHANGED
@@ -17,4 +17,8 @@
17
17
 
18
18
  # 1.0.9 - 1.0.10
19
19
  1. [25/4/2025] update clusters, 0 argument mean no clusters.
20
- 2. [25/4/2025] first typescript support
20
+ 2. [25/4/2025] first typescript support
21
+
22
+ # 1.0.12
23
+ 1. cors middleware
24
+ 2. formdata service fixing default get data
package/index.test.js CHANGED
@@ -6,6 +6,9 @@ const app = new TurboExpress();
6
6
 
7
7
  // console.log("testing development...")
8
8
 
9
- app.get("asd", ()=>{ })
9
+ app.get("/", ()=>{ })
10
+ app.post("/test", TurboExpress.Cors({ origins: ["*"] }), async (req, res) => {
11
+ res.json({ query: req.queriesObj(), params: req.paramsObj(), body: await req.body() })
12
+ })
10
13
 
11
- app.listen(3001, () => console.log("Service is running"));
14
+ app.listen(3000, () => console.log("Service is running"));
@@ -4,7 +4,7 @@
4
4
  * @PerfecTEvolutioN
5
5
  * @project - TurboExpress
6
6
  * @name TurboExpress
7
- * @namespace TurboExpress::middlewares::static_middleware
7
+ * @namespace TurboExpress::middlewares::cors_middleware
8
8
  * @license - MIT
9
9
  * @author - Mike Karypidis
10
10
  * @version - 1.0.0
@@ -23,14 +23,34 @@ const ResponseInterface = require("../types/ResponseInterface");
23
23
  * @param {ResponseInterface} res
24
24
  * @param {*} next
25
25
  */
26
- module.exports = function cors_middleware (req, res, next)
26
+ module.exports = function cors_middleware(req, res, next)
27
27
  {
28
- const { origins, methods, credentials, headers } = this;
28
+ const config = this || {};
29
+ const origins = Array.isArray(config.origins) && config.origins.length ? config.origins : ["*"];
30
+ const methods = Array.isArray(config.methods) && config.methods.length ? config.methods : ["GET", "HEAD", "PUT", "PATCH", "POST", "DELETE", "OPTIONS"];
31
+ const headers = Array.isArray(config.headers) ? config.headers : [];
32
+ const credentials = config.credentials === true;
33
+ const maxAge = Number.isSafeInteger(config.maxAge) ? config.maxAge : 3600;
34
+
35
+ const requestHeaders = req.headers();
36
+ const requestOrigin = requestHeaders.origin;
37
+ const requestedHeaders = requestHeaders["access-control-request-headers"];
38
+ const requestMethod = String(req.IncomingMessage?.method || "GET").toUpperCase();
39
+ const wildcard = origins.includes("*");
40
+
41
+ if(requestOrigin && !wildcard && !origins.includes(requestOrigin)) return next();
42
+
43
+ if(wildcard && !credentials) {
44
+ res.header("Access-Control-Allow-Origin", "*");
45
+ } else if(requestOrigin) {
46
+ res.header("Access-Control-Allow-Origin", requestOrigin);
47
+ res.header("Vary", "Origin");
48
+ }
49
+
50
+ if(credentials) res.header("Access-Control-Allow-Credentials", "true");
29
51
 
30
- res.header("Access-Control-Allow-Origin", origins.join(","));
31
- res.header("Access-Control-Allow-Credentials", credentials);
32
52
  res.header("Access-Control-Allow-Methods", methods.join(","));
33
- res.header("Access-Control-Max-Age", 3600);
53
+ res.header("Access-Control-Max-Age", String(maxAge));
34
54
 
35
55
  let allowedHeaders = "";
36
56
  const headers_req = req.headers();
@@ -45,6 +65,10 @@ module.exports = function cors_middleware (req, res, next)
45
65
  0, (allowedHeaders + headers.join(",")).length - 1
46
66
  ));
47
67
 
48
- next();
68
+ if(requestMethod === "OPTIONS") {
69
+ res.status(204);
70
+ return res.send("");
71
+ }
49
72
 
73
+ return next();
50
74
  }
@@ -19,6 +19,10 @@
19
19
  const multiparty = require("multiparty")
20
20
  const FileType = require("../types/FileType");
21
21
 
22
+ const INTEGER_PATTERN = /^-?(?:0|[1-9]\d*)$/;
23
+ const DECIMAL_PATTERN = /^-?(?:0|[1-9]\d*)\.\d+(?:[eE][+-]?\d+)?$/;
24
+ const SCIENTIFIC_PATTERN = /^-?(?:0|[1-9]\d*)(?:\.\d+)?[eE][+-]?\d+$/;
25
+ const MAX_JSON_FIELD_LENGTH = 1024 * 1024; // 1 MB
22
26
 
23
27
  module.exports = class FormDataService
24
28
  {
@@ -71,16 +75,110 @@ module.exports = class FormDataService
71
75
  }
72
76
 
73
77
 
74
- #getValueByType (value)
78
+ #getValueByType(value)
75
79
  {
76
- if(typeof value !== "string") return null
77
- if(value.toLowerCase() === "true") return true;
78
- if(value.toLowerCase() === "false") return false;
79
- if(value.toLowerCase() === "nil" || value.toLowerCase() === "null") return null;
80
- if(!isNaN(Number(value))) return Number(value);
80
+ // Multiparty normally returns strings, but do not destroy
81
+ // unexpected values if its behavior changes in the future.
82
+ if (typeof value !== "string") {
83
+ return value;
84
+ }
85
+
86
+ // Preserve empty strings and whitespace exactly.
87
+ if (value === "" || value.trim() === "") {
88
+ return value;
89
+ }
90
+
91
+ // Do not trim before conversion. Whitespace may be meaningful.
92
+ if (value !== value.trim()) {
93
+ return value;
94
+ }
95
+
96
+ const normalized = value.toLowerCase();
97
+
98
+ switch (normalized) {
99
+ case "true":
100
+ return true;
101
+
102
+ case "false":
103
+ return false;
104
+
105
+ case "null":
106
+ case "nil":
107
+ return null;
108
+
109
+ default:
110
+ break;
111
+ }
112
+
113
+ // Strict integer conversion.
114
+ if (INTEGER_PATTERN.test(value)) {
115
+ const parsed = Number(value);
116
+
117
+ // Prevent database identifiers and large integers from being corrupted.
118
+ if (!Number.isSafeInteger(parsed)) {
119
+ return value;
120
+ }
121
+
122
+ // "-0" has special behavior in JavaScript; preserve it as entered.
123
+ if (Object.is(parsed, -0)) {
124
+ return value;
125
+ }
126
+
127
+ return parsed;
128
+ }
129
+
130
+ // Strict decimal and scientific-notation conversion.
131
+ if (
132
+ DECIMAL_PATTERN.test(value) ||
133
+ SCIENTIFIC_PATTERN.test(value)
134
+ ) {
135
+ const parsed = Number(value);
136
+
137
+ if (!Number.isFinite(parsed)) {
138
+ return value;
139
+ }
140
+
141
+ // Avoid converting high-precision decimal values that Number
142
+ // cannot represent reliably.
143
+ if (this.#countSignificantDigits(value) > 15) {
144
+ return value;
145
+ }
146
+
147
+ return parsed;
148
+ }
149
+
150
+ // Parse explicitly structured JSON values.
151
+ if (
152
+ value.length <= MAX_JSON_FIELD_LENGTH &&
153
+ (
154
+ (value.startsWith("{") && value.endsWith("}")) ||
155
+ (value.startsWith("[") && value.endsWith("]"))
156
+ )
157
+ ) {
158
+ try {
159
+ return JSON.parse(value);
160
+ } catch {
161
+ // Invalid JSON remains the original string.
162
+ return value;
163
+ }
164
+ }
165
+
166
+ // Dates, UUIDs, AFMs, phone numbers, postal codes,
167
+ // hexadecimal values and ordinary text remain strings.
81
168
  return value;
82
169
  }
83
170
 
171
+ #countSignificantDigits(value)
172
+ {
173
+ const coefficient = value
174
+ .replace(/^[+-]/, "")
175
+ .split(/[eE]/, 1)[0]
176
+ .replace(".", "")
177
+ .replace(/^0+/, "");
178
+
179
+ return coefficient.length;
180
+ }
181
+
84
182
  }
85
183
 
86
184
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "turbo-express-js",
3
- "version": "1.0.11",
3
+ "version": "1.0.12",
4
4
  "description": "Turbo Express JS - Performance, Security, Easy-to-use Web Server Framework",
5
5
  "main": "index.js",
6
6
  "directories": {