@dargmuesli/nuxt-vio 19.0.0 → 20.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app/app.config.ts +35 -33
- package/app/components/vio/_/VioApp.vue +10 -12
- package/app/components/vio/_/VioTime.vue +35 -0
- package/app/components/vio/page/VioPageLegalNotice.vue +69 -45
- package/app/components/vio/page/VioPagePrivacyPolicy.vue +11 -2
- package/app/composables/timeZone.ts +10 -0
- package/nuxt.config.ts +1 -4
- package/package.json +11 -10
- package/server/middleware/headers.ts +3 -1
- package/server/plugins/security.ts +2 -0
- package/{shared → server}/utils/site.ts +1 -1
- package/shared/utils/form.ts +1 -0
- package/shared/utils/networking.ts +3 -0
- package/shared/utils/nuxt.ts +2 -0
- package/shared/utils/utils.ts +1 -1
- package/app/composables/dateTime.ts +0 -9
- package/app/plugins/dayjs.ts +0 -30
- package/app/plugins/i18n.ts +0 -5
- package/server/tsconfig.json +0 -3
- package/shared/utils/auth.ts +0 -126
- /package/{shared → app}/utils/timezone.ts +0 -0
package/app/app.config.ts
CHANGED
|
@@ -5,55 +5,57 @@ export default defineAppConfig({
|
|
|
5
5
|
},
|
|
6
6
|
})
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
responsibility: {
|
|
16
|
-
address: {
|
|
17
|
-
city: string
|
|
18
|
-
name: string
|
|
19
|
-
street: string
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
tmg: {
|
|
23
|
-
address: {
|
|
24
|
-
city: string
|
|
25
|
-
name: string
|
|
26
|
-
street: string
|
|
8
|
+
declare module 'nuxt/schema' {
|
|
9
|
+
interface AppConfig {
|
|
10
|
+
vio: {
|
|
11
|
+
pages?: {
|
|
12
|
+
legalNotice?: {
|
|
13
|
+
contact: {
|
|
14
|
+
email: string
|
|
27
15
|
}
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
privacyPolicy?: {
|
|
31
|
-
hostingCdn?: {
|
|
32
|
-
external: {
|
|
16
|
+
responsibility: {
|
|
33
17
|
address: {
|
|
34
18
|
city: string
|
|
35
19
|
name: string
|
|
36
20
|
street: string
|
|
37
21
|
}
|
|
38
22
|
}
|
|
39
|
-
|
|
40
|
-
mandatoryInfo?: {
|
|
41
|
-
responsible: {
|
|
23
|
+
tmg: {
|
|
42
24
|
address: {
|
|
43
25
|
city: string
|
|
44
|
-
email: string
|
|
45
26
|
name: string
|
|
46
27
|
street: string
|
|
47
28
|
}
|
|
48
29
|
}
|
|
49
30
|
}
|
|
31
|
+
privacyPolicy?: {
|
|
32
|
+
hostingCdn?: {
|
|
33
|
+
external: {
|
|
34
|
+
address: {
|
|
35
|
+
city: string
|
|
36
|
+
name: string
|
|
37
|
+
street: string
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
mandatoryInfo?: {
|
|
42
|
+
responsible: {
|
|
43
|
+
address: {
|
|
44
|
+
city: string
|
|
45
|
+
email: string
|
|
46
|
+
name: string
|
|
47
|
+
street: string
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
50
52
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
server?: {
|
|
54
|
+
middleware: {
|
|
55
|
+
headers: Record<string, string>
|
|
56
|
+
}
|
|
55
57
|
}
|
|
58
|
+
themeColor?: string
|
|
56
59
|
}
|
|
57
|
-
themeColor?: string
|
|
58
60
|
}
|
|
59
61
|
}
|
|
@@ -16,26 +16,24 @@ const props = withDefaults(defineProps<Props>(), {
|
|
|
16
16
|
ogImageComponent: undefined,
|
|
17
17
|
})
|
|
18
18
|
|
|
19
|
-
const {
|
|
20
|
-
const
|
|
19
|
+
const { t } = useI18n()
|
|
20
|
+
const timeZone = useTimeZone()
|
|
21
21
|
|
|
22
22
|
const { loadingIds, indicateLoadingDone } = useLoadingDoneIndicator('app')
|
|
23
23
|
|
|
24
24
|
// methods
|
|
25
25
|
const initialize = () => {
|
|
26
|
-
$dayjs.locale(locale.value)
|
|
27
|
-
|
|
28
26
|
if (import.meta.client) {
|
|
29
|
-
|
|
30
|
-
// default: () => undefined, // setting `default` on the client side only does not write the cookie
|
|
31
|
-
httpOnly: false,
|
|
32
|
-
sameSite: 'strict',
|
|
33
|
-
secure: true,
|
|
34
|
-
})
|
|
35
|
-
// @ts-expect-error `tz` should be part of `$dayjs` (https://github.com/iamkun/dayjs/issues/2106)
|
|
36
|
-
cookieTimezone.value = $dayjs.tz.guess()
|
|
27
|
+
saveTimeZoneAsCookie()
|
|
37
28
|
}
|
|
38
29
|
}
|
|
30
|
+
const saveTimeZoneAsCookie = () =>
|
|
31
|
+
(useCookie(TIMEZONE_COOKIE_NAME, {
|
|
32
|
+
// default: () => undefined, // setting `default` on the client side only does not write the cookie
|
|
33
|
+
httpOnly: false,
|
|
34
|
+
sameSite: 'strict',
|
|
35
|
+
secure: true,
|
|
36
|
+
}).value = timeZone)
|
|
39
37
|
|
|
40
38
|
// computations
|
|
41
39
|
const isLoading = computed(() => !!loadingIds.value.length)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<NuxtTime
|
|
3
|
+
v-bind="forwardedProps"
|
|
4
|
+
:locale="props.locale || defaultLocale"
|
|
5
|
+
:time-zone="props.timeZone || defaultTimeZone"
|
|
6
|
+
/>
|
|
7
|
+
</template>
|
|
8
|
+
|
|
9
|
+
<script setup lang="ts">
|
|
10
|
+
import { reactiveOmit } from '@vueuse/core'
|
|
11
|
+
import { useForwardProps } from 'reka-ui'
|
|
12
|
+
|
|
13
|
+
// TODO: use imported type (https://github.com/nuxt/nuxt/issues/29757)
|
|
14
|
+
import type { NuxtTimeProps } from '#app'
|
|
15
|
+
|
|
16
|
+
const { locale: defaultLocale } = useI18n()
|
|
17
|
+
const defaultTimeZone = useTimeZone()
|
|
18
|
+
|
|
19
|
+
const props = withDefaults(defineProps<NuxtTimeProps>(), {
|
|
20
|
+
// ...dateTimeFormatOptions, TODO: use shared options
|
|
21
|
+
day: 'numeric',
|
|
22
|
+
hour: 'numeric',
|
|
23
|
+
locale: undefined,
|
|
24
|
+
minute: 'numeric',
|
|
25
|
+
month: 'short',
|
|
26
|
+
relative: undefined,
|
|
27
|
+
timeZone: undefined,
|
|
28
|
+
timeZoneName: undefined,
|
|
29
|
+
weekday: undefined,
|
|
30
|
+
year: 'numeric',
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
const delegatedProps = reactiveOmit(props, 'locale', 'timeZone')
|
|
34
|
+
const forwardedProps = useForwardProps(delegatedProps)
|
|
35
|
+
</script>
|
|
@@ -1,53 +1,72 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<VioLayoutProse class="m-auto">
|
|
3
3
|
<h1>{{ title }}</h1>
|
|
4
|
-
<h2>{{ t('tmg') }}</h2>
|
|
5
|
-
<address>
|
|
6
|
-
<slot v-if="$slots.tmgAddress" name="tmgAddress" />
|
|
7
|
-
<i18n-t v-else keypath="tmgAddress">
|
|
8
|
-
<template #br>
|
|
9
|
-
<br />
|
|
10
|
-
</template>
|
|
11
|
-
<template #city>
|
|
12
|
-
{{ appConfig.vio.pages.legalNotice.tmg.address.city }}
|
|
13
|
-
</template>
|
|
14
|
-
<template #name>
|
|
15
|
-
{{ appConfig.vio.pages.legalNotice.tmg.address.name }}
|
|
16
|
-
</template>
|
|
17
|
-
<template #street>
|
|
18
|
-
{{ appConfig.vio.pages.legalNotice.tmg.address.street }}
|
|
19
|
-
</template>
|
|
20
|
-
</i18n-t>
|
|
21
|
-
</address>
|
|
22
4
|
|
|
23
|
-
<
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
5
|
+
<section
|
|
6
|
+
v-if="appConfig.vio.pages?.legalNotice"
|
|
7
|
+
:aria-labelledby="templateIdTmg"
|
|
8
|
+
>
|
|
9
|
+
<h2 :id="templateIdTmg">{{ t('tmg') }}</h2>
|
|
10
|
+
<address>
|
|
11
|
+
<slot v-if="$slots.tmgAddress" name="tmgAddress" />
|
|
12
|
+
<i18n-t v-else keypath="tmgAddress">
|
|
13
|
+
<template #br>
|
|
14
|
+
<br />
|
|
15
|
+
</template>
|
|
16
|
+
<template #city>
|
|
17
|
+
{{ appConfig.vio.pages.legalNotice.tmg.address.city }}
|
|
18
|
+
</template>
|
|
19
|
+
<template #name>
|
|
20
|
+
{{ appConfig.vio.pages.legalNotice.tmg.address.name }}
|
|
21
|
+
</template>
|
|
22
|
+
<template #street>
|
|
23
|
+
{{ appConfig.vio.pages.legalNotice.tmg.address.street }}
|
|
24
|
+
</template>
|
|
25
|
+
</i18n-t>
|
|
26
|
+
</address>
|
|
27
|
+
</section>
|
|
32
28
|
|
|
33
|
-
<
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
<
|
|
41
|
-
{{
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
29
|
+
<section
|
|
30
|
+
v-if="appConfig.vio.pages?.legalNotice"
|
|
31
|
+
:aria-labelledby="templateIdContact"
|
|
32
|
+
>
|
|
33
|
+
<h2 :id="templateIdContact">{{ t('contact') }}</h2>
|
|
34
|
+
<p>
|
|
35
|
+
<slot v-if="$slots.contactEmail" name="contactEmail" />
|
|
36
|
+
<span v-else>
|
|
37
|
+
{{
|
|
38
|
+
t('email', { email: appConfig.vio.pages.legalNotice.contact.email })
|
|
39
|
+
}}
|
|
40
|
+
</span>
|
|
41
|
+
</p>
|
|
42
|
+
</section>
|
|
43
|
+
|
|
44
|
+
<section
|
|
45
|
+
v-if="appConfig.vio.pages?.legalNotice"
|
|
46
|
+
:aria-labelledby="templateIdResponsibility"
|
|
47
|
+
>
|
|
48
|
+
<h2 :id="templateIdResponsibility">{{ t('responsibility') }}</h2>
|
|
49
|
+
<address>
|
|
50
|
+
<slot
|
|
51
|
+
v-if="$slots.responsibilityAddress"
|
|
52
|
+
name="responsibilityAddress"
|
|
53
|
+
/>
|
|
54
|
+
<i18n-t v-else keypath="responsibilityAddress">
|
|
55
|
+
<template #br>
|
|
56
|
+
<br />
|
|
57
|
+
</template>
|
|
58
|
+
<template #city>
|
|
59
|
+
{{ appConfig.vio.pages.legalNotice.responsibility.address.city }}
|
|
60
|
+
</template>
|
|
61
|
+
<template #name>
|
|
62
|
+
{{ appConfig.vio.pages.legalNotice.responsibility.address.name }}
|
|
63
|
+
</template>
|
|
64
|
+
<template #street>
|
|
65
|
+
{{ appConfig.vio.pages.legalNotice.responsibility.address.street }}
|
|
66
|
+
</template>
|
|
67
|
+
</i18n-t>
|
|
68
|
+
</address>
|
|
69
|
+
</section>
|
|
51
70
|
|
|
52
71
|
<h3>{{ t('liabilityContentTitle') }}</h3>
|
|
53
72
|
<p>{{ t('liabilityContentDescription1') }}</p>
|
|
@@ -73,6 +92,11 @@ const { t } = useI18n()
|
|
|
73
92
|
|
|
74
93
|
// data
|
|
75
94
|
const title = t('title')
|
|
95
|
+
|
|
96
|
+
// template
|
|
97
|
+
const templateIdContact = useId()
|
|
98
|
+
const templateIdResponsibility = useId()
|
|
99
|
+
const templateIdTmg = useId()
|
|
76
100
|
</script>
|
|
77
101
|
|
|
78
102
|
<i18n lang="yaml">
|
|
@@ -44,7 +44,11 @@
|
|
|
44
44
|
</section>
|
|
45
45
|
</section>
|
|
46
46
|
</li>
|
|
47
|
-
<li
|
|
47
|
+
<li
|
|
48
|
+
v-if="
|
|
49
|
+
isEnabled.hostingCdn && appConfig.vio.pages?.privacyPolicy?.hostingCdn
|
|
50
|
+
"
|
|
51
|
+
>
|
|
48
52
|
<section>
|
|
49
53
|
<h2>{{ t('hostingCdn') }}</h2>
|
|
50
54
|
|
|
@@ -102,7 +106,12 @@
|
|
|
102
106
|
<p>{{ t('mandatoryInfoPrivacyDescription3') }}</p>
|
|
103
107
|
</section>
|
|
104
108
|
|
|
105
|
-
<section
|
|
109
|
+
<section
|
|
110
|
+
v-if="
|
|
111
|
+
isEnabled.mandatoryInfo.responsible &&
|
|
112
|
+
appConfig.vio.pages?.privacyPolicy?.mandatoryInfo
|
|
113
|
+
"
|
|
114
|
+
>
|
|
106
115
|
<h3>{{ t('mandatoryInfoResponsibleTitle') }}</h3>
|
|
107
116
|
<p>{{ t('mandatoryInfoResponsibleDescription1') }}</p>
|
|
108
117
|
<address>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export const useTimeZone = () =>
|
|
2
|
+
useNuxtApp().ssrContext?.event.context.$timeZone ||
|
|
3
|
+
useCookie(TIMEZONE_COOKIE_NAME, {
|
|
4
|
+
httpOnly: false,
|
|
5
|
+
sameSite: 'strict',
|
|
6
|
+
secure: true,
|
|
7
|
+
}).value ||
|
|
8
|
+
(import.meta.client
|
|
9
|
+
? Intl.DateTimeFormat().resolvedOptions().timeZone
|
|
10
|
+
: undefined)
|
package/nuxt.config.ts
CHANGED
|
@@ -67,7 +67,7 @@ export default defineNuxtConfig(
|
|
|
67
67
|
nuxtConfigSecurityHeaders.contentSecurityPolicy = defu(
|
|
68
68
|
{
|
|
69
69
|
'script-src-elem': [
|
|
70
|
-
"'unsafe-inline'", //
|
|
70
|
+
"'unsafe-inline'", // TODO: remove (https://github.com/Baroshem/nuxt-security/pull/659)
|
|
71
71
|
],
|
|
72
72
|
},
|
|
73
73
|
VIO_GET_CSP({ siteUrl: new URL(SITE_URL) }),
|
|
@@ -123,9 +123,6 @@ export default defineNuxtConfig(
|
|
|
123
123
|
},
|
|
124
124
|
|
|
125
125
|
// modules
|
|
126
|
-
colorMode: {
|
|
127
|
-
classSuffix: '',
|
|
128
|
-
},
|
|
129
126
|
cookieControl: {
|
|
130
127
|
cookies: {
|
|
131
128
|
necessary: [
|
package/package.json
CHANGED
|
@@ -5,24 +5,23 @@
|
|
|
5
5
|
"@heroicons/vue": "2.2.0",
|
|
6
6
|
"@http-util/status-i18n": "0.9.0",
|
|
7
7
|
"@intlify/eslint-plugin-vue-i18n": "4.1.0",
|
|
8
|
-
"@nuxt/devtools": "3.0
|
|
8
|
+
"@nuxt/devtools": "3.1.0",
|
|
9
9
|
"@nuxt/eslint": "1.10.0",
|
|
10
10
|
"@nuxt/image": "2.0.0",
|
|
11
|
-
"@nuxtjs/color-mode": "
|
|
11
|
+
"@nuxtjs/color-mode": "4.0.0",
|
|
12
12
|
"@nuxtjs/html-validator": "2.1.0",
|
|
13
13
|
"@nuxtjs/i18n": "10.2.0",
|
|
14
14
|
"@nuxtjs/seo": "3.2.2",
|
|
15
15
|
"@pinia/nuxt": "0.11.3",
|
|
16
16
|
"@tailwindcss/forms": "0.5.10",
|
|
17
17
|
"@tailwindcss/typography": "0.5.19",
|
|
18
|
-
"@tailwindcss/vite": "4.1.
|
|
18
|
+
"@tailwindcss/vite": "4.1.17",
|
|
19
19
|
"@types/lodash-es": "4.17.12",
|
|
20
20
|
"@urql/core": "6.0.1",
|
|
21
21
|
"@urql/vue": "2.0.0",
|
|
22
22
|
"@vuelidate/core": "2.0.3",
|
|
23
23
|
"@vuelidate/validators": "2.0.4",
|
|
24
24
|
"clipboardy": "5.0.0",
|
|
25
|
-
"dayjs": "2.0.0-alpha.4",
|
|
26
25
|
"eslint": "9.39.1",
|
|
27
26
|
"eslint-config-prettier": "10.1.8",
|
|
28
27
|
"eslint-plugin-compat": "6.0.2",
|
|
@@ -30,7 +29,7 @@
|
|
|
30
29
|
"eslint-plugin-yml": "1.19.0",
|
|
31
30
|
"globals": "16.5.0",
|
|
32
31
|
"jiti": "2.6.1",
|
|
33
|
-
"jose": "6.1.
|
|
32
|
+
"jose": "6.1.1",
|
|
34
33
|
"nuxt-gtag": "4.1.0",
|
|
35
34
|
"nuxt-security": "2.4.0",
|
|
36
35
|
"sweetalert2": "11.26.3",
|
|
@@ -40,22 +39,24 @@
|
|
|
40
39
|
"@types/node": "24.10.0",
|
|
41
40
|
"@urql/devtools": "2.0.3",
|
|
42
41
|
"@urql/exchange-graphcache": "8.1.0",
|
|
42
|
+
"@vueuse/core": "14.0.0",
|
|
43
43
|
"consola": "3.4.2",
|
|
44
44
|
"defu": "6.1.4",
|
|
45
45
|
"h3": "1.15.4",
|
|
46
46
|
"lodash-es": "4.17.21",
|
|
47
|
-
"nuxt": "4.2.
|
|
47
|
+
"nuxt": "4.2.1",
|
|
48
48
|
"pinia": "3.0.4",
|
|
49
49
|
"prettier": "3.6.2",
|
|
50
50
|
"prettier-plugin-tailwindcss": "0.7.1",
|
|
51
|
+
"reka-ui": "2.6.0",
|
|
51
52
|
"serve": "14.2.5",
|
|
52
|
-
"sharp": "0.34.
|
|
53
|
+
"sharp": "0.34.5",
|
|
53
54
|
"stylelint": "16.25.0",
|
|
54
55
|
"stylelint-config-recommended-vue": "1.6.1",
|
|
55
56
|
"stylelint-config-standard": "39.0.1",
|
|
56
57
|
"stylelint-no-unsupported-browser-features": "8.0.5",
|
|
57
|
-
"tailwindcss": "4.1.
|
|
58
|
-
"vue": "3.5.
|
|
58
|
+
"tailwindcss": "4.1.17",
|
|
59
|
+
"vue": "3.5.24",
|
|
59
60
|
"vue-router": "4.6.3"
|
|
60
61
|
},
|
|
61
62
|
"engines": {
|
|
@@ -106,5 +107,5 @@
|
|
|
106
107
|
"start:static": "serve playground/.output/public --ssl-cert ./.config/certificates/ssl.crt --ssl-key ./.config/certificates/ssl.key"
|
|
107
108
|
},
|
|
108
109
|
"type": "module",
|
|
109
|
-
"version": "
|
|
110
|
+
"version": "20.0.0-beta.1"
|
|
110
111
|
}
|
|
@@ -3,6 +3,7 @@ import type { NuxtOptions } from 'nuxt/schema'
|
|
|
3
3
|
|
|
4
4
|
// remove invalid `'none'`s and duplicates
|
|
5
5
|
export const cleanupCsp = (
|
|
6
|
+
// @ts-expect-error https://github.com/Baroshem/nuxt-security/pull/661
|
|
6
7
|
nuxtSecurityConfiguration: Partial<NuxtOptions['security']>,
|
|
7
8
|
) => {
|
|
8
9
|
if (
|
|
@@ -27,6 +28,7 @@ export const cleanupCsp = (
|
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
export default defineNitroPlugin((nitroApp) => {
|
|
31
|
+
// @ts-expect-error https://github.com/Baroshem/nuxt-security/pull/661
|
|
30
32
|
nitroApp.hooks.hook('nuxt-security:routeRules', async (routeRules) => {
|
|
31
33
|
const { siteUrlTyped: siteUrl } = useSiteUrl()
|
|
32
34
|
|
package/shared/utils/form.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import type { CombinedError } from '@urql/core'
|
|
2
2
|
import type { H3Event } from 'h3'
|
|
3
|
+
import { computed, reactive } from 'vue'
|
|
3
4
|
import type { Ref } from 'vue'
|
|
4
5
|
|
|
6
|
+
import type { ApiData, BackendError } from '../types/api'
|
|
7
|
+
|
|
5
8
|
export const getApiDataDefault = (): ApiData =>
|
|
6
9
|
computed(() =>
|
|
7
10
|
reactive({
|
package/shared/utils/nuxt.ts
CHANGED
package/shared/utils/utils.ts
CHANGED
package/app/plugins/dayjs.ts
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import dayjs from 'dayjs'
|
|
2
|
-
import type { DayjsFn } from 'dayjs'
|
|
3
|
-
|
|
4
|
-
import 'dayjs/locale/de'
|
|
5
|
-
|
|
6
|
-
import isSameOrBefore from 'dayjs/plugin/isSameOrBefore'
|
|
7
|
-
import localizedFormat from 'dayjs/plugin/localizedFormat'
|
|
8
|
-
import relativeTime from 'dayjs/plugin/relativeTime'
|
|
9
|
-
import timezone from 'dayjs/plugin/timezone'
|
|
10
|
-
import utc from 'dayjs/plugin/utc'
|
|
11
|
-
|
|
12
|
-
export default defineNuxtPlugin((_nuxtApp) => {
|
|
13
|
-
dayjs.extend(isSameOrBefore)
|
|
14
|
-
dayjs.extend(localizedFormat)
|
|
15
|
-
dayjs.extend(relativeTime)
|
|
16
|
-
dayjs.extend(timezone)
|
|
17
|
-
dayjs.extend(utc)
|
|
18
|
-
|
|
19
|
-
return {
|
|
20
|
-
provide: {
|
|
21
|
-
dayjs,
|
|
22
|
-
},
|
|
23
|
-
}
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
declare module '#app' {
|
|
27
|
-
interface NuxtApp {
|
|
28
|
-
$dayjs: DayjsFn
|
|
29
|
-
}
|
|
30
|
-
}
|
package/app/plugins/i18n.ts
DELETED
package/server/tsconfig.json
DELETED
package/shared/utils/auth.ts
DELETED
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
import type { Client } from '@urql/vue'
|
|
2
|
-
import { consola } from 'consola'
|
|
3
|
-
import { setCookie } from 'h3'
|
|
4
|
-
import type { H3Event } from 'h3'
|
|
5
|
-
import { decodeJwt } from 'jose'
|
|
6
|
-
|
|
7
|
-
import { useVioAuthStore } from '../../app/stores/auth'
|
|
8
|
-
|
|
9
|
-
export const getJwtFromCookie = () => {
|
|
10
|
-
const cookie = useCookie(JWT_NAME())
|
|
11
|
-
|
|
12
|
-
if (!cookie.value) {
|
|
13
|
-
consola.debug('No token cookie.')
|
|
14
|
-
return
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const jwt = decodeJwt(cookie.value)
|
|
18
|
-
|
|
19
|
-
if (jwt.exp === undefined || jwt.exp <= Date.now() / 1000) {
|
|
20
|
-
consola.info('Token expired.')
|
|
21
|
-
return
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
return {
|
|
25
|
-
jwt: cookie.value,
|
|
26
|
-
jwtDecoded: jwt,
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export const jwtStore = async ({
|
|
31
|
-
$urqlReset,
|
|
32
|
-
event,
|
|
33
|
-
isInProduction,
|
|
34
|
-
jwt,
|
|
35
|
-
store,
|
|
36
|
-
}: {
|
|
37
|
-
$urqlReset: () => Client
|
|
38
|
-
event?: H3Event
|
|
39
|
-
isInProduction: boolean
|
|
40
|
-
jwt?: string
|
|
41
|
-
store: ReturnType<typeof useVioAuthStore>
|
|
42
|
-
}) => {
|
|
43
|
-
$urqlReset()
|
|
44
|
-
|
|
45
|
-
consola.trace('Storing the following JWT: ' + jwt)
|
|
46
|
-
store.jwtSet(jwt)
|
|
47
|
-
|
|
48
|
-
if (event) {
|
|
49
|
-
setCookie(event, JWT_NAME(), jwt || '', {
|
|
50
|
-
expires: jwt ? new Date(Date.now() + 86400 * 1000 * 31) : new Date(0),
|
|
51
|
-
httpOnly: true,
|
|
52
|
-
path: '/',
|
|
53
|
-
sameSite: 'lax', // Cannot be 'strict' to allow authentications after clicking on links within webmailers.
|
|
54
|
-
secure: isInProduction,
|
|
55
|
-
})
|
|
56
|
-
} else {
|
|
57
|
-
try {
|
|
58
|
-
await $fetch('/api/auth', {
|
|
59
|
-
method: 'POST',
|
|
60
|
-
...(jwt ? { headers: { Authorization: `Bearer ${jwt}` } } : {}),
|
|
61
|
-
})
|
|
62
|
-
} catch (error) {
|
|
63
|
-
console.error(error)
|
|
64
|
-
return Promise.reject(Error('Authentication api call failed.'))
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export const useJwtStore = () => {
|
|
70
|
-
const { $urqlReset, ssrContext } = useNuxtApp()
|
|
71
|
-
const store = useVioAuthStore()
|
|
72
|
-
const runtimeConfig = useRuntimeConfig()
|
|
73
|
-
|
|
74
|
-
return {
|
|
75
|
-
async jwtStore(jwt?: string) {
|
|
76
|
-
await jwtStore({
|
|
77
|
-
$urqlReset: $urqlReset as () => Client,
|
|
78
|
-
event: ssrContext?.event,
|
|
79
|
-
isInProduction: runtimeConfig.public.vio.isInProduction,
|
|
80
|
-
jwt,
|
|
81
|
-
store,
|
|
82
|
-
})
|
|
83
|
-
},
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
export const signOut = async ({
|
|
88
|
-
$urqlReset,
|
|
89
|
-
// client,
|
|
90
|
-
event,
|
|
91
|
-
isInProduction,
|
|
92
|
-
store,
|
|
93
|
-
}: {
|
|
94
|
-
$urqlReset: () => Client
|
|
95
|
-
client: Client
|
|
96
|
-
event?: H3Event
|
|
97
|
-
isInProduction: boolean
|
|
98
|
-
store: ReturnType<typeof useVioAuthStore>
|
|
99
|
-
}) => {
|
|
100
|
-
await jwtStore({ $urqlReset, event, isInProduction, store })
|
|
101
|
-
// await authenticationAnonymous({
|
|
102
|
-
// $urqlReset,
|
|
103
|
-
// client,
|
|
104
|
-
// event,
|
|
105
|
-
// isInProduction,
|
|
106
|
-
// store,
|
|
107
|
-
// })
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
export const useSignOut = () => {
|
|
111
|
-
const { $urql, $urqlReset, ssrContext } = useNuxtApp()
|
|
112
|
-
const store = useVioAuthStore()
|
|
113
|
-
const runtimeConfig = useRuntimeConfig()
|
|
114
|
-
|
|
115
|
-
return {
|
|
116
|
-
async signOut() {
|
|
117
|
-
await signOut({
|
|
118
|
-
$urqlReset: $urqlReset as () => Client,
|
|
119
|
-
client: ($urql as Ref<Client>).value,
|
|
120
|
-
event: ssrContext?.event,
|
|
121
|
-
isInProduction: runtimeConfig.public.vio.isInProduction,
|
|
122
|
-
store,
|
|
123
|
-
})
|
|
124
|
-
},
|
|
125
|
-
}
|
|
126
|
-
}
|
|
File without changes
|