Skip to content

Commit 8f18668

Browse files
Merge pull request #14 from austinlparker/changeCaching
Revalidate cache when new entries arrive
2 parents 2ae1fe8 + 402640d commit 8f18668

File tree

6 files changed

+130
-2
lines changed

6 files changed

+130
-2
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,5 @@ next-env.d.ts
3737

3838
# Local Netlify folder
3939
.netlify
40+
41+
.env

src/app/api/revalidate/route.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { revalidatePath } from "next/cache";
2+
import { NextRequest } from "next/server";
3+
4+
export async function POST(request: NextRequest) {
5+
const token = request.headers.get("authorization");
6+
7+
if (token !== `Bearer ${process.env.REVALIDATION_TOKEN}`) {
8+
return new Response("Unauthorized", { status: 401 });
9+
}
10+
11+
try {
12+
revalidatePath("/", "page");
13+
revalidatePath("/feed", "page");
14+
15+
return new Response("Revalidated", { status: 200 });
16+
} catch (error: unknown) {
17+
// Log the error and return a 500
18+
console.error("Revalidation error:", error);
19+
return new Response(
20+
`Error revalidating: ${error instanceof Error ? error.message : "Unknown error"}`,
21+
{ status: 500 },
22+
);
23+
}
24+
}

src/app/api/test/route.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { saveEntry } from "@/lib/store";
2+
import { ChangelogEntry } from "@/types/entry";
3+
4+
export async function POST() {
5+
// Only allow in development
6+
if (process.env.NODE_ENV !== "development") {
7+
return new Response("Test endpoint only available in development", {
8+
status: 403,
9+
});
10+
}
11+
12+
const testEntry: ChangelogEntry = {
13+
id: Date.now(), // Use timestamp as ID for test entries
14+
title: `Test Entry ${new Date().toISOString()}`,
15+
description: "This is a test entry to verify cache revalidation",
16+
date: new Date().toISOString(),
17+
metadata: {
18+
sourceRepo: "open-telemetry/test-repo",
19+
state: "opened",
20+
url: "https://github.com/open-telemetry/test-repo/pull/123",
21+
author: "test-user",
22+
},
23+
};
24+
25+
try {
26+
await saveEntry(testEntry);
27+
return new Response("Test entry added", { status: 200 });
28+
} catch (error) {
29+
console.error("Error adding test entry:", error);
30+
return new Response("Error adding test entry", { status: 500 });
31+
}
32+
}

src/app/page.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { getAllEntries } from "@/lib/store";
22
import { ChangelogList } from "@/components/list";
3+
import { TestControls } from "@/components/test-controls";
34
import { RiRssFill, RiGithubFill, RiExternalLinkLine } from "react-icons/ri";
45

56
export const revalidate = 60;
@@ -48,6 +49,8 @@ export default async function Home() {
4849
</div>
4950
</header>
5051

52+
{process.env.NODE_ENV === "development" && <TestControls />}
53+
5154
<main
5255
id="main-content"
5356
role="main"

src/components/test-controls.tsx

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
"use client";
2+
3+
import { useState } from "react";
4+
5+
export function TestControls() {
6+
const [status, setStatus] = useState<string>("");
7+
8+
const addTestEntry = async () => {
9+
try {
10+
setStatus("Adding test entry...");
11+
const response = await fetch("/api/test", {
12+
method: "POST",
13+
});
14+
15+
if (!response.ok) {
16+
throw new Error(`HTTP error! status: ${response.status}`);
17+
}
18+
19+
setStatus("Test entry added! Check if the page updates.");
20+
21+
// Clear status after 3 seconds
22+
setTimeout(() => setStatus(""), 3000);
23+
} catch (error) {
24+
setStatus(
25+
`Error: ${error instanceof Error ? error.message : String(error)}`,
26+
);
27+
}
28+
};
29+
30+
return (
31+
<div className="fixed bottom-4 right-4 p-4 bg-white dark:bg-gray-800 rounded-lg shadow-lg border border-gray-200 dark:border-gray-700">
32+
<button
33+
onClick={addTestEntry}
34+
className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"
35+
>
36+
Add Test Entry
37+
</button>
38+
{status && (
39+
<p className="mt-2 text-sm text-gray-600 dark:text-gray-300">
40+
{status}
41+
</p>
42+
)}
43+
</div>
44+
);
45+
}

src/lib/store.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,18 +135,41 @@ const MOCK_ENTRIES: ChangelogEntry[] = [
135135
},
136136
];
137137

138+
// In-memory store for development
139+
const devStore: ChangelogEntry[] = [];
140+
138141
export async function saveEntry(entry: ChangelogEntry) {
142+
if (process.env.NODE_ENV === "development") {
143+
console.log("Development mode: saving to in-memory store");
144+
// Add to start of array to match the sorting in getAllEntries
145+
devStore.unshift(entry);
146+
return;
147+
}
148+
139149
try {
140150
const store = getStore("changelog-store");
141151
await store.setJSON(entry.id.toString(), entry);
152+
153+
// Trigger revalidation
154+
const baseUrl = process.env.NEXT_PUBLIC_BASE_URL || "http://localhost:3000";
155+
await fetch(`${baseUrl}/api/revalidate`, {
156+
method: "POST",
157+
headers: {
158+
Authorization: `Bearer ${process.env.REVALIDATION_TOKEN}`,
159+
},
160+
});
142161
} catch (error) {
143162
console.warn("Failed to save entry:", error);
144-
// In development/build, just log the entry
145163
console.log("Would have saved:", entry);
146164
}
147165
}
148166

149167
export async function getAllEntries(): Promise<ChangelogEntry[]> {
168+
if (process.env.NODE_ENV === "development") {
169+
console.log("Development mode: reading from in-memory store");
170+
return devStore.length > 0 ? devStore : MOCK_ENTRIES;
171+
}
172+
150173
try {
151174
const store = getStore("changelog-store");
152175
const list = await store.list();
@@ -164,7 +187,6 @@ export async function getAllEntries(): Promise<ChangelogEntry[]> {
164187
);
165188
} catch (error) {
166189
console.warn("Failed to get entries:", error);
167-
// Return mock data in development/build
168190
return MOCK_ENTRIES;
169191
}
170192
}

0 commit comments

Comments
 (0)