@farming-labs/svelte 0.1.60 → 0.1.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.
- package/dist/server.js +117 -1
- package/package.json +2 -2
package/dist/server.js
CHANGED
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
import fs from "node:fs";
|
|
31
31
|
import path from "node:path";
|
|
32
32
|
import matter from "gray-matter";
|
|
33
|
-
import { applySidebarFolderIndexBehavior, buildDocsAgentDiscoverySpec, findDocsMarkdownPage, isDocsAgentDiscoveryRequest, isDocsSkillRequest, normalizeDocsRelated, performDocsSearch, renderDocsMarkdownDocument, renderDocsSkillDocument, stripGeneratedAgentProvenance, resolveDocsAgentMdxContent, resolvePageSidebarFolderIndexBehavior, resolveSearchRequestConfig, resolveDocsI18n, resolveDocsLlmsTxtFormat, resolveDocsLocale, resolveDocsMarkdownRequest, resolveDocsPath, resolvePageReadingTime, resolveReadingTimeOptions, resolveDocsSkillFormat, } from "@farming-labs/docs";
|
|
33
|
+
import { applySidebarFolderIndexBehavior, buildDocsAgentDiscoverySpec, emitDocsAnalyticsEvent, findDocsMarkdownPage, isDocsAgentDiscoveryRequest, isDocsSkillRequest, normalizeDocsRelated, performDocsSearch, renderDocsMarkdownDocument, renderDocsSkillDocument, stripGeneratedAgentProvenance, resolveDocsAgentMdxContent, resolvePageSidebarFolderIndexBehavior, resolveSearchRequestConfig, resolveDocsI18n, resolveDocsLlmsTxtFormat, resolveDocsLocale, resolveDocsMarkdownRequest, resolveDocsPath, resolvePageReadingTime, resolveReadingTimeOptions, resolveDocsSkillFormat, } from "@farming-labs/docs";
|
|
34
34
|
import { createDocsMcpHttpHandler, resolveDocsMcpConfig, serializeDocsIconRegistry, serializeOpenDocsProviders, } from "@farming-labs/docs/server";
|
|
35
35
|
import { loadDocsNavTree, loadDocsContent, flattenNavTree } from "./content.js";
|
|
36
36
|
import { renderMarkdown } from "./markdown.js";
|
|
@@ -341,6 +341,7 @@ function findPageInMap(contentMap, dirPrefix, slug) {
|
|
|
341
341
|
*/
|
|
342
342
|
export function createDocsServer(config = {}) {
|
|
343
343
|
const entry = config.entry ?? "docs";
|
|
344
|
+
const analytics = config.analytics;
|
|
344
345
|
const contentDirBase = config.contentDir ?? entry;
|
|
345
346
|
const rootDir = path.resolve(config.rootDir ?? process.cwd());
|
|
346
347
|
const i18n = resolveDocsI18n(config.i18n);
|
|
@@ -702,6 +703,7 @@ export function createDocsServer(config = {}) {
|
|
|
702
703
|
headers: { "Content-Type": "application/json" },
|
|
703
704
|
});
|
|
704
705
|
}
|
|
706
|
+
const searchStartedAt = Date.now();
|
|
705
707
|
const results = await performDocsSearch({
|
|
706
708
|
pages: getSearchIndex(ctx),
|
|
707
709
|
query,
|
|
@@ -710,6 +712,20 @@ export function createDocsServer(config = {}) {
|
|
|
710
712
|
pathname: event.url.searchParams.get("pathname") ?? undefined,
|
|
711
713
|
siteTitle: llmsTitle,
|
|
712
714
|
});
|
|
715
|
+
await emitDocsAnalyticsEvent(analytics, {
|
|
716
|
+
type: "api_search",
|
|
717
|
+
source: "server",
|
|
718
|
+
url: event.request.url,
|
|
719
|
+
path: event.url.pathname,
|
|
720
|
+
locale: ctx.locale,
|
|
721
|
+
input: { query },
|
|
722
|
+
properties: {
|
|
723
|
+
queryLength: query.length,
|
|
724
|
+
resultCount: results.length,
|
|
725
|
+
pathname: event.url.searchParams.get("pathname") ?? undefined,
|
|
726
|
+
durationMs: Math.max(0, Date.now() - searchStartedAt),
|
|
727
|
+
},
|
|
728
|
+
});
|
|
713
729
|
return new Response(JSON.stringify(results), {
|
|
714
730
|
headers: { "Content-Type": "application/json" },
|
|
715
731
|
});
|
|
@@ -737,7 +753,16 @@ export function createDocsServer(config = {}) {
|
|
|
737
753
|
}
|
|
738
754
|
const DEFAULT_SYSTEM_PROMPT = buildDefaultSystemPrompt();
|
|
739
755
|
async function POST(event) {
|
|
756
|
+
const requestUrl = new URL(event.request.url);
|
|
757
|
+
const requestStartedAt = Date.now();
|
|
740
758
|
if (!aiConfig.enabled) {
|
|
759
|
+
await emitDocsAnalyticsEvent(analytics, {
|
|
760
|
+
type: "api_ai_error",
|
|
761
|
+
source: "server",
|
|
762
|
+
url: event.request.url,
|
|
763
|
+
path: requestUrl.pathname,
|
|
764
|
+
properties: { reason: "disabled" },
|
|
765
|
+
});
|
|
741
766
|
return new Response(JSON.stringify({
|
|
742
767
|
error: "AI is not enabled. Set `ai: { enabled: true }` in your docs config to enable it.",
|
|
743
768
|
}), { status: 404, headers: { "Content-Type": "application/json" } });
|
|
@@ -746,6 +771,16 @@ export function createDocsServer(config = {}) {
|
|
|
746
771
|
(typeof import.meta !== "undefined" ? import.meta.env?.OPENAI_API_KEY : undefined) ??
|
|
747
772
|
(typeof process !== "undefined" ? process.env?.OPENAI_API_KEY : undefined);
|
|
748
773
|
if (!resolvedKey) {
|
|
774
|
+
await emitDocsAnalyticsEvent(analytics, {
|
|
775
|
+
type: "api_ai_error",
|
|
776
|
+
source: "server",
|
|
777
|
+
url: event.request.url,
|
|
778
|
+
path: requestUrl.pathname,
|
|
779
|
+
properties: {
|
|
780
|
+
reason: "missing_api_key",
|
|
781
|
+
durationMs: Math.max(0, Date.now() - requestStartedAt),
|
|
782
|
+
},
|
|
783
|
+
});
|
|
749
784
|
return new Response(JSON.stringify({
|
|
750
785
|
error: "AI is enabled but no API key was found. Set `apiKey` in your docs config `ai` section or add OPENAI_API_KEY to your environment.",
|
|
751
786
|
}), { status: 500, headers: { "Content-Type": "application/json" } });
|
|
@@ -756,14 +791,48 @@ export function createDocsServer(config = {}) {
|
|
|
756
791
|
body = await event.request.json();
|
|
757
792
|
}
|
|
758
793
|
catch {
|
|
794
|
+
await emitDocsAnalyticsEvent(analytics, {
|
|
795
|
+
type: "api_ai_error",
|
|
796
|
+
source: "server",
|
|
797
|
+
url: event.request.url,
|
|
798
|
+
path: requestUrl.pathname,
|
|
799
|
+
locale: ctx.locale,
|
|
800
|
+
properties: {
|
|
801
|
+
reason: "invalid_json",
|
|
802
|
+
durationMs: Math.max(0, Date.now() - requestStartedAt),
|
|
803
|
+
},
|
|
804
|
+
});
|
|
759
805
|
return new Response(JSON.stringify({ error: "Invalid JSON body. Expected { messages: [...] }" }), { status: 400, headers: { "Content-Type": "application/json" } });
|
|
760
806
|
}
|
|
761
807
|
const messages = body.messages;
|
|
762
808
|
if (!Array.isArray(messages) || messages.length === 0) {
|
|
809
|
+
await emitDocsAnalyticsEvent(analytics, {
|
|
810
|
+
type: "api_ai_error",
|
|
811
|
+
source: "server",
|
|
812
|
+
url: event.request.url,
|
|
813
|
+
path: requestUrl.pathname,
|
|
814
|
+
locale: ctx.locale,
|
|
815
|
+
properties: {
|
|
816
|
+
reason: "missing_messages",
|
|
817
|
+
durationMs: Math.max(0, Date.now() - requestStartedAt),
|
|
818
|
+
},
|
|
819
|
+
});
|
|
763
820
|
return new Response(JSON.stringify({ error: "messages array is required and must not be empty." }), { status: 400, headers: { "Content-Type": "application/json" } });
|
|
764
821
|
}
|
|
765
822
|
const lastUserMessage = [...messages].reverse().find((m) => m.role === "user");
|
|
766
823
|
if (!lastUserMessage) {
|
|
824
|
+
await emitDocsAnalyticsEvent(analytics, {
|
|
825
|
+
type: "api_ai_error",
|
|
826
|
+
source: "server",
|
|
827
|
+
url: event.request.url,
|
|
828
|
+
path: requestUrl.pathname,
|
|
829
|
+
locale: ctx.locale,
|
|
830
|
+
properties: {
|
|
831
|
+
reason: "missing_user_message",
|
|
832
|
+
messageCount: messages.length,
|
|
833
|
+
durationMs: Math.max(0, Date.now() - requestStartedAt),
|
|
834
|
+
},
|
|
835
|
+
});
|
|
767
836
|
return new Response(JSON.stringify({ error: "At least one user message is required." }), {
|
|
768
837
|
status: 400,
|
|
769
838
|
headers: { "Content-Type": "application/json" },
|
|
@@ -789,6 +858,20 @@ export function createDocsServer(config = {}) {
|
|
|
789
858
|
: undefined;
|
|
790
859
|
const resolved = resolveAIModelAndProvider(aiConfig, requestedModel);
|
|
791
860
|
const finalKey = resolved.apiKey ?? resolvedKey;
|
|
861
|
+
await emitDocsAnalyticsEvent(analytics, {
|
|
862
|
+
type: "api_ai_request",
|
|
863
|
+
source: "server",
|
|
864
|
+
url: event.request.url,
|
|
865
|
+
path: requestUrl.pathname,
|
|
866
|
+
locale: ctx.locale,
|
|
867
|
+
input: { question: lastUserMessage.content },
|
|
868
|
+
properties: {
|
|
869
|
+
messageCount: messages.length,
|
|
870
|
+
questionLength: lastUserMessage.content.length,
|
|
871
|
+
retrievedCount: scored.length,
|
|
872
|
+
model: resolved.model,
|
|
873
|
+
},
|
|
874
|
+
});
|
|
792
875
|
const llmResponse = await fetch(`${resolved.baseUrl}/chat/completions`, {
|
|
793
876
|
method: "POST",
|
|
794
877
|
headers: {
|
|
@@ -799,8 +882,40 @@ export function createDocsServer(config = {}) {
|
|
|
799
882
|
});
|
|
800
883
|
if (!llmResponse.ok) {
|
|
801
884
|
const errText = await llmResponse.text().catch(() => "Unknown error");
|
|
885
|
+
await emitDocsAnalyticsEvent(analytics, {
|
|
886
|
+
type: "api_ai_error",
|
|
887
|
+
source: "server",
|
|
888
|
+
url: event.request.url,
|
|
889
|
+
path: requestUrl.pathname,
|
|
890
|
+
locale: ctx.locale,
|
|
891
|
+
input: { question: lastUserMessage.content },
|
|
892
|
+
properties: {
|
|
893
|
+
reason: "llm_error",
|
|
894
|
+
status: llmResponse.status,
|
|
895
|
+
messageCount: messages.length,
|
|
896
|
+
questionLength: lastUserMessage.content.length,
|
|
897
|
+
retrievedCount: scored.length,
|
|
898
|
+
model: resolved.model,
|
|
899
|
+
durationMs: Math.max(0, Date.now() - requestStartedAt),
|
|
900
|
+
},
|
|
901
|
+
});
|
|
802
902
|
return new Response(JSON.stringify({ error: `LLM API error (${llmResponse.status}): ${errText}` }), { status: 502, headers: { "Content-Type": "application/json" } });
|
|
803
903
|
}
|
|
904
|
+
await emitDocsAnalyticsEvent(analytics, {
|
|
905
|
+
type: "api_ai_response",
|
|
906
|
+
source: "server",
|
|
907
|
+
url: event.request.url,
|
|
908
|
+
path: requestUrl.pathname,
|
|
909
|
+
locale: ctx.locale,
|
|
910
|
+
input: { question: lastUserMessage.content },
|
|
911
|
+
properties: {
|
|
912
|
+
messageCount: messages.length,
|
|
913
|
+
questionLength: lastUserMessage.content.length,
|
|
914
|
+
retrievedCount: scored.length,
|
|
915
|
+
model: resolved.model,
|
|
916
|
+
durationMs: Math.max(0, Date.now() - requestStartedAt),
|
|
917
|
+
},
|
|
918
|
+
});
|
|
804
919
|
return new Response(llmResponse.body, {
|
|
805
920
|
headers: {
|
|
806
921
|
"Content-Type": "text/event-stream",
|
|
@@ -831,6 +946,7 @@ export function createDocsServer(config = {}) {
|
|
|
831
946
|
},
|
|
832
947
|
},
|
|
833
948
|
mcp: config.mcp,
|
|
949
|
+
analytics,
|
|
834
950
|
defaultName: mcpSiteTitle,
|
|
835
951
|
});
|
|
836
952
|
return { load, GET, POST, MCP };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@farming-labs/svelte",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.62",
|
|
4
4
|
"description": "SvelteKit adapter for @farming-labs/docs — content loading and navigation utilities",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"docs",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"devDependencies": {
|
|
57
57
|
"@types/node": "^22.10.0",
|
|
58
58
|
"typescript": "^5.9.3",
|
|
59
|
-
"@farming-labs/docs": "0.1.
|
|
59
|
+
"@farming-labs/docs": "0.1.62"
|
|
60
60
|
},
|
|
61
61
|
"peerDependencies": {
|
|
62
62
|
"@farming-labs/docs": "*"
|