docus 5.4.4 → 5.5.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.vue +16 -6
- package/app/components/app/AppHeader.vue +5 -0
- package/app/components/docs/DocsAsideRightBottom.vue +28 -1
- package/app/composables/useSeo.ts +207 -0
- package/app/pages/[[lang]]/[...slug].vue +17 -9
- package/app/plugins/i18n.ts +28 -11
- package/app/templates/landing.vue +4 -10
- package/app/types/index.d.ts +49 -0
- package/app/utils/navigation.ts +31 -0
- package/i18n/locales/en.json +27 -0
- package/i18n/locales/fr.json +28 -1
- package/modules/assistant/README.md +213 -0
- package/modules/assistant/index.ts +100 -0
- package/modules/assistant/runtime/components/AssistantChat.vue +21 -0
- package/modules/assistant/runtime/components/AssistantChatDisabled.vue +3 -0
- package/modules/assistant/runtime/components/AssistantFloatingInput.vue +110 -0
- package/modules/assistant/runtime/components/AssistantLoading.vue +164 -0
- package/modules/assistant/runtime/components/AssistantMatrix.vue +92 -0
- package/modules/assistant/runtime/components/AssistantPanel.vue +329 -0
- package/modules/assistant/runtime/components/AssistantPreStream.vue +46 -0
- package/modules/assistant/runtime/composables/useAssistant.ts +107 -0
- package/modules/assistant/runtime/composables/useHighlighter.ts +34 -0
- package/modules/assistant/runtime/server/api/search.ts +111 -0
- package/modules/assistant/runtime/types.ts +7 -0
- package/modules/config.ts +6 -4
- package/modules/css.ts +6 -2
- package/modules/markdown-rewrite.ts +130 -0
- package/nuxt.config.ts +22 -1
- package/nuxt.schema.ts +63 -0
- package/package.json +24 -15
- package/server/routes/sitemap.xml.ts +93 -0
- package/utils/meta.ts +9 -3
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { defineNuxtModule, logger } from '@nuxt/kit'
|
|
2
|
+
import { resolve } from 'node:path'
|
|
3
|
+
import { readFile, writeFile } from 'node:fs/promises'
|
|
4
|
+
|
|
5
|
+
const log = logger.withTag('Docus')
|
|
6
|
+
|
|
7
|
+
export default defineNuxtModule({
|
|
8
|
+
meta: {
|
|
9
|
+
name: 'markdown-rewrite',
|
|
10
|
+
},
|
|
11
|
+
setup(_options, nuxt) {
|
|
12
|
+
nuxt.hooks.hook('nitro:init', (nitro) => {
|
|
13
|
+
if (nitro.options.dev || !nitro.options.preset.includes('vercel')) {
|
|
14
|
+
return
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
nitro.hooks.hook('compiled', async () => {
|
|
18
|
+
const vcJSON = resolve(nitro.options.output.dir, 'config.json')
|
|
19
|
+
const vcConfig = JSON.parse(await readFile(vcJSON, 'utf8'))
|
|
20
|
+
|
|
21
|
+
// Check if llms.txt exists before setting up any routes
|
|
22
|
+
let llmsTxt
|
|
23
|
+
const llmsTxtPath = resolve(nitro.options.output.publicDir, 'llms.txt')
|
|
24
|
+
try {
|
|
25
|
+
llmsTxt = await readFile(llmsTxtPath, 'utf-8')
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
log.warn('llms.txt not found, skipping markdown redirect routes')
|
|
29
|
+
return
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Always redirect / to /llms.txt
|
|
33
|
+
const routes = [
|
|
34
|
+
{
|
|
35
|
+
src: '^/$',
|
|
36
|
+
dest: '/llms.txt',
|
|
37
|
+
has: [{ type: 'header', key: 'accept', value: '(.*)text/markdown(.*)' }],
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
src: '^/$',
|
|
41
|
+
dest: '/llms.txt',
|
|
42
|
+
has: [{ type: 'header', key: 'user-agent', value: 'curl/.*' }],
|
|
43
|
+
},
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
// Check if i18n is enabled
|
|
47
|
+
const isI18nEnabled = !!(nuxt.options.i18n && nuxt.options.i18n.locales)
|
|
48
|
+
let localeCodes: string[] = []
|
|
49
|
+
|
|
50
|
+
if (isI18nEnabled) {
|
|
51
|
+
// Get locale codes
|
|
52
|
+
const locales = nuxt.options.i18n.locales || []
|
|
53
|
+
localeCodes = locales.map((locale) => {
|
|
54
|
+
return typeof locale === 'string' ? locale : locale.code
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
// Create a regex pattern for all locales (e.g., "en|fr|es")
|
|
58
|
+
const localePattern = localeCodes.join('|')
|
|
59
|
+
|
|
60
|
+
// Add routes for each locale homepage: /{locale} → /llms.txt
|
|
61
|
+
routes.push(
|
|
62
|
+
{
|
|
63
|
+
src: `^/(${localePattern})$`,
|
|
64
|
+
dest: '/llms.txt',
|
|
65
|
+
has: [{ type: 'header', key: 'accept', value: '(.*)text/markdown(.*)' }],
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
src: `^/(${localePattern})$`,
|
|
69
|
+
dest: '/llms.txt',
|
|
70
|
+
has: [{ type: 'header', key: 'user-agent', value: 'curl/.*' }],
|
|
71
|
+
},
|
|
72
|
+
)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Parse llms.txt to get all documentation pages
|
|
76
|
+
const urlRegex = /\[([^\]]+)\]\((https?:\/\/[^)]+)\)/g
|
|
77
|
+
const matches = [...llmsTxt.matchAll(urlRegex)]
|
|
78
|
+
|
|
79
|
+
for (const match of matches) {
|
|
80
|
+
const url = match[2]
|
|
81
|
+
if (!url) continue
|
|
82
|
+
|
|
83
|
+
try {
|
|
84
|
+
// Extract path from URL
|
|
85
|
+
const urlObj = new URL(url)
|
|
86
|
+
const rawPath = urlObj.pathname
|
|
87
|
+
|
|
88
|
+
// Skip root path (already handled)
|
|
89
|
+
if (rawPath === '/') continue
|
|
90
|
+
|
|
91
|
+
// Only process raw markdown URLs from llms.txt
|
|
92
|
+
if (!rawPath.startsWith('/raw/')) continue
|
|
93
|
+
|
|
94
|
+
// Convert /raw/en/getting-started/installation.md to /en/getting-started/installation
|
|
95
|
+
const pagePath = rawPath.replace('/raw', '').replace(/\.md$/, '')
|
|
96
|
+
|
|
97
|
+
// Skip locale homepages (e.g., /en, /fr) - they already redirect to /llms.txt
|
|
98
|
+
if (isI18nEnabled) {
|
|
99
|
+
const isLocaleHomepage = localeCodes.some(code => pagePath === `/${code}`)
|
|
100
|
+
if (isLocaleHomepage) continue
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Add redirect routes: page URL → raw markdown URL
|
|
104
|
+
const docsRoutes = [
|
|
105
|
+
{
|
|
106
|
+
src: `^${pagePath}$`,
|
|
107
|
+
dest: rawPath,
|
|
108
|
+
has: [{ type: 'header', key: 'accept', value: '(.*)text/markdown(.*)' }],
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
src: `^${pagePath}$`,
|
|
112
|
+
dest: rawPath,
|
|
113
|
+
has: [{ type: 'header', key: 'user-agent', value: 'curl/.*' }],
|
|
114
|
+
},
|
|
115
|
+
]
|
|
116
|
+
routes.push(...docsRoutes)
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
// Skip invalid URLs
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
vcConfig.routes.unshift(...routes)
|
|
124
|
+
|
|
125
|
+
await writeFile(vcJSON, JSON.stringify(vcConfig, null, 2), 'utf8')
|
|
126
|
+
log.info(`Successfully wrote ${routes.length} routes to ${vcJSON} (serve markdown content to AI agents)`)
|
|
127
|
+
})
|
|
128
|
+
})
|
|
129
|
+
},
|
|
130
|
+
})
|
package/nuxt.config.ts
CHANGED
|
@@ -6,6 +6,7 @@ export default defineNuxtConfig({
|
|
|
6
6
|
modules: [
|
|
7
7
|
resolve('./modules/config'),
|
|
8
8
|
resolve('./modules/routing'),
|
|
9
|
+
resolve('./modules/markdown-rewrite'),
|
|
9
10
|
resolve('./modules/css'),
|
|
10
11
|
'@nuxt/ui',
|
|
11
12
|
'@nuxt/content',
|
|
@@ -19,9 +20,14 @@ export default defineNuxtConfig({
|
|
|
19
20
|
extendViteConfig((config) => {
|
|
20
21
|
config.optimizeDeps ||= {}
|
|
21
22
|
config.optimizeDeps.include ||= []
|
|
22
|
-
config.optimizeDeps.include.push(
|
|
23
|
+
config.optimizeDeps.include.push(
|
|
24
|
+
'@nuxt/content > slugify',
|
|
25
|
+
// Fix @vercel/oidc ESM export issue (transitive dep of @ai-sdk/gateway)
|
|
26
|
+
'@vercel/oidc',
|
|
27
|
+
)
|
|
23
28
|
config.optimizeDeps.include = config.optimizeDeps.include
|
|
24
29
|
.map(id => id.replace(/^@nuxt\/content > /, 'docus > @nuxt/content > '))
|
|
30
|
+
.map(id => id.replace(/^@vercel\/oidc$/, 'docus > @vercel/oidc'))
|
|
25
31
|
})
|
|
26
32
|
},
|
|
27
33
|
],
|
|
@@ -44,6 +50,11 @@ export default defineNuxtConfig({
|
|
|
44
50
|
},
|
|
45
51
|
},
|
|
46
52
|
},
|
|
53
|
+
mdc: {
|
|
54
|
+
highlight: {
|
|
55
|
+
shikiEngine: 'javascript',
|
|
56
|
+
},
|
|
57
|
+
},
|
|
47
58
|
experimental: {
|
|
48
59
|
asyncContext: true,
|
|
49
60
|
},
|
|
@@ -76,9 +87,19 @@ export default defineNuxtConfig({
|
|
|
76
87
|
nitroConfig.prerender = nitroConfig.prerender || {}
|
|
77
88
|
nitroConfig.prerender.routes = nitroConfig.prerender.routes || []
|
|
78
89
|
nitroConfig.prerender.routes.push(...(routes || []))
|
|
90
|
+
nitroConfig.prerender.routes.push('/sitemap.xml')
|
|
79
91
|
},
|
|
80
92
|
},
|
|
81
93
|
icon: {
|
|
82
94
|
provider: 'iconify',
|
|
83
95
|
},
|
|
96
|
+
robots: {
|
|
97
|
+
groups: [
|
|
98
|
+
{
|
|
99
|
+
userAgent: '*',
|
|
100
|
+
allow: '/',
|
|
101
|
+
},
|
|
102
|
+
],
|
|
103
|
+
sitemap: '/sitemap.xml',
|
|
104
|
+
},
|
|
84
105
|
})
|
package/nuxt.schema.ts
CHANGED
|
@@ -214,5 +214,68 @@ export default defineNuxtSchema({
|
|
|
214
214
|
}),
|
|
215
215
|
},
|
|
216
216
|
}),
|
|
217
|
+
assistant: group({
|
|
218
|
+
title: 'Assistant',
|
|
219
|
+
description: 'Assistant configuration.',
|
|
220
|
+
icon: 'i-lucide-sparkles',
|
|
221
|
+
fields: {
|
|
222
|
+
floatingInput: field({
|
|
223
|
+
type: 'boolean',
|
|
224
|
+
title: 'Floating Input',
|
|
225
|
+
description: 'Show the floating input at the bottom of documentation pages.',
|
|
226
|
+
icon: 'i-lucide-message-circle',
|
|
227
|
+
default: true,
|
|
228
|
+
}),
|
|
229
|
+
explainWithAi: field({
|
|
230
|
+
type: 'boolean',
|
|
231
|
+
title: 'Explain with AI',
|
|
232
|
+
description: 'Show the "Explain with AI" button in the documentation sidebar.',
|
|
233
|
+
icon: 'i-lucide-brain',
|
|
234
|
+
default: true,
|
|
235
|
+
}),
|
|
236
|
+
faqQuestions: field({
|
|
237
|
+
type: 'array',
|
|
238
|
+
title: 'FAQ Questions',
|
|
239
|
+
description: 'List of FAQ questions. Can be an array of strings or an array of categories with questions.',
|
|
240
|
+
icon: 'i-lucide-help-circle',
|
|
241
|
+
default: [],
|
|
242
|
+
}),
|
|
243
|
+
shortcuts: group({
|
|
244
|
+
title: 'Shortcuts',
|
|
245
|
+
description: 'Keyboard shortcuts configuration.',
|
|
246
|
+
icon: 'i-lucide-keyboard',
|
|
247
|
+
fields: {
|
|
248
|
+
focusInput: field({
|
|
249
|
+
type: 'string',
|
|
250
|
+
title: 'Focus Input',
|
|
251
|
+
description: 'Shortcut to focus the floating input (e.g., meta_i, ctrl_k).',
|
|
252
|
+
icon: 'i-lucide-keyboard',
|
|
253
|
+
default: 'meta_i',
|
|
254
|
+
}),
|
|
255
|
+
},
|
|
256
|
+
}),
|
|
257
|
+
icons: group({
|
|
258
|
+
title: 'Icons',
|
|
259
|
+
description: 'Icons configuration.',
|
|
260
|
+
icon: 'i-lucide-settings',
|
|
261
|
+
fields: {
|
|
262
|
+
trigger: field({
|
|
263
|
+
type: 'icon',
|
|
264
|
+
title: 'Trigger',
|
|
265
|
+
description: 'Icon for the AI chat trigger button and slideover header.',
|
|
266
|
+
icon: 'i-lucide-sparkles',
|
|
267
|
+
default: 'i-lucide-sparkles',
|
|
268
|
+
}),
|
|
269
|
+
explain: field({
|
|
270
|
+
type: 'icon',
|
|
271
|
+
title: 'Explain',
|
|
272
|
+
description: 'Icon for the "Explain with AI" button.',
|
|
273
|
+
icon: 'i-lucide-brain',
|
|
274
|
+
default: 'i-lucide-brain',
|
|
275
|
+
}),
|
|
276
|
+
},
|
|
277
|
+
}),
|
|
278
|
+
},
|
|
279
|
+
}),
|
|
217
280
|
},
|
|
218
281
|
})
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "docus",
|
|
3
3
|
"description": "Nuxt layer for Docus documentation theme",
|
|
4
|
-
"version": "5.
|
|
4
|
+
"version": "5.5.1",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./nuxt.config.ts",
|
|
7
7
|
"repository": {
|
|
@@ -22,30 +22,39 @@
|
|
|
22
22
|
"README.md"
|
|
23
23
|
],
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@
|
|
26
|
-
"@
|
|
27
|
-
"@
|
|
28
|
-
"@
|
|
25
|
+
"@ai-sdk/gateway": "^3.0.39",
|
|
26
|
+
"@ai-sdk/mcp": "^1.0.19",
|
|
27
|
+
"@ai-sdk/vue": "3.0.78",
|
|
28
|
+
"@iconify-json/lucide": "^1.2.90",
|
|
29
|
+
"@iconify-json/simple-icons": "^1.2.70",
|
|
30
|
+
"@iconify-json/vscode-icons": "^1.2.41",
|
|
31
|
+
"@nuxt/content": "^3.11.2",
|
|
29
32
|
"@nuxt/image": "^2.0.0",
|
|
30
|
-
"@nuxt/kit": "^4.
|
|
31
|
-
"@nuxt/ui": "^4.
|
|
32
|
-
"@nuxtjs/i18n": "^10.2.
|
|
33
|
-
"@nuxtjs/mcp-toolkit": "^0.6.
|
|
34
|
-
"@nuxtjs/mdc": "^0.20.
|
|
35
|
-
"@nuxtjs/robots": "^5.
|
|
36
|
-
"@vueuse/core": "^14.1
|
|
33
|
+
"@nuxt/kit": "^4.3.1",
|
|
34
|
+
"@nuxt/ui": "^4.4.0",
|
|
35
|
+
"@nuxtjs/i18n": "^10.2.3",
|
|
36
|
+
"@nuxtjs/mcp-toolkit": "^0.6.3",
|
|
37
|
+
"@nuxtjs/mdc": "^0.20.1",
|
|
38
|
+
"@nuxtjs/robots": "^5.7.0",
|
|
39
|
+
"@vueuse/core": "^14.2.1",
|
|
40
|
+
"ai": "6.0.78",
|
|
37
41
|
"defu": "^6.1.4",
|
|
38
42
|
"exsolve": "^1.0.8",
|
|
39
43
|
"git-url-parse": "^16.1.0",
|
|
40
|
-
"minimark": "^0.
|
|
41
|
-
"motion-v": "^1.
|
|
44
|
+
"minimark": "^1.0.0",
|
|
45
|
+
"motion-v": "^1.10.3",
|
|
42
46
|
"nuxt-llms": "^0.2.0",
|
|
43
47
|
"nuxt-og-image": "^5.1.13",
|
|
44
48
|
"pkg-types": "^2.3.0",
|
|
45
49
|
"scule": "^1.3.0",
|
|
50
|
+
"@shikijs/core": "^3.22.0",
|
|
51
|
+
"@shikijs/engine-javascript": "^3.22.0",
|
|
52
|
+
"@shikijs/langs": "^3.22.0",
|
|
53
|
+
"@shikijs/themes": "^3.22.0",
|
|
54
|
+
"shiki-stream": "^0.1.4",
|
|
46
55
|
"tailwindcss": "^4.1.18",
|
|
47
56
|
"ufo": "^1.6.3",
|
|
48
|
-
"zod": "^4.3.
|
|
57
|
+
"zod": "^4.3.6",
|
|
49
58
|
"zod-to-json-schema": "^3.25.1"
|
|
50
59
|
},
|
|
51
60
|
"peerDependencies": {
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { queryCollection } from '@nuxt/content/server'
|
|
2
|
+
import { getAvailableLocales, getCollectionsToQuery } from '../utils/content'
|
|
3
|
+
import { inferSiteURL } from '../../utils/meta'
|
|
4
|
+
|
|
5
|
+
interface SitemapUrl {
|
|
6
|
+
loc: string
|
|
7
|
+
lastmod?: string
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export default defineEventHandler(async (event) => {
|
|
11
|
+
const config = useRuntimeConfig(event)
|
|
12
|
+
const siteUrl = inferSiteURL() || ''
|
|
13
|
+
|
|
14
|
+
const availableLocales = getAvailableLocales(config.public as Record<string, unknown>)
|
|
15
|
+
const collections = getCollectionsToQuery(undefined, availableLocales)
|
|
16
|
+
|
|
17
|
+
if (availableLocales.length > 0) {
|
|
18
|
+
for (const locale of availableLocales) {
|
|
19
|
+
collections.push(`landing_${locale}`)
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
collections.push('landing')
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const urls: SitemapUrl[] = []
|
|
27
|
+
|
|
28
|
+
for (const collection of collections) {
|
|
29
|
+
try {
|
|
30
|
+
const pages = await queryCollection(event, collection as 'docs').all()
|
|
31
|
+
|
|
32
|
+
for (const page of pages) {
|
|
33
|
+
const meta = page as unknown as Record<string, unknown>
|
|
34
|
+
const pagePath = (page.path as string) || '/'
|
|
35
|
+
|
|
36
|
+
// Skip pages with sitemap: false in frontmatter
|
|
37
|
+
if (meta.sitemap === false) continue
|
|
38
|
+
|
|
39
|
+
// Skip .navigation files (used for navigation configuration)
|
|
40
|
+
if (pagePath.endsWith('.navigation') || pagePath.includes('/.navigation')) continue
|
|
41
|
+
|
|
42
|
+
const urlEntry: SitemapUrl = {
|
|
43
|
+
loc: pagePath,
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Add lastmod if available (modifiedAt from content)
|
|
47
|
+
if (meta.modifiedAt && typeof meta.modifiedAt === 'string') {
|
|
48
|
+
urlEntry.lastmod = meta.modifiedAt.split('T')[0] // Use date part only (YYYY-MM-DD)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
urls.push(urlEntry)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
// Collection might not exist, skip it
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const sitemap = generateSitemap(urls, siteUrl)
|
|
60
|
+
|
|
61
|
+
setResponseHeader(event, 'content-type', 'application/xml')
|
|
62
|
+
return sitemap
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
function generateSitemap(urls: SitemapUrl[], siteUrl: string): string {
|
|
66
|
+
const urlEntries = urls
|
|
67
|
+
.map((url) => {
|
|
68
|
+
const loc = siteUrl ? `${siteUrl}${url.loc}` : url.loc
|
|
69
|
+
let entry = ` <url>\n <loc>${escapeXml(loc)}</loc>`
|
|
70
|
+
|
|
71
|
+
if (url.lastmod) {
|
|
72
|
+
entry += `\n <lastmod>${escapeXml(url.lastmod)}</lastmod>`
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
entry += `\n </url>`
|
|
76
|
+
return entry
|
|
77
|
+
})
|
|
78
|
+
.join('\n')
|
|
79
|
+
|
|
80
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
81
|
+
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
|
82
|
+
${urlEntries}
|
|
83
|
+
</urlset>`
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function escapeXml(str: string): string {
|
|
87
|
+
return str
|
|
88
|
+
.replace(/&/g, '&')
|
|
89
|
+
.replace(/</g, '<')
|
|
90
|
+
.replace(/>/g, '>')
|
|
91
|
+
.replace(/"/g, '"')
|
|
92
|
+
.replace(/'/g, ''')
|
|
93
|
+
}
|
package/utils/meta.ts
CHANGED
|
@@ -1,15 +1,21 @@
|
|
|
1
1
|
import { readFile } from 'node:fs/promises'
|
|
2
2
|
import { resolve } from 'node:path'
|
|
3
|
+
import { withHttps } from 'ufo'
|
|
3
4
|
|
|
4
5
|
export function inferSiteURL() {
|
|
5
6
|
// https://github.com/unjs/std-env/issues/59
|
|
6
|
-
|
|
7
|
-
process.env.
|
|
8
|
-
||
|
|
7
|
+
const url = (
|
|
8
|
+
process.env.NUXT_PUBLIC_SITE_URL // Nuxt public runtime config
|
|
9
|
+
|| process.env.NUXT_SITE_URL // Nuxt site config
|
|
10
|
+
|| process.env.VERCEL_PROJECT_PRODUCTION_URL // Vercel production URL
|
|
11
|
+
|| process.env.VERCEL_BRANCH_URL // Vercel branch URL
|
|
12
|
+
|| process.env.VERCEL_URL // Vercel deployment URL
|
|
9
13
|
|| process.env.URL // Netlify
|
|
10
14
|
|| process.env.CI_PAGES_URL // Gitlab Pages
|
|
11
15
|
|| process.env.CF_PAGES_URL // Cloudflare Pages
|
|
12
16
|
)
|
|
17
|
+
|
|
18
|
+
return url ? withHttps(url) : undefined
|
|
13
19
|
}
|
|
14
20
|
|
|
15
21
|
export async function getPackageJsonMetadata(dir: string) {
|