Moved away from SSR to regular Node API server.
This commit is contained in:
parent
9aea69c7be
commit
83d93aefc0
30 changed files with 939 additions and 1024 deletions
|
@ -43,7 +43,7 @@ docker compose up -d
|
|||
pnpm run dev
|
||||
```
|
||||
|
||||
This will start the PostgreSQL server on `localhost:5432` and the application server accessible at [http://localhost:9100](http://localhost:9100).
|
||||
This will start the PostgreSQL server on `localhost:5432` the API server on `localhost:8000` (shouldn't need to directly work with this) and the application server accessible at [http://localhost:9000](http://localhost:9000).
|
||||
|
||||
I recommend using [Postico](https://eggerapps.io/postico/) for Mac or [pgAdmin](https://www.pgadmin.org/) for Windows to manage the PostgreSQL database.
|
||||
|
||||
|
@ -54,5 +54,3 @@ To create a production build of the application, run:
|
|||
```bash
|
||||
pnpm run build
|
||||
```
|
||||
|
||||
This command compiles and optimizes the application for deployment. The output files are usually placed in the `dist` directory.
|
|
@ -8,8 +8,8 @@
|
|||
"private": true,
|
||||
"scripts": {
|
||||
"test": "echo \"No test specified\" && exit 0",
|
||||
"dev": "pnpm prisma migrate dev && quasar dev -m ssr",
|
||||
"build": "quasar build -m ssr",
|
||||
"dev": "pnpm i && pnpm prisma migrate dev && concurrently \"quasar dev -m spa\" \"nodemon src-server/server.js\"",
|
||||
"build": "quasar build -m spa",
|
||||
"postinstall": "quasar prepare"
|
||||
},
|
||||
"dependencies": {
|
||||
|
@ -43,9 +43,11 @@
|
|||
"@types/uuid": "^10.0.0",
|
||||
"@vue/eslint-config-prettier": "^10.2.0",
|
||||
"autoprefixer": "^10.4.2",
|
||||
"concurrently": "^9.1.2",
|
||||
"eslint": "^9.25.1",
|
||||
"eslint-plugin-vue": "^10.0.0",
|
||||
"globals": "^16.0.0",
|
||||
"nodemon": "^3.1.10",
|
||||
"postcss": "^8.4.14",
|
||||
"prettier": "^3.5.3",
|
||||
"prisma": "^6.6.0",
|
||||
|
|
112
pnpm-lock.yaml
generated
112
pnpm-lock.yaml
generated
|
@ -93,6 +93,9 @@ importers:
|
|||
autoprefixer:
|
||||
specifier: ^10.4.2
|
||||
version: 10.4.21(postcss@8.5.3)
|
||||
concurrently:
|
||||
specifier: ^9.1.2
|
||||
version: 9.1.2
|
||||
eslint:
|
||||
specifier: ^9.25.1
|
||||
version: 9.25.1
|
||||
|
@ -102,6 +105,9 @@ importers:
|
|||
globals:
|
||||
specifier: ^16.0.0
|
||||
version: 16.0.0
|
||||
nodemon:
|
||||
specifier: ^3.1.10
|
||||
version: 3.1.10
|
||||
postcss:
|
||||
specifier: ^8.4.14
|
||||
version: 8.5.3
|
||||
|
@ -1065,6 +1071,11 @@ packages:
|
|||
concat-map@0.0.1:
|
||||
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
|
||||
|
||||
concurrently@9.1.2:
|
||||
resolution: {integrity: sha512-H9MWcoPsYddwbOGM6difjVwVZHl63nwMEwDJG/L7VGtuaJhb12h2caPG2tVPWs7emuYix252iGfqOyrz1GczTQ==}
|
||||
engines: {node: '>=18'}
|
||||
hasBin: true
|
||||
|
||||
confbox@0.1.8:
|
||||
resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==}
|
||||
|
||||
|
@ -1590,6 +1601,10 @@ packages:
|
|||
resolution: {integrity: sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
|
||||
has-flag@3.0.0:
|
||||
resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==}
|
||||
engines: {node: '>=4'}
|
||||
|
||||
has-flag@4.0.0:
|
||||
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
|
||||
engines: {node: '>=8'}
|
||||
|
@ -1647,6 +1662,9 @@ packages:
|
|||
ieee754@1.2.1:
|
||||
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
|
||||
|
||||
ignore-by-default@1.0.1:
|
||||
resolution: {integrity: sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==}
|
||||
|
||||
ignore@5.3.2:
|
||||
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
|
||||
engines: {node: '>= 4'}
|
||||
|
@ -2008,6 +2026,11 @@ packages:
|
|||
resolution: {integrity: sha512-psAuZdTIRN08HKVd/E8ObdV6NO7NTBY3KsC30F7M4H1OnmLCUNaS56FpYxyb26zWLSyYF9Ozch9KYHhHegsiOQ==}
|
||||
engines: {node: '>=6.0.0'}
|
||||
|
||||
nodemon@3.1.10:
|
||||
resolution: {integrity: sha512-WDjw3pJ0/0jMFmyNDp3gvY2YizjLmmOUQo6DEBY+JgdvW/yQ9mEeSw6H5ythl5Ny2ytb7f9C2nIbjSxMNzbJXw==}
|
||||
engines: {node: '>=10'}
|
||||
hasBin: true
|
||||
|
||||
normalize-path@3.0.0:
|
||||
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
@ -2215,6 +2238,9 @@ packages:
|
|||
proxy-from-env@1.1.0:
|
||||
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
|
||||
|
||||
pstree.remy@1.1.8:
|
||||
resolution: {integrity: sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==}
|
||||
|
||||
pump@3.0.2:
|
||||
resolution: {integrity: sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==}
|
||||
|
||||
|
@ -2537,6 +2563,10 @@ packages:
|
|||
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
shell-quote@1.8.2:
|
||||
resolution: {integrity: sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
side-channel-list@1.0.0:
|
||||
resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
@ -2566,6 +2596,10 @@ packages:
|
|||
simple-get@4.0.1:
|
||||
resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==}
|
||||
|
||||
simple-update-notifier@2.0.0:
|
||||
resolution: {integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
source-map-js@1.2.1:
|
||||
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
@ -2630,6 +2664,10 @@ packages:
|
|||
resolution: {integrity: sha512-5JRxVqC8I8NuOUjzBbvVJAKNM8qoVuH0O77h4WInc/qC2q5IreqKxYwgkga3PfA22OayK2ikceb/B26dztPl+Q==}
|
||||
engines: {node: '>=16'}
|
||||
|
||||
supports-color@5.5.0:
|
||||
resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==}
|
||||
engines: {node: '>=4'}
|
||||
|
||||
supports-color@7.2.0:
|
||||
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
|
||||
engines: {node: '>=8'}
|
||||
|
@ -2694,9 +2732,17 @@ packages:
|
|||
resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
|
||||
engines: {node: '>=0.6'}
|
||||
|
||||
touch@3.1.1:
|
||||
resolution: {integrity: sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==}
|
||||
hasBin: true
|
||||
|
||||
tr46@0.0.3:
|
||||
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
|
||||
|
||||
tree-kill@1.2.2:
|
||||
resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==}
|
||||
hasBin: true
|
||||
|
||||
ts-api-utils@2.1.0:
|
||||
resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==}
|
||||
engines: {node: '>=18.12'}
|
||||
|
@ -2748,6 +2794,9 @@ packages:
|
|||
resolution: {integrity: sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==}
|
||||
engines: {node: '>= 0.8'}
|
||||
|
||||
undefsafe@2.0.5:
|
||||
resolution: {integrity: sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==}
|
||||
|
||||
undici-types@6.21.0:
|
||||
resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
|
||||
|
||||
|
@ -3102,7 +3151,7 @@ snapshots:
|
|||
'@eslint/config-array@0.20.0':
|
||||
dependencies:
|
||||
'@eslint/object-schema': 2.1.6
|
||||
debug: 4.4.0
|
||||
debug: 4.4.0(supports-color@5.5.0)
|
||||
minimatch: 3.1.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
@ -3116,7 +3165,7 @@ snapshots:
|
|||
'@eslint/eslintrc@3.3.1':
|
||||
dependencies:
|
||||
ajv: 6.12.6
|
||||
debug: 4.4.0
|
||||
debug: 4.4.0(supports-color@5.5.0)
|
||||
espree: 10.3.0
|
||||
globals: 14.0.0
|
||||
ignore: 5.3.2
|
||||
|
@ -3575,7 +3624,7 @@ snapshots:
|
|||
dependencies:
|
||||
'@typescript-eslint/types': 8.31.0
|
||||
'@typescript-eslint/visitor-keys': 8.31.0
|
||||
debug: 4.4.0
|
||||
debug: 4.4.0(supports-color@5.5.0)
|
||||
fast-glob: 3.3.3
|
||||
is-glob: 4.0.3
|
||||
minimatch: 9.0.5
|
||||
|
@ -4008,6 +4057,16 @@ snapshots:
|
|||
|
||||
concat-map@0.0.1: {}
|
||||
|
||||
concurrently@9.1.2:
|
||||
dependencies:
|
||||
chalk: 4.1.2
|
||||
lodash: 4.17.21
|
||||
rxjs: 7.8.2
|
||||
shell-quote: 1.8.2
|
||||
supports-color: 8.1.1
|
||||
tree-kill: 1.2.2
|
||||
yargs: 17.7.2
|
||||
|
||||
confbox@0.1.8: {}
|
||||
|
||||
content-disposition@0.5.4:
|
||||
|
@ -4055,9 +4114,11 @@ snapshots:
|
|||
dependencies:
|
||||
ms: 2.0.0
|
||||
|
||||
debug@4.4.0:
|
||||
debug@4.4.0(supports-color@5.5.0):
|
||||
dependencies:
|
||||
ms: 2.1.3
|
||||
optionalDependencies:
|
||||
supports-color: 5.5.0
|
||||
|
||||
decompress-response@6.0.0:
|
||||
dependencies:
|
||||
|
@ -4201,7 +4262,7 @@ snapshots:
|
|||
|
||||
esbuild-register@3.6.0(esbuild@0.25.3):
|
||||
dependencies:
|
||||
debug: 4.4.0
|
||||
debug: 4.4.0(supports-color@5.5.0)
|
||||
esbuild: 0.25.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
@ -4292,7 +4353,7 @@ snapshots:
|
|||
ajv: 6.12.6
|
||||
chalk: 4.1.2
|
||||
cross-spawn: 7.0.6
|
||||
debug: 4.4.0
|
||||
debug: 4.4.0(supports-color@5.5.0)
|
||||
escape-string-regexp: 4.0.0
|
||||
eslint-scope: 8.3.0
|
||||
eslint-visitor-keys: 4.2.0
|
||||
|
@ -4597,6 +4658,8 @@ snapshots:
|
|||
- encoding
|
||||
- supports-color
|
||||
|
||||
has-flag@3.0.0: {}
|
||||
|
||||
has-flag@4.0.0: {}
|
||||
|
||||
has-property-descriptors@1.0.2:
|
||||
|
@ -4653,7 +4716,7 @@ snapshots:
|
|||
https-proxy-agent@7.0.6:
|
||||
dependencies:
|
||||
agent-base: 7.1.3
|
||||
debug: 4.4.0
|
||||
debug: 4.4.0(supports-color@5.5.0)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
|
@ -4667,6 +4730,8 @@ snapshots:
|
|||
|
||||
ieee754@1.2.1: {}
|
||||
|
||||
ignore-by-default@1.0.1: {}
|
||||
|
||||
ignore@5.3.2: {}
|
||||
|
||||
immutable@5.1.1: {}
|
||||
|
@ -4990,6 +5055,19 @@ snapshots:
|
|||
|
||||
nodemailer@6.9.16: {}
|
||||
|
||||
nodemon@3.1.10:
|
||||
dependencies:
|
||||
chokidar: 3.6.0
|
||||
debug: 4.4.0(supports-color@5.5.0)
|
||||
ignore-by-default: 1.0.1
|
||||
minimatch: 3.1.2
|
||||
pstree.remy: 1.1.8
|
||||
semver: 7.7.1
|
||||
simple-update-notifier: 2.0.0
|
||||
supports-color: 5.5.0
|
||||
touch: 3.1.1
|
||||
undefsafe: 2.0.5
|
||||
|
||||
normalize-path@3.0.0: {}
|
||||
|
||||
normalize-range@0.1.2: {}
|
||||
|
@ -5207,6 +5285,8 @@ snapshots:
|
|||
|
||||
proxy-from-env@1.1.0: {}
|
||||
|
||||
pstree.remy@1.1.8: {}
|
||||
|
||||
pump@3.0.2:
|
||||
dependencies:
|
||||
end-of-stream: 1.4.4
|
||||
|
@ -5533,6 +5613,8 @@ snapshots:
|
|||
|
||||
shebang-regex@3.0.0: {}
|
||||
|
||||
shell-quote@1.8.2: {}
|
||||
|
||||
side-channel-list@1.0.0:
|
||||
dependencies:
|
||||
es-errors: 1.3.0
|
||||
|
@ -5573,6 +5655,10 @@ snapshots:
|
|||
once: 1.4.0
|
||||
simple-concat: 1.0.1
|
||||
|
||||
simple-update-notifier@2.0.0:
|
||||
dependencies:
|
||||
semver: 7.7.1
|
||||
|
||||
source-map-js@1.2.1: {}
|
||||
|
||||
source-map-support@0.5.21:
|
||||
|
@ -5633,6 +5719,10 @@ snapshots:
|
|||
dependencies:
|
||||
copy-anything: 3.0.5
|
||||
|
||||
supports-color@5.5.0:
|
||||
dependencies:
|
||||
has-flag: 3.0.0
|
||||
|
||||
supports-color@7.2.0:
|
||||
dependencies:
|
||||
has-flag: 4.0.0
|
||||
|
@ -5705,8 +5795,12 @@ snapshots:
|
|||
|
||||
toidentifier@1.0.1: {}
|
||||
|
||||
touch@3.1.1: {}
|
||||
|
||||
tr46@0.0.3: {}
|
||||
|
||||
tree-kill@1.2.2: {}
|
||||
|
||||
ts-api-utils@2.1.0(typescript@5.8.3):
|
||||
dependencies:
|
||||
typescript: 5.8.3
|
||||
|
@ -5744,6 +5838,8 @@ snapshots:
|
|||
dependencies:
|
||||
random-bytes: 1.0.0
|
||||
|
||||
undefsafe@2.0.5: {}
|
||||
|
||||
undici-types@6.21.0: {}
|
||||
|
||||
unicode-properties@1.4.1:
|
||||
|
@ -5825,7 +5921,7 @@ snapshots:
|
|||
|
||||
vue-eslint-parser@10.1.3(eslint@9.25.1):
|
||||
dependencies:
|
||||
debug: 4.4.0
|
||||
debug: 4.4.0(supports-color@5.5.0)
|
||||
eslint: 9.25.1
|
||||
eslint-scope: 8.3.0
|
||||
eslint-visitor-keys: 4.2.0
|
||||
|
|
|
@ -76,7 +76,15 @@ export default defineConfig((/* ctx */) =>
|
|||
// Full list of options: https://v2.quasar.dev/quasar-cli-vite/quasar-config-file#devserver
|
||||
devServer: {
|
||||
// https: true,
|
||||
open: true // opens browser window automatically
|
||||
open: true, // opens browser window automatically
|
||||
|
||||
//Add a proxy from /api to the backend server for dev usage
|
||||
proxy: {
|
||||
'/api': {
|
||||
target : 'http://localhost:8000',
|
||||
changeOrigin: true
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// https://v2.quasar.dev/quasar-cli-vite/quasar-config-file#framework
|
||||
|
|
|
@ -426,11 +426,18 @@ router.delete('/passkeys/:credentialID', async(req, res) =>
|
|||
});
|
||||
|
||||
// Check Authentication Status
|
||||
router.get('/status', (req, res) =>
|
||||
router.get('/status', async(req, res) =>
|
||||
{
|
||||
if (req.session.loggedInUserId)
|
||||
{
|
||||
return res.json({ status: 'authenticated' });
|
||||
const user = await getUserById(req.session.loggedInUserId);
|
||||
if (!user)
|
||||
{
|
||||
req.session.destroy(err =>
|
||||
{});
|
||||
return res.status(401).json({ status: 'unauthenticated' });
|
||||
}
|
||||
return res.json({ status: 'authenticated', user: { id: user.id, username: user.username, email: user.email } });
|
||||
}
|
||||
res.json({ status: 'unauthenticated' });
|
||||
});
|
100
src-server/server.js
Normal file
100
src-server/server.js
Normal file
|
@ -0,0 +1,100 @@
|
|||
/**
|
||||
* More info about this file:
|
||||
* https://v2.quasar.dev/quasar-cli-vite/developing-ssr/ssr-webserver
|
||||
*
|
||||
* Runs in Node context.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Make sure to yarn add / npm install (in your project root)
|
||||
* anything you import here (except for express and compression).
|
||||
*/
|
||||
import express from 'express';
|
||||
import compression from 'compression';
|
||||
import session from 'express-session'; // Added for session management
|
||||
import { v4 as uuidv4 } from 'uuid'; // Added for generating session IDs
|
||||
import apiRoutes from './routes/api.js';
|
||||
import authRoutes from './routes/auth.js'; // Added for WebAuthn routes
|
||||
import chatRoutes from './routes/chat.js'; // Added for Chat routes
|
||||
import cron from 'node-cron';
|
||||
import { generateAndStoreMantisSummary } from './services/mantisSummarizer.js';
|
||||
|
||||
// Define Relying Party details (Update with your actual details)
|
||||
export const rpID = process.env.NODE_ENV === 'production' ? 'your-production-domain.com' : 'localhost';
|
||||
export const rpName = 'StylePoint';
|
||||
export const origin = process.env.NODE_ENV === 'production' ? `https://${rpID}` : `http://${rpID}:9000`;
|
||||
|
||||
// In-memory store for challenges (Replace with a persistent store in production)
|
||||
export const challengeStore = new Map();
|
||||
|
||||
const app = express();
|
||||
|
||||
// Session middleware configuration
|
||||
app.use(session({
|
||||
genid: (req) => uuidv4(), // Use UUIDs for session IDs
|
||||
secret: process.env.SESSION_SECRET || 'a-very-strong-secret-key', // Use an environment variable for the secret
|
||||
resave: false,
|
||||
saveUninitialized: true,
|
||||
cookie: {
|
||||
secure: process.env.NODE_ENV === 'production', // Use secure cookies in production
|
||||
httpOnly: true,
|
||||
maxAge: 1000 * 60 * 60 * 24 // 1 day
|
||||
}
|
||||
}));
|
||||
|
||||
// Initialize the database (now synchronous)
|
||||
try
|
||||
{
|
||||
console.log('Prisma Client is ready.'); // Log Prisma readiness
|
||||
|
||||
// Schedule the Mantis summary task after DB initialization
|
||||
// Run daily at 1:00 AM server time (adjust as needed)
|
||||
cron.schedule('0 1 * * *', async() =>
|
||||
{
|
||||
console.log('Running scheduled Mantis summary task...');
|
||||
try
|
||||
{
|
||||
await generateAndStoreMantisSummary();
|
||||
console.log('Scheduled Mantis summary task completed.');
|
||||
}
|
||||
catch (error)
|
||||
{
|
||||
console.error('Error running scheduled Mantis summary task:', error);
|
||||
}
|
||||
}, {
|
||||
scheduled: true,
|
||||
timezone: 'Europe/London' // Example: Set to your server's timezone
|
||||
});
|
||||
}
|
||||
catch (error)
|
||||
{
|
||||
console.error('Error during server setup:', error);
|
||||
// Optionally handle the error more gracefully, e.g., prevent server start
|
||||
process.exit(1); // Exit if setup fails
|
||||
}
|
||||
|
||||
// attackers can use this header to detect apps running Express
|
||||
// and then launch specifically-targeted attacks
|
||||
app.disable('x-powered-by');
|
||||
|
||||
// Add JSON body parsing middleware
|
||||
app.use(express.json());
|
||||
|
||||
// Add API routes
|
||||
app.use('/api', apiRoutes);
|
||||
app.use('/api/auth', authRoutes);
|
||||
app.use('/api/chat', chatRoutes);
|
||||
|
||||
// place here any middlewares that
|
||||
// absolutely need to run before anything else
|
||||
if (process.env.PROD)
|
||||
{
|
||||
app.use(compression());
|
||||
}
|
||||
|
||||
app.use(express.static('public', { index: false }));
|
||||
|
||||
app.listen(8000, () =>
|
||||
{
|
||||
console.log('Server is running on http://localhost:8000');
|
||||
});
|
|
@ -10,6 +10,8 @@ export async function askGemini(content)
|
|||
|
||||
const GOOGLE_API_KEY = await getSetting('GEMINI_API_KEY');
|
||||
|
||||
console.log('Google API Key:', GOOGLE_API_KEY); // Debugging line to check the key
|
||||
|
||||
if (!GOOGLE_API_KEY)
|
||||
{
|
||||
throw new Error('Google API key is not set in the database.');
|
||||
|
@ -62,17 +64,7 @@ export async function askGeminiChat(threadId, content)
|
|||
messages = messages.slice(0, -1);
|
||||
}
|
||||
|
||||
const setting = await prisma.setting.findUnique({
|
||||
where: { key: 'GEMINI_API_KEY' },
|
||||
select: { value: true }
|
||||
});
|
||||
|
||||
if (!setting)
|
||||
{
|
||||
throw new Error('Google API key is not set in the database.');
|
||||
}
|
||||
|
||||
const GOOGLE_API_KEY = setting.value;
|
||||
const GOOGLE_API_KEY = await getSetting('GEMINI_API_KEY');
|
||||
|
||||
const ai = GOOGLE_API_KEY ? new GoogleGenAI({
|
||||
apiKey: GOOGLE_API_KEY,
|
|
@ -1,71 +0,0 @@
|
|||
import { defineSsrMiddleware } from '#q-app/wrappers';
|
||||
|
||||
// This middleware should execute as last one
|
||||
// since it captures everything and tries to
|
||||
// render the page with Vue
|
||||
|
||||
export default defineSsrMiddleware(({ app, resolve, render, serve }) =>
|
||||
{
|
||||
// we capture any other Express route and hand it
|
||||
// over to Vue and Vue Router to render our page
|
||||
app.get(resolve.urlPath('*'), (req, res) =>
|
||||
{
|
||||
res.setHeader('Content-Type', 'text/html');
|
||||
|
||||
render(/* the ssrContext: */ { req, res })
|
||||
.then(html =>
|
||||
{
|
||||
// now let's send the rendered html to the client
|
||||
res.send(html);
|
||||
})
|
||||
.catch(err =>
|
||||
{
|
||||
// oops, we had an error while rendering the page
|
||||
|
||||
// we were told to redirect to another URL
|
||||
if (err.url)
|
||||
{
|
||||
if (err.code)
|
||||
{
|
||||
res.redirect(err.code, err.url);
|
||||
}
|
||||
else
|
||||
{
|
||||
res.redirect(err.url);
|
||||
}
|
||||
}
|
||||
else if (err.code === 404)
|
||||
{
|
||||
// Should reach here only if no "catch-all" route
|
||||
// is defined in /src/routes
|
||||
res.status(404).send('404 | Page Not Found');
|
||||
}
|
||||
else if (process.env.DEV)
|
||||
{
|
||||
// well, we treat any other code as error;
|
||||
// if we're in dev mode, then we can use Quasar CLI
|
||||
// to display a nice error page that contains the stack
|
||||
// and other useful information
|
||||
|
||||
// serve.error is available on dev only
|
||||
serve.error({ err, req, res });
|
||||
}
|
||||
else
|
||||
{
|
||||
// we're in production, so we should have another method
|
||||
// to display something to the client when we encounter an error
|
||||
// (for security reasons, it's not ok to display the same wealth
|
||||
// of information as we do in development)
|
||||
|
||||
// Render Error Page on production or
|
||||
// create a route (/src/routes) for an error page and redirect to it
|
||||
res.status(500).send('500 | Internal Server Error');
|
||||
|
||||
if (process.env.DEBUGGING)
|
||||
{
|
||||
console.error(err.stack);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,241 +0,0 @@
|
|||
/**
|
||||
* More info about this file:
|
||||
* https://v2.quasar.dev/quasar-cli-vite/developing-ssr/ssr-webserver
|
||||
*
|
||||
* Runs in Node context.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Make sure to yarn add / npm install (in your project root)
|
||||
* anything you import here (except for express and compression).
|
||||
*/
|
||||
import express from 'express';
|
||||
import compression from 'compression';
|
||||
import session from 'express-session'; // Added for session management
|
||||
import { v4 as uuidv4 } from 'uuid'; // Added for generating session IDs
|
||||
import {
|
||||
defineSsrCreate,
|
||||
defineSsrListen,
|
||||
defineSsrClose,
|
||||
defineSsrServeStaticContent,
|
||||
defineSsrRenderPreloadTag
|
||||
} from '#q-app/wrappers';
|
||||
|
||||
import prisma from './database.js'; // Import the prisma client instance
|
||||
import apiRoutes from './routes/api.js';
|
||||
import authRoutes from './routes/auth.js'; // Added for WebAuthn routes
|
||||
import chatRoutes from './routes/chat.js'; // Added for Chat routes
|
||||
import cron from 'node-cron';
|
||||
import { generateAndStoreMantisSummary } from './services/mantisSummarizer.js';
|
||||
|
||||
// Define Relying Party details (Update with your actual details)
|
||||
export const rpID = process.env.NODE_ENV === 'production' ? 'your-production-domain.com' : 'localhost';
|
||||
export const rpName = 'StylePoint';
|
||||
export const origin = process.env.NODE_ENV === 'production' ? `https://${rpID}` : `http://${rpID}:9100`;
|
||||
|
||||
// In-memory store for challenges (Replace with a persistent store in production)
|
||||
export const challengeStore = new Map();
|
||||
|
||||
/**
|
||||
* Create your webserver and return its instance.
|
||||
* If needed, prepare your webserver to receive
|
||||
* connect-like middlewares.
|
||||
*
|
||||
* Can be async: defineSsrCreate(async ({ ... }) => { ... })
|
||||
*/
|
||||
export const create = defineSsrCreate((/* { ... } */) =>
|
||||
{
|
||||
const app = express();
|
||||
|
||||
// Session middleware configuration
|
||||
app.use(session({
|
||||
genid: (req) => uuidv4(), // Use UUIDs for session IDs
|
||||
secret: process.env.SESSION_SECRET || 'a-very-strong-secret-key', // Use an environment variable for the secret
|
||||
resave: false,
|
||||
saveUninitialized: true,
|
||||
cookie: {
|
||||
secure: process.env.NODE_ENV === 'production', // Use secure cookies in production
|
||||
httpOnly: true,
|
||||
maxAge: 1000 * 60 * 60 * 24 // 1 day
|
||||
}
|
||||
}));
|
||||
|
||||
// Initialize the database (now synchronous)
|
||||
try
|
||||
{
|
||||
console.log('Prisma Client is ready.'); // Log Prisma readiness
|
||||
|
||||
// Schedule the Mantis summary task after DB initialization
|
||||
// Run daily at 1:00 AM server time (adjust as needed)
|
||||
cron.schedule('0 1 * * *', async() =>
|
||||
{
|
||||
console.log('Running scheduled Mantis summary task...');
|
||||
try
|
||||
{
|
||||
await generateAndStoreMantisSummary();
|
||||
console.log('Scheduled Mantis summary task completed.');
|
||||
}
|
||||
catch (error)
|
||||
{
|
||||
console.error('Error running scheduled Mantis summary task:', error);
|
||||
}
|
||||
}, {
|
||||
scheduled: true,
|
||||
timezone: 'Europe/London' // Example: Set to your server's timezone
|
||||
});
|
||||
console.log('Mantis summary cron job scheduled.');
|
||||
|
||||
// Optional: Run once immediately on server start if needed
|
||||
generateAndStoreMantisSummary().catch(err => console.error('Initial Mantis summary failed:', err));
|
||||
|
||||
}
|
||||
catch (error)
|
||||
{
|
||||
console.error('Error during server setup:', error);
|
||||
// Optionally handle the error more gracefully, e.g., prevent server start
|
||||
process.exit(1); // Exit if setup fails
|
||||
}
|
||||
|
||||
// attackers can use this header to detect apps running Express
|
||||
// and then launch specifically-targeted attacks
|
||||
app.disable('x-powered-by');
|
||||
|
||||
// Add JSON body parsing middleware
|
||||
app.use(express.json());
|
||||
|
||||
// Add API routes
|
||||
app.use('/api', apiRoutes);
|
||||
app.use('/auth', authRoutes); // Added WebAuthn auth routes
|
||||
app.use('/api/chat', chatRoutes); // Added Chat routes
|
||||
|
||||
// place here any middlewares that
|
||||
// absolutely need to run before anything else
|
||||
if (process.env.PROD)
|
||||
{
|
||||
app.use(compression());
|
||||
}
|
||||
|
||||
return app;
|
||||
});
|
||||
|
||||
/**
|
||||
* You need to make the server listen to the indicated port
|
||||
* and return the listening instance or whatever you need to
|
||||
* close the server with.
|
||||
*
|
||||
* The "listenResult" param for the "close()" definition below
|
||||
* is what you return here.
|
||||
*
|
||||
* For production, you can instead export your
|
||||
* handler for serverless use or whatever else fits your needs.
|
||||
*
|
||||
* Can be async: defineSsrListen(async ({ app, devHttpsApp, port }) => { ... })
|
||||
*/
|
||||
export const listen = defineSsrListen(({ app, devHttpsApp, port }) =>
|
||||
{
|
||||
const server = devHttpsApp || app;
|
||||
return server.listen(port, () =>
|
||||
{
|
||||
if (process.env.PROD)
|
||||
{
|
||||
console.log('Server listening at port ' + port);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Should close the server and free up any resources.
|
||||
* Will be used on development mode when the server needs
|
||||
* to be restarted, or when the application shuts down.
|
||||
*
|
||||
* Can be async: defineSsrClose(async ({ ... }) => { ... })
|
||||
*/
|
||||
export const close = defineSsrClose(async({ listenResult }) =>
|
||||
{
|
||||
// Close the database connection when the server shuts down
|
||||
try
|
||||
{
|
||||
await prisma.$disconnect();
|
||||
console.log('Prisma Client disconnected.');
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
console.error('Error disconnecting Prisma Client:', e);
|
||||
}
|
||||
|
||||
return listenResult.close();
|
||||
});
|
||||
|
||||
const maxAge = process.env.DEV
|
||||
? 0
|
||||
: 1000 * 60 * 60 * 24 * 30;
|
||||
|
||||
/**
|
||||
* Should return a function that will be used to configure the webserver
|
||||
* to serve static content at "urlPath" from "pathToServe" folder/file.
|
||||
*
|
||||
* Notice resolve.urlPath(urlPath) and resolve.public(pathToServe) usages.
|
||||
*
|
||||
* Can be async: defineSsrServeStaticContent(async ({ app, resolve }) => {
|
||||
* Can return an async function: return async ({ urlPath = '/', pathToServe = '.', opts = {} }) => {
|
||||
*/
|
||||
export const serveStaticContent = defineSsrServeStaticContent(({ app, resolve }) =>
|
||||
{
|
||||
return ({ urlPath = '/', pathToServe = '.', opts = {} }) =>
|
||||
{
|
||||
const serveFn = express.static(resolve.public(pathToServe), { maxAge, ...opts });
|
||||
app.use(resolve.urlPath(urlPath), serveFn);
|
||||
};
|
||||
});
|
||||
|
||||
const jsRE = /\.js$/;
|
||||
const cssRE = /\.css$/;
|
||||
const woffRE = /\.woff$/;
|
||||
const woff2RE = /\.woff2$/;
|
||||
const gifRE = /\.gif$/;
|
||||
const jpgRE = /\.jpe?g$/;
|
||||
const pngRE = /\.png$/;
|
||||
|
||||
/**
|
||||
* Should return a String with HTML output
|
||||
* (if any) for preloading indicated file
|
||||
*/
|
||||
export const renderPreloadTag = defineSsrRenderPreloadTag((file/* , { ssrContext } */) =>
|
||||
{
|
||||
if (jsRE.test(file) === true)
|
||||
{
|
||||
return `<link rel="modulepreload" href="${file}" crossorigin>`;
|
||||
}
|
||||
|
||||
if (cssRE.test(file) === true)
|
||||
{
|
||||
return `<link rel="stylesheet" href="${file}" crossorigin>`;
|
||||
}
|
||||
|
||||
if (woffRE.test(file) === true)
|
||||
{
|
||||
return `<link rel="preload" href="${file}" as="font" type="font/woff" crossorigin>`;
|
||||
}
|
||||
|
||||
if (woff2RE.test(file) === true)
|
||||
{
|
||||
return `<link rel="preload" href="${file}" as="font" type="font/woff2" crossorigin>`;
|
||||
}
|
||||
|
||||
if (gifRE.test(file) === true)
|
||||
{
|
||||
return `<link rel="preload" href="${file}" as="image" type="image/gif" crossorigin>`;
|
||||
}
|
||||
|
||||
if (jpgRE.test(file) === true)
|
||||
{
|
||||
return `<link rel="preload" href="${file}" as="image" type="image/jpeg" crossorigin>`;
|
||||
}
|
||||
|
||||
if (pngRE.test(file) === true)
|
||||
{
|
||||
return `<link rel="preload" href="${file}" as="image" type="image/png" crossorigin>`;
|
||||
}
|
||||
|
||||
return '';
|
||||
});
|
10
src/App.vue
10
src/App.vue
|
@ -3,5 +3,13 @@
|
|||
</template>
|
||||
|
||||
<script setup>
|
||||
//
|
||||
import { useAuthStore } from './stores/auth';
|
||||
|
||||
defineOptions({
|
||||
preFetch()
|
||||
{
|
||||
const authStore = useAuthStore();
|
||||
return authStore.checkAuthStatus();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
14
src/boot/axios.js
Normal file
14
src/boot/axios.js
Normal file
|
@ -0,0 +1,14 @@
|
|||
import { boot } from 'quasar/wrappers';
|
||||
import axios from 'axios';
|
||||
|
||||
// Be careful when using SSR for cross-request state pollution
|
||||
// due to creating a Singleton instance here;
|
||||
// If any client changes this (global) instance, it might be a
|
||||
// good idea to move this instance creation inside of the
|
||||
// "export default () => {}" function below (which runs individually
|
||||
// for each client)
|
||||
|
||||
axios.defaults.withCredentials = true; // Enable sending cookies with requests
|
||||
|
||||
// Export the API instance so you can import it easily elsewhere, e.g. stores
|
||||
export default axios;
|
|
@ -147,7 +147,7 @@
|
|||
</template>
|
||||
|
||||
<script setup>
|
||||
import axios from 'axios';
|
||||
import axios from 'boot/axios';
|
||||
import { ref, computed } from 'vue'; // Import computed
|
||||
import { useRouter } from 'vue-router';
|
||||
import { useQuasar } from 'quasar';
|
||||
|
@ -221,7 +221,7 @@ async function logout()
|
|||
{
|
||||
try
|
||||
{
|
||||
await axios.post('/auth/logout');
|
||||
await axios.post('/api/auth/logout');
|
||||
authStore.logout(); // Use the store action to update state
|
||||
// No need to manually push, router guard should redirect
|
||||
// router.push({ name: 'login' });
|
||||
|
|
|
@ -139,7 +139,7 @@
|
|||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import axios from 'axios';
|
||||
import axios from 'boot/axios';
|
||||
import { useQuasar } from 'quasar';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
|
|
|
@ -157,7 +157,7 @@
|
|||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue';
|
||||
import axios from 'axios';
|
||||
import axios from 'boot/axios';
|
||||
import { useQuasar } from 'quasar';
|
||||
import { useRouter, useRoute } from 'vue-router';
|
||||
|
||||
|
|
|
@ -125,7 +125,7 @@
|
|||
|
||||
<script setup>
|
||||
import { ref, onMounted, reactive } from 'vue';
|
||||
import axios from 'axios';
|
||||
import axios from 'boot/axios';
|
||||
import { useQuasar } from 'quasar';
|
||||
import { useRouter, useRoute } from 'vue-router';
|
||||
|
||||
|
|
|
@ -96,7 +96,7 @@
|
|||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue';
|
||||
import axios from 'axios';
|
||||
import axios from 'boot/axios';
|
||||
import { useQuasar } from 'quasar';
|
||||
|
||||
const $q = useQuasar();
|
||||
|
|
|
@ -99,7 +99,7 @@
|
|||
|
||||
<script setup>
|
||||
import { ref, onMounted, computed } from 'vue';
|
||||
import axios from 'axios';
|
||||
import axios from 'boot/axios';
|
||||
import { useQuasar } from 'quasar';
|
||||
|
||||
const componentProps = defineProps({
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
import { ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { startAuthentication } from '@simplewebauthn/browser';
|
||||
import axios from 'axios';
|
||||
import axios from 'boot/axios';
|
||||
import { useAuthStore } from 'stores/auth'; // Import the auth store
|
||||
|
||||
const username = ref('');
|
||||
|
@ -65,7 +65,7 @@ async function handleLogin()
|
|||
try
|
||||
{
|
||||
// 1. Get options from server
|
||||
const optionsRes = await axios.post('/auth/generate-authentication-options', {
|
||||
const optionsRes = await axios.post('/api/auth/generate-authentication-options', {
|
||||
username: username.value || undefined, // Send username if provided
|
||||
});
|
||||
const options = optionsRes.data;
|
||||
|
@ -74,7 +74,7 @@ async function handleLogin()
|
|||
const authResp = await startAuthentication(options);
|
||||
|
||||
// 3. Send response to server for verification
|
||||
const verificationRes = await axios.post('/auth/verify-authentication', {
|
||||
const verificationRes = await axios.post('/api/auth/verify-authentication', {
|
||||
authenticationResponse: authResp,
|
||||
});
|
||||
|
||||
|
|
|
@ -69,7 +69,7 @@
|
|||
<q-item-label
|
||||
class="q-mt-sm markdown-content"
|
||||
>
|
||||
<div v-html="parseMarkdown(summary.content)" />
|
||||
<div v-html="parseMarkdown(summary.summaryText)" />
|
||||
</q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
|
@ -102,7 +102,7 @@
|
|||
<script setup>
|
||||
import { ref, onMounted, computed } from 'vue';
|
||||
import { date, useQuasar } from 'quasar'; // Import useQuasar
|
||||
import axios from 'axios';
|
||||
import axios from 'boot/axios';
|
||||
import { marked } from 'marked';
|
||||
|
||||
const $q = useQuasar(); // Initialize Quasar plugin usage
|
||||
|
|
|
@ -126,7 +126,7 @@
|
|||
<script setup>
|
||||
import { ref, computed, onMounted } from 'vue';
|
||||
import { startRegistration, startAuthentication } from '@simplewebauthn/browser'; // Import startAuthentication
|
||||
import axios from 'axios';
|
||||
import axios from 'boot/axios';
|
||||
import { useAuthStore } from 'stores/auth';
|
||||
|
||||
const registerLoading = ref(false);
|
||||
|
@ -160,7 +160,7 @@ async function fetchPasskeys()
|
|||
identifiedPasskeyId.value = null; // Clear identified key
|
||||
try
|
||||
{
|
||||
const response = await axios.get('/auth/passkeys');
|
||||
const response = await axios.get('/api/auth/passkeys');
|
||||
passkeys.value = response.data || [];
|
||||
}
|
||||
catch (error)
|
||||
|
@ -216,7 +216,7 @@ async function handleRegister()
|
|||
try
|
||||
{
|
||||
// 1. Get options from server
|
||||
const optionsRes = await axios.post('/auth/generate-registration-options', {
|
||||
const optionsRes = await axios.post('/api/auth/generate-registration-options', {
|
||||
username: username.value, // Use username from store
|
||||
});
|
||||
const options = optionsRes.data;
|
||||
|
@ -225,7 +225,7 @@ async function handleRegister()
|
|||
const regResp = await startRegistration(options);
|
||||
|
||||
// 3. Send response to server for verification
|
||||
const verificationRes = await axios.post('/auth/verify-registration', {
|
||||
const verificationRes = await axios.post('/api/auth/verify-registration', {
|
||||
registrationResponse: regResp,
|
||||
});
|
||||
|
||||
|
@ -288,7 +288,7 @@ async function handleDelete(credentialID)
|
|||
|
||||
try
|
||||
{
|
||||
await axios.delete(`/auth/passkeys/${credentialID}`);
|
||||
await axios.delete(`/api/auth/passkeys/${credentialID}`);
|
||||
deleteSuccessMessage.value = 'Passkey deleted successfully.';
|
||||
fetchPasskeys(); // Refresh the list
|
||||
}
|
||||
|
@ -325,7 +325,7 @@ async function handleIdentify()
|
|||
{
|
||||
// 1. Get authentication options from the server
|
||||
// We don't need to send username as the server should use the session
|
||||
const optionsRes = await axios.post('/auth/generate-authentication-options', {}); // Send empty body
|
||||
const optionsRes = await axios.post('/api/auth/generate-authentication-options', {}); // Send empty body
|
||||
const options = optionsRes.data;
|
||||
|
||||
// Optionally filter options to only allow the specific key if needed, but usually not necessary for identification
|
||||
|
|
|
@ -60,7 +60,7 @@
|
|||
import { ref, onMounted, computed } from 'vue'; // Import computed
|
||||
import { useRouter } from 'vue-router';
|
||||
import { startRegistration } from '@simplewebauthn/browser';
|
||||
import axios from 'axios';
|
||||
import axios from 'boot/axios';
|
||||
import { useAuthStore } from 'stores/auth'; // Import the auth store
|
||||
|
||||
const loading = ref(false);
|
||||
|
@ -111,7 +111,7 @@ async function handleRegister()
|
|||
try
|
||||
{
|
||||
// 1. Get options from server
|
||||
const optionsRes = await axios.post('/auth/generate-registration-options', {
|
||||
const optionsRes = await axios.post('/api/auth/generate-registration-options', {
|
||||
username: currentUsername, // Use username from store
|
||||
});
|
||||
const options = optionsRes.data;
|
||||
|
@ -120,7 +120,7 @@ async function handleRegister()
|
|||
const regResp = await startRegistration(options);
|
||||
|
||||
// 3. Send response to server for verification
|
||||
const verificationRes = await axios.post('/auth/verify-registration', {
|
||||
const verificationRes = await axios.post('/api/auth/verify-registration', {
|
||||
registrationResponse: regResp,
|
||||
});
|
||||
|
||||
|
|
|
@ -78,7 +78,7 @@
|
|||
<script setup>
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { useQuasar } from 'quasar';
|
||||
import axios from 'axios';
|
||||
import axios from 'boot/axios';
|
||||
|
||||
const $q = useQuasar();
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { defineStore } from 'pinia';
|
||||
import axios from 'axios';
|
||||
import axios from 'boot/axios';
|
||||
|
||||
export const useAuthStore = defineStore('auth', {
|
||||
state: () => ({
|
||||
|
@ -15,8 +15,10 @@ export const useAuthStore = defineStore('auth', {
|
|||
this.error = null;
|
||||
try
|
||||
{
|
||||
const res = await axios.get('/auth/check-auth');
|
||||
if (res.data.isAuthenticated)
|
||||
const res = await axios.get('/api/auth/status', {
|
||||
withCredentials: true, // Ensure cookies are sent with the request
|
||||
});
|
||||
if (res.data.status === 'authenticated')
|
||||
{
|
||||
this.isAuthenticated = true;
|
||||
this.user = res.data.user;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { defineStore } from 'pinia';
|
||||
import { ref, computed, watch } from 'vue'; // Import watch
|
||||
import axios from 'axios';
|
||||
import axios from 'boot/axios';
|
||||
|
||||
export const useChatStore = defineStore('chat', () =>
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue