Grabber-In-Tanstack-Two / src /lib /grabber /search.functions.ts
ChBysk's picture
Upload folder using huggingface_hub
fa7b380 verified
Raw
History Blame Contribute Delete
2.64 kB
import { createServerFn } from "@tanstack/react-start";
import { z } from "zod";
import { normalizePost, getByPath, type NormalizedPost, type SiteConfig } from "./sites";
const SiteSchema: z.ZodType<SiteConfig> = z.object({
id: z.string(),
name: z.string(),
baseUrl: z.string().url(),
searchPath: z.string(),
params: z.object({ tags: z.string(), page: z.string(), limit: z.string() }),
postsPath: z.string(),
fields: z.object({
id: z.string(),
previewUrl: z.string(),
fileUrl: z.string(),
ext: z.string(),
tags: z.string(),
source: z.string().optional(),
rating: z.string().optional(),
score: z.string().optional(),
sampleUrl: z.string().optional(),
fileSize: z.string().optional(),
width: z.string().optional(),
height: z.string().optional(),
md5: z.string().optional(),
uploader: z.string().optional(),
createdAt: z.string().optional(),
}),
headers: z.record(z.string(), z.string()).optional(),
pageStartsAt: z.number().optional(),
});
const InputSchema = z.object({
site: SiteSchema,
tags: z.string().default(""),
page: z.number().int().min(1).default(1),
limit: z.number().int().min(1).max(200).default(40),
});
export type SearchResult = {
posts: NormalizedPost[];
error?: string;
};
export const searchPosts = createServerFn({ method: "POST" })
.inputValidator((input: unknown) => InputSchema.parse(input))
.handler(async ({ data }): Promise<SearchResult> => {
const { site, tags, page, limit } = data;
const pageParam = (site.pageStartsAt ?? 1) === 0 ? page - 1 : page;
const url = new URL(site.searchPath, site.baseUrl);
url.searchParams.set(site.params.tags, tags);
url.searchParams.set(site.params.page, String(pageParam));
url.searchParams.set(site.params.limit, String(limit));
try {
const res = await fetch(url.toString(), {
headers: {
Accept: "application/json",
"User-Agent": "LovableGrabber/1.0",
...(site.headers ?? {}),
},
});
if (!res.ok) {
return { posts: [], error: `${site.name} returned ${res.status}` };
}
const json = await res.json();
const arr = getByPath(json, site.postsPath);
if (!Array.isArray(arr)) {
return { posts: [], error: `Response at "${site.postsPath}" is not an array` };
}
const posts = arr
.map((raw) => normalizePost(raw, site.fields))
.filter((p): p is NormalizedPost => p !== null);
return { posts };
} catch (err) {
return { posts: [], error: err instanceof Error ? err.message : "Request failed" };
}
});