Compare commits

..

32 Commits

Author SHA1 Message Date
c35726bf5c fix(lst): missing , in versionRc 2025-03-23 11:11:06 -05:00
e82208fc5e build(build): removed from showing in the change log 2025-03-23 11:10:00 -05:00
9bdca3317c chore: bump build number to 50 2025-03-23 11:06:13 -05:00
61abd44328 chore(release): 2.9.0 2025-03-23 11:05:26 -05:00
acb9876d9b chore: bump build number to 49 2025-03-23 11:02:22 -05:00
10d88f53eb fix(frontend): removed unwanted import 2025-03-23 11:01:21 -05:00
bba0aa2ee4 refactor(frontend): added date-fns into the frontend 2025-03-23 11:00:38 -05:00
b7773ec02a fix(sqlserver): if we already have a connection just return we dont want to try a second time 2025-03-23 11:00:15 -05:00
b9dd6e3ae2 fix(auth): fixed the getaccess to be getuseraccess as it was orignally 2025-03-23 10:59:48 -05:00
f940bcdc9d fix(serverlist): corrected the time by removing teh Z at the end of the time 2025-03-23 10:59:23 -05:00
2ae3c8ba59 fix(loginform): removed the console log that was left by accident 2025-03-23 10:58:49 -05:00
97b9c4db4a chore: bump build number to 48 2025-03-23 10:16:28 -05:00
d8eddafcae feat(auth): add, update were added for adm account in backend only 2025-03-23 10:07:28 -05:00
58b58424ab test(returnres): tryed to make a standard return res but will come back to this later 2025-03-23 10:06:34 -05:00
72d52d9256 feat(trycatch): added in theo's try catch to reduce the code and love it 2025-03-23 10:05:51 -05:00
5dfece09b7 refactor(login): removed all the data from teh login dropdown as it could cause issues 2025-03-23 10:05:27 -05:00
97eb73c6d1 test(streaming logs): will come back to this later this is killing me inside 2025-03-23 10:04:58 -05:00
bb6d523abb refactor(server): removed the websocket wrapper going wiht normal ws 2025-03-22 10:06:14 -05:00
09d3a7041a docs(install): added more env params and an install install stuff 2025-03-22 10:05:47 -05:00
132e8d0146 feat(lst): added prettier config so we have the same formatting across all computers 2025-03-22 10:05:10 -05:00
d0a0d08902 feat(scripts): made moving scripts more proper 2025-03-22 10:04:48 -05:00
208cd615af refactor(auth): added in correct bycrptjs 2025-03-22 10:04:14 -05:00
e82ef76316 test(streaming): more testing on streaming the lofs 2025-03-22 08:21:11 -05:00
4db4eea2d1 test(streaming): more streaming test 2025-03-21 22:08:13 -05:00
edcfff6cc6 fix(scaler): fix due to update 2025-03-21 22:07:49 -05:00
61860c759e build(updater): dynamic ports mainly for iowa2 2025-03-21 22:07:32 -05:00
08c9b3404f test(streaming logs): more test but failed again 2025-03-21 22:06:53 -05:00
93ed2e9ee8 fix(calendar): this component had a bug and needed a lib update 2025-03-21 22:06:25 -05:00
fb9ee15bda chore(pkg updates): updated all pkgs 2025-03-21 21:48:04 -05:00
76bc0db3dd test(server): start/stop/restart buttons added. comment #14 2025-03-21 20:09:39 -05:00
2e5de34cb5 fix(login): if we have a wrong password or username we didnt properly error instead we crashed 2025-03-21 19:44:02 -05:00
07e47e64ae fix(consume material): when we consumed material the button was never reenabled
closes #15
2025-03-21 19:42:51 -05:00
53 changed files with 5207 additions and 6561 deletions

View File

@@ -1,16 +1,17 @@
{ {
"types": [ "types": [
{"type": "feat", "section": "🌟 Enhancements"}, { "type": "feat", "section": "🌟 Enhancements" },
{"type": "fix", "section": "🐛 Bug fixes"}, { "type": "fix", "section": "🐛 Bug fixes" },
{"type": "chore", "hidden": false, "section": "📝 Chore"}, { "type": "chore", "hidden": false, "section": "📝 Chore" },
{"type": "docs", "section": "📚 Documentation"}, { "type": "docs", "section": "📚 Documentation" },
{"type": "style", "hidden": true}, { "type": "style", "hidden": true },
{"type": "refactor", "section": "🛠️ Code Refactor"}, { "type": "refactor", "section": "🛠️ Code Refactor" },
{"type": "perf", "hidden": false, "section": "🚀 Performance"}, { "type": "perf", "hidden": false, "section": "🚀 Performance" },
{"type": "test", "section": "📝 Testing Code"}, { "type": "test", "section": "📝 Testing Code" },
{"type": "ci", "section": "📈 Project changes"} { "type": "ci", "hidden": false, "section": "📈 Project changes" },
], { "type": "build", "hidden": true, "section": "📈 Project Builds" }
"commitUrlFormat": "https://git.tuffraid.net/cowch/lstV2/commits/{{hash}}", ],
"compareUrlFormat": "https://git.tuffraid.net/cowch/lstV2/compare/{{previousTag}}...{{currentTag}}", "commitUrlFormat": "https://git.tuffraid.net/cowch/lstV2/commits/{{hash}}",
"header": "# All CHanges to LST can be found below.\n" "compareUrlFormat": "https://git.tuffraid.net/cowch/lstV2/compare/{{previousTag}}...{{currentTag}}",
"header": "# All CHanges to LST can be found below.\n"
} }

26
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,26 @@
{
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
"[javascript]": {
"editor.formatOnSave": true
},
"[javascriptreact]": {
"editor.formatOnSave": true
},
"[typescript]": {
"editor.formatOnSave": true
},
"[typescriptreact]": {
"editor.formatOnSave": true
},
"[json]": {
"editor.formatOnSave": true
},
"[graphql]": {
"editor.formatOnSave": true
},
"[handlebars]": {
"editor.formatOnSave": true
}
}

View File

