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
29 changes: 23 additions & 6 deletions apps/website/e2e/website.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,29 @@ test('/llms.txt returns plain text', async ({ page }) => {
expect(response?.headers()['content-type']).toContain('text/plain');
});

test('marketing pages do not link to retired whitepaper PDFs', async ({ page }) => {
for (const route of ['/', '/angular', '/render', '/chat', '/pilot-to-prod', '/solutions']) {
test('marketing pages link to downloadable whitepaper PDFs', async ({ page }) => {
const expectedDownloads: Record<string, string> = {
'/': '/whitepaper.pdf',
'/angular': '/whitepapers/angular.pdf',
'/render': '/whitepapers/render.pdf',
'/chat': '/whitepapers/chat.pdf',
};

for (const [route, href] of Object.entries(expectedDownloads)) {
await page.goto(route);
const retiredLinks = await page.locator('a[href$=".pdf"]').evaluateAll(links =>
links.map(link => link.getAttribute('href')).filter(Boolean),
);
expect(retiredLinks, `${route} has retired PDF links`).toEqual([]);
await expect(page.locator(`a[href="${href}"]`).first(), `${route} links ${href}`).toBeVisible();
}
});

test('whitepaper PDFs are served as static downloads', async ({ request }) => {
for (const href of [
'/whitepaper.pdf',
'/whitepapers/angular.pdf',
'/whitepapers/render.pdf',
'/whitepapers/chat.pdf',
]) {
const response = await request.get(href);
expect(response.ok(), `${href} responds successfully`).toBe(true);
expect(response.headers()['content-type'], `${href} content type`).toContain('application/pdf');
}
});
6 changes: 3 additions & 3 deletions apps/website/emails/angular-download.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { wrapEmail, esc } from './email-wrapper';

const DOCS_URL = 'https://cacheplane.ai/docs/agent/api/agent';
const DOWNLOAD_URL = 'https://cacheplane.ai/whitepapers/angular.pdf';

export function angularDownloadHtml(name?: string): string {
return wrapEmail({
body: `
<p style="font-size:20px;font-weight:700;color:#1a1a2e;margin:0 0 8px;line-height:1.3">Your Enterprise Guide to Agent Streaming</p>
<p style="font-size:14px;color:#555770;line-height:1.7;margin:0 0 24px">${name ? `Hi ${esc(name)}, t` : 'T'}he guide is being refreshed to match the current @ngaf/langgraph API. We will send the updated version when it is ready. In the meantime, start with the current agent() reference.</p>
<p style="font-size:14px;color:#555770;line-height:1.7;margin:0 0 24px">${name ? `Hi ${esc(name)}, t` : 'T'}he guide covers six chapters: the last-mile problem, the agent() API, thread persistence, interrupt flows, full LangGraph feature coverage, and deterministic testing.</p>
<div style="text-align:center;margin:0 0 4px">
<a href="${DOCS_URL}" style="display:inline-block;background-color:#004090;color:#fff;padding:12px 32px;border-radius:8px;font-size:14px;font-weight:700;text-decoration:none">Read the agent() Docs</a>
<a href="${DOWNLOAD_URL}" style="display:inline-block;background-color:#004090;color:#fff;padding:12px 32px;border-radius:8px;font-size:14px;font-weight:700;text-decoration:none">Download the Guide</a>
</div>
`,
});
Expand Down
6 changes: 3 additions & 3 deletions apps/website/emails/chat-download.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { wrapEmail, esc } from './email-wrapper';

const DOCS_URL = 'https://cacheplane.ai/docs/chat/components/chat';
const DOWNLOAD_URL = 'https://cacheplane.ai/whitepapers/chat.pdf';

export function chatDownloadHtml(name?: string): string {
return wrapEmail({
body: `
<p style="font-size:20px;font-weight:700;color:#1a1a2e;margin:0 0 8px;line-height:1.3">Your Enterprise Guide to Agent Chat Interfaces</p>
<p style="font-size:14px;color:#555770;line-height:1.7;margin:0 0 24px">${name ? `Hi ${esc(name)}, t` : 'T'}he guide is being refreshed to match the current @ngaf/chat API. We will send the updated version when it is ready. In the meantime, the current chat component docs are live.</p>
<p style="font-size:14px;color:#555770;line-height:1.7;margin:0 0 24px">${name ? `Hi ${esc(name)}, t` : 'T'}he guide covers five chapters: the sprint tax, batteries-included components, theming and design system integration, generative UI in chat, and debug tooling.</p>
<div style="text-align:center;margin:0 0 4px">
<a href="${DOCS_URL}" style="display:inline-block;background-color:#5a00c8;color:#fff;padding:12px 32px;border-radius:8px;font-size:14px;font-weight:700;text-decoration:none">Read the Chat Docs</a>
<a href="${DOWNLOAD_URL}" style="display:inline-block;background-color:#5a00c8;color:#fff;padding:12px 32px;border-radius:8px;font-size:14px;font-weight:700;text-decoration:none">Download the Guide</a>
</div>
`,
});
Expand Down
4 changes: 2 additions & 2 deletions apps/website/emails/drip-whitepaper-followup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export function dripWhitepaperFollowupHtml(day: number): { subject: string; html
<p style="font-size:11px;font-family:monospace;text-transform:uppercase;letter-spacing:0.08em;color:#004090;font-weight:700;margin:0 0 8px">Whitepaper Follow-up</p>
<p style="font-size:20px;font-weight:700;color:#1a1a2e;margin:0 0 14px;line-height:1.3">Did you get a chance to read Chapter 3?</p>
<p style="font-size:14px;color:#555770;line-height:1.7;margin:0 0 24px">Chapter 3 covers <strong>tool-call rendering</strong> — how to surface agent actions as real UI instead of raw JSON. It's the chapter most teams bookmark first.</p>
<a href="https://cacheplane.ai/docs" style="display:inline-block;background-color:#004090;color:#fff;padding:12px 28px;border-radius:8px;font-size:14px;font-weight:700;text-decoration:none">Read the Current Docs →</a>
<a href="https://cacheplane.ai/whitepaper.pdf" style="display:inline-block;background-color:#004090;color:#fff;padding:12px 28px;border-radius:8px;font-size:14px;font-weight:700;text-decoration:none">Read the Guide →</a>
`,
showUnsubscribe: true,
}),
Expand Down Expand Up @@ -58,7 +58,7 @@ export function dripWhitepaperFollowupHtml(day: number): { subject: string; html
body: `
<p style="font-size:11px;font-family:monospace;text-transform:uppercase;letter-spacing:0.08em;color:#004090;font-weight:700;margin:0 0 8px">Let's Connect</p>
<p style="font-size:20px;font-weight:700;color:#1a1a2e;margin:0 0 14px;line-height:1.3">Ready to ship your agent? Let's talk.</p>
<p style="font-size:14px;color:#555770;line-height:1.7;margin:0 0 24px">If your team is evaluating how to take an Angular + LangGraph agent to production, I'd love to hear what you're building. Reply to this email or <a href="mailto:hello@cacheplane.io" style="color:#004090;text-decoration:underline">schedule a conversation</a> — no pitch, just a technical discussion about your use case.</p>
<p style="font-size:14px;color:#555770;line-height:1.7;margin:0 0 24px">If your team is evaluating how to take an Angular + LangGraph agent to production, I'd love to hear what you're building. Reply to this email or <a href="mailto:hello@cacheplane.ai" style="color:#004090;text-decoration:underline">schedule a conversation</a> — no pitch, just a technical discussion about your use case.</p>
`,
showUnsubscribe: true,
}),
Expand Down
6 changes: 3 additions & 3 deletions apps/website/emails/render-download.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { wrapEmail, esc } from './email-wrapper';

const DOCS_URL = 'https://cacheplane.ai/docs/render/getting-started/introduction';
const DOWNLOAD_URL = 'https://cacheplane.ai/whitepapers/render.pdf';

export function renderDownloadHtml(name?: string): string {
return wrapEmail({
body: `
<p style="font-size:20px;font-weight:700;color:#1a1a2e;margin:0 0 8px;line-height:1.3">Your Enterprise Guide to Generative UI</p>
<p style="font-size:14px;color:#555770;line-height:1.7;margin:0 0 24px">${name ? `Hi ${esc(name)}, t` : 'T'}he guide is being refreshed to match the current @ngaf/render API. We will send the updated version when it is ready. In the meantime, the current render docs are live.</p>
<p style="font-size:14px;color:#555770;line-height:1.7;margin:0 0 24px">${name ? `Hi ${esc(name)}, t` : 'T'}he guide covers five chapters: the coupling problem, declarative UI specs with Vercel's json-render standard, the component registry, streaming JSON patches, and state management.</p>
<div style="text-align:center;margin:0 0 4px">
<a href="${DOCS_URL}" style="display:inline-block;background-color:#1a7a40;color:#fff;padding:12px 32px;border-radius:8px;font-size:14px;font-weight:700;text-decoration:none">Read the Render Docs</a>
<a href="${DOWNLOAD_URL}" style="display:inline-block;background-color:#1a7a40;color:#fff;padding:12px 32px;border-radius:8px;font-size:14px;font-weight:700;text-decoration:none">Download the Guide</a>
</div>
`,
});
Expand Down
6 changes: 3 additions & 3 deletions apps/website/emails/whitepaper-download.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { wrapEmail, esc } from './email-wrapper';

const DOCS_URL = 'https://cacheplane.ai/docs';
const DOWNLOAD_URL = 'https://cacheplane.ai/whitepaper.pdf';

export function whitepaperDownloadHtml(name?: string): string {
return wrapEmail({
body: `
<p style="font-size:20px;font-weight:700;color:#1a1a2e;margin:0 0 8px;line-height:1.3">Your Angular Agent Readiness Guide</p>
<p style="font-size:14px;color:#555770;line-height:1.7;margin:0 0 24px">${name ? `Hi ${esc(name)}, t` : 'T'}he guide is being refreshed to match the current Angular Agent Framework API. We will send the updated version when it is ready. In the meantime, the docs cover the current agent(), chat, render, and AG-UI surfaces.</p>
<p style="font-size:14px;color:#555770;line-height:1.7;margin:0 0 24px">${name ? `Hi ${esc(name)}, t` : 'T'}he guide covers six production-readiness dimensions: streaming state, thread persistence, tool-call rendering, human approval flows, generative UI, and deterministic testing.</p>
<div style="text-align:center;margin:0 0 4px">
<a href="${DOCS_URL}" style="display:inline-block;background-color:#004090;color:#fff;padding:12px 32px;border-radius:8px;font-size:14px;font-weight:700;text-decoration:none">Read the Current Docs</a>
<a href="${DOWNLOAD_URL}" style="display:inline-block;background-color:#004090;color:#fff;padding:12px 32px;border-radius:8px;font-size:14px;font-weight:700;text-decoration:none">Download the Guide</a>
</div>
`,
});
Expand Down
Loading
Loading