85interface TraversedCitation extends Citation {
86traversalStatus: "success" | "not_attempted" | "failed" | "url_missing";
87fetchedContentSummary?: string; // Note: Original code didn't fetch summary, only status
88error?: string;
89}
479errorInvalidFile: "Invalid file type. Please upload a PDF.",
480errorFileSize: "File is too large (Max {maxSize}).", // Updated to use replacement
481errorFetchFailed: "Failed to perform analysis: {errorMessage}", // Placeholder for dynamic message
482analysisTitle: "Analysis Results", // Keep if needed elsewhere, dashboard cards have own titles now
483loadingAnalysis: "Analyzing Document...",
515errorInvalidFile: "Tipo de archivo inválido. Por favor, suba un PDF.",
516errorFileSize: "El archivo es demasiado grande (Máx {maxSize}).", // Updated
517errorFetchFailed: "Falló la realización del análisis: {errorMessage}",
518analysisTitle: "Resultados del Análisis",
519loadingAnalysis: "Analizando Documento...",
819820try {
821// Fetch from the current location, expecting the Val to handle POST
822const response = await fetch(window.location.pathname + '?format=json', { // Ensure format=json is requested
823method: 'POST',
824headers: { 'Accept': 'application/json'}, // Crucial: Tell server we want JSON back
909console.error('Analysis Request Error:', error);
910// Use the specific error message from the caught error
911displayError('errorFetchFailed', { errorMessage: error.message });
912resultsArea.style.display = 'none';
913} finally {
952const { OpenAI } = await import("https://esm.town/v/std/openai");
953const { z } = await import("npm:zod");
954const { fetch } = await import("https://esm.town/v/std/fetch");
955// Import the PDF extraction library
956const { PDFExtract, PDFExtractOptions } = await import("npm:pdf.js-extract");
1040const traversalPromises = citations.map(async (citation): Promise<TraversedCitation> => {
1041if (citation.potentialUrl) {
1042traversedCount++; // Increment here is slightly inaccurate if fetch fails early, but simpler
1043let status: TraversedCitation["traversalStatus"] = "failed";
1044let errorMsg: string | undefined = undefined;
1045let urlToFetch = citation.potentialUrl;
1046// Basic URL validation/fixing
1047if (!urlToFetch.startsWith('http://') && !urlToFetch.startsWith('https://')) {
1048urlToFetch = 'http://' + urlToFetch; // Default to http if protocol missing
1049}
10501051try {
1052// Log the attempt for this specific URL
1053log.push({ agent, type: "step", message: `Attempting to fetch: ${urlToFetch}` });
1054const response = await fetch(urlToFetch, {
1055headers: { "User-Agent": "ValTownPolicyAnalysisBot/1.0 (+http://val.town)" }, // Be a good bot citizen
1056redirect: "follow", // Follow redirects
1065status = "success";
1066// Log success for this URL
1067log.push({ agent, type: "result", message: `Successfully accessed: ${urlToFetch}` });
1068return { ...citation, potentialUrl: urlToFetch, traversalStatus: status, error: undefined };
1069} catch (error) {
1070errorMsg = `Workspace failed for ${urlToFetch}: ${error.message.substring(0, 100)}`; // Keep error msg concise
1071// Log failure for this URL
1072log.push({ agent, type: "error", message: errorMsg });
1073status = "failed";
1074return { ...citation, potentialUrl: urlToFetch, traversalStatus: status, error: errorMsg };
1075}
1076} else {
1149log.push({ agent: ingestionAgent, type: "step", message: \`Workspaceing from URL: \${input.documentUrl}\` });
1150try {
1151// Basic check for common non-HTTP URL schemes that fetch will reject
1152if (!input.documentUrl.match(/^https?:\/\//i)) {
1153throw new Error("Invalid URL scheme. Only http and https are supported.");
1154}
1155const response = await fetch(input.documentUrl, {
1156headers: { "Accept": "text/plain, text/html, application/pdf", "User-Agent": "ValTownPolicyAnalysisBot/1.0" },
1157redirect: "follow",
1158timeout: 10000 // 10 second timeout for fetching
1159});
1160if (!response.ok) throw new Error(\`HTTP error! Status: \${response.status} \${response.statusText}\`);
1171} else if (contentType.includes("text/html") || contentType.includes("text/plain") || contentType === "") { // Allow empty content type
1172const text = await response.text();
1173if (!text || text.trim().length === 0) throw new Error("Fetched content is empty or not text.");
1174log.push({
1175agent: ingestionAgent,
11851186} catch (error) {
1187const errorMessage = \`Failed to fetch or process URL \${input.documentUrl}: \${error.message}\`;
1188log.push({ agent: ingestionAgent, type: "error", message: errorMessage });
1189documentText = null;
vtProjectSearchimport.ts3 matches
27if (userId && !processedUsers.has(userId)) {
28try {
29// Fetch user data
30const user = await vt.users.retrieve(userId);
3143processedUsers.add(userId);
44} catch (error) {
45console.error(`Error fetching user ${userId}:`, error);
46// Continue with val processing even if user fetch fails
47}
48}
myanythingmain.tsx1 match
2526try {
27const response = await fetch(window.location.href, {
28method: 'POST',
29body: formData
myeverythingmain.tsx1 match
2526try {
27const response = await fetch(window.location.href, {
28method: "POST",
29body: formData,
2526try {
27const response = await fetch(window.location.href, {
28method: "POST",
29body: formData,
FixItWandindex.http.ts1 match
18});
1920export default app.fetch;
daily-advice-appmain.tsx4 matches
7const [loading, setLoading] = useState(false);
89async function fetchAdvice() {
10setLoading(true);
11try {
12const res = await fetch("https://api.adviceslip.com/advice");
13const data = await res.json();
14setAdvice(data.slip.advice);
2122useEffect(() => {
23fetchAdvice();
24}, []);
2532</p>
33<button
34onClick={fetchAdvice}
35className="mt-6 bg-blue-500 hover:bg-blue-600 text-white font-semibold py-2 px-4 rounded w-full"
36disabled={loading}
mini-remixrender.tsx1 match
56e.preventDefault()
57const form = e.currentTarget as HTMLFormElement
58const res = await fetch(form.action || window.location.href, {
59method: form.method || "POST",
60body: new FormData(form),
moiPosterImprovedMoiEditor.tsx7 matches
8disabled?: boolean;
9username?: string; // Username prop to set default author
10valId?: string; // Val ID for fetching endpoints
11apiToken?: string; // Token for API requests
12}
62const initializedRef = useRef(false);
63
64// Fetch HTTP endpoints if available
65useEffect(() => {
66if (!valId || !apiToken) return;
67
68const fetchEndpoints = async () => {
69setLoadingEndpoints(true);
70setEndpointsError(null);
71
72try {
73const response = await fetch(`/api/vals/${valId}/endpoints`, {
74headers: { 'Authorization': `Bearer ${apiToken}` }
75});
76
77if (!response.ok) {
78throw new Error(`Failed to fetch endpoints: ${response.statusText}`);
79}
80
82setEndpoints(data.endpoints || []);
83} catch (error) {
84console.error('Error fetching endpoints:', error);
85setEndpointsError(error instanceof Error ? error.message : 'Unknown error');
86} finally {
89};
90
91fetchEndpoints();
92}, [valId, apiToken]);
93
moiPosterImprovedApp.tsx29 matches
34const [tokenError, setTokenError] = useState<string | null>(null);
35const [username, setUsername] = useState<string>("");
36// Flag to track if we've already tried to fetch data
37const [initialFetchDone, setInitialFetchDone] = useState(false);
38// Editor key for forcing re-render
39const [editorKey, setEditorKey] = useState<string>("editor-0");
57}, [apiToken]);
5859// Fetch user information to get username
60const fetchUserInfo = useCallback(async () => {
61if (!apiToken) return;
6263try {
64const response = await fetch(`/api/user`, {
65headers: { "Authorization": `Bearer ${apiToken}` },
66});
74}
75} catch (error) {
76console.warn("Could not fetch user info:", error);
77// Non-critical error, don't show to user
78}
79}, [apiToken]);
8081const fetchVals = useCallback(async () => {
82if (!apiToken) {
83setError("Val Town API Key is required to list your vals.");
84setLoading(false);
85setVals([]);
86setInitialFetchDone(true);
87return;
88}
97try {
98const queryParams = filterPrivacy !== "all" ? `?privacy=${filterPrivacy}` : "";
99const response = await fetch(`/api/vals${queryParams}`, {
100headers: { "Authorization": `Bearer ${apiToken}` },
101});
108setVals([]);
109} else {
110setError(`Failed to fetch vals: ${errorData.error || response.statusText}`);
111}
112throw new Error(`Failed to fetch vals (Status: ${response.status})`);
113}
114const data = await response.json();
121}
122} catch (err) {
123console.error(`Error fetching vals:`, err);
124if (!error && !tokenError) {
125setError(`Failed to load vals. Please try again later.`);
127} finally {
128setLoading(false);
129setInitialFetchDone(true);
130}
131}, [apiToken, filterPrivacy, initialFetchDone, error, tokenError]);
132133// Run initial fetch only once when API token is available
134useEffect(() => {
135if (apiToken && !initialFetchDone && !loading) {
136fetchUserInfo();
137fetchVals();
138}
139}, [apiToken, initialFetchDone, loading, fetchUserInfo, fetchVals]);
140141const handleValSelect = async (val: Val) => {
165try {
166const valId = val.id;
167const response = await fetch(`/api/vals/${valId}/moi`);
168if (!response.ok) {
169const errorData = await response.json().catch(() => ({ error: `HTTP error ${response.status}` }));
170throw new Error(errorData.error || "Failed to fetch moi.md");
171}
172const data: MoiFile = await response.json();
179pendingSaveContentRef.current = initialContent;
180} catch (err) {
181console.error("Error fetching moi.md:", err);
182setItemError(`Failed to fetch moi.md content: ${err instanceof Error ? err.message : String(err)}`);
183if (selectedVal) {
184const defaultContent = generateDefaultMoiContent(selectedVal);
274console.log("Updating existing moi.md file");
275// Update existing moi.md file using the current API endpoint
276const response = await fetch(`/api/vals/${valId}/moi`, {
277method: "POST",
278headers: { "Content-Type": "application/json", "Authorization": `Bearer ${apiToken}` },
296console.log("Creating new moi.md file");
297// Create new moi.md file for vals that don't have one yet
298const response = await fetch(`/api/vals/${valId}/file`, {
299method: "POST",
300headers: { "Content-Type": "application/json", "Authorization": `Bearer ${apiToken}` },
327
328// Refresh the vals list to show updated status
329fetchVals();
330
331setTimeout(() => setSaveSuccess(false), 3000);
351setApiToken(newToken);
352353// Reset the initialFetchDone flag if the token changes
354if (newToken !== apiToken) {
355setInitialFetchDone(false);
356}
357};
443{/* Refresh Button: Aqua background, Black text */}
444<button
445onClick={fetchVals}
446disabled={loading || !apiToken}
447className={`px-3 py-1.5 rounded-md text-sm transition-colors text-[#000000] ${