@@ -1,5 +1,130 @@
# All CHanges to LST can be found below. # All CHanges to LST can be found below.
## [2.9.0](https://git.tuffraid.net/cowch/lstV2/compare/v2.8.0...v2.9.0) (2025-03-23)
### 📈 Project changes
* **frontend:** added ocme as a proxy in the dev ([eb2c34c](https://git.tuffraid.net/cowch/lstV2/commits/eb2c34c557b72c3387b70addac30a4d8291402d4))
### 📚 Documentation
* **install:** added more env params and an install install stuff ([09d3a70](https://git.tuffraid.net/cowch/lstV2/commits/09d3a7041a18283a5add86ea845a8d7249522769))
* **install:** removed the super secret key ([357c118](https://git.tuffraid.net/cowch/lstV2/commits/357c1183964be0f3c02207c24bc8f83347282211))
* **logs:** changes how logs are put into the db they will be there name vs key ([18daca9](https://git.tuffraid.net/cowch/lstV2/commits/18daca904e0305371c6128988b48d54e3aec9a2a))
* **migration:** added more documents on the install md ([0bd217c](https://git.tuffraid.net/cowch/lstV2/commits/0bd217c727d726d62ddf06a0e44e95c4606361cf))
### 📝 Testing Code
* **ocme:** cycle count intital improvements ([7a22b52](https://git.tuffraid.net/cowch/lstV2/commits/7a22b52c916335c748598b82e78819c325bb8c4c))
* **ocp dash:** more work on the dashboard ([f3c4c26](https://git.tuffraid.net/cowch/lstV2/commits/f3c4c26ef957e6fe359a77f139ad36cdacefb8ef))
* **ocp:** more work on the dashboard ([8324fff](https://git.tuffraid.net/cowch/lstV2/commits/8324fffeb664bff3751ffc26e988a4a506b658a9))
* **returnres:** tryed to make a standard return res but will come back to this later ([58b5842](https://git.tuffraid.net/cowch/lstV2/commits/58b58424abbf98feec0c5442a59f4d055bbd1811))
* **rfid:** more work on the rfid service ([21c3749](https://git.tuffraid.net/cowch/lstV2/commits/21c374903b5cba56ced44b7eb2066ee902fc7bc3))
* **server:** start/stop/restart buttons added. comment [#14](https://git.tuffraid.net/cowch/lstV2/issues/14) ([76bc0db](https://git.tuffraid.net/cowch/lstV2/commits/76bc0db3dd9c48b69e4f6f571181a1f07c48bdeb))
* **streaming logs:** more test but failed again ([08c9b34](https://git.tuffraid.net/cowch/lstV2/commits/08c9b3404f548a167464445ec2f19288a092b0dc))
* **streaming logs:** test for streaming logs ([73eb705](https://git.tuffraid.net/cowch/lstV2/commits/73eb70538e36601cf436aaba244f99d5bd873d34))
* **streaming logs:** will come back to this later this is killing me inside ([97eb73c](https://git.tuffraid.net/cowch/lstV2/commits/97eb73c6d1aef747ef98f5f666fe47622795746f))
* **streaming:** more streaming test ([4db4eea](https://git.tuffraid.net/cowch/lstV2/commits/4db4eea2d12e37809879e96ed4279d6e23e83acc))
* **streaming:** more testing on streaming the lofs ([e82ef76](https://git.tuffraid.net/cowch/lstV2/commits/e82ef76316f0562b57124eb977c86fd2c6a3f332))
### 🌟 Enhancements
* **admincheck:** this check is so we dont use stuff on the wrong servers ([3d08398](https://git.tuffraid.net/cowch/lstV2/commits/3d083986aed528c2f881d6f673c0be03b8986c0b))
* **auth:** add, update were added for adm account in backend only ([d8eddaf](https://git.tuffraid.net/cowch/lstV2/commits/d8eddafcaea9141e9413a122a320649c7dd325e5))
* **auth:** remove all old localstorage if no session ([8fb06c7](https://git.tuffraid.net/cowch/lstV2/commits/8fb06c71d370a27697628077474a261596b567e0))
* **db:** logs, manualprints added ([0914b53](https://git.tuffraid.net/cowch/lstV2/commits/0914b5334119fa705eedddc6c9e8303cb82da551))
* **installer:** added a check for lstv2 already installed ([4696835](https://git.tuffraid.net/cowch/lstV2/commits/4696835c6557c2eae3be6a292144493be9d98f67))
* **logger:** logger service created with its endpoints ([7ec5c5b](https://git.tuffraid.net/cowch/lstV2/commits/7ec5c5beb0a9b02e8b8761908ee75ac2cfd317ee))
* **logger:** streaming logs works server side not frontend for now ([e833c48](https://git.tuffraid.net/cowch/lstV2/commits/e833c48cc8f68af40888ea161100e02f6ad19604))
* **lst:** added in delay global function ([7497432](https://git.tuffraid.net/cowch/lstV2/commits/74974323f0a7bd7c2eaa22024b7a8e91db2868e2))
* **lst:** added prettier config so we have the same formatting across all computers ([132e8d0](https://git.tuffraid.net/cowch/lstV2/commits/132e8d0146318fa9deb673bbcabf0d80c2a6d39f))
* **ocme:** added in ocme service so we can utlize 2 ports ([ae7e3fd](https://git.tuffraid.net/cowch/lstV2/commits/ae7e3fd54e5c256fb82e68f2e935e3b914e43d13))
* **ocme:** cycle count implemeneted ([74bcd6e](https://git.tuffraid.net/cowch/lstV2/commits/74bcd6e805c34e181f0c48310a799daf3afaee66))
* **ocmeserver:** the server was just migrated so it can be upgraded to lstv2 ([e258aae](https://git.tuffraid.net/cowch/lstV2/commits/e258aaead9a56cc4de36c17ed60b0bdaa91019cb))
* **ocp:** added in service plus manual print log ([7165c95](https://git.tuffraid.net/cowch/lstV2/commits/7165c959b9d5b37c0d4b01cb3f5bc27b40cec71d))
* **ports:** added in production port if in production ([121bed5](https://git.tuffraid.net/cowch/lstV2/commits/121bed59fda04b2ad134feb0895428515a1c56d8))
* **scripts:** made moving scripts more proper ([d0a0d08](https://git.tuffraid.net/cowch/lstV2/commits/d0a0d0890255acf890ba402386847b19566c92df))
* **serverdata:** added in huston, sherman. and corrected contact info in westbend ([4908d66](https://git.tuffraid.net/cowch/lstV2/commits/4908d6644a392395e660d382536c0fd31e3d0647))
* **server:** ocpService and loggerService added ([2d3f308](https://git.tuffraid.net/cowch/lstV2/commits/2d3f30887744bddfe22dc764188cf727a5e476df))
* **servers:** added dayton in ([bbd7a17](https://git.tuffraid.net/cowch/lstV2/commits/bbd7a17144e1e1a0faa192139cb1539c2f1ecc5c))
* **settings:** added in setting store ([1cd1d3a](https://git.tuffraid.net/cowch/lstV2/commits/1cd1d3a3e9e1ec1bf16ac2552caf24aa299959bf))
* **settings:** more seed settings ([e597968](https://git.tuffraid.net/cowch/lstV2/commits/e597968777e88289d361fdc01ec683a1f4c80192))
* **trycatch:** added in theo's try catch to reduce the code and love it ([72d52d9](https://git.tuffraid.net/cowch/lstV2/commits/72d52d925677eeeac6d158028114201862b6e2a2))
### 🛠️ Code Refactor
* **auth:** added in correct bycrptjs ([208cd61](https://git.tuffraid.net/cowch/lstV2/commits/208cd615af8250686745aa5b6779706ae267e423))
* **auth:** moved prod back to server as we run 2 instances during migration ([7a15b16](https://git.tuffraid.net/cowch/lstV2/commits/7a15b160ac2393cd66a932e598ffaa5aeda5812f))
* **consume materail:** get token from localstorage as the store isnt wokring properly ([354f326](https://git.tuffraid.net/cowch/lstV2/commits/354f3260a55b53bfb461a37db9d64550bacbfe04))
* **frontend:** added date-fns into the frontend ([bba0aa2](https://git.tuffraid.net/cowch/lstV2/commits/bba0aa2ee4e9b9be1db184da894ce6e96fd2e38f))
* **login:** removed all the data from teh login dropdown as it could cause issues ([5dfece0](https://git.tuffraid.net/cowch/lstV2/commits/5dfece09b7285dda96875bbc740df803d816b92a))
* **login:** removed roles from the login to shrink the jwt ([c9aa41a](https://git.tuffraid.net/cowch/lstV2/commits/c9aa41ab0099b7a05d50d9a981cf7e8a42a04733))
* **production:** changes ocp to viewwer ([ab5af4d](https://git.tuffraid.net/cowch/lstV2/commits/ab5af4deacbeaf1ed93c6231fb98b187f7540ca4))
* **server query:** bumped the refresh from 500ms to 2500ms ([866b6d5](https://git.tuffraid.net/cowch/lstV2/commits/866b6d5120810252b089580d341f3fb1b62e951a))
* **serverdata:** remapped the server list to all be on the E drive and deactivated ([8b8c9ac](https://git.tuffraid.net/cowch/lstV2/commits/8b8c9acb6969b63f157ea95b7d61923bf4bb4eae))
* **server:** removed the websocket wrapper going wiht normal ws ([bb6d523](https://git.tuffraid.net/cowch/lstV2/commits/bb6d523abbd3c9423eddbaab96e297b4850e2aa8))
* **settings:** refactored the admincheck so we can reuse it ([ca0ba7f](https://git.tuffraid.net/cowch/lstV2/commits/ca0ba7fe59f7e19d0de4924a419cce461de4b7a1))
* **settings:** removed the need to login to get the settings ([5945ace](https://git.tuffraid.net/cowch/lstV2/commits/5945ace9f259f6ef418c1621c246982b5b572dc1))
* **settings:** used the common response function created ([316b27e](https://git.tuffraid.net/cowch/lstV2/commits/316b27e3e011a0c0b4ce88ea579290807b8927c5))
* **stores:** added in axios ([3b8f180](https://git.tuffraid.net/cowch/lstV2/commits/3b8f18093ead2a988b2b19d1e8f25db6eaeaaee8))
* **view access:** if role [] then allow them to see it ([e17b8e7](https://git.tuffraid.net/cowch/lstV2/commits/e17b8e7bbe94c25c1bd3414b1db31191c87553d6))
### 🐛 Bug fixes
* **auth:** added in the correct function for days between logins ([ed11b2b](https://git.tuffraid.net/cowch/lstV2/commits/ed11b2b26ff80fde9f94615f740eb5152b16744d))
* **auth:** fixed the getaccess to be getuseraccess as it was orignally ([b9dd6e3](https://git.tuffraid.net/cowch/lstV2/commits/b9dd6e3ae2f5c158dd4827ae0c9db2c6747c57e1))
* **calendar:** this component had a bug and needed a lib update ([93ed2e9](https://git.tuffraid.net/cowch/lstV2/commits/93ed2e9ee8c98edd6a8c47d6e7a0caf6a8e93278))
* **consume material:** when we consumed material the button was never reenabled ([07e47e6](https://git.tuffraid.net/cowch/lstV2/commits/07e47e64ae2f4ddd325a2fdb34c82143c9adf84b)), closes [#15](https://git.tuffraid.net/cowch/lstV2/issues/15)
* **frontend:** removed unwanted import ([10d88f5](https://git.tuffraid.net/cowch/lstV2/commits/10d88f53ebaf670c9f6b3ca59cbbaf4d88f26b9f))
* **loginform:** removed the console log that was left by accident ([2ae3c8b](https://git.tuffraid.net/cowch/lstV2/commits/2ae3c8ba5916b5249135b86b374ac1bf32837478))
* **login:** if we have a wrong password or username we didnt properly error instead we crashed ([2e5de34](https://git.tuffraid.net/cowch/lstV2/commits/2e5de34cb50c79cd60e038492b2397eee69def11))
* **scaler:** fix due to update ([edcfff6](https://git.tuffraid.net/cowch/lstV2/commits/edcfff6cc6cf81e56b5532f0876383659b951a5d))
* **serverlist:** corrected the time by removing teh Z at the end of the time ([f940bcd](https://git.tuffraid.net/cowch/lstV2/commits/f940bcdc9df2d3e9989d49feae88036a6f8c7013))
* **sqlserver:** if we already have a connection just return we dont want to try a second time ([b7773ec](https://git.tuffraid.net/cowch/lstV2/commits/b7773ec02aa26c01530723dc146e0c9f4dae41d3))
### 📝 Chore
* **builds:** bummped lstv1 build ([739e6bb](https://git.tuffraid.net/cowch/lstV2/commits/739e6bbe9fa48fae682f9931a2c8bcb763feb636))
* bump build number to 20 ([0975f4e](https://git.tuffraid.net/cowch/lstV2/commits/0975f4e499a8a2aec0662352cb4496299292d4ea))
* bump build number to 21 ([4e885ce](https://git.tuffraid.net/cowch/lstV2/commits/4e885ce74c02ee1fd95a93402d1d32ecf357b1cb))
* bump build number to 22 ([43ca16d](https://git.tuffraid.net/cowch/lstV2/commits/43ca16dc807b9fa3496498e90a871568f0e5f54c))
* bump build number to 23 ([bff0e77](https://git.tuffraid.net/cowch/lstV2/commits/bff0e77766b49c72d77fa55cfaab2d347a1a75dc))
* bump build number to 24 ([f4433f4](https://git.tuffraid.net/cowch/lstV2/commits/f4433f41926dab72a239fc585ddd1e14acb80c7e))
* bump build number to 25 ([f1979f0](https://git.tuffraid.net/cowch/lstV2/commits/f1979f0fc914f3b94bad1816cd405a6431d1ba4a))
* bump build number to 26 ([491de26](https://git.tuffraid.net/cowch/lstV2/commits/491de26a0bbe6dfca9e1cb068991789c29a09ac0))
* bump build number to 27 ([26ea8d5](https://git.tuffraid.net/cowch/lstV2/commits/26ea8d5e89bb1b44ceb6b205da3ad158c603fca0))
* bump build number to 28 ([1e02d4f](https://git.tuffraid.net/cowch/lstV2/commits/1e02d4fa4fc1a007634da49fe2697d63c89cba18))
* bump build number to 29 ([9796947](https://git.tuffraid.net/cowch/lstV2/commits/9796947db5443c8b5678d7502037458d680e4018))
* bump build number to 30 ([4a48dd2](https://git.tuffraid.net/cowch/lstV2/commits/4a48dd2bb57064953ef6e192c76b91bb844a24de))
* bump build number to 31 ([227e2aa](https://git.tuffraid.net/cowch/lstV2/commits/227e2aa00c2a3e5526e0347c76676de345dfea5d))
* bump build number to 32 ([f035e6f](https://git.tuffraid.net/cowch/lstV2/commits/f035e6f14a9e2123a10010d4f515f78f0c222599))
* bump build number to 33 ([03aa7e5](https://git.tuffraid.net/cowch/lstV2/commits/03aa7e5aeee39b1b390b4da2019f44459487e0a0))
* bump build number to 34 ([f4c44fb](https://git.tuffraid.net/cowch/lstV2/commits/f4c44fb02ba857890af66a2747381ef1c3def25b))
* bump build number to 35 ([8b72a1b](https://git.tuffraid.net/cowch/lstV2/commits/8b72a1b47e715f4146e586e9fdd6abcabd97743d))
* bump build number to 36 ([8a143fb](https://git.tuffraid.net/cowch/lstV2/commits/8a143fbb19d2270b0139a7a4edbce745c477b6b1))
* bump build number to 37 ([b0634d9](https://git.tuffraid.net/cowch/lstV2/commits/b0634d9427f6fff3a239680204b5e6daf6163e37))
* bump build number to 38 ([751b9d5](https://git.tuffraid.net/cowch/lstV2/commits/751b9d5701cf7e81641f154a02041869e1b80c49))
* bump build number to 39 ([6dd5f4b](https://git.tuffraid.net/cowch/lstV2/commits/6dd5f4b61f3a27779980cf14915c4394256eae20))
* bump build number to 40 ([d98a659](https://git.tuffraid.net/cowch/lstV2/commits/d98a6592628f36c654039ccea25db163ddf15e8c))
* bump build number to 41 ([807a4ca](https://git.tuffraid.net/cowch/lstV2/commits/807a4ca6993b5dfa82a45aaf44a2d661c3e03428))
* bump build number to 42 ([196ea00](https://git.tuffraid.net/cowch/lstV2/commits/196ea009720a65c520f5626658ac7885a41796cb))
* bump build number to 43 ([34b80cf](https://git.tuffraid.net/cowch/lstV2/commits/34b80cf2368228b70cd6a79d44ba0f95b5c5941a))
* bump build number to 44 ([808e3d8](https://git.tuffraid.net/cowch/lstV2/commits/808e3d84efa0889077a12cbf8e28df794a51f2bc))
* bump build number to 45 ([38d1043](https://git.tuffraid.net/cowch/lstV2/commits/38d10436069d3db1612a622d9b9e0c7aec04f6dd))
* bump build number to 46 ([532a722](https://git.tuffraid.net/cowch/lstV2/commits/532a7227631cf67664ca41133330d8cfa59f429b))
* bump build number to 47 ([f665406](https://git.tuffraid.net/cowch/lstV2/commits/f6654067f5f01c3ee4855f0cbe07593f13263ce7))
* bump build number to 48 ([97b9c4d](https://git.tuffraid.net/cowch/lstV2/commits/97b9c4db4a67faf68edae4dc1217b28f87d003e8))
* bump build number to 49 ([acb9876](https://git.tuffraid.net/cowch/lstV2/commits/acb9876d9b715894481d31d9bb104e54561710d0))
* **pkg updates:** updated all pkgs ([fb9ee15](https://git.tuffraid.net/cowch/lstV2/commits/fb9ee15bda89257815012023ed5543ef55b5f379))
* **updatescript:** added in so we can do a full install with an env creation for old ([cb3ab66](https://git.tuffraid.net/cowch/lstV2/commits/cb3ab668d866ea9e3428e548d9065a9681174e82))
## [2.8.0](https://git.tuffraid.net/cowch/lstV2/compare/v2.7.0...v2.8.0) (2025-03-16) ## [2.8.0](https://git.tuffraid.net/cowch/lstV2/compare/v2.7.0...v2.8.0) (2025-03-16)

View File

@@ -0,0 +1,2 @@
DROP TABLE "apiHits" CASCADE;--> statement-breakpoint
DROP TABLE "eom" CASCADE;

File diff suppressed because it is too large Load Diff

View File

@@ -176,6 +176,13 @@
"when": 1742408812383, "when": 1742408812383,
"tag": "0024_curved_venom", "tag": "0024_curved_venom",
"breakpoints": true "breakpoints": true
},
{
"idx": 25,
"version": "7",
"when": 1742655504936,
"tag": "0025_amusing_sugar_man",
"breakpoints": true
} }
] ]
} }

File diff suppressed because it is too large Load Diff

View File

@@ -12,7 +12,7 @@
"checkupdates": "npm-check-updates" "checkupdates": "npm-check-updates"
}, },
"dependencies": { "dependencies": {
"@hookform/resolvers": "^4.1.2", "@hookform/resolvers": "^4.1.3",
"@radix-ui/react-avatar": "^1.1.3", "@radix-ui/react-avatar": "^1.1.3",
"@radix-ui/react-checkbox": "^1.1.4", "@radix-ui/react-checkbox": "^1.1.4",
"@radix-ui/react-collapsible": "^1.1.3", "@radix-ui/react-collapsible": "^1.1.3",
@@ -25,46 +25,47 @@
"@radix-ui/react-slot": "^1.1.2", "@radix-ui/react-slot": "^1.1.2",
"@radix-ui/react-tabs": "^1.1.3", "@radix-ui/react-tabs": "^1.1.3",
"@radix-ui/react-tooltip": "^1.1.8", "@radix-ui/react-tooltip": "^1.1.8",
"@tailwindcss/vite": "^4.0.9", "@tailwindcss/vite": "^4.0.15",
"@tanstack/react-query": "^5.66.9", "@tanstack/react-query": "^5.69.0",
"@tanstack/react-router": "^1.111.11", "@tanstack/react-router": "^1.114.27",
"@tanstack/react-table": "^8.21.2", "@tanstack/react-table": "^8.21.2",
"class-variance-authority": "^0.7.1", "class-variance-authority": "^0.7.1",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"date-fns": "^4.1.0", "date-fns": "^4.1.0",
"date-fns-tz": "^3.2.0",
"dotenv": "^16.4.7", "dotenv": "^16.4.7",
"hono": "^4.7.2", "hono": "^4.7.5",
"js-cookie": "^3.0.5", "js-cookie": "^3.0.5",
"jsonwebtoken": "^9.0.2", "jsonwebtoken": "^9.0.2",
"lucide-react": "^0.476.0", "lucide-react": "^0.483.0",
"next-themes": "^0.4.4", "next-themes": "^0.4.6",
"npm-check-updates": "^17.1.15", "npm-check-updates": "^17.1.16",
"react": "^19.0.0", "react": "^19.0.0",
"react-day-picker": "^8.10.1", "react-day-picker": "^8.10.1",
"react-dom": "^19.0.0", "react-dom": "^19.0.0",
"react-grid-layout": "^1.5.0", "react-grid-layout": "^1.5.1",
"react-hook-form": "^7.54.2", "react-hook-form": "^7.54.2",
"sonner": "^2.0.1", "sonner": "^2.0.1",
"tailwind-merge": "^3.0.2", "tailwind-merge": "^3.0.2",
"tailwindcss": "^4.0.9", "tailwindcss": "^4.0.15",
"tailwindcss-animate": "^1.0.7", "tailwindcss-animate": "^1.0.7",
"zod": "^3.24.2", "zod": "^3.24.2",
"zustand": "^5.0.3" "zustand": "^5.0.3"
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "^9.21.0", "@eslint/js": "^9.23.0",
"@tanstack/router-devtools": "^1.106.0", "@tanstack/router-devtools": "^1.114.27",
"@tanstack/router-plugin": "^1.106.0", "@tanstack/router-plugin": "^1.114.27",
"@types/react": "^19.0.10", "@types/react": "^19.0.12",
"@types/react-dom": "^19.0.4", "@types/react-dom": "^19.0.4",
"@types/react-grid-layout": "^1.3.5", "@types/react-grid-layout": "^1.3.5",
"@vitejs/plugin-react-swc": "^3.8.0", "@vitejs/plugin-react-swc": "^3.8.1",
"eslint": "^9.21.0", "eslint": "^9.23.0",
"eslint-plugin-react-hooks": "^5.0.0", "eslint-plugin-react-hooks": "^5.2.0",
"eslint-plugin-react-refresh": "^0.4.19", "eslint-plugin-react-refresh": "^0.4.19",
"globals": "^15.15.0", "globals": "^16.0.0",
"typescript": "~5.7.2", "typescript": "~5.8.2",
"typescript-eslint": "^8.24.1", "typescript-eslint": "^8.27.0",
"vite": "^6.2.0" "vite": "^6.2.2"
} }
} }

View File

@@ -0,0 +1,22 @@
import {Button} from "@/components/ui/button";
import {Tooltip, TooltipContent, TooltipProvider, TooltipTrigger} from "@/components/ui/tooltip";
import {RotateCcw} from "lucide-react";
export default function RestartServer() {
return (
<div>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button variant={"outline"} size={"icon"}>
<RotateCcw />
</Button>
</TooltipTrigger>
<TooltipContent>
<p>Restart Server ... Needs added still</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</div>
);
}

View File

@@ -1,98 +1,125 @@
import {LstCard} from "@/components/extendedUI/LstCard"; import { LstCard } from "@/components/extendedUI/LstCard";
import { Skeleton } from "@/components/ui/skeleton";
import {Skeleton} from "@/components/ui/skeleton"; import {
import {Table, TableBody, TableCell, TableHead, TableHeader, TableRow} from "@/components/ui/table"; Table,
import {useSessionStore} from "@/lib/store/sessionStore"; TableBody,
import {useModuleStore} from "@/lib/store/useModuleStore"; TableCell,
import {getServers} from "@/utils/querys/servers"; TableHead,
import {useQuery} from "@tanstack/react-query"; TableHeader,
import {useRouter} from "@tanstack/react-router"; TableRow,
import {format} from "date-fns"; } from "@/components/ui/table";
import { useSessionStore } from "@/lib/store/sessionStore";
import { useModuleStore } from "@/lib/store/useModuleStore";
import { getServers } from "@/utils/querys/servers";
import { useQuery } from "@tanstack/react-query";
import { useRouter } from "@tanstack/react-router";
import { format } from "date-fns";
import UpdateServer from "./UpdateServer"; import UpdateServer from "./UpdateServer";
import {adminUrlCheck} from "@/utils/adminUrlCheck"; import { adminUrlCheck } from "@/utils/adminUrlCheck";
import RestartServer from "./RestartServer";
import StopServer from "./StopServer";
import StartServer from "./StartServer";
export type Servers = { export type Servers = {
server_id?: string; server_id?: string;
sName?: string; sName?: string;
serverDNS?: string; serverDNS?: string;
plantToken?: string; plantToken?: string;
idAddress: string; idAddress: string;
lastUpdated: string; lastUpdated: string;
isUpgrading: boolean; isUpgrading: boolean;
}; };
export default function ServerPage() { export default function ServerPage() {
const {user, token} = useSessionStore(); const { user, token } = useSessionStore();
const {modules} = useModuleStore(); const { modules } = useModuleStore();
const router = useRouter(); const router = useRouter();
const {data, isError, error, isLoading} = useQuery(getServers(token ?? "")); const { data, isError, error, isLoading } = useQuery(getServers(token ?? ""));
const adminModule = modules.filter((n) => n.name === "admin"); const adminModule = modules.filter((n) => n.name === "admin");
const userLevel = user?.roles?.filter((r) => r.module_id === adminModule[0].module_id) || []; const userLevel =
user?.roles?.filter((r) => r.module_id === adminModule[0].module_id) || [];
if (!adminModule[0]?.roles?.includes(userLevel[0]?.role)) { if (!adminModule[0]?.roles?.includes(userLevel[0]?.role)) {
router.navigate({to: "/"}); router.navigate({ to: "/" });
} }
if (isError) { if (isError) {
return <div>{JSON.stringify(error)}</div>; return <div>{JSON.stringify(error)}</div>;
} }
return (
<LstCard className="m-2 flex place-content-center w-dvh"> console.log(data);
<Table> return (
<TableHeader> <LstCard className="m-2 flex place-content-center w-dvh">
<TableRow> <Table>
<TableHead>Name</TableHead> <TableHeader>
<TableHead>Server</TableHead> <TableRow>
<TableHead>PlantToken</TableHead> <TableHead>Name</TableHead>
<TableHead>IP Address</TableHead> <TableHead>Server</TableHead>
<TableHead>Date Last updated</TableHead> <TableHead>PlantToken</TableHead>
<TableHead>Update Server</TableHead> <TableHead>IP Address</TableHead>
</TableRow> <TableHead>Date Last updated</TableHead>
</TableHeader> <TableHead>Update Server</TableHead>
{isLoading ? ( </TableRow>
<> </TableHeader>
<TableBody> {isLoading ? (
{Array(10) <>
.fill(0) <TableBody>
.map((_, i) => ( {Array(10)
<TableRow key={i}> .fill(0)
<TableCell className="font-medium"> .map((_, i) => (
<Skeleton className="h-4" /> <TableRow key={i}>
</TableCell> <TableCell className="font-medium">
<TableCell> <Skeleton className="h-4" />
<Skeleton className="h-4" /> </TableCell>
</TableCell> <TableCell>
<TableCell> <Skeleton className="h-4" />
<Skeleton className="h-4" /> </TableCell>
</TableCell> <TableCell>
<TableCell> <Skeleton className="h-4" />
<Skeleton className="h-4" /> </TableCell>
</TableCell> <TableCell>
</TableRow> <Skeleton className="h-4" />
))} </TableCell>
</TableBody> </TableRow>
</> ))}
) : ( </TableBody>
<TableBody> </>
{data?.map((server: Servers) => ( ) : (
<TableRow key={server.server_id}> <TableBody>
<TableCell className="font-medium">{server.sName}</TableCell> {data?.map((server: Servers) => {
<TableCell className="font-medium">{server.serverDNS}</TableCell> const strippedDate = server.lastUpdated.replace("Z", ""); // Remove Z
<TableCell className="font-medium">{server.plantToken}</TableCell> const formattedDate = format(strippedDate, "MM/dd/yyyy hh:mm a");
<TableCell className="font-medium">{server.idAddress}</TableCell> return (
<TableCell className="font-medium"> <TableRow key={server.server_id}>
{format(server.lastUpdated, "MM/dd/yyyy hh:mm")} <TableCell className="font-medium">{server.sName}</TableCell>
</TableCell> <TableCell className="font-medium">
<TableCell className="font-medium"> {server.serverDNS}
{adminUrlCheck() && <UpdateServer server={server} token={token as string} />} </TableCell>
</TableCell> <TableCell className="font-medium">
</TableRow> {server.plantToken}
))} </TableCell>
</TableBody> <TableCell className="font-medium">
)} {server.idAddress}
</Table> </TableCell>
</LstCard> <TableCell className="font-medium">{formattedDate}</TableCell>
); <TableCell className="font-medium">
{adminUrlCheck() && (
<div className="flex flex-row">
<UpdateServer server={server} token={token as string} />
<StartServer />
<StopServer />
<RestartServer />
</div>
)}
</TableCell>
</TableRow>
);
})}
</TableBody>
)}
</Table>
</LstCard>
);
} }

View File

@@ -0,0 +1,22 @@
import {Button} from "@/components/ui/button";
import {Tooltip, TooltipContent, TooltipProvider, TooltipTrigger} from "@/components/ui/tooltip";
import {Play} from "lucide-react";
export default function StartServer() {
return (
<div>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button variant={"outline"} size={"icon"}>
<Play />
</Button>
</TooltipTrigger>
<TooltipContent>
<p>Start Server ... Needs added still</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</div>
);
}

View File

@@ -0,0 +1,22 @@
import {Button} from "@/components/ui/button";
import {Tooltip, TooltipContent, TooltipProvider, TooltipTrigger} from "@/components/ui/tooltip";
import {Octagon} from "lucide-react";
export default function StopServer() {
return (
<div>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button variant={"outline"} size={"icon"}>
<Octagon />
</Button>
</TooltipTrigger>
<TooltipContent>
<p>Stop Server ... Needs added still</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</div>
);
}

View File

@@ -5,6 +5,7 @@ import {Servers} from "./ServerPage";
import {useQuery} from "@tanstack/react-query"; import {useQuery} from "@tanstack/react-query";
import {getSettings} from "@/utils/querys/settings"; import {getSettings} from "@/utils/querys/settings";
import axios from "axios"; import axios from "axios";
import {Tooltip, TooltipContent, TooltipProvider, TooltipTrigger} from "@/components/ui/tooltip";
export default function UpdateServer({server, token}: {server: Servers; token: string}) { export default function UpdateServer({server, token}: {server: Servers; token: string}) {
const {data} = useQuery(getSettings(token ?? "")); const {data} = useQuery(getSettings(token ?? ""));
@@ -33,9 +34,18 @@ export default function UpdateServer({server, token}: {server: Servers; token: s
}; };
return ( return (
<div> <div>
<Button variant={"outline"} size={"icon"} onClick={upgrade} disabled={server.isUpgrading}> <TooltipProvider>
<CircleFadingArrowUp /> <Tooltip>
</Button> <TooltipTrigger asChild>
<Button variant={"outline"} size={"icon"} onClick={upgrade} disabled={server.isUpgrading}>
<CircleFadingArrowUp />
</Button>
</TooltipTrigger>
<TooltipContent>
<p>Update {server.sName}</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</div> </div>
); );
} }

View File

@@ -1,145 +1,164 @@
import {useSessionStore} from "../../lib/store/sessionStore"; import { useSessionStore } from "../../lib/store/sessionStore";
import {LstCard} from "../extendedUI/LstCard"; import { LstCard } from "../extendedUI/LstCard";
import {CardHeader} from "../ui/card"; import { CardHeader } from "../ui/card";
import {toast} from "sonner"; import { toast } from "sonner";
import {z} from "zod"; import { z } from "zod";
import {useRouter} from "@tanstack/react-router"; import { useRouter } from "@tanstack/react-router";
import {Controller, useForm} from "react-hook-form"; import { Controller, useForm } from "react-hook-form";
import {zodResolver} from "@hookform/resolvers/zod"; import { zodResolver } from "@hookform/resolvers/zod";
import {Label} from "../ui/label"; import { Label } from "../ui/label";
import {Input} from "../ui/input"; import { Input } from "../ui/input";
import {Checkbox} from "../ui/checkbox"; import { Checkbox } from "../ui/checkbox";
import {Button} from "../ui/button"; import { Button } from "../ui/button";
const FormSchema = z.object({ const FormSchema = z.object({
username: z.string().min(1, "You must enter a valid username"), username: z.string().min(1, "You must enter a valid username"),
password: z.string().min(4, "You must enter a valid password"), password: z.string().min(4, "You must enter a valid password"),
rememberMe: z.boolean(), rememberMe: z.boolean(),
}); });
const LoginForm = () => { const LoginForm = () => {
const {setSession} = useSessionStore(); const { setSession } = useSessionStore();
const rememeberMe = localStorage.getItem("rememberMe") === "true"; const rememeberMe = localStorage.getItem("rememberMe") === "true";
const username = localStorage.getItem("username") || ""; const username = localStorage.getItem("username") || "";
const router = useRouter(); const router = useRouter();
const { const {
register, register,
handleSubmit, handleSubmit,
control, control,
formState: {errors}, formState: { errors },
} = useForm<z.infer<typeof FormSchema>>({ } = useForm<z.infer<typeof FormSchema>>({
resolver: zodResolver(FormSchema), resolver: zodResolver(FormSchema),
defaultValues: { defaultValues: {
username: username || "", username: username || "",
password: "", password: "",
rememberMe: rememeberMe, rememberMe: rememeberMe,
},
});
const onSubmitLogin = async (value: z.infer<typeof FormSchema>) => {
// Do something with form data
// first update the rememberMe incase it was selected
if (value.rememberMe) {
localStorage.setItem("rememberMe", value.rememberMe.toString());
localStorage.setItem("username", value.username);
} else {
localStorage.removeItem("rememberMe");
localStorage.removeItem("username");
}
try {
const response = await fetch("/api/auth/login", {
method: "POST",
headers: {
"Content-Type": "application/json",
}, },
}); body: JSON.stringify({
username: value.username,
password: value.password,
}),
});
const onSubmitLogin = async (value: z.infer<typeof FormSchema>) => { const data = await response.json();
// Do something with form data
// first update the rememberMe incase it was selected // Store token in localStorage
if (value.rememberMe) { // localStorage.setItem("auth_token", data.data.token);
localStorage.setItem("rememberMe", value.rememberMe.toString()); if (data.success) {
localStorage.setItem("username", value.username); const prod = btoa(`${value.username.toLowerCase()}:${value.password}`);
} else { const prodUser = { ...data.user, prod: prod };
localStorage.removeItem("rememberMe");
localStorage.removeItem("username");
}
try { setSession(prodUser, data.token);
const response = await fetch("/api/auth/login", { toast.success(`You are logged in as ${data.user.username}`);
method: "POST", router.navigate({ to: "/" });
headers: { }
"Content-Type": "application/json",
},
body: JSON.stringify({username: value.username, password: value.password}),
});
const data = await response.json(); if (!data.success) {
toast.error(`${data.message}`);
}
// Store token in localStorage //console.log(data);
// localStorage.setItem("auth_token", data.data.token); } catch (err) {
const prod = btoa(`${value.username.toLowerCase()}:${value.password}`); toast.error("Invalid credentials");
const prodUser = {...data.user, prod: prod}; }
};
setSession(prodUser, data.token); return (
toast.success(`You are logged in as ${data.user.username}`); <div className="ml-[25%]">
router.navigate({to: "/"}); <LstCard className="p-3 w-96">
} catch (err) { <CardHeader>
toast.error("Invalid credentials"); <div>
} <p className="text-2xl">Login to LST</p>
}; </div>
</CardHeader>
<hr className="rounded"></hr>
<form onSubmit={handleSubmit(onSubmitLogin)}>
<div>
<Label htmlFor="username" className="m-1">
Username
</Label>
<Input
placeholder="smith001"
{...register("username")}
className={errors.username ? "border-red-500" : ""}
aria-invalid={!!errors.username}
/>
{errors.username && (
<p className="text-red-500 text-sm mt-1">
{errors.username.message}
</p>
)}
</div>
<div>
<>
<Label htmlFor={"password"} className="m-1">
Password
</Label>
<Input
type="password"
{...register("password")}
className={errors.password ? "border-red-500" : ""}
aria-invalid={!!errors.password}
/>
{errors.password && (
<p className="text-red-500 text-sm mt-1">
{errors.password.message}
</p>
)}
</>
</div>
<div className="flex justify-between pt-2">
<div className="flex">
<Controller
render={({ field }) => (
<>
<Checkbox
id="remember"
checked={field.value}
onCheckedChange={field.onChange}
/>
<label
htmlFor="remember"
className="pl-2 text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
>
remember me
</label>
</>
)}
control={control}
name="rememberMe"
defaultValue={rememeberMe}
/>
</div>
return ( <div className="flex justify-end">
<div className="ml-[25%]"> <Button type="submit">Submit</Button>
<LstCard className="p-3 w-96"> </div>
<CardHeader> </div>
<div> </form>
<p className="text-2xl">Login to LST</p> </LstCard>
</div> </div>
</CardHeader> );
<hr className="rounded"></hr>
<form onSubmit={handleSubmit(onSubmitLogin)}>
<div>
<Label htmlFor="username" className="m-1">
Username
</Label>
<Input
placeholder="smith001"
{...register("username")}
className={errors.username ? "border-red-500" : ""}
aria-invalid={!!errors.username}
/>
{errors.username && <p className="text-red-500 text-sm mt-1">{errors.username.message}</p>}
</div>
<div>
<>
<Label htmlFor={"password"} className="m-1">
Password
</Label>
<Input
type="password"
{...register("password")}
className={errors.password ? "border-red-500" : ""}
aria-invalid={!!errors.password}
/>
{errors.password && <p className="text-red-500 text-sm mt-1">{errors.password.message}</p>}
</>
</div>
<div className="flex justify-between pt-2">
<div className="flex">
<Controller
render={({field}) => (
<>
<Checkbox
id="remember"
checked={field.value}
onCheckedChange={field.onChange}
/>
<label
htmlFor="remember"
className="pl-2 text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
>
remember me
</label>
</>
)}
control={control}
name="rememberMe"
defaultValue={rememeberMe}
/>
</div>
<div className="flex justify-end">
<Button type="submit">Submit</Button>
</div>
</div>
</form>
</LstCard>
</div>
);
}; };
export default LoginForm; export default LoginForm;

View File

@@ -16,24 +16,25 @@ export default function ConsumeMaterial() {
const {token} = useSessionStore(); const {token} = useSessionStore();
const handleConsume = async (data: any) => { const handleConsume = async (data: any) => {
setSubmitting(!submitting); setSubmitting(true);
try { try {
const result = await axios.post(`/api/logistics/consume`, data, { const result = await axios.post(`/api/logistics/consume`, data, {
headers: {Authorization: `Bearer ${token}`}, headers: {Authorization: `Bearer ${token}`},
}); });
if (result.data.success) { if (result.data.success) {
toast.success(result.data.message); toast.success(result.data.message);
setSubmitting(!submitting); setSubmitting(false);
reset(); reset();
} }
if (!result.data.success) { if (!result.data.success) {
//console.log(result.data); //console.log(result.data);
setSubmitting(!submitting); setSubmitting(false);
toast.error(result.data.message); toast.error(result.data.message);
} }
} catch (error: any) { } catch (error: any) {
//console.log(error); //console.log(error);
setSubmitting(!submitting); setSubmitting(false);
if (error.status === 401) { if (error.status === 401) {
toast.error("Unauthorized to do this task."); toast.error("Unauthorized to do this task.");
} else { } else {

View File

@@ -1,46 +1,71 @@
//import {useEffect, useState} from "react"; /**
import {LstCard} from "../extendedUI/LstCard"; * we will do a very sloppy way for this just keep fetching the logs we spent to much time on this :()
import {CardContent, CardHeader} from "../ui/card"; */
import {Skeleton} from "../ui/skeleton";
import {Button} from "../ui/button";
import {toast} from "sonner";
export default function CycleCountLog() { // //import {useEffect, useState} from "react";
//const [logs, setLogs] = useState([]); // import {LstCard} from "../extendedUI/LstCard";
//const [streaming, setStreaming] = useState(false); // Track if streaming is active // import {CardContent, CardHeader} from "../ui/card";
// import {Skeleton} from "../ui/skeleton";
// import {Button} from "../ui/button";
// import {toast} from "sonner";
// import {useEffect} from "react";
// useEffect(() => { // export default function CycleCountLog() {
// // Start streaming when the button is clicked // //const [logs, setLogs] = useState([]);
// let es; // //const [streaming, setStreaming] = useState(false); // Track if streaming is active
// es = new EventSource("http://localhost:4000/api/logger/logs/stream?service=ocme-count&level=info"); // useEffect(() => {
// es.onopen = () => console.log(">>> Connection opened!"); // // Start streaming when the button is clicked
// es.onerror = (e) => console.log("ERROR!", e); // let es;
// es.onmessage = (e) => {
// console.log(">>>", JSON.stringify(e));
// };
// return () => es.close(); // const url = `http://localhost:4000/api/logger/logs/stream?service=ocme-count&level=info`;
// }, []); // Effect runs when `streaming` state changes
// const handleStartStreaming = () => { // es = new EventSource(url);
// setStreaming(true); // Start streaming when button is clicked // es.onopen = () => console.log(">>> Connection opened!");
// }; // es.onerror = (e) => console.log("ERROR!", e);
return ( // es.onmessage = (e) => {
<LstCard className="w-48"> // const data = JSON.parse(e.data);
<CardHeader className="flex justify-center">
<span>Cycle Count logs</span> // console.log(e);
</CardHeader> // console.log(data);
<CardContent> // switch (data.type) {
{Array(10) // case "time-update":
.fill(0) // console.log(data);
.map((_, i) => ( // break;
<div key={i}> // case "error":
<Skeleton className="m-2 h-4" /> // console.log(data);
</div> // break;
))} // case "done":
</CardContent> // console.log(data);
<Button onClick={() => toast.success("SOmething")}>Start Stream</Button> // es.close(); // Close the connection when done
</LstCard>
); // break;
} // default:
// break;
// }
// };
// return () => es.close();
// }, []);
// // const handleStartStreaming = () => {
// // setStreaming(true); // Start streaming when button is clicked
// // };
// return (
// <LstCard className="w-48">
// <CardHeader className="flex justify-center">
// <span>Cycle Count logs</span>
// </CardHeader>
// <CardContent>
// {Array(10)
// .fill(0)
// .map((_, i) => (
// <div key={i}>
// <Skeleton className="m-2 h-4" />
// </div>
// ))}
// </CardContent>
// <Button onClick={() => toast.success("SOmething")}>Start Stream</Button>
// </LstCard>
// );
// }

View File

@@ -5,19 +5,20 @@ import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@/lib/utils" import { cn } from "@/lib/utils"
const buttonVariants = cva( const buttonVariants = cva(
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-[color,box-shadow] disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
{ {
variants: { variants: {
variant: { variant: {
default: default:
"bg-primary text-primary-foreground shadow-xs hover:bg-primary/90", "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
destructive: destructive:
"bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40", "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
outline: outline:
"border border-input bg-background shadow-xs hover:bg-accent hover:text-accent-foreground", "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
secondary: secondary:
"bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80", "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
ghost: "hover:bg-accent hover:text-accent-foreground", ghost:
"hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
link: "text-primary underline-offset-4 hover:underline", link: "text-primary underline-offset-4 hover:underline",
}, },
size: { size: {

View File

@@ -44,7 +44,7 @@ function TooltipContent({
data-slot="tooltip-content" data-slot="tooltip-content"
sideOffset={sideOffset} sideOffset={sideOffset}
className={cn( className={cn(
"bg-primary text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit rounded-md px-3 py-1.5 text-xs text-balance", "bg-primary text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance",
className className
)} )}
{...props} {...props}

View File

@@ -1,91 +1,94 @@
import {createRootRoute, Link, Outlet} from "@tanstack/react-router"; import { createRootRoute, Link, Outlet } from "@tanstack/react-router";
//import {TanStackRouterDevtools} from "@tanstack/router-devtools"; //import {TanStackRouterDevtools} from "@tanstack/router-devtools";
import Cookies from "js-cookie"; import Cookies from "js-cookie";
import {SidebarProvider} from "../components/ui/sidebar"; import { SidebarProvider } from "../components/ui/sidebar";
import {ThemeProvider} from "../components/layout/theme-provider"; import { ThemeProvider } from "../components/layout/theme-provider";
import {ModeToggle} from "../components/layout/mode-toggle"; import { ModeToggle } from "../components/layout/mode-toggle";
import {AppSidebar} from "../components/layout/lst-sidebar"; import { AppSidebar } from "../components/layout/lst-sidebar";
import {Avatar, AvatarFallback, AvatarImage} from "../components/ui/avatar"; import { Avatar, AvatarFallback, AvatarImage } from "../components/ui/avatar";
import { import {
DropdownMenu, DropdownMenu,
DropdownMenuContent, DropdownMenuContent,
DropdownMenuItem, DropdownMenuItem,
DropdownMenuLabel, DropdownMenuLabel,
DropdownMenuSeparator, DropdownMenuSeparator,
DropdownMenuTrigger, DropdownMenuTrigger,
} from "../components/ui/dropdown-menu"; } from "../components/ui/dropdown-menu";
import {SessionProvider} from "../components/providers/Providers"; import { SessionProvider } from "../components/providers/Providers";
import {Toaster} from "sonner"; import { Toaster } from "sonner";
import {Button} from "../components/ui/button"; //import { Button } from "../components/ui/button";
import {useSessionStore} from "../lib/store/sessionStore"; import { useSessionStore } from "../lib/store/sessionStore";
import {useSession} from "@/hooks/useSession"; import { useSession } from "@/hooks/useSession";
import {useLogout} from "@/hooks/useLogout"; import { useLogout } from "@/hooks/useLogout";
// same as the layout // same as the layout
export const Route = createRootRoute({ export const Route = createRootRoute({
component: () => { component: () => {
const sidebarState = Cookies.get("sidebar_state") === "true"; const sidebarState = Cookies.get("sidebar_state") === "true";
const {session} = useSession(); const { session } = useSession();
const {user} = useSessionStore(); const { user } = useSessionStore();
const logout = useLogout(); const logout = useLogout();
return ( return (
<> <>
<SessionProvider> <SessionProvider>
<ThemeProvider> <ThemeProvider>
<nav className="flex justify-end"> <nav className="flex justify-end">
<div className="m-2 flex flex-row"> <div className="m-2 flex flex-row">
<div className="m-auto pr-2"> <div className="m-auto pr-2">
<p>Add Card</p> <p>Add Card</p>
</div> </div>
<div className="m-1"> <div className="m-1">
<ModeToggle /> <ModeToggle />
</div> </div>
{session ? ( {session ? (
<div className="m-1"> <div className="m-1">
<DropdownMenu> <DropdownMenu>
<DropdownMenuTrigger> <DropdownMenuTrigger>
<Avatar> <Avatar>
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" /> <AvatarImage
<AvatarFallback>CN</AvatarFallback> src="https://github.com/shadcn.png"
</Avatar> alt="@shadcn"
</DropdownMenuTrigger> />
<DropdownMenuContent> <AvatarFallback>CN</AvatarFallback>
<DropdownMenuLabel>Hello {user?.username}</DropdownMenuLabel> </Avatar>
<DropdownMenuSeparator /> </DropdownMenuTrigger>
<DropdownMenuItem>Profile</DropdownMenuItem> <DropdownMenuContent>
<DropdownMenuLabel>
Hello {user?.username}
</DropdownMenuLabel>
<DropdownMenuSeparator />
{/* <DropdownMenuItem>Profile</DropdownMenuItem>
<DropdownMenuItem>Billing</DropdownMenuItem> <DropdownMenuItem>Billing</DropdownMenuItem>
<DropdownMenuItem>Team</DropdownMenuItem> <DropdownMenuItem>Team</DropdownMenuItem>
<DropdownMenuItem>Subscription</DropdownMenuItem> <DropdownMenuItem>Subscription</DropdownMenuItem> */}
<hr className="solid"></hr> <hr className="solid"></hr>
<DropdownMenuItem> <DropdownMenuItem>
<div className="m-auto mt-3"> <div className="m-auto">
<Button onClick={() => logout()} variant="ghost"> <button onClick={() => logout()}>Logout</button>
Logout </div>
</Button> </DropdownMenuItem>
</div> </DropdownMenuContent>
</DropdownMenuItem> </DropdownMenu>
</DropdownMenuContent> </div>
</DropdownMenu> ) : (
</div> <div>
) : ( <Link to="/login">Login</Link>
<> </div>
<Link to="/login">Login</Link> )}
</> </div>
)} </nav>
</div> <SidebarProvider defaultOpen={sidebarState}>
</nav> <AppSidebar />
<SidebarProvider defaultOpen={sidebarState}> <Toaster expand={true} richColors closeButton />
<AppSidebar /> <Outlet />
<Toaster expand={true} richColors closeButton /> </SidebarProvider>
<Outlet /> </ThemeProvider>
</SidebarProvider> </SessionProvider>
</ThemeProvider>
</SessionProvider>
{/* <TanStackRouterDevtools position="bottom-right" /> */} {/* <TanStackRouterDevtools position="bottom-right" /> */}
</> </>
); );
}, },
}); });

View File

@@ -18,8 +18,16 @@ export default defineConfig({
}, },
server: { server: {
proxy: { proxy: {
"/api": {target: `http://localhost:${Number(process.env.VITE_SERVER_PORT || 4400)}`, changeOrigin: true}, "/api": {
"/ocme": {target: `http://localhost:${Number(process.env.VITE_SERVER_PORT || 4400)}`, changeOrigin: true}, target: `http://localhost:${Number(process.env.VITE_SERVER_PORT || 4400)}`,
changeOrigin: true,
secure: false,
},
"/ocme": {
target: `http://localhost:${Number(process.env.VITE_SERVER_PORT || 4400)}`,
changeOrigin: true,
secure: false,
},
}, },
}, },
}); });

6243
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{ {
"name": "lstv2", "name": "lstv2",
"version": "2.8.0", "version": "2.9.0",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "concurrently -n \"server,frontend\" -c \"#007755,#2f6da3\" \"npm run dev:server\" \"cd frontend && npm run dev\"", "dev": "concurrently -n \"server,frontend\" -c \"#007755,#2f6da3\" \"npm run dev:server\" \"cd frontend && npm run dev\"",
@@ -9,8 +9,10 @@
"dev:dbgen": " drizzle-kit generate --config=drizzle-dev.config.ts", "dev:dbgen": " drizzle-kit generate --config=drizzle-dev.config.ts",
"dev:dbmigrate": " drizzle-kit migrate --config=drizzle-dev.config.ts", "dev:dbmigrate": " drizzle-kit migrate --config=drizzle-dev.config.ts",
"build": "npm run build:server && npm run build:frontend", "build": "npm run build:server && npm run build:frontend",
"build:server": "rimraf build && tsc --build && xcopy server\\scripts dist\\server\\scripts /E /I /Y && xcopy server\\services\\server\\utils\\serverData.json dist\\server\\services\\server\\utils /E /I /Y ", "build:server": "rimraf dist && tsc --build && npm run copy:scripts",
"build:frontend": "cd frontend && npm run build", "build:frontend": "cd frontend && npm run build",
"copy:scripts": "tsx server/scripts/copyScripts.ts",
"copy:servers": "xcopy server\\services\\server\\utils\\serverData.json dist\\server\\services\\server\\utils /E /I /Y",
"start": "set NODE_ENV=production && npm run start:server", "start": "set NODE_ENV=production && npm run start:server",
"start:server": "dotenvx run -f .env -- node dist/server/index.js", "start:server": "dotenvx run -f .env -- node dist/server/index.js",
"db:generate": "npx drizzle-kit generate", "db:generate": "npx drizzle-kit generate",
@@ -22,50 +24,7 @@
"prodBuild": "npm run v1Build && powershell -ExecutionPolicy Bypass -File server/scripts/build.ps1 -dir \"C:\\Users\\matthes01\\Documents\\lstv2\" && npm run zipServer", "prodBuild": "npm run v1Build && powershell -ExecutionPolicy Bypass -File server/scripts/build.ps1 -dir \"C:\\Users\\matthes01\\Documents\\lstv2\" && npm run zipServer",
"commit": "cz", "commit": "cz",
"prodinstall": "npm i --omit=dev && npm run db:migrate", "prodinstall": "npm i --omit=dev && npm run db:migrate",
"checkupdates": "npm-check-updates" "checkupdates": "npx npm-check-updates"
},
"dependencies": {
"@dotenvx/dotenvx": "^1.38.3",
"@hono/node-server": "^1.13.8",
"@hono/zod-openapi": "^0.18.4",
"@scalar/hono-api-reference": "^0.5.175",
"@types/jsonwebtoken": "^9.0.8",
"adm-zip": "^0.5.16",
"axios": "^1.7.9",
"bcrypt": "^5.1.1",
"compression": "^1.8.0",
"cookie": "^1.0.2",
"date-fns": "^4.1.0",
"dotenv": "^16.4.7",
"drizzle-kit": "^0.30.4",
"drizzle-orm": "^0.39.3",
"drizzle-zod": "^0.7.0",
"fast-xml-parser": "^5.0.9",
"jsonwebtoken": "^9.0.2",
"mssql": "^11.0.1",
"nodemailer": "^6.10.0",
"nodemailer-express-handlebars": "^7.0.0",
"pg": "^8.13.3",
"pino": "^9.6.0",
"pino-abstract-transport": "^2.0.0",
"pino-pretty": "^13.0.0",
"postgres": "^3.4.5",
"zod": "^3.24.2"
},
"devDependencies": {
"@types/adm-zip": "^0.5.7",
"@types/bcrypt": "^5.0.2",
"@types/js-cookie": "^3.0.6",
"@types/mssql": "^9.1.7",
"@types/node": "^22.13.5",
"@types/pg": "^8.11.11",
"concurrently": "^8.2.0",
"cz-conventional-changelog": "^3.3.0",
"dotenv": "^16.3.1",
"rimraf": "^6.0.1",
"standard-version": "^9.5.0",
"tsx": "^4.7.1",
"typescript": "~5.7.3"
}, },
"config": { "config": {
"commitizen": { "commitizen": {
@@ -73,7 +32,50 @@
} }
}, },
"admConfig": { "admConfig": {
"build": 47, "build": 50,
"oldBuild": "backend-0.1.3.zip" "oldBuild": "backend-0.1.3.zip"
},
"devDependencies": {
"@types/adm-zip": "^0.5.7",
"@types/bcrypt": "^5.0.2",
"@types/fs-extra": "^11.0.4",
"@types/js-cookie": "^3.0.6",
"@types/mssql": "^9.1.7",
"@types/node": "^22.13.11",
"@types/pg": "^8.11.11",
"@types/ws": "^8.18.0",
"concurrently": "^9.1.2",
"cz-conventional-changelog": "^3.3.0",
"drizzle-kit": "^0.30.5",
"fs-extra": "^11.3.0",
"standard-version": "^9.5.0",
"tsx": "^4.19.3",
"typescript": "^5.8.2"
},
"dependencies": {
"@dotenvx/dotenvx": "^1.39.0",
"@hono/node-server": "^1.14.0",
"@hono/zod-openapi": "^0.19.2",
"@scalar/hono-api-reference": "^0.7.2",
"@types/jsonwebtoken": "^9.0.9",
"adm-zip": "^0.5.16",
"axios": "^1.8.4",
"bcryptjs": "^3.0.2",
"date-fns": "^4.1.0",
"drizzle-orm": "^0.41.0",
"drizzle-zod": "^0.7.0",
"fast-xml-parser": "^5.0.9",
"jsonwebtoken": "^9.0.2",
"mssql": "^11.0.1",
"nodemailer": "^6.10.0",
"nodemailer-express-handlebars": "^7.0.0",
"pg": "^8.14.1",
"pino": "^9.6.0",
"pino-abstract-transport": "^2.0.0",
"pino-pretty": "^13.0.0",
"postgres": "^3.4.5",
"rimraf": "^6.0.1",
"ws": "^8.18.1",
"zod": "^3.24.2"
} }
} }

View File

@@ -0,0 +1,29 @@
import type { Context } from "hono";
export type ReturnRes<T> =
| { success: true; message: string; data: T }
| { success: false; message: string; error: any };
export const returnRes = <T>(
success: boolean,
message: string,
data: T | null = null
): ReturnRes<T> => {
/**
* just a simple return to reduce the typing and make sure we are always consitant with our returns.
*
* data can be an error as well.
*/
return success
? { success, message, data: data as T }
: { success, message, error: data ?? "An unknown error occurred" };
};
// export const returnApi = (c:Context,success: boolean, message: string, data?: any, code: number)=>{
// /**
// * just a simple return to reduce the typing and make sure we are always consitant with our returns.
// *
// * data can be an error as well.
// */
// return c.json({success, message, data}, code);
// }

View File

@@ -0,0 +1,24 @@
// Types for the result object with discriminated union
type Success<T> = {
data: T;
error: null;
};
type Failure<E> = {
data: null;
error: E;
};
type Result<T, E = Error> = Success<T> | Failure<E>;
// Main wrapper function
export async function tryCatch<T, E = Error>(
promise: Promise<T>
): Promise<Result<T, E>> {
try {
const data = await promise;
return { data, error: null };
} catch (error) {
return { data: null, error: error as E };
}
}

View File

@@ -1,12 +1,12 @@
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"; process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
import {serve} from "@hono/node-server"; import { serve } from "@hono/node-server";
import {OpenAPIHono} from "@hono/zod-openapi"; import { OpenAPIHono } from "@hono/zod-openapi";
import {proxy} from "hono/proxy"; import { proxy } from "hono/proxy";
import {serveStatic} from "@hono/node-server/serve-static"; import { serveStatic } from "@hono/node-server/serve-static";
import {logger} from "hono/logger"; import { logger } from "hono/logger";
import {cors} from "hono/cors"; import { cors } from "hono/cors";
import {createLog} from "./services/logger/logger.js"; import { createLog } from "./services/logger/logger.js";
import { WebSocketServer } from "ws";
// custom routes // custom routes
import scalar from "./services/general/route/scalar.js"; import scalar from "./services/general/route/scalar.js";
import system from "./services/server/systemServer.js"; import system from "./services/server/systemServer.js";
@@ -19,9 +19,9 @@ import rfid from "./services/rfid/rfidService.js";
import printers from "./services/printers/printerService.js"; import printers from "./services/printers/printerService.js";
import loggerService from "./services/logger/loggerService.js"; import loggerService from "./services/logger/loggerService.js";
import ocpService from "./services/ocp/ocpService.js"; import ocpService from "./services/ocp/ocpService.js";
import {db} from "../database/dbclient.js"; import { db } from "../database/dbclient.js";
import {settings} from "../database/schema/settings.js"; import { settings } from "../database/schema/settings.js";
import {count, eq} from "drizzle-orm"; import { count } from "drizzle-orm";
// create the main prodlogin here // create the main prodlogin here
const username = "lst_user"; const username = "lst_user";
@@ -29,63 +29,66 @@ const password = "Alpla$$Prod";
export const lstAuth = btoa(`${username}:${password}`); export const lstAuth = btoa(`${username}:${password}`);
// checking to make sure we have the settings intialized // checking to make sure we have the settings intialized
const serverIntialized = await db.select({count: count()}).from(settings); const serverIntialized = await db.select({ count: count() }).from(settings);
export const installed = serverIntialized[0].count === 0 && process.env.NODE_ENV !== "development" ? false : true; export const installed =
serverIntialized[0].count === 0 && process.env.NODE_ENV !== "development"
? false
: true;
createLog("info", "LST", "server", `Server is installed: ${installed}`); createLog("info", "LST", "server", `Server is installed: ${installed}`);
const app = new OpenAPIHono({strict: false}); const app = new OpenAPIHono({ strict: false });
// middle ware // middle ware
app.use("*", logger()); app.use("*", logger());
app.use( app.use(
"*", "*",
cors({ cors({
origin: "*", // Allow all origins origin: "*", // Allow all origins
allowHeaders: ["Content-Type", "Authorization", "X-Requested-With"], allowHeaders: ["Content-Type", "Authorization", "X-Requested-With"],
allowMethods: ["GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"], allowMethods: ["GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"],
//exposeHeaders: ["Content-Length", "X-Kuma-Revision"], //exposeHeaders: ["Content-Length", "X-Kuma-Revision"],
credentials: true, // Allow credentials if needed credentials: true, // Allow credentials if needed
maxAge: 600, maxAge: 600,
}) })
); );
// Middleware to normalize route case // Middleware to normalize route case
app.use("*", async (c, next) => { app.use("*", async (c, next) => {
const lowercasedUrl = c.req.url.toLowerCase(); const lowercasedUrl = c.req.url.toLowerCase();
//console.log("Incoming Request:", c.req.url, c.req.method); //console.log("Incoming Request:", c.req.url, c.req.method);
// If the URL is already lowercase, continue as usual // If the URL is already lowercase, continue as usual
if (c.req.url === lowercasedUrl) { if (c.req.url === lowercasedUrl) {
return next(); return next();
} }
// Otherwise, re-route internally // Otherwise, re-route internally
return c.redirect(lowercasedUrl, 308); // 308 preserves the HTTP method return c.redirect(lowercasedUrl, 308); // 308 preserves the HTTP method
}); });
app.doc("/api/ref", { app.doc("/api/ref", {
openapi: "3.0.0", openapi: "3.0.0",
info: { info: {
version: "2.0.0", version: "2.0.0",
title: "LST API", title: "LST API",
}, },
}); });
const routes = [ const routes = [
scalar, scalar,
auth, auth,
// apiHits, // apiHits,
system, system,
tcpServer, tcpServer,
sqlService, sqlService,
logistics, logistics,
rfid, rfid,
printers, printers,
loggerService, loggerService,
ocpService, ocpService,
] as const; ] as const;
const appRoutes = routes.forEach((route) => { const appRoutes = routes.forEach((route) => {
app.route("/api/", route); app.route("/api/", route);
}); });
app.route("/ocme/", ocme); app.route("/ocme/", ocme);
@@ -118,46 +121,56 @@ app.route("/ocme/", ocme);
//---------------------------------------------------\\ //---------------------------------------------------\\
// the catch all api route // the catch all api route
app.all("/api/*", (c) => c.json({error: "API route not found"}, 404)); app.all("/api/*", (c) => c.json({ error: "API route not found" }, 404));
// front end static files // front end static files
app.use("/*", serveStatic({root: "./frontend/dist"})); app.use("/*", serveStatic({ root: "./frontend/dist" }));
app.use("*", serveStatic({path: "./frontend/dist/index.html"})); app.use("*", serveStatic({ path: "./frontend/dist/index.html" }));
// Handle app exit signals // Handle app exit signals
process.on("SIGINT", async () => { process.on("SIGINT", async () => {
console.log("\nGracefully shutting down..."); console.log("\nGracefully shutting down...");
//await closePool(); //await closePool();
process.exit(0); process.exit(0);
}); });
process.on("SIGTERM", async () => { process.on("SIGTERM", async () => {
console.log("Received termination signal, closing database..."); console.log("Received termination signal, closing database...");
//await closePool(); //await closePool();
process.exit(0); process.exit(0);
}); });
process.on("uncaughtException", async (err) => { process.on("uncaughtException", async (err) => {
console.log("Uncaught Exception:", err); console.log("Uncaught Exception:", err);
//await closePool(); //await closePool();
process.exit(1); process.exit(1);
}); });
process.on("beforeExit", async () => { process.on("beforeExit", async () => {
console.log("Process is about to exit..."); console.log("Process is about to exit...");
//await closePool(); //await closePool();
process.exit(0);
}); });
const port = process.env.NODE_ENV === "development" ? process.env.VITE_SERVER_PORT : process.env.PROD_PORT; const port =
process.env.NODE_ENV === "development"
? process.env.VITE_SERVER_PORT
: process.env.PROD_PORT;
serve( serve(
{ {
fetch: app.fetch, fetch: app.fetch,
port: Number(port), port: Number(port),
hostname: "0.0.0.0", hostname: "0.0.0.0",
}, },
(info) => { (info) => {
createLog("info", "LST", "server", `Server is running on http://${info.address}:${info.port}`); createLog(
} "info",
"LST",
"server",
`Server is running on http://${info.address}:${info.port}`
);
}
); );
export type AppRoutes = typeof appRoutes; export type AppRoutes = typeof appRoutes;

View File

@@ -0,0 +1,65 @@
import fs from "fs-extra";
import path from "path";
import { fileURLToPath } from "url";
// Get the current directory of the module
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const sourceDir = path.join(__dirname, "/");
const destDir = path.join("./", "dist", "server", "scripts");
// Copy only .ps1 files
fs.readdir(sourceDir)
.then((files) => {
files.forEach((file) => {
if (path.extname(file) === ".ps1") {
const sourceFile = path.join(sourceDir, file);
const destFile = path.join(destDir, file);
// Copy each .ps1 file
fs.copy(sourceFile, destFile)
.then(() => {
console.log(`Copied: ${file}`);
})
.catch((err) => {
console.error(`Error copying file: ${file}`, err);
});
}
});
})
.catch((err) => {
console.error("Error reading source directory:", err);
});
// Paths for source and destination of serverData.json
const sourceFile = path.join(
"./",
"server",
"services",
"server",
"utils",
"serverData.json"
);
const serverDataDest = path.join(
"./",
"dist",
"server",
"services",
"server",
"utils"
);
const destFile = path.join(serverDataDest, "serverData.json");
// Ensure the destination directory exists
fs.ensureDir(destDir)
.then(() => {
// Copy the serverData.json file
return fs.copy(sourceFile, destFile);
})
.then(() => {
console.log("serverData.json copied successfully!");
})
.catch((err) => {
console.error("Error copying serverData.json:", err);
});

View File

@@ -1,37 +1,56 @@
# Install # Install
## Files needed to be downloaded before install. ## Files needed to be downloaded before install.
### To run the server ### To run the server
* [PostgresSQL](https://www.postgresql.org/download/windows/) - current version using is 17
* [NodeJS](https://nodejs.org) - [PostgresSQL](https://www.postgresql.org/download/windows/) - current version using is 17
* [NSSM](https://nssm.cc/) - [NodeJS](https://nodejs.org)
- [NSSM](https://nssm.cc/)
### To manage the server ### To manage the server
* [VSCODE](https://code.visualstudio.com/)
* [Postman](https://www.postman.com/downloads/) - [VSCODE](https://code.visualstudio.com/)
- [Postman](https://www.postman.com/downloads/)
## Creating directories needed ## Creating directories needed
* Create a new folder where we will host the server files.
* Copy the nssm.exe into this folder - Create a new folder where we will host the server files.
* Copy the build files to the server (only needed for intial install). - Copy the nssm.exe into this folder
* This will house all the compiles and minified files needed to start the server up, this includes the frontend. - Copy the build files to the server (only needed for intial install).
* Save the nssm.exe into this folder as well, this will be used to control the service. - This will house all the compiles and minified files needed to start the server up, this includes the frontend.
- Save the nssm.exe into this folder as well, this will be used to control the service.
## Do the intial install ## Do the intial install
### DB instal setup ### DB instal setup
1. Install postgres 1. Install postgres
2. Open pgAdmin 2. Open pgAdmin
3. create a new Database named lst_db 3. create a new Database named lst_db
### Intial server setup ### Intial server setup
1. Open VSCode and navigate to the folder where you extracted the files. 1. Open VSCode and navigate to the folder where you extracted the files.
2. Click trusted when it pops up. 2. Click trusted when it pops up.
3. Open a terminal window inside vscode. 3. Open a terminal window inside vscode.
4. Run the install script this will install all dependaceys needed as well as do all the database migrations 4. Run the install script this will install all dependaceys needed as well as do all the database migrations
```bash ```bash
npm run prodinstall npm run prodinstall
``` ```
Next we want to do an intial build for the db
```bash
npm run build
```
### Create the .env file ### Create the .env file
In the root of the folder create a new .env file In the root of the folder create a new .env file
add in the below and change each setting area that says change me to something that suits your needs add in the below and change each setting area that says change me to something that suits your needs
```env ```env
# PORTS # PORTS
# To keep it all simple we will pass VITE to the ports that are used on both sides. # To keep it all simple we will pass VITE to the ports that are used on both sides.
@@ -39,7 +58,9 @@ VITE_SERVER_PORT=4400
# logLevel # logLevel
LOG_LEVEL=debug LOG_LEVEL=debug
PROD_PORT=4000
# DUE to lstv1 we need 3000
SEC_PORT=3000
# Auth stuff # Auth stuff
SALTING=12 SALTING=12
SECRET=CHANGEME SECRET=CHANGEME
@@ -64,62 +85,80 @@ MAXLOTS=3
``` ```
### Run the start command to get all the basic settings and modules installed ### Run the start command to get all the basic settings and modules installed
1. Run the below 1. Run the below
```bash ```bash
npm start npm start
``` ```
This command will start up the server and seed the database. This command will start up the server and seed the database.
* Settings will be set here.
* All modules will be added. - Settings will be set here.
- All modules will be added.
2. Press CTRL + C to stop the server. 2. Press CTRL + C to stop the server.
3. Reopen postgres and review the settings make the changes to match the server your going to be running in. 3. Reopen postgres and review the settings make the changes to match the server your going to be running in.
* Change the server - Change the server
* change the dbServer - change the dbServer
* change plantToken - change plantToken
* then the remaining settings confirm if you need on or want to leave as default. - then the remaining settings confirm if you need on or want to leave as default.
### Creating first user. ### Creating first user.
1. Start the server back up. 1. Start the server back up.
```bash ```bash
npm start npm start
``` ```
2. Open http://[SERVER]:[PORT]/api/docs or postman and create a user. 2. Open http://[SERVER]:[PORT]/api/docs or postman and create a user.
* Please do not try to manually enter a new user this is due to how the password is hashed, as well as setting systemAdmin for the first user. - Please do not try to manually enter a new user this is due to how the password is hashed, as well as setting systemAdmin for the first user.
* Change the server and port to what you changed in the DB. - Change the server and port to what you changed in the DB.
3. Stop the server again with CTRL + C. 3. Stop the server again with CTRL + C.
### Running as a serivice. ### Running as a serivice.
You want to CD into the scripts folder. You want to CD into the scripts folder.
```bash ```bash
cd .\dist\server\scripts\ cd .\dist\server\scripts\
``` ```
Next use the example command below to get the service up and running. Next use the example command below to get the service up and running.
* Options legend
* serviceName = not recommended to change to reduce issues with the update process - Options legend
* option = use install for the install, but you can use this script later to stop, start, restart the service. - serviceName = not recommended to change to reduce issues with the update process
* appPath = where did you extract the server files - option = use install for the install, but you can use this script later to stop, start, restart the service.
* description = no need to change this unless you want it to be something else - appPath = where did you extract the server files
* command = do not change this unless you know what your doing and really need to change this. - description = no need to change this unless you want it to be something else
- command = do not change this unless you know what your doing and really need to change this.
```powershell ```powershell
.\services.ps1 -serviceName "LSTV2" -option "install" -appPath "E:\LST\lstV2" -description "Logistics Support Tool V2" -command "run start" .\services.ps1 -serviceName "LSTV2" -option "install" -appPath "E:\LST\lstV2" -description "Logistics Support Tool V2" -command "run start"
``` ```
# Migrating From V1 to V2 # Migrating From V1 to V2
## User migration ## User migration
1. Open the sqlite db and export to sql the users table 1. Open the sqlite db and export to sql the users table
2. OPen the sql in notepad++ or your editor of choice and change the query to be similar to below. 2. OPen the sql in notepad++ or your editor of choice and change the query to be similar to below.
* we only need to have save the username, role, email, password - we only need to have save the username, role, email, password
An example new query will look like An example new query will look like
* Below is how it looks when exported from sqlite
- Below is how it looks when exported from sqlite
```sql ```sql
INSERT INTO "User" ("id", "username", "email", "role", "password", "passwordToken", "tokenExpire", "active", "pinCode", "lastLogin", "add_user", "add_date", "upd_user", "upd_date") VALUES INSERT INTO "User" ("id", "username", "email", "role", "password", "passwordToken", "tokenExpire", "active", "pinCode", "lastLogin", "add_user", "add_date", "upd_user", "upd_date") VALUES
(1, 'matthes01', 'blake.matthes@alpla.com', 'admin', 'JDJiJDEMUJEdGtL', NULL, NULL, '1', NULL, '1721075647687', 'LST_System', '1721075647687', 'LST_System', '1721075647687'); (1, 'matthes01', 'blake.matthes@alpla.com', 'admin', 'JDJiJDEMUJEdGtL', NULL, NULL, '1', NULL, '1721075647687', 'LST_System', '1721075647687', 'LST_System', '1721075647687');
``` ```
The way we want to put recreate the query to work with the new db The way we want to put recreate the query to work with the new db
* Below example
- Below example
```sql ```sql
INSERT INTO "users" ("username", "email", "role", "password") VALUES INSERT INTO "users" ("username", "email", "role", "password") VALUES
('matthes01','blake.matthes@alpla.com','admin','JDJiJDE1FuNFpkYlk4NGdHUXpEMzlHR1BD'), ('matthes01','blake.matthes@alpla.com','admin','JDJiJDE1FuNFpkYlk4NGdHUXpEMzlHR1BD'),
@@ -127,11 +166,12 @@ INSERT INTO "users" ("username", "email", "role", "password") VALUES
('brandon001','brandon.harry@alpla.com','manager','wdm1RSXJlZnJDYTZP'); ('brandon001','brandon.harry@alpla.com','manager','wdm1RSXJlZnJDYTZP');
; ;
``` ```
* You could have many users and just add like above with the identical info from the db
- You could have many users and just add like above with the identical info from the db
## Running v1 along Side V2 for the interm ## Running v1 along Side V2 for the interm
* change v2 prod port to 4000 in the env and db
* change v1 env to 4400 in the env. and in the db you will need to change the auth server to 4000 and the serverPort to 4400 - change v2 prod port to 4000 in the env and db
- change v1 env to 4400 in the env. and in the db you will need to change the auth server to 4000 and the serverPort to 4400
This will change so that v2 is the main server now, this is needed for ocme mainly. This will change so that v2 is the main server now, this is needed for ocme mainly.

View File

@@ -254,16 +254,29 @@ API_KEY= "E3ECD3619A943B98C6F33E3322362"
Write-Host "Creating the env file in the front end" Write-Host "Creating the env file in the front end"
$envContentTemplateb = @" $envContentTemplateb = @"
DATABASE_URL="file:E:\LST\db\lstBackendDB.db" DATABASE_URL="file:E:\LST\db\{dbLink}.db"
"@ "@
try { try {
$dbLink = "lstBackendDB"
if ($token -eq "usiow2") {
$dbLink = "lstBackendDB_2"
}
if ($token -in @("test1", "test2", "test3")) {
$dbLink = "lstBackendDB"
}
# Replace {url} with the actual $url
$envContentb = $envContentTemplateb -replace "{dbLink}", $dbLink
# Define the path where the .env file should be created # Define the path where the .env file should be created
$envFilePathb = $obslst + "\packages\database\.env" $envFilePathb = $obslst + "\packages\database\.env"
# Write the content to the .env file # Write the content to the .env file
$envContentTemplateb | Out-File -FilePath $envFilePathb -Encoding UTF8 -Force $envContentb | Out-File -FilePath $envFilePathb -Encoding UTF8 -Force
# Optional: Verify the file was created # Optional: Verify the file was created
if (Test-Path $envFilePathb) { if (Test-Path $envFilePathb) {
@@ -287,12 +300,19 @@ NODE_ENV = production
# server apiKey # server apiKey
API_KEY = E3ECD3619A943B98C6F33E3322362 API_KEY = E3ECD3619A943B98C6F33E3322362
# Prisma DB link # Prisma DB link
DATABASE_URL="file:E:\LST\db\lstBackendDB.db" DATABASE_URL="file:E:\LST\db\{dbLink}.db"
# if you still want the db in the same folder as the server install you need to do like the example below else use the relevent link # if you still want the db in the same folder as the server install you need to do like the example below else use the relevent link
DATEBASE_LOC="E:\LST\db\lstBackendDB.db" DATEBASE_LOC="E:\LST\db\{dbLink}.db"
DATABASE_BACKUP_LOC="E:\LST\backups" DATABASE_BACKUP_LOC="E:\LST\backups"
# Server port # Server port
SERVER_PORT = 4400 GATEWAY_PORT={gatewayport}
AUTH_PORT=4100
SYSTEM_APP_PORT={systemport}
OCME_PORT={ocme}
# This should me removed once we have the entire app broke out to its own apps
OLD_APP_PORT={appPort}
# Logging # Logging
LOG_LEVEL = info LOG_LEVEL = info
LOG_LOC ="E:\\LST\\logs" LOG_LOC ="E:\\LST\\logs"
@@ -310,13 +330,39 @@ COOKIE_EXPIRES_TIME = 60
RESET_TOKEN = 330 RESET_TOKEN = 330
"@ "@
try { try {
# Define the path where the .env file should be created $dbLink = "lstBackendDB"
$envFilePathd = $obslst + "\.env" $gatewayport = "4400"
$systemport = "4200"
$ocmeport = "4300"
$appport = "4900"
# Write the content to the .env file if ($token -eq "usiow2") {
$envContentTemplated | Out-File -FilePath $envFilePathd -Encoding UTF8 -Force $dbLink = "lstBackendDB_2"
$gatewayport = "4401"
$systemport = "4201"
$ocmeport = "4301"
$appport = "4901"
}
if ($token -in @("test1", "test2", "test3")) {
$dbLink = "lstBackendDB"
}
#
$port1 = $envContentTemplated -replace "{gatewayport}", $gatewayport
$port2 = $port1 -replace "{systemport}", $systemport
$port3 = $port2 -replace "{ocme}", $ocmeport
$port4 = $port3 -replace "{appPort}", $appport
$envContentd = $port4 -replace "{dbLink}", $dbLink
# Define the path where the .env file should be created
$envFilePathd = $obslst + "\.env"
# Write the content to the .env file
$envContentd | Out-File -FilePath $envFilePathd -Encoding UTF8 -Force
# Optional: Verify the file was created # Optional: Verify the file was created
if (Test-Path $envFilePathd) { if (Test-Path $envFilePathd) {

View File

@@ -1,153 +1,193 @@
import AdmZip from "adm-zip"; import AdmZip from "adm-zip";
import path from "path"; import path from "path";
import fs from "fs"; import fs from "fs";
import {execSync} from "child_process"; import { execSync } from "child_process";
import {createLog} from "../services/logger/logger.js"; import { createLog } from "../services/logger/logger.js";
import {getAppInfo} from "../globalUtils/appInfo.js"; import { getAppInfo } from "../globalUtils/appInfo.js";
// create the ignore list // create the ignore list
const ignoreList = [ const ignoreList = [
".git", ".git",
"builds", "builds",
"server", "server",
"node_modules", "node_modules",
"apiDocsLSTV2", "apiDocsLSTV2",
"testFiles", "testFiles",
".env", ".env",
".gitignore", ".gitignore",
".versionrc.json", ".versionrc.json",
"drizzle-dev.config.ts", "drizzle-dev.config.ts",
"nssm.exe", "nssm.exe",
"postgresql-17.2-3-windows-x64.exe", "postgresql-17.2-3-windows-x64.exe",
// front end ignore // front end ignore
"frontend/node_modules", "frontend/node_modules",
"fonrtend/.env", "fonrtend/.env",
"frontend/public", "frontend/public",
"frontend/src", "frontend/src",
"frontend/.gitignore", "frontend/.gitignore",
"frontend/eslint.config.js", "frontend/eslint.config.js",
"frontend/index.html", "frontend/index.html",
"frontend/package.json", "frontend/package.json",
"frontend/package-lock.json", "frontend/package-lock.json",
"frontend/README.md", "frontend/README.md",
"frontend/tsconfig.json", "frontend/tsconfig.json",
"frontend/tsconfig.app.json", "frontend/tsconfig.app.json",
"frontend/tsconfig.node.json", "frontend/tsconfig.node.json",
"frontend/vite.config.ts", "frontend/vite.config.ts",
"frontend/components.json", "frontend/components.json",
]; ];
const shouldIgnore = (itemPath: any) => { const shouldIgnore = (itemPath: any) => {
const normalizedItemPath = itemPath.replace(/\\/g, "/"); const normalizedItemPath = itemPath.replace(/\\/g, "/");
return ignoreList.some((ignorePattern) => { return ignoreList.some((ignorePattern) => {
const normalizedIgnorePatther = ignorePattern.replace(/\\/g, "/"); const normalizedIgnorePatther = ignorePattern.replace(/\\/g, "/");
return ( return (
normalizedItemPath === normalizedIgnorePatther || normalizedItemPath === normalizedIgnorePatther ||
normalizedItemPath.startsWith(`${normalizedIgnorePatther}/`) normalizedItemPath.startsWith(`${normalizedIgnorePatther}/`)
); );
}); });
}; };
const addToZip = (zip: any, currentPath: string, rootPath: string) => { const addToZip = (zip: any, currentPath: string, rootPath: string) => {
const items = fs.readdirSync(currentPath); const items = fs.readdirSync(currentPath);
items.forEach((item) => { items.forEach((item) => {
const itemPath = path.join(currentPath, item); const itemPath = path.join(currentPath, item);
const relativePath = path.relative(rootPath, itemPath); const relativePath = path.relative(rootPath, itemPath);
// Skip if the item is in the ignore list // Skip if the item is in the ignore list
if (shouldIgnore(relativePath)) { if (shouldIgnore(relativePath)) {
createLog("info", "lst", "zipUpBuild", `Ignoring: ${relativePath}`); createLog("info", "lst", "zipUpBuild", `Ignoring: ${relativePath}`);
return; return;
} }
const stat = fs.statSync(itemPath); const stat = fs.statSync(itemPath);
if (stat.isDirectory()) { if (stat.isDirectory()) {
// If it's a directory, recursively add its contents // If it's a directory, recursively add its contents
addToZip(zip, itemPath, rootPath); addToZip(zip, itemPath, rootPath);
} else { } else {
// If it's a file, add it to the zip with the preserved folder structure // If it's a file, add it to the zip with the preserved folder structure
zip.addLocalFile(itemPath, path.dirname(relativePath)); zip.addLocalFile(itemPath, path.dirname(relativePath));
} }
}); });
}; };
const updateBuildNumber = (appLock: string) => { const updateBuildNumber = (appLock: string) => {
const packagePath = path.join(appLock, "package.json"); // Adjust path if necessary const packagePath = path.join(appLock, "package.json"); // Adjust path if necessary
try { try {
// Read package.json // Read package.json
const pkgData = fs.readFileSync(packagePath, "utf8"); const pkgData = fs.readFileSync(packagePath, "utf8");
const pkgJson = JSON.parse(pkgData); const pkgJson = JSON.parse(pkgData);
// Ensure admConfig exists // Ensure admConfig exists
if (pkgJson.admConfig && typeof pkgJson.admConfig.build === "number") { if (pkgJson.admConfig && typeof pkgJson.admConfig.build === "number") {
// Increment the build number // Increment the build number
pkgJson.admConfig.build += 1; pkgJson.admConfig.build += 1;
// Write the updated data back // Write the updated data back
fs.writeFileSync(packagePath, JSON.stringify(pkgJson, null, 2), "utf8"); fs.writeFileSync(packagePath, JSON.stringify(pkgJson, null, 2), "utf8");
createLog("info", "lst", "zipUpBuild", `Build number updated to: ${pkgJson.admConfig.build}`); createLog(
// Auto-commit changes "info",
execSync("git add package.json"); "lst",
execSync(`git commit -m "chore: bump build number to ${pkgJson.admConfig.build}"`); "zipUpBuild",
} else { `Build number updated to: ${pkgJson.admConfig.build}`
createLog("error", "lst", "zipUpBuild", "admConfig.build is missing or not a number"); );
} // Auto-commit changes
} catch (error) { execSync("git add package.json");
createLog("error", "lst", "zipUpBuild", `Error updating build number: ${error}`); execSync(
`git commit -m "build: bump build number to ${pkgJson.admConfig.build}"`
);
} else {
createLog(
"error",
"lst",
"zipUpBuild",
"admConfig.build is missing or not a number"
);
} }
} catch (error) {
createLog(
"error",
"lst",
"zipUpBuild",
`Error updating build number: ${error}`
);
}
}; };
export const createZip = async (appLock: string) => { export const createZip = async (appLock: string) => {
const app = await getAppInfo(appLock); const app = await getAppInfo(appLock);
const zip = new AdmZip(); const zip = new AdmZip();
//dest path for this app... hard coded for meow will be in db later //dest path for this app... hard coded for meow will be in db later
const destPath = `${process.env.DEVFOLDER}\\builds`; const destPath = `${process.env.DEVFOLDER}\\builds`;
const srcPath = `${process.env.DEVFOLDER}`; const srcPath = `${process.env.DEVFOLDER}`;
addToZip(zip, srcPath, srcPath); addToZip(zip, srcPath, srcPath);
// Write the zip file to disk // Write the zip file to disk
const outputZipPath = path.join(destPath, `${app.name}-${app.version}-${app.admConfig.build}.zip`); const outputZipPath = path.join(
zip.writeZip(outputZipPath); destPath,
`${app.name}-${app.version}-${app.admConfig.build}.zip`
);
zip.writeZip(outputZipPath);
createLog("info", "lst", "zipUpBuild", `Zip file created at ${outputZipPath}`); createLog(
updateBuildNumber(appLock); "info",
"lst",
"zipUpBuild",
`Zip file created at ${outputZipPath}`
);
updateBuildNumber(appLock);
// only keep the last 5 builds for the type we have. // only keep the last 5 builds for the type we have.
try { try {
const appFiles = fs const appFiles = fs
.readdirSync(destPath) .readdirSync(destPath)
.filter((file) => file.startsWith(app.name)) // Ensure only backend files are matched .filter((file) => file.startsWith(app.name)) // Ensure only backend files are matched
.map((file) => ({ .map((file) => ({
name: file, name: file,
time: fs.statSync(path.join(destPath, file)).mtime.getTime(), time: fs.statSync(path.join(destPath, file)).mtime.getTime(),
})) }))
.sort((a, b) => a.time - b.time); // Sort by modification time (oldest first) .sort((a, b) => a.time - b.time); // Sort by modification time (oldest first)
createLog("info", "lst", "zipUpBuild", `app Files (sorted by time):", ${JSON.stringify(appFiles)}`); createLog(
"info",
"lst",
"zipUpBuild",
`app Files (sorted by time):", ${JSON.stringify(appFiles)}`
);
if (appFiles.length > 5) { if (appFiles.length > 5) {
appFiles.slice(0, -5).forEach((file) => { appFiles.slice(0, -5).forEach((file) => {
const filePath = path.join(destPath, file.name); const filePath = path.join(destPath, file.name);
try { try {
fs.unlinkSync(filePath); fs.unlinkSync(filePath);
createLog("info", "lst", "zipUpBuild", `Deleted: ${file.name}`); createLog("info", "lst", "zipUpBuild", `Deleted: ${file.name}`);
} catch (error: any) { } catch (error: any) {
createLog("error", "lst", "zipUpBuild", `Failed to delete ${file.name}: ${error.message}`); createLog(
} "error",
}); "lst",
} else { "zipUpBuild",
createLog("info", "lst", "zipUpBuild", "No files to delete."); `Failed to delete ${file.name}: ${error.message}`
);
} }
} catch (error: any) { });
createLog("error", "lst", "zipUpBuild", `Error reading directory or deleting files:", ${error.message}`); } else {
createLog("info", "lst", "zipUpBuild", "No files to delete.");
} }
} catch (error: any) {
createLog(
"error",
"lst",
"zipUpBuild",
`Error reading directory or deleting files:", ${error.message}`
);
}
}; };
//createZip("C:\\Users\\matthes01\\Documents\\lstv2"); //createZip("C:\\Users\\matthes01\\Documents\\lstv2");
@@ -155,16 +195,16 @@ export const createZip = async (appLock: string) => {
// Only call `createZip` if the script is executed directly // Only call `createZip` if the script is executed directly
if (process.argv.length > 2) { if (process.argv.length > 2) {
const location = process.argv[2]; const location = process.argv[2];
if (!location) { if (!location) {
createLog("error", "lst", "zipUpBuild", "Error: No location provided.");
process.exit(1);
} else {
createLog("info", "lst", "zipUpBuild", "Startiing the zip process.");
}
createZip(location);
} else {
createLog("error", "lst", "zipUpBuild", "Error: No location provided."); createLog("error", "lst", "zipUpBuild", "Error: No location provided.");
process.exit(1);
} else {
createLog("info", "lst", "zipUpBuild", "Startiing the zip process.");
}
createZip(location);
} else {
createLog("error", "lst", "zipUpBuild", "Error: No location provided.");
} }

View File

@@ -1,30 +1,37 @@
import {OpenAPIHono} from "@hono/zod-openapi"; import { OpenAPIHono } from "@hono/zod-openapi";
import {authMiddleware} from "./middleware/authMiddleware.js";
import login from "./routes/login.js"; import login from "./routes/login.js";
import register from "./routes/register.js"; import register from "./routes/register.js";
import session from "./routes/session.js"; import session from "./routes/session.js";
import getAccess from "./routes/userRoles/getUserRoles.js"; import getAccess from "./routes/user/getUserRoles.js";
import setAccess from "./routes/userRoles/setUserRoles.js"; import setAccess from "./routes/userAdmin/setUserRoles.js";
import profile from "./routes/user/profileUpdate.js"; import profile from "./routes/user/profileUpdate.js";
import {areRolesIn} from "./utils/roleCheck.js"; import { areRolesIn } from "./utils/roleCheck.js";
import createUser from "./routes/userAdmin/createUser.js";
import allUsers from "./routes/userAdmin/getUsers.js";
import updateUser from "./routes/userAdmin/updateUser.js";
const app = new OpenAPIHono(); const app = new OpenAPIHono();
// run the role check // run the role check
setTimeout(() => { setTimeout(() => {
areRolesIn(); areRolesIn();
}, 5000); }, 5000);
app.route("auth/login", login); const routes = [
app.route("auth/register", register); login,
app.route("auth/session", session); register,
session,
profile,
getAccess,
setAccess,
createUser,
allUsers,
updateUser,
] as const;
// required to login // app.route("/server", modules);
/* User area just needs to be logged in to enter here */ const appRoutes = routes.forEach((route) => {
app.route("auth/profileupdate", profile); app.route("/auth", route);
});
/* will need to increase to make sure the person coming here has the correct permissions */
app.route("auth/getuseraccess", getAccess);
app.route("auth/setuseraccess", setAccess);
export default app; export default app;

View File

@@ -0,0 +1,24 @@
import { db } from "../../../../../database/dbclient.js";
import { users } from "../../../../../database/schema/users.js";
import { returnRes } from "../../../../globalUtils/routeDefs/returnRes.js";
import { tryCatch } from "../../../../globalUtils/tryCatch.js";
import { createLog } from "../../../logger/logger.js";
export const getAllUsers = async () => {
/**
* returns all users that are in lst
*/
createLog("info", "apiAuthedRoute", "auth", "Get all users");
const { data, error } = await tryCatch(db.select().from(users));
if (error) {
returnRes(
false,
"There was an error getting users",
new Error("No user exists.")
);
}
returnRes(true, "All users.", data);
return { success: true, message: "All users", data };
};

View File

@@ -0,0 +1,68 @@
import { eq } from "drizzle-orm";
import { db } from "../../../../../database/dbclient.js";
import { users } from "../../../../../database/schema/users.js";
import { tryCatch } from "../../../../globalUtils/tryCatch.js";
import type { User } from "../../../../types/users.js";
import { createPassword } from "../../utils/createPassword.js";
import { createLog } from "../../../logger/logger.js";
export const updateUserADM = async (userData: User) => {
/**
* The user model will need to be passed over so we can update per the request on the user.
* password, username, email.
*/
createLog(
"info",
"apiAuthedRoute",
"auth",
`${userData.user_id} is being updated.`
);
// get the orignal user info
const { data: user, error: userError } = await tryCatch(
db.select().from(users).where(eq(users.user_id, userData.user_id!))
);
if (userError) {
return {
success: false,
message: "There was an error getting the user",
userError,
};
}
if (user?.length === 0) {
return {
success: false,
message:
"The user you are looking for has either been deleted or dose not exist.",
};
}
const upd_user = user as User;
const password: string = userData.password
? await createPassword(userData.password!)
: upd_user.password!;
const data = {
username: userData.username ? userData.username : upd_user?.username,
password: password,
email: userData.email ? userData.email : upd_user.email,
};
// term ? ilike(posts.title, term) : undefined
const { data: updData, error: updError } = await tryCatch(
db.update(users).set(data).where(eq(users.user_id, userData.user_id!))
);
if (updError) {
return {
success: false,
message: "There was an error getting the user",
updError,
};
}
return {
success: true,
message: `${userData.username} has been updated.`,
updData,
};
};

View File

@@ -0,0 +1,85 @@
import { createMiddleware } from "hono/factory";
import type { CustomJwtPayload } from "../../../types/jwtToken.js";
import { verify } from "hono/jwt";
import { db } from "../../../../database/dbclient.js";
import { modules } from "../../../../database/schema/modules.js";
import { and, eq } from "drizzle-orm";
import { userRoles } from "../../../../database/schema/userRoles.js";
import { tryCatch } from "../../../globalUtils/tryCatch.js";
const hasCorrectRole = (requiredRole: string[], module: string) =>
createMiddleware(async (c, next) => {
/**
* We want to check to make sure you have the correct role to be here
*/
const authHeader = c.req.header("Authorization");
if (!authHeader || !authHeader.startsWith("Bearer ")) {
return c.json({ error: "Unauthorized" }, 401);
}
const token = authHeader.split(" ")[1];
// deal with token data
const { data: tokenData, error: tokenError } = await tryCatch(
verify(token, process.env.JWT_SECRET!)
);
if (tokenError) {
return c.json({ error: "Invalid token" }, 401);
}
const customToken = tokenData as CustomJwtPayload;
// Get the module
const { data: mod, error: modError } = await tryCatch(
db.select().from(modules).where(eq(modules.name, module))
);
if (modError) {
console.log(modError);
return;
}
if (mod.length === 0) {
return c.json({ error: "You have entered an invalid module name" }, 403);
}
// check if the user has the role needed to get into this module
const { data: userRole, error: userRoleError } = await tryCatch(
db
.select()
.from(userRoles)
.where(
and(
eq(userRoles.module_id, mod[0].module_id),
eq(userRoles.user_id, customToken.user?.user_id!)
)
)
);
if (userRoleError) {
return;
}
if (!userRole) {
return c.json(
{
error:
"The module you are trying to access is not active or is invalid.",
},
403
);
}
if (!requiredRole.includes(userRole[0]?.role)) {
return c.json(
{ error: "You do not have access to this part of the app." },
403
);
}
await next();
});
export default hasCorrectRole;

View File

@@ -1,90 +1,97 @@
import {z, createRoute, OpenAPIHono} from "@hono/zod-openapi"; import { z, createRoute, OpenAPIHono } from "@hono/zod-openapi";
import {login} from "../controllers/login.js"; import { login } from "../controllers/login.js";
const app = new OpenAPIHono(); const app = new OpenAPIHono();
const UserSchema = z const UserSchema = z
.object({ .object({
username: z.string().optional().openapi({example: "smith002"}), username: z.string().optional().openapi({ example: "smith002" }),
//email: z.string().optional().openapi({example: "s.smith@example.com"}), //email: z.string().optional().openapi({example: "s.smith@example.com"}),
password: z.string().openapi({example: "password123"}), password: z.string().openapi({ example: "password123" }),
}) })
.openapi("User"); .openapi("User");
const route = createRoute({ const route = createRoute({
tags: ["Auth"], tags: ["Auth"],
summary: "Login as user", summary: "Login as user",
description: "Login as a user to get a JWT token", description: "Login as a user to get a JWT token",
method: "post", method: "post",
path: "/", path: "/login",
request: { request: {
body: { body: {
content: { content: {
"application/json": {schema: UserSchema}, "application/json": { schema: UserSchema },
}, },
},
}, },
responses: { },
200: { responses: {
content: { 200: {
"application/json": { content: {
schema: z.object({ "application/json": {
success: z.boolean().openapi({example: true}), schema: z.object({
message: z.string().openapi({example: "Logged in"}), success: z.boolean().openapi({ example: true }),
}), message: z.string().openapi({ example: "Logged in" }),
}, }),
},
description: "Response message",
}, },
},
description: "Response message",
},
400: { 400: {
content: { content: {
"application/json": { "application/json": {
schema: z.object({ schema: z.object({
success: z.boolean().openapi({example: false}), success: z.boolean().openapi({ example: false }),
message: z.string().openapi({example: "Username and password required"}), message: z
}), .string()
}, .openapi({ example: "Username and password required" }),
}, }),
description: "Bad request",
},
401: {
content: {
"application/json": {
schema: z.object({
success: z.boolean().openapi({example: false}),
message: z.string().openapi({example: "Username and password required"}),
}),
},
},
description: "Bad request",
}, },
},
description: "Bad request",
}, },
401: {
content: {
"application/json": {
schema: z.object({
success: z.boolean().openapi({ example: false }),
message: z
.string()
.openapi({ example: "Username and password required" }),
}),
},
},
description: "Bad request",
},
},
}); });
app.openapi(route, async (c) => { app.openapi(route, async (c) => {
const {username, password, email} = await c.req.json(); const { username, password, email } = await c.req.json();
if (!username || !password) { if (!username || !password) {
return c.json( return c.json(
{ {
success: false, success: false,
message: "Username and password are required", message: "Username and password are required",
}, },
400 400
); );
} }
try { try {
const {token, user} = await login(username.toLowerCase(), password); const { token, user } = await login(username.toLowerCase(), password);
// Set the JWT as an HTTP-only cookie // Set the JWT as an HTTP-only cookie
//c.header("Set-Cookie", `auth_token=${token}; HttpOnly; Secure; Path=/; SameSite=None; Max-Age=3600`); //c.header("Set-Cookie", `auth_token=${token}; HttpOnly; Secure; Path=/; SameSite=None; Max-Age=3600`);
return c.json({success: true, message: "Login successful", user, token}, 200); return c.json(
} catch (err) { { success: true, message: "Login successful", user, token },
return c.json({success: false, message: "Incorrect Credentials"}, 401); 200
} );
} catch (err) {
return c.json({ success: false, message: "Incorrect Credentials" }, 401);
}
}); });
export default app; export default app;

View File

@@ -1,97 +1,110 @@
import {z, createRoute, OpenAPIHono} from "@hono/zod-openapi"; import { z, createRoute, OpenAPIHono } from "@hono/zod-openapi";
import {apiHit} from "../../../globalUtils/apiHits.js"; import { apiHit } from "../../../globalUtils/apiHits.js";
import {registerUser} from "../controllers/register.js"; import { registerUser } from "../controllers/register.js";
const app = new OpenAPIHono(); const app = new OpenAPIHono();
const UserSchema = z.object({ const UserSchema = z.object({
username: z username: z
.string() .string()
.regex(/^[a-zA-Z0-9_]{3,30}$/) .regex(/^[a-zA-Z0-9_]{3,30}$/)
.openapi({example: "smith034"}), .openapi({ example: "smith034" }),
email: z.string().email().openapi({example: "smith@example.com"}), email: z.string().email().openapi({ example: "smith@example.com" }),
password: z password: z
.string() .string()
.min(6, {message: "Passwords must be longer than 3 characters"}) .min(6, { message: "Passwords must be longer than 3 characters" })
.regex(/[A-Z]/, {message: "Password must contain at least one uppercase letter"}) .regex(/[A-Z]/, {
.regex(/[\W_]/, {message: "Password must contain at least one special character"}) message: "Password must contain at least one uppercase letter",
.openapi({example: "Password1!"}), })
.regex(/[\W_]/, {
message: "Password must contain at least one special character",
})
.openapi({ example: "Password1!" }),
}); });
type User = z.infer<typeof UserSchema>; type User = z.infer<typeof UserSchema>;
const responseSchema = z.object({ const responseSchema = z.object({
success: z.boolean().optional().openapi({example: true}), success: z.boolean().optional().openapi({ example: true }),
message: z.string().optional().openapi({example: "User Created"}), message: z.string().optional().openapi({ example: "User Created" }),
}); });
app.openapi( app.openapi(
createRoute({ createRoute({
tags: ["Auth"], tags: ["Auth"],
summary: "Register a new user", summary: "Register a new user",
method: "post", method: "post",
path: "/", path: "/register",
request: { request: {
body: { body: {
content: { content: {
"application/json": {schema: UserSchema}, "application/json": { schema: UserSchema },
},
},
}, },
responses: { },
200: { },
content: {"application/json": {schema: responseSchema}}, responses: {
description: "Retrieve the user", 200: {
}, content: { "application/json": { schema: responseSchema } },
400: { description: "Retrieve the user",
content: { },
"application/json": { 400: {
schema: z.object({ content: {
success: z.boolean().openapi({example: false}), "application/json": {
message: z.string().openapi({example: "Invalid credentials passed"}), schema: z.object({
}), success: z.boolean().openapi({ example: false }),
}, message: z
}, .string()
description: "Retrieve the user", .openapi({ example: "Invalid credentials passed" }),
}, }),
},
}, },
}), description: "Retrieve the user",
async (c) => { },
// apit hit },
apiHit(c, {endpoint: "api/auth/register"}); }),
let {username, email, password} = await c.req.json(); async (c) => {
// apit hit
apiHit(c, { endpoint: "api/auth/register" });
let { username, email, password } = await c.req.json();
if (!username || !email || !password) { if (!username || !email || !password) {
return c.json({success: false, message: "Credentials missing"}, 400); return c.json({ success: false, message: "Credentials missing" }, 400);
}
// some usernames that should be ignored
const badActors = ["admin", "root"];
if (badActors.includes(username)) {
return c.json(
{
success: false,
message: `${username} is not a valid name to be registerd please try again`,
},
400
);
}
try {
const register = await registerUser(username, password, email);
return c.json({success: register.success, message: register.message, user: register?.user}, 200);
} catch (error) {
console.log(error);
return c.json(
{
success: false,
message: `${username} already exists please login or reset password, if you feel this is an error please contact your admin.`,
},
400
);
}
} }
// some usernames that should be ignored
const badActors = ["admin", "root"];
if (badActors.includes(username)) {
return c.json(
{
success: false,
message: `${username} is not a valid name to be registerd please try again`,
},
400
);
}
try {
const register = await registerUser(username, password, email);
return c.json(
{
success: register.success,
message: register.message,
user: register?.user,
},
200
);
} catch (error) {
console.log(error);
return c.json(
{
success: false,
message: `${username} already exists please login or reset password, if you feel this is an error please contact your admin.`,
},
400
);
}
}
); );
export default app; export default app;

View File

@@ -1,97 +1,110 @@
import {z, createRoute, OpenAPIHono} from "@hono/zod-openapi"; import { z, createRoute, OpenAPIHono } from "@hono/zod-openapi";
import {verify} from "hono/jwt"; import { verify } from "hono/jwt";
import {authMiddleware} from "../middleware/authMiddleware.js"; import { authMiddleware } from "../middleware/authMiddleware.js";
import jwt from "jsonwebtoken"; import jwt from "jsonwebtoken";
const session = new OpenAPIHono(); const session = new OpenAPIHono();
const expiresIn = Number(process.env.JWT_EXPIRES!) || 60; const expiresIn = Number(process.env.JWT_EXPIRES!) || 60;
const secret: string = process.env.JWT_SECRET!; const secret: string = process.env.JWT_SECRET!;
const {sign} = jwt; const { sign } = jwt;
const UserSchema = z.object({ const UserSchema = z.object({
username: z username: z
.string() .string()
.regex(/^[a-zA-Z0-9_]{3,30}$/) .regex(/^[a-zA-Z0-9_]{3,30}$/)
.openapi({example: "smith034"}), .openapi({ example: "smith034" }),
email: z.string().email().openapi({example: "smith@example.com"}), email: z.string().email().openapi({ example: "smith@example.com" }),
password: z password: z
.string() .string()
.min(6, {message: "Passwords must be longer than 3 characters"}) .min(6, { message: "Passwords must be longer than 3 characters" })
.regex(/[A-Z]/, {message: "Password must contain at least one uppercase letter"}) .regex(/[A-Z]/, {
.regex(/[\W_]/, {message: "Password must contain at least one special character"}) message: "Password must contain at least one uppercase letter",
.openapi({example: "Password1!"}), })
.regex(/[\W_]/, {
message: "Password must contain at least one special character",
})
.openapi({ example: "Password1!" }),
}); });
session.openapi( session.openapi(
createRoute({ createRoute({
tags: ["Auth"], tags: ["Auth"],
summary: "Checks a user session based on there token", summary: "Checks a user session based on there token",
description: "Can post there via Authentiaction header or cookies", description: "Can post there via Authentiaction header or cookies",
method: "get", method: "get",
path: "/", path: "/session",
middleware: authMiddleware, middleware: authMiddleware,
// request: { // request: {
// body: { // body: {
// content: { // content: {
// "application/json": {schema: UserSchema}, // "application/json": {schema: UserSchema},
// }, // },
// }, // },
// }, // },
responses: { responses: {
200: { 200: {
content: { content: {
"application/json": { "application/json": {
schema: z.object({ schema: z.object({
data: z.object({ data: z.object({
token: z.string().openapi({example: "sdkjhgsldkvhdakl;jvhs;adkjfhvds.kvnsad;ovhads"}), token: z
// user: z.object({ .string()
// user_id: z.string().openapi({example: "04316c86-f086-4cc6-b3d4-cca164a26f3f"}), .openapi({
// username: z.string().openapi({example: "smith"}), example: "sdkjhgsldkvhdakl;jvhs;adkjfhvds.kvnsad;ovhads",
// email: z.string().openapi({example: "smith@example.com"}).optional(), }),
// }), // user: z.object({
}), // user_id: z.string().openapi({example: "04316c86-f086-4cc6-b3d4-cca164a26f3f"}),
}), // username: z.string().openapi({example: "smith"}),
}, // email: z.string().openapi({example: "smith@example.com"}).optional(),
}, // }),
description: "Login successful", }),
}, }),
401: { },
content: {
"application/json": {
schema: z.object({
message: z.string().openapi({example: "Unathenticated"}),
}),
},
},
description: "Error of why you were not logged in.",
},
}, },
}), description: "Login successful",
async (c) => { },
const authHeader = c.req.header("Authorization"); 401: {
content: {
"application/json": {
schema: z.object({
message: z.string().openapi({ example: "Unathenticated" }),
}),
},
},
description: "Error of why you were not logged in.",
},
},
}),
async (c) => {
const authHeader = c.req.header("Authorization");
if (authHeader?.includes("Basic")) { if (authHeader?.includes("Basic")) {
return c.json({message: "You are a Basic user! Please login to get a token"}, 401); return c.json(
} { message: "You are a Basic user! Please login to get a token" },
401
if (!authHeader) { );
return c.json({message: "Unauthorized"}, 401);
}
const token = authHeader?.split("Bearer ")[1] || "";
try {
const payload = await verify(token, process.env.JWT_SECRET!);
// If it's valid, return a new token
const newToken = sign({user: payload.user}, secret, {expiresIn: expiresIn * 60});
return c.json({data: {token: newToken, user: payload.user}}, 200);
} catch (error) {
return c.json({message: "Unauthorized"}, 401);
}
} }
if (!authHeader) {
return c.json({ message: "Unauthorized" }, 401);
}
const token = authHeader?.split("Bearer ")[1] || "";
try {
const payload = await verify(token, process.env.JWT_SECRET!);
// If it's valid, return a new token
const newToken = sign({ user: payload.user }, secret, {
expiresIn: expiresIn * 60,
});
return c.json({ data: { token: newToken, user: payload.user } }, 200);
} catch (error) {
return c.json({ message: "Unauthorized" }, 401);
}
}
); );
// const token = authHeader?.split("Bearer ")[1] || ""; // const token = authHeader?.split("Bearer ")[1] || "";

View File

@@ -0,0 +1,59 @@
import { z, createRoute, OpenAPIHono } from "@hono/zod-openapi";
import jwt from "jsonwebtoken";
import type { CustomJwtPayload } from "../../../../types/jwtToken.js";
import { authMiddleware } from "../../middleware/authMiddleware.js";
import { roleCheck } from "../../controllers/userRoles/getUserAccess.js";
const { verify } = jwt;
const app = new OpenAPIHono();
const responseSchema = z.object({
message: z.string().optional().openapi({ example: "User Created" }),
});
app.openapi(
createRoute({
tags: ["auth:user"],
summary: "returns the users access",
method: "get",
path: "/getuseraccess",
middleware: [authMiddleware],
responses: {
200: {
content: { "application/json": { schema: responseSchema } },
description: "Retrieve the user",
},
},
}),
async (c) => {
// apit hit
//apiHit(c, { endpoint: "api/auth/getUserRoles" });
const authHeader = c.req.header("Authorization");
const token = authHeader?.split("Bearer ")[1] || "";
try {
const secret = process.env.JWT_SECRET!;
if (!secret) {
throw new Error("JWT_SECRET is not defined in environment variables");
}
const payload = verify(token, secret) as CustomJwtPayload;
const canAccess = await roleCheck(payload.user?.user_id);
return c.json(
{
sucess: true,
message: `User ${payload.user?.username} can access`,
data: canAccess,
},
200
);
} catch (error) {
console.log(error);
}
return c.json({ message: "UserRoles coming over" });
}
);
export default app;

View File

@@ -1,95 +1,120 @@
import {createRoute, OpenAPIHono, z} from "@hono/zod-openapi"; import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
import {authMiddleware} from "../../middleware/authMiddleware.js"; import { authMiddleware } from "../../middleware/authMiddleware.js";
import {updateProfile} from "../../controllers/users/updateProfile.js"; import { updateProfile } from "../../controllers/users/updateProfile.js";
import {verify} from "hono/jwt"; import { verify } from "hono/jwt";
import {createLog} from "../../../logger/logger.js"; import { createLog } from "../../../logger/logger.js";
const app = new OpenAPIHono(); const app = new OpenAPIHono();
const UserSchema = z.object({ const UserSchema = z.object({
password: z password: z
.string() .string()
.min(6, {message: "Passwords must be longer than 3 characters"}) .min(6, { message: "Passwords must be longer than 3 characters" })
.regex(/[A-Z]/, {message: "Password must contain at least one uppercase letter"}) .regex(/[A-Z]/, {
.regex(/[\W_]/, {message: "Password must contain at least one special character"}) message: "Password must contain at least one uppercase letter",
.openapi({example: "Password1!"}), })
.regex(/[\W_]/, {
message: "Password must contain at least one special character",
})
.openapi({ example: "Password1!" }),
}); });
app.openapi( app.openapi(
createRoute({ createRoute({
tags: ["User"], tags: ["auth:user"],
summary: "Updates a users Profile", summary: "Updates a users Profile",
description: "Currently you can only update your password over the API", description: "Currently you can only update your password over the API",
method: "post", method: "post",
path: "/", path: "/profile",
middleware: authMiddleware, middleware: authMiddleware,
request: { request: {
body: { body: {
content: { content: {
"application/json": {schema: UserSchema}, "application/json": { schema: UserSchema },
},
},
}, },
responses: { },
200: { },
content: { responses: {
"application/json": { 200: {
schema: z.object({ content: {
message: z.string().optional().openapi({example: "User Profile has been updated"}), "application/json": {
}), schema: z.object({
}, message: z
}, .string()
description: "Sucess return", .optional()
}, .openapi({ example: "User Profile has been updated" }),
401: { }),
content: { },
"application/json": {
schema: z.object({message: z.string().optional().openapi({example: "Unauthenticated"})}),
},
},
description: "Unauthorized",
},
500: {
content: {
"application/json": {
schema: z.object({message: z.string().optional().openapi({example: "Internal Server error"})}),
},
},
description: "Internal Server Error",
},
}, },
}), description: "Sucess return",
async (c) => { },
// make sure we have a vaid user being accessed thats really logged in 401: {
const authHeader = c.req.header("Authorization"); content: {
"application/json": {
schema: z.object({
message: z
.string()
.optional()
.openapi({ example: "Unauthenticated" }),
}),
},
},
description: "Unauthorized",
},
500: {
content: {
"application/json": {
schema: z.object({
message: z
.string()
.optional()
.openapi({ example: "Internal Server error" }),
}),
},
},
description: "Internal Server Error",
},
},
}),
async (c) => {
// make sure we have a vaid user being accessed thats really logged in
const authHeader = c.req.header("Authorization");
if (authHeader?.includes("Basic")) { if (authHeader?.includes("Basic")) {
return c.json({message: "You are a Basic user! Please login to get a token"}, 401); return c.json(
} { message: "You are a Basic user! Please login to get a token" },
401
if (!authHeader) { );
return c.json({message: "Unauthorized"}, 401);
}
const token = authHeader?.split("Bearer ")[1] || "";
let user;
try {
const payload = await verify(token, process.env.JWT_SECRET!);
user = payload.user;
} catch (error) {
createLog("error", "lst", "auth", "Failed session check, user must be logged out");
return c.json({message: "Unauthorized"}, 401);
}
// now pass all the data over to update the user info
try {
const data = await c?.req.json();
await updateProfile(user, data, token);
return c.json({message: "Your profile has been updated"});
} catch (error) {
return c.json({message: "There was an error", error});
}
} }
if (!authHeader) {
return c.json({ message: "Unauthorized" }, 401);
}
const token = authHeader?.split("Bearer ")[1] || "";
let user;
try {
const payload = await verify(token, process.env.JWT_SECRET!);
user = payload.user;
} catch (error) {
createLog(
"error",
"lst",
"auth",
"Failed session check, user must be logged out"
);
return c.json({ message: "Unauthorized" }, 401);
}
// now pass all the data over to update the user info
try {
const data = await c?.req.json();
await updateProfile(user, data, token);
return c.json({ message: "Your profile has been updated" });
} catch (error) {
return c.json({ message: "There was an error", error });
}
}
); );
export default app; export default app;

View File

@@ -0,0 +1,115 @@
import { z, createRoute, OpenAPIHono } from "@hono/zod-openapi";
import { registerUser } from "../../controllers/register.js";
import { authMiddleware } from "../../middleware/authMiddleware.js";
import hasCorrectRole from "../../middleware/roleCheck.js";
const app = new OpenAPIHono();
const UserSchema = z.object({
username: z
.string()
.regex(/^[a-zA-Z0-9_]{3,30}$/)
.openapi({ example: "smith034" }),
email: z.string().email().openapi({ example: "smith@example.com" }),
password: z
.string()
.min(6, { message: "Passwords must be longer than 3 characters" })
.regex(/[A-Z]/, {
message: "Password must contain at least one uppercase letter",
})
.regex(/[\W_]/, {
message: "Password must contain at least one special character",
})
.openapi({ example: "Password1!" }),
});
type User = z.infer<typeof UserSchema>;
const responseSchema = z.object({
success: z.boolean().optional().openapi({ example: true }),
message: z.string().optional().openapi({ example: "User Created" }),
});
app.openapi(
createRoute({
tags: ["Auth:admin"],
summary: "Creates user",
method: "post",
path: "/",
middleware: [
authMiddleware,
hasCorrectRole(["admin", "systemAdmin"], "admin"),
],
request: {
body: {
content: {
"application/json": { schema: UserSchema },
},
},
},
responses: {
200: {
content: { "application/json": { schema: responseSchema } },
description: "Retrieve the user",
},
400: {
content: {
"application/json": {
schema: z.object({
success: z.boolean().openapi({ example: false }),
message: z
.string()
.openapi({ example: "Invalid credentials passed" }),
}),
},
},
description: "Retrieve the user",
},
},
}),
async (c) => {
// apit hit
//apiHit(c, {endpoint: "api/auth/register"});
let { username, email, password } = await c.req.json();
if (!username || !email || !password) {
return c.json({ success: false, message: "Credentials missing" }, 400);
}
// some usernames that should be ignored
const badActors = ["admin", "root"];
if (badActors.includes(username)) {
return c.json(
{
success: false,
message: `${username} is not a valid name to be registerd please try again`,
},
400
);
}
try {
const register = await registerUser(username, password, email);
return c.json(
{
success: register.success,
message: register.message,
user: register?.user,
},
200
);
} catch (error) {
console.log(error);
return c.json(
{
success: false,
message: `${username} already exists please login or reset password, if you feel this is an error please contact your admin.`,
},
400
);
}
}
);
export default app;

View File

@@ -0,0 +1,35 @@
import { z, createRoute, OpenAPIHono } from "@hono/zod-openapi";
import { responses } from "../../../../globalUtils/routeDefs/responses.js";
import { getAllUsers } from "../../controllers/userAdmin/getUsers.js";
import { authMiddleware } from "../../middleware/authMiddleware.js";
import hasCorrectRole from "../../middleware/roleCheck.js";
const app = new OpenAPIHono();
app.openapi(
createRoute({
tags: ["Auth:admin"],
summary: "Gets Users",
method: "get",
path: "/allusers",
middleware: [
authMiddleware,
hasCorrectRole(["admin", "systemAdmin"], "admin"),
],
responses: responses(),
}),
async (c) => {
// apit hit
//apiHit(c, {endpoint: "api/auth/register"});
const allUsers: any = await getAllUsers();
return c.json({
success: allUsers?.success,
message: allUsers?.message,
data: allUsers?.data,
});
}
);
export default app;

View File

@@ -0,0 +1,71 @@
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
import { setUserAccess } from "../../controllers/userRoles/setUserRoles.js";
import { apiHit } from "../../../../globalUtils/apiHits.js";
import { apiReturn } from "../../../../globalUtils/apiReturn.js";
import { authMiddleware } from "../../middleware/authMiddleware.js";
import hasCorrectRole from "../../middleware/roleCheck.js";
import { responses } from "../../../../globalUtils/routeDefs/responses.js";
const app = new OpenAPIHono();
const responseSchema = z.object({
success: z.boolean().openapi({ example: true }),
message: z.string().optional().openapi({ example: "user access" }),
data: z.array(z.object({})).optional().openapi({ example: [] }),
});
const UserAccess = z.object({
username: z
.string()
.regex(/^[a-zA-Z0-9_]{3,30}$/)
.openapi({ example: "smith034" }),
module: z.string().openapi({ example: "production" }),
role: z.string().openapi({ example: "viewer" }),
override: z.string().optional().openapi({ example: "secretString" }),
});
app.openapi(
createRoute({
tags: ["Auth:admin"],
summary: "Sets Users access",
method: "post",
path: "/setuseraccess",
middleware: [
authMiddleware,
hasCorrectRole(["admin", "systemAdmin"], "admin"),
],
description: "When logged in you will be able to grant new permissions",
request: {
body: {
content: {
"application/json": { schema: UserAccess },
},
},
},
responses: responses(),
}),
async (c) => {
//apiHit(c, { endpoint: "api/auth/setUserRoles" });
const { username, module, role, override } = await c.req.json();
try {
const access = await setUserAccess(username, module, role, override);
//return apiReturn(c, true, access?.message, access?.data, 200);
return c.json(
{ success: access.success, message: access.message, data: access.data },
200
);
} catch (error) {
console.log(error);
//return apiReturn(c, false, "Error in setting the user access", error, 400);
return c.json(
{
success: false,
message: "Error in setting the user access",
data: error,
},
400
);
}
}
);
export default app;

View File

@@ -0,0 +1,91 @@
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
import { setUserAccess } from "../../controllers/userRoles/setUserRoles.js";
import { apiHit } from "../../../../globalUtils/apiHits.js";
import { apiReturn } from "../../../../globalUtils/apiReturn.js";
import { authMiddleware } from "../../middleware/authMiddleware.js";
import hasCorrectRole from "../../middleware/roleCheck.js";
import { responses } from "../../../../globalUtils/routeDefs/responses.js";
import { updateUserADM } from "../../controllers/userAdmin/updateUserAdm.js";
const app = new OpenAPIHono();
const responseSchema = z.object({
success: z.boolean().openapi({ example: true }),
message: z.string().optional().openapi({ example: "user access" }),
data: z.array(z.object({})).optional().openapi({ example: [] }),
});
const UserAccess = z.object({
user_id: z.string().openapi({ example: "users UUID" }),
username: z
.string()
.regex(/^[a-zA-Z0-9_]{3,30}$/)
.optional()
.openapi({ example: "smith034" }),
email: z
.string()
.email()
.optional()
.openapi({ example: "smith@example.com" }),
password: z
.string()
.min(6, { message: "Passwords must be longer than 3 characters" })
.regex(/[A-Z]/, {
message: "Password must contain at least one uppercase letter",
})
.regex(/[\W_]/, {
message: "Password must contain at least one special character",
})
.optional()
.openapi({ example: "Password1!" }),
});
app.openapi(
createRoute({
tags: ["Auth:admin"],
summary: "updates a specific user",
method: "post",
path: "/updateuser",
middleware: [
authMiddleware,
hasCorrectRole(["admin", "systemAdmin"], "admin"),
],
//description: "When logged in you will be able to grant new permissions",
request: {
body: {
content: {
"application/json": { schema: UserAccess },
},
},
},
responses: responses(),
}),
async (c) => {
//apiHit(c, { endpoint: "api/auth/setUserRoles" });
const userData = await c.req.json();
try {
const userUPD: any = await updateUserADM(userData);
//return apiReturn(c, true, access?.message, access?.data, 200);
return c.json(
{
success: userUPD.success,
message: userUPD.message,
data: userUPD.data,
},
200
);
} catch (error) {
console.log(error);
//return apiReturn(c, false, "Error in setting the user access", error, 400);
return c.json(
{
success: false,
message: "Error in setting the user access",
data: error,
},
400
);
}
}
);
export default app;

View File

@@ -1,53 +0,0 @@
import {z, createRoute, OpenAPIHono} from "@hono/zod-openapi";
import {apiHit} from "../../../../globalUtils/apiHits.js";
import jwt from "jsonwebtoken";
import {roleCheck} from "../../controllers/userRoles/getUserAccess.js";
import type {CustomJwtPayload} from "../../../../types/jwtToken.js";
import {authMiddleware} from "../../middleware/authMiddleware.js";
const {verify} = jwt;
const app = new OpenAPIHono();
const responseSchema = z.object({
message: z.string().optional().openapi({example: "User Created"}),
});
app.openapi(
createRoute({
tags: ["Auth"],
summary: "Returns the useraccess table",
method: "get",
path: "/",
middleware: authMiddleware,
responses: {
200: {
content: {"application/json": {schema: responseSchema}},
description: "Retrieve the user",
},
},
}),
async (c) => {
// apit hit
apiHit(c, {endpoint: "api/auth/getUserRoles"});
const authHeader = c.req.header("Authorization");
const token = authHeader?.split("Bearer ")[1] || "";
try {
const secret = process.env.JWT_SECRET!;
if (!secret) {
throw new Error("JWT_SECRET is not defined in environment variables");
}
const payload = verify(token, secret) as CustomJwtPayload;
const canAccess = await roleCheck(payload.user?.user_id);
return c.json({sucess: true, message: `User ${payload.user?.username} can access`, data: canAccess}, 200);
} catch (error) {
console.log(error);
}
return c.json({message: "UserRoles coming over"});
}
);
export default app;

View File

@@ -1,65 +0,0 @@
import {createRoute, OpenAPIHono, z} from "@hono/zod-openapi";
import {setUserAccess} from "../../controllers/userRoles/setUserRoles.js";
import {apiHit} from "../../../../globalUtils/apiHits.js";
import {apiReturn} from "../../../../globalUtils/apiReturn.js";
import {authMiddleware} from "../../middleware/authMiddleware.js";
const app = new OpenAPIHono();
const responseSchema = z.object({
success: z.boolean().openapi({example: true}),
message: z.string().optional().openapi({example: "user access"}),
data: z.array(z.object({})).optional().openapi({example: []}),
});
const UserAccess = z.object({
username: z
.string()
.regex(/^[a-zA-Z0-9_]{3,30}$/)
.openapi({example: "smith034"}),
module: z.string().openapi({example: "production"}),
role: z.string().openapi({example: "viewer"}),
override: z.string().optional().openapi({example: "secretString"}),
});
app.openapi(
createRoute({
tags: ["Auth"],
summary: "Sets Users access",
method: "post",
path: "/",
middleware: authMiddleware,
description: "When logged in you will be able to grant new permissions",
request: {
body: {
content: {
"application/json": {schema: UserAccess},
},
},
},
responses: {
200: {
content: {"application/json": {schema: responseSchema}},
description: "Retrieve the user",
},
400: {
content: {"application/json": {schema: responseSchema}},
description: "Failed to get user access",
},
},
}),
async (c) => {
apiHit(c, {endpoint: "api/auth/setUserRoles"});
const {username, module, role, override} = await c.req.json();
try {
const access = await setUserAccess(username, module, role, override);
//return apiReturn(c, true, access?.message, access?.data, 200);
return c.json({success: access.success, message: access.message, data: access.data}, 200);
} catch (error) {
console.log(error);
//return apiReturn(c, false, "Error in setting the user access", error, 400);
return c.json({success: false, message: "Error in setting the user access", data: error}, 400);
}
}
);
export default app;

View File

@@ -1,16 +1,18 @@
import bcrypt from "bcrypt"; import bcrypt from "bcryptjs";
export const checkPassword = async (
currentPassword: string,
dbPassword: string
) => {
let decyptPass = "";
try {
decyptPass = atob(dbPassword);
} catch (error) {
console.log(error);
}
// encypt password
const pass: string | undefined = process.env.SECRET;
export const checkPassword = async (currentPassword: string, dbPassword: string) => { const checked = bcrypt.compareSync(pass + currentPassword, decyptPass);
let decyptPass = "";
try {
decyptPass = atob(dbPassword);
} catch (error) {
console.log(error);
}
// encypt password
const pass: string | undefined = process.env.SECRET;
const checked = bcrypt.compareSync(pass + currentPassword, decyptPass); return checked;
return checked;
}; };

View File

@@ -1,17 +1,17 @@
import bcrypt from "bcrypt"; import bcrypt from "bcryptjs";
export const createPassword = async (password: string) => { export const createPassword = async (password: string) => {
// encypt password // encypt password
let pass: string | undefined = process.env.SECRET; let pass: string | undefined = process.env.SECRET;
let salt: string | undefined = process.env.SALTING; let salt: string | undefined = process.env.SALTING;
if (!pass || !salt) { if (!pass || !salt) {
pass = "error"; pass = "error";
} else { } else {
pass = bcrypt.hashSync(pass + password, parseInt(salt)); pass = bcrypt.hashSync(pass + password, parseInt(salt));
pass = btoa(pass); pass = btoa(pass);
} }
return pass; return pass;
}; };

View File

@@ -55,9 +55,9 @@ app.get(
"nsurlsession", "nsurlsession",
"undici", "undici",
], ],
spec: {
url: "/api/ref", url: "/api/ref",
},
baseServerURL: "https://scalar.com", baseServerURL: "https://scalar.com",
servers: [ servers: [
{ {

View File

@@ -1,7 +1,7 @@
import type {Context} from "hono"; import type {Context} from "hono";
import {db} from "../../../../database/dbclient.js"; import {db} from "../../../../database/dbclient.js";
import {and, eq, gt} from "drizzle-orm"; import {and, eq, gt} from "drizzle-orm";
import {streamSSE} from "hono/streaming"; import {streamSSE, streamText} from "hono/streaming";
import {logs} from "../../../../database/schema/logs.js"; import {logs} from "../../../../database/schema/logs.js";
export async function streamLogs(c: Context) { export async function streamLogs(c: Context) {

View File

@@ -29,7 +29,23 @@ app.openapi(
}), }),
async (c) => { async (c) => {
apiHit(c, {endpoint: `api/logger/logs`}); apiHit(c, {endpoint: `api/logger/logs`});
return streamLogs(c); c.header("Content-Type", "text/event-stream");
c.header("Cache-Control", "no-cache");
c.header("Connection", "keep-alive");
return streamSSE(c, async (stream) => {
let id = 0;
const encoder = new TextEncoder();
while (true) {
const message = `It is ${new Date().toISOString()}`;
await stream.writeSSE({
data: message,
event: "time-update",
id: String(id++),
});
encoder.encode(`data: ${JSON.stringify({type: "progress", data: id})}\n\n`);
await stream.sleep(1000);
}
});
} }
); );
export default app; export default app;

View File

@@ -1,7 +1,7 @@
{ {
"servers": [ "servers": [
{ {
"sName": "test", "sName": "Test",
"serverDNS": "usmcd1vms036", "serverDNS": "usmcd1vms036",
"plantToken": "test3", "plantToken": "test3",
"idAdress": "10.193.0.56", "idAdress": "10.193.0.56",
@@ -33,7 +33,7 @@
"contactPhone": "6366970253", "contactPhone": "6366970253",
"customerTiAcc": "ALPL01BETHINT", "customerTiAcc": "ALPL01BETHINT",
"lstServerPort": "4000", "lstServerPort": "4000",
"active": false, "active": true,
"serverLoc": "E:\\LST\\lstv2", "serverLoc": "E:\\LST\\lstv2",
"oldVersion": "E:\\LST\\lst_backend", "oldVersion": "E:\\LST\\lst_backend",
"shippingHours": "[{\"early\": \"06:30\", \"late\": \"23:00\"}]", "shippingHours": "[{\"early\": \"06:30\", \"late\": \"23:00\"}]",

View File

@@ -1,111 +1,198 @@
import sql from "mssql"; import sql from "mssql";
import {prodSqlConfig} from "./utils/prodServerConfig.js"; import { prodSqlConfig } from "./utils/prodServerConfig.js";
import {createLog} from "../logger/logger.js"; import { createLog } from "../logger/logger.js";
import {db} from "../../../database/dbclient.js"; import { db } from "../../../database/dbclient.js";
import {settings} from "../../../database/schema/settings.js"; import { settings } from "../../../database/schema/settings.js";
import {eq} from "drizzle-orm"; import { eq } from "drizzle-orm";
import {installed} from "../../index.js"; import { installed } from "../../index.js";
import {checkHostnamePort} from "../../globalUtils/pingServer.js"; import { checkHostnamePort } from "../../globalUtils/pingServer.js";
let pool: any; let pool: any;
let connected: boolean = false; let connected: boolean = false;
export const initializeProdPool = async () => { export const initializeProdPool = async () => {
if (!installed) { if (!installed) {
createLog("info", "lst", "sqlProd", "The server was not installed will reconnect in 5 seconds"); createLog(
setTimeout(() => { "info",
initializeProdPool(); "lst",
}, 5 * 1000); "sqlProd",
"The server was not installed will reconnect in 5 seconds"
);
setTimeout(() => {
initializeProdPool();
}, 5 * 1000);
return {success: false, message: "The server is not installed."}; return { success: false, message: "The server is not installed." };
} }
const dbServer = await db.select().from(settings).where(eq(settings.name, "dbServer")); const dbServer = await db
const serverUp = await checkHostnamePort(`${dbServer[0].value}:1433`); .select()
.from(settings)
.where(eq(settings.name, "dbServer"));
const serverUp = await checkHostnamePort(`${dbServer[0].value}:1433`);
if (!serverUp) { if (!serverUp) {
createLog("error", "lst", "server", `The sql ${dbServer[0].value} is not reachable`); createLog(
return {success: false, message: `The sql ${dbServer[0].value} is not reachable`}; "error",
} "lst",
"server",
`The sql ${dbServer[0].value} is not reachable`
);
return {
success: false,
message: `The sql ${dbServer[0].value} is not reachable`,
};
}
// make sure the server is not set to localhost this will prevent some weird issues later but can be localhost on the dev // make sure the server is not set to localhost this will prevent some weird issues later but can be localhost on the dev
const serverLoc = await db.select().from(settings).where(eq(settings.name, "dbServer")); const serverLoc = await db
if (serverLoc[0].value === "localhost" && process.env.NODE_ENV !== "development") { .select()
createLog("error", "lst", "sqlProd", "The server is set to localhost, and you are not in development mode."); .from(settings)
return {success: false, message: "The server is set to localhost, and you are not in development mode."}; .where(eq(settings.name, "dbServer"));
} if (
serverLoc[0].value === "localhost" &&
process.env.NODE_ENV !== "development"
) {
createLog(
"error",
"lst",
"sqlProd",
"The server is set to localhost, and you are not in development mode."
);
return {
success: false,
message:
"The server is set to localhost, and you are not in development mode.",
};
}
// if you were restarting from the endpoint you get this lovely error // if you were restarting from the endpoint you get this lovely error
if (connected) { if (connected) {
createLog("error", "lst", "sqlProd", "There is already a connection."); createLog("error", "lst", "sqlProd", "There is already a connection.");
return {success: false, message: "There is already a connection."}; return { success: false, message: "There is already a connection." };
} }
try { try {
const config = await prodSqlConfig(); const config = await prodSqlConfig();
pool = await sql.connect(config!); pool = await sql.connect(config!);
createLog("info", "lst", "sqlProd", `Connected to ${config?.server}, and looking at ${config?.database}`); createLog(
connected = true; "info",
return {success: true, message: "The sql server connection has been closed"}; "lst",
} catch (error) { "sqlProd",
createLog("error", "lst", "sqlProd", `${JSON.stringify(error)}, "There was an error connecting to the pool."`); `Connected to ${config?.server}, and looking at ${config?.database}`
throw new Error("There was an error closing the sql connection"); );
} connected = true;
return {
success: true,
message: "The sql server connection has been closed",
};
} catch (error) {
createLog(
"error",
"lst",
"sqlProd",
`${JSON.stringify(error)}, "There was an error connecting to the pool."`
);
throw new Error("There was an error closing the sql connection");
}
}; };
export const closePool = async () => { export const closePool = async () => {
try { if (!connected) {
await pool.close(); createLog(
createLog("info", "lst", "sqlProd", "Connection pool closed"); "error",
connected = false; "lst",
return {success: true, message: "The sql server connection has been closed"}; "sqlProd",
} catch (error) { "There is no connection a connection."
createLog( );
"error", return { success: false, message: "There is already a connection." };
"lst", }
"sqlProd", try {
`${JSON.stringify(error)}, "There was an error closing the sql connection"` await pool.close();
); createLog("info", "lst", "sqlProd", "Connection pool closed");
throw new Error("There was an error closing the sql connection"); connected = false;
} return {
success: true,
message: "The sql server connection has been closed",
};
} catch (error) {
createLog(
"error",
"lst",
"sqlProd",
`${JSON.stringify(
error
)}, "There was an error closing the sql connection"`
);
throw new Error("There was an error closing the sql connection");
}
}; };
export async function query(queryToRun: string, name: string) { export async function query(queryToRun: string, name: string) {
/** /**
* Just an extra catch incase someone tried to run a query while we were not connected to the server or sql server * Just an extra catch incase someone tried to run a query while we were not connected to the server or sql server
*/ */
const dbServer = await db.select().from(settings).where(eq(settings.name, "dbServer")); const dbServer = await db
const serverUp = await checkHostnamePort(`${dbServer[0].value}:1433`); .select()
.from(settings)
.where(eq(settings.name, "dbServer"));
const serverUp = await checkHostnamePort(`${dbServer[0].value}:1433`);
if (!serverUp) { if (!serverUp) {
createLog("error", "lst", "server", `The sql ${dbServer[0].value} is not reachable`); createLog(
return {success: false, message: `The sql ${dbServer[0].value} is not reachable`}; "error",
"lst",
"server",
`The sql ${dbServer[0].value} is not reachable`
);
return {
success: false,
message: `The sql ${dbServer[0].value} is not reachable`,
};
}
if (!connected) {
createLog(
"error",
"lst",
"server",
`The sql ${dbServer[0].value} is not connected`
);
return {
success: false,
message: `The sql ${dbServer[0].value} is not not connected`,
};
}
/**
* We no longer need to send over the plant token change as we do it inside the query function.
*/
const plantToken = await db
.select()
.from(settings)
.where(eq(settings.name, "plantToken"));
const query = queryToRun.replaceAll("test1", plantToken[0].value);
try {
const result = await pool.request().query(query);
return result.recordset;
} catch (error: any) {
if (error.code === "ETIMEOUT") {
createLog(
"error",
"lst",
"sqlProd",
`${JSON.stringify(error)}, ${name} did not run due to a timeout.`
);
throw new Error(`${name} query did not run due to a timeout.`);
} }
if (!connected) { if (error.code === "EREQUEST") {
createLog("error", "lst", "server", `The sql ${dbServer[0].value} is not connected`); throw new Error(
return {success: false, message: `The sql ${dbServer[0].value} is not not connected`}; `${name} encoutnered an error ${error.originalError.info.message}`
);
} }
/**
* We no longer need to send over the plant token change as we do it inside the query function.
*/
const plantToken = await db.select().from(settings).where(eq(settings.name, "plantToken"));
const query = queryToRun.replaceAll("test1", plantToken[0].value);
try { //console.log(error.originalError.info.message);
const result = await pool.request().query(query); //EREQUEST
//throw new Error(`${name} encoutnered an error ${error.code}`);
return result.recordset; }
} catch (error: any) {
if (error.code === "ETIMEOUT") {
createLog("error", "lst", "sqlProd", `${JSON.stringify(error)}, ${name} did not run due to a timeout.`);
throw new Error(`${name} query did not run due to a timeout.`);
}
if (error.code === "EREQUEST") {
throw new Error(`${name} encoutnered an error ${error.originalError.info.message}`);
}
//console.log(error.originalError.info.message);
//EREQUEST
//throw new Error(`${name} encoutnered an error ${error.code}`);
}
} }

View File

@@ -1,10 +1,11 @@
import type {Roles} from "./roles.js"; import type { Roles } from "./roles.js";
export type User = { export type User = {
user_id?: string; user_id?: string;
email?: string; email?: string;
username?: string; username?: string;
roles?: Roles[]; roles?: Roles[];
role?: string; role?: string;
prod?: string; prod?: string;
password?: string;
}; };

View File

@@ -1,20 +1,20 @@
{ {
"compilerOptions": { "compilerOptions": {
"target": "ESNext", "target": "ESNext",
"module": "NodeNext", "module": "NodeNext",
"moduleResolution": "nodenext", "moduleResolution": "nodenext",
"strict": true, "strict": true,
"verbatimModuleSyntax": true, "verbatimModuleSyntax": true,
"skipLibCheck": true, "skipLibCheck": true,
"types": ["node"], "types": ["node"],
"jsx": "react-jsx", "jsx": "react-jsx",
"jsxImportSource": "hono/jsx", "jsxImportSource": "hono/jsx",
"outDir": "./dist", "outDir": "./dist",
"removeComments": true, "removeComments": true,
"allowJs": true, "allowJs": true,
"esModuleInterop": true, "esModuleInterop": true,
"resolveJsonModule": true "resolveJsonModule": true
}, },
"include": ["server", "scripts/**/*.ts"],
"exclude": ["node_modules", "frontend", "dist", "testFiles"] "exclude": ["node_modules", "frontend", "dist", "testFiles"]
} }