@farming-labs/docs 0.2.60 → 0.2.62

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.
Files changed (51) hide show
  1. package/README.md +1 -1
  2. package/package.json +11 -1
  3. package/dist/agent-BFqyqEnC.mjs +0 -4547
  4. package/dist/agent-DlxriaTs.mjs +0 -624
  5. package/dist/agent-evals-kJs2Y9xR.mjs +0 -2144
  6. package/dist/agent-export-BgUaiW8f.mjs +0 -869
  7. package/dist/agent-scope-CCaIY1aK.mjs +0 -283
  8. package/dist/agents-Djh-HXih.mjs +0 -219
  9. package/dist/analytics-Bx44lg6d.mjs +0 -177
  10. package/dist/cli/index.d.mts +0 -15
  11. package/dist/cli/index.mjs +0 -452
  12. package/dist/client/react.d.mts +0 -45
  13. package/dist/client/react.mjs +0 -223
  14. package/dist/cloud-BH_sHX64.mjs +0 -1615
  15. package/dist/cloud-analytics-CSyFE6SS.mjs +0 -132
  16. package/dist/cloud-ask-ai-B2WnG4fF.d.mts +0 -23
  17. package/dist/cloud-ask-ai-hnJfj8-X.mjs +0 -382
  18. package/dist/code-blocks-qe0T8-xe.mjs +0 -871
  19. package/dist/codeblocks-Bq67u32v.mjs +0 -250
  20. package/dist/config-DASewQ0x.mjs +0 -363
  21. package/dist/dev-DgY5xGl9.mjs +0 -1333
  22. package/dist/docs-cloud-server.d.mts +0 -70
  23. package/dist/docs-cloud-server.mjs +0 -310
  24. package/dist/doctor-CO1VMcF_.mjs +0 -1906
  25. package/dist/downgrade-BZs86NVr.mjs +0 -184
  26. package/dist/errors-CVqZ3kOO.mjs +0 -20
  27. package/dist/golden-evaluations-BN9u2wxw.mjs +0 -1483
  28. package/dist/i18n-CAlj1ADU.mjs +0 -40
  29. package/dist/index.d.mts +0 -1099
  30. package/dist/index.mjs +0 -9
  31. package/dist/init-Bd_k06bR.mjs +0 -1233
  32. package/dist/mcp-B_yXL5G5.mjs +0 -137
  33. package/dist/mcp.d.mts +0 -287
  34. package/dist/mcp.mjs +0 -4135
  35. package/dist/metadata-BDuewuzq.mjs +0 -237
  36. package/dist/package-version-qik_4J6C.mjs +0 -128
  37. package/dist/reading-time-BkEft6SD.mjs +0 -741
  38. package/dist/review-NC-sOdXn.mjs +0 -665
  39. package/dist/robots-DskPvGPw.mjs +0 -178
  40. package/dist/robots-ltltiLJF.mjs +0 -197
  41. package/dist/search-C1JitPwi.d.mts +0 -397
  42. package/dist/search-D57JXQLj.mjs +0 -1758
  43. package/dist/search-o4Ud6OXv.mjs +0 -102
  44. package/dist/server.d.mts +0 -341
  45. package/dist/server.mjs +0 -11
  46. package/dist/sitemap-Cq-Yj_iA.mjs +0 -247
  47. package/dist/sitemap-server-C1ibVKOy.mjs +0 -1137
  48. package/dist/templates-DNw15P-x.mjs +0 -2373
  49. package/dist/types-XHABMh_f.d.mts +0 -3248
  50. package/dist/upgrade-BCJTCW3O.mjs +0 -56
  51. package/dist/utils-6UCLxv4B.mjs +0 -225
