lieko-express 0.0.7 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/lieko-express.js +147 -479
  2. package/package.json +2 -2
package/lieko-express.js CHANGED
@@ -3,410 +3,15 @@ const net = require("net");
3
3
  const fs = require("fs");
4
4
  const path = require("path");
5
5
 
6
- process.env.UV_THREADPOOL_SIZE = require('os').availableParallelism();
7
-
8
- class ValidationError extends Error {
9
- constructor(errors) {
10
- super('Validation failed');
11
- this.name = 'ValidationError';
12
- this.errors = errors;
13
- }
14
- }
15
-
16
- class Schema {
17
- constructor(rules) {
18
- this.rules = rules;
19
- this.fields = rules;
20
- }
21
-
22
- validate(data) {
23
- const errors = [];
24
- for (const [field, validators] of Object.entries(this.rules)) {
25
- const value = data[field];
26
- for (const validator of validators) {
27
- const error = validator(value, field, data);
28
- if (error) {
29
- errors.push(error);
30
- break;
31
- }
32
- }
33
- }
34
- if (errors.length > 0) throw new ValidationError(errors);
35
- return true;
36
- }
37
- }
38
-
39
- const validators = {
40
- required: (message = 'Field is required') => {
41
- return (value, field) => {
42
- if (value === undefined || value === null || value === '') {
43
- return { field, message, type: 'required' };
44
- }
45
- return null;
46
- };
47
- },
48
-
49
- requiredTrue: (message = 'Field must be true') => {
50
- return (value, field) => {
51
- const normalized = value === true || value === 'true' || value === '1' || value === 1;
52
- if (!normalized) {
53
- return { field, message, type: 'requiredTrue' };
54
- }
55
- return null;
56
- }
57
- },
58
-
59
- optional: () => {
60
- return () => null;
61
- },
62
-
63
- string: (message = 'Field must be a string') => {
64
- return (value, field) => {
65
- if (value !== undefined && typeof value !== 'string') {
66
- return { field, message, type: 'string' };
67
- }
68
- return null;
69
- };
70
- },
71
-
72
- number: (message = 'Field must be a number') => {
73
- return (value, field) => {
74
- if (value !== undefined && typeof value !== 'number') {
75
- return { field, message, type: 'number' };
76
- }
77
- return null;
78
- };
79
- },
80
-
81
- boolean: (message = 'Field must be a boolean') => {
82
- return (value, field) => {
83
- if (value === undefined || value === null || value === '') return null;
84
-
85
- const validTrue = ['true', true, 1, '1'];
86
- const validFalse = ['false', false, 0, '0'];
87
-
88
- const isValid = validTrue.includes(value) || validFalse.includes(value);
89
-
90
- if (!isValid) {
91
- return { field, message, type: 'boolean' };
92
- }
93
-
94
- return null;
95
- };
96
- },
97
-
98
- integer: (message = 'Field must be an integer') => {
99
- return (value, field) => {
100
- if (value !== undefined && !Number.isInteger(value)) {
101
- return { field, message, type: 'integer' };
102
- }
103
- return null;
104
- };
105
- },
106
-
107
- positive: (message = 'Field must be positive') => {
108
- return (value, field) => {
109
- if (value !== undefined && value <= 0) {
110
- return { field, message, type: 'positive' };
111
- }
112
- return null;
113
- };
114
- },
115
-
116
- negative: (message = 'Field must be negative') => {
117
- return (value, field) => {
118
- if (value !== undefined && value >= 0) {
119
- return { field, message, type: 'negative' };
120
- }
121
- return null;
122
- };
123
- },
124
-
125
- email: (message = 'Invalid email format') => {
126
- return (value, field) => {
127
- if (value !== undefined && value !== null) {
128
- const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
129
- if (!emailRegex.test(value)) {
130
- return { field, message, type: 'email' };
131
- }
132
- }
133
- return null;
134
- };
135
- },
136
-
137
- min: (minValue, message) => {
138
- return (value, field) => {
139
- if (value !== undefined && value !== null) {
140
- if (typeof value === 'string' && value.length < minValue) {
141
- return {
142
- field,
143
- message: message || `Field must be at least ${minValue} characters`,
144
- type: 'min'
145
- };
146
- }
147
- if (typeof value === 'number' && value < minValue) {
148
- return {
149
- field,
150
- message: message || `Field must be at least ${minValue}`,
151
- type: 'min'
152
- };
153
- }
154
- }
155
- return null;
156
- };
157
- },
158
-
159
- max: (maxValue, message) => {
160
- return (value, field) => {
161
- if (value !== undefined && value !== null) {
162
- if (typeof value === 'string' && value.length > maxValue) {
163
- return {
164
- field,
165
- message: message || `Field must be at most ${maxValue} characters`,
166
- type: 'max'
167
- };
168
- }
169
- if (typeof value === 'number' && value > maxValue) {
170
- return {
171
- field,
172
- message: message || `Field must be at most ${maxValue}`,
173
- type: 'max'
174
- };
175
- }
176
- }
177
- return null;
178
- };
179
- },
180
-
181
- length: (n, message) => {
182
- return (value, field) => {
183
- if (typeof value === 'string' && value.length !== n) {
184
- return {
185
- field,
186
- message: message || `Field must be exactly ${n} characters`,
187
- type: 'length'
188
- };
189
- }
190
- return null;
191
- };
192
- },
193
-
194
- minLength: (minLength, message) => {
195
- return (value, field) => {
196
- if (value !== undefined && value !== null && typeof value === 'string') {
197
- if (value.length < minLength) {
198
- return {
199
- field,
200
- message: message || `Field must be at least ${minLength} characters`,
201
- type: 'minLength'
202
- };
203
- }
204
- }
205
- return null;
206
- };
207
- },
208
-
209
- maxLength: (maxLength, message) => {
210
- return (value, field) => {
211
- if (value !== undefined && value !== null && typeof value === 'string') {
212
- if (value.length > maxLength) {
213
- return {
214
- field,
215
- message: message || `Field must be at most ${maxLength} characters`,
216
- type: 'maxLength'
217
- };
218
- }
219
- }
220
- return null;
221
- };
222
- },
223
-
224
- pattern: (regex, message = 'Invalid format') => {
225
- return (value, field) => {
226
- if (value !== undefined && value !== null && typeof value === 'string') {
227
- if (!regex.test(value)) {
228
- return { field, message, type: 'pattern' };
229
- }
230
- }
231
- return null;
232
- };
233
- },
234
-
235
- oneOf: (allowedValues, message) => {
236
- return (value, field) => {
237
- if (value !== undefined && value !== null) {
238
- if (!allowedValues.includes(value)) {
239
- return {
240
- field,
241
- message: message || `Field must be one of: ${allowedValues.join(', ')}`,
242
- type: 'oneOf'
243
- };
244
- }
245
- }
246
- return null;
247
- };
248
- },
249
-
250
- notOneOf: (values, message) => {
251
- return (value, field) => {
252
- if (values.includes(value)) {
253
- return {
254
- field,
255
- message: message || `Field cannot be one of: ${values.join(', ')}`,
256
- type: 'notOneOf'
257
- };
258
- }
259
- return null;
260
- };
261
- },
262
-
263
- custom: (validatorFn, message = 'Validation failed') => {
264
- return (value, field, data) => {
265
- const isValid = validatorFn(value, data);
266
- if (!isValid) {
267
- return { field, message, type: 'custom' };
268
- }
269
- return null;
270
- };
271
- },
272
-
273
- equal: (expectedValue, message) => {
274
- return (value, field) => {
275
- if (value !== expectedValue) {
276
- return {
277
- field,
278
- message: message || `Field must be equal to ${expectedValue}`,
279
- type: 'equal'
280
- };
281
- }
282
- return null;
283
- };
284
- },
285
-
286
- mustBeTrue: (message = 'This field must be accepted') => {
287
- return (value, field) => {
288
- const normalized = value === true || value === 'true' || value === '1' || value === 1;
289
- if (!normalized) {
290
- return { field, message, type: 'mustBeTrue' };
291
- }
292
- return null;
293
- };
294
- },
295
-
296
- mustBeFalse: (message = 'This field must be declined') => {
297
- return (value, field) => {
298
- const normalized = value === false || value === 'false' || value === '0' || value === 0;
299
- if (!normalized) {
300
- return { field, message, type: 'mustBeFalse' };
301
- }
302
- return null;
303
- };
304
- },
305
-
306
- date: (message = 'Invalid date') => {
307
- return (value, field) => {
308
- if (!value) return null;
309
- const date = new Date(value);
310
- if (isNaN(date.getTime())) {
311
- return { field, message, type: 'date' };
312
- }
313
- return null;
314
- };
315
- },
316
-
317
- before: (limit, message) => {
318
- return (value, field) => {
319
- if (!value) return null;
320
- const d1 = new Date(value);
321
- const d2 = new Date(limit);
322
- if (isNaN(d1) || d1 >= d2) {
323
- return {
324
- field,
325
- message: message || `Date must be before ${limit}`,
326
- type: 'before'
327
- };
328
- }
329
- return null;
330
- };
331
- },
332
-
333
- after: (limit, message) => {
334
- return (value, field) => {
335
- if (!value) return null;
336
- const d1 = new Date(value);
337
- const d2 = new Date(limit);
338
- if (isNaN(d1) || d1 <= d2) {
339
- return {
340
- field,
341
- message: message || `Date must be after ${limit}`,
342
- type: 'after'
343
- };
344
- }
345
- return null;
346
- };
347
- },
348
-
349
- startsWith: (prefix, message) => {
350
- return (value, field) => {
351
- if (typeof value === 'string' && !value.startsWith(prefix)) {
352
- return {
353
- field,
354
- message: message || `Field must start with "${prefix}"`,
355
- type: 'startsWith'
356
- };
357
- }
358
- return null;
359
- };
360
- },
361
-
362
- endsWith: (suffix, message) => {
363
- return (value, field) => {
364
- if (typeof value === 'string' && !value.endsWith(suffix)) {
365
- return {
366
- field,
367
- message: message || `Field must end with "${suffix}"`,
368
- type: 'endsWith'
369
- };
370
- }
371
- return null;
372
- };
373
- }
374
- };
375
-
376
- function validate(schema) {
377
- return (req, res, next) => {
378
- try {
379
- schema.validate(req.body);
380
- next();
381
- } catch (error) {
382
- if (error instanceof ValidationError) {
383
- return res.status(400).json({
384
- success: false,
385
- message: 'Validation failed',
386
- errors: error.errors
387
- });
388
- }
389
- throw error;
390
- }
391
- };
392
- }
6
+ const {
7
+ Schema,
8
+ ValidationError,
9
+ validators,
10
+ validate,
11
+ validatePartial
12
+ } = require('./lib/schema');
393
13
 
