beavuck-time 2.3.5 → 2.3.7

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 (67) hide show
  1. package/build/api.js +20 -0
  2. package/build/config/corsOptions.js +60 -0
  3. package/build/config/logger.js +36 -0
  4. package/build/controllers/nowController.js +30 -0
  5. package/build/errors/BeavuckTimeClientError.js +13 -0
  6. package/build/errors/BeavuckTimeServerError.js +16 -0
  7. package/build/errors/CorsError.js +13 -0
  8. package/build/errors/base/BeavuckTimeError.js +14 -0
  9. package/build/middlewares/corsMiddleware.js +34 -0
  10. package/build/middlewares/errorHandler.js +47 -0
  11. package/build/middlewares/notFoundHandler.js +9 -0
  12. package/build/middlewares/rateLimiter.js +16 -0
  13. package/build/models/now.js +14 -0
  14. package/build/routes/routes.js +54 -0
  15. package/build/server.js +63 -0
  16. package/build/services/nowService.js +11 -0
  17. package/build/types/isoTimestamp.js +4 -0
  18. package/build/utils/urlUtil.js +31 -0
  19. package/openapi/swagger.json +1 -1
  20. package/package.json +14 -4
  21. package/.env +0 -21
  22. package/.env.test +0 -30
  23. package/.gitlab/issue_templates/bug.md +0 -53
  24. package/.gitlab/issue_templates/enhancement.md +0 -53
  25. package/.gitlab/merge_request_templates/bug_fix.md +0 -9
  26. package/.gitlab/merge_request_templates/enhancement.md +0 -9
  27. package/.gitlab-ci.yml +0 -158
  28. package/.nvmrc +0 -1
  29. package/.sonarlint/connectedMode.json +0 -4
  30. package/DOCKERHUB_OVERVIEW.md +0 -185
  31. package/Dockerfile +0 -25
  32. package/HELP.md +0 -53
  33. package/api-tests/bruno/bruno.json +0 -9
  34. package/api-tests/bruno/collection.bru +0 -7
  35. package/api-tests/bruno/environments/local.bru +0 -8
  36. package/api-tests/bruno/now/nok/nok_no_origin.bru +0 -19
  37. package/api-tests/bruno/now/nok/nok_non_recognized_referrer.bru +0 -23
  38. package/api-tests/bruno/now/nok/nok_non_trusted_origin.bru +0 -23
  39. package/api-tests/bruno/now/nok/nok_non_truted_origin_nor_referrer.bru +0 -24
  40. package/api-tests/bruno/now/ok/ok_same_origin.bru +0 -23
  41. package/api-tests/bruno/now/ok/ok_same_referrer.bru +0 -23
  42. package/api-tests/bruno/now/ok/ok_trusted_origin.bru +0 -23
  43. package/eslint.config.mjs +0 -28
  44. package/sonar-project.properties +0 -9
  45. package/src/__tests__/api.test.ts +0 -98
  46. package/src/__tests__/middlewares/errorHandler.test.ts +0 -93
  47. package/src/__tests__/utils/urlUtil.test.ts +0 -53
  48. package/src/api.ts +0 -19
  49. package/src/config/corsOptions.ts +0 -63
  50. package/src/config/logger.ts +0 -38
  51. package/src/controllers/nowController.ts +0 -19
  52. package/src/errors/BeavuckTimeClientError.ts +0 -12
  53. package/src/errors/BeavuckTimeServerError.ts +0 -18
  54. package/src/errors/CorsError.ts +0 -12
  55. package/src/errors/base/BeavuckTimeError.ts +0 -12
  56. package/src/middlewares/corsMiddleware.ts +0 -32
  57. package/src/middlewares/errorHandler.ts +0 -57
  58. package/src/middlewares/notFoundHandler.ts +0 -8
  59. package/src/middlewares/rateLimiter.ts +0 -15
  60. package/src/models/now.ts +0 -14
  61. package/src/routes/routes.ts +0 -84
  62. package/src/server.ts +0 -83
  63. package/src/services/nowService.ts +0 -9
  64. package/src/types/isoTimestamp.ts +0 -8
  65. package/src/utils/urlUtil.ts +0 -29
  66. package/tsconfig.json +0 -38
  67. package/tsoa.json +0 -12