@@ -1,132 +0,0 @@
1
- //#region src/cloud-analytics.ts
2
- const DEFAULT_DOCS_CLOUD_ANALYTICS_ENDPOINT = "https://api.farming-labs.dev/v1/analytics/events";
3
- function normalizeRuntimeEnvValue(value) {
4
- const normalized = value?.trim();
5
- return normalized ? normalized : void 0;
6
- }
7
- function readRuntimeEnv(name) {
8
- if (typeof process === "undefined" || !process.env) return;
9
- switch (name) {
10
- case "PUBLIC_DOCS_CLOUD_PROJECT_ID": return normalizeRuntimeEnvValue(process.env.PUBLIC_DOCS_CLOUD_PROJECT_ID);
11
- case "NEXT_PUBLIC_DOCS_CLOUD_PROJECT_ID": return normalizeRuntimeEnvValue(process.env.NEXT_PUBLIC_DOCS_CLOUD_PROJECT_ID);
12
- case "DOCS_CLOUD_PROJECT_ID": return normalizeRuntimeEnvValue(process.env.DOCS_CLOUD_PROJECT_ID);
13
- case "PUBLIC_DOCS_CLOUD_ANALYTICS_KEY": return normalizeRuntimeEnvValue(process.env.PUBLIC_DOCS_CLOUD_ANALYTICS_KEY);
14
- case "NEXT_PUBLIC_DOCS_CLOUD_ANALYTICS_KEY": return normalizeRuntimeEnvValue(process.env.NEXT_PUBLIC_DOCS_CLOUD_ANALYTICS_KEY);
15
- case "DOCS_CLOUD_ANALYTICS_KEY": return normalizeRuntimeEnvValue(process.env.DOCS_CLOUD_ANALYTICS_KEY);
16
- case "PUBLIC_DOCS_CLOUD_ANALYTICS_ENABLED": return normalizeRuntimeEnvValue(process.env.PUBLIC_DOCS_CLOUD_ANALYTICS_ENABLED);
17
- case "NEXT_PUBLIC_DOCS_CLOUD_ANALYTICS_ENABLED": return normalizeRuntimeEnvValue(process.env.NEXT_PUBLIC_DOCS_CLOUD_ANALYTICS_ENABLED);
18
- case "DOCS_CLOUD_ANALYTICS_ENABLED": return normalizeRuntimeEnvValue(process.env.DOCS_CLOUD_ANALYTICS_ENABLED);
19
- case "PUBLIC_DOCS_CLOUD_ANALYTICS_ENDPOINT": return normalizeRuntimeEnvValue(process.env.PUBLIC_DOCS_CLOUD_ANALYTICS_ENDPOINT);
20
- case "NEXT_PUBLIC_DOCS_CLOUD_ANALYTICS_ENDPOINT": return normalizeRuntimeEnvValue(process.env.NEXT_PUBLIC_DOCS_CLOUD_ANALYTICS_ENDPOINT);
21
- case "DOCS_CLOUD_ANALYTICS_ENDPOINT": return normalizeRuntimeEnvValue(process.env.DOCS_CLOUD_ANALYTICS_ENDPOINT);
22
- default: return;
23
- }
24
- }
25
- function isFalsyEnv(value) {
26
- if (!value) return false;
27
- return /^(0|false|no|off)$/i.test(value);
28
- }
29
- function resolveDocsCloudAnalyticsOptions(analytics) {
30
- if (analytics === false || analytics && typeof analytics === "object" && (analytics.enabled === false || analytics.cloud === false)) return null;
31
- const projectId = readRuntimeEnv("PUBLIC_DOCS_CLOUD_PROJECT_ID") ?? readRuntimeEnv("NEXT_PUBLIC_DOCS_CLOUD_PROJECT_ID") ?? readRuntimeEnv("DOCS_CLOUD_PROJECT_ID");
32
- const apiKey = readRuntimeEnv("PUBLIC_DOCS_CLOUD_ANALYTICS_KEY") ?? readRuntimeEnv("NEXT_PUBLIC_DOCS_CLOUD_ANALYTICS_KEY") ?? readRuntimeEnv("DOCS_CLOUD_ANALYTICS_KEY");
33
- const enabled = readRuntimeEnv("PUBLIC_DOCS_CLOUD_ANALYTICS_ENABLED") ?? readRuntimeEnv("NEXT_PUBLIC_DOCS_CLOUD_ANALYTICS_ENABLED") ?? readRuntimeEnv("DOCS_CLOUD_ANALYTICS_ENABLED");
34
- const endpoint = readRuntimeEnv("PUBLIC_DOCS_CLOUD_ANALYTICS_ENDPOINT") ?? readRuntimeEnv("NEXT_PUBLIC_DOCS_CLOUD_ANALYTICS_ENDPOINT") ?? readRuntimeEnv("DOCS_CLOUD_ANALYTICS_ENDPOINT") ?? DEFAULT_DOCS_CLOUD_ANALYTICS_ENDPOINT;
35
- if (isFalsyEnv(enabled)) return null;
36
- if (!projectId) return null;
37
- return {
38
- endpoint,
39
- projectId,
40
- apiKey
41
- };
42
- }
43
- function asRecord(value) {
44
- return value && typeof value === "object" && !Array.isArray(value) ? value : {};
45
- }
46
- function asString(value) {
47
- return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
48
- }
49
- function normalizeAnalyticsLabel(value) {
50
- return value?.trim().toLowerCase().replace(/[-\s]+/g, "_") ?? "";
51
- }
52
- function isProtocolAgentEvent(event) {
53
- const type = normalizeAnalyticsLabel(event.type);
54
- return normalizeAnalyticsLabel(event.source) === "mcp" || type.startsWith("mcp_");
55
- }
56
- function inferAgentProvider(event) {
57
- const type = normalizeAnalyticsLabel(event.type);
58
- if (normalizeAnalyticsLabel(event.source) === "mcp" || type.startsWith("mcp_")) return "MCP client";
59
- if (type.startsWith("agent_") || type === "agents_request") return "Docs agent";
60
- if ([
61
- "llms_request",
62
- "markdown_request",
63
- "skill_request"
64
- ].includes(type)) return "Docs reader";
65
- }
66
- function detectAgentProviderFromUserAgent(userAgent) {
67
- const value = userAgent?.toLowerCase() ?? "";
68
- if (!value) return;
69
- for (const [pattern, provider] of [
70
- [/cursor/i, "Cursor"],
71
- [/codex/i, "Codex"],
72
- [/chatgpt-user|chatgpt/i, "ChatGPT"],
73
- [/gptbot/i, "GPTBot"],
74
- [/oai-searchbot|openai-search/i, "ChatGPT Search"],
75
- [/openai/i, "ChatGPT"],
76
- [/github-copilot|githubcopilot|copilot/i, "GitHub Copilot"],
77
- [/claudebot|claude-user|anthropic/i, "Claude"],
78
- [/perplexitybot|perplexity-user/i, "Perplexity"],
79
- [/google-extended|googlebot|apis-google/i, "Google"],
80
- [/bingbot|msnbot/i, "Bing"],
81
- [/duckduckbot/i, "DuckDuckGo"],
82
- [/applebot/i, "Apple"],
83
- [/bytespider|bytedance/i, "ByteDance"],
84
- [/ccbot|common crawl/i, "Common Crawl"],
85
- [/ahrefsbot/i, "Ahrefs"],
86
- [/semrushbot/i, "Semrush"]
87
- ]) if (pattern.test(value)) return provider;
88
- if (/bot|crawler|spider|slurp|facebookexternalhit|ia_archiver/.test(value)) return "Other bot";
89
- }
90
- function withDocsCloudAnalyticsHints(event) {
91
- const properties = asRecord(event.properties);
92
- const detectedAgent = detectAgentProviderFromUserAgent(asString(properties.userAgent) ?? asString(properties.user_agent));
93
- const protocolAgent = isProtocolAgentEvent(event);
94
- const incomingTrafficType = asString(properties.trafficType)?.toLowerCase();
95
- const explicitAgent = incomingTrafficType === "agent" || incomingTrafficType === "bot";
96
- const agentProvider = asString(properties.agentName) ?? asString(properties.agent) ?? asString(properties.botProvider) ?? asString(properties.provider) ?? asString(properties.crawler) ?? asString(asRecord(properties.bot).provider) ?? detectedAgent ?? (protocolAgent || explicitAgent ? inferAgentProvider(event) : void 0);
97
- if (!explicitAgent && !protocolAgent && !detectedAgent && !agentProvider) return event;
98
- return {
99
- ...event,
100
- properties: {
101
- ...properties,
102
- trafficType: "agent",
103
- ...agentProvider && !asString(properties.agentName) ? { agentName: agentProvider } : {},
104
- ...agentProvider && !asString(properties.botProvider) ? { botProvider: agentProvider } : {}
105
- }
106
- };
107
- }
108
- async function sendDocsCloudAnalyticsEvent(options, event) {
109
- const fetcher = options.fetch ?? (typeof fetch === "function" ? fetch : void 0);
110
- if (!fetcher) return;
111
- const endpoint = options.endpoint?.trim() || DEFAULT_DOCS_CLOUD_ANALYTICS_ENDPOINT;
112
- const projectId = options.projectId?.trim();
113
- if (!endpoint || !projectId) return;
114
- try {
115
- const normalizedEvent = withDocsCloudAnalyticsHints(event);
116
- await fetcher(endpoint, {
117
- method: "POST",
118
- headers: {
119
- "content-type": "application/json",
120
- ...options.apiKey ? { authorization: `Bearer ${options.apiKey}` } : {}
121
- },
122
- body: JSON.stringify({
123
- projectId,
124
- event: normalizedEvent
125
- }),
126
- keepalive: true
127
- });
128
- } catch {}
129
- }
130
-
131
- //#endregion
132
- export { sendDocsCloudAnalyticsEvent as n, resolveDocsCloudAnalyticsOptions as t };
@@ -1,23 +0,0 @@
1
- import { F as DocsAnalyticsConfig, Y as DocsCloudConfig, t as AIConfig } from "./types-XHABMh_f.mjs";
2
-
3
- //#region src/cloud-ask-ai.d.ts
4
- interface DocsCloudAskAIConfig {
5
- ai?: Pick<AIConfig, "docsUrl" | "enabled" | "provider" | "stream">;
6
- analytics?: boolean | DocsAnalyticsConfig;
7
- cloud?: DocsCloudConfig;
8
- }
9
- interface DocsCloudAskAIResponseOptions {
10
- config?: DocsCloudAskAIConfig;
11
- /**
12
- * Runtime env map for frameworks that expose environment variables outside
13
- * `process.env`, for example SvelteKit's `$env/dynamic/private`.
14
- */
15
- env?: Record<string, string | undefined>;
16
- fetch?: typeof fetch;
17
- publicBaseUrl?: string;
18
- locale?: string;
19
- }
20
- declare function isDocsCloudAskAIProvider(config: Pick<AIConfig, "enabled" | "provider"> | undefined): boolean;
21
- declare function createDocsCloudAskAIResponse(request: Request, options?: DocsCloudAskAIResponseOptions): Promise<Response>;
22
- //#endregion
23
- export { isDocsCloudAskAIProvider as i, DocsCloudAskAIResponseOptions as n, createDocsCloudAskAIResponse as r, DocsCloudAskAIConfig as t };
@@ -1,382 +0,0 @@
1
- import { a as emitDocsAnalyticsEvent } from "./analytics-Bx44lg6d.mjs";
2
-
3
- //#region src/cloud-ask-ai.ts
4
- const DEFAULT_DOCS_CLOUD_API_BASE_URL = "https://api.farming-labs.dev";
5
- const DEFAULT_DOCS_CLOUD_API_KEY_ENV = "DOCS_CLOUD_API_KEY";
6
- const DOCS_CLOUD_PROJECT_ID_ENVS = [
7
- "PUBLIC_DOCS_CLOUD_PROJECT_ID",
8
- "DOCS_CLOUD_PROJECT_ID",
9
- "NEXT_PUBLIC_DOCS_CLOUD_PROJECT_ID"
10
- ];
11
- const DOCS_CLOUD_API_BASE_URL_ENVS = [
12
- "DOCS_CLOUD_API_BASE_URL",
13
- "DOCS_CLOUD_API_URL",
14
- "PUBLIC_DOCS_CLOUD_URL",
15
- "NEXT_PUBLIC_DOCS_CLOUD_URL"
16
- ];
17
- const DOCS_CLOUD_FOOTER_GUARD_CHARS = 256;
18
- const docsCloudRelevantDocsPattern = /\n{2,}(?:-{3,}|\*{3,}|_{3,})[ \t]*\n{1,3}(?:#{1,6}[ \t]+)?(?:\*\*)?Relevant docs(?:\*\*)?[ \t]*/i;
19
- const docsCloudThematicBreakPattern = /^[ \t]*(?:-{3,}|\*{3,}|_{3,})[ \t]*$/gm;
20
- function isPlainObject(value) {
21
- return typeof value === "object" && value !== null && !Array.isArray(value);
22
- }
23
- function readEnv(name, env) {
24
- const trimmed = (env?.[name] ?? (typeof process !== "undefined" ? process.env?.[name] : void 0))?.trim();
25
- return trimmed ? trimmed : void 0;
26
- }
27
- function readFirstEnv(names, env) {
28
- for (const name of names) {
29
- const value = readEnv(name, env);
30
- if (value) return value;
31
- }
32
- }
33
- function resolveDocsCloudApiBaseUrl(env) {
34
- return (readFirstEnv(DOCS_CLOUD_API_BASE_URL_ENVS, env) ?? DEFAULT_DOCS_CLOUD_API_BASE_URL).replace(/\/+$/, "");
35
- }
36
- function resolveDocsCloudProjectId(env) {
37
- return readFirstEnv(DOCS_CLOUD_PROJECT_ID_ENVS, env);
38
- }
39
- function resolveDocsCloudApiKey(cloudConfig, env) {
40
- const envName = cloudConfig?.apiKey?.env?.trim() || DEFAULT_DOCS_CLOUD_API_KEY_ENV;
41
- return {
42
- envName,
43
- apiKey: readEnv(envName, env)
44
- };
45
- }
46
- function jsonError(message, status) {
47
- return Response.json({ error: message }, { status });
48
- }
49
- function textFromMessageContent(content) {
50
- if (typeof content === "string") return content;
51
- if (!Array.isArray(content)) return "";
52
- return content.map((part) => {
53
- if (typeof part === "string") return part;
54
- if (!isPlainObject(part)) return "";
55
- if (typeof part.text === "string") return part.text;
56
- if (typeof part.content === "string") return part.content;
57
- return "";
58
- }).filter(Boolean).join("\n");
59
- }
60
- function lastUserQuestion(messages) {
61
- if (!Array.isArray(messages)) return "";
62
- return textFromMessageContent([...messages].reverse().find((message) => message?.role === "user")?.content).trim();
63
- }
64
- function resolveQuestion(body) {
65
- return typeof body.question === "string" && body.question.trim() ? body.question.trim() : lastUserQuestion(body.messages);
66
- }
67
- function shouldStreamResponse(request, body, aiConfig) {
68
- if (typeof body.stream === "boolean") return body.stream;
69
- if (aiConfig?.stream === false) return false;
70
- const accept = request.headers.get("accept")?.toLowerCase();
71
- return !accept || accept.includes("text/event-stream") || accept.includes("*/*");
72
- }
73
- function stripRelevantDocsFooter(content) {
74
- return content.replace(new RegExp(`${docsCloudRelevantDocsPattern.source}[\\s\\S]*$`, "i"), "").trimEnd();
75
- }
76
- function stripMarkdownThematicBreaks(content) {
77
- return content.replace(docsCloudThematicBreakPattern, "").replace(/\n{3,}/g, "\n\n").trimEnd();
78
- }
79
- function cleanDocsCloudAnswer(content) {
80
- return stripMarkdownThematicBreaks(stripRelevantDocsFooter(content));
81
- }
82
- function safeDocsCloudContent(content, final = false) {
83
- const footerStart = content.search(docsCloudRelevantDocsPattern);
84
- if (footerStart >= 0) return stripMarkdownThematicBreaks(content.slice(0, footerStart));
85
- if (final) return cleanDocsCloudAnswer(content);
86
- return stripMarkdownThematicBreaks(content.slice(0, Math.max(0, content.length - DOCS_CLOUD_FOOTER_GUARD_CHARS)));
87
- }
88
- function createOpenAICompatibleSseChunk(content) {
89
- return `data: ${JSON.stringify({ choices: [{ delta: { content } }] })}\n\n`;
90
- }
91
- function createOpenAICompatibleSseResponse(content) {
92
- const encoder = new TextEncoder();
93
- const stream = new ReadableStream({ start(controller) {
94
- if (content) controller.enqueue(encoder.encode(createOpenAICompatibleSseChunk(content)));
95
- controller.enqueue(encoder.encode("data: [DONE]\n\n"));
96
- controller.close();
97
- } });
98
- return new Response(stream, { headers: {
99
- "Content-Type": "text/event-stream",
100
- "Cache-Control": "no-cache, no-transform",
101
- Connection: "keep-alive"
102
- } });
103
- }
104
- function openAICompatibleDeltaContent(value) {
105
- if (!isPlainObject(value)) return void 0;
106
- const firstChoice = Array.isArray(value.choices) ? value.choices[0] : void 0;
107
- if (!isPlainObject(firstChoice) || !isPlainObject(firstChoice.delta)) return void 0;
108
- return typeof firstChoice.delta.content === "string" ? firstChoice.delta.content : void 0;
109
- }
110
- function docsCloudStreamContent(value) {
111
- if (typeof value === "string") return value;
112
- if (!isPlainObject(value)) return void 0;
113
- for (const key of [
114
- "content",
115
- "text",
116
- "answer",
117
- "delta"
118
- ]) {
119
- const content = value[key];
120
- if (typeof content === "string") return content;
121
- }
122
- }
123
- function docsCloudAnswerFromPayload(payload) {
124
- if (!isPlainObject(payload)) return "";
125
- for (const key of [
126
- "answer",
127
- "text",
128
- "content"
129
- ]) {
130
- const content = payload[key];
131
- if (typeof content === "string") return content;
132
- }
133
- return "";
134
- }
135
- function createCleanDocsCloudSseResponse(upstream) {
136
- if (!upstream.ok || !upstream.body) return new Response(upstream.body, {
137
- status: upstream.status,
138
- statusText: upstream.statusText,
139
- headers: {
140
- "Content-Type": upstream.headers.get("Content-Type") ?? "text/event-stream",
141
- "Cache-Control": upstream.headers.get("Cache-Control") ?? "no-cache, no-transform",
142
- Connection: upstream.headers.get("Connection") ?? "keep-alive"
143
- }
144
- });
145
- const decoder = new TextDecoder();
146
- const encoder = new TextEncoder();
147
- const stream = new ReadableStream({ async start(controller) {
148
- const reader = upstream.body.getReader();
149
- let buffer = "";
150
- let content = "";
151
- let emittedLength = 0;
152
- const enqueue = (chunk) => {
153
- controller.enqueue(encoder.encode(chunk));
154
- };
155
- const emitSafeContent = (final = false) => {
156
- const safeContent = safeDocsCloudContent(content, final);
157
- if (safeContent.length <= emittedLength) return;
158
- enqueue(createOpenAICompatibleSseChunk(safeContent.slice(emittedLength)));
159
- emittedLength = safeContent.length;
160
- };
161
- const flushEvent = (event) => {
162
- const data = event.split(/\r?\n/).filter((line) => line.startsWith("data:")).map((line) => line.slice(5).trim()).filter(Boolean).join("\n").trim();
163
- if (!data) return;
164
- if (data === "[DONE]") return;
165
- try {
166
- const parsed = JSON.parse(data);
167
- const delta = openAICompatibleDeltaContent(parsed) ?? docsCloudStreamContent(parsed);
168
- if (delta) {
169
- content += delta;
170
- emitSafeContent();
171
- }
172
- } catch {
173
- content += data;
174
- emitSafeContent();
175
- }
176
- };
177
- try {
178
- while (true) {
179
- const { value, done } = await reader.read();
180
- if (done) break;
181
- buffer += decoder.decode(value, { stream: true });
182
- const events = buffer.split(/\r?\n\r?\n/);
183
- buffer = events.pop() ?? "";
184
- for (const event of events) flushEvent(event);
185
- }
186
- buffer += decoder.decode();
187
- if (buffer.trim()) flushEvent(buffer);
188
- } catch {}
189
- emitSafeContent(true);
190
- enqueue("data: [DONE]\n\n");
191
- controller.close();
192
- } });
193
- return new Response(stream, {
194
- status: upstream.status,
195
- statusText: upstream.statusText,
196
- headers: {
197
- "Content-Type": "text/event-stream",
198
- "Cache-Control": upstream.headers.get("Cache-Control") ?? "no-cache, no-transform",
199
- Connection: upstream.headers.get("Connection") ?? "keep-alive"
200
- }
201
- });
202
- }
203
- function analyticsProperties(request) {
204
- const userAgent = request.headers.get("user-agent")?.trim();
205
- return userAgent ? { userAgent } : {};
206
- }
207
- function isDocsCloudAskAIProvider(config) {
208
- return config?.enabled === true && config.provider === "docs-cloud";
209
- }
210
- async function createDocsCloudAskAIResponse(request, options = {}) {
211
- const config = options.config;
212
- const aiConfig = config?.ai;
213
- const analytics = config?.analytics;
214
- const requestUrl = new URL(request.url);
215
- const requestStartedAt = Date.now();
216
- const requestProperties = analyticsProperties(request);
217
- let body;
218
- try {
219
- body = await request.json();
220
- } catch {
221
- await emitDocsAnalyticsEvent(analytics, {
222
- type: "api_ai_error",
223
- source: "server",
224
- url: request.url,
225
- path: requestUrl.pathname,
226
- locale: options.locale,
227
- properties: {
228
- ...requestProperties,
229
- reason: "invalid_json",
230
- provider: "docs-cloud",
231
- durationMs: Math.max(0, Date.now() - requestStartedAt)
232
- }
233
- });
234
- return jsonError("Invalid JSON body. Expected { messages: [...] }.", 400);
235
- }
236
- const question = resolveQuestion(body);
237
- const messages = Array.isArray(body.messages) ? body.messages : void 0;
238
- if (!question) {
239
- await emitDocsAnalyticsEvent(analytics, {
240
- type: "api_ai_error",
241
- source: "server",
242
- url: request.url,
243
- path: requestUrl.pathname,
244
- locale: options.locale,
245
- properties: {
246
- ...requestProperties,
247
- reason: "missing_user_message",
248
- provider: "docs-cloud",
249
- durationMs: Math.max(0, Date.now() - requestStartedAt)
250
- }
251
- });
252
- return jsonError("At least one user message is required.", 400);
253
- }
254
- const projectId = resolveDocsCloudProjectId(options.env);
255
- const { envName, apiKey } = resolveDocsCloudApiKey(config?.cloud, options.env);
256
- if (!projectId || !apiKey) {
257
- const reason = !projectId ? "missing_docs_cloud_project_id" : "missing_docs_cloud_api_key";
258
- await emitDocsAnalyticsEvent(analytics, {
259
- type: "api_ai_error",
260
- source: "server",
261
- url: request.url,
262
- path: requestUrl.pathname,
263
- locale: options.locale,
264
- input: { question },
265
- properties: {
266
- ...requestProperties,
267
- reason,
268
- provider: "docs-cloud",
269
- envName: !apiKey ? envName : void 0,
270
- durationMs: Math.max(0, Date.now() - requestStartedAt)
271
- }
272
- });
273
- return jsonError(!projectId ? `Docs Cloud Ask AI is missing ${DOCS_CLOUD_PROJECT_ID_ENVS.join(" or ")}. Add the project id to the deployment environment.` : `Docs Cloud Ask AI is missing ${envName}. Add it to the deployment environment.`, 500);
274
- }
275
- const stream = shouldStreamResponse(request, body, aiConfig);
276
- const apiBaseUrl = resolveDocsCloudApiBaseUrl(options.env);
277
- const publicBaseUrl = aiConfig?.docsUrl ?? options.publicBaseUrl ?? requestUrl.origin;
278
- const requestedModel = typeof body.model === "string" && body.model.trim() ? body.model.trim() : void 0;
279
- await emitDocsAnalyticsEvent(analytics, {
280
- type: "api_ai_request",
281
- source: "server",
282
- url: request.url,
283
- path: requestUrl.pathname,
284
- locale: options.locale,
285
- input: { question },
286
- properties: {
287
- ...requestProperties,
288
- provider: "docs-cloud",
289
- messageCount: messages?.length,
290
- questionLength: question.length,
291
- model: requestedModel ?? "docs-cloud"
292
- }
293
- });
294
- let upstream;
295
- try {
296
- upstream = await (options.fetch ?? fetch)(`${apiBaseUrl}/v1/projects/${encodeURIComponent(projectId)}/knowledge/ask`, {
297
- method: "POST",
298
- headers: {
299
- Accept: stream ? "text/event-stream, application/json" : "application/json",
300
- Authorization: `Bearer ${apiKey}`,
301
- "Content-Type": "application/json",
302
- "X-Docs-Cloud-Public-Base-Url": publicBaseUrl
303
- },
304
- body: JSON.stringify({
305
- messages,
306
- question,
307
- answerMode: "auto",
308
- answerStyle: "public",
309
- modelPreference: requestedModel,
310
- stream,
311
- publicBaseUrl
312
- })
313
- });
314
- } catch {
315
- await emitDocsAnalyticsEvent(analytics, {
316
- type: "api_ai_error",
317
- source: "server",
318
- url: request.url,
319
- path: requestUrl.pathname,
320
- locale: options.locale,
321
- input: { question },
322
- properties: {
323
- ...requestProperties,
324
- reason: "docs_cloud_fetch_error",
325
- provider: "docs-cloud",
326
- durationMs: Math.max(0, Date.now() - requestStartedAt)
327
- }
328
- });
329
- return jsonError("Docs Cloud Ask AI request failed.", 502);
330
- }
331
- if (!upstream.ok) {
332
- await upstream.text().catch(() => "");
333
- await emitDocsAnalyticsEvent(analytics, {
334
- type: "api_ai_error",
335
- source: "server",
336
- url: request.url,
337
- path: requestUrl.pathname,
338
- locale: options.locale,
339
- input: { question },
340
- properties: {
341
- ...requestProperties,
342
- reason: "docs_cloud_error",
343
- provider: "docs-cloud",
344
- status: upstream.status,
345
- durationMs: Math.max(0, Date.now() - requestStartedAt)
346
- }
347
- });
348
- return jsonError(`Docs Cloud Ask AI error (${upstream.status}).`, 502);
349
- }
350
- await emitDocsAnalyticsEvent(analytics, {
351
- type: "api_ai_response",
352
- source: "server",
353
- url: request.url,
354
- path: requestUrl.pathname,
355
- locale: options.locale,
356
- input: { question },
357
- properties: {
358
- ...requestProperties,
359
- provider: "docs-cloud",
360
- status: upstream.status,
361
- durationMs: Math.max(0, Date.now() - requestStartedAt)
362
- }
363
- });
364
- const contentType = upstream.headers.get("Content-Type") ?? "";
365
- if (stream && contentType.includes("text/event-stream")) return createCleanDocsCloudSseResponse(upstream);
366
- const upstreamBody = await upstream.text();
367
- let payload;
368
- let answer = upstreamBody;
369
- try {
370
- payload = JSON.parse(upstreamBody);
371
- answer = docsCloudAnswerFromPayload(payload) || answer;
372
- } catch {}
373
- const cleanAnswer = cleanDocsCloudAnswer(answer);
374
- if (stream) return createOpenAICompatibleSseResponse(cleanAnswer);
375
- return Response.json(isPlainObject(payload) ? {
376
- ...payload,
377
- answer: cleanAnswer
378
- } : { answer: cleanAnswer });
379
- }
380
-
381
- //#endregion
382
- export { isDocsCloudAskAIProvider as n, createDocsCloudAskAIResponse as t };