refactor(docs): cleanup fumadocs PR — revert deepseek, add i18n fallback, restore LanguageSelector

- Revert unrelated deepseek-web.ts changes (should be separate PR)
- Add .source/ to .gitignore (Fumadocs generated files)
- Remove contributor IP from allowedDevOrigins
- Add i18n runtime fallback: reads NEXT_LOCALE cookie, loads translated
  .md from docs/i18n/<locale>/docs/ (preserves existing translation pipeline)
- Restore LanguageSelector in Fumadocs layout nav
- Restore SEO metadata (title template, description, robots)
This commit is contained in:
diegosouzapw
2026-05-23 03:36:02 -03:00
parent f49069ab01
commit c6655e45c4
9 changed files with 108 additions and 367 deletions

3
.gitignore vendored
View File

@@ -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/

View File

@@ -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;

View File

@@ -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"] } }
);

View File

@@ -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,
}
);

View File

@@ -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 };

View File

@@ -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,

View File

@@ -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
if (typeof frag.content === "string") parts.push(frag.content);
}
}
// APPEND to fragment content
if (
typeof data?.p === "string" &&
data.p.includes("/content") &&
data?.o === "APPEND" &&
typeof data?.v === "string"
) {
parts.push(data.v);
}
// Bare string tokens
if (typeof data?.v === "string" && !data?.p && !data?.o) {
parts.push(data.v);
}
} catch {
// skip
}
@@ -338,44 +295,6 @@ async function collectSSEContent(deepseekStream: ReadableStream): Promise<string
return parts.join("");
}
// ── Prompt builder (DeepSeek native format, matches Chat2API) ────────────
function messagesToPrompt(messages: Array<{ role: string; content: string }>): 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,

View File

@@ -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/<locale>/docs/<section>/<FILE>.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 (
<DocsPage toc={page.data.toc} full={page.data.full}>
<DocsBody>
<div className="prose-content" dangerouslySetInnerHTML={{ __html: i18nHtml }} />
</DocsBody>
</DocsPage>
);
}
// Default: English MDX rendered natively by Fumadocs
const MDX = page.data.body;
return (
<DocsPage toc={page.data.toc} full={page.data.full}>
<DocsBody>
@@ -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();
}

View File

@@ -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: (
<Suspense fallback={<div className="w-24 h-8" />}>
<LanguageSelector />
</Suspense>
),
},
links: [
{