mirror of
https://github.com/PretendoNetwork/website.git
synced 2026-04-26 10:04:25 -05:00
Merge pull request #399 from PretendoNetwork/nuxt-refactor-registration
Nuxt refactor: Registration
This commit is contained in:
commit
21ae7a4db9
|
|
@ -24,7 +24,11 @@ export default defineNuxtConfig({
|
||||||
},
|
},
|
||||||
|
|
||||||
runtimeConfig: {
|
runtimeConfig: {
|
||||||
apiBase: 'https://api.pretendo.cc'
|
apiBase: 'https://api.pretendo.cc',
|
||||||
|
|
||||||
|
public: {
|
||||||
|
hCaptchaSitekey: ''
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
css: ['~/assets/css/main.css'],
|
css: ['~/assets/css/main.css'],
|
||||||
|
|
|
||||||
12
package-lock.json
generated
12
package-lock.json
generated
|
|
@ -9,6 +9,7 @@
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"license": "AGPL-3.0-only",
|
"license": "AGPL-3.0-only",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@hcaptcha/vue3-hcaptcha": "^1.3.0",
|
||||||
"@nuxt/content": "^3.4.0",
|
"@nuxt/content": "^3.4.0",
|
||||||
"@nuxt/eslint": "^1.3.0",
|
"@nuxt/eslint": "^1.3.0",
|
||||||
"@nuxt/fonts": "^0.11.1",
|
"@nuxt/fonts": "^0.11.1",
|
||||||
|
|
@ -1270,6 +1271,17 @@
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@hcaptcha/vue3-hcaptcha": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@hcaptcha/vue3-hcaptcha/-/vue3-hcaptcha-1.3.0.tgz",
|
||||||
|
"integrity": "sha512-IEonS6JiYdU7uy6aeib8cYtMO4nj8utwStbA9bWHyYbOvOvhpkV+AW8vfSKh6SntYxqle/TRwhv+kU9p92CfsA==",
|
||||||
|
"dependencies": {
|
||||||
|
"vue": "^3.2.19"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"vue": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@humanfs/core": {
|
"node_modules/@humanfs/core": {
|
||||||
"version": "0.19.1",
|
"version": "0.19.1",
|
||||||
"resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
|
"resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@
|
||||||
"lint:fix": "eslint . --fix"
|
"lint:fix": "eslint . --fix"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@hcaptcha/vue3-hcaptcha": "^1.3.0",
|
||||||
"@nuxt/content": "^3.4.0",
|
"@nuxt/content": "^3.4.0",
|
||||||
"@nuxt/eslint": "^1.3.0",
|
"@nuxt/eslint": "^1.3.0",
|
||||||
"@nuxt/fonts": "^0.11.1",
|
"@nuxt/fonts": "^0.11.1",
|
||||||
|
|
|
||||||
137
src/assets/css/auth.css
Normal file
137
src/assets/css/auth.css
Normal file
|
|
@ -0,0 +1,137 @@
|
||||||
|
header {
|
||||||
|
margin: 35px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-form-wrapper {
|
||||||
|
height: 80vh;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-content: center;
|
||||||
|
flex-direction: column;
|
||||||
|
margin: 15vh auto;
|
||||||
|
width: fit-content;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
form.account {
|
||||||
|
height: fit-content;
|
||||||
|
display: block;
|
||||||
|
padding: 40px 48px;
|
||||||
|
background-color: var(--bg-shade-2);
|
||||||
|
color: var(--text-shade-1);
|
||||||
|
border-radius: 12px;
|
||||||
|
width: min(480px, 90vw);
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
form.account h2 {
|
||||||
|
margin: 0;
|
||||||
|
color: var(--text-shade-3);
|
||||||
|
}
|
||||||
|
|
||||||
|
form.account p {
|
||||||
|
margin: 12px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
form.account div {
|
||||||
|
margin-top: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
form.account label {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
form.account button {
|
||||||
|
width: 100%;
|
||||||
|
background: var(--accent-shade-0);
|
||||||
|
}
|
||||||
|
|
||||||
|
form.account a {
|
||||||
|
text-decoration: none;
|
||||||
|
display: block;
|
||||||
|
color: var(--text-shade-1);
|
||||||
|
text-align: right;
|
||||||
|
margin: 6px 0;
|
||||||
|
width: fit-content;
|
||||||
|
}
|
||||||
|
|
||||||
|
form.account a:hover {
|
||||||
|
color: var(--text-shade-3);
|
||||||
|
}
|
||||||
|
|
||||||
|
form.account a.pwdreset {
|
||||||
|
margin-left: auto;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
form.account a.register {
|
||||||
|
margin: auto;
|
||||||
|
margin-top: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes banner-notice {
|
||||||
|
0% {
|
||||||
|
top: -150px;
|
||||||
|
}
|
||||||
|
|
||||||
|
20% {
|
||||||
|
top: 35px;
|
||||||
|
}
|
||||||
|
|
||||||
|
80% {
|
||||||
|
top: 35px;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
top: -150px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner-notice {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: -150px;
|
||||||
|
width: 100%;
|
||||||
|
animation: banner-notice 5s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner-notice div {
|
||||||
|
padding: 4px 36px;
|
||||||
|
border-radius: 5px;
|
||||||
|
z-index: 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner-notice.error div {
|
||||||
|
background: var(--red-shade-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
form.account.register {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
width: min(780px, 90vw);
|
||||||
|
column-gap: 24px;
|
||||||
|
margin-bottom: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
form.account.register p,
|
||||||
|
form.account.register div.email,
|
||||||
|
form.account.register div.buttons {
|
||||||
|
grid-column: 1 / span 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 720px) {
|
||||||
|
form.account.register {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
form.account.register p,
|
||||||
|
form.account.register div.email,
|
||||||
|
form.account.register div.buttons {
|
||||||
|
grid-column: unset;
|
||||||
|
}
|
||||||
|
}
|
||||||
5
src/pages/account/forgot-password/index.vue
Normal file
5
src/pages/account/forgot-password/index.vue
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<p>TODO: forgot password stub page</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<p>account stub page</p>
|
<p>TODO: account stub page</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -9,22 +9,27 @@ const loginForm = reactive({ username: '', password: '' });
|
||||||
const errorMessage = ref<string | null>();
|
const errorMessage = ref<string | null>();
|
||||||
|
|
||||||
async function loginSubmission() {
|
async function loginSubmission() {
|
||||||
await $fetch('/api/account/login', {
|
try {
|
||||||
method: 'POST',
|
await $fetch('/api/account/login', {
|
||||||
body: loginForm
|
method: 'POST',
|
||||||
}).catch((error: FetchError) => {
|
body: loginForm
|
||||||
errorMessage.value = error.statusText;
|
});
|
||||||
setTimeout(() => { // TODO: this is not the best way to clear this out, but this is temporary! replace all toasts with input alerts in the future
|
|
||||||
|
if (typeof redirect.value === 'string') {
|
||||||
|
await navigateTo(redirect.value);
|
||||||
|
} else {
|
||||||
|
await navigateTo('/account');
|
||||||
|
}
|
||||||
|
} catch (error: unknown) {
|
||||||
|
if (error instanceof FetchError) {
|
||||||
|
errorMessage.value = error.statusText;
|
||||||
|
} else {
|
||||||
|
errorMessage.value = `Error during registration: ${error}`; // TODO: localize
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(() => { // TODO: replace this toast
|
||||||
errorMessage.value = null;
|
errorMessage.value = null;
|
||||||
}, 5000);
|
}, 5000);
|
||||||
|
|
||||||
return;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (typeof redirect.value === 'string') {
|
|
||||||
await navigateTo(redirect.value);
|
|
||||||
} else {
|
|
||||||
await navigateTo('/account');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
@ -85,150 +90,5 @@ async function loginSubmission() {
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
header {
|
@import "/assets/css/auth.css";
|
||||||
margin: 35px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.account-form-wrapper {
|
|
||||||
height: 75vh;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-content: center;
|
|
||||||
flex-direction: column;
|
|
||||||
margin: auto;
|
|
||||||
width: fit-content;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
form.account {
|
|
||||||
height: fit-content;
|
|
||||||
display: block;
|
|
||||||
padding: 40px 48px;
|
|
||||||
background-color: var(--bg-shade-2);
|
|
||||||
color: var(--text-shade-1);
|
|
||||||
border-radius: 12px;
|
|
||||||
width: min(480px, 90vw);
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
form.account h2 {
|
|
||||||
margin: 0;
|
|
||||||
color: var(--text-shade-3);
|
|
||||||
}
|
|
||||||
|
|
||||||
form.account p {
|
|
||||||
margin: 12px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
form.account div {
|
|
||||||
margin-top: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
form.account label {
|
|
||||||
display: block;
|
|
||||||
margin-bottom: 6px;
|
|
||||||
text-transform: uppercase;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
form.account button {
|
|
||||||
width: 100%;
|
|
||||||
background: var(--accent-shade-0);
|
|
||||||
}
|
|
||||||
|
|
||||||
form.account a {
|
|
||||||
text-decoration: none;
|
|
||||||
display: block;
|
|
||||||
color: var(--text-shade-1);
|
|
||||||
text-align: right;
|
|
||||||
margin: 6px 0;
|
|
||||||
width: fit-content;
|
|
||||||
}
|
|
||||||
|
|
||||||
form.account a:hover {
|
|
||||||
color: var(--text-shade-3);
|
|
||||||
}
|
|
||||||
|
|
||||||
form.account a.pwdreset {
|
|
||||||
margin-left: auto;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
form.account a.register {
|
|
||||||
margin: auto;
|
|
||||||
margin-top: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes banner-notice {
|
|
||||||
0% {
|
|
||||||
top: -150px;
|
|
||||||
}
|
|
||||||
|
|
||||||
20% {
|
|
||||||
top: 35px;
|
|
||||||
}
|
|
||||||
|
|
||||||
80% {
|
|
||||||
top: 35px;
|
|
||||||
}
|
|
||||||
|
|
||||||
100% {
|
|
||||||
top: -150px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.banner-notice {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
top: -150px;
|
|
||||||
width: 100%;
|
|
||||||
animation: banner-notice 5s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.banner-notice div {
|
|
||||||
padding: 4px 36px;
|
|
||||||
border-radius: 5px;
|
|
||||||
z-index: 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
.banner-notice.error div {
|
|
||||||
background: var(--red-shade-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
form.account.register {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(2, 1fr);
|
|
||||||
width: min(780px, 90vw);
|
|
||||||
column-gap: 24px;
|
|
||||||
margin-bottom: 48px;
|
|
||||||
}
|
|
||||||
|
|
||||||
form.account.register div.h-captcha {
|
|
||||||
grid-column: 1 / span 2;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
form.account.register p,
|
|
||||||
form.account.register div.email,
|
|
||||||
form.account.register div.buttons {
|
|
||||||
grid-column: 1 / span 2;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
@media screen and (max-width: 720px) {
|
|
||||||
form.account.register {
|
|
||||||
grid-template-columns: 1fr;
|
|
||||||
}
|
|
||||||
|
|
||||||
form.account.register div.h-captcha,
|
|
||||||
form.account.register p,
|
|
||||||
form.account.register div.email,
|
|
||||||
form.account.register div.buttons {
|
|
||||||
grid-column: unset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
139
src/pages/account/register/index.vue
Normal file
139
src/pages/account/register/index.vue
Normal file
|
|
@ -0,0 +1,139 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import VueHcaptcha from '@hcaptcha/vue3-hcaptcha';
|
||||||
|
import { FetchError } from 'ofetch';
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
const redirect = computed(() => route.query.redirect);
|
||||||
|
const loginURI = computed(() => `/account/login${redirect.value ? `?redirect=${redirect.value}` : ''}`);
|
||||||
|
|
||||||
|
const registerForm = reactive({ email: '', username: '', mii_name: '', password: '', password_confirm: '' });
|
||||||
|
|
||||||
|
const errorMessage = ref<string | null>();
|
||||||
|
const invisibleHcaptcha = ref<VueHcaptcha | null>(null);
|
||||||
|
|
||||||
|
async function registerSubmission() {
|
||||||
|
try {
|
||||||
|
const hCaptchaResponse = invisibleHcaptcha.value ? (await invisibleHcaptcha.value.executeAsync()).response : null;
|
||||||
|
|
||||||
|
await $fetch('/api/account/register', {
|
||||||
|
method: 'POST',
|
||||||
|
body: { ...registerForm, hCaptchaResponse }
|
||||||
|
});
|
||||||
|
|
||||||
|
if (typeof redirect.value === 'string') {
|
||||||
|
await navigateTo(redirect.value);
|
||||||
|
} else {
|
||||||
|
await navigateTo('/account');
|
||||||
|
}
|
||||||
|
} catch (error: unknown) {
|
||||||
|
if (error instanceof FetchError) {
|
||||||
|
errorMessage.value = error.statusText;
|
||||||
|
} else {
|
||||||
|
if (error === 'challenge-closed') { // Thrown if the captcha is closed, can be safely ignored
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
errorMessage.value = `Error during registration: ${error}`; // TODO: localize
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(() => { // TODO: replace this toast
|
||||||
|
errorMessage.value = null;
|
||||||
|
}, 5000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="account-form-wrapper">
|
||||||
|
<form
|
||||||
|
class="account register"
|
||||||
|
@submit.prevent="registerSubmission"
|
||||||
|
>
|
||||||
|
<h2>{{ $t("account.loginForm.register") }}</h2>
|
||||||
|
<p>{{ $t("account.loginForm.detailsPrompt") }}</p>
|
||||||
|
<div class="email">
|
||||||
|
<label for="email">{{ $t("account.loginForm.email") }}</label>
|
||||||
|
<input
|
||||||
|
id="email"
|
||||||
|
v-model="registerForm.email"
|
||||||
|
name="email"
|
||||||
|
type="email"
|
||||||
|
required
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="username">{{ $t("account.loginForm.username") }}</label>
|
||||||
|
<input
|
||||||
|
id="username"
|
||||||
|
v-model="registerForm.username"
|
||||||
|
name="username"
|
||||||
|
minlength="6"
|
||||||
|
maxlength="16"
|
||||||
|
required
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="mii_name">{{ $t("account.loginForm.miiName") }}</label>
|
||||||
|
<input
|
||||||
|
id="mii_name"
|
||||||
|
v-model="registerForm.mii_name"
|
||||||
|
name="mii_name"
|
||||||
|
maxlength="10"
|
||||||
|
required
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="password">{{ $t("account.loginForm.password") }}</label>
|
||||||
|
<input
|
||||||
|
id="password"
|
||||||
|
v-model="registerForm.password"
|
||||||
|
name="password"
|
||||||
|
type="password"
|
||||||
|
autocomplete="new-password"
|
||||||
|
required
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="password_confirm">{{ $t("account.loginForm.confirmPassword") }}</label>
|
||||||
|
<input
|
||||||
|
id="password_confirm"
|
||||||
|
v-model="registerForm.password_confirm"
|
||||||
|
name="password_confirm"
|
||||||
|
type="password"
|
||||||
|
autocomplete="new-password"
|
||||||
|
required
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="buttons">
|
||||||
|
<button type="submit">
|
||||||
|
{{ $t("account.loginForm.register") }}
|
||||||
|
</button>
|
||||||
|
<a
|
||||||
|
:href="loginURI"
|
||||||
|
class="register"
|
||||||
|
>{{ $t("account.loginForm.loginPrompt") }}</a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<vue-hcaptcha
|
||||||
|
v-if="$config.public.hCaptchaSitekey"
|
||||||
|
ref="invisibleHcaptcha"
|
||||||
|
:sitekey="$config.public.hCaptchaSitekey"
|
||||||
|
class="h-captcha"
|
||||||
|
size="invisible"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
v-if="errorMessage"
|
||||||
|
class="banner-notice error"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<p>{{ errorMessage }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
@import "/assets/css/auth.css";
|
||||||
|
</style>
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
import { FetchError } from 'ofetch';
|
import { FetchError } from 'ofetch';
|
||||||
|
|
||||||
type LoginCCResponse = {
|
interface LoginCCResponse {
|
||||||
refresh_token: string;
|
refresh_token: string;
|
||||||
access_token: string;
|
access_token: string;
|
||||||
token_type: string;
|
token_type: string;
|
||||||
expires_in: number;
|
expires_in: number;
|
||||||
};
|
}
|
||||||
|
|
||||||
export default defineEventHandler(async (event) => {
|
export default defineEventHandler(async (event) => {
|
||||||
const body = await readBody(event);
|
const body = await readBody(event);
|
||||||
|
|
|
||||||
|
|
@ -1 +1,35 @@
|
||||||
// TODO: registration
|
import { FetchError } from 'ofetch';
|
||||||
|
|
||||||
|
interface RegisterCCResponse { // TODO: this is the same as the login response. figure out where we should put types and merge into AuthCCReponse!
|
||||||
|
refresh_token: string;
|
||||||
|
access_token: string;
|
||||||
|
token_type: string;
|
||||||
|
expires_in: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default defineEventHandler(async (event) => {
|
||||||
|
const body = await readBody(event);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const apiResponse = await $fetch<RegisterCCResponse>(`/v1/register`, {
|
||||||
|
method: 'POST',
|
||||||
|
baseURL: useRuntimeConfig(event).apiBase,
|
||||||
|
body: body
|
||||||
|
});
|
||||||
|
|
||||||
|
setCookie(event, 'refresh_token', apiResponse.refresh_token);
|
||||||
|
setCookie(event, 'access_token', apiResponse.access_token);
|
||||||
|
setCookie(event, 'token_type', apiResponse.token_type);
|
||||||
|
|
||||||
|
setResponseStatus(event, 200);
|
||||||
|
event.node.res.end();
|
||||||
|
} catch (error: unknown) {
|
||||||
|
if (error instanceof FetchError) {
|
||||||
|
setResponseStatus(event, error.status, error.data.error);
|
||||||
|
} else {
|
||||||
|
setResponseStatus(event, 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
event.node.res.end();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user