-
Notifications
You must be signed in to change notification settings - Fork 1
Reposition homepage around music-layer-for-agents #17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
fb7c5cd
f6b1a61
270f686
02d1639
fda114a
4ca1527
c955286
f32c06c
baea003
7f32c12
135ead1
9e66c1f
f4ef972
f13d229
e729fee
7be77c3
536cfe1
dd1c773
8cb1e35
3c224d4
de93359
c8a5024
2fc7b8d
557afa6
c9839c8
7784196
a6cd37e
88e6e2c
811220f
1ec511f
10cd783
d8fd94b
48de7cc
b103e37
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,56 @@ | ||||||||||||||||||||||||||||||
| import { CUSTOMER_LOGOS } from "@/lib/customerLogos"; | ||||||||||||||||||||||||||||||
| import { readFile } from "node:fs/promises"; | ||||||||||||||||||||||||||||||
| import path from "node:path"; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| export const runtime = "nodejs"; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| export async function GET( | ||||||||||||||||||||||||||||||
| _request: Request, | ||||||||||||||||||||||||||||||
| { params }: { params: Promise<{ slug: string }> }, | ||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||
| const { slug } = await params; | ||||||||||||||||||||||||||||||
| const logo = CUSTOMER_LOGOS.find((entry) => entry.slug === slug); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if (!logo) { | ||||||||||||||||||||||||||||||
| return new Response("Not found", { status: 404 }); | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| const logoPath = path.join( | ||||||||||||||||||||||||||||||
| process.cwd(), | ||||||||||||||||||||||||||||||
| "design", | ||||||||||||||||||||||||||||||
| "logos", | ||||||||||||||||||||||||||||||
| "customers", | ||||||||||||||||||||||||||||||
| logo.fileName, | ||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||
| const svg = await readFile(logoPath, "utf8"); | ||||||||||||||||||||||||||||||
| const normalizedSvg = svg.replace(/<svg\b([^>]*)>/, (_match, attrs) => { | ||||||||||||||||||||||||||||||
| let nextAttrs = attrs | ||||||||||||||||||||||||||||||
| .replace(/\swidth="[^"]*"/, "") | ||||||||||||||||||||||||||||||
| .replace(/\sheight="[^"]*"/, ""); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if (logo.viewBoxOverride) { | ||||||||||||||||||||||||||||||
| if (/\sviewBox="[^"]*"/.test(nextAttrs)) { | ||||||||||||||||||||||||||||||
| nextAttrs = nextAttrs.replace( | ||||||||||||||||||||||||||||||
| /\sviewBox="[^"]*"/, | ||||||||||||||||||||||||||||||
| ` viewBox="${logo.viewBoxOverride}"`, | ||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||
| nextAttrs = `${nextAttrs} viewBox="${logo.viewBoxOverride}"`; | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| return `<svg${nextAttrs}>`; | ||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| return new Response(normalizedSvg, { | ||||||||||||||||||||||||||||||
| headers: { | ||||||||||||||||||||||||||||||
| "Content-Type": "image/svg+xml; charset=utf-8", | ||||||||||||||||||||||||||||||
| "Cache-Control": "public, max-age=86400, stale-while-revalidate=604800", | ||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||
| } catch { | ||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: This catch block returns 404 for all errors, but since the slug is already validated against Prompt for AI agents |
||||||||||||||||||||||||||||||
| return new Response("Not found", { status: 404 }); | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
Comment on lines
+53
to
+55
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: cat -n app/api/customer-logos/[slug]/route.tsRepository: recoupable/marketing Length of output: 1924 Distinguish between file-not-found and other filesystem errors in the catch block. The current catch block returns 🔧 Proposed fix- } catch {
- return new Response("Not found", { status: 404 });
+ } catch (error: unknown) {
+ const isNotFound =
+ typeof error === "object" &&
+ error !== null &&
+ "code" in error &&
+ (error as { code?: string }).code === "ENOENT";
+
+ return new Response(isNotFound ? "Not found" : "Internal server error", {
+ status: isNotFound ? 404 : 500,
+ });
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: recoupable/marketing
Length of output: 166
🏁 Script executed:
Repository: recoupable/marketing
Length of output: 1924
🏁 Script executed:
Repository: recoupable/marketing
Length of output: 46
🏁 Script executed:
Repository: recoupable/marketing
Length of output: 3279
🏁 Script executed:
Repository: recoupable/marketing
Length of output: 221
🏁 Script executed:
Repository: recoupable/marketing
Length of output: 46
🏁 Script executed:
Repository: recoupable/marketing
Length of output: 46
🏁 Script executed:
Repository: recoupable/marketing
Length of output: 1543
🏁 Script executed:
Repository: recoupable/marketing
Length of output: 575
🏁 Script executed:
Repository: recoupable/marketing
Length of output: 156
Validate route params with Zod before lookup.
This endpoint accepts
slugfrom route params without validation. Per the coding guidelines ("Use Zod for all validation"), please add a Zod schema and parse params before the lookup.🔧 Proposed fix
import { CUSTOMER_LOGOS } from "`@/lib/customerLogos`"; import { readFile } from "node:fs/promises"; import path from "node:path"; +import { z } from "zod"; + +const paramsSchema = z.object({ + slug: z.string().min(1), +}); export const runtime = "nodejs"; export async function GET( _request: Request, { params }: { params: Promise<{ slug: string }> }, ) { - const { slug } = await params; + const { slug } = paramsSchema.parse(await params);🤖 Prompt for AI Agents