diff --git a/.gitignore b/.gitignore index 4dde1baa34..c693eb8c16 100644 --- a/.gitignore +++ b/.gitignore @@ -177,3 +177,6 @@ scripts/i18n/_pending-keys.json .claude/commands/port-upstream-features-cc.md .claude/commands/port-upstream-issues-cc.md .claude/worktrees/ + +# Fumadocs generated source +.source/ diff --git a/.source/browser.ts b/.source/browser.ts deleted file mode 100644 index 3f8dda9608..0000000000 --- a/.source/browser.ts +++ /dev/null @@ -1,90 +0,0 @@ -// @ts-nocheck -import { browser } from "fumadocs-mdx/runtime/browser"; -import type * as Config from "../source.config"; - -const create = browser< - typeof Config, - import("fumadocs-mdx/runtime/types").InternalTypeConfig & { - DocData: {}; - } ->(); -const browserCollections = { - docs: create.doc("docs", { - "architecture/ARCHITECTURE.md": () => - import("../docs/architecture/ARCHITECTURE.md?collection=docs"), - "architecture/AUTHZ_GUIDE.md": () => - import("../docs/architecture/AUTHZ_GUIDE.md?collection=docs"), - "architecture/CODEBASE_DOCUMENTATION.md": () => - import("../docs/architecture/CODEBASE_DOCUMENTATION.md?collection=docs"), - "architecture/REPOSITORY_MAP.md": () => - import("../docs/architecture/REPOSITORY_MAP.md?collection=docs"), - "architecture/RESILIENCE_GUIDE.md": () => - import("../docs/architecture/RESILIENCE_GUIDE.md?collection=docs"), - "compression/COMPRESSION_ENGINES.md": () => - import("../docs/compression/COMPRESSION_ENGINES.md?collection=docs"), - "compression/COMPRESSION_GUIDE.md": () => - import("../docs/compression/COMPRESSION_GUIDE.md?collection=docs"), - "compression/COMPRESSION_LANGUAGE_PACKS.md": () => - import("../docs/compression/COMPRESSION_LANGUAGE_PACKS.md?collection=docs"), - "compression/COMPRESSION_RULES_FORMAT.md": () => - import("../docs/compression/COMPRESSION_RULES_FORMAT.md?collection=docs"), - "compression/RTK_COMPRESSION.md": () => - import("../docs/compression/RTK_COMPRESSION.md?collection=docs"), - "frameworks/A2A-SERVER.md": () => import("../docs/frameworks/A2A-SERVER.md?collection=docs"), - "frameworks/AGENT_PROTOCOLS_GUIDE.md": () => - import("../docs/frameworks/AGENT_PROTOCOLS_GUIDE.md?collection=docs"), - "frameworks/CLOUD_AGENT.md": () => import("../docs/frameworks/CLOUD_AGENT.md?collection=docs"), - "frameworks/EVALS.md": () => import("../docs/frameworks/EVALS.md?collection=docs"), - "frameworks/GAMIFICATION.md": () => - import("../docs/frameworks/GAMIFICATION.md?collection=docs"), - "frameworks/MCP-SERVER.md": () => import("../docs/frameworks/MCP-SERVER.md?collection=docs"), - "frameworks/MEMORY.md": () => import("../docs/frameworks/MEMORY.md?collection=docs"), - "frameworks/OPENCODE.md": () => import("../docs/frameworks/OPENCODE.md?collection=docs"), - "frameworks/SKILLS.md": () => import("../docs/frameworks/SKILLS.md?collection=docs"), - "frameworks/WEBHOOKS.md": () => import("../docs/frameworks/WEBHOOKS.md?collection=docs"), - "guides/DOCKER_GUIDE.md": () => import("../docs/guides/DOCKER_GUIDE.md?collection=docs"), - "guides/ELECTRON_GUIDE.md": () => import("../docs/guides/ELECTRON_GUIDE.md?collection=docs"), - "guides/FEATURES.md": () => import("../docs/guides/FEATURES.md?collection=docs"), - "guides/I18N.md": () => import("../docs/guides/I18N.md?collection=docs"), - "guides/KIRO_SETUP.md": () => import("../docs/guides/KIRO_SETUP.md?collection=docs"), - "guides/PWA_GUIDE.md": () => import("../docs/guides/PWA_GUIDE.md?collection=docs"), - "guides/SETUP_GUIDE.md": () => import("../docs/guides/SETUP_GUIDE.md?collection=docs"), - "guides/TERMUX_GUIDE.md": () => import("../docs/guides/TERMUX_GUIDE.md?collection=docs"), - "guides/TROUBLESHOOTING.md": () => import("../docs/guides/TROUBLESHOOTING.md?collection=docs"), - "guides/UNINSTALL.md": () => import("../docs/guides/UNINSTALL.md?collection=docs"), - "guides/USER_GUIDE.md": () => import("../docs/guides/USER_GUIDE.md?collection=docs"), - "ops/COVERAGE_PLAN.md": () => import("../docs/ops/COVERAGE_PLAN.md?collection=docs"), - "ops/E2E_DASHBOARD_SHAKEDOWN_v3.8.0.md": () => - import("../docs/ops/E2E_DASHBOARD_SHAKEDOWN_v3.8.0.md?collection=docs"), - "ops/FLY_IO_DEPLOYMENT_GUIDE.md": () => - import("../docs/ops/FLY_IO_DEPLOYMENT_GUIDE.md?collection=docs"), - "ops/PROXY_GUIDE.md": () => import("../docs/ops/PROXY_GUIDE.md?collection=docs"), - "ops/RELEASE_CHECKLIST.md": () => import("../docs/ops/RELEASE_CHECKLIST.md?collection=docs"), - "ops/SQLITE_RUNTIME.md": () => import("../docs/ops/SQLITE_RUNTIME.md?collection=docs"), - "ops/TUNNELS_GUIDE.md": () => import("../docs/ops/TUNNELS_GUIDE.md?collection=docs"), - "ops/VM_DEPLOYMENT_GUIDE.md": () => - import("../docs/ops/VM_DEPLOYMENT_GUIDE.md?collection=docs"), - "routing/AUTO-COMBO.md": () => import("../docs/routing/AUTO-COMBO.md?collection=docs"), - "routing/REASONING_REPLAY.md": () => - import("../docs/routing/REASONING_REPLAY.md?collection=docs"), - "security/CLI_TOKEN.md": () => import("../docs/security/CLI_TOKEN.md?collection=docs"), - "security/CLI_TOKEN_AUTH.md": () => - import("../docs/security/CLI_TOKEN_AUTH.md?collection=docs"), - "security/COMPLIANCE.md": () => import("../docs/security/COMPLIANCE.md?collection=docs"), - "security/ERROR_SANITIZATION.md": () => - import("../docs/security/ERROR_SANITIZATION.md?collection=docs"), - "security/GUARDRAILS.md": () => import("../docs/security/GUARDRAILS.md?collection=docs"), - "security/PUBLIC_CREDS.md": () => import("../docs/security/PUBLIC_CREDS.md?collection=docs"), - "security/ROUTE_GUARD_TIERS.md": () => - import("../docs/security/ROUTE_GUARD_TIERS.md?collection=docs"), - "security/STEALTH_GUIDE.md": () => import("../docs/security/STEALTH_GUIDE.md?collection=docs"), - "reference/API_REFERENCE.md": () => - import("../docs/reference/API_REFERENCE.md?collection=docs"), - "reference/CLI-TOOLS.md": () => import("../docs/reference/CLI-TOOLS.md?collection=docs"), - "reference/ENVIRONMENT.md": () => import("../docs/reference/ENVIRONMENT.md?collection=docs"), - "reference/FREE_TIERS.md": () => import("../docs/reference/FREE_TIERS.md?collection=docs"), - "reference/PROVIDER_REFERENCE.md": () => - import("../docs/reference/PROVIDER_REFERENCE.md?collection=docs"), - }), -}; -export default browserCollections; diff --git a/.source/dynamic.ts b/.source/dynamic.ts deleted file mode 100644 index 4b5ce7ff35..0000000000 --- a/.source/dynamic.ts +++ /dev/null @@ -1,14 +0,0 @@ -// @ts-nocheck -import { dynamic } from "fumadocs-mdx/runtime/dynamic"; -import * as Config from "../source.config"; - -const create = await dynamic< - typeof Config, - import("fumadocs-mdx/runtime/types").InternalTypeConfig & { - DocData: {}; - } ->( - Config, - { configPath: "source.config.ts", environment: "next", outDir: ".source" }, - { doc: { passthroughs: ["extractedReferences"] } } -); diff --git a/.source/server.ts b/.source/server.ts deleted file mode 100644 index a5585282c7..0000000000 --- a/.source/server.ts +++ /dev/null @@ -1,147 +0,0 @@ -// @ts-nocheck -import { default as __fd_glob_63 } from "../docs/security/meta.json?collection=docs"; -import { default as __fd_glob_62 } from "../docs/reference/openapi.yaml?collection=docs"; -import { default as __fd_glob_61 } from "../docs/reference/meta.json?collection=docs"; -import { default as __fd_glob_60 } from "../docs/routing/meta.json?collection=docs"; -import { default as __fd_glob_59 } from "../docs/ops/meta.json?collection=docs"; -import { default as __fd_glob_58 } from "../docs/guides/meta.json?collection=docs"; -import { default as __fd_glob_57 } from "../docs/frameworks/meta.json?collection=docs"; -import { default as __fd_glob_56 } from "../docs/compression/meta.json?collection=docs"; -import { default as __fd_glob_55 } from "../docs/architecture/meta.json?collection=docs"; -import { default as __fd_glob_54 } from "../docs/meta.json?collection=docs"; -import * as __fd_glob_53 from "../docs/reference/PROVIDER_REFERENCE.md?collection=docs"; -import * as __fd_glob_52 from "../docs/reference/FREE_TIERS.md?collection=docs"; -import * as __fd_glob_51 from "../docs/reference/ENVIRONMENT.md?collection=docs"; -import * as __fd_glob_50 from "../docs/reference/CLI-TOOLS.md?collection=docs"; -import * as __fd_glob_49 from "../docs/reference/API_REFERENCE.md?collection=docs"; -import * as __fd_glob_48 from "../docs/security/STEALTH_GUIDE.md?collection=docs"; -import * as __fd_glob_47 from "../docs/security/ROUTE_GUARD_TIERS.md?collection=docs"; -import * as __fd_glob_46 from "../docs/security/PUBLIC_CREDS.md?collection=docs"; -import * as __fd_glob_45 from "../docs/security/GUARDRAILS.md?collection=docs"; -import * as __fd_glob_44 from "../docs/security/ERROR_SANITIZATION.md?collection=docs"; -import * as __fd_glob_43 from "../docs/security/COMPLIANCE.md?collection=docs"; -import * as __fd_glob_42 from "../docs/security/CLI_TOKEN_AUTH.md?collection=docs"; -import * as __fd_glob_41 from "../docs/security/CLI_TOKEN.md?collection=docs"; -import * as __fd_glob_40 from "../docs/routing/REASONING_REPLAY.md?collection=docs"; -import * as __fd_glob_39 from "../docs/routing/AUTO-COMBO.md?collection=docs"; -import * as __fd_glob_38 from "../docs/ops/VM_DEPLOYMENT_GUIDE.md?collection=docs"; -import * as __fd_glob_37 from "../docs/ops/TUNNELS_GUIDE.md?collection=docs"; -import * as __fd_glob_36 from "../docs/ops/SQLITE_RUNTIME.md?collection=docs"; -import * as __fd_glob_35 from "../docs/ops/RELEASE_CHECKLIST.md?collection=docs"; -import * as __fd_glob_34 from "../docs/ops/PROXY_GUIDE.md?collection=docs"; -import * as __fd_glob_33 from "../docs/ops/FLY_IO_DEPLOYMENT_GUIDE.md?collection=docs"; -import * as __fd_glob_32 from "../docs/ops/E2E_DASHBOARD_SHAKEDOWN_v3.8.0.md?collection=docs"; -import * as __fd_glob_31 from "../docs/ops/COVERAGE_PLAN.md?collection=docs"; -import * as __fd_glob_30 from "../docs/guides/USER_GUIDE.md?collection=docs"; -import * as __fd_glob_29 from "../docs/guides/UNINSTALL.md?collection=docs"; -import * as __fd_glob_28 from "../docs/guides/TROUBLESHOOTING.md?collection=docs"; -import * as __fd_glob_27 from "../docs/guides/TERMUX_GUIDE.md?collection=docs"; -import * as __fd_glob_26 from "../docs/guides/SETUP_GUIDE.md?collection=docs"; -import * as __fd_glob_25 from "../docs/guides/PWA_GUIDE.md?collection=docs"; -import * as __fd_glob_24 from "../docs/guides/KIRO_SETUP.md?collection=docs"; -import * as __fd_glob_23 from "../docs/guides/I18N.md?collection=docs"; -import * as __fd_glob_22 from "../docs/guides/FEATURES.md?collection=docs"; -import * as __fd_glob_21 from "../docs/guides/ELECTRON_GUIDE.md?collection=docs"; -import * as __fd_glob_20 from "../docs/guides/DOCKER_GUIDE.md?collection=docs"; -import * as __fd_glob_19 from "../docs/frameworks/WEBHOOKS.md?collection=docs"; -import * as __fd_glob_18 from "../docs/frameworks/SKILLS.md?collection=docs"; -import * as __fd_glob_17 from "../docs/frameworks/OPENCODE.md?collection=docs"; -import * as __fd_glob_16 from "../docs/frameworks/MEMORY.md?collection=docs"; -import * as __fd_glob_15 from "../docs/frameworks/MCP-SERVER.md?collection=docs"; -import * as __fd_glob_14 from "../docs/frameworks/GAMIFICATION.md?collection=docs"; -import * as __fd_glob_13 from "../docs/frameworks/EVALS.md?collection=docs"; -import * as __fd_glob_12 from "../docs/frameworks/CLOUD_AGENT.md?collection=docs"; -import * as __fd_glob_11 from "../docs/frameworks/AGENT_PROTOCOLS_GUIDE.md?collection=docs"; -import * as __fd_glob_10 from "../docs/frameworks/A2A-SERVER.md?collection=docs"; -import * as __fd_glob_9 from "../docs/compression/RTK_COMPRESSION.md?collection=docs"; -import * as __fd_glob_8 from "../docs/compression/COMPRESSION_RULES_FORMAT.md?collection=docs"; -import * as __fd_glob_7 from "../docs/compression/COMPRESSION_LANGUAGE_PACKS.md?collection=docs"; -import * as __fd_glob_6 from "../docs/compression/COMPRESSION_GUIDE.md?collection=docs"; -import * as __fd_glob_5 from "../docs/compression/COMPRESSION_ENGINES.md?collection=docs"; -import * as __fd_glob_4 from "../docs/architecture/RESILIENCE_GUIDE.md?collection=docs"; -import * as __fd_glob_3 from "../docs/architecture/REPOSITORY_MAP.md?collection=docs"; -import * as __fd_glob_2 from "../docs/architecture/CODEBASE_DOCUMENTATION.md?collection=docs"; -import * as __fd_glob_1 from "../docs/architecture/AUTHZ_GUIDE.md?collection=docs"; -import * as __fd_glob_0 from "../docs/architecture/ARCHITECTURE.md?collection=docs"; -import { server } from "fumadocs-mdx/runtime/server"; -import type * as Config from "../source.config"; - -const create = server< - typeof Config, - import("fumadocs-mdx/runtime/types").InternalTypeConfig & { - DocData: {}; - } ->({ doc: { passthroughs: ["extractedReferences"] } }); - -export const docs = await create.docs( - "docs", - "docs", - { - "meta.json": __fd_glob_54, - "architecture/meta.json": __fd_glob_55, - "compression/meta.json": __fd_glob_56, - "frameworks/meta.json": __fd_glob_57, - "guides/meta.json": __fd_glob_58, - "ops/meta.json": __fd_glob_59, - "routing/meta.json": __fd_glob_60, - "reference/meta.json": __fd_glob_61, - "reference/openapi.yaml": __fd_glob_62, - "security/meta.json": __fd_glob_63, - }, - { - "architecture/ARCHITECTURE.md": __fd_glob_0, - "architecture/AUTHZ_GUIDE.md": __fd_glob_1, - "architecture/CODEBASE_DOCUMENTATION.md": __fd_glob_2, - "architecture/REPOSITORY_MAP.md": __fd_glob_3, - "architecture/RESILIENCE_GUIDE.md": __fd_glob_4, - "compression/COMPRESSION_ENGINES.md": __fd_glob_5, - "compression/COMPRESSION_GUIDE.md": __fd_glob_6, - "compression/COMPRESSION_LANGUAGE_PACKS.md": __fd_glob_7, - "compression/COMPRESSION_RULES_FORMAT.md": __fd_glob_8, - "compression/RTK_COMPRESSION.md": __fd_glob_9, - "frameworks/A2A-SERVER.md": __fd_glob_10, - "frameworks/AGENT_PROTOCOLS_GUIDE.md": __fd_glob_11, - "frameworks/CLOUD_AGENT.md": __fd_glob_12, - "frameworks/EVALS.md": __fd_glob_13, - "frameworks/GAMIFICATION.md": __fd_glob_14, - "frameworks/MCP-SERVER.md": __fd_glob_15, - "frameworks/MEMORY.md": __fd_glob_16, - "frameworks/OPENCODE.md": __fd_glob_17, - "frameworks/SKILLS.md": __fd_glob_18, - "frameworks/WEBHOOKS.md": __fd_glob_19, - "guides/DOCKER_GUIDE.md": __fd_glob_20, - "guides/ELECTRON_GUIDE.md": __fd_glob_21, - "guides/FEATURES.md": __fd_glob_22, - "guides/I18N.md": __fd_glob_23, - "guides/KIRO_SETUP.md": __fd_glob_24, - "guides/PWA_GUIDE.md": __fd_glob_25, - "guides/SETUP_GUIDE.md": __fd_glob_26, - "guides/TERMUX_GUIDE.md": __fd_glob_27, - "guides/TROUBLESHOOTING.md": __fd_glob_28, - "guides/UNINSTALL.md": __fd_glob_29, - "guides/USER_GUIDE.md": __fd_glob_30, - "ops/COVERAGE_PLAN.md": __fd_glob_31, - "ops/E2E_DASHBOARD_SHAKEDOWN_v3.8.0.md": __fd_glob_32, - "ops/FLY_IO_DEPLOYMENT_GUIDE.md": __fd_glob_33, - "ops/PROXY_GUIDE.md": __fd_glob_34, - "ops/RELEASE_CHECKLIST.md": __fd_glob_35, - "ops/SQLITE_RUNTIME.md": __fd_glob_36, - "ops/TUNNELS_GUIDE.md": __fd_glob_37, - "ops/VM_DEPLOYMENT_GUIDE.md": __fd_glob_38, - "routing/AUTO-COMBO.md": __fd_glob_39, - "routing/REASONING_REPLAY.md": __fd_glob_40, - "security/CLI_TOKEN.md": __fd_glob_41, - "security/CLI_TOKEN_AUTH.md": __fd_glob_42, - "security/COMPLIANCE.md": __fd_glob_43, - "security/ERROR_SANITIZATION.md": __fd_glob_44, - "security/GUARDRAILS.md": __fd_glob_45, - "security/PUBLIC_CREDS.md": __fd_glob_46, - "security/ROUTE_GUARD_TIERS.md": __fd_glob_47, - "security/STEALTH_GUIDE.md": __fd_glob_48, - "reference/API_REFERENCE.md": __fd_glob_49, - "reference/CLI-TOOLS.md": __fd_glob_50, - "reference/ENVIRONMENT.md": __fd_glob_51, - "reference/FREE_TIERS.md": __fd_glob_52, - "reference/PROVIDER_REFERENCE.md": __fd_glob_53, - } -); diff --git a/.source/source.config.mjs b/.source/source.config.mjs deleted file mode 100644 index 215b34afa0..0000000000 --- a/.source/source.config.mjs +++ /dev/null @@ -1,19 +0,0 @@ -// source.config.ts -import { defineDocs, defineConfig } from "fumadocs-mdx/config"; -var docs = defineDocs({ - dir: "docs", - docs: { - files: [ - "./architecture/**/*.md", - "./guides/**/*.md", - "./reference/**/*.md", - "./frameworks/**/*.md", - "./routing/**/*.md", - "./security/**/*.md", - "./compression/**/*.md", - "./ops/**/*.md", - ], - }, -}); -var source_config_default = defineConfig(); -export { source_config_default as default, docs }; diff --git a/next.config.mjs b/next.config.mjs index 6a2a81fdcc..2c5dc8a7c8 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -148,7 +148,7 @@ const nextConfig = { "process", ], transpilePackages: ["@omniroute/open-sse", "@lobehub/icons", "fumadocs-ui", "fumadocs-core"], - allowedDevOrigins: ["localhost", "127.0.0.1", "192.168.0.250", "192.168.0.111"], + allowedDevOrigins: ["localhost", "127.0.0.1", "192.168.0.250"], typescript: { // TODO: Re-enable after fixing all sub-component useTranslations scope issues ignoreBuildErrors: true, diff --git a/open-sse/executors/deepseek-web.ts b/open-sse/executors/deepseek-web.ts index a4d1389884..6b88576709 100644 --- a/open-sse/executors/deepseek-web.ts +++ b/open-sse/executors/deepseek-web.ts @@ -212,7 +212,7 @@ function transformSSE(deepseekStream: ReadableStream, model: string): ReadableSt } } - // response/fragments path (array of fragments) + // response/fragments path (incremental updates) if ((data as any)?.p === "response/fragments" && Array.isArray((data as any)?.v)) { if (!emittedRole) { emittedRole = true; @@ -229,36 +229,6 @@ function transformSSE(deepseekStream: ReadableStream, model: string): ReadableSt } } - // Incremental APPEND to fragment content (expert/pro mode) - const p = (data as any)?.p; - const o = (data as any)?.o; - if ( - typeof p === "string" && - p.includes("/content") && - o === "APPEND" && - typeof (data as any)?.v === "string" - ) { - if (!emittedRole) { - emittedRole = true; - chunk({ role: "assistant", content: "" }); - } - const isThink = p.includes("thinking") || p.includes("think"); - if (isThink) { - chunk({ reasoning_content: (data as any).v }); - } else { - chunk({ content: (data as any).v }); - } - } - - // Bare string tokens: {"v": "word"} with no "p" field - if (typeof (data as any)?.v === "string" && !p && !o) { - if (!emittedRole) { - emittedRole = true; - chunk({ role: "assistant", content: "" }); - } - chunk({ content: (data as any).v }); - } - if ((data as any)?.p === "response/status" && (data as any)?.v === "FINISHED") { if (!emittedRole) { emittedRole = true; @@ -316,19 +286,6 @@ async function collectSSEContent(deepseekStream: ReadableStream): Promise): string { - const extractText = (content: unknown): string => { - if (Array.isArray(content)) { - return (content as any[]) - .filter((item: any) => item.type === "text") - .map((item: any) => item.text) - .join("\n"); - } - return String(content || ""); - }; - - if (messages.length === 0) return ""; - - // Collect system prompt(s) and find the last user message - const systemParts: string[] = []; - let lastUserContent = ""; - for (const m of messages) { - if (m.role === "system") { - const text = extractText(m.content).trim(); - if (text) systemParts.push(text); - } else if (m.role === "user") { - lastUserContent = extractText(m.content).trim(); - } - } - - const parts: string[] = []; - if (systemParts.length > 0) { - parts.push(systemParts.join("\n\n")); - } - if (lastUserContent) { - parts.push(lastUserContent); - } - - return parts.join("\n\n").replace(/!\[.+\]\(.+\)/g, ""); -} - // ── DeepSeek API calls (Bearer token auth, like Chat2API) ─────────────── async function acquireAccessToken( @@ -405,11 +324,6 @@ async function acquireAccessToken( } const json = await resp.json(); - if (json?.code && json.code !== 0) { - const errMsg = json.msg || json?.data?.biz_msg || `error code ${json.code}`; - tokenCache.delete(userToken); - throw new Error(`DeepSeek rejected token: ${errMsg}`); - } const bizData = json?.data?.biz_data || json?.biz_data; if (!bizData?.token) { const errMsg = json?.msg || json?.data?.biz_msg || "Unknown error"; @@ -548,8 +462,14 @@ export class DeepSeekWebExecutor extends BaseExecutor { const powAnswer = await solvePow(powChallenge); log?.info?.("DEEPSEEK-WEB", `PoW solved in ${Date.now() - t0}ms`); - // 5. Build prompt from messages (DeepSeek native chat markers, matching Chat2API) - const prompt = messagesToPrompt(messages); + // 5. Build prompt from messages + const prompt = messages + .map((m) => { + if (m.role === "system") return `[System]: ${m.content}`; + if (m.role === "assistant") return `[Assistant]: ${m.content}`; + return m.content; + }) + .join("\n"); // 6. Resolve model type, thinking, and search from model name + body flags const { modelType, thinkingEnabled, searchEnabled } = resolveModelOptions( @@ -602,7 +522,6 @@ export class DeepSeekWebExecutor extends BaseExecutor { let errMsg = `DeepSeek API error (${status})`; if (status === 401 || status === 403) { tokenCache.delete(userToken); - sessionCache.delete((rawCreds.connectionId as string) || ""); errMsg = "DeepSeek token expired — get a fresh userToken from localStorage."; } else if (status === 429) { errMsg = "DeepSeek rate limited. Wait and retry."; @@ -635,10 +554,7 @@ export class DeepSeekWebExecutor extends BaseExecutor { const errMsg = `DeepSeek error ${json.code}: ${json.msg}`; log?.warn?.("DEEPSEEK-WEB", errMsg); const status = json.code === 40003 ? 401 : json.code === 40002 ? 429 : 502; - if (json.code === 40003) { - tokenCache.delete(userToken); - sessionCache.delete((rawCreds.connectionId as string) || ""); - } + if (json.code === 40003) tokenCache.delete(userToken); return { response: errorResponse(status, errMsg, json.code), url: COMPLETION_URL, diff --git a/src/app/docs/[...slug]/page.tsx b/src/app/docs/[...slug]/page.tsx index 885036f4e3..de27cd6e5e 100644 --- a/src/app/docs/[...slug]/page.tsx +++ b/src/app/docs/[...slug]/page.tsx @@ -3,14 +3,84 @@ import { DocsPage, DocsBody } from "fumadocs-ui/layouts/docs/page"; import { notFound } from "next/navigation"; import defaultMdxComponents from "fumadocs-ui/mdx"; import type { Metadata } from "next"; +import { cookies } from "next/headers"; +import { DEFAULT_LOCALE, LOCALE_COOKIE } from "@/i18n/config"; +import fs from "node:fs"; +import path from "node:path"; +import { marked } from "marked"; + +// ── Locale detection ──────────────────────────────────────────────────────── + +function getDocsLocale(): string { + try { + const cookieStore = cookies(); + return (cookieStore as any).get(LOCALE_COOKIE)?.value || DEFAULT_LOCALE; + } catch { + return DEFAULT_LOCALE; + } +} + +// ── i18n fallback ─────────────────────────────────────────────────────────── +// When locale ≠ "en", try to load the translated .md from +// `docs/i18n//docs/
/.md` — the exact path layout that +// `scripts/i18n/run-translation.mjs` produces. Returns rendered HTML or null. + +function tryI18nFallback(slug: string[], locale: string): string | null { + if (!locale || locale === "en") return null; + + const docsRoot = path.resolve(process.cwd(), "docs"); + const sectionDir = path.join(docsRoot, "i18n", locale, "docs", ...slug.slice(0, -1)); + if (!fs.existsSync(sectionDir)) return null; + + // Fumadocs lowercases slugs — match case-insensitively against i18n dir + const target = slug[slug.length - 1]; + let files: string[]; + try { + files = fs.readdirSync(sectionDir); + } catch { + return null; + } + + const match = files.find((f) => f.toLowerCase().replace(/\.md$/, "") === target.toLowerCase()); + if (!match) return null; + + const filePath = path.join(sectionDir, match); + const raw = fs.readFileSync(filePath, "utf8"); + + // Strip the i18n header (heading + language bar + ---) before rendering. + // Translated files have: # Title (Native)\n\n🌐 Languages: ...\n\n---\n\nbody + const bodyMatch = raw.match(/^---\s*$/m); + const body = + bodyMatch && bodyMatch.index != null + ? raw.slice(bodyMatch.index + bodyMatch[0].length).trim() + : raw; + + return marked.parse(body) as string; +} + +// ── Page component ────────────────────────────────────────────────────────── export default async function Page(props: { params: Promise<{ slug: string[] }> }) { const params = await props.params; const page = source.getPage(params.slug); if (!page) notFound(); - const MDX = page.data.body; + const locale = getDocsLocale(); + const i18nHtml = tryI18nFallback(params.slug, locale); + if (i18nHtml) { + // Render translated markdown (non-English locale with available translation) + return ( + + +
+ + + ); + } + + // Default: English MDX rendered natively by Fumadocs + const MDX = page.data.body; return ( @@ -20,7 +90,9 @@ export default async function Page(props: { params: Promise<{ slug: string[] }> ); } -export async function generateStaticParams() { +// ── Static params & metadata ──────────────────────────────────────────────── + +export function generateStaticParams() { return source.generateParams(); } diff --git a/src/app/docs/layout.tsx b/src/app/docs/layout.tsx index cf8961e03a..f4df0fc6e4 100644 --- a/src/app/docs/layout.tsx +++ b/src/app/docs/layout.tsx @@ -3,11 +3,31 @@ import { DocsLayout } from "fumadocs-ui/layouts/docs"; import { source } from "@/lib/source"; import type { ReactNode } from "react"; import type { BaseLayoutProps } from "fumadocs-ui/layouts/shared"; +import { Suspense } from "react"; +import LanguageSelector from "@/shared/components/LanguageSelector"; + +export const metadata = { + title: { + template: "%s — OmniRoute Docs", + default: "OmniRoute Documentation", + }, + description: + "Comprehensive documentation for OmniRoute AI gateway — setup, API, compression, deployment, and more.", + robots: { + index: true, + follow: true, + }, +}; const docsLayoutOptions: BaseLayoutProps = { nav: { title: "OmniRoute Docs", url: "/docs", + children: ( + }> + + + ), }, links: [ {