package/build/api.js ADDED
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ // src/api.ts
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.api = void 0;
8
+ const express_1 = __importDefault(require("express"));
9
+ const corsMiddleware_1 = require("./middlewares/corsMiddleware");
10
+ const errorHandler_1 = require("./middlewares/errorHandler");
11
+ const rateLimiter_1 = require("./middlewares/rateLimiter");
12
+ const notFoundHandler_1 = require("./middlewares/notFoundHandler");
13
+ const routes_1 = require("./routes/routes");
14
+ exports.api = (0, express_1.default)();
15
+ exports.api.disable('x-powered-by');
16
+ exports.api.use(corsMiddleware_1.corsMiddleware);
17
+ exports.api.use(errorHandler_1.errorHandler);
18
+ exports.api.use(rateLimiter_1.rateLimiter);
19
+ (0, routes_1.RegisterRoutes)(exports.api);
20
+ exports.api.use(notFoundHandler_1.notFoundHandler);
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ // src/config/corsOptions.ts
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.corsOptions = void 0;
8
+ exports.getHostUrl = getHostUrl;
9
+ exports.initHostUrl = initHostUrl;
10
+ exports.getTrustedOrigins = getTrustedOrigins;
11
+ exports.initTrustedOrigins = initTrustedOrigins;
12
+ exports.isAllTrusted = isAllTrusted;
13
+ exports.isOriginAbsentOrTrusted = isOriginAbsentOrTrusted;
14
+ const CorsError_1 = require("../errors/CorsError");
15
+ const urlUtil_1 = require("../utils/urlUtil");
16
+ const http_status_codes_1 = require("http-status-codes");
17
+ const dotenvx_1 = __importDefault(require("@dotenvx/dotenvx"));
18
+ dotenvx_1.default.config();
19
+ exports.corsOptions = {
20
+ methods: ['GET', 'OPTIONS'],
21
+ optionsSuccessStatus: http_status_codes_1.StatusCodes.OK,
22
+ origin: (origin, callback) => {
23
+ if (isAllTrusted() ||
24
+ (0, urlUtil_1.isSameOrigin)(getHostUrl(), (0, urlUtil_1.tryParseUrl)(origin)) ||
25
+ isOriginAbsentOrTrusted(origin)) {
26
+ // eslint-disable-next-line no-restricted-syntax
27
+ callback(null, true);
28
+ }
29
+ else {
30
+ callback(new CorsError_1.CorsError(origin), false);
31
+ }
32
+ },
33
+ };
34
+ let HOST_URL;
35
+ let TRUSTED_ORIGINS;
36
+ function getHostUrl() {
37
+ if (!HOST_URL) {
38
+ initHostUrl();
39
+ }
40
+ return HOST_URL;
41
+ }
42
+ function initHostUrl() {
43
+ HOST_URL = new URL(process.env.BEAVUCK_TIME_HOST_URL);
44
+ }
45
+ function getTrustedOrigins() {
46
+ if (!TRUSTED_ORIGINS || TRUSTED_ORIGINS.length === 0) {
47
+ initTrustedOrigins();
48
+ }
49
+ return TRUSTED_ORIGINS;
50
+ }
51
+ function initTrustedOrigins() {
52
+ const trustedOrigins = process.env.BEAVUCK_TIME_TRUSTED_ORIGINS;
53
+ TRUSTED_ORIGINS = trustedOrigins.split(',');
54
+ }
55
+ function isAllTrusted() {
56
+ return getTrustedOrigins().includes('*');
57
+ }
58
+ function isOriginAbsentOrTrusted(origin) {
59
+ return !origin || getTrustedOrigins().includes(origin);
60
+ }
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ // src/config/logger.ts
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.logger = void 0;
8
+ const winston_1 = require("winston");
9
+ require("winston-daily-rotate-file");
10
+ const dotenvx_1 = __importDefault(require("@dotenvx/dotenvx"));
11
+ dotenvx_1.default.config();
12
+ const LOGS_DIR = 'logs';
13
+ const LOG_LEVEL = process.env.BEAVUCK_TIME_LOG_LEVEL ?? 'info';
14
+ const MAX_LOG_FILES = process.env.BEAVUCK_TIME_MAX_LOG_FILES ?? 64;
15
+ const MAX_SIZE_LOG_FILES = process.env.BEAVUCK_TIME_MAX_SIZE_LOG_FILES ?? '1m';
16
+ const dailyRotateFileTransport = new winston_1.transports.DailyRotateFile({
17
+ filename: `${LOGS_DIR}/%DATE%-combined.log`,
18
+ datePattern: 'YYYY-MM-DD',
19
+ zippedArchive: true,
20
+ maxSize: MAX_SIZE_LOG_FILES,
21
+ maxFiles: MAX_LOG_FILES,
22
+ });
23
+ exports.logger = (0, winston_1.createLogger)({
24
+ level: LOG_LEVEL,
25
+ format: winston_1.format.combine(winston_1.format.timestamp(), winston_1.format.printf(({ timestamp, level, message }) => {
26
+ return `${timestamp} [${level.toUpperCase()}]: ${message}`;
27
+ })),
28
+ transports: [
29
+ new winston_1.transports.Console(),
30
+ new winston_1.transports.File({
31
+ filename: `${LOGS_DIR}/error.log`,
32
+ level: 'error',
33
+ }),
34
+ dailyRotateFileTransport,
35
+ ],
36
+ });
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ // src/controllers/nowController.ts
3
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
4
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
5
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
6
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
7
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
8
+ };
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.NowController = void 0;
11
+ const tsoa_1 = require("tsoa");
12
+ const nowService_1 = require("../services/nowService");
13
+ let NowController = class NowController extends tsoa_1.Controller {
14
+ /**
15
+ * Get the current time in ISO format, in UTC timezone
16
+ * @summary Get current time
17
+ */
18
+ async getNow() {
19
+ return new nowService_1.NowService().get();
20
+ }
21
+ };
22
+ exports.NowController = NowController;
23
+ __decorate([
24
+ (0, tsoa_1.Tags)('now'),
25
+ (0, tsoa_1.Get)(),
26
+ (0, tsoa_1.OperationId)('getNow')
27
+ ], NowController.prototype, "getNow", null);
28
+ exports.NowController = NowController = __decorate([
29
+ (0, tsoa_1.Route)('now')
30
+ ], NowController);
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ // src/errors/BeavuckTimeClientError.ts
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.BeavuckTimeClientError = void 0;
5
+ const BeavuckTimeError_1 = require("./base/BeavuckTimeError");
6
+ const http_status_codes_1 = require("http-status-codes");
7
+ class BeavuckTimeClientError extends BeavuckTimeError_1.BeavuckTimeError {
8
+ static baseMessage = 'Client Error';
9
+ constructor(message, code = http_status_codes_1.StatusCodes.BAD_REQUEST) {
10
+ super(`${BeavuckTimeClientError.baseMessage}: ${message}`, code);
11
+ }
12
+ }
13
+ exports.BeavuckTimeClientError = BeavuckTimeClientError;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ // src/errors/BeavuckTimeServerError.ts
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.BeavuckTimeServerError = void 0;
5
+ const BeavuckTimeError_1 = require("./base/BeavuckTimeError");
6
+ const http_status_codes_1 = require("http-status-codes");
7
+ class BeavuckTimeServerError extends BeavuckTimeError_1.BeavuckTimeError {
8
+ static baseMessage = 'Internal Server Error';
9
+ constructor(message, code = http_status_codes_1.StatusCodes.INTERNAL_SERVER_ERROR) {
10
+ super(`${BeavuckTimeServerError.baseMessage}: ${message}`, code);
11
+ }
12
+ static fromError(error) {
13
+ return error instanceof BeavuckTimeServerError ? error : (new BeavuckTimeServerError(error.message));
14
+ }
15
+ }
16
+ exports.BeavuckTimeServerError = BeavuckTimeServerError;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ // src/errors/CorsError.ts
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.CorsError = void 0;
5
+ const http_status_codes_1 = require("http-status-codes");
6
+ const BeavuckTimeClientError_1 = require("./BeavuckTimeClientError");
7
+ class CorsError extends BeavuckTimeClientError_1.BeavuckTimeClientError {
8
+ static baseMessage = 'Origin forbidden by CORS';
9
+ constructor(origin) {
10
+ super(`${CorsError.baseMessage}: ${origin}`, http_status_codes_1.StatusCodes.FORBIDDEN);
11
+ }
12
+ }
13
+ exports.CorsError = CorsError;
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ // src/errors/base/BeavuckTimeError.ts
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.BeavuckTimeError = void 0;
5
+ class BeavuckTimeError extends Error {
6
+ code;
7
+ constructor(message, code) {
8
+ super(message);
9
+ this.name = this.constructor.name;
10
+ this.code = code;
11
+ Error.captureStackTrace(this, this.constructor);
12
+ }
13
+ }
14
+ exports.BeavuckTimeError = BeavuckTimeError;
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ // src/middlewares/corsMiddleware.ts
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.corsMiddleware = void 0;
8
+ const cors_1 = __importDefault(require("cors"));
9
+ const urlUtil_1 = require("../utils/urlUtil");
10
+ const CorsError_1 = require("../errors/CorsError");
11
+ const logger_1 = require("../config/logger");
12
+ const BeavuckTimeServerError_1 = require("../errors/BeavuckTimeServerError");
13
+ const corsOptions_1 = require("../config/corsOptions");
14
+ const corsMiddleware = (req, res, next) => {
15
+ const HOST_URL = (0, urlUtil_1.tryParseUrl)(process.env.BEAVUCK_TIME_HOST_URL ?? '');
16
+ // 'referer' is a misspelling that was kept for compatibility: https://en.wikipedia.org/wiki/HTTP_referer
17
+ const referrerHeader = req.headers.referrer || req.headers.referer;
18
+ if (req.headers.origin) {
19
+ logger_1.logger.debug(`CORS request from ${req.headers.origin}`);
20
+ (0, cors_1.default)(corsOptions_1.corsOptions)(req, res, next);
21
+ }
22
+ else if (!HOST_URL) {
23
+ const noHostUrl = 'Host URL not set';
24
+ next(new BeavuckTimeServerError_1.BeavuckTimeServerError(noHostUrl));
25
+ }
26
+ else if ((0, urlUtil_1.isSameOrigin)(HOST_URL, (0, urlUtil_1.tryParseUrl)(referrerHeader ?? ''))) {
27
+ next();
28
+ }
29
+ else {
30
+ const badOriginAndOrReferrer = `origin: ${req.headers.origin}, referrer: ${referrerHeader}`;
31
+ next(new CorsError_1.CorsError(badOriginAndOrReferrer));
32
+ }
33
+ };
34
+ exports.corsMiddleware = corsMiddleware;
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ // src/middlewares/errorHandler.ts
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.errorHandler = void 0;
5
+ const logger_1 = require("../config/logger");
6
+ const BeavuckTimeClientError_1 = require("../errors/BeavuckTimeClientError");
7
+ const BeavuckTimeServerError_1 = require("../errors/BeavuckTimeServerError");
8
+ const http_status_codes_1 = require("http-status-codes");
9
+ const tsoa_1 = require("tsoa");
10
+ const errorHandler = (err, req, res, next) => {
11
+ if (err instanceof tsoa_1.ValidateError) {
12
+ const logMsg = `Validation error on ${req.path}: ${err.fields}`;
13
+ const resStatus = http_status_codes_1.StatusCodes.UNPROCESSABLE_ENTITY;
14
+ const resMsgObj = { message: 'Validation Error', details: err.fields };
15
+ handleOtherError(res, logMsg, resStatus, resMsgObj);
16
+ }
17
+ else if (err instanceof BeavuckTimeClientError_1.BeavuckTimeClientError) {
18
+ handleBeavuckClientError(res, err);
19
+ }
20
+ else if (err instanceof BeavuckTimeServerError_1.BeavuckTimeServerError || err instanceof Error) {
21
+ handleBeavuckServerError(res, BeavuckTimeServerError_1.BeavuckTimeServerError.fromError(err));
22
+ }
23
+ else if (err) {
24
+ handleOtherError(res);
25
+ }
26
+ else {
27
+ next();
28
+ }
29
+ };
30
+ exports.errorHandler = errorHandler;
31
+ function sendErrorResponse(res, err) {
32
+ res.status(err.code).json({ message: err.message });
33
+ }
34
+ function handleBeavuckClientError(res, err) {
35
+ logger_1.logger.warn(err);
36
+ sendErrorResponse(res, err);
37
+ }
38
+ function handleBeavuckServerError(res, err) {
39
+ logger_1.logger.error(err);
40
+ sendErrorResponse(res, err);
41
+ }
42
+ function handleOtherError(res, logMsg = `Unknown error`, resStatus = http_status_codes_1.StatusCodes.INTERNAL_SERVER_ERROR, resMsg = {
43
+ message: BeavuckTimeServerError_1.BeavuckTimeServerError.baseMessage,
44
+ }) {
45
+ logger_1.logger.error(`${logMsg}: ${JSON.stringify(resMsg)}`);
46
+ res.status(resStatus).json(resMsg);
47
+ }
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ // src/middlewares/notFoundHandler.ts
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.notFoundHandler = void 0;
5
+ const http_status_codes_1 = require("http-status-codes");
6
+ const notFoundHandler = (_req, res) => {
7
+ res.status(http_status_codes_1.StatusCodes.NOT_FOUND).send({ message: 'Not Found' });
8
+ };
9
+ exports.notFoundHandler = notFoundHandler;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ // src/middlewares/rateLimiter.ts
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.rateLimiter = void 0;
8
+ const express_rate_limit_1 = __importDefault(require("express-rate-limit"));
9
+ const NO_RATE_LIMIT = '-1';
10
+ const RATE_LIMIT = parseInt(process.env.BEAVUCK_TIME_RATE_LIMIT ?? NO_RATE_LIMIT, 10);
11
+ const SECONDS_IN_ONE_MINUTE = 60;
12
+ const MILLISECONDS_IN_ONE_SECOND = 1000;
13
+ const ONE_MINUTE = SECONDS_IN_ONE_MINUTE * MILLISECONDS_IN_ONE_SECOND;
14
+ exports.rateLimiter = RATE_LIMIT > 0 ?
15
+ (0, express_rate_limit_1.default)({ windowMs: ONE_MINUTE, limit: RATE_LIMIT })
16
+ : (_req, _res, next) => next();
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ // src/models/now.ts
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.Now = void 0;
5
+ /**
6
+ * @example {"now": "2019-08-24T14:15:22Z"}
7
+ */
8
+ class Now {
9
+ now;
10
+ constructor() {
11
+ this.now = new Date().toISOString();
12
+ }
13
+ }
14
+ exports.Now = Now;
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RegisterRoutes = RegisterRoutes;
4
+ const runtime_1 = require("@tsoa/runtime");
5
+ // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
6
+ const nowController_1 = require("./../controllers/nowController");
7
+ // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
8
+ const models = {
9
+ "IsoTimestamp": {
10
+ "dataType": "refAlias",
11
+ "type": { "dataType": "string", "validators": {} },
12
+ },
13
+ // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
14
+ "Now": {
15
+ "dataType": "refObject",
16
+ "properties": {
17
+ "now": { "ref": "IsoTimestamp", "required": true },
18
+ },
19
+ "additionalProperties": false,
20
+ },
21
+ // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
22
+ };
23
+ const templateService = new runtime_1.ExpressTemplateService(models, { "noImplicitAdditionalProperties": "throw-on-extras", "bodyCoercion": true });
24
+ // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
25
+ function RegisterRoutes(app) {
26
+ // ###########################################################################################################
27
+ // NOTE: If you do not see routes for all of your controllers in this file, then you might not have informed tsoa of where to look
28
+ // Please look into the "controllerPathGlobs" config option described in the readme: https://github.com/lukeautry/tsoa
29
+ // ###########################################################################################################
30
+ const argsNowController_getNow = {};
31
+ app.get('/now', ...((0, runtime_1.fetchMiddlewares)(nowController_1.NowController)), ...((0, runtime_1.fetchMiddlewares)(nowController_1.NowController.prototype.getNow)), async function NowController_getNow(request, response, next) {
32
+ // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
33
+ let validatedArgs = [];
34
+ try {
35
+ validatedArgs = templateService.getValidatedArgs({ args: argsNowController_getNow, request, response });
36
+ const controller = new nowController_1.NowController();
37
+ await templateService.apiHandler({
38
+ methodName: 'getNow',
39
+ controller,
40
+ response,
41
+ next,
42
+ validatedArgs,
43
+ successStatus: undefined,
44
+ });
45
+ }
46
+ catch (err) {
47
+ return next(err);
48
+ }
49
+ });
50
+ // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
51
+ // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
52
+ // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
53
+ }
54
+ // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ // src/server.ts
4
+ var __importDefault = (this && this.__importDefault) || function (mod) {
5
+ return (mod && mod.__esModule) ? mod : { "default": mod };
6
+ };
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.startServer = startServer;
9
+ const api_1 = require("./api");
10
+ const logger_1 = require("./config/logger");
11
+ const urlUtil_1 = require("./utils/urlUtil");
12
+ const dotenvx_1 = __importDefault(require("@dotenvx/dotenvx"));
13
+ dotenvx_1.default.config();
14
+ function validateEnv({ hostUrl, trustedOrigins, }) {
15
+ if (!hostUrl || !(0, urlUtil_1.tryParseUrl)(hostUrl)) {
16
+ logger_1.logger.error('HOST_URL not set or is not a valid URL');
17
+ process.exit(1);
18
+ }
19
+ if (!trustedOrigins) {
20
+ logger_1.logger.error('TRUSTED_ORIGINS not set');
21
+ process.exit(1);
22
+ }
23
+ }
24
+ function startServer(options = {}) {
25
+ const API_PORT = options.port ?? process.env.BEAVUCK_TIME_API_PORT ?? 3000;
26
+ const HOST_URL = options.hostUrl ?? process.env.BEAVUCK_TIME_HOST_URL ?? '';
27
+ const TRUSTED_ORIGINS = options.trustedOrigins ?? process.env.BEAVUCK_TIME_TRUSTED_ORIGINS ?? '';
28
+ validateEnv({ hostUrl: HOST_URL, trustedOrigins: TRUSTED_ORIGINS });
29
+ const server = api_1.api.listen(API_PORT, () => {
30
+ logger_1.logger.info(`
31
+ | | | | ,=.
32
+ | |__ ___ __ ___ ___ _ ___| | __ ,=""""==.__.=" o".___
33
+ | '_ \\ / _ \\/ _\` \\ \\ / / | | |/ __| |/ / ,=.==" ___/
34
+ | |_) | __/ (_| |\\ V /| |_| | (__| < ,==.," , , \\,===""
35
+ |_.__/ \\___|\\__,_| \\_/ \\__,_|\\___|_|\\_\\ < ,==) \\"'"=._.==) \\
36
+ \`=='' \`" \`"
37
+
38
+ Beavuck Time microservice started successfully
39
+
40
+ Ready on API port ${API_PORT} (if this is running in a container, this port number is internal to the container)
41
+ `);
42
+ });
43
+ server.on('error', (err) => {
44
+ logger_1.logger.error(`Beavuck Time Server error [${err.code}]: ${err.message}`);
45
+ process.exit(1);
46
+ });
47
+ const gracefulShutdown = (signal) => {
48
+ logger_1.logger.info(`${signal} signal received: closing HTTP server`);
49
+ server.close(() => {
50
+ logger_1.logger.info('HTTP server closed');
51
+ process.exit(0);
52
+ });
53
+ };
54
+ const SIGTERM = 'SIGTERM';
55
+ const SIGINT = 'SIGINT';
56
+ process.on(SIGTERM, () => gracefulShutdown(SIGTERM));
57
+ process.on(SIGINT, () => gracefulShutdown(SIGINT));
58
+ return server;
59
+ }
60
+ // Support running as standalone binary
61
+ if (require.main === module) {
62
+ startServer();
63
+ }
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ // src/services/nowService.ts
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.NowService = void 0;
5
+ const now_1 = require("../models/now");
6
+ class NowService {
7
+ get() {
8
+ return new now_1.Now();
9
+ }
10
+ }
11
+ exports.NowService = NowService;
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RFC_3339_FORMAT = void 0;
4
+ exports.RFC_3339_FORMAT = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$/;
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ // src/utils/urlUtil.ts
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.isSameOrigin = isSameOrigin;
5
+ exports.tryParseUrl = tryParseUrl;
6
+ const url_1 = require("url");
7
+ const logger_1 = require("../config/logger");
8
+ function isSameOrigin(thisUrl, thatUrl) {
9
+ logger_1.logger.debug(`Comparing origins: ${thisUrl?.origin} and ${thatUrl?.origin}`);
10
+ if (!thisUrl || !thatUrl)
11
+ return false;
12
+ if (thisUrl.origin === thatUrl.origin)
13
+ return true;
14
+ const isSameProtocol = thisUrl.protocol === thatUrl.protocol;
15
+ const isSameHost = thisUrl.hostname === thatUrl.hostname;
16
+ const isSamePort = thisUrl.port === thatUrl.port;
17
+ return isSameProtocol && isSameHost && isSamePort;
18
+ }
19
+ function tryParseUrl(urlString) {
20
+ if (!urlString) {
21
+ logger_1.logger.debug('Empty URL string');
22
+ return undefined;
23
+ }
24
+ try {
25
+ return new url_1.URL(urlString);
26
+ }
27
+ catch (error) {
28
+ logger_1.logger.warn(`Invalid URL string: ${urlString} (${error})`);
29
+ }
30
+ return undefined;
31
+ }
@@ -32,7 +32,7 @@
32
32
  },