394
- function validatePartial(schema) {
395
- const partial = {};
396
-
397
- for (const field in schema.fields) {
398
- const rules = schema.fields[field];
399
-
400
- const filtered = rules.filter(v =>
401
- v.name !== 'required' &&
402
- v.name !== 'requiredTrue' &&
403
- v.name !== 'mustBeTrue'
404
- );
405
- partial[field] = [validators.optional(), ...filtered];
406
- }
407
-
408
- return new Schema(partial);
409
- }
14
+ process.env.UV_THREADPOOL_SIZE = require('os').availableParallelism();
410
15
 
411
16
  class LiekoExpress {
412
17
  constructor() {
@@ -424,10 +29,11 @@ class LiekoExpress {
424
29
  strictTrailingSlash: true,
425
30
  allowTrailingSlash: true,
426
31
  views: path.join(process.cwd(), "views"),
427
- "view engine": null
32
+ "view engine": "html"
428
33
  };
429
34
 
430
35
  this.engines = {};
36
+ this.engines['.html'] = this._defaultHtmlEngine.bind(this);
431
37
 
432
38
  this.bodyParserOptions = {
433
39
  json: {
@@ -551,6 +157,33 @@ class LiekoExpress {
551
157
  }
552
158
  }
553
159
 
160
+ _logCorsDebug(req, opts) {
161
+ if (!opts.debug) return;
162
+
163
+ console.log("\n[CORS DEBUG]");
164
+ console.log("Request:", req.method, req.url);
165
+ console.log("Origin:", req.headers.origin || "none");
166
+
167
+ console.log("Applied CORS Policy:");
168
+ console.log(" - Access-Control-Allow-Origin:", opts.origin);
169
+ console.log(" - Access-Control-Allow-Methods:", opts.methods.join(", "));
170
+ console.log(" - Access-Control-Allow-Headers:", opts.headers.join(", "));
171
+
172
+ if (opts.credentials) {
173
+ console.log(" - Access-Control-Allow-Credentials: true");
174
+ }
175
+
176
+ if (opts.exposedHeaders?.length) {
177
+ console.log(" - Access-Control-Expose-Headers:", opts.exposedHeaders.join(", "));
178
+ }
179
+
180
+ console.log(" - Max-Age:", opts.maxAge);
181
+
182
+ if (req.method === "OPTIONS") {
183
+ console.log("Preflight request handled with status 204\n");
184
+ }
185
+ }
186
+
554
187
  debug(value = true) {
555
188
  if (typeof value === 'string') {
556
189
  value = value.toLowerCase() === 'true';
@@ -1202,7 +835,7 @@ ${cyan} (req, res, next) => {
1202
835
  filePath = indexPath;
1203
836
  break;
1204
837
  }
1205
- } catch (e) {}
838
+ } catch (e) { }
1206
839
  }
1207
840
  }
1208
841
 
@@ -1215,7 +848,7 @@ ${cyan} (req, res, next) => {
1215
848
  filePath = testPath;
1216
849
  found = true;
1217
850
  break;
1218
- } catch (e) {}
851
+ } catch (e) { }
1219
852
  }
