Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion src/layouts/global.astro
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,28 @@ interface Props {
title: string;
description: string;

// Show the signup form. Blog posts get it automatically; other pages opt in,
// since it has no business interrupting the demo and player pages.
subscribe?: boolean;

frontmatter?: {
title: string;
date: string;
description: string;
cover?: string;
subscribe?: boolean;
};
}

let { title, frontmatter, description } = Astro.props;
const { subscribe } = Astro.props;
if (frontmatter?.title) title = frontmatter.title;
if (frontmatter?.description) description = frontmatter.description;

// `date` is what makes a page a blog post. An explicit flag, from either a prop
// (.astro pages) or frontmatter (.mdx pages), wins over that default.
const showSubscribe = subscribe ?? frontmatter?.subscribe ?? Boolean(frontmatter?.date);

const siteUrl = Astro.site?.toString().replace(/\/$/, "") ?? "https://moq.dev";
const pageUrl = new URL(Astro.url.pathname, siteUrl).toString();
const fullTitle = title ? `${title} - Media over QUIC` : "Media over QUIC";
Expand Down Expand Up @@ -121,7 +131,7 @@ const proUrl = import.meta.env.MODE === "staging" ? "https://moq.wtf" : "https:/
)
}
<slot />
{frontmatter?.date && <Subscribe />}
{showSubscribe && <Subscribe />}
</article>
</div>
</body>
Expand Down
2 changes: 1 addition & 1 deletion src/pages/blog/index.astro
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ posts.sort((a, b) => {
});
---

<MainLayout title="Blog" description="Blog posts and fun stuff">
<MainLayout title="Blog" description="Blog posts and fun stuff" subscribe>
<section>
<div class="flex items-center justify-between mb-6">
<h1>Blog Posts</h1>
Expand Down
13 changes: 7 additions & 6 deletions worker/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,22 +48,23 @@ async function handleSubscribe(request: Request, env: Env): Promise<Response> {
body: JSON.stringify({
email,
unsubscribed: false,
segments: [env.RESEND_SEGMENT_ID],
// Objects, not bare ids. A string here is a 422 that used to be reported
// to the visitor as success, so every signup was dropped on the floor.
segments: [{ id: env.RESEND_SEGMENT_ID }],
}),
});
} catch (err) {
console.error(`Resend POST /contacts → fetch threw: ${err}`);
return json({ error: "subscribe failed" }, 502);
}

// Treat any non-5xx as success so we don't leak whether an address is
// already on the list (Resend returns 4xx for duplicates). Log 4xx for
// debugging since a misconfigured segment ID would silently break sends.
// Resend upserts contacts: re-subscribing an existing address returns 201 with
// the same contact id, so there is no duplicate to hide and no reason to
// swallow a 4xx. Anything not ok is a real failure (malformed body, unknown
// segment), and calling those success is what silently discarded every signup.
// Only log status + request id, not the body (which may contain the email).
if (!res.ok) {
console.error(`Resend POST /contacts → ${res.status} (request-id: ${res.headers.get("x-request-id") ?? "n/a"})`);
}
if (res.status >= 500) {
return json({ error: "subscribe failed" }, 502);
}

Expand Down
Loading