33
33
  "info": {
34
34
  "title": "beavuck-time",
35
- "version": "beta",
35
+ "version": "2.3.7",
36
36
  "description": "Get time in ISO format, in UTC timezone, from a simple, lightweight node server",
37
37
  "license": {
38
38
  "name": "Unlicense"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "beavuck-time",
3
- "version": "2.3.5",
3
+ "version": "2.3.7",
4
4
  "description": "Get time in ISO format, in UTC timezone, from a simple, lightweight node server",
5
5
  "keywords": [
6
6
  "time",
@@ -21,8 +21,16 @@
21
21
  "author": "Alexis Drai",
22
22
  "type": "commonjs",
23
23
  "main": "build/api.js",
24
+ "files": [
25
+ "build/",
26
+ "openapi/swagger.json",
27
+ "package.json",
28
+ "CONTRIBUTING.md",
29
+ "README.md",
30
+ "UNLICENSE"
31
+ ],
24
32
  "bin": {
25
- "beavuck-time": "./build/server.js"
33
+ "beavuck-time": "build/server.js"
26
34
  },
27
35
  "scripts": {
28
36
  "run-integration-tests": "cd api-tests/bruno && npm install -g @usebruno/cli && bru run --env local --bail",
@@ -30,13 +38,15 @@
30
38
  "up-minor": "npm version minor --no-git-tag-version",
31
39
  "up-major": "npm version major --no-git-tag-version",
32
40
  "update-dependencies": "ncu --format group && ncu -u && npm install --verbose && npm prune --verbose && npm audit fix --verbose",
41
+ "prepublishOnly": "npm install && npm run build",
33
42
  "lint": "eslint --fix src/",
43
+ "typecheck": "tsc --noEmit",
34
44
  "format": "prettier --write src/ --log-level warn",
35
- "clean": "npm run lint && npm run format",
45
+ "clean": "npm run lint && npm run typecheck && npm run format",
36
46
  "test": "DOTENV_CONFIG_PATH=./.env.test jest --coverage",
37
47
  "build": "tsoa spec-and-routes && tsc",
38
48
  "start": "node build/server.js",
39
- "go": "npm install && npm run build && npm run clean && npm run test && npm start"
49
+ "go": "rm -rf build && npm install && npm run build && npm run clean && npm run test && npm start"
40
50
  },
41
51
  "dependencies": {
42
52
  "@dotenvx/dotenvx": "^1.49.0",
package/.env DELETED
@@ -1,21 +0,0 @@
1
- # CORS
2
- ## URL of this API
3
- BEAVUCK_TIME_HOST_URL=http://localhost:3000
4
- ## To allow requests from any origin, include * (not recommended)
5
- BEAVUCK_TIME_TRUSTED_ORIGINS=http://localhost:8477
6
-
7
- # Server
8
- ## Port of this API: in a container, this is the internal port -- outside of a container, this is the external port. Default is 3000
9
- BEAVUCK_TIME_API_PORT=3000
10
-
11
- # Rate limiting
12
- ## Requests per minute for each IP address. If not a strictly positive, "no limit". Default is -1
13
- BEAVUCK_TIME_RATE_LIMIT=-1
14
-
15
- # Logging
16
- ## Level of detail in logs: error, warn, info, http, verbose, debug, silly. Default is info
17
- BEAVUCK_TIME_LOG_LEVEL=info
18
- ## Maximum number of logs to keep. This can be a number of files or number of days. If using days, add 'd' as the suffix. Default is 64
19
- BEAVUCK_TIME_MAX_LOG_FILES=64
20
- ## Maximum size of the file after which it will rotate. This can be a number of bytes, or units of kb, mb, and gb. If using the units, add 'k', 'm', or 'g' as the suffix. The units need to directly follow the number. Default is 1m
21
- BEAVUCK_TIME_MAX_SIZE_LOG_FILES=1m
package/.env.test DELETED
@@ -1,30 +0,0 @@
1
- #/-------------------[DOTENV_PUBLIC_KEY]--------------------/
2
- #/ public-key encryption for .env files /
3
- #/ [how it works](https://dotenvx.com/encryption) /
4
- #/----------------------------------------------------------/
5
- DOTENV_PUBLIC_KEY_TEST="02d5c6b7efe5269d1fd3626adac3338f0971e58e2555e8e27c53a7e70047273a1c"
6
-
7
- # Just testing dotenvx here. Not used in .env. Not useful either -- nothing secret in this file at any rate.
8
- # To change any of those values, run `dotenvx set key value` (ex: `dotenvx set HOST_URL http://localhost:3000`)
9
-
10
- # CORS
11
- ## URL of this API
12
- BEAVUCK_TIME_HOST_URL=encrypted:BG5D1BHPO/UlcKh8c1s4s2YDqFQ0yIiduOKDHAsc9GNlm4/BRSPwxHNka+jJopZp++w+nfARNbSJwdgBoZvlbjujb/E8uJ2CX4erxmh1j+HBpmri2ocBa04NnJodMojPkcuxJqP3RSKfh61u+Fo1oTpCoZ8yYg==
13
- ## To allow requests from any origin, include * (not recommended)
14
- BEAVUCK_TIME_TRUSTED_ORIGINS=encrypted:BE1fOSnJ8rnMU+A1orA9/Ujee4ypigUywnZ9g85l74XiNxEDoOdQmAIiSjYut+y/Y5b3VkqF+vBAgP++LYCMGTPoANWHgscZ+DAzsgqeFjsFp9WTKuWXxTeauI3HzLWI3v44o67oSZ1myWk9wsvc9WWwN4plrA==
15
-
16
- # Server
17
- ## Port of this API: in a container, this is the internal port -- outside of a container, this is the external port. Default is 3000
18
- BEAVUCK_TIME_API_PORT=encrypted:BGw4+UyXhxyfMzdxNjZBzTN/akEDL77i+XDqNRZA6w9ed7GYrQyYvuvEho+4VYir9T014sgLYRNeS09cR2mJV8pjyYWzHYhdXQyDeihUcNbLvIpfsZu7KH+aIeHaPx5YIRGJDSM=
19
-
20
- # Rate limiting
21
- ## Requests per minute for each IP address. If not a strictly positive, "no limit". Default is -1
22
- BEAVUCK_TIME_RATE_LIMIT=encrypted:BD1uTBsjTAjd+GYlZGM0S5DVCkmiOSEouDmLQj9XztlHpP2u8KyHxByIzUed8qkJXzbcf8zvTsANzY44V91m9UZZqXeZDOQlCqmn+ZpzmPDSA3VMUPzIdUpYF9DD7rWIgxvF
23
-
24
- # Logging
25
- ## Level of detail in logs: error, warn, info, http, verbose, debug, silly. Default is info
26
- BEAVUCK_TIME_LOG_LEVEL=encrypted:BGfqcxa9XJrMBk7U9QqkbfnXimot5dnz0kRroclEwtsY0JVc8VCw35idcSKpdS3jhCIxg0enNCZEbVMFMt6Q37yvYlIUqCKqk229moGTDSkQ2V/38pwnmzMS1LD/+nUH2yyFpWA=
27
- ## Maximum number of logs to keep. This can be a number of files or number of days. If using days, add 'd' as the suffix. Default is 64
28
- BEAVUCK_TIME_MAX_LOG_FILES=encrypted:BET35n9Sfhqkdahr+JCwV/1sfX5zCE2FmH4lFFOi/WUhg9Wi+DIm2NH2WqfHcYIiWcRRnqpr3f2gnXwLsmRMcSydk7gxuERgA+mn0F2ygzbjTQUw+6l3snLgHKskKTuuA1rO
29
- ## Maximum size of the file after which it will rotate. This can be a number of bytes, or units of kb, mb, and gb. If using the units, add 'k', 'm', or 'g' as the suffix. The units need to directly follow the number. Default is 1m
30
- BEAVUCK_TIME_MAX_SIZE_LOG_FILES=encrypted:BJLXlbtMDxs5di0o+FRr6Im9gYs3GayVwjWomavHzCychYr9JZyOyMTrBN8YrusYoHklvEoHuGfIkUB1m8ErDEl8eJlJvaPZr30+NLPujWSrVwb1B9v8lBon2TfrDQulqSX6