@desaubv/quik 0.0.21 → 0.0.81

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/index.js CHANGED
@@ -1,3 +1,15 @@
1
+ // src/core/errors/serverErrors.ts
2
+ var ServerInvalidRouteError = class extends Error {
3
+ constructor(path3) {
4
+ super(`"${path3}" is not a QuikRouter instance.`);
5
+ }
6
+ };
7
+ var ServerInvalidCronError = class extends Error {
8
+ constructor() {
9
+ super(`Invalid object, must be a QuikCron instance.`);
10
+ }
11
+ };
12
+
1
13
  // src/core/logger.ts
2
14
  import fs from "fs";
3
15
  import path from "path";
@@ -24,37 +36,122 @@ var colors = Object.fromEntries(
24
36
  );
25
37
 
26
38
  // src/core/time.ts
27
- function dateToString(date, format) {
39
+ function dateToString(date, format, timeZone) {
40
+ const formatter = new Intl.DateTimeFormat("en-US", {
41
+ timeZone,
42
+ year: "numeric",
43
+ month: "2-digit",
44
+ day: "2-digit",
45
+ hour: "2-digit",
46
+ minute: "2-digit",
47
+ second: "2-digit",
48
+ hourCycle: "h23"
49
+ });
50
+ const parts = formatter.formatToParts(date);
51
+ const values = Object.fromEntries(
52
+ parts.filter(({ type }) => type !== "literal").map(({ type, value }) => [type, value])
53
+ );
28
54
  return format.replace(/(YYYY|MM|DD|hh|mm|ss)/g, (match) => {
29
55
  switch (match) {
30
56
  case "YYYY":
31
- return date.getFullYear().toString();
57
+ return values.year || "";
32
58
  case "MM":
33
- return (date.getMonth() + 1).toString().padStart(2, "0");
59
+ return values.month || "";
34
60
  case "DD":
35
- return date.getDate().toString().padStart(2, "0");
61
+ return values.day || "";
36
62
  case "hh":
37
- return date.getHours().toString().padStart(2, "0");
63
+ return values.hour || "";
38
64
  case "mm":
39
- return date.getMinutes().toString().padStart(2, "0");
65
+ return values.minute || "";
40
66
  case "ss":
41
- return date.getSeconds().toString().padStart(2, "0");
67
+ return values.second || "";
42
68
  default:
43
69
  return match;
44
70
  }
45
71
  });
46
72
  }
73
+ function isValidTimeZone(timeZone) {
74
+ try {
75
+ new Intl.DateTimeFormat("en-US", {
76
+ timeZone
77
+ });
78
+ return true;
79
+ } catch {
80
+ return false;
81
+ }
82
+ }
83
+
84
+ // src/locales/en.json
85
+ var en_default = {
86
+ logger: {
87
+ levels: {
88
+ log: "log",
89
+ info: "info",
90
+ warning: "warning",
91
+ error: "error",
92
+ debug: "debug"
93
+ }
94
+ },
95
+ server: {
96
+ name: "server",
97
+ start: "Server running at",
98
+ routers_loaded: "routers loaded",
99
+ crons_loaded: "crons loaded",
100
+ static_loaded: "static dirs loaded",
101
+ static_warn: "directory does not exist"
102
+ },
103
+ time: {
104
+ invalidTimeZone1: "Invalid time zone:",
105
+ invalidTimeZone2: "Using system default time zone."
106
+ }
107
+ };
108
+
109
+ // src/locales/es.json
110
+ var es_default = {
111
+ logger: {
112
+ levels: {
113
+ log: "log",
114
+ info: "info",
115
+ warning: "advertencia",
116
+ error: "error",
117
+ debug: "depuraci\xF3n"
118
+ }
119
+ },
120
+ server: {
121
+ name: "servidor",
122
+ start: "Servidor corriendo en",
123
+ routers_loaded: "rutas cargadas",
124
+ crons_loaded: "crons cargados",
125
+ static_loaded: "carpetas estaticas cargadas",
126
+ static_warn: "no existe el directorio"
127
+ },
128
+ time: {
129
+ invalidTimeZone1: "Zona horaria inv\xE1lida:",
130
+ invalidTimeZone2: "Usando la zona horaria predeterminada del sistema."
131
+ }
132
+ };
133
+
134
+ // src/core/translator.ts
135
+ var locales = {
136
+ en: en_default,
137
+ es: es_default
138
+ };
139
+ function translate(language, key) {
140
+ return locales[language][key];
141
+ }
47
142
 
48
143
  // src/core/logger.ts
49
144
  var defaultConfig = {
145
+ language: "en",
50
146
  save: {
51
147
  logFilePath: null,
52
- errorFilePath: null,
53
- //"logs/error.log",
54
- warningFilePath: null
148
+ infoFilePath: null,
149
+ errorFilePath: "logs/error.log",
150
+ warningFilePath: "logs/warning.log"
55
151
  },
56
152
  color: {
57
153
  logColor: "blue",
154
+ infoColor: "green",
58
155
  errorColor: "red",
59
156
  warningColor: "yellow",
60
157
  debugColor: null
@@ -99,7 +196,17 @@ function write(level, color2, file, ...content) {
99
196
  function parseContent(level, ...body) {
100
197
  let header = "";
101
198
  if (config.format.timestampFormat) {
102
- const timestamp = dateToString(/* @__PURE__ */ new Date(), config.format.timestampFormat);
199
+ const now = /* @__PURE__ */ new Date();
200
+ const timeZone = config.format.timeZone;
201
+ let tz = timeZone;
202
+ if (timeZone && !isValidTimeZone(timeZone)) {
203
+ tz = void 0;
204
+ }
205
+ const timestamp = dateToString(
206
+ now,
207
+ config.format.timestampFormat,
208
+ tz
209
+ );
103
210
  header += `${timestamp} `;
104
211
  }
105
212
  switch (config.format.titleCase) {
@@ -131,6 +238,8 @@ function saveToFile(filePath, content) {
131
238
  }
132
239
  function mergeConfig(current, update) {
133
240
  return {
241
+ ...current,
242
+ ...update,
134
243
  save: {
135
244
  ...current.save,
136
245
  ...update.save
@@ -155,42 +264,434 @@ var logger = {
155
264
  return Object.freeze(structuredClone(config));
156
265
  },
157
266
  log(...content) {
267
+ const messages = translate(config.language, "logger");
158
268
  write(
159
- "log",
269
+ messages.levels.log,
160
270
  config.color.logColor,
161
271
  config.save.logFilePath,
162
272
  ...content
163
273
  );
164
274
  },
275
+ info(...content) {
276
+ const messages = translate(config.language, "logger");
277
+ write(
278
+ messages.levels.info,
279
+ config.color.infoColor,
280
+ config.save.infoFilePath,
281
+ ...content
282
+ );
283
+ },
165
284
  error(...content) {
285
+ const messages = translate(config.language, "logger");
166
286
  write(
167
- "error",
287
+ messages.levels.error,
168
288
  config.color.errorColor,
169
289
  config.save.errorFilePath,
170
290
  ...content
171
291
  );
172
292
  },
173
293
  warning(...content) {
294
+ const messages = translate(config.language, "logger");
174
295
  write(
175
- "warning",
296
+ messages.levels.warning,
176
297
  config.color.warningColor,
177
298
  config.save.warningFilePath,
178
299
  ...content
179
300
  );
180
301
  },
181
302
  debug(...content) {
303
+ const messages = translate(config.language, "logger");
182
304
  write(
183
- "debug",
305
+ messages.levels.debug,
184
306
  config.color.debugColor,
185
307
  null,
186
308
  ...content
187
309
  );
188
310
  },
311
+ clear() {
312
+ console.clear();
313
+ },
189
314
  custom(level, color2, file, ...content) {
190
315
  write(level, color2, file, ...content);
191
316
  }
192
317
  };
318
+
319
+ // src/core/router.ts
320
+ import { Router as ExpressRouter } from "express";
321
+ var QuikRouter = class {
322
+ router;
323
+ pendingMiddleware = [];
324
+ currentPath = "";
325
+ constructor() {
326
+ this.router = ExpressRouter();
327
+ }
328
+ middleware(...handlers) {
329
+ this.pendingMiddleware.push(...handlers);
330
+ return this;
331
+ }
332
+ path(path3) {
333
+ this.currentPath = path3;
334
+ return this;
335
+ }
336
+ register(method, handler) {
337
+ this.router[method](
338
+ this.currentPath,
339
+ ...this.pendingMiddleware,
340
+ async (req, res, next) => {
341
+ try {
342
+ await handler(req, res, next);
343
+ } catch (err) {
344
+ next(err);
345
+ }
346
+ }
347
+ );
348
+ this.pendingMiddleware = [];
349
+ this.currentPath = "";
350
+ return this;
351
+ }
352
+ get(handler) {
353
+ return this.register("get", handler);
354
+ }
355
+ post(handler) {
356
+ return this.register("post", handler);
357
+ }
358
+ put(handler) {
359
+ return this.register("put", handler);
360
+ }
361
+ patch(handler) {
362
+ return this.register("patch", handler);
363
+ }
364
+ delete(handler) {
365
+ return this.register("delete", handler);
366
+ }
367
+ };
368
+ function Router() {
369
+ return new QuikRouter();
370
+ }
371
+
372
+ // src/core/server.ts
373
+ import express from "express";
374
+ import http from "http";
375
+ import path2 from "path";
376
+ import fs2 from "fs";
377
+
378
+ // src/cron/cron.ts
379
+ import cron from "node-cron";
380
+ import "node-cron";
381
+
382
+ // src/http/status.ts
383
+ var Status = {
384
+ // 1xx Informational
385
+ CONTINUE: 100,
386
+ SWITCHING_PROTOCOLS: 101,
387
+ PROCESSING: 102,
388
+ EARLY_HINTS: 103,
389
+ // 2xx Success
390
+ OK: 200,
391
+ CREATED: 201,
392
+ ACCEPTED: 202,
393
+ NON_AUTHORITATIVE_INFORMATION: 203,
394
+ NO_CONTENT: 204,
395
+ RESET_CONTENT: 205,
396
+ PARTIAL_CONTENT: 206,
397
+ MULTI_STATUS: 207,
398
+ ALREADY_REPORTED: 208,
399
+ IM_USED: 226,
400
+ // 3xx Redirection
401
+ MULTIPLE_CHOICES: 300,
402
+ MOVED_PERMANENTLY: 301,
403
+ FOUND: 302,
404
+ SEE_OTHER: 303,
405
+ NOT_MODIFIED: 304,
406
+ TEMPORARY_REDIRECT: 307,
407
+ PERMANENT_REDIRECT: 308,
408
+ // 4xx Client Errors
409
+ BAD_REQUEST: 400,
410
+ UNAUTHORIZED: 401,
411
+ PAYMENT_REQUIRED: 402,
412
+ FORBIDDEN: 403,
413
+ NOT_FOUND: 404,
414
+ METHOD_NOT_ALLOWED: 405,
415
+ NOT_ACCEPTABLE: 406,
416
+ PROXY_AUTHENTICATION_REQUIRED: 407,
417
+ REQUEST_TIMEOUT: 408,
418
+ CONFLICT: 409,
419
+ GONE: 410,
420
+ LENGTH_REQUIRED: 411,
421
+ PRECONDITION_FAILED: 412,
422
+ PAYLOAD_TOO_LARGE: 413,
423
+ URI_TOO_LONG: 414,
424
+ UNSUPPORTED_MEDIA_TYPE: 415,
425
+ RANGE_NOT_SATISFIABLE: 416,
426
+ EXPECTATION_FAILED: 417,
427
+ IM_A_TEAPOT: 418,
428
+ MISDIRECTED_REQUEST: 421,
429
+ UNPROCESSABLE_CONTENT: 422,
430
+ LOCKED: 423,
431
+ FAILED_DEPENDENCY: 424,
432
+ UPGRADE_REQUIRED: 426,
433
+ PRECONDITION_REQUIRED: 428,
434
+ TOO_MANY_REQUESTS: 429,
435
+ REQUEST_HEADER_FIELDS_TOO_LARGE: 431,
436
+ UNAVAILABLE_FOR_LEGAL_REASONS: 451,
437
+ // 5xx Server Errors
438
+ INTERNAL_SERVER_ERROR: 500,
439
+ NOT_IMPLEMENTED: 501,
440
+ BAD_GATEWAY: 502,
441
+ SERVICE_UNAVAILABLE: 503,
442
+ GATEWAY_TIMEOUT: 504,
443
+ HTTP_VERSION_NOT_SUPPORTED: 505,
444
+ VARIANT_ALSO_NEGOTIATES: 506,
445
+ INSUFFICIENT_STORAGE: 507,
446
+ LOOP_DETECTED: 508,
447
+ NOT_EXTENDED: 510,
448
+ NETWORK_AUTHENTICATION_REQUIRED: 511
449
+ };
450
+
451
+ // src/core/handlers/notFoundHandler.ts
452
+ var QuikNotFoundHandler = (req, res) => {
453
+ res.status(Status.NOT_FOUND).json({
454
+ error: "Not Found",
455
+ message: `Route ${req.method} ${req.originalUrl} not found`
456
+ });
457
+ };
458
+
459
+ // src/core/handlers/httpErrorHandler.ts
460
+ var QuikErrorHandler = (err, req, res, next) => {
461
+ logger.error(err);
462
+ if (res.headersSent) {
463
+ return next(err);
464
+ }
465
+ res.status(Status.INTERNAL_SERVER_ERROR).json({
466
+ error: "Internal Server Error"
467
+ });
468
+ };
469
+
470
+ // src/core/server.ts
471
+ var defaultConfig2 = {
472
+ language: "en",
473
+ bodyParser: {
474
+ type: "json"
475
+ },
476
+ http: {
477
+ port: 8080
478
+ },
479
+ express: {}
480
+ };
481
+ var defaultNotFoundHandler = QuikNotFoundHandler;
482
+ var defaultErrorHandler = QuikErrorHandler;
483
+ var QuikServer = class {
484
+ app;
485
+ httpServer;
486
+ middlewares = [];
487
+ routes = {};
488
+ staticDirs = [];
489
+ crons = [];
490
+ notFoundHandler;
491
+ errorHandler;
492
+ config;
493
+ constructor() {
494
+ this.app = express();
495
+ this.config = structuredClone(defaultConfig2);
496
+ this.httpServer = http.createServer(
497
+ this.app
498
+ );
499
+ this.notFoundHandler = defaultNotFoundHandler;
500
+ this.errorHandler = defaultErrorHandler;
501
+ }
502
+ setConfig(config2) {
503
+ this.config = {
504
+ ...this.config,
505
+ ...config2,
506
+ http: {
507
+ ...this.config.http,
508
+ ...config2.http
509
+ },
510
+ express: {
511
+ ...this.config.express,
512
+ ...config2.express
513
+ }
514
+ };
515
+ if (config2.timeZone && !isValidTimeZone(config2.timeZone)) {
516
+ const messages = translate(this.config.language, "time");
517
+ logger.warning(
518
+ `${messages.invalidTimeZone1} ${config2.timeZone}. ${messages.invalidTimeZone2}`
519
+ );
520
+ }
521
+ return this;
522
+ }
523
+ setNotFoundHandler(handler) {
524
+ if (!handler) {
525
+ this.notFoundHandler = void 0;
526
+ return this;
527
+ }
528
+ this.notFoundHandler = handler;
529
+ return this;
530
+ }
531
+ setErrorHandler(handler) {
532
+ if (!handler) {
533
+ this.errorHandler = void 0;
534
+ return this;
535
+ }
536
+ this.errorHandler = handler;
537
+ return this;
538
+ }
539
+ addMiddleware(...middlewares) {
540
+ this.middlewares.push(
541
+ ...middlewares
542
+ );
543
+ return this;
544
+ }
545
+ addRoute(path3, router) {
546
+ if (!(router instanceof QuikRouter)) {
547
+ throw new ServerInvalidRouteError(path3);
548
+ }
549
+ if (!path3.startsWith("/"))
550
+ path3 = "/" + path3;
551
+ this.routes[path3] = router;
552
+ return this;
553
+ }
554
+ #listen() {
555
+ const { port, host } = this.config.http;
556
+ const messages = translate(this.config.language, "server");
557
+ this.httpServer.listen(
558
+ port,
559
+ host,
560
+ () => {
561
+ logger.info(`${messages.start} ${host ?? "localhost"}:${port}`);
562
+ }
563
+ );
564
+ return this;
565
+ }
566
+ addCron(cron2) {
567
+ if (cron2.constructor.name != "QuikCron") {
568
+ throw new ServerInvalidCronError();
569
+ }
570
+ this.crons.push(cron2);
571
+ return this;
572
+ }
573
+ addStaticDir(...paths) {
574
+ for (const i in paths) {
575
+ const dir = paths[i] ?? "";
576
+ const dirPath = path2.resolve(dir);
577
+ const exists = fs2.existsSync(dirPath);
578
+ if (!exists) {
579
+ const messages = translate(this.config.language, "server");
580
+ logger.warning(`[ STATIC ] "${dir}" ${messages.static_warn}`);
581
+ continue;
582
+ }
583
+ this.staticDirs.push(...paths);
584
+ }
585
+ return this;
586
+ }
587
+ #configureHTTP() {
588
+ const config2 = this.config.http;
589
+ if (config2.timeout)
590
+ this.httpServer.timeout = config2.timeout;
591
+ if (config2.keepAlive)
592
+ this.httpServer.keepAliveTimeout = config2.keepAlive;
593
+ if (config2.maxConnections)
594
+ this.httpServer.maxConnections = config2.maxConnections;
595
+ return this;
596
+ }
597
+ #configureExpress() {
598
+ const config2 = this.config.express;
599
+ if (config2.trustProxy !== void 0) {
600
+ this.app.set(
601
+ "trust proxy",
602
+ config2.trustProxy
603
+ );
604
+ }
605
+ return this;
606
+ }
607
+ #configureMiddleware() {
608
+ const bodyParser = this.config.bodyParser;
609
+ switch (bodyParser.type) {
610
+ case "json":
611
+ this.app.use(
612
+ express.json(bodyParser.options)
613
+ );
614
+ break;
615
+ case "urlencoded":
616
+ this.app.use(
617
+ express.urlencoded(bodyParser.options)
618
+ );
619
+ break;
620
+ case "raw":
621
+ this.app.use(
622
+ express.raw(bodyParser.options)
623
+ );
624
+ break;
625
+ case "text":
626
+ this.app.use(
627
+ express.text(bodyParser.options)
628
+ );
629
+ break;
630
+ }
631
+ if (this.middlewares.length > 0)
632
+ this.app.use(...this.middlewares);
633
+ return this;
634
+ }
635
+ #configureRoutes() {
636
+ for (const [path3, router] of Object.entries(this.routes)) {
637
+ this.app.use(
638
+ path3,
639
+ router.router
640
+ );
641
+ }
642
+ const messages = translate(this.config.language, "server");
643
+ logger.info(`[ ROUTER ] ${Object.entries(this.routes).length} ${messages.routers_loaded}.`);
644
+ return this;
645
+ }
646
+ #loadCrons() {
647
+ for (const cron2 of this.crons) {
648
+ cron2.start();
649
+ }
650
+ const messages = translate(this.config.language, "server");
651
+ logger.info(`[ CRON ] ${this.crons.length} ${messages.crons_loaded}.`);
652
+ return this;
653
+ }
654
+ #loadStaticDirs() {
655
+ for (const dir of this.staticDirs) {
656
+ const dirPath = path2.resolve(dir);
657
+ this.app.use(express.static(dirPath));
658
+ }
659
+ const messages = translate(this.config.language, "server");
660
+ logger.info(`[ STATIC ] ${this.staticDirs.length} ${messages.static_loaded}.`);
661
+ return this;
662
+ }
663
+ #loadHandlers() {
664
+ if (this.notFoundHandler) {
665
+ this.app.use(
666
+ this.notFoundHandler
667
+ );
668
+ }
669
+ if (this.errorHandler) {
670
+ this.app.use(
671
+ this.errorHandler
672
+ );
673
+ }
674
+ }
675
+ start() {
676
+ this.#configureExpress();
677
+ this.#configureMiddleware();
678
+ this.#loadStaticDirs();
679
+ this.#configureRoutes();
680
+ this.#loadHandlers();
681
+ this.#loadCrons();
682
+ this.#configureHTTP();
683
+ this.#listen();
684
+ return this;
685
+ }
686
+ };
687
+ function Server() {
688
+ return new QuikServer();
689
+ }
193
690
  export {
691
+ QuikRouter,
692
+ Router,
693
+ Server,
694
+ ServerInvalidRouteError,
194
695
  logger
195
696
  };
196
697
  //# sourceMappingURL=index.js.map