@desaubv/quik 0.0.31 → 0.1.0

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