diff --git a/bugs.pdf b/bugs.pdf new file mode 100644 index 0000000..c61c9a7 Binary files /dev/null and b/bugs.pdf differ diff --git a/data/bug copy.json b/data/bug copy.json index 2671b7f..4b277a0 100644 --- a/data/bug copy.json +++ b/data/bug copy.json @@ -1,37 +1,44 @@ [ { - "_id": "9i0mL", - "title": "Cannot save a new car", - "description": "problem when clicking Save", - "severity": 1, - "createdAt": 1542107359454 - }, - { - "_id": "xx3jM", - "title": "Cannot save a new car", - "description": "problem when clicking Save", - "severity": 2, - "createdAt": 1542107359454 + "_id": "a1b2c3", + "title": "Fix login bug", + "description": "Fixing the issue causing login failures.", + "severity": 3, + "createdAt": 1625140800000, + "labels": [ + "critical", + "dev-branch" + ] }, { - "_id": "6lDCn", - "title": "Cannot save a new car", - "description": "problem when clicking Save", - "severity": 1, - "createdAt": 1542107359454 + "_id": "j1k2l3", + "title": "Update documentation", + "description": "Updating the project documentation for new release.", + "severity": 3, + "createdAt": 1625400000000, + "labels": [ + "need-CR" + ] }, { - "_id": "Ujz4N", - "title": "Cannot save a new car", - "description": "problem when clicking Save", - "severity": 1, - "createdAt": 1542107359454 + "_id": "m4n5o6", + "title": "Refactor codebase", + "description": "Refactoring the codebase for better readability and maintenance.", + "severity": 4, + "createdAt": 1625486400000, + "labels": [ + "dev-branch" + ] }, { - "_id": "L078v", - "title": "Cannot save a new car", - "description": "problem when clicking Save", - "severity": 3, - "createdAt": 1542107359454 + "_id": "p7q8r9", + "title": "Fix security issue", + "description": "Addressing the security vulnerability identified in the audit.", + "severity": 5, + "createdAt": 1625572800000, + "labels": [ + "critical", + "need-CR" + ] } ] \ No newline at end of file diff --git a/data/bug.json b/data/bug.json index 0793fa0..8619c09 100644 --- a/data/bug.json +++ b/data/bug.json @@ -1,74 +1,54 @@ [ { - "title": "saved", - "description": "", - "severity": 1, - "createdAt": 1718799635301, + "_id": "a1b2c3", + "title": "Fix login bug", + "description": "Fixing the issue causing login failures.", + "severity": 2, + "createdAt": 1625140800000, "labels": [ "critical", - "need-CR", "dev-branch" - ], - "_id": "HtGef" - }, - { - "_id": "h2BUl", - "title": "deleteed", - "description": "", - "severity": 0, - "createdAt": 1718799665026, - "labels": [ - "critical", - "", - "" ] }, { - "title": "a", - "description": "", + "_id": "j1k2l3", + "title": "Update documentation", + "description": "Updating the project documentation for new release.", "severity": 3, - "createdAt": 1718806958801, + "createdAt": 1625400000000, "labels": [ - "critical", - "", - "" - ], - "_id": "2vvA4" + "need-CR" + ] }, { - "title": "", - "description": "", - "severity": 0, - "createdAt": 1718820128882, + "_id": "m4n5o6", + "title": "Refactor codebase", + "description": "Refactoring the codebase for better readability and maintenance.", + "severity": 4, + "createdAt": 1625486400000, "labels": [ - "", - "", - "" - ], - "_id": "XIscN" + "dev-branch" + ] }, { - "title": "", - "description": "", - "severity": 0, - "createdAt": 1718820136369, + "_id": "p7q8r9", + "title": "Fix security issue", + "description": "Addressing the security vulnerability identified in the audit.", + "severity": 5, + "createdAt": 1625572800000, "labels": [ - "", - "", - "" - ], - "_id": "oQu2W" + "critical", + "need-CR" + ] }, { - "title": "", + "title": "critical", "description": "", - "severity": 0, - "createdAt": 1718820140320, + "severity": 7, + "createdAt": 1719145297585, "labels": [ - "", - "", - "" + "critical" ], - "_id": "yYzob" + "_id": "nTLX4" } ] \ No newline at end of file diff --git a/logs/backend.log b/logs/backend.log index a3133b7..b909dc0 100644 --- a/logs/backend.log +++ b/logs/backend.log @@ -115,3 +115,63 @@ 20.6.2024, 13:42:18 - INFO - Server listening on port http://127.0.0.1:3030/ 20.6.2024, 13:43:52 - INFO - Server listening on port http://127.0.0.1:3030/ 20.6.2024, 14:00:01 - INFO - Server listening on port http://127.0.0.1:3030/ +20.6.2024, 14:05:15 - INFO - Server listening on port http://127.0.0.1:3030/ +20.6.2024, 14:05:31 - INFO - Server listening on port http://127.0.0.1:3030/ +20.6.2024, 14:09:44 - INFO - Server listening on port http://127.0.0.1:3030/ +20.6.2024, 16:22:49 - INFO - Server listening on port http://127.0.0.1:3030/ +20.6.2024, 16:23:19 - INFO - Server listening on port http://127.0.0.1:3030/ +20.6.2024, 16:25:54 - INFO - Server listening on port http://127.0.0.1:3030/ +20.6.2024, 16:26:28 - INFO - Server listening on port http://127.0.0.1:3030/ +20.6.2024, 16:29:17 - INFO - Server listening on port http://127.0.0.1:3030/ +20.6.2024, 16:31:19 - INFO - Server listening on port http://127.0.0.1:3030/ +20.6.2024, 16:39:34 - INFO - Server listening on port http://127.0.0.1:3030/ +20.6.2024, 16:40:32 - INFO - Server listening on port http://127.0.0.1:3030/ +20.6.2024, 16:43:05 - INFO - Server listening on port http://127.0.0.1:3030/ +20.6.2024, 16:44:18 - INFO - Server listening on port http://127.0.0.1:3030/ +20.6.2024, 16:44:50 - INFO - Server listening on port http://127.0.0.1:3030/ +20.6.2024, 16:47:21 - INFO - Server listening on port http://127.0.0.1:3030/ +20.6.2024, 16:48:33 - INFO - Server listening on port http://127.0.0.1:3030/ +20.6.2024, 16:49:04 - INFO - Server listening on port http://127.0.0.1:3030/ +20.6.2024, 16:53:49 - INFO - Server listening on port http://127.0.0.1:3030/ +20.6.2024, 18:12:58 - INFO - Server listening on port http://127.0.0.1:3030/ +20.6.2024, 23:33:16 - INFO - Server listening on port http://127.0.0.1:3030/ +20.6.2024, 23:36:38 - INFO - Server listening on port http://127.0.0.1:3030/ +20.6.2024, 23:38:13 - INFO - Server listening on port http://127.0.0.1:3030/ +20.6.2024, 23:58:45 - INFO - Server listening on port http://127.0.0.1:3030/ +21.6.2024, 14:42:46 - INFO - Server listening on port http://127.0.0.1:3030/ +21.6.2024, 14:49:26 - INFO - Server listening on port http://127.0.0.1:3030/ +21.6.2024, 14:55:17 - INFO - Server listening on port http://127.0.0.1:3030/ +21.6.2024, 15:07:03 - INFO - Server listening on port http://127.0.0.1:3030/ +21.6.2024, 15:09:14 - INFO - Server listening on port http://127.0.0.1:3030/ +21.6.2024, 15:16:30 - INFO - Server listening on port http://127.0.0.1:3030/ +21.6.2024, 15:19:27 - INFO - Server listening on port http://127.0.0.1:3030/ +21.6.2024, 15:29:23 - INFO - Server listening on port http://127.0.0.1:3030/ +21.6.2024, 15:48:25 - INFO - Server listening on port http://127.0.0.1:3030/ +21.6.2024, 15:54:29 - INFO - Server listening on port http://127.0.0.1:3030/ +21.6.2024, 15:59:44 - INFO - Server listening on port http://127.0.0.1:3030/ +21.6.2024, 16:09:43 - INFO - Server listening on port http://127.0.0.1:3030/ +21.6.2024, 16:11:25 - INFO - Server listening on port http://127.0.0.1:3030/ +21.6.2024, 16:13:09 - INFO - Server listening on port http://127.0.0.1:3030/ +21.6.2024, 16:16:05 - INFO - Server listening on port http://127.0.0.1:3030/ +21.6.2024, 16:17:47 - INFO - Server listening on port http://127.0.0.1:3030/ +21.6.2024, 16:19:26 - INFO - Server listening on port http://127.0.0.1:3030/ +21.6.2024, 16:23:13 - INFO - Server listening on port http://127.0.0.1:3030/ +21.6.2024, 17:46:38 - INFO - Server listening on port http://127.0.0.1:3030/ +21.6.2024, 17:57:08 - INFO - Server listening on port http://127.0.0.1:3030/ +21.6.2024, 17:57:32 - INFO - Server listening on port http://127.0.0.1:3030/ +21.6.2024, 18:05:25 - INFO - Server listening on port http://127.0.0.1:3030/ +21.6.2024, 18:08:33 - INFO - Server listening on port http://127.0.0.1:3030/ +21.6.2024, 18:09:44 - INFO - Server listening on port http://127.0.0.1:3030/ +21.6.2024, 18:13:53 - INFO - Server listening on port http://127.0.0.1:3030/ +21.6.2024, 18:46:00 - INFO - Server listening on port http://127.0.0.1:3030/ +21.6.2024, 18:49:49 - INFO - Server listening on port http://127.0.0.1:3030/ +21.6.2024, 18:50:27 - INFO - Server listening on port http://127.0.0.1:3030/ +23.6.2024, 0:03:12 - INFO - Server listening on port http://127.0.0.1:3030/ +23.6.2024, 11:48:10 - INFO - Server listening on port http://127.0.0.1:3030/ +23.6.2024, 15:26:00 - INFO - Server listening on port http://127.0.0.1:3030/ +23.6.2024, 15:27:42 - INFO - Server listening on port http://127.0.0.1:3030/ +23.6.2024, 15:28:59 - INFO - Server listening on port http://127.0.0.1:3030/ +23.6.2024, 15:31:42 - INFO - Server listening on port http://127.0.0.1:3030/ +23.6.2024, 15:34:38 - INFO - Server listening on port http://127.0.0.1:3030/ +23.6.2024, 15:35:03 - INFO - Server listening on port http://127.0.0.1:3030/ +23.6.2024, 16:20:47 - INFO - Server listening on port http://127.0.0.1:3030/ diff --git a/package-lock.json b/package-lock.json index 6854182..7992934 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,16 @@ "cookie-parser": "^1.4.6", "express": "^4.19.2", "follow-redirects": "^1.15.6", - "nodemon": "^3.1.3" + "nodemon": "^3.1.3", + "pdfkit": "^0.15.0" + } + }, + "node_modules/@swc/helpers": { + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.3.17.tgz", + "integrity": "sha512-tb7Iu+oZ+zWJZ3HJqwx8oNwSDIU440hmVMDPhpACWQWnrZHK99Bxs70gT1L2dnr5Hg50ZRWEFkQCAnOVVV0z1Q==", + "dependencies": { + "tslib": "^2.4.0" } }, "node_modules/accepts": { @@ -39,16 +48,64 @@ "node": ">= 8" } }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", + "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", + "dependencies": { + "call-bind": "^1.0.5", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/binary-extensions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", @@ -103,6 +160,14 @@ "node": ">=8" } }, + "node_modules/brotli": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/brotli/-/brotli-1.3.3.tgz", + "integrity": "sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==", + "dependencies": { + "base64-js": "^1.1.2" + } + }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -152,6 +217,14 @@ "fsevents": "~2.3.2" } }, + "node_modules/clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", + "engines": { + "node": ">=0.8" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -209,6 +282,11 @@ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" }, + "node_modules/crypto-js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", + "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==" + }, "node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -217,6 +295,37 @@ "ms": "2.0.0" } }, + "node_modules/deep-equal": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz", + "integrity": "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==", + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.5", + "es-get-iterator": "^1.1.3", + "get-intrinsic": "^1.2.2", + "is-arguments": "^1.1.1", + "is-array-buffer": "^3.0.2", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "isarray": "^2.0.5", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.1", + "side-channel": "^1.0.4", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/define-data-property": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", @@ -233,6 +342,22 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -250,6 +375,11 @@ "npm": "1.2.8000 || >= 1.4.16" } }, + "node_modules/dfa": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/dfa/-/dfa-1.2.0.tgz", + "integrity": "sha512-ED3jP8saaweFTjeGX8HQPjeC1YYyZs98jGNZx6IiBvxW7JG5v492kamAQB3m2wop07CvU/RQmzcKr6bgcC5D/Q==" + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -282,6 +412,25 @@ "node": ">= 0.4" } }, + "node_modules/es-get-iterator": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", + "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "is-arguments": "^1.1.1", + "is-map": "^2.0.2", + "is-set": "^2.0.2", + "is-string": "^1.0.7", + "isarray": "^2.0.5", + "stop-iteration-iterator": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -383,6 +532,30 @@ } } }, + "node_modules/fontkit": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/fontkit/-/fontkit-1.9.0.tgz", + "integrity": "sha512-HkW/8Lrk8jl18kzQHvAw9aTHe1cqsyx5sDnxncx652+CIfhawokEPkeM3BoIC+z/Xv7a0yMr0f3pRRwhGH455g==", + "dependencies": { + "@swc/helpers": "^0.3.13", + "brotli": "^1.3.2", + "clone": "^2.1.2", + "deep-equal": "^2.0.5", + "dfa": "^1.2.0", + "restructure": "^2.0.1", + "tiny-inflate": "^1.0.3", + "unicode-properties": "^1.3.1", + "unicode-trie": "^2.0.0" + } + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dependencies": { + "is-callable": "^1.1.3" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -420,6 +593,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/get-intrinsic": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", @@ -460,6 +641,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -501,6 +690,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", @@ -548,6 +751,19 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "node_modules/internal-slot": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", + "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.0", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -556,6 +772,47 @@ "node": ">= 0.10" } }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", + "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -567,6 +824,46 @@ "node": ">=8" } }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -586,6 +883,17 @@ "node": ">=0.10.0" } }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -594,6 +902,141 @@ "node": ">=0.12.0" } }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", + "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", + "dependencies": { + "call-bind": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz", + "integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==", + "dependencies": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + }, + "node_modules/jpeg-exif": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/jpeg-exif/-/jpeg-exif-1.1.4.tgz", + "integrity": "sha512-a+bKEcCjtuW5WTdgeXFzswSrdqi0jk4XlEtZlx5A94wCoBpFjfFTbo/Tra5SpNCl/YFZPvcV1dJc+TAYeg6ROQ==" + }, + "node_modules/linebreak": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/linebreak/-/linebreak-1.1.0.tgz", + "integrity": "sha512-MHp03UImeVhB7XZtjd0E4n6+3xr5Dq/9xI/5FptGk5FrbDR3zagPa2DS6U8ks/3HjbKWG9Q1M2ufOzxV2qLYSQ==", + "dependencies": { + "base64-js": "0.0.8", + "unicode-trie": "^2.0.0" + } + }, + "node_modules/linebreak/node_modules/base64-js": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.8.tgz", + "integrity": "sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw==", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -733,6 +1176,46 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/object-is": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", + "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/on-finished": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", @@ -744,6 +1227,11 @@ "node": ">= 0.8" } }, + "node_modules/pako": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", + "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==" + }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -757,6 +1245,18 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" }, + "node_modules/pdfkit": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/pdfkit/-/pdfkit-0.15.0.tgz", + "integrity": "sha512-Z0dx0sEPKLW2kbThS1SWZ0iSHlRPoFMpP+oSjNrtwRjsfGivwE+r6emyEFwQG/fx1Ri0AGUHmDcGOSMMlLLnSg==", + "dependencies": { + "crypto-js": "^4.2.0", + "fontkit": "^1.8.1", + "jpeg-exif": "^1.1.4", + "linebreak": "^1.0.2", + "png-js": "^1.0.0" + } + }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", @@ -768,6 +1268,19 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/png-js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/png-js/-/png-js-1.0.0.tgz", + "integrity": "sha512-k+YsbhpA9e+EFfKjTCH3VW6aoKlyNYI6NYdTfDL4CIvFnvsuO84ttonmZE7rc+v23SLTH8XX+5w/Ak9v0xGY4g==" + }, + "node_modules/possible-typed-array-names": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -832,6 +1345,28 @@ "node": ">=8.10.0" } }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", + "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", + "dependencies": { + "call-bind": "^1.0.6", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "set-function-name": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/restructure": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/restructure/-/restructure-2.0.1.tgz", + "integrity": "sha512-e0dOpjm5DseomnXx2M5lpdZ5zoHqF1+bqdMJUohoYVVQa7cBdnk7fdmeI6byNWP/kiME72EeTiSypTCVnpLiDg==" + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -925,6 +1460,20 @@ "node": ">= 0.4" } }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -966,6 +1515,17 @@ "node": ">= 0.8" } }, + "node_modules/stop-iteration-iterator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", + "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", + "dependencies": { + "internal-slot": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -977,6 +1537,11 @@ "node": ">=4" } }, + "node_modules/tiny-inflate": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", + "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==" + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -1004,6 +1569,11 @@ "nodetouch": "bin/nodetouch.js" } }, + "node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" + }, "node_modules/type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -1021,6 +1591,24 @@ "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==" }, + "node_modules/unicode-properties": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/unicode-properties/-/unicode-properties-1.4.1.tgz", + "integrity": "sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==", + "dependencies": { + "base64-js": "^1.3.0", + "unicode-trie": "^2.0.0" + } + }, + "node_modules/unicode-trie": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-2.0.0.tgz", + "integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==", + "dependencies": { + "pako": "^0.2.5", + "tiny-inflate": "^1.0.0" + } + }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -1044,6 +1632,56 @@ "engines": { "node": ">= 0.8" } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", + "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } } } } diff --git a/package.json b/package.json index 2e40122..6b388f4 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "cookie-parser": "^1.4.6", "express": "^4.19.2", "follow-redirects": "^1.15.6", - "nodemon": "^3.1.3" + "nodemon": "^3.1.3", + "pdfkit": "^0.15.0" } } diff --git a/public/RootCmp.jsx b/public/RootCmp.jsx index 8eff01d..c730aa7 100644 --- a/public/RootCmp.jsx +++ b/public/RootCmp.jsx @@ -13,7 +13,7 @@ export function App() {
-
+
} /> } /> diff --git a/public/assets/style/base/base.css b/public/assets/style/base/base.css index b28f8e4..3c4c8c7 100644 --- a/public/assets/style/base/base.css +++ b/public/assets/style/base/base.css @@ -6,8 +6,10 @@ html { } body { + height: 100vh; margin: 0; color: var(--gray3); + background-image: linear-gradient(-86deg, #95c4a8 0, #8bb3bc 100%); } h1, @@ -30,8 +32,6 @@ a { cursor: pointer; } - - /* Dont stretch my Media */ img, embed, diff --git a/public/assets/style/base/layout.css b/public/assets/style/base/layout.css index 9e068de..7a8ac4f 100644 --- a/public/assets/style/base/layout.css +++ b/public/assets/style/base/layout.css @@ -1,6 +1,7 @@ .main-layout { display: grid; - grid-template-columns: 1.6rem 1fr 1.6rem; + grid-template-columns: 10vw 1fr 10vw; + row-gap: 20px; } .main-layout > * { diff --git a/public/assets/style/cmps/AppHeader.css b/public/assets/style/cmps/AppHeader.css index c38ee80..d16bbbd 100644 --- a/public/assets/style/cmps/AppHeader.css +++ b/public/assets/style/cmps/AppHeader.css @@ -1,32 +1,27 @@ -.app-header { - background-color: var(--clr1); - color: var(--clr2bg-light); - -} .header-container { - display: flex; + display: grid; + grid-template-columns: 1fr 1fr; + grid-auto-flow: column; + justify-content: space-between; align-items: center; - + color: var(--clr1); } - .header-container h1 { - flex-grow: 1; + grid-column: 1; } -.app-nav { +nav { display: flex; gap: 15px; } - a.active { color: rgb(241, 212, 241); font-weight: 600; - text-decoration: underline; + text-decoration: none; } - @media (max-width: 720px) { .app-header { color: var(--clr2bg-light); diff --git a/public/assets/style/cmps/BugDetails.css b/public/assets/style/cmps/BugDetails.css index a7e9a8b..8864f6f 100644 --- a/public/assets/style/cmps/BugDetails.css +++ b/public/assets/style/cmps/BugDetails.css @@ -1,18 +1,7 @@ -.car-details { - display: flex; - flex-direction: column; - align-items: flex-start; -} -.car-details h1 { - color: var(--clr1); - font-size: 2em; +.bug-details { + margin: 100px auto; + display: grid; + font-size: 1.5em; + color: var(--clr1); } -.car-details h5 { - color: var(--clr2); -} -.car-details img { - max-width: 200px; - display: block; - margin: auto; -} \ No newline at end of file diff --git a/public/assets/style/cmps/BugFilter.css b/public/assets/style/cmps/BugFilter.css index 76aadf0..42e4dcf 100644 --- a/public/assets/style/cmps/BugFilter.css +++ b/public/assets/style/cmps/BugFilter.css @@ -1,11 +1,13 @@ .bug-filter { display: grid; grid-auto-flow: column; + align-items: center; gap: 10px; padding: 1em; border-radius: 3em; - background-color: var(--clr2bg); + background-image: var(--clr2bgi); + color: var(--clr2); } .bug-filter input,select { diff --git a/public/assets/style/cmps/BugIndex.css b/public/assets/style/cmps/BugIndex.css new file mode 100644 index 0000000..69c1fd3 --- /dev/null +++ b/public/assets/style/cmps/BugIndex.css @@ -0,0 +1,17 @@ +.bug-index { + color: var(--clr1); +} + +.main-index { + display: grid; + gap: 20px; +} + +.add-bug { + width: 20%; +} + +button { + background-color: rgb(117, 173, 192); + color: var(--clr1); +} \ No newline at end of file diff --git a/public/assets/style/cmps/BugList.css b/public/assets/style/cmps/BugList.css index 346c1a0..b0a666d 100644 --- a/public/assets/style/cmps/BugList.css +++ b/public/assets/style/cmps/BugList.css @@ -13,5 +13,6 @@ grid-template-columns: 1fr 1fr 1fr 1fr 1fr; justify-content: space-around; align-items: center; - background-color: var(--clr1bg); + background-image: var(--clr2bgi); + color: var(--clr2); } diff --git a/public/assets/style/cmps/GetPageBugs.css b/public/assets/style/cmps/GetPageBugs.css new file mode 100644 index 0000000..34a35a6 --- /dev/null +++ b/public/assets/style/cmps/GetPageBugs.css @@ -0,0 +1,3 @@ +.get-page-bugs { + text-align: center; +} \ No newline at end of file diff --git a/public/assets/style/cmps/Home.css b/public/assets/style/cmps/Home.css index dffe02a..c41aaa2 100644 --- a/public/assets/style/cmps/Home.css +++ b/public/assets/style/cmps/Home.css @@ -1,7 +1,10 @@ - .home { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; -} \ No newline at end of file + display: grid; + grid-template-columns: 30vw 1fr 30vw; + text-align: center; +} + +.home > * { + margin: 100px auto; + grid-column: 2; +} diff --git a/public/assets/style/cmps/UserMsg.css b/public/assets/style/cmps/UserMsg.css index a760720..5c6f550 100644 --- a/public/assets/style/cmps/UserMsg.css +++ b/public/assets/style/cmps/UserMsg.css @@ -1,25 +1,10 @@ .user-msg { - background-color: lightgray; padding: .5em 1em; position: fixed; bottom: 1em; right: 1em; - color: white; font-weight: bold; - border: 3px solid black; border-radius: 2px; + background-color: rgb(56, 55, 55); + color: white; } - -.user-msg.success { - background-color: var(--clr1); -} - -.user-msg.error { - background-color: var(--clr2); -} - - -.user-msg button{ - float: right; - margin: 1em; -} \ No newline at end of file diff --git a/public/assets/style/main.css b/public/assets/style/main.css index 67a8547..399696f 100644 --- a/public/assets/style/main.css +++ b/public/assets/style/main.css @@ -11,10 +11,12 @@ /* Components */ @import "cmps/AppHeader.css"; @import "cmps/UserMsg.css"; -@import "cmps/ToggleButton.css"; +@import "cmps/Home.css"; +@import "cmps/BugIndex.css"; @import "cmps/BugFilter.css"; @import "cmps/BugList.css"; @import "cmps/BugPreview.css"; @import "cmps/BugDetails.css"; @import "cmps/BugEdit.css"; +@import "cmps/GetPageBugs.css"; diff --git a/public/assets/style/setup/vars.css b/public/assets/style/setup/vars.css index 4a4175a..3ae1680 100644 --- a/public/assets/style/setup/vars.css +++ b/public/assets/style/setup/vars.css @@ -1,14 +1,15 @@ :root { - --clr1: rgb(96, 107, 91); - --clr2: rgb(120, 99, 110); + --clr1: rgba(255, 255, 255, 0.831); + --clr2: rgb(120, 99, 110); - --clr1bg: rgb(153, 166, 149); - --clr1bg-light: rgb(205, 221, 200); - --clr2bg: rgb(233, 206, 221); - --clr2bg-light: rgb(253, 236, 246); + --clr1bg: rgb(197, 203, 196); + --clr1bg-light: rgb(205, 221, 200); + --clr2bg: rgb(88, 88, 88); + --clr2bg-light: rgb(253, 236, 246); - --gray1: rgb(240, 240, 240); - --gray2: rgb(155, 155, 155); - --gray3: rgb(44, 44, 44); + --gray1: rgb(240, 240, 240); + --gray2: rgb(155, 155, 155); + --gray3: rgb(44, 44, 44); -} \ No newline at end of file + --clr2bgi: linear-gradient(-86deg, #49989c 0, #baecf9 100%); +} diff --git a/public/cmps/AppFooter.jsx b/public/cmps/AppFooter.jsx index 96fdb8d..5a2b08c 100644 --- a/public/cmps/AppFooter.jsx +++ b/public/cmps/AppFooter.jsx @@ -10,7 +10,6 @@ export function AppFooter () { return (

- coffeerights to all

) diff --git a/public/cmps/AppHeader.jsx b/public/cmps/AppHeader.jsx index 131fb87..2bd0ffb 100644 --- a/public/cmps/AppHeader.jsx +++ b/public/cmps/AppHeader.jsx @@ -1,21 +1,23 @@ -const {NavLink} = ReactRouterDOM -const {useEffect} = React +const { NavLink } = ReactRouterDOM +const { useEffect } = React -import {UserMsg} from './UserMsg.jsx' +import { UserMsg } from './UserMsg.jsx' export function AppHeader() { - useEffect(() => { - // component did mount when dependancy array is empty - }, []) + useEffect(() => { + // component did mount when dependancy array is empty + }, []) - return ( -
- - -

Bugs are Forever

-
- ) + return ( +
+
+ +

Bugs are Forever

+ +
+
+ ) } diff --git a/public/cmps/BugFilter.jsx b/public/cmps/BugFilter.jsx index 04632ef..3930ed0 100644 --- a/public/cmps/BugFilter.jsx +++ b/public/cmps/BugFilter.jsx @@ -1,6 +1,6 @@ const { useState, useEffect } = React -export function BugFilter({ filterBy, onSetFilterBy }) { +export function BugFilter({ filterBy, onSetFilterBy, labels: availableLabels }) { const [filterByToEdit, setFilterByToEdit] = useState(filterBy) useEffect(() => { @@ -8,10 +8,10 @@ export function BugFilter({ filterBy, onSetFilterBy }) { }, [filterByToEdit]) function handelChange({ target }) { - const name = target.name + const field = target.name let value = target.value - console.log('value:', value) - console.log('name:', name) + console.log('name:', field) + console.dir(target) switch (target.type) { case 'number': @@ -21,11 +21,27 @@ export function BugFilter({ filterBy, onSetFilterBy }) { case 'checkbox': value = target.checked break + default: + break } - setFilterByToEdit(prevFilter => ({ ...prevFilter, [name]: value })) + console.log('value:', value) + setFilterByToEdit(prevFilter => ({ ...prevFilter, [field]: value, pageIdx: 0 })) } - const { txt, minSeverity } = filterByToEdit + function handleLabelChange({ target }) { + const { name: label, checked: isChecked } = target + + setFilterByToEdit(prevFilter => ({ + ...prevFilter, + pageIdx: 0, + labels: isChecked + ? [...prevFilter.labels, label] + : prevFilter.labels.filter(lbl => lbl !== label), + })) + } + + const { txt, minSeverity, labels } = filterByToEdit + console.log('labels:', labels) return (
- + + + +

labels:

+ {availableLabels.map(label => ( + + ))}
) } diff --git a/public/pages/BugDetails.jsx b/public/pages/BugDetails.jsx index 1b9989e..6f986a2 100644 --- a/public/pages/BugDetails.jsx +++ b/public/pages/BugDetails.jsx @@ -21,13 +21,13 @@ export function BugDetails() { }, []) if (!bug) return

loadings....

- return
+ return

Bug Details 🐛

{bug.title}

Severity: {bug.severity}

{bug.labels.join(', ')}

Back to List -
+ } diff --git a/public/pages/BugIndex.jsx b/public/pages/BugIndex.jsx index 3ea5adc..e4a8f6b 100644 --- a/public/pages/BugIndex.jsx +++ b/public/pages/BugIndex.jsx @@ -9,12 +9,13 @@ const { useState, useEffect, useRef } = React export function BugIndex() { const [bugs, setBugs] = useState([]) + const [labels, setLabels] = useState([]) const [filterBy, setFilterBy] = useState(bugService.getDefaultFilter()) const debouncedSetFilterBy = useRef(utilService.debounce(onSetFilterBy, 500)) useEffect(() => { - loadBugs() + loadLabels() }, []) useEffect(() => { @@ -28,8 +29,14 @@ export function BugIndex() { setFilterBy(prevFilter => ({ ...prevFilter, ...filterBy })) } - function loadBugs() { - bugService.query().then(setBugs) + function loadLabels() { + bugService + .getLabels() + .then(labels => setLabels(labels)) + .catch(err => { + console.log(err) + showErrorMsg('Cannot get labels') + }) } function onRemoveBug(bugId) { @@ -52,10 +59,8 @@ export function BugIndex() { severity: +prompt('Bug severity?'), labels: [], } - for (let i = 0; i < 3; i++) { - let label = prompt('label?(critical, need-CR, dev-branch)') - bug.labels.push(label) - } + let label = prompt('label?(critical, need-CR, dev-branch)').split(',').join('') + bug.labels.push(label) bugService .save(bug) @@ -88,15 +93,37 @@ export function BugIndex() { }) } + function onDownloadPdf() { + bugService + .downloadPdf() + .then(() => { + console.log('PDF DOWNLOAD') + showSuccessMsg('Download pdf successfully') + }) + .catch(err => { + console.log('err:', err) + showErrorMsg('Cannot download pdf') + }) + } + return ( -
+

Bugs App

-
- - +
+ +
+ + +
- +
-
+
) } diff --git a/public/pages/Home.jsx b/public/pages/Home.jsx index bb9487a..c48c769 100644 --- a/public/pages/Home.jsx +++ b/public/pages/Home.jsx @@ -1,7 +1,6 @@ export function Home() { return ( -
-

Home is Home

+
) diff --git a/public/services/bug.service.js b/public/services/bug.service.js index 84b2cd3..5abd3a0 100644 --- a/public/services/bug.service.js +++ b/public/services/bug.service.js @@ -1,5 +1,3 @@ -import { request } from "express" - const BASE_URL = '/api/bug' export const bugService = { @@ -8,6 +6,8 @@ export const bugService = { save, remove, getDefaultFilter, + getLabels, + downloadPdf } function query(filterBy = {}) { @@ -17,16 +17,22 @@ function getById(bugId) { return axios.get(BASE_URL + '/' + bugId).then(res => res.data) } function remove(bugId) { - return axios.delete(BASE_URL + '/' + bugId).then(() => console.log(bugId + ' deleted')) + return axios.delete(BASE_URL + '/' + bugId).then(res => res.data) } function save(bug) { - if (bug._id) { - return axios.put(BASE_URL + '/' + bug._id, bug).then(res => res.data) - } else { - return axios.post(BASE_URL, bug).then(res => res.data) - } + const method = bug._id ? 'put' : 'post' + return axios[method](BASE_URL, bug).then(res => res.data) +} + +function getLabels() { + return axios.get(BASE_URL + '/labels').then(res => res.data) } function getDefaultFilter() { - return { txt: '', minSeverity: '', pageIdx: 0, labels: '', sortBy: '' } + return { txt: '', minSeverity: 0, pageIdx: 0, labels: [], sortBy: '' } +} + +function downloadPdf() { + return axios.get(BASE_URL + '/download') + .then(res => res.data) } diff --git a/server.js b/server.js index 5acb530..87880d2 100644 --- a/server.js +++ b/server.js @@ -1,5 +1,7 @@ import express from 'express' import cookieParser from 'cookie-parser' +import fs from 'fs' +import PDFDocument from 'pdfkit' import { bugService } from './services/bug.service.js' import { loggerService } from './services/logger.service.js' @@ -15,8 +17,9 @@ app.get('/api/bug', (req, res) => { txt: req.query.txt || '', minSeverity: +req.query.minSeverity || 0, pageIdx: +req.query.pageIdx || 0, - labels: req.query.labels || '', sortBy: req.query.sortBy || '', + labels: req.query.labels || [], + checkbox: req.query.checkbox || '', } bugService @@ -28,18 +31,58 @@ app.get('/api/bug', (req, res) => { }) }) +app.get('/api/bug/labels', (req, res) => { + bugService + .getLabels() + .then(labels => res.send(labels)) + .catch(err => { + loggerService.error(`Couldn't get labels`, err) + res.status(500).send(`Couldn't get labels`) + }) +}) + +app.get('/api/bug/download', (req, res) => { + const doc = new PDFDocument() + doc.pipe(fs.createWriteStream('bugs.pdf')) + doc.fontSize(25).text('BUGS LIST').fontSize(16) + + bugService.query() + .then((bugs) => { + bugs.forEach((bug) => { + const bugTxt = `${bug.title}: ${bug.description}. (severity: ${bug.severity})` + doc.text(bugTxt) + }) + + doc.end() + res.end() + }) +}) + + app.get('/api/bug/:id', (req, res) => { const { id } = req.params var visitedBugs = req.cookies.visitedBugs || [] - if (visitedBugs.length >= 3) res.status(401).send('You cannot access the bug, wait!') + if (visitedBugs.length >= 3) return res.status(401).send('You cannot access the bug, wait!') if (!visitedBugs.includes(id)) visitedBugs.push(id) res.cookie('visitedBugs', visitedBugs, { maxAge: 7000 }) - bugService.getById(id).then(bug => res.send(bug)) + bugService + .getById(id) + .then(bug => res.send(bug)) + .catch(err => { + loggerService.error(`Couldn't get bug (${id})`, err) + res.status(500).send(`Couldn't get bug (${id})`) + }) +}) + +app.delete('/api/bug/:id', (req, res) => { + const { id } = req.params + + bugService.remove(id).then(() => res.send(`Bug ${id} deleted...`)) }) -app.put('/api/bug/:id', (req, res) => { +app.put('/api/bug', (req, res) => { const { _id, title, description, severity, createdAt, labels } = req.body const bugToSave = { _id, @@ -53,7 +96,7 @@ app.put('/api/bug/:id', (req, res) => { bugService.save(bugToSave).then(savedBug => res.send(savedBug)) }) -app.post('/api/bug/', (req, res) => { +app.post('/api/bug', (req, res) => { const { title, description, severity, createdAt, labels } = req.body const bugToSave = { title: title || '', @@ -66,11 +109,5 @@ app.post('/api/bug/', (req, res) => { bugService.save(bugToSave).then(savedBug => res.send(savedBug)) }) -app.delete('/api/bug/:id', (req, res) => { - const { id } = req.params - - bugService.remove(id).then(() => res.send(`Bug ${id} deleted...`)) -}) - const port = 3030 app.listen(port, () => loggerService.info(`Server listening on port http://127.0.0.1:${port}/`)) diff --git a/services/bug.service.js b/services/bug.service.js index 64fcee1..8285f52 100644 --- a/services/bug.service.js +++ b/services/bug.service.js @@ -5,12 +5,14 @@ export const bugService = { getById, remove, save, + getLabels } const PAGE_SIZE = 3 var bugs = utilService.readJsonFile('./data/bug.json') function query(filterBy) { var filteredBugs = bugs + if (!filterBy) return Promise.resolve(filteredBugs) if (filterBy.txt) { const regExp = new RegExp(filterBy.txt, 'i') @@ -19,33 +21,21 @@ function query(filterBy) { if (filterBy.minSeverity) { filteredBugs = filteredBugs.filter(bug => bug.severity >= filterBy.minSeverity) } - if (filterBy.labels) { - switch (filterBy.labels) { - case 'critical': - filteredBugs = filteredBugs.filter(bug => bug.labels.includes('critical')) - break - case 'need-CR': - filteredBugs = filteredBugs.filter(bug => bug.labels.includes('need-CR')) - break - case 'dev-branch': - filteredBugs = filteredBugs.filter(bug => bug.labels.includes('dev-branch')) - break - case 'all': - filteredBugs = filteredBugs.filter(bug => bug) - break - } + if (filterBy.labels?.length) { + filteredBugs = filteredBugs.filter(bug => filterBy.labels.every(label => bug.labels.includes(label))) } if (filterBy.sortBy) { + var descending = filterBy.checkbox === 'true' ? -1 : 1 switch (filterBy.sortBy) { case 'createdAt': - filteredBugs.sort((b1, b2) => b1.createdAt - b2.createdAt) + filteredBugs.sort((b1, b2) => (b1.createdAt - b2.createdAt) * descending) break case 'severity': - filteredBugs.sort((b1, b2) => b1.severity - b2.severity) + filteredBugs.sort((b1, b2) => (b1.severity - b2.severity) * descending) break case 'title': - filteredBugs.sort((b1, b2) => b1.title.localeCompare(b2.title)) + filteredBugs.sort((b1, b2) => b1.title.localeCompare(b2.title) * descending) break } } @@ -79,6 +69,15 @@ function save(bugToSave) { return _saveBugsToFile().then(() => bugToSave) } +function getLabels() { + return query().then(bugs => { + const bugsLabels = bugs.reduce((acc, bug) => { + return [...acc, ...bug.labels] + }, []) + return [...new Set(bugsLabels)] + }) +} + function _saveBugsToFile() { return utilService.writeJsonFile('./data/bug.json', bugs) }