docus 5.10.0 → 5.11.0
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 +1 -1
- package/app/components/docs/DocsPageHeaderLinks.vue +9 -4
- package/app/pages/[[lang]]/[...slug].vue +1 -0
- package/app/plugins/i18n.ts +1 -1
- package/modules/assistant/index.ts +4 -2
- package/modules/assistant/runtime/server/api/search.ts +41 -9
- package/modules/config.ts +13 -2
- package/modules/css.ts +27 -6
- package/modules/markdown-rewrite.ts +12 -2
- package/modules/skills/index.ts +4 -2
- package/package.json +19 -18
- package/server/mcp/tools/get-page.ts +7 -4
- package/server/mcp/tools/list-pages.ts +6 -3
package/app/app.config.ts
CHANGED
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { useClipboard } from '@vueuse/core'
|
|
3
|
+
import { joinURL, withTrailingSlash } from 'ufo'
|
|
3
4
|
import { useRuntimeConfig } from '#imports'
|
|
4
5
|
|
|
5
6
|
const route = useRoute()
|
|
6
7
|
const toast = useToast()
|
|
7
|
-
const
|
|
8
|
+
const runtimeConfig = useRuntimeConfig()
|
|
9
|
+
const appBaseURL = runtimeConfig.app?.baseURL || '/'
|
|
10
|
+
const mcpRoute = (runtimeConfig.public.mcp as { route?: string } | undefined)?.route || '/mcp'
|
|
8
11
|
|
|
9
12
|
const { copy, copied } = useClipboard()
|
|
10
13
|
const { t } = useDocusI18n()
|
|
11
14
|
|
|
12
|
-
const markdownLink = computed(() => `${window?.location?.origin}${appBaseURL}raw${route.path}.md`)
|
|
15
|
+
const markdownLink = computed(() => `${window?.location?.origin}${withTrailingSlash(appBaseURL)}raw${route.path}.md`)
|
|
16
|
+
const mcpServerUrl = computed(() => `${window?.location?.origin}${joinURL(appBaseURL, mcpRoute)}`)
|
|
17
|
+
const mcpDeeplink = joinURL(mcpRoute, 'deeplink')
|
|
13
18
|
const items = [
|
|
14
19
|
[{
|
|
15
20
|
label: t('docs.copy.link'),
|
|
@@ -41,7 +46,7 @@ const items = [
|
|
|
41
46
|
label: 'Copy MCP Server URL',
|
|
42
47
|
icon: 'i-lucide-link',
|
|
43
48
|
onSelect() {
|
|
44
|
-
copy(
|
|
49
|
+
copy(mcpServerUrl.value)
|
|
45
50
|
toast.add({
|
|
46
51
|
title: 'Copied to clipboard',
|
|
47
52
|
icon: 'i-lucide-check-circle',
|
|
@@ -52,7 +57,7 @@ const items = [
|
|
|
52
57
|
label: 'Add MCP Server',
|
|
53
58
|
icon: 'i-simple-icons:cursor',
|
|
54
59
|
target: '_blank',
|
|
55
|
-
to:
|
|
60
|
+
to: mcpDeeplink,
|
|
56
61
|
},
|
|
57
62
|
],
|
|
58
63
|
]
|
package/app/plugins/i18n.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { RouteLocationNormalized } from 'vue-router'
|
|
2
2
|
import { consola } from 'consola'
|
|
3
3
|
|
|
4
|
-
const log = consola.withTag('
|
|
4
|
+
const log = consola.withTag('docus')
|
|
5
5
|
|
|
6
6
|
// Lazy import functions for locale files (bundled but not eagerly loaded)
|
|
7
7
|
const localeFiles = import.meta.glob<{ default: Record<string, unknown> }>('../../i18n/locales/*.json')
|
|
@@ -21,7 +21,7 @@ export interface AssistantModuleOptions {
|
|
|
21
21
|
model?: string
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
const log = logger.withTag('
|
|
24
|
+
const log = logger.withTag('docus')
|
|
25
25
|
|
|
26
26
|
const defaults: Required<AssistantModuleOptions> = {
|
|
27
27
|
apiPath: '/__docus__/assistant',
|
|
@@ -77,7 +77,9 @@ export default defineNuxtModule<AssistantModuleOptions>({
|
|
|
77
77
|
)
|
|
78
78
|
|
|
79
79
|
if (!hasAiGatewayAuth) {
|
|
80
|
-
|
|
80
|
+
nuxt.hook('modules:done', () => {
|
|
81
|
+
log.warn('AI assistant disabled: neither `AI_GATEWAY_API_KEY` nor `VERCEL_OIDC_TOKEN` found')
|
|
82
|
+
})
|
|
81
83
|
return
|
|
82
84
|
}
|
|
83
85
|
|
|
@@ -1,9 +1,27 @@
|
|
|
1
1
|
import { streamText, convertToModelMessages, createUIMessageStream, createUIMessageStreamResponse } from 'ai'
|
|
2
2
|
import type { UIMessageStreamWriter, ToolCallPart, ToolSet } from 'ai'
|
|
3
3
|
import { createMCPClient } from '@ai-sdk/mcp'
|
|
4
|
+
import type { H3Event } from 'h3'
|
|
4
5
|
|
|
5
6
|
const MAX_STEPS = 10
|
|
6
7
|
|
|
8
|
+
function createLocalFetch(event: H3Event): typeof fetch {
|
|
9
|
+
const origin = getRequestURL(event).origin
|
|
10
|
+
|
|
11
|
+
return (input, init) => {
|
|
12
|
+
const requestUrl = input instanceof URL
|
|
13
|
+
? input
|
|
14
|
+
: typeof input === 'string'
|
|
15
|
+
? new URL(input, origin)
|
|
16
|
+
: new URL(input.url)
|
|
17
|
+
const localPath = requestUrl.origin === origin
|
|
18
|
+
? `${requestUrl.pathname}${requestUrl.search}`
|
|
19
|
+
: requestUrl.toString()
|
|
20
|
+
|
|
21
|
+
return event.fetch(localPath, init)
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
7
25
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
8
26
|
function stopWhenResponseComplete({ steps }: { steps: any[] }): boolean {
|
|
9
27
|
const lastStep = steps.at(-1)
|
|
@@ -66,15 +84,29 @@ export default defineEventHandler(async (event) => {
|
|
|
66
84
|
const mcpServer = config.assistant.mcpServer
|
|
67
85
|
const isExternalUrl = mcpServer.startsWith('http://') || mcpServer.startsWith('https://')
|
|
68
86
|
const baseURL = config.app?.baseURL?.replace(/\/$/, '') || ''
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
:
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
87
|
+
|
|
88
|
+
let transport: Parameters<typeof createMCPClient>[0]['transport']
|
|
89
|
+
if (isExternalUrl) {
|
|
90
|
+
transport = {
|
|
91
|
+
type: 'http',
|
|
92
|
+
url: mcpServer,
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
else if (import.meta.dev) {
|
|
96
|
+
transport = {
|
|
97
|
+
type: 'http',
|
|
98
|
+
url: `http://localhost:3000${baseURL}${mcpServer}`,
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
transport = {
|
|
103
|
+
type: 'http',
|
|
104
|
+
url: `${getRequestURL(event).origin}${baseURL}${mcpServer}`,
|
|
105
|
+
fetch: createLocalFetch(event),
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const httpClient = await createMCPClient({ transport })
|
|
78
110
|
const mcpTools = await httpClient.tools()
|
|
79
111
|
|
|
80
112
|
const stream = createUIMessageStream({
|
package/modules/config.ts
CHANGED
|
@@ -5,10 +5,11 @@ import { join } from 'node:path'
|
|
|
5
5
|
import { inferSiteURL, getPackageJsonMetadata } from '../utils/meta'
|
|
6
6
|
import { getGitBranch, getGitEnv, getLocalGitInfo } from '../utils/git'
|
|
7
7
|
|
|
8
|
-
const log = logger.withTag('
|
|
8
|
+
const log = logger.withTag('docus')
|
|
9
9
|
|
|
10
10
|
type I18nLocale = string | { code: string, name?: string }
|
|
11
11
|
type DocusI18nOptions = { locales?: I18nLocale[], strategy?: string }
|
|
12
|
+
type DocusMcpOptions = { route?: string, enabled?: boolean }
|
|
12
13
|
type RegisterModuleOptions = {
|
|
13
14
|
langDir: string
|
|
14
15
|
locales: Array<{ code: string, name: string, file: string }>
|
|
@@ -39,7 +40,7 @@ export default defineNuxtModule({
|
|
|
39
40
|
url,
|
|
40
41
|
name: siteName,
|
|
41
42
|
debug: false,
|
|
42
|
-
})
|
|
43
|
+
}) as typeof nuxt.options.site
|
|
43
44
|
|
|
44
45
|
nuxt.options.appConfig.header = defu(nuxt.options.appConfig.header, {
|
|
45
46
|
title: siteName,
|
|
@@ -58,6 +59,16 @@ export default defineNuxtModule({
|
|
|
58
59
|
branch: getGitBranch(),
|
|
59
60
|
})
|
|
60
61
|
|
|
62
|
+
/*
|
|
63
|
+
** MCP route (expose to client so the page header dropdown stays in sync
|
|
64
|
+
** with the user-configured `mcp.route` from @nuxtjs/mcp-toolkit)
|
|
65
|
+
*/
|
|
66
|
+
const mcpOptions = (nuxt.options as typeof nuxt.options & { mcp?: DocusMcpOptions }).mcp
|
|
67
|
+
nuxt.options.runtimeConfig.public.mcp = defu(
|
|
68
|
+
nuxt.options.runtimeConfig.public.mcp as DocusMcpOptions | undefined,
|
|
69
|
+
{ route: mcpOptions?.route || '/mcp' },
|
|
70
|
+
)
|
|
71
|
+
|
|
61
72
|
const forcedColorMode = (nuxt.options.appConfig.docus as Record<string, unknown>)?.colorMode as string | undefined
|
|
62
73
|
if (forcedColorMode === 'light' || forcedColorMode === 'dark') {
|
|
63
74
|
nuxt.options.colorMode = defu({ preference: forcedColorMode, fallback: forcedColorMode }, nuxt.options.colorMode || {}) as typeof nuxt.options.colorMode
|
package/modules/css.ts
CHANGED
|
@@ -1,21 +1,37 @@
|
|
|
1
|
-
import { defineNuxtModule, addTemplate, createResolver } from '@nuxt/kit'
|
|
2
|
-
import {
|
|
1
|
+
import { defineNuxtModule, addTemplate, createResolver, logger } from '@nuxt/kit'
|
|
2
|
+
import { existsSync } from 'node:fs'
|
|
3
|
+
import { readFile } from 'node:fs/promises'
|
|
4
|
+
import { resolve } from 'pathe'
|
|
3
5
|
import { resolveModulePath } from 'exsolve'
|
|
4
6
|
|
|
7
|
+
const log = logger.withTag('docus')
|
|
8
|
+
|
|
5
9
|
export default defineNuxtModule({
|
|
6
10
|
meta: {
|
|
7
|
-
name: 'css',
|
|
11
|
+
name: 'docus-css',
|
|
8
12
|
},
|
|
9
13
|
async setup(_options, nuxt) {
|
|
10
|
-
const dir = nuxt.options.rootDir
|
|
11
14
|
const resolver = createResolver(import.meta.url)
|
|
12
15
|
|
|
13
|
-
const contentDir =
|
|
16
|
+
const contentDir = resolve(nuxt.options.rootDir, 'content')
|
|
14
17
|
const uiPath = resolveModulePath('@nuxt/ui', { from: import.meta.url, conditions: ['style'] })
|
|
15
18
|
const tailwindPath = resolveModulePath('tailwindcss', { from: import.meta.url, conditions: ['style'] })
|
|
16
19
|
const layerDir = resolver.resolve('../app')
|
|
17
20
|
const assistantDir = resolver.resolve('../modules/assistant')
|
|
18
21
|
|
|
22
|
+
let userDocusPath: string | null = resolve(nuxt.options.srcDir, 'app.css')
|
|
23
|
+
if (existsSync(userDocusPath)) {
|
|
24
|
+
const userDocusCss = await readFile(userDocusPath, 'utf-8')
|
|
25
|
+
if (userDocusCss.includes('@import "tailwindcss"')) {
|
|
26
|
+
nuxt.hook('modules:done', () => {
|
|
27
|
+
log.warn('`app.css` contains `@import "tailwindcss";` consider removing it to avoid duplicate css.')
|
|
28
|
+
})
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
userDocusPath = null
|
|
33
|
+
}
|
|
34
|
+
|
|
19
35
|
const cssTemplate = addTemplate({
|
|
20
36
|
filename: 'docus.css',
|
|
21
37
|
getContents: () => {
|
|
@@ -25,7 +41,12 @@ export default defineNuxtModule({
|
|
|
25
41
|
@source "${contentDir.replace(/\\/g, '/')}/**/*";
|
|
26
42
|
@source "${layerDir.replace(/\\/g, '/')}/**/*";
|
|
27
43
|
@source "../../app.config.ts";
|
|
28
|
-
@source "${assistantDir.replace(/\\/g, '/')}/**/*"
|
|
44
|
+
@source "${assistantDir.replace(/\\/g, '/')}/**/*";
|
|
45
|
+
|
|
46
|
+
:root {
|
|
47
|
+
--ui-container: 90rem;
|
|
48
|
+
}
|
|
49
|
+
` + (userDocusPath ? `\n@import ${JSON.stringify(userDocusPath)};` : '')
|
|
29
50
|
},
|
|
30
51
|
})
|
|
31
52
|
|
|
@@ -2,7 +2,7 @@ import { defineNuxtModule, logger } from '@nuxt/kit'
|
|
|
2
2
|
import { resolve } from 'node:path'
|
|
3
3
|
import { readFile, writeFile } from 'node:fs/promises'
|
|
4
4
|
|
|
5
|
-
const log = logger.withTag('
|
|
5
|
+
const log = logger.withTag('docus')
|
|
6
6
|
|
|
7
7
|
type I18nLocale = string | { code: string }
|
|
8
8
|
type DocusI18nOptions = { locales?: I18nLocale[] }
|
|
@@ -32,16 +32,22 @@ export default defineNuxtModule({
|
|
|
32
32
|
return
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
// Always redirect / to /llms.txt
|
|
35
|
+
// Always redirect / to /llms.txt and ensure plain text content type
|
|
36
|
+
const markdownHeaders = {
|
|
37
|
+
'content-type': 'text/markdown; charset=utf-8',
|
|
38
|
+
}
|
|
39
|
+
|
|
36
40
|
const routes = [
|
|
37
41
|
{
|
|
38
42
|
src: '^/$',
|
|
39
43
|
dest: '/llms.txt',
|
|
44
|
+
headers: markdownHeaders,
|
|
40
45
|
has: [{ type: 'header', key: 'accept', value: '(.*)text/markdown(.*)' }],
|
|
41
46
|
},
|
|
42
47
|
{
|
|
43
48
|
src: '^/$',
|
|
44
49
|
dest: '/llms.txt',
|
|
50
|
+
headers: markdownHeaders,
|
|
45
51
|
has: [{ type: 'header', key: 'user-agent', value: 'curl/.*' }],
|
|
46
52
|
},
|
|
47
53
|
]
|
|
@@ -66,11 +72,13 @@ export default defineNuxtModule({
|
|
|
66
72
|
{
|
|
67
73
|
src: `^/(${localePattern})$`,
|
|
68
74
|
dest: '/llms.txt',
|
|
75
|
+
headers: markdownHeaders,
|
|
69
76
|
has: [{ type: 'header', key: 'accept', value: '(.*)text/markdown(.*)' }],
|
|
70
77
|
},
|
|
71
78
|
{
|
|
72
79
|
src: `^/(${localePattern})$`,
|
|
73
80
|
dest: '/llms.txt',
|
|
81
|
+
headers: markdownHeaders,
|
|
74
82
|
has: [{ type: 'header', key: 'user-agent', value: 'curl/.*' }],
|
|
75
83
|
},
|
|
76
84
|
)
|
|
@@ -109,11 +117,13 @@ export default defineNuxtModule({
|
|
|
109
117
|
{
|
|
110
118
|
src: `^${pagePath}$`,
|
|
111
119
|
dest: rawPath,
|
|
120
|
+
headers: markdownHeaders,
|
|
112
121
|
has: [{ type: 'header', key: 'accept', value: '(.*)text/markdown(.*)' }],
|
|
113
122
|
},
|
|
114
123
|
{
|
|
115
124
|
src: `^${pagePath}$`,
|
|
116
125
|
dest: rawPath,
|
|
126
|
+
headers: markdownHeaders,
|
|
117
127
|
has: [{ type: 'header', key: 'user-agent', value: 'curl/.*' }],
|
|
118
128
|
},
|
|
119
129
|
]
|
package/modules/skills/index.ts
CHANGED
|
@@ -19,7 +19,7 @@ export interface SkillsModuleOptions {
|
|
|
19
19
|
const SKILL_NAME_REGEX = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/
|
|
20
20
|
const MAX_NAME_LENGTH = 64
|
|
21
21
|
|
|
22
|
-
const log = logger.withTag('
|
|
22
|
+
const log = logger.withTag('docus')
|
|
23
23
|
|
|
24
24
|
const defaults: Required<SkillsModuleOptions> = {
|
|
25
25
|
dir: 'skills',
|
|
@@ -38,7 +38,9 @@ export default defineNuxtModule<SkillsModuleOptions>({
|
|
|
38
38
|
const catalog = await scanSkills(skillsDir)
|
|
39
39
|
if (!catalog.length) return
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
nuxt.hook('modules:done', () => {
|
|
42
|
+
log.info(`Found ${catalog.length} agent skill${catalog.length > 1 ? 's' : ''}: ${catalog.map(s => s.name).join(', ')}`)
|
|
43
|
+
})
|
|
42
44
|
|
|
43
45
|
nuxt.options.runtimeConfig.skills = { catalog }
|
|
44
46
|
|
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.11.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./nuxt.config.ts",
|
|
7
7
|
"repository": {
|
|
@@ -23,39 +23,40 @@
|
|
|
23
23
|
"README.md"
|
|
24
24
|
],
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@ai-sdk/gateway": "^3.0.
|
|
27
|
-
"@ai-sdk/mcp": "^1.0.
|
|
28
|
-
"@ai-sdk/vue": "3.0.
|
|
29
|
-
"@iconify-json/lucide": "^1.2.
|
|
30
|
-
"@iconify-json/simple-icons": "^1.2.
|
|
26
|
+
"@ai-sdk/gateway": "^3.0.104",
|
|
27
|
+
"@ai-sdk/mcp": "^1.0.36",
|
|
28
|
+
"@ai-sdk/vue": "3.0.168",
|
|
29
|
+
"@iconify-json/lucide": "^1.2.102",
|
|
30
|
+
"@iconify-json/simple-icons": "^1.2.79",
|
|
31
31
|
"@iconify-json/vscode-icons": "^1.2.45",
|
|
32
|
-
"@nuxt/content": "^3.
|
|
32
|
+
"@nuxt/content": "^3.13.0",
|
|
33
33
|
"@nuxt/image": "^2.0.0",
|
|
34
34
|
"@nuxt/kit": "^4.4.2",
|
|
35
|
-
"@nuxt/ui": "^4.
|
|
35
|
+
"@nuxt/ui": "^4.7.1",
|
|
36
36
|
"@nuxtjs/i18n": "^10.2.4",
|
|
37
|
-
"@nuxtjs/mcp-toolkit": "^0.13.
|
|
38
|
-
"@nuxtjs/mdc": "^0.21.
|
|
39
|
-
"@nuxtjs/robots": "^6.0.
|
|
37
|
+
"@nuxtjs/mcp-toolkit": "^0.13.4",
|
|
38
|
+
"@nuxtjs/mdc": "^0.21.1",
|
|
39
|
+
"@nuxtjs/robots": "^6.0.7",
|
|
40
40
|
"@shikijs/core": "^4.0.2",
|
|
41
41
|
"@shikijs/engine-javascript": "^4.0.2",
|
|
42
42
|
"@shikijs/langs": "^4.0.2",
|
|
43
43
|
"@shikijs/themes": "^4.0.2",
|
|
44
|
-
"@takumi-rs/core": "^0.
|
|
44
|
+
"@takumi-rs/core": "^1.0.15",
|
|
45
45
|
"@vueuse/core": "^14.2.1",
|
|
46
|
-
"ai": "6.0.
|
|
47
|
-
"defu": "^6.1.
|
|
46
|
+
"ai": "6.0.168",
|
|
47
|
+
"defu": "^6.1.7",
|
|
48
48
|
"exsolve": "^1.0.8",
|
|
49
49
|
"git-url-parse": "^16.1.0",
|
|
50
|
-
"motion-v": "^2.2.
|
|
50
|
+
"motion-v": "^2.2.1",
|
|
51
51
|
"nuxt-llms": "^0.2.0",
|
|
52
|
-
"nuxt-og-image": "^6.
|
|
52
|
+
"nuxt-og-image": "^6.4.5",
|
|
53
|
+
"pathe": "^2.0.3",
|
|
53
54
|
"pkg-types": "^2.3.0",
|
|
54
55
|
"scule": "^1.3.0",
|
|
55
56
|
"shiki-stream": "^0.1.4",
|
|
56
|
-
"tailwindcss": "^4.2.
|
|
57
|
+
"tailwindcss": "^4.2.3",
|
|
57
58
|
"ufo": "^1.6.3",
|
|
58
|
-
"yaml": "^2.
|
|
59
|
+
"yaml": "^2.8.3",
|
|
59
60
|
"zod": "^4.3.6",
|
|
60
61
|
"zod-to-json-schema": "^3.25.2"
|
|
61
62
|
},
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod'
|
|
2
|
+
import { joinURL } from 'ufo'
|
|
2
3
|
import { queryCollection } from '@nuxt/content/server'
|
|
3
4
|
import type { Collections } from '@nuxt/content'
|
|
4
5
|
import { getAvailableLocales, getCollectionFromPath } from '../../utils/content'
|
|
@@ -33,11 +34,13 @@ WORKFLOW: This tool returns the complete page content including title, descripti
|
|
|
33
34
|
cache: '1h',
|
|
34
35
|
handler: async ({ path }) => {
|
|
35
36
|
const event = useEvent()
|
|
36
|
-
const config = useRuntimeConfig(event)
|
|
37
|
+
const config = useRuntimeConfig(event)
|
|
38
|
+
const publicConfig = config.public
|
|
37
39
|
const siteUrl = getRequestURL(event).origin || inferSiteURL()
|
|
40
|
+
const baseURL = config.app?.baseURL || '/'
|
|
38
41
|
|
|
39
|
-
const availableLocales = getAvailableLocales(
|
|
40
|
-
const collectionName =
|
|
42
|
+
const availableLocales = getAvailableLocales(publicConfig)
|
|
43
|
+
const collectionName = publicConfig.i18n?.locales
|
|
41
44
|
? getCollectionFromPath(path, availableLocales)
|
|
42
45
|
: 'docs'
|
|
43
46
|
|
|
@@ -58,7 +61,7 @@ WORKFLOW: This tool returns the complete page content including title, descripti
|
|
|
58
61
|
path: page.path,
|
|
59
62
|
description: page.description,
|
|
60
63
|
content,
|
|
61
|
-
url:
|
|
64
|
+
url: siteUrl ? joinURL(siteUrl, baseURL, page.path) : joinURL(baseURL, page.path),
|
|
62
65
|
}
|
|
63
66
|
}
|
|
64
67
|
catch (error) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod'
|
|
2
|
+
import { joinURL } from 'ufo'
|
|
2
3
|
import { queryCollection } from '@nuxt/content/server'
|
|
3
4
|
import type { Collections } from '@nuxt/content'
|
|
4
5
|
import { getCollectionsToQuery, getAvailableLocales } from '../../utils/content'
|
|
@@ -39,10 +40,12 @@ OUTPUT: Returns a structured list with:
|
|
|
39
40
|
cache: '1h',
|
|
40
41
|
handler: async ({ locale }) => {
|
|
41
42
|
const event = useEvent()
|
|
42
|
-
const config = useRuntimeConfig(event)
|
|
43
|
+
const config = useRuntimeConfig(event)
|
|
44
|
+
const publicConfig = config.public
|
|
43
45
|
|
|
44
46
|
const siteUrl = getRequestURL(event).origin || inferSiteURL()
|
|
45
|
-
const
|
|
47
|
+
const baseURL = config.app?.baseURL || '/'
|
|
48
|
+
const availableLocales = getAvailableLocales(publicConfig)
|
|
46
49
|
const collections = getCollectionsToQuery(locale, availableLocales)
|
|
47
50
|
|
|
48
51
|
try {
|
|
@@ -57,7 +60,7 @@ OUTPUT: Returns a structured list with:
|
|
|
57
60
|
path: page.path,
|
|
58
61
|
description: page.description,
|
|
59
62
|
locale: collectionName.replace('docs_', ''),
|
|
60
|
-
url:
|
|
63
|
+
url: siteUrl ? joinURL(siteUrl, baseURL, page.path) : joinURL(baseURL, page.path),
|
|
61
64
|
}))
|
|
62
65
|
}),
|
|
63
66
|
)
|