beavuck-time 3.2.13 → 3.3.1

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.
@@ -27,7 +27,7 @@
27
27
  },
28
28
  "info": {
29
29
  "title": "beavuck-time",
30
- "version": "3.2.13",
30
+ "version": "3.3.1",
31
31
  "description": "Get time in ISO format, in UTC timezone, from a simple, lightweight node server",
32
32
  "license": {
33
33
  "name": "Unlicense"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "beavuck-time",
3
- "version": "3.2.13",
3
+ "version": "3.3.1",
4
4
  "description": "Get time in ISO format, in UTC timezone, from a simple, lightweight node server",
5
5
  "keywords": [
6
6
  "time",
@@ -33,12 +33,12 @@
33
33
  "beavuck-time": "build/server.js"
34
34
  },
35
35
  "scripts": {
36
- "run-integration-tests": "cd api_tests/time_api_tests && npx --yes @usebruno/cli run --env local --bail",
36
+ "run-integration-tests": "cd api_tests/time_api_tests && npm i -g --ignore-scripts --allow-git=none --min-release-age=10 @usebruno/cli && bru run --delay 50 --env local --bail",
37
37
  "up-patch": "npm version patch --no-git-tag-version",
38
38
  "up-minor": "npm version minor --no-git-tag-version",
39
39
  "up-major": "npm version major --no-git-tag-version",
40
- "upgrade-dependencies": "ncu --cooldown=10d --format group && ncu -u --cooldown=10d && npm run safe-install && npm prune --verbose && npm run audit",
41
- "audit": "npm audit fix --verbose",
40
+ "upgrade-dependencies": "ncu --format group && ncu -u --cooldown=10d -x typescript && npm run safe-install && npm prune --verbose && npm run audit",
41
+ "audit": "npm audit fix --omit=dev --ignore-scripts --allow-git=none --min-release-age=10 --verbose",
42
42
  "prepublishOnly": "npm run safe-install && npm run build",
43
43
  "safe-install": "npm install --ignore-scripts --allow-git=none --min-release-age=10",
44
44
  "safe-install:ci": "npm ci --ignore-scripts --allow-git=none --min-release-age=10",
@@ -55,9 +55,9 @@
55
55
  "@tsoa/runtime": "^6.6.0",
56
56
  "cors": "^2.8.6",
57
57
  "express": "^5.2.1",
58
- "express-rate-limit": "^8.6.2",
58
+ "express-rate-limit": "^8.7.0",
59
59
  "http-status-codes": "^2.3.0",
60
- "joi": "^18.2.3",
60
+ "joi": "^18.2.5",
61
61
  "tsoa": "^7.0.0-alpha.0",
62
62
  "winston": "^3.19.0",
63
63
  "winston-daily-rotate-file": "^5.0.0"
@@ -67,21 +67,22 @@
67
67
  "@types/cors": "^2.8.19",
68
68
  "@types/express": "^5.0.6",
69
69
  "@types/jest": "^30.0.0",
70
- "@types/node": "^26.1.2",
70
+ "@types/node": "^26.4.1",
71
71
  "@types/supertest": "^7.2.1",
72
- "eslint": "^10.8.0",
73
- "globals": "^17.9.0",
74
- "jest": "^30.4.2",
75
- "jest-util": "^30.4.1",
76
- "npm-check-updates": "^23.0.1",
72
+ "eslint": "^10.9.1",
73
+ "eslint-plugin-import-x": "^4.17.1",
74
+ "globals": "^17.12.0",
75
+ "jest": "^30.5.1",
76
+ "jest-util": "^30.5.1",
77
+ "npm-check-updates": "^23.1.0",
77
78
  "prettier": "3.9.6",
78
79
  "supertest": "^7.2.2",
79
80
  "ts-jest": "^29.4.12",
80
81
  "typescript": "^6.0.3",
81
- "typescript-eslint": "^8.66.0"
82
+ "typescript-eslint": "^8.69.0"
82
83
  },
83
84
  "engines": {
84
- "node": ">=20.12.0"
85
+ "node": ">=22"
85
86
  },
86
87
  "prettier": {
87
88
  "experimentalTernaries": true,
@@ -1,74 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- const supertest_1 = __importDefault(require("supertest"));
7
- const api_1 = require("../api");
8
- const http_status_codes_1 = require("http-status-codes");
9
- const isoTimestamp_1 = require("../types/isoTimestamp");
10
- function getSomeTrustedOrigin() {
11
- return process.env.BEAVUCK_TIME_TRUSTED_ORIGINS?.split(',')[0] ?? '';
12
- }
13
- /**
14
- * Increments the callsMadeSoFar counter and returns the response and trusted origin
15
- */
16
- async function makeSuccessfulCallToNowEndpoint() {
17
- const trustedOrigin = getSomeTrustedOrigin();
18
- const res = await (0, supertest_1.default)(api_1.api).get('/now').set('Origin', trustedOrigin);
19
- return { res, trustedOrigin };
20
- }
21
- describe('App Initialization', () => {
22
- it('should disable x-powered-by header', async () => {
23
- const res = await (0, supertest_1.default)(api_1.api).get('/now');
24
- expect(res.header['x-powered-by']).toBeUndefined();
25
- });
26
- it('should allow requests from trusted origins', async () => {
27
- const { res, trustedOrigin } = await makeSuccessfulCallToNowEndpoint();
28
- expect(res.header['access-control-allow-origin']).toBe(trustedOrigin);
29
- expect(res.status).toBe(http_status_codes_1.StatusCodes.OK);
30
- });
31
- it('should block requests from non-trusted origins', async () => {
32
- const res = await (0, supertest_1.default)(api_1.api).get('/now').set('Origin', 'https://non-trusted.com');
33
- expect(res.header['access-control-allow-origin']).toBeUndefined();
34
- expect(res.status).toBe(http_status_codes_1.StatusCodes.FORBIDDEN);
35
- });
36
- it('should block requests with no origin header', async () => {
37
- const res = await (0, supertest_1.default)(api_1.api).get('/now');
38
- expect(res.header['access-control-allow-origin']).toBeUndefined();
39
- expect(res.status).toBe(http_status_codes_1.StatusCodes.FORBIDDEN);
40
- });
41
- it('should allow requests with no origin header but a referrer header identical to server url', async () => {
42
- const REFERRER = process.env.BEAVUCK_TIME_HOST_URL;
43
- const res = await (0, supertest_1.default)(api_1.api).get('/now').set('Referrer', REFERRER);
44
- expect(res.header['access-control-allow-origin']).toBeUndefined();
45
- expect(res.status).toBe(http_status_codes_1.StatusCodes.OK);
46
- });
47
- it('should allow requests with no origin header but a referer (sic) header identical to server url', async () => {
48
- const REFERER = process.env.BEAVUCK_TIME_HOST_URL;
49
- const res = await (0, supertest_1.default)(api_1.api).get('/now').set('Referer', REFERER);
50
- expect(res.header['access-control-allow-origin']).toBeUndefined();
51
- expect(res.status).toBe(http_status_codes_1.StatusCodes.OK);
52
- });
53
- it('should handle errors using errorHandler middleware', async () => {
54
- const res = await (0, supertest_1.default)(api_1.api).get('/nope').set('Origin', getSomeTrustedOrigin());
55
- expect(res.status).toBe(http_status_codes_1.StatusCodes.NOT_FOUND);
56
- });
57
- it('should return the current time in ISO format', async () => {
58
- const { res } = await makeSuccessfulCallToNowEndpoint();
59
- expect(res.status).toBe(http_status_codes_1.StatusCodes.OK);
60
- expect(res.body).toHaveProperty('now');
61
- expect(res.body.now).toMatch(isoTimestamp_1.RFC_3339_FORMAT);
62
- });
63
- it('should return 500 if HOST_URL is not set', async () => {
64
- const originalHostUrl = process.env.BEAVUCK_TIME_HOST_URL;
65
- delete process.env.BEAVUCK_TIME_HOST_URL;
66
- const res = await (0, supertest_1.default)(api_1.api).get('/now');
67
- expect(res.status).toBe(http_status_codes_1.StatusCodes.INTERNAL_SERVER_ERROR);
68
- process.env.BEAVUCK_TIME_HOST_URL = originalHostUrl;
69
- });
70
- it('should block requests with non-trusted referrer header if origin is not OK', async () => {
71
- const res = await (0, supertest_1.default)(api_1.api).get('/now').set('Referrer', 'https://non-trusted.com');
72
- expect(res.status).toBe(http_status_codes_1.StatusCodes.FORBIDDEN);
73
- });
74
- });
@@ -1,34 +0,0 @@
1
- "use strict";
2
- // src/__tests__/config/corsOptions.test.ts
3
- Object.defineProperty(exports, "__esModule", { value: true });
4
- const corsOptions_1 = require("../../config/corsOptions");
5
- function setTrustedOrigins(...origins) {
6
- process.env.BEAVUCK_TIME_TRUSTED_ORIGINS = origins.join(',');
7
- (0, corsOptions_1.initTrustedOrigins)();
8
- }
9
- describe('isOriginTrusted', () => {
10
- it('returns true for an exact match', () => {
11
- setTrustedOrigins('https://app.example.com');
12
- expect((0, corsOptions_1.isOriginTrusted)('https://app.example.com')).toBe(true);
13
- });
14
- it('returns true for a wildcard pattern matching the origin host', () => {
15
- setTrustedOrigins('https://app.example.com/*');
16
- expect((0, corsOptions_1.isOriginTrusted)('https://app.example.com')).toBe(true);
17
- });
18
- it('does not allow a domain that merely shares a prefix with a trusted origin', () => {
19
- setTrustedOrigins('https://app.example.com');
20
- expect((0, corsOptions_1.isOriginTrusted)('https://app.example.com.evil.com')).toBe(false);
21
- });
22
- it('does not allow a domain that shares a prefix with a wildcard trusted origin', () => {
23
- setTrustedOrigins('https://app.example.com/*');
24
- expect((0, corsOptions_1.isOriginTrusted)('https://app.example.com.evil.com')).toBe(false);
25
- });
26
- it('returns false for an untrusted origin', () => {
27
- setTrustedOrigins('https://app.example.com');
28
- expect((0, corsOptions_1.isOriginTrusted)('https://other.com')).toBe(false);
29
- });
30
- it('returns false when the trusted origin pattern is malformed', () => {
31
- setTrustedOrigins('not-a-url/*');
32
- expect((0, corsOptions_1.isOriginTrusted)('not-a-url')).toBe(false);
33
- });
34
- });
@@ -1,63 +0,0 @@
1
- "use strict";
2
- // src/__tests__/middlewares/corsMiddleware.test.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
- const cors_1 = __importDefault(require("cors"));
8
- const corsMiddleware_1 = require("../../middlewares/corsMiddleware");
9
- const corsError_1 = require("../../errors/corsError");
10
- const beavuckTimeServerError_1 = require("../../errors/beavuckTimeServerError");
11
- const logger_1 = require("../../config/logger");
12
- jest.mock('cors');
13
- jest.mock('../../config/logger');
14
- const mockCors = cors_1.default;
15
- describe('corsMiddleware', () => {
16
- let req;
17
- let res;
18
- let next;
19
- beforeEach(() => {
20
- req = { headers: {} };
21
- res = {};
22
- next = jest.fn();
23
- mockCors.mockReturnValue((_req, _res, n) => n());
24
- process.env.BEAVUCK_TIME_HOST_URL = 'http://localhost:3000';
25
- });
26
- afterEach(() => {
27
- jest.clearAllMocks();
28
- });
29
- it('delegates to cors() when origin header is present', () => {
30
- req.headers.origin = 'http://trusted.com';
31
- (0, corsMiddleware_1.corsMiddleware)(req, res, next);
32
- expect(mockCors).toHaveBeenCalled();
33
- expect(next).toHaveBeenCalledWith();
34
- });
35
- it('logs the sanitized origin on CORS requests', () => {
36
- req.headers.origin = 'http://evil.com\x01injected';
37
- (0, corsMiddleware_1.corsMiddleware)(req, res, next);
38
- expect(logger_1.logger.debug).toHaveBeenCalledWith('CORS request from http://evil.cominjected');
39
- });
40
- it('calls next with BeavuckTimeServerError when HOST_URL is not set', () => {
41
- delete process.env.BEAVUCK_TIME_HOST_URL;
42
- (0, corsMiddleware_1.corsMiddleware)(req, res, next);
43
- expect(next).toHaveBeenCalledWith(expect.any(beavuckTimeServerError_1.BeavuckTimeServerError));
44
- });
45
- it('calls next without error when referrer matches the host', () => {
46
- req.headers.referer = 'http://localhost:3000/page';
47
- (0, corsMiddleware_1.corsMiddleware)(req, res, next);
48
- expect(next).toHaveBeenCalledWith();
49
- });
50
- it('calls next with CorsError when neither origin nor referrer is trusted', () => {
51
- req.headers.referer = 'http://untrusted.com';
52
- (0, corsMiddleware_1.corsMiddleware)(req, res, next);
53
- expect(next).toHaveBeenCalledWith(expect.any(corsError_1.CorsError));
54
- });
55
- it('sanitizes control characters from the CorsError message', () => {
56
- req.headers.referer = 'http://evil.com\x0ainjected';
57
- (0, corsMiddleware_1.corsMiddleware)(req, res, next);
58
- const error = next.mock.calls[0][0];
59
- // eslint-disable-next-line no-control-regex
60
- expect(error.message).not.toMatch(/\x0a/);
61
- expect(error.message).toContain('http://evil.cominjected');
62
- });
63
- });
@@ -1,80 +0,0 @@
1
- "use strict";
2
- // src/__tests__/middlewares/errorHandler.test.ts
3
- Object.defineProperty(exports, "__esModule", { value: true });
4
- const errorHandler_1 = require("../../middlewares/errorHandler");
5
- const beavuckTimeClientError_1 = require("../../errors/beavuckTimeClientError");
6
- const beavuckTimeServerError_1 = require("../../errors/beavuckTimeServerError");
7
- const corsError_1 = require("../../errors/corsError");
8
- const http_status_codes_1 = require("http-status-codes");
9
- const logger_1 = require("../../config/logger");
10
- const tsoa_1 = require("tsoa");
11
- jest.mock('../../config/logger');
12
- describe('errorHandler', () => {
13
- let req;
14
- let res;
15
- let next;
16
- beforeEach(() => {
17
- req = {};
18
- res = {
19
- status: jest.fn().mockReturnThis(),
20
- json: jest.fn().mockReturnThis(),
21
- };
22
- next = jest.fn();
23
- });
24
- it('should handle BeavuckTimeClientError', () => {
25
- const err = new beavuckTimeClientError_1.BeavuckTimeClientError('Some message');
26
- (0, errorHandler_1.errorHandler)(err, req, res, next);
27
- expect(logger_1.logger.warn).toHaveBeenCalledWith(err);
28
- expect(res.status).toHaveBeenCalledWith(err.code);
29
- expect(res.json).toHaveBeenCalledWith({ message: `${err.message}` });
30
- });
31
- it('should handle CorsError', () => {
32
- const err = new corsError_1.CorsError('Some message');
33
- (0, errorHandler_1.errorHandler)(err, req, res, next);
34
- expect(logger_1.logger.warn).toHaveBeenCalledWith(err);
35
- expect(res.status).toHaveBeenCalledWith(err.code);
36
- expect(res.json).toHaveBeenCalledWith({ message: `${err.message}` });
37
- });
38
- it('should handle BeavuckTimeServerError', () => {
39
- const err = new beavuckTimeServerError_1.BeavuckTimeServerError('Some message');
40
- (0, errorHandler_1.errorHandler)(err, req, res, next);
41
- expect(logger_1.logger.error).toHaveBeenCalledWith(err);
42
- expect(res.status).toHaveBeenCalledWith(err.code);
43
- expect(res.json).toHaveBeenCalledWith({ message: beavuckTimeServerError_1.BeavuckTimeServerError.baseMessage });
44
- });
45
- it('should handle non-specific error', () => {
46
- const err = new Error('Some message');
47
- (0, errorHandler_1.errorHandler)(err, req, res, next);
48
- const beavuckError = beavuckTimeServerError_1.BeavuckTimeServerError.fromError(err);
49
- expect(logger_1.logger.error).toHaveBeenCalledWith(beavuckError);
50
- expect(res.status).toHaveBeenCalledWith(http_status_codes_1.StatusCodes.INTERNAL_SERVER_ERROR);
51
- expect(res.json).toHaveBeenCalledWith({ message: beavuckTimeServerError_1.BeavuckTimeServerError.baseMessage });
52
- });
53
- it('should call next if no error', () => {
54
- (0, errorHandler_1.errorHandler)(undefined, req, res, next);
55
- expect(next).toHaveBeenCalled();
56
- });
57
- it('should handle ValidateError', () => {
58
- const err = new tsoa_1.ValidateError({}, 'Some message');
59
- (0, errorHandler_1.errorHandler)(err, req, res, next);
60
- expect(logger_1.logger.error).toHaveBeenCalled();
61
- expect(res.status).toHaveBeenCalledWith(http_status_codes_1.StatusCodes.UNPROCESSABLE_ENTITY);
62
- expect(res.json).toHaveBeenCalledWith({
63
- message: 'Validation Error',
64
- details: err.fields,
65
- });
66
- });
67
- it('should handle unknown error type', () => {
68
- const err = { some: 'unknown error' };
69
- (0, errorHandler_1.errorHandler)(err, req, res, next);
70
- expect(logger_1.logger.error).toHaveBeenCalled();
71
- expect(res.status).toHaveBeenCalledWith(http_status_codes_1.StatusCodes.INTERNAL_SERVER_ERROR);
72
- expect(res.json).toHaveBeenCalledWith({
73
- message: 'Internal Server Error',
74
- });
75
- });
76
- it('should handle null error', () => {
77
- (0, errorHandler_1.errorHandler)(undefined, req, res, next);
78
- expect(next).toHaveBeenCalled();
79
- });
80
- });
@@ -1,15 +0,0 @@
1
- "use strict";
2
- // src/__tests__/utils/stringUtil.test.ts
3
- Object.defineProperty(exports, "__esModule", { value: true });
4
- const stringUtil_1 = require("../../utils/stringUtil");
5
- describe('sanitizeForLog', () => {
6
- it('strips C0 control characters', () => {
7
- expect((0, stringUtil_1.sanitizeForLog)('foo\x00\x01\x1fbar')).toBe('foobar');
8
- });
9
- it('strips DEL and C1 control characters', () => {
10
- expect((0, stringUtil_1.sanitizeForLog)('foo\x7f\x80\x9fbar')).toBe('foobar');
11
- });
12
- it('leaves printable characters untouched', () => {
13
- expect((0, stringUtil_1.sanitizeForLog)('https://evil.com')).toBe('https://evil.com');
14
- });
15
- });
@@ -1,46 +0,0 @@
1
- "use strict";
2
- // src/__tests__/utils/urlUtil.test.ts
3
- Object.defineProperty(exports, "__esModule", { value: true });
4
- const urlUtil_1 = require("../../utils/urlUtil");
5
- const node_url_1 = require("node:url");
6
- const A_VALID_URL_STRING = 'https://example.com:1234';
7
- const SAME_VALID_URL_DIFFERENT_PORT = 'https://example.com:81';
8
- const SOME_OTHER_VALID_URL_STRING = 'https://different.com:1234';
9
- const AN_INVALID_URL_STRING = 'invalid';
10
- describe('urlUtil', () => {
11
- describe('isSameOrigin', () => {
12
- it('returns false when either URL is undefined', () => {
13
- const url = new node_url_1.URL(A_VALID_URL_STRING);
14
- expect((0, urlUtil_1.isSameOrigin)(url)).toBe(false);
15
- expect((0, urlUtil_1.isSameOrigin)(undefined, url)).toBe(false);
16
- });
17
- it('returns true when URLs have the same origin', () => {
18
- const url1 = new node_url_1.URL(A_VALID_URL_STRING);
19
- const url2 = new node_url_1.URL(A_VALID_URL_STRING);
20
- expect((0, urlUtil_1.isSameOrigin)(url1, url2)).toBe(true);
21
- });
22
- it('returns false when URLs have the same origin but different ports', () => {
23
- const url1 = new node_url_1.URL(A_VALID_URL_STRING);
24
- const url2 = new node_url_1.URL(SAME_VALID_URL_DIFFERENT_PORT);
25
- expect((0, urlUtil_1.isSameOrigin)(url1, url2)).toBe(false);
26
- });
27
- it('returns false when URLs have different origins', () => {
28
- const url1 = new node_url_1.URL(A_VALID_URL_STRING);
29
- const url2 = new node_url_1.URL(SOME_OTHER_VALID_URL_STRING);
30
- expect((0, urlUtil_1.isSameOrigin)(url1, url2)).toBe(false);
31
- });
32
- });
33
- describe('tryParseUrl', () => {
34
- it('returns undefined when URL string is undefined', () => {
35
- expect((0, urlUtil_1.tryParseUrl)()).toBeUndefined();
36
- });
37
- it('returns a URL object when URL string is valid', () => {
38
- const url = (0, urlUtil_1.tryParseUrl)(A_VALID_URL_STRING);
39
- expect(url).toBeInstanceOf(node_url_1.URL);
40
- expect(url?.origin).toBe(A_VALID_URL_STRING);
41
- });
42
- it('returns undefined when URL string is invalid', () => {
43
- expect((0, urlUtil_1.tryParseUrl)(AN_INVALID_URL_STRING)).toBeUndefined();
44
- });
45
- });
46
- });
package/build/api.js DELETED
@@ -1,20 +0,0 @@
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);
@@ -1,71 +0,0 @@
1
- "use strict";
2
- // src/config/corsOptions.ts
3
- Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.corsOptions = void 0;
5
- exports.getHostUrl = getHostUrl;
6
- exports.initHostUrl = initHostUrl;
7
- exports.getTrustedOrigins = getTrustedOrigins;
8
- exports.initTrustedOrigins = initTrustedOrigins;
9
- exports.isAllTrusted = isAllTrusted;
10
- exports.isOriginTrusted = isOriginTrusted;
11
- const corsError_1 = require("../errors/corsError");
12
- const urlUtil_1 = require("../utils/urlUtil");
13
- const http_status_codes_1 = require("http-status-codes");
14
- exports.corsOptions = {
15
- methods: ['GET', 'OPTIONS'],
16
- optionsSuccessStatus: http_status_codes_1.StatusCodes.OK,
17
- origin: (origin, callback) => {
18
- if (!origin || isAllTrusted() || (0, urlUtil_1.isSameOrigin)(getHostUrl(), (0, urlUtil_1.tryParseUrl)(origin)) || isOriginTrusted(origin)) {
19
- // eslint-disable-next-line no-restricted-syntax -- the http external library expects null
20
- callback(null, true);
21
- }
22
- else {
23
- callback(new corsError_1.CorsError(origin), false);
24
- }
25
- },
26
- };
27
- let HOST_URL;
28
- let TRUSTED_ORIGINS;
29
- function getHostUrl() {
30
- if (!HOST_URL) {
31
- initHostUrl();
32
- }
33
- return HOST_URL;
34
- }
35
- function initHostUrl() {
36
- HOST_URL = new URL(process.env.BEAVUCK_TIME_HOST_URL);
37
- }
38
- function getTrustedOrigins() {
39
- if (!TRUSTED_ORIGINS || TRUSTED_ORIGINS.length === 0) {
40
- initTrustedOrigins();
41
- }
42
- return TRUSTED_ORIGINS;
43
- }
44
- function initTrustedOrigins() {
45
- const trustedOrigins = process.env.BEAVUCK_TIME_TRUSTED_ORIGINS;
46
- TRUSTED_ORIGINS = trustedOrigins
47
- .split(',')
48
- .map(to => to.trim())
49
- .filter(to => to.length > 0);
50
- }
51
- function isAllTrusted() {
52
- return getTrustedOrigins().includes('*');
53
- }
54
- function isOriginTrusted(origin) {
55
- if (getTrustedOrigins().includes(origin)) {
56
- return true;
57
- }
58
- return getTrustedOrigins().some(trusted => {
59
- const trustedPattern = trusted.replace(/\/\*$/, '');
60
- try {
61
- const trustedUrl = new URL(trustedPattern);
62
- const originUrl = new URL(origin);
63
- return (trustedUrl.protocol === originUrl.protocol &&
64
- trustedUrl.hostname === originUrl.hostname &&
65
- trustedUrl.port === originUrl.port);
66
- }
67
- catch {
68
- return false;
69
- }
70
- });
71
- }
@@ -1,31 +0,0 @@
1
- "use strict";
2
- // src/config/logger.ts
3
- Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.logger = void 0;
5
- const winston_1 = require("winston");
6
- require("winston-daily-rotate-file");
7
- const LOGS_DIR = 'beavuck-time-logs';
8
- const LOG_LEVEL = process.env.BEAVUCK_TIME_LOG_LEVEL ?? 'info';
9
- const MAX_LOG_FILES = process.env.BEAVUCK_TIME_MAX_LOG_FILES ?? 64;
10
- const MAX_SIZE_LOG_FILES = process.env.BEAVUCK_TIME_MAX_SIZE_LOG_FILES ?? '1m';
11
- const dailyRotateFileTransport = new winston_1.transports.DailyRotateFile({
12
- filename: `${LOGS_DIR}/%DATE%-combined.log`,
13
- datePattern: 'YYYY-MM-DD',
14
- zippedArchive: true,
15
- maxSize: MAX_SIZE_LOG_FILES,
16
- maxFiles: MAX_LOG_FILES,
17
- });
18
- exports.logger = (0, winston_1.createLogger)({
19
- level: LOG_LEVEL,
20
- format: winston_1.format.combine(winston_1.format.timestamp(), winston_1.format.printf(({ timestamp, level, message }) => {
21
- return `${timestamp} [${level.toUpperCase()}]: ${message}`;
22
- })),
23
- transports: [
24
- new winston_1.transports.Console(),
25
- new winston_1.transports.File({
26
- filename: `${LOGS_DIR}/error.log`,
27
- level: 'error',
28
- }),
29
- dailyRotateFileTransport,
30
- ],
31
- });
@@ -1,30 +0,0 @@
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);
@@ -1,14 +0,0 @@
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;
@@ -1,13 +0,0 @@
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;
@@ -1,16 +0,0 @@
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;
@@ -1,13 +0,0 @@
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;
@@ -1,14 +0,0 @@
1
- "use strict";
2
- // src/errors/errorResponse.ts
3
- Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.ErrorResponse = void 0;
5
- const beavuckTimeServerError_1 = require("./beavuckTimeServerError");
6
- class ErrorResponse {
7
- message;
8
- details;
9
- constructor(message = beavuckTimeServerError_1.BeavuckTimeServerError.baseMessage, details) {
10
- this.message = message;
11
- this.details = details;
12
- }
13
- }
14
- exports.ErrorResponse = ErrorResponse;
@@ -1,35 +0,0 @@
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 stringUtil_1 = require("../utils/stringUtil");
15
- const corsMiddleware = (req, res, next) => {
16
- const HOST_URL = (0, urlUtil_1.tryParseUrl)(process.env.BEAVUCK_TIME_HOST_URL ?? '');
17
- const origin = req.headers.origin;
18
- // 'referer' is a misspelling that was kept for compatibility: https://en.wikipedia.org/wiki/HTTP_referer
19
- const referrerHeader = req.headers.referrer || req.headers.referer;
20
- if (origin) {
21
- logger_1.logger.debug(`CORS request from ${(0, stringUtil_1.sanitizeForLog)(origin)}`);
22
- (0, cors_1.default)(corsOptions_1.corsOptions)(req, res, next);
23
- }
24
- else if (!HOST_URL) {
25
- next(new beavuckTimeServerError_1.BeavuckTimeServerError('Host URL not set'));
26
- }
27
- else if ((0, urlUtil_1.isSameOrigin)(HOST_URL, (0, urlUtil_1.tryParseUrl)(referrerHeader ?? ''))) {
28
- next();
29
- }
30
- else {
31
- const sanitizedReferrer = referrerHeader === undefined ? undefined : (0, stringUtil_1.sanitizeForLog)(referrerHeader);
32
- next(new corsError_1.CorsError(`origin: ${origin}, referrer: ${sanitizedReferrer}`));
33
- }
34
- };
35
- exports.corsMiddleware = corsMiddleware;
@@ -1,52 +0,0 @@
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 errorResponse_1 = require("../errors/errorResponse");
11
- const stringUtil_1 = require("../utils/stringUtil");
12
- const errorHandler = (err, req, res, next) => {
13
- if (err instanceof tsoa_1.ValidateError) {
14
- const logMsg = `Validation error on ${req.path}: ${JSON.stringify(err.fields)}`;
15
- const resStatus = http_status_codes_1.StatusCodes.UNPROCESSABLE_ENTITY;
16
- const resMsgObj = { message: 'Validation Error', details: err.fields };
17
- handleOtherError(res, logMsg, resStatus, resMsgObj);
18
- }
19
- else if (err instanceof beavuckTimeClientError_1.BeavuckTimeClientError) {
20
- handleBeavuckClientError(res, err);
21
- }
22
- else if (err instanceof beavuckTimeServerError_1.BeavuckTimeServerError || err instanceof Error) {
23
- handleBeavuckServerError(res, beavuckTimeServerError_1.BeavuckTimeServerError.fromError(err));
24
- }
25
- else if (err) {
26
- handleOtherError(res);
27
- }
28
- else {
29
- next();
30
- }
31
- };
32
- exports.errorHandler = errorHandler;
33
- function sendErrorResponse(res, err) {
34
- res.status(err.code).json({ message: err.message });
35
- }
36
- function handleBeavuckClientError(res, err) {
37
- logger_1.logger.warn(err);
38
- sendErrorResponse(res, err);
39
- }
40
- function handleBeavuckServerError(res, err) {
41
- logger_1.logger.error(err);
42
- res.status(err.code).json({ message: beavuckTimeServerError_1.BeavuckTimeServerError.baseMessage });
43
- }
44
- function handleOtherError(res, logMsg = `Unknown error`, resStatus = http_status_codes_1.StatusCodes.INTERNAL_SERVER_ERROR, resMsg = new errorResponse_1.ErrorResponse()) {
45
- if (resStatus === http_status_codes_1.StatusCodes.INTERNAL_SERVER_ERROR) {
46
- handleBeavuckServerError(res, new beavuckTimeServerError_1.BeavuckTimeServerError(logMsg));
47
- }
48
- else {
49
- logger_1.logger.error(`${(0, stringUtil_1.sanitizeForLog)(logMsg)}: ${JSON.stringify(resMsg)}`);
50
- res.status(resStatus).json(resMsg);
51
- }
52
- }
@@ -1,9 +0,0 @@
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;
@@ -1,14 +0,0 @@
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 = Number.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 ? (0, express_rate_limit_1.default)({ windowMs: ONE_MINUTE, limit: RATE_LIMIT }) : (_req, _res, next) => next();
@@ -1,14 +0,0 @@
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;
@@ -1,49 +0,0 @@
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
- "Now": {
10
- "dataType": "refObject",
11
- "properties": {
12
- "now": { "dataType": "string", "required": true },
13
- },
14
- "additionalProperties": false,
15
- },
16
- // 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
17
- };
18
- const templateService = new runtime_1.ExpressTemplateService(models, { "noImplicitAdditionalProperties": "throw-on-extras", "bodyCoercion": true });
19
- // 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
20
- function RegisterRoutes(app) {
21
- // ###########################################################################################################
22
- // 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
23
- // Please look into the "controllerPathGlobs" config option described in the readme: https://github.com/lukeautry/tsoa
24
- // ###########################################################################################################
25
- const argsNowController_getNow = {};
26
- 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) {
27
- // 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
28
- let validatedArgs = [];
29
- try {
30
- validatedArgs = templateService.getValidatedArgs({ args: argsNowController_getNow, request, response });
31
- const controller = new nowController_1.NowController();
32
- await templateService.apiHandler({
33
- methodName: 'getNow',
34
- controller,
35
- response,
36
- next,
37
- validatedArgs,
38
- successStatus: undefined,
39
- });
40
- }
41
- catch (err) {
42
- return next(err);
43
- }
44
- });
45
- // 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
46
- // 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
47
- // 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
48
- }
49
- // 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
package/build/server.js DELETED
@@ -1,79 +0,0 @@
1
- #!/usr/bin/env node
2
- "use strict";
3
- // src/server.ts
4
- Object.defineProperty(exports, "__esModule", { value: true });
5
- exports.startServer = startServer;
6
- const api_1 = require("./api");
7
- const logger_1 = require("./config/logger");
8
- const urlUtil_1 = require("./utils/urlUtil");
9
- try {
10
- process.loadEnvFile();
11
- }
12
- catch {
13
- // .env file is optional
14
- }
15
- function startServer(options = {}) {
16
- manageEnvVars(options);
17
- const server = api_1.api.listen(process.env.BEAVUCK_TIME_API_PORT, () => {
18
- logger_1.logger.info(`
19
- | | | | ,=.
20
- | |__ ___ __ ___ ___ _ ___| | __ ,=""""==.__.=" o".___
21
- | '_ \\ / _ \\/ _\` \\ \\ / / | | |/ __| |/ / ,=.==" ___/
22
- | |_) | __/ (_| |\\ V /| |_| | (__| < ,==.," , , \\,===""
23
- |_.__/ \\___|\\__,_| \\_/ \\__,_|\\___|_|\\_\\ < ,==) \\"'"=._.==) \\
24
- \`=='' \`" \`"
25
- 888 d8b
26
- 888 Y8P
27
- 888
28
- 88888888888888b.d88b. .d88b.
29
- 888 888888 "888 "88bd8P Y8b
30
- 888 888888 888 88888888888
31
- Y88b. 888888 888 888Y8b.
32
- "Y888888888 888 888 "Y8888
33
-
34
- Beavuck Time started successfully
35
-
36
- Ready on port ${process.env.BEAVUCK_TIME_API_PORT} (if this is running in a container, this port number is internal to the container)
37
- `);
38
- });
39
- server.on('error', (err) => {
40
- logger_1.logger.error(`Beavuck Time Server error [${err.code}]: ${err.message}`);
41
- process.exit(1);
42
- });
43
- const gracefulShutdown = (signal) => {
44
- logger_1.logger.info(`${signal} signal received: closing HTTP server`);
45
- server.close(() => {
46
- logger_1.logger.info('HTTP server closed');
47
- process.exit(0);
48
- });
49
- };
50
- const SIGTERM = 'SIGTERM';
51
- const SIGINT = 'SIGINT';
52
- process.on(SIGTERM, () => gracefulShutdown(SIGTERM));
53
- process.on(SIGINT, () => gracefulShutdown(SIGINT));
54
- return server;
55
- }
56
- function manageEnvVars(options) {
57
- logger_1.logger.info('serverOptions: ' + JSON.stringify(options));
58
- process.env.BEAVUCK_TIME_API_PORT = options.apiPort === undefined ? '3000' : String(options.apiPort);
59
- logger_1.logger.debug('API_PORT: ' + process.env.BEAVUCK_TIME_API_PORT);
60
- process.env.BEAVUCK_TIME_HOST_URL = options.hostUrl ?? process.env.BEAVUCK_TIME_HOST_URL;
61
- logger_1.logger.debug('HOST_URL: ' + process.env.BEAVUCK_TIME_HOST_URL);
62
- process.env.BEAVUCK_TIME_TRUSTED_ORIGINS = options.trustedOrigins ?? process.env.BEAVUCK_TIME_TRUSTED_ORIGINS;
63
- logger_1.logger.debug('TRUSTED_ORIGINS: ' + process.env.BEAVUCK_TIME_TRUSTED_ORIGINS);
64
- validateEnv();
65
- }
66
- function validateEnv() {
67
- if (!process.env.BEAVUCK_TIME_HOST_URL || !(0, urlUtil_1.tryParseUrl)(process.env.BEAVUCK_TIME_HOST_URL)) {
68
- logger_1.logger.error('HOST_URL not set or is not a valid URL');
69
- process.exit(1);
70
- }
71
- if (!process.env.BEAVUCK_TIME_TRUSTED_ORIGINS) {
72
- logger_1.logger.error('TRUSTED_ORIGINS not set');
73
- process.exit(1);
74
- }
75
- }
76
- // Support running as standalone binary
77
- if (require.main === module) {
78
- startServer();
79
- }
@@ -1,11 +0,0 @@
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;
@@ -1,10 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.RFC_3339_FORMAT = void 0;
4
- /**
5
- * Stringified date-time in RFC 3339 format (often referred to as ISO 8601 format)
6
- * See [RFC 3339 section 5.6](https://datatracker.ietf.org/doc/html/rfc3339#section-5.6)
7
- * @example 2019-08-24T14:15:22Z
8
- * @format date-time
9
- */
10
- exports.RFC_3339_FORMAT = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$/;
@@ -1,10 +0,0 @@
1
- "use strict";
2
- // src/utils/stringUtil.ts
3
- Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.sanitizeForLog = sanitizeForLog;
5
- function sanitizeForLog(value) {
6
- // About the warning suppression: we're specifically working on control characters here,
7
- // to sanitize strings for protection against log injection
8
- // eslint-disable-next-line no-control-regex
9
- return value.replaceAll(/[\u0000-\u001F\u007F-\u009F]/g, '');
10
- }
@@ -1,34 +0,0 @@
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 node_url_1 = require("node:url");
7
- const logger_1 = require("../config/logger");
8
- const stringUtil_1 = require("./stringUtil");
9
- function isSameOrigin(thisUrl, thatUrl) {
10
- logger_1.logger.debug(`Comparing origins: ${thisUrl?.origin ? (0, stringUtil_1.sanitizeForLog)(thisUrl?.origin) : undefined} and ${thatUrl?.origin ? (0, stringUtil_1.sanitizeForLog)(thatUrl?.origin) : undefined}`);
11
- if (!thisUrl || !thatUrl) {
12
- return false;
13
- }
14
- if (thisUrl.origin === thatUrl.origin) {
15
- return true;
16
- }
17
- const isSameProtocol = thisUrl.protocol === thatUrl.protocol;
18
- const isSameHost = thisUrl.hostname === thatUrl.hostname;
19
- const isSamePort = thisUrl.port === thatUrl.port;
20
- return isSameProtocol && isSameHost && isSamePort;
21
- }
22
- function tryParseUrl(urlString) {
23
- if (!urlString) {
24
- logger_1.logger.debug('Empty URL string');
25
- return undefined;
26
- }
27
- try {
28
- return new node_url_1.URL(urlString);
29
- }
30
- catch (error) {
31
- logger_1.logger.warn(`Invalid URL string: ${(0, stringUtil_1.sanitizeForLog)(urlString)} (${error})`);
32
- }
33
- return undefined;
34
- }