Files
Wayne Sutton 87e02d00dc feat: add featured section, logo gallery, Firecrawl import, and API export
Featured Section
- Frontmatter-controlled featured items with featured: true and featuredOrder
- Card view with excerpts and list/card toggle button
- View preference saved to localStorage
- New Convex queries for featured posts and pages with by_featured index

Logo Gallery
- Continuous marquee scroll with clickable logos
- CSS animation, grayscale with color on hover
- Configurable speed, position, and title
- 5 sample logos included

Firecrawl Content Importer
- npm run import <url> scrapes external URLs to markdown drafts
- Creates local files in content/blog/ with frontmatter
- Then sync to dev or prod (no separate import:prod command)

API Enhancements
- New /api/export endpoint for batch content fetching
- AI plugin discovery at /.well-known/ai-plugin.json
- OpenAPI 3.0 spec at /openapi.yaml
- Enhanced llms.txt documentation

Documentation
- AGENTS.md with codebase instructions for AI agents
- Updated all sync vs deploy tables to include import workflow
- Renamed content/pages/changelog.md to changelog-page.md

Technical
- New components: FeaturedCards.tsx, LogoMarquee.tsx
- New script: scripts/import-url.ts
- New dependency: @mendable/firecrawl-js
- Schema updates with featured, featuredOrder, excerpt fields
2025-12-18 12:28:25 -08:00

62 lines
1.7 KiB
TypeScript

import type { Context } from "@netlify/edge-functions";
// Edge function to proxy API endpoints to Convex HTTP
export default async function handler(
request: Request,
_context: Context,
): Promise<Response> {
const convexUrl =
Deno.env.get("VITE_CONVEX_URL") || Deno.env.get("CONVEX_URL");
if (!convexUrl) {
return new Response(
JSON.stringify({
error:
"VITE_CONVEX_URL not set. Add it to Netlify environment variables.",
}),
{ status: 500, headers: { "Content-Type": "application/json" } },
);
}
// Construct the Convex site URL for the HTTP endpoint
const convexSiteUrl = convexUrl.replace(".cloud", ".site");
const url = new URL(request.url);
const targetUrl = `${convexSiteUrl}${url.pathname}${url.search}`;
try {
const response = await fetch(targetUrl, {
headers: {
Accept: "application/json",
},
});
if (!response.ok) {
return new Response(JSON.stringify({ error: "API endpoint error" }), {
status: response.status,
headers: { "Content-Type": "application/json" },
});
}
const data = await response.text();
const contentType =
response.headers.get("Content-Type") || "application/json";
return new Response(data, {
headers: {
"Content-Type": contentType,
"Cache-Control": "public, max-age=300, s-maxage=600",
"Access-Control-Allow-Origin": "*",
},
});
} catch {
return new Response(JSON.stringify({ error: "Failed to fetch from API" }), {
status: 502,
headers: { "Content-Type": "application/json" },
});
}
}
export const config = {
path: ["/api/posts", "/api/post", "/api/export"],
};