1220
853
  if (!found) return next();
1221
854
  } else if (!stats) {
@@ -1242,7 +875,7 @@ ${cyan} (req, res, next) => {
1242
875
  stats = indexStats;
1243
876
  break;
1244
877
  }
1245
- } catch (e) {}
878
+ } catch (e) { }
1246
879
  }
1247
880
 
1248
881
  if (stats.isDirectory()) {
@@ -1352,6 +985,10 @@ ${cyan} (req, res, next) => {
1352
985
  }
1353
986
 
1354
987
  const finalHandler = handlers[handlers.length - 1];
988
+ if (!finalHandler) {
989
+ throw new Error(`Route handler is undefined for ${method} ${path}`);
990
+ }
991
+
1355
992
  const routeMiddlewares = handlers.slice(0, -1);
1356
993
 
1357
994
  routeMiddlewares.forEach(mw => {
@@ -1363,7 +1000,7 @@ ${cyan} (req, res, next) => {
1363
1000
  const paths = Array.isArray(path) ? path : [path];
1364
1001
 
1365
1002
  paths.forEach(original => {
1366
- let p = String(original).trim();
1003
+ let p = String(original).trim();
1367
1004
  p = p.replace(/\/+/g, '/');
1368
1005
 
1369
1006
  if (p !== '/' && p.endsWith('/')) {
@@ -1383,7 +1020,7 @@ ${cyan} (req, res, next) => {
1383
1020
  path: p,
1384
1021
  originalPath: original,
1385
1022
  handler: finalHandler,
1386
- handlerName: finalHandler.name || 'anonymous',
1023
+ handlerName: (finalHandler && finalHandler.name) || 'anonymous',
1387
1024
  middlewares: routeMiddlewares,
1388
1025
  pattern: this._pathToRegex(p),
1389
1026
  allowTrailingSlash: this.settings.allowTrailingSlash ?? false,
@@ -1447,7 +1084,6 @@ ${cyan} (req, res, next) => {
1447
1084
  }
1448
1085
  }
1449
1086
  }
1450
-
1451
1087
  return null;
1452
1088
  }
1453
1089
 
@@ -1780,6 +1416,16 @@ ${cyan} (req, res, next) => {
1780
1416
 
1781
1417
  req.originalUrl = req.url;
1782
1418
  req.xhr = (req.headers['x-requested-with'] || '').toLowerCase() === 'xmlhttprequest';
1419
+
1420
+ req.get = (name) => {
1421
+ if (typeof name !== 'string') return undefined;
1422
+ const lower = name.toLowerCase();
1423
+ for (const key in req.headers) {
1424
+ if (key.toLowerCase() === lower) return req.headers[key];
1425
+ }
1426
+ return undefined;
1427
+ };
1428
+ req.header = req.get;
1783
1429
  }
1784
1430
 
1785
1431
  _enhanceResponse(req, res) {
@@ -1862,35 +1508,39 @@ ${cyan} (req, res, next) => {
1862
1508
  if (!ext) {
1863
1509
  ext = this.settings['view engine'];
1864
1510
  if (!ext) {
1865
- throw new Error('No default view engine specified. Use app.set("view engine", "ejs") or provide file extension.');
1511
+ ext = '.html';
1512
+ viewPath = view + ext;
1513
+ } else {
1514
+ if (!ext.startsWith('.')) ext = '.' + ext;
1515
+ viewPath = view + ext;
1866
1516
  }
1867
- if (!ext.startsWith('.')) ext = '.' + ext;
1868
- viewPath = view + ext;
1869
1517
  }
1870
1518
 
1871
1519
  const viewsDir = this.settings.views || path.join(process.cwd(), 'views');
1872
1520
  let fullPath = path.join(viewsDir, viewPath);
1873
-
1874
1521
  let fileExists = false;
1875
1522
  try {
1876
1523
  await fs.promises.access(fullPath);
1877
1524
  fileExists = true;
1878
1525
  } catch (err) {
1879
- const htmlPath = fullPath.replace(new RegExp(ext.replace('.', '\\.') + '$'), '.html');
1880
- try {
1881
- await fs.promises.access(htmlPath);
1882
- fullPath = htmlPath;
1883
- fileExists = true;
1884
- } catch (err2) {
1885
- fileExists = false;
1526
+ const extensions = ['.html', '.ejs', '.pug', '.hbs'];
1527
+ for (const tryExt of extensions) {
1528
+ if (tryExt === ext) continue;
1529
+ const tryPath = fullPath.replace(new RegExp(ext.replace('.', '\\.') + '$'), tryExt);
1530
+ try {
1531
+ await fs.promises.access(tryPath);
1532
+ fullPath = tryPath;
1533
+ ext = tryExt;
1534
+ fileExists = true;
1535
+ break;
1536
+ } catch (err2) { }
1886
1537
  }
1887
1538
  }
1888
1539
 
1889
1540
  if (!fileExists) {
1890
1541
  const error = new Error(
1891
- `View "${view}" not found. Tried:\n` +
1892
- `- ${fullPath}\n` +
1893
- `- ${fullPath.replace(new RegExp(ext.replace('.', '\\.') + '$'), '.html')}`
1542
+ `View "${view}" not found in views directory "${viewsDir}".\n` +
1543
+ `Tried: ${fullPath}`
1894
1544
  );
1895
1545
  error.code = 'ENOENT';
1896
1546
  if (callback) return callback(error);
@@ -1900,24 +1550,38 @@ ${cyan} (req, res, next) => {
1900
1550
  const renderEngine = this.engines[ext];
1901
1551
 
1902
1552
  if (!renderEngine) {
1903
- throw new Error(`No engine registered for extension "${ext}". Use app.engine("${ext}", renderFunction)`);
1553
+ throw new Error(
1554
+ `No engine registered for extension "${ext}".\n` +
1555
+ `Use app.engine("${ext}", renderFunction) to register one.`
1556
+ );
1904
1557
  }
1905
1558
 
1906
- renderEngine(fullPath, locals, (err, html) => {
1907
- if (err) {
1908
- if (callback) return callback(err);
1909
- throw err;
1910
- }
1559
+ return new Promise((resolve, reject) => {
1560
+ renderEngine(fullPath, locals, (err, html) => {
1561
+ if (err) {
1562
+ if (callback) {
1563
+ callback(err);
1564
+ resolve();
1565
+ } else {
1566
+ reject(err);
1567
+ }
1568
+ return;
1569
+ }
1911
1570
 
1912
- if (callback) {
1913
- callback(null, html);
1914
- } else {
1915
- res.statusCode = statusCode;
1916
- res.setHeader('Content-Type', 'text/html; charset=utf-8');
1917
- responseSent = true;
1918
- statusCode = 200;
1919
- res.end(html);
1920
- }
1571
+ if (callback) {
1572
+ callback(null, html);
1573
+ resolve();
1574
+ } else {
1575
+ /*
1576
+ HBS cause error header already sent here ??
1577
+ */
1578
+ //res.statusCode = statusCode || 200;
1579
+ //res.setHeader('Content-Type', 'text/html; charset=utf-8');
1580
+ //responseSent = true;
1581
+ res.html(html);
1582
+ resolve();
1583
+ }
1584
+ });
1921
1585
  });
1922
1586
 
1923
1587
  } catch (error) {
@@ -1929,17 +1593,15 @@ ${cyan} (req, res, next) => {
1929
1593
  }
1930
1594
  };
1931
1595
 
1932
-
1933
1596
  res.json = (data) => {
1934
1597
  if (responseSent) return res;
1935
1598
 
1936
1599
  const json = JSON.stringify(data);
1937
1600
  const length = Buffer.byteLength(json);
1938
1601
 
1939
- res.writeHead(statusCode, buildHeaders('application/json; charset=utf-8', length));
1602
+ res.writeHead(statusCode || 200, buildHeaders('application/json; charset=utf-8', length));
1940
1603
 
1941
1604
  responseSent = true;
1942
- statusCode = 200;
1943
1605
  return res.end(json);
1944
1606
  };
1945
1607
 
@@ -1964,15 +1626,14 @@ ${cyan} (req, res, next) => {
1964
1626
 
1965
1627
  const length = Buffer.byteLength(body);
1966
1628
 
1967
- res.writeHead(statusCode, buildHeaders(contentType, length));
1629
+ res.writeHead(statusCode || 200, buildHeaders(contentType, length));
1968
1630
 
1969
1631
  responseSent = true;
1970
- statusCode = 200;
1971
1632
  return res.end(body);
1972
1633
  };
1973
1634
 
1974
- res.html = function (html, status = 200) {
1975
- res.statusCode = status;
1635
+ res.html = function (html, status) {
1636
+ res.statusCode = status !== undefined ? status : (statusCode || 200);
1976
1637
  res.setHeader('Content-Type', 'text/html; charset=utf-8');
1977
1638
  res.end(html);
1978
1639
  };
@@ -2067,6 +1728,42 @@ ${cyan} (req, res, next) => {
2067
1728
  };
2068
1729
  }
2069
1730
 
1731
+ _defaultHtmlEngine(filePath, locals, callback) {
1732
+ fs.readFile(filePath, 'utf-8', (err, content) => {
1733
+ if (err) return callback(err);
1734
+
1735
+ let rendered = content;
1736
+
1737
+ Object.keys(locals).forEach(key => {
1738
+ if (locals[key] !== undefined && locals[key] !== null) {
1739
+ const safeRegex = new RegExp(`{{\\s*${key}\\s*}}`, 'g');
1740
+ const unsafeRegex = new RegExp(`{{{\\s*${key}\\s*}}}`, 'g');
1741
+
1742
+ if (safeRegex.test(rendered)) {
1743
+ const escaped = this._escapeHtml(String(locals[key]));
1744
+ rendered = rendered.replace(safeRegex, escaped);
1745
+ }
1746
+
1747
+ if (unsafeRegex.test(rendered)) {
1748
+ rendered = rendered.replace(unsafeRegex, String(locals[key]));
1749
+ }
1750
+ }
1751
+ });
1752
+
1753
+ callback(null, rendered);
1754
+ });
1755
+ }
1756
+
1757
+ _escapeHtml(text) {
1758
+ if (typeof text !== 'string') return text;
1759
+ return text
1760
+ .replace(/&/g, '&amp;')
1761
+ .replace(/</g, '&lt;')
1762
+ .replace(/>/g, '&gt;')
1763
+ .replace(/"/g, '&quot;')
1764
+ .replace(/'/g, '&#039;');
1765
+ }
1766
+
2070
1767
  async _runMiddleware(handler, req, res) {
2071
1768
  return new Promise((resolve, reject) => {
2072
1769
  const next = (err) => err ? reject(err) : resolve();
@@ -2144,34 +1841,7 @@ ${cyan} (req, res, next) => {
2144
1841
  logLines.push('---------------------------------------------');
2145
1842
  console.log('\n' + logLines.join('\n') + '\n');
2146
1843
  }
2147
-
2148
- _logCorsDebug(req, opts) {
2149
- if (!opts.debug) return;
2150
-
2151
- console.log("\n[CORS DEBUG]");
2152
- console.log("Request:", req.method, req.url);
2153
- console.log("Origin:", req.headers.origin || "none");
2154
-
2155
- console.log("Applied CORS Policy:");
2156
- console.log(" - Access-Control-Allow-Origin:", opts.origin);
2157
- console.log(" - Access-Control-Allow-Methods:", opts.methods.join(", "));
2158
- console.log(" - Access-Control-Allow-Headers:", opts.headers.join(", "));
2159
-
2160
- if (opts.credentials) {
2161
- console.log(" - Access-Control-Allow-Credentials: true");
2162
- }
2163
-
2164
- if (opts.exposedHeaders?.length) {
2165
- console.log(" - Access-Control-Expose-Headers:", opts.exposedHeaders.join(", "));
2166
- }
2167
-
2168
- console.log(" - Max-Age:", opts.maxAge);
2169
-
2170
- if (req.method === "OPTIONS") {
2171
- console.log("Preflight request handled with status 204\n");
2172
- }
2173
- }
2174
-
1844
+
2175
1845
  listRoutes() {
2176
1846
  const routeEntries = [];
2177
1847
 
@@ -2242,6 +1912,7 @@ ${cyan} (req, res, next) => {
2242
1912
  console.log(` \x1b[36m${r.method.padEnd(7)}\x1b[0m \x1b[33m${pathStr}\x1b[0m \x1b[90m(mw: ${r.mw})\x1b[0m`);
2243
1913
  }
2244
1914
  }
1915
+
2245
1916
  listen() {
2246
1917
  const args = Array.from(arguments);
2247
1918
  const server = createServer(this._handleRequest.bind(this));
@@ -2262,13 +1933,10 @@ function Router() {
2262
1933
 
2263
1934
  module.exports = Lieko;
2264
1935
  module.exports.Router = Router;
1936
+
2265
1937
  module.exports.Schema = Schema;
2266
- module.exports.schema = (...args) => new Schema(...args);
1938
+ module.exports.createSchema = (...args) => new Schema(...args);
2267
1939
  module.exports.validators = validators;
2268
1940
  module.exports.validate = validate;
2269
1941
  module.exports.validatePartial = validatePartial;
2270
1942
  module.exports.ValidationError = ValidationError;
2271
- module.exports.static = function (root, options) {
2272
- const app = new LiekoExpress();
2273
- return app.static(root, options);
2274
- };
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "lieko-express",
3
- "version": "0.0.7",
3
+ "version": "0.0.8",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/eiwSrvt/lieko-express"
7
7
  },
8
8
  "homepage": "https://github.com/eiwSrvt/lieko-express",
9
- "description": "Lieko-express — A Modern, Minimal, REST API Framework for Node.js",
9
+ "description": "Lieko-express — A Modern, Minimal, express-like Framework for Node.js",
10
10
  "main": "lieko-express.js",
11
11
  "scripts": {
12
12
  "test": "echo \"Error: no test specified\" && exit 1"