gothamstoryblok 1.0.15
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/README.md +84 -0
- package/dist/module.d.mts +11 -0
- package/dist/module.json +9 -0
- package/dist/module.mjs +50 -0
- package/dist/runtime/composables/useAsyncGothamStoryblok.d.ts +11 -0
- package/dist/runtime/composables/useAsyncGothamStoryblok.js +62 -0
- package/dist/runtime/composables/useLanguage.d.ts +6 -0
- package/dist/runtime/composables/useLanguage.js +15 -0
- package/dist/runtime/composables/useSeo.d.ts +1 -0
- package/dist/runtime/composables/useSeo.js +69 -0
- package/dist/runtime/composables/useSizes.d.ts +23 -0
- package/dist/runtime/composables/useSizes.js +70 -0
- package/dist/runtime/composables/useStoryblokEditor.d.ts +3 -0
- package/dist/runtime/composables/useStoryblokEditor.js +10 -0
- package/dist/runtime/plugins/01.setupLanguages.d.ts +2 -0
- package/dist/runtime/plugins/01.setupLanguages.js +26 -0
- package/dist/runtime/plugins/02.utils.d.ts +30 -0
- package/dist/runtime/plugins/02.utils.js +74 -0
- package/dist/runtime/plugins/03.labels.d.ts +6 -0
- package/dist/runtime/plugins/03.labels.js +50 -0
- package/dist/runtime/plugins/04.images.d.ts +8 -0
- package/dist/runtime/plugins/04.images.js +39 -0
- package/dist/runtime/plugins/05.datasources.d.ts +8 -0
- package/dist/runtime/plugins/05.datasources.js +19 -0
- package/dist/runtime/plugins/test.d.ts +2 -0
- package/dist/runtime/plugins/test.js +4 -0
- package/dist/runtime/server/api/storyblok/all.get.d.ts +2 -0
- package/dist/runtime/server/api/storyblok/all.get.js +16 -0
- package/dist/runtime/server/api/storyblok/cache.get.d.ts +2 -0
- package/dist/runtime/server/api/storyblok/cache.get.js +15 -0
- package/dist/runtime/server/api/storyblok/clearCache.get.d.ts +2 -0
- package/dist/runtime/server/api/storyblok/clearCache.get.js +66 -0
- package/dist/runtime/server/api/storyblok/clearCache.post.d.ts +2 -0
- package/dist/runtime/server/api/storyblok/clearCache.post.js +15 -0
- package/dist/runtime/server/api/storyblok/datasources.get.d.ts +2 -0
- package/dist/runtime/server/api/storyblok/datasources.get.js +41 -0
- package/dist/runtime/server/api/storyblok/getall.get.d.ts +2 -0
- package/dist/runtime/server/api/storyblok/getall.get.js +34 -0
- package/dist/runtime/server/api/storyblok/links.get.d.ts +2 -0
- package/dist/runtime/server/api/storyblok/links.get.js +17 -0
- package/dist/runtime/server/api/storyblok/request.get.d.ts +2 -0
- package/dist/runtime/server/api/storyblok/request.get.js +17 -0
- package/dist/runtime/server/api/storyblok/space.get.d.ts +2 -0
- package/dist/runtime/server/api/storyblok/space.get.js +14 -0
- package/dist/runtime/server/tsconfig.json +3 -0
- package/dist/runtime/server/utils/storyblok.d.ts +5 -0
- package/dist/runtime/server/utils/storyblok.js +183 -0
- package/dist/types.d.mts +3 -0
- package/package.json +55 -0
package/README.md
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
Get your module up and running quickly.
|
|
3
|
+
|
|
4
|
+
Find and replace all on all files (CMD+SHIFT+F):
|
|
5
|
+
- Name: My Module
|
|
6
|
+
- Package name: my-module
|
|
7
|
+
- Description: My new Nuxt module
|
|
8
|
+
-->
|
|
9
|
+
|
|
10
|
+
# My Module
|
|
11
|
+
|
|
12
|
+
[![npm version][npm-version-src]][npm-version-href]
|
|
13
|
+
[![npm downloads][npm-downloads-src]][npm-downloads-href]
|
|
14
|
+
[![License][license-src]][license-href]
|
|
15
|
+
[![Nuxt][nuxt-src]][nuxt-href]
|
|
16
|
+
|
|
17
|
+
My new Nuxt module for doing amazing things.
|
|
18
|
+
|
|
19
|
+
- [✨ Release Notes](/CHANGELOG.md)
|
|
20
|
+
<!-- - [🏀 Online playground](https://stackblitz.com/github/your-org/my-module?file=playground%2Fapp.vue) -->
|
|
21
|
+
<!-- - [📖 Documentation](https://example.com) -->
|
|
22
|
+
|
|
23
|
+
## Features
|
|
24
|
+
|
|
25
|
+
<!-- Highlight some of the features your module provide here -->
|
|
26
|
+
- ⛰ Foo
|
|
27
|
+
- 🚠 Bar
|
|
28
|
+
- 🌲 Baz
|
|
29
|
+
|
|
30
|
+
## Quick Setup
|
|
31
|
+
|
|
32
|
+
Install the module to your Nuxt application with one command:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npx nuxi module add my-module
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
That's it! You can now use My Module in your Nuxt app ✨
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
## Contribution
|
|
42
|
+
|
|
43
|
+
<details>
|
|
44
|
+
<summary>Local development</summary>
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
# Install dependencies
|
|
48
|
+
npm install
|
|
49
|
+
|
|
50
|
+
# Generate type stubs
|
|
51
|
+
npm run dev:prepare
|
|
52
|
+
|
|
53
|
+
# Develop with the playground
|
|
54
|
+
npm run dev
|
|
55
|
+
|
|
56
|
+
# Build the playground
|
|
57
|
+
npm run dev:build
|
|
58
|
+
|
|
59
|
+
# Run ESLint
|
|
60
|
+
npm run lint
|
|
61
|
+
|
|
62
|
+
# Run Vitest
|
|
63
|
+
npm run test
|
|
64
|
+
npm run test:watch
|
|
65
|
+
|
|
66
|
+
# Release new version
|
|
67
|
+
npm run release
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
</details>
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
<!-- Badges -->
|
|
74
|
+
[npm-version-src]: https://img.shields.io/npm/v/my-module/latest.svg?style=flat&colorA=020420&colorB=00DC82
|
|
75
|
+
[npm-version-href]: https://npmjs.com/package/my-module
|
|
76
|
+
|
|
77
|
+
[npm-downloads-src]: https://img.shields.io/npm/dm/my-module.svg?style=flat&colorA=020420&colorB=00DC82
|
|
78
|
+
[npm-downloads-href]: https://npm.chart.dev/my-module
|
|
79
|
+
|
|
80
|
+
[license-src]: https://img.shields.io/npm/l/my-module.svg?style=flat&colorA=020420&colorB=00DC82
|
|
81
|
+
[license-href]: https://npmjs.com/package/my-module
|
|
82
|
+
|
|
83
|
+
[nuxt-src]: https://img.shields.io/badge/Nuxt-020420?logo=nuxt
|
|
84
|
+
[nuxt-href]: https://nuxt.com
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import * as _nuxt_schema from '@nuxt/schema';
|
|
2
|
+
|
|
3
|
+
interface ModuleOptions {
|
|
4
|
+
expire: number;
|
|
5
|
+
version: 'draft' | 'published';
|
|
6
|
+
key: string;
|
|
7
|
+
}
|
|
8
|
+
declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
|
|
9
|
+
|
|
10
|
+
export { _default as default };
|
|
11
|
+
export type { ModuleOptions };
|
package/dist/module.json
ADDED
package/dist/module.mjs
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { readdirSync } from 'node:fs';
|
|
2
|
+
import { dirname, join } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { defineNuxtModule, createResolver, addPlugin, addServerHandler, addImportsDir } from '@nuxt/kit';
|
|
5
|
+
|
|
6
|
+
const currentDir = dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
const addServerRoutes = (resolver) => {
|
|
8
|
+
const basePath = "/api/storyblok";
|
|
9
|
+
const sourcePath = "./runtime/server/api/storyblok";
|
|
10
|
+
const targetDir = join(currentDir, sourcePath);
|
|
11
|
+
const files = readdirSync(targetDir);
|
|
12
|
+
const cleanedFiles = files.filter((e) => e.includes(".js") || e.includes(".ts")).map((e) => e.replace(".js", "").replace(".ts", ""));
|
|
13
|
+
cleanedFiles.forEach((handler) => {
|
|
14
|
+
const [route, method] = handler.split(".");
|
|
15
|
+
addServerHandler({
|
|
16
|
+
route: `${basePath}/${route}`,
|
|
17
|
+
handler: resolver.resolve(`${sourcePath}/${route}.${method}`)
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
};
|
|
21
|
+
const addPlugins = (resolver) => {
|
|
22
|
+
addPlugin(resolver.resolve("./runtime/plugins/01.setupLanguages"));
|
|
23
|
+
addPlugin(resolver.resolve("./runtime/plugins/02.utils"));
|
|
24
|
+
addPlugin(resolver.resolve("./runtime/plugins/03.labels"));
|
|
25
|
+
addPlugin(resolver.resolve("./runtime/plugins/04.images"));
|
|
26
|
+
addPlugin(resolver.resolve("./runtime/plugins/05.datasources"));
|
|
27
|
+
};
|
|
28
|
+
const addComposables = (resolver) => {
|
|
29
|
+
addImportsDir(resolver.resolve("runtime/composables"));
|
|
30
|
+
};
|
|
31
|
+
const module$1 = defineNuxtModule({
|
|
32
|
+
meta: {
|
|
33
|
+
name: "gothamstoryblok",
|
|
34
|
+
configKey: "gothamstoryblok"
|
|
35
|
+
},
|
|
36
|
+
defaults: {
|
|
37
|
+
expire: 1,
|
|
38
|
+
version: "draft",
|
|
39
|
+
key: ""
|
|
40
|
+
},
|
|
41
|
+
setup(_options, _nuxt) {
|
|
42
|
+
_nuxt.options.runtimeConfig.gothamstoryblok = { ..._options };
|
|
43
|
+
const resolver = createResolver(import.meta.url);
|
|
44
|
+
addPlugins(resolver);
|
|
45
|
+
addServerRoutes(resolver);
|
|
46
|
+
addComposables(resolver);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
export { module$1 as default };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export function useAsyncGothamStoryblok(url: any, options: any, bridgeOptions: any, nocomponent?: boolean): Promise<{
|
|
2
|
+
story?: undefined;
|
|
3
|
+
stories?: undefined;
|
|
4
|
+
rels?: undefined;
|
|
5
|
+
refresh?: undefined;
|
|
6
|
+
} | {
|
|
7
|
+
story: import("vue").Ref<any, any>;
|
|
8
|
+
stories: import("vue").Ref<any, any>;
|
|
9
|
+
rels: import("vue").Ref<any, any>;
|
|
10
|
+
refresh: () => void;
|
|
11
|
+
}>;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { useStoryblokBridge } from '@storyblok/vue'
|
|
2
|
+
import { useNuxtApp, useState, useAsyncData, createError, useLanguage, onMounted } from '#imports'
|
|
3
|
+
|
|
4
|
+
export const useAsyncGothamStoryblok = async (url, options, bridgeOptions, nocomponent = false) => {
|
|
5
|
+
const { $__ } = useNuxtApp()
|
|
6
|
+
const uniqueKey = `${JSON.stringify(options)}${url}`
|
|
7
|
+
const story = useState(`${uniqueKey}-state`)
|
|
8
|
+
const stories = useState(`${uniqueKey}-stories-state`)
|
|
9
|
+
const rels = useState(`${uniqueKey}-rels-state`)
|
|
10
|
+
if (!nocomponent) {
|
|
11
|
+
onMounted(() => {
|
|
12
|
+
if (!stories.value && story.value && story.value.id) {
|
|
13
|
+
useStoryblokBridge(
|
|
14
|
+
story.value.id,
|
|
15
|
+
evStory => (story.value = evStory),
|
|
16
|
+
bridgeOptions,
|
|
17
|
+
)
|
|
18
|
+
}
|
|
19
|
+
})
|
|
20
|
+
}
|
|
21
|
+
var refresh = () => {}
|
|
22
|
+
if (!story.value) {
|
|
23
|
+
const { data, error, refresh: refreshAsync } = await useAsyncData(uniqueKey, async () => {
|
|
24
|
+
var params = {
|
|
25
|
+
fullSlug: url,
|
|
26
|
+
}
|
|
27
|
+
if (options) params = { ...params, ...options }
|
|
28
|
+
const { currentLanguage, defaultLanguage } = useLanguage()
|
|
29
|
+
if (!params.language && currentLanguage.value != defaultLanguage) params.language = currentLanguage.value
|
|
30
|
+
|
|
31
|
+
if (params.isEditor) {
|
|
32
|
+
const { $__clearCache } = useNuxtApp()
|
|
33
|
+
await $__clearCache(params)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return $fetch('/api/storyblok/request', { query: params })
|
|
37
|
+
})
|
|
38
|
+
refresh = refreshAsync
|
|
39
|
+
|
|
40
|
+
if (error.value) throw error.value
|
|
41
|
+
|
|
42
|
+
if (!data?.value && !nocomponent) throw createError({ statusCode: 404, statusMessage: $__('errorPageNotFound'), fatal: true })
|
|
43
|
+
if (data?.value) {
|
|
44
|
+
if (data.value.total) {
|
|
45
|
+
stories.value = data.value.stories
|
|
46
|
+
return { ...data.value }
|
|
47
|
+
}
|
|
48
|
+
if (Array.isArray(data.value)) {
|
|
49
|
+
stories.value = data.value
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
story.value = data.value
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (options?.resolve_relations) {
|
|
56
|
+
story.value = data.value?.story
|
|
57
|
+
rels.value = data.value?.rels
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return { story, stories, rels, refresh }
|
|
62
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { useState } from '#imports'
|
|
2
|
+
|
|
3
|
+
export const useLanguage = () => {
|
|
4
|
+
const languages = useState('languages', () => undefined)
|
|
5
|
+
const currentLanguage = useState('currentLanguage', () => undefined)
|
|
6
|
+
const defaultLanguage = useState('defaultLanguage', () => undefined)
|
|
7
|
+
const slugList = useState('slugList', () => [])
|
|
8
|
+
|
|
9
|
+
return {
|
|
10
|
+
languages,
|
|
11
|
+
currentLanguage,
|
|
12
|
+
defaultLanguage,
|
|
13
|
+
slugList,
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function useSeo(story: any): void;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { renderRichText } from '@storyblok/js'
|
|
2
|
+
import { useRequestURL, useRoute, useNuxtApp, useLanguage, useHead } from '#imports'
|
|
3
|
+
|
|
4
|
+
const hostChecker = (array, string) => {
|
|
5
|
+
for (var i in array) {
|
|
6
|
+
if (string?.includes(array[i])) return true
|
|
7
|
+
}
|
|
8
|
+
return false
|
|
9
|
+
}
|
|
10
|
+
export const useSeo = (story) => {
|
|
11
|
+
const richText = data => renderRichText(data)
|
|
12
|
+
const { host } = useRequestURL()
|
|
13
|
+
const route = useRoute()
|
|
14
|
+
const { defaultLanguage } = useLanguage()
|
|
15
|
+
const { $__, $__img } = useNuxtApp()
|
|
16
|
+
var siteName = $__('configSiteName') != '' ? `${$__('configSiteName')} - ` : ''
|
|
17
|
+
const metadata
|
|
18
|
+
= story.value?.content?.metadata
|
|
19
|
+
|| {
|
|
20
|
+
title: null,
|
|
21
|
+
description: $__('configSiteDescription'),
|
|
22
|
+
image: $__img('configSiteImage'),
|
|
23
|
+
follow: 'follow',
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
var { title, description, image, follow } = metadata
|
|
27
|
+
title = title || story?.value?.content?.title || story?.name
|
|
28
|
+
|
|
29
|
+
if (typeof title == 'object' && title?.type) {
|
|
30
|
+
const rendered = richText(title)
|
|
31
|
+
title = rendered?.replace(/<[^>]*>?/g, '')
|
|
32
|
+
}
|
|
33
|
+
if (!title && siteName && siteName?.includes(' - ')) {
|
|
34
|
+
siteName = siteName.replace(' - ', '')
|
|
35
|
+
title = ''
|
|
36
|
+
}
|
|
37
|
+
title = siteName + title
|
|
38
|
+
|
|
39
|
+
description = description || story?.value?.content?.previewText || $__('configSiteDescription')
|
|
40
|
+
|
|
41
|
+
const noFollow = follow == 'nofollow' || hostChecker(['development', 'staging'], host)
|
|
42
|
+
follow = noFollow ? 'noindex, nofollow' : 'index, follow'
|
|
43
|
+
|
|
44
|
+
const path = route.fullPath || route.path
|
|
45
|
+
|
|
46
|
+
useHead({
|
|
47
|
+
title: title,
|
|
48
|
+
htmlAttrs: {
|
|
49
|
+
lang: route.params.lang || defaultLanguage.value,
|
|
50
|
+
},
|
|
51
|
+
link: [
|
|
52
|
+
{ rel: 'canonical', href: 'https://' + host + path },
|
|
53
|
+
],
|
|
54
|
+
meta: [
|
|
55
|
+
{ property: 'og:url', content: 'https://' + host + path },
|
|
56
|
+
{ property: 'og:image:width', content: '1200' },
|
|
57
|
+
{ property: 'og:image:height', content: '630' },
|
|
58
|
+
{ property: 'og:image', content: image },
|
|
59
|
+
{ property: 'og:description', content: description },
|
|
60
|
+
{ property: 'og:site_name', content: $__('configSiteName') },
|
|
61
|
+
{ property: 'og:title', content: title },
|
|
62
|
+
{ property: 'og:type', content: 'article' },
|
|
63
|
+
{ name: 'apple-mobile-web-app-title', content: title },
|
|
64
|
+
{ name: 'application-name', content: $__('configSiteName') },
|
|
65
|
+
{ name: 'description', content: description },
|
|
66
|
+
{ name: 'robots', content: follow },
|
|
67
|
+
],
|
|
68
|
+
})
|
|
69
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export function useSizes(): {
|
|
2
|
+
reference: import("vue").Ref<undefined, undefined>;
|
|
3
|
+
sizes: import("vue").Ref<{
|
|
4
|
+
width: number;
|
|
5
|
+
height: number;
|
|
6
|
+
fr: number;
|
|
7
|
+
}, {
|
|
8
|
+
width: number;
|
|
9
|
+
height: number;
|
|
10
|
+
fr: number;
|
|
11
|
+
}>;
|
|
12
|
+
scroll: import("vue").Ref<{
|
|
13
|
+
top: number;
|
|
14
|
+
left: number;
|
|
15
|
+
}, {
|
|
16
|
+
top: number;
|
|
17
|
+
left: number;
|
|
18
|
+
}>;
|
|
19
|
+
observe: (el: any, fn: any) => void;
|
|
20
|
+
mw: (size: any) => number;
|
|
21
|
+
mh: (size: any) => number;
|
|
22
|
+
init: () => void;
|
|
23
|
+
};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { useState, watch } from '#imports'
|
|
2
|
+
|
|
3
|
+
export const useSizes = () => {
|
|
4
|
+
const gridCount = 80
|
|
5
|
+
const reference = useState('reference', () => undefined)
|
|
6
|
+
|
|
7
|
+
const mw = (size) => {
|
|
8
|
+
if (size) return sizes.value.fr * size
|
|
9
|
+
return 0
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const mh = (size) => {
|
|
13
|
+
if (size) return sizes.value.height / 100 * size
|
|
14
|
+
return 0
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const sizes = useState('sizes', () => ({ width: 0, height: 0, fr: 0 }))
|
|
18
|
+
const scroll = useState('scroll', () => ({ top: 0, left: 0 }))
|
|
19
|
+
|
|
20
|
+
const resizeListener = () => {
|
|
21
|
+
reference.value = reference.value ?? window
|
|
22
|
+
// se mi riferisco alla window devo recuperare la inner altrimenti recupero la client
|
|
23
|
+
const width = (reference.value.clientWidth ?? reference.value.innerWidth)
|
|
24
|
+
const height = (reference.value.clientHeight ?? reference.value.innerHeight)
|
|
25
|
+
|
|
26
|
+
sizes.value.fr = width / gridCount
|
|
27
|
+
sizes.value.width = width
|
|
28
|
+
sizes.value.height = height
|
|
29
|
+
}
|
|
30
|
+
const scrollListener = () => {
|
|
31
|
+
const top = reference.value.scrollY !== undefined ? reference.value.scrollY : reference.value.scrollTop
|
|
32
|
+
const left = reference.value.scrollY !== undefined ? reference.value.scrollX : reference.value.scrollLeft
|
|
33
|
+
|
|
34
|
+
scroll.value.top = top
|
|
35
|
+
scroll.value.left = left
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
watch(reference, () => {
|
|
39
|
+
resizeListener()
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
const init = () => {
|
|
43
|
+
if (import.meta.client) {
|
|
44
|
+
resizeListener()
|
|
45
|
+
window.addEventListener('resize', resizeListener)
|
|
46
|
+
window.addEventListener('scroll', scrollListener)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const observer = useState('observer', () => null)
|
|
51
|
+
const observerFunctions = useState('observerFunctions', () => [])
|
|
52
|
+
if (import.meta.client && !observer.value) {
|
|
53
|
+
observer.value = new IntersectionObserver((entries) => {
|
|
54
|
+
entries.forEach((entry) => {
|
|
55
|
+
if (entry.isIntersecting) {
|
|
56
|
+
const index = entry.target.dataset.functionIndex
|
|
57
|
+
const fn = observerFunctions.value[index]
|
|
58
|
+
fn()
|
|
59
|
+
}
|
|
60
|
+
})
|
|
61
|
+
}, { threshold: 0.1 })
|
|
62
|
+
}
|
|
63
|
+
const observe = (el, fn) => {
|
|
64
|
+
observer.value.observe(el)
|
|
65
|
+
observerFunctions.value.push(fn)
|
|
66
|
+
el.dataset.functionIndex = observerFunctions.value.indexOf(fn)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return { reference, sizes, scroll, observe, mw, mh, init }
|
|
70
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { useRoute, useState } from '#imports'
|
|
2
|
+
|
|
3
|
+
export const useStoryblokEditor = () => {
|
|
4
|
+
const route = useRoute()
|
|
5
|
+
const sbEditor = useState('sbEditor', () => {
|
|
6
|
+
return false
|
|
7
|
+
})
|
|
8
|
+
sbEditor.value = Object.keys(route.query)?.includes('_storyblok_tk[space_id]')
|
|
9
|
+
return { sbEditor }
|
|
10
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { createError, useLanguage, useRoute } from '#imports'
|
|
2
|
+
import { defineNuxtPlugin } from '#app'
|
|
3
|
+
|
|
4
|
+
export default defineNuxtPlugin({
|
|
5
|
+
name: 'setuplanguages',
|
|
6
|
+
parallel: false,
|
|
7
|
+
async setup() {
|
|
8
|
+
const { languages, currentLanguage, defaultLanguage } = useLanguage()
|
|
9
|
+
const route = useRoute()
|
|
10
|
+
const { fullslug } = route.params
|
|
11
|
+
currentLanguage.value = fullslug && fullslug[0] ? fullslug[0] : undefined
|
|
12
|
+
if (import.meta.server) {
|
|
13
|
+
try {
|
|
14
|
+
const space = await $fetch('/api/storyblok/space')
|
|
15
|
+
languages.value = space.available_languages
|
|
16
|
+
defaultLanguage.value = space.default_language
|
|
17
|
+
if (currentLanguage.value?.length != 2) currentLanguage.value = defaultLanguage.value
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
console.log(error)
|
|
21
|
+
throw createError({ statusCode: 500, statusMessage: 'Error setupLanguage plugin' })
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
if (currentLanguage.value?.length != 2) currentLanguage.value = defaultLanguage.value
|
|
25
|
+
},
|
|
26
|
+
})
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
declare const _default: import("#app").Plugin<{
|
|
2
|
+
__url: (u: any) => any;
|
|
3
|
+
__parseEndpoint: () => {
|
|
4
|
+
endpoint: undefined;
|
|
5
|
+
language?: undefined;
|
|
6
|
+
version?: undefined;
|
|
7
|
+
} | {
|
|
8
|
+
endpoint: any;
|
|
9
|
+
language: any;
|
|
10
|
+
version: unknown;
|
|
11
|
+
};
|
|
12
|
+
__filename: (str: any) => any;
|
|
13
|
+
__formatDate: (d: any) => string;
|
|
14
|
+
__clearCache: (query: any) => Promise<void>;
|
|
15
|
+
}> & import("#app").ObjectPlugin<{
|
|
16
|
+
__url: (u: any) => any;
|
|
17
|
+
__parseEndpoint: () => {
|
|
18
|
+
endpoint: undefined;
|
|
19
|
+
language?: undefined;
|
|
20
|
+
version?: undefined;
|
|
21
|
+
} | {
|
|
22
|
+
endpoint: any;
|
|
23
|
+
language: any;
|
|
24
|
+
version: unknown;
|
|
25
|
+
};
|
|
26
|
+
__filename: (str: any) => any;
|
|
27
|
+
__formatDate: (d: any) => string;
|
|
28
|
+
__clearCache: (query: any) => Promise<void>;
|
|
29
|
+
}>;
|
|
30
|
+
export default _default;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { defineNuxtPlugin } from '#app'
|
|
2
|
+
import { useLanguage, useRoute, useRuntimeConfig, useStoryblokEditor } from '#imports'
|
|
3
|
+
|
|
4
|
+
export default defineNuxtPlugin({
|
|
5
|
+
dependsOn: ['labels', 'images'],
|
|
6
|
+
async setup() {
|
|
7
|
+
return {
|
|
8
|
+
provide: {
|
|
9
|
+
__url: (u) => {
|
|
10
|
+
if (!u) return undefined
|
|
11
|
+
if (u == '#' || u.substring(0, 4) == 'http') return u
|
|
12
|
+
const { languages, currentLanguage, slugList } = useLanguage()
|
|
13
|
+
u = u.substring(0, 1) == '/' ? u : '/' + u
|
|
14
|
+
if (languages.value.length < 2) return u
|
|
15
|
+
u = u.replace(/([^:])\/\//g, '$1/')
|
|
16
|
+
const founded = slugList.value.find(s => (u == s.fullslug || u == '/' + s.fullslug))
|
|
17
|
+
if (founded?.slugs) {
|
|
18
|
+
const sp = u.split('/')
|
|
19
|
+
sp[sp.length - 1] = founded?.slugs[currentLanguage.value]
|
|
20
|
+
u = sp.join('/')
|
|
21
|
+
}
|
|
22
|
+
const prefix = '/' + currentLanguage.value + '/'
|
|
23
|
+
const startString = u.substring(0, 4)
|
|
24
|
+
if (prefix != startString) u = prefix + u
|
|
25
|
+
u = u.replace(/([^:])\/\//g, '$1/')
|
|
26
|
+
return u
|
|
27
|
+
},
|
|
28
|
+
__parseEndpoint: () => {
|
|
29
|
+
const config = useRuntimeConfig()
|
|
30
|
+
const route = useRoute()
|
|
31
|
+
const { languages, currentLanguage, defaultLanguage, slugList } = useLanguage()
|
|
32
|
+
|
|
33
|
+
let language
|
|
34
|
+
let fullslug
|
|
35
|
+
|
|
36
|
+
if (route?.params?.fullslug && route?.params?.fullslug.length > 0) {
|
|
37
|
+
fullslug = JSON.parse(JSON.stringify(route?.params?.fullslug))
|
|
38
|
+
const availableLanguages = languages.value
|
|
39
|
+
if (availableLanguages?.includes(fullslug[0])) {
|
|
40
|
+
language = fullslug[0] != defaultLanguage.value ? fullslug[0] : undefined
|
|
41
|
+
fullslug.shift()
|
|
42
|
+
}
|
|
43
|
+
if (fullslug[0] == '' || !fullslug[0]) fullslug = undefined
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const endpoint = fullslug || ['homepage']
|
|
47
|
+
const version = config.public.storyblokVersion
|
|
48
|
+
// ECCEZIONE PER I TRANSLATED SLUGS
|
|
49
|
+
if (!route.query['_storyblok_tk[token]'] && slugList.value?.length > 0) {
|
|
50
|
+
let slug = endpoint.pop()
|
|
51
|
+
const founded = slugList.value.find(s => s.slugs[currentLanguage.value] == slug)
|
|
52
|
+
if (!founded?.slug) {
|
|
53
|
+
return { endpoint: undefined }
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
endpoint.push(founded?.slug)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return { endpoint: endpoint.join('/'), language, version }
|
|
60
|
+
},
|
|
61
|
+
__filename: (str) => {
|
|
62
|
+
return str.replace(/^.*[\\/]/, '')
|
|
63
|
+
},
|
|
64
|
+
__formatDate: d => (new Date(d)).toLocaleDateString('IT-it', { day: '2-digit', month: '2-digit', year: 'numeric' }),
|
|
65
|
+
__clearCache: async (query) => {
|
|
66
|
+
const { sbEditor } = useStoryblokEditor()
|
|
67
|
+
if (sbEditor.value) {
|
|
68
|
+
await $fetch('/api/storyblok/clearCache', { query })
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
})
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { defineNuxtPlugin } from '#app'
|
|
2
|
+
import { useFetch, useRoute, useLanguage } from '#imports'
|
|
3
|
+
|
|
4
|
+
export default defineNuxtPlugin({
|
|
5
|
+
name: 'labels',
|
|
6
|
+
parallel: true,
|
|
7
|
+
async setup() {
|
|
8
|
+
const { params } = useRoute()
|
|
9
|
+
const { defaultLanguage, languages } = useLanguage()
|
|
10
|
+
|
|
11
|
+
var labels = {}
|
|
12
|
+
let language = defaultLanguage.value
|
|
13
|
+
if (params?.fullslug && params?.fullslug.length > 0) {
|
|
14
|
+
const fullslug = JSON.parse(JSON.stringify(params?.fullslug))
|
|
15
|
+
if (languages.value?.includes(fullslug[0])) {
|
|
16
|
+
language = fullslug[0]
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
const query = {
|
|
20
|
+
starts_with: 'system/labels',
|
|
21
|
+
language,
|
|
22
|
+
}
|
|
23
|
+
const { data: stories } = await useFetch('/api/storyblok/request', {
|
|
24
|
+
query,
|
|
25
|
+
})
|
|
26
|
+
if (stories?.value?.length) {
|
|
27
|
+
for (var story of stories.value) {
|
|
28
|
+
if (story?.content?.items?.length) {
|
|
29
|
+
for (var label of story.content.items) {
|
|
30
|
+
labels[label.key] = label.text
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
provide: {
|
|
37
|
+
__: (...args) => {
|
|
38
|
+
var s = args[0]
|
|
39
|
+
var prefix = args[2]
|
|
40
|
+
const key = prefix ? prefix + '_' + s : s
|
|
41
|
+
s = labels[key] || labels[key] === '' ? labels[key] : s
|
|
42
|
+
for (var i = 1; i < args.length; i++) {
|
|
43
|
+
s = s.replace('%s', args[i])
|
|
44
|
+
}
|
|
45
|
+
return s || ''
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
})
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { defineNuxtPlugin, useFetch } from '#app'
|
|
2
|
+
|
|
3
|
+
export default defineNuxtPlugin({
|
|
4
|
+
name: 'images',
|
|
5
|
+
parallel: true,
|
|
6
|
+
async setup() {
|
|
7
|
+
var images = {}
|
|
8
|
+
const { data: stories } = await useFetch('/api/storyblok/request', {
|
|
9
|
+
query: {
|
|
10
|
+
starts_with: 'system/images',
|
|
11
|
+
},
|
|
12
|
+
})
|
|
13
|
+
if (stories?.value?.length) {
|
|
14
|
+
for (var story of stories.value) {
|
|
15
|
+
if (story.content?.items?.length) {
|
|
16
|
+
for (var image of story.content.items) {
|
|
17
|
+
images[image.key] = image.asset
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return {
|
|
23
|
+
provide: {
|
|
24
|
+
__img: (key) => {
|
|
25
|
+
return images[key]
|
|
26
|
+
},
|
|
27
|
+
__svg: async (svgUrl) => {
|
|
28
|
+
if (!svgUrl) return null
|
|
29
|
+
const extension = svgUrl.split('.').pop()
|
|
30
|
+
if (!extension?.includes('svg')) return null
|
|
31
|
+
svgUrl = svgUrl.replace('https://', 'https://s3.amazonaws.com/')
|
|
32
|
+
const response = await $fetch(svgUrl)
|
|
33
|
+
const data = await response.text()
|
|
34
|
+
return data
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
})
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { defineNuxtPlugin, useFetch } from '#app'
|
|
2
|
+
|
|
3
|
+
export default defineNuxtPlugin({
|
|
4
|
+
async setup() {
|
|
5
|
+
const { data: datasources } = await useFetch('/api/storyblok/datasources')
|
|
6
|
+
return {
|
|
7
|
+
provide: {
|
|
8
|
+
__datasource: (key) => {
|
|
9
|
+
return datasources.value.find(d => d?.value == key)
|
|
10
|
+
},
|
|
11
|
+
__datasources: (key) => {
|
|
12
|
+
if (key) return datasources.value.filter(d => d?.datasource == key)
|
|
13
|
+
|
|
14
|
+
return datasources
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
})
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { getAll } from '../../utils/storyblok.js'
|
|
2
|
+
import { defineCachedEventHandler, getQuery, setHeader } from '#imports'
|
|
3
|
+
|
|
4
|
+
export default defineCachedEventHandler(async (event) => {
|
|
5
|
+
const query = getQuery(event)
|
|
6
|
+
setHeader(event, 'x-origin-url', event.node.req.url)
|
|
7
|
+
return await getAll(query)
|
|
8
|
+
}, {
|
|
9
|
+
maxAge: process.env.DEFAULT_EXPIRE,
|
|
10
|
+
group: 'storyblok',
|
|
11
|
+
shouldInvalidateCache: (e) => {
|
|
12
|
+
const query = getQuery(e)
|
|
13
|
+
const bypass = query.sbToken != undefined
|
|
14
|
+
return bypass
|
|
15
|
+
},
|
|
16
|
+
})
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { defineEventHandler, useStorage } from '#imports'
|
|
2
|
+
|
|
3
|
+
export default defineEventHandler(async () => {
|
|
4
|
+
const cacheStorage = useStorage('cache:storyblok:_')
|
|
5
|
+
const cachedKeys = await cacheStorage.getKeys()
|
|
6
|
+
const promises = cachedKeys.map(async (c) => {
|
|
7
|
+
const item = await cacheStorage.getItem(c)
|
|
8
|
+
return {
|
|
9
|
+
name: c,
|
|
10
|
+
...item,
|
|
11
|
+
}
|
|
12
|
+
})
|
|
13
|
+
const items = await Promise.all(promises)
|
|
14
|
+
return items
|
|
15
|
+
})
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import Cloudflare from 'cloudflare'
|
|
2
|
+
import { clearLinks } from '../../utils/storyblok.js'
|
|
3
|
+
import { defineEventHandler, useRuntimeConfig, getQuery, useStorage } from '#imports'
|
|
4
|
+
|
|
5
|
+
const { cloudflare } = useRuntimeConfig()
|
|
6
|
+
|
|
7
|
+
const { zoneID, email, apiKey } = cloudflare
|
|
8
|
+
let cloudFlareClient
|
|
9
|
+
if (apiKey && email) {
|
|
10
|
+
cloudFlareClient = new Cloudflare({
|
|
11
|
+
apiEmail: email,
|
|
12
|
+
apiKey: apiKey,
|
|
13
|
+
})
|
|
14
|
+
}
|
|
15
|
+
const foundSlugInBody = (body, slug) => {
|
|
16
|
+
if (body?.full_slug && body?.full_slug == slug) return true
|
|
17
|
+
if (!body?.full_slug && Array.isArray(body)) {
|
|
18
|
+
const filtered = body.filter(e => e.full_slug == slug || e.full_slug == slug + '/')
|
|
19
|
+
return filtered.length > 0
|
|
20
|
+
}
|
|
21
|
+
const stringbody = JSON.stringify(body)
|
|
22
|
+
if (stringbody.includes(slug)) return true
|
|
23
|
+
return false
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export default defineEventHandler(async (event) => {
|
|
27
|
+
// Clear cache Nitro
|
|
28
|
+
const config = useRuntimeConfig()
|
|
29
|
+
const query = getQuery(event)
|
|
30
|
+
const { fullSlug, language, itemId } = query
|
|
31
|
+
const cacheStorage = useStorage('cache:storyblok:_')
|
|
32
|
+
const cachedKeys = await cacheStorage.getKeys()
|
|
33
|
+
const endpoint = language && language != config.defaultLanguage ? `${language}/${fullSlug}` : fullSlug
|
|
34
|
+
console.log('Clear cache Nitro - endpoint', endpoint)
|
|
35
|
+
if (itemId) {
|
|
36
|
+
console.log('ITEM ID', itemId)
|
|
37
|
+
return await cacheStorage.removeItem(itemId)
|
|
38
|
+
}
|
|
39
|
+
// ho rimosso il push nell'array del promise all perché per qualche ragione non svuotava correttamente in locale.
|
|
40
|
+
// così è più lento ma funziona.
|
|
41
|
+
for (var i in cachedKeys) {
|
|
42
|
+
if (fullSlug) {
|
|
43
|
+
const stored = await cacheStorage.getItem(cachedKeys[i])
|
|
44
|
+
const toclear = foundSlugInBody(stored?.value?.body, endpoint)
|
|
45
|
+
if (toclear) {
|
|
46
|
+
console.log('clerearing', cachedKeys[i])
|
|
47
|
+
await cacheStorage.removeItem(cachedKeys[i])
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
await cacheStorage.removeItem(cachedKeys[i])
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
console.log('Cleared cache Nitro - endpoint', endpoint)
|
|
55
|
+
await clearLinks()
|
|
56
|
+
|
|
57
|
+
if (cloudFlareClient) {
|
|
58
|
+
try {
|
|
59
|
+
await cloudFlareClient.cache.purge({ zone_id: zoneID, purge_everything: true })
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
console.log('err purge cloudflare cache', error)
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return true
|
|
66
|
+
})
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { clearLinks } from '../../utils/storyblok.js'
|
|
2
|
+
import { defineEventHandler, useStorage } from '#imports'
|
|
3
|
+
|
|
4
|
+
export default defineEventHandler(async () => {
|
|
5
|
+
// Clear cache Nitro
|
|
6
|
+
const cacheStorage = useStorage('cache:storyblok:_')
|
|
7
|
+
const cachedKeys = await cacheStorage.getKeys()
|
|
8
|
+
let promiseArr = []
|
|
9
|
+
for (var i in cachedKeys) promiseArr.push(cacheStorage.removeItem(cachedKeys[i]))
|
|
10
|
+
await Promise.all(promiseArr)
|
|
11
|
+
|
|
12
|
+
await clearLinks()
|
|
13
|
+
|
|
14
|
+
return true
|
|
15
|
+
})
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// https://developers.cloudflare.com/workers/examples/aggregate-requests/
|
|
2
|
+
|
|
3
|
+
import { defineCachedEventHandler, useRuntimeConfig, createError, getQuery } from '#imports'
|
|
4
|
+
|
|
5
|
+
const config = useRuntimeConfig()
|
|
6
|
+
export default defineCachedEventHandler(async () => {
|
|
7
|
+
try {
|
|
8
|
+
let arr = []
|
|
9
|
+
const cv = Date.now()
|
|
10
|
+
const { datasources } = await fetch('https://api.storyblok.com/v2/cdn/datasources?' + new URLSearchParams({ token: config.gothamstoryblok.key, per_page: 100, cv }), { headers: { 'Content-Type': 'application/json' } }).then(response => response.json())
|
|
11
|
+
|
|
12
|
+
const promiseArr = []
|
|
13
|
+
datasources.map((d) => {
|
|
14
|
+
promiseArr.push(
|
|
15
|
+
fetch('https://api.storyblok.com/v2/cdn/datasource_entries?' + new URLSearchParams({ token: config.gothamstoryblok.key, per_page: 100, cv, datasource: d.slug }, { headers: { 'Content-Type': 'application/json' } })),
|
|
16
|
+
)
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
const responses = await Promise.all(promiseArr)
|
|
20
|
+
const response = await Promise.all(responses.map(r => r.json()))
|
|
21
|
+
|
|
22
|
+
for (var i in response) {
|
|
23
|
+
response[i].datasource_entries = response[i].datasource_entries.map(e => ({ ...e, datasource: datasources[i].slug }))
|
|
24
|
+
arr = arr.concat(response[i].datasource_entries)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return arr
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
console.log(error)
|
|
31
|
+
throw createError({ statusCode: 500, statusMessage: 'Error building datasources' })
|
|
32
|
+
}
|
|
33
|
+
}, {
|
|
34
|
+
maxAge: process.env.DEFAULT_EXPIRE,
|
|
35
|
+
group: 'storyblok',
|
|
36
|
+
shouldInvalidateCache: (e) => {
|
|
37
|
+
const query = getQuery(e)
|
|
38
|
+
const bypass = query.sbToken != undefined
|
|
39
|
+
return bypass
|
|
40
|
+
},
|
|
41
|
+
})
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { storyblokInit, apiPlugin } from '@storyblok/js'
|
|
2
|
+
import { defineCachedEventHandler, useRuntimeConfig, getQuery } from '#imports'
|
|
3
|
+
|
|
4
|
+
const config = useRuntimeConfig()
|
|
5
|
+
const { storyblokApi } = storyblokInit({
|
|
6
|
+
accessToken: config.gothamstoryblok.key,
|
|
7
|
+
use: [apiPlugin],
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
export default defineCachedEventHandler(async (event) => {
|
|
11
|
+
const query = getQuery(event)
|
|
12
|
+
delete query.sbToken
|
|
13
|
+
const params = {
|
|
14
|
+
...query,
|
|
15
|
+
version: config.gothamstoryblok.version,
|
|
16
|
+
}
|
|
17
|
+
storyblokApi.flushCache()
|
|
18
|
+
const { data: { stories } } = await storyblokApi.get('cdn/stories', params)
|
|
19
|
+
|
|
20
|
+
return stories
|
|
21
|
+
}, {
|
|
22
|
+
maxAge: 60 * 60 * 12,
|
|
23
|
+
group: 'storyblok',
|
|
24
|
+
shouldInvalidateCache: async (e) => {
|
|
25
|
+
const query = getQuery(e)
|
|
26
|
+
const bypass = query.sbToken != undefined
|
|
27
|
+
console.log('bypass', bypass)
|
|
28
|
+
if (bypass) {
|
|
29
|
+
storyblokApi.flushCache()
|
|
30
|
+
await $fetch('/api/storyblok/clearCache')
|
|
31
|
+
}
|
|
32
|
+
return bypass
|
|
33
|
+
},
|
|
34
|
+
})
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { links } from '../../utils/storyblok.js'
|
|
2
|
+
import { defineCachedEventHandler, getQuery, setHeader } from '#imports'
|
|
3
|
+
|
|
4
|
+
export default defineCachedEventHandler(async (event) => {
|
|
5
|
+
const query = getQuery(event)
|
|
6
|
+
setHeader(event, 'x-origin-url', event.node.req.url)
|
|
7
|
+
return await links(query)
|
|
8
|
+
}, {
|
|
9
|
+
maxAge: process.env.DEFAULT_EXPIRE,
|
|
10
|
+
group: 'storyblok',
|
|
11
|
+
name: 'links',
|
|
12
|
+
shouldInvalidateCache: (e) => {
|
|
13
|
+
const query = getQuery(e)
|
|
14
|
+
const bypass = query.sbToken != undefined
|
|
15
|
+
return bypass
|
|
16
|
+
},
|
|
17
|
+
})
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { request } from '../../utils/storyblok.js'
|
|
2
|
+
import { defineCachedEventHandler, getQuery, setHeader } from '#imports'
|
|
3
|
+
|
|
4
|
+
export default defineCachedEventHandler(async (event) => {
|
|
5
|
+
const query = getQuery(event)
|
|
6
|
+
setHeader(event, 'x-origin-url', event.node.req.url)
|
|
7
|
+
return await request(query)
|
|
8
|
+
}, {
|
|
9
|
+
maxAge: process.env.DEFAULT_EXPIRE,
|
|
10
|
+
group: 'storyblok',
|
|
11
|
+
shouldInvalidateCache: (e) => {
|
|
12
|
+
const query = getQuery(e)
|
|
13
|
+
const bypass = query.sbToken != undefined
|
|
14
|
+
return bypass
|
|
15
|
+
},
|
|
16
|
+
|
|
17
|
+
})
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { space } from '../../utils/storyblok.js'
|
|
2
|
+
import { defineCachedEventHandler, getQuery } from '#imports'
|
|
3
|
+
|
|
4
|
+
export default defineCachedEventHandler(async () => {
|
|
5
|
+
return await space()
|
|
6
|
+
}, {
|
|
7
|
+
maxAge: process.env.DEFAULT_EXPIRE,
|
|
8
|
+
group: 'storyblok',
|
|
9
|
+
shouldInvalidateCache: (e) => {
|
|
10
|
+
const query = getQuery(e)
|
|
11
|
+
const bypass = query.sbToken != undefined
|
|
12
|
+
return bypass
|
|
13
|
+
},
|
|
14
|
+
})
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { useRuntimeConfig, createError, useStorage } from '#imports'
|
|
2
|
+
|
|
3
|
+
const config = useRuntimeConfig()
|
|
4
|
+
const request = async (query) => {
|
|
5
|
+
try {
|
|
6
|
+
const defaultLanguage = config.defaultLanguage
|
|
7
|
+
const cv = Date.now()
|
|
8
|
+
const { find_by, returntotal, isEditor } = query
|
|
9
|
+
if (returntotal) delete query.returntotal
|
|
10
|
+
if (isEditor) delete query.isEditor
|
|
11
|
+
const params = {
|
|
12
|
+
cv,
|
|
13
|
+
version: config.gothamstoryblok.version,
|
|
14
|
+
token: config.gothamstoryblok.key,
|
|
15
|
+
find_by,
|
|
16
|
+
}
|
|
17
|
+
if (query.language && query.language != defaultLanguage) {
|
|
18
|
+
params.language = query.language
|
|
19
|
+
}
|
|
20
|
+
if (query.resolve_relations) {
|
|
21
|
+
params.resolve_relations = query.resolve_relations
|
|
22
|
+
}
|
|
23
|
+
if (query.fullSlug) {
|
|
24
|
+
await checkFullSlug(query.fullSlug)
|
|
25
|
+
|
|
26
|
+
const data = await $fetch(`https://api.storyblok.com/v2/cdn/stories/${query.fullSlug}`, { method: 'GET', query: params })
|
|
27
|
+
|
|
28
|
+
const { story, rels } = data
|
|
29
|
+
|
|
30
|
+
if (params.resolve_relations) return { story, rels }
|
|
31
|
+
return story
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
let { _data: data, headers } = await $fetch.raw('https://api.storyblok.com/v2/cdn/stories', {
|
|
35
|
+
query: {
|
|
36
|
+
cv,
|
|
37
|
+
version: config.gothamstoryblok.version,
|
|
38
|
+
token: config.gothamstoryblok.key,
|
|
39
|
+
...query,
|
|
40
|
+
},
|
|
41
|
+
})
|
|
42
|
+
const perPage = Number.parseInt(headers.get('per-page'))
|
|
43
|
+
const total = Number.parseInt(headers.get('total'))
|
|
44
|
+
let { stories, rels } = data
|
|
45
|
+
if (!isEditor || isEditor === 'false') stories = stories.filter(s => !s?.content?.metadata?.disbledforlanguage)
|
|
46
|
+
|
|
47
|
+
let res = stories
|
|
48
|
+
if (returntotal) res = { stories, perPage, total }
|
|
49
|
+
if (rels.length) {
|
|
50
|
+
if (returntotal) {
|
|
51
|
+
res.rels = rels
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
res = { stories, rels }
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return res
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
throw error
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const space = async () => {
|
|
66
|
+
const data = await $fetch(`https://api.storyblok.com/v2/cdn/spaces/me`, {
|
|
67
|
+
query: {
|
|
68
|
+
token: config.gothamstoryblok.key,
|
|
69
|
+
},
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
const { space } = data
|
|
73
|
+
const available_languages = [...space.language_codes, config.defaultLanguage]
|
|
74
|
+
space.available_languages = available_languages
|
|
75
|
+
space.default_language = config.defaultLanguage
|
|
76
|
+
delete space.language_codes
|
|
77
|
+
return space
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const getAll = async (params) => {
|
|
81
|
+
const requestParams = {
|
|
82
|
+
...params,
|
|
83
|
+
returntotal: true,
|
|
84
|
+
per_page: 100,
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const getStories = async (page = 1, allStories = []) => {
|
|
88
|
+
try {
|
|
89
|
+
const { stories, total } = await request(requestParams)
|
|
90
|
+
allStories.push(...stories)
|
|
91
|
+
console.log(allStories.length < total)
|
|
92
|
+
if (allStories.length === 100) {
|
|
93
|
+
return getStories(page + 1, allStories)
|
|
94
|
+
}
|
|
95
|
+
return allStories
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
return error
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
try {
|
|
103
|
+
return await getStories()
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
return error
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const links = async (query) => {
|
|
111
|
+
const cv = Date.now()
|
|
112
|
+
try {
|
|
113
|
+
const { links } = await $fetch('https://api.storyblok.com/v2/cdn/links', {
|
|
114
|
+
query: {
|
|
115
|
+
cv,
|
|
116
|
+
version: config.gothamstoryblok.version,
|
|
117
|
+
token: config.gothamstoryblok.key,
|
|
118
|
+
...query,
|
|
119
|
+
},
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
return links
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
throw error
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
let linksList = undefined
|
|
130
|
+
let linksListPromise = null
|
|
131
|
+
const loadLinksList = async () => {
|
|
132
|
+
if (linksList) return linksList
|
|
133
|
+
// Se un'altra richiesta la sta già caricando, aspetta quella
|
|
134
|
+
if (!linksListPromise) {
|
|
135
|
+
linksListPromise = (async () => {
|
|
136
|
+
const result = {
|
|
137
|
+
slug: {},
|
|
138
|
+
uuid: {},
|
|
139
|
+
id: {},
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const links = await $fetch('/api/storyblok/links', { query: { per_page: 1000 } })
|
|
143
|
+
|
|
144
|
+
for (const i in links) {
|
|
145
|
+
const link = links[i]
|
|
146
|
+
const slugParts = link.slug.split('/')
|
|
147
|
+
const slug = slugParts[slugParts.length - 1]
|
|
148
|
+
|
|
149
|
+
if (!result.slug[slug]) result.slug[slug] = link
|
|
150
|
+
if (!result.uuid[link.uuid]) result.uuid[link.uuid] = link
|
|
151
|
+
if (!result.id[link.id]) result.id[link.id] = link
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
linksList = result
|
|
155
|
+
linksListPromise = null // reset per richieste future
|
|
156
|
+
return result
|
|
157
|
+
})()
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return linksListPromise
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const checkFullSlug = async (fullSlug) => {
|
|
164
|
+
const cachedLinks = await loadLinksList()
|
|
165
|
+
|
|
166
|
+
const slugs = fullSlug.split('/')
|
|
167
|
+
const slug = slugs[slugs.length - 1]
|
|
168
|
+
|
|
169
|
+
if (!(cachedLinks.slug[slug] || cachedLinks.id[slug] || cachedLinks.uuid[slug])) {
|
|
170
|
+
throw createError({ statusCode: 404, message: 'Not found (fullSlug)' })
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const clearLinks = async () => {
|
|
175
|
+
linksList = undefined
|
|
176
|
+
linksListPromise = null
|
|
177
|
+
|
|
178
|
+
const cacheLinks = useStorage('cache:storyblok:links')
|
|
179
|
+
const cachedKeys = await cacheLinks.getKeys()
|
|
180
|
+
for (var i in cachedKeys) await cacheLinks.removeItem(cachedKeys[i])
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export { request, space, getAll, links, clearLinks }
|
package/dist/types.d.mts
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "gothamstoryblok",
|
|
3
|
+
"version": "1.0.15",
|
|
4
|
+
"description": "Gotham.Studio | Storyblok and utils module",
|
|
5
|
+
"repository": "Gothamsiti/gothamstoryblok",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/types.d.mts",
|
|
11
|
+
"import": "./dist/module.mjs"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"main": "./dist/module.mjs",
|
|
15
|
+
"typesVersions": {
|
|
16
|
+
"*": {
|
|
17
|
+
".": [
|
|
18
|
+
"./dist/types.d.mts"
|
|
19
|
+
]
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist"
|
|
24
|
+
],
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@nuxt/kit": "^4.2.2",
|
|
27
|
+
"@storyblok/js": "^4.4.3",
|
|
28
|
+
"@storyblok/vue": "^9.4.3",
|
|
29
|
+
"cloudflare": "^5.2.0"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@nuxt/devtools": "^3.1.1",
|
|
33
|
+
"@nuxt/eslint-config": "^1.12.1",
|
|
34
|
+
"@nuxt/module-builder": "^1.0.2",
|
|
35
|
+
"@nuxt/schema": "^4.2.2",
|
|
36
|
+
"@nuxt/test-utils": "^3.21.0",
|
|
37
|
+
"@types/node": "latest",
|
|
38
|
+
"changelogen": "^0.6.2",
|
|
39
|
+
"eslint": "^9.39.2",
|
|
40
|
+
"nuxt": "^4.2.2",
|
|
41
|
+
"typescript": "~5.9.3",
|
|
42
|
+
"vitest": "^4.0.16",
|
|
43
|
+
"vue-tsc": "^3.2.1"
|
|
44
|
+
},
|
|
45
|
+
"scripts": {
|
|
46
|
+
"dev": "npm run dev:prepare && nuxi dev playground",
|
|
47
|
+
"dev:build": "nuxi build playground",
|
|
48
|
+
"dev:prepare": "nuxt-module-build build --stub && nuxt-module-build prepare && nuxi prepare playground",
|
|
49
|
+
"release": "npm run lint && npm run test && npm run prepack && changelogen --release && npm publish && git push --follow-tags",
|
|
50
|
+
"lint": "eslint .",
|
|
51
|
+
"test": "vitest run",
|
|
52
|
+
"test:watch": "vitest watch",
|
|
53
|
+
"test:types": "vue-tsc --noEmit && cd playground && vue-tsc --noEmit"
|
|
54
|
+
}
|
|
55
|
+
}
|