diff --git a/apps/sanity/sanity.config.ts b/apps/sanity/sanity.config.ts
index 1b712b1d5..56ec16fe9 100644
--- a/apps/sanity/sanity.config.ts
+++ b/apps/sanity/sanity.config.ts
@@ -63,11 +63,11 @@ const apiVersion = process.env.SANITY_STUDIO_API_VERSION || "2025-09-30";
const presentationEnabled =
process.env.SANITY_STUDIO_DISABLE_PRESENTATION !== "true";
-// Use local Next.js dev server for presentation preview when running Studio locally
+// Use local Astro dev server for presentation preview when running Studio locally
const isLocal =
typeof import.meta !== "undefined" &&
(import.meta as unknown as { env?: { DEV?: boolean } }).env?.DEV;
-const localPreviewOrigin = "http://localhost:3000";
+const localPreviewOrigin = "http://localhost:4321";
// ── Shared helpers ───────────────────────────────────────────────────
function resolveHref(type: string, slug?: string): string | undefined {
@@ -242,6 +242,10 @@ function buildPlugins(previewUrl: string): PluginOptions[] {
route: "/post/:slug",
filter: `_type == "post" && slug.current == $slug`,
},
+ {
+ route: "/podcast/:slug",
+ filter: `_type == "podcast" && slug.current == $slug`,
+ },
]),
locations: {
settings: defineLocations({
diff --git a/apps/site/src/components/DraftModeToggle.astro b/apps/site/src/components/DraftModeToggle.astro
index 999e8eae5..17bf0a03d 100644
--- a/apps/site/src/components/DraftModeToggle.astro
+++ b/apps/site/src/components/DraftModeToggle.astro
@@ -20,3 +20,17 @@ const returnTo = Astro.url.pathname + Astro.url.search;
Exit draft mode
+
+
diff --git a/apps/site/src/lib/sanity/config.ts b/apps/site/src/lib/sanity/config.ts
index 813cb87c9..5b2a02e03 100644
--- a/apps/site/src/lib/sanity/config.ts
+++ b/apps/site/src/lib/sanity/config.ts
@@ -28,7 +28,7 @@ const DEFAULTS = {
projectId: "hfh83o0w",
dataset: "production",
apiVersion: "2025-09-30",
- studioUrl: "https://codingcat.dev.sanity.studio/production",
+ studioUrl: "https://codingcat-prod.sanity.studio",
} as const;
function read(env: EnvLike | undefined, key: string): string | undefined {
diff --git a/apps/site/src/middleware.ts b/apps/site/src/middleware.ts
index 6e0ea4414..0f7d25edb 100644
--- a/apps/site/src/middleware.ts
+++ b/apps/site/src/middleware.ts
@@ -90,9 +90,11 @@ export const onRequest = defineMiddleware(async (context, next) => {
"max-age=31536000; includeSubDomains; preload",
);
response.headers.set("X-Content-Type-Options", "nosniff");
- response.headers.set("X-Frame-Options", "SAMEORIGIN");
response.headers.set("Referrer-Policy", "strict-origin-when-cross-origin");
- response.headers.set("Content-Security-Policy", "frame-ancestors 'self'");
+ response.headers.set(
+ "Content-Security-Policy",
+ "frame-ancestors 'self' https://*.sanity.studio http://localhost:3333",
+ );
// AIPREF / AI Preference Headers
response.headers.set("Content-Usage", "train-ai=n, search=y");
diff --git a/apps/site/src/pages/api/draft-mode/disable.ts b/apps/site/src/pages/api/draft-mode/disable.ts
index 360316393..dee57280c 100644
--- a/apps/site/src/pages/api/draft-mode/disable.ts
+++ b/apps/site/src/pages/api/draft-mode/disable.ts
@@ -45,17 +45,33 @@ export const POST: APIRoute = async ({ request, url, cookies, redirect }) => {
returnTo = url.searchParams.get("returnTo");
}
+ const isHttps = url.protocol === "https:";
cookies.delete(PREVIEW_COOKIE, { path: "/" });
- cookies.set(PREVIEW_COOKIE, "", { maxAge: 0, path: "/" });
+ cookies.set(PREVIEW_COOKIE, "", {
+ maxAge: 0,
+ path: "/",
+ httpOnly: true,
+ secure: isHttps,
+ sameSite: isHttps ? "none" : "lax",
+ partitioned: isHttps,
+ });
return redirect(resolveDestination(returnTo), 303);
};
export const GET: APIRoute = async ({ url, cookies, redirect }) => {
const returnTo = url.searchParams.get("returnTo");
+ const isHttps = url.protocol === "https:";
cookies.delete(PREVIEW_COOKIE, { path: "/" });
- cookies.set(PREVIEW_COOKIE, "", { maxAge: 0, path: "/" });
+ cookies.set(PREVIEW_COOKIE, "", {
+ maxAge: 0,
+ path: "/",
+ httpOnly: true,
+ secure: isHttps,
+ sameSite: isHttps ? "none" : "lax",
+ partitioned: isHttps,
+ });
return redirect(resolveDestination(returnTo), 307);
};
diff --git a/apps/site/src/pages/api/draft-mode/enable.ts b/apps/site/src/pages/api/draft-mode/enable.ts
index 2b240725e..805907a8a 100644
--- a/apps/site/src/pages/api/draft-mode/enable.ts
+++ b/apps/site/src/pages/api/draft-mode/enable.ts
@@ -10,10 +10,15 @@ export const GET: APIRoute = async ({ url, cookies, redirect }) => {
(import.meta.env as Record)
?.SANITY_API_READ_TOKEN;
- // Query params supported: secret, slug, returnTo
- const secret = url.searchParams.get("secret");
+ // Query params supported: sanity-preview-secret/secret, sanity-preview-pathname/returnTo, slug, sanity-preview-perspective
+ const secret =
+ url.searchParams.get("sanity-preview-secret") ??
+ url.searchParams.get("secret");
const slug = url.searchParams.get("slug");
- const returnTo = url.searchParams.get("returnTo");
+ const returnTo =
+ url.searchParams.get("sanity-preview-pathname") ??
+ url.searchParams.get("returnTo");
+ const perspective = url.searchParams.get("sanity-preview-perspective");
if (!readToken) {
console.warn(
@@ -35,11 +40,18 @@ export const GET: APIRoute = async ({ url, cookies, redirect }) => {
destination = "/";
}
+ if (perspective && !destination.includes("sanity-preview-perspective=")) {
+ const sep = destination.includes("?") ? "&" : "?";
+ destination = `${destination}${sep}sanity-preview-perspective=${encodeURIComponent(perspective)}`;
+ }
+
+ const isHttps = url.protocol === "https:";
cookies.set(PREVIEW_COOKIE, "true", {
path: "/",
httpOnly: true,
- secure: true,
- sameSite: "lax",
+ secure: isHttps,
+ sameSite: isHttps ? "none" : "lax",
+ partitioned: isHttps,
});
return redirect(destination, 307);
diff --git a/apps/site/tests/tier1-features.test.mjs b/apps/site/tests/tier1-features.test.mjs
index 7c03d9e66..a04b5cd68 100644
--- a/apps/site/tests/tier1-features.test.mjs
+++ b/apps/site/tests/tier1-features.test.mjs
@@ -877,7 +877,8 @@ describe("Tier 1 - Feature Coverage", () => {
assert.equal(setCookieVal, "true");
assert.equal(setCookieOpts.httpOnly, true);
assert.equal(setCookieOpts.secure, true);
- assert.equal(setCookieOpts.sameSite, "lax");
+ assert.equal(setCookieOpts.sameSite, "none");
+ assert.equal(setCookieOpts.partitioned, true);
});
it("6.7 POST and GET /api/draft-mode/disable clears __sanity_preview cookie and redirects", async () => {
diff --git a/apps/site/wrangler.jsonc b/apps/site/wrangler.jsonc
index 573c03a28..1954017ad 100644
--- a/apps/site/wrangler.jsonc
+++ b/apps/site/wrangler.jsonc
@@ -37,7 +37,7 @@
"PUBLIC_SANITY_PROJECT_ID": "hfh83o0w",
"PUBLIC_SANITY_DATASET": "dev",
"PUBLIC_SANITY_API_VERSION": "2025-09-30",
- "PUBLIC_SANITY_STUDIO_URL": "https://codingcat-dev.sanity.studio/dev",
+ "PUBLIC_SANITY_STUDIO_URL": "https://codingcat-dev.sanity.studio",
"SITE_URL": "https://dev.codingcat.dev",
"FLIPCORE_API_URL": "https://api.flipfeeds.dev",
"PUBLIC_FLIPCORE_WEB_URL": "https://flipfeeds.dev"
@@ -76,7 +76,7 @@
"PUBLIC_SANITY_PROJECT_ID": "hfh83o0w",
"PUBLIC_SANITY_DATASET": "production",
"PUBLIC_SANITY_API_VERSION": "2025-09-30",
- "PUBLIC_SANITY_STUDIO_URL": "https://codingcat-dev.sanity.studio/production",
+ "PUBLIC_SANITY_STUDIO_URL": "https://codingcat-prod.sanity.studio",
"SITE_URL": "https://codingcat.dev",
"FLIPCORE_API_URL": "https://api.flipfeeds.com",
"PUBLIC_FLIPCORE_WEB_URL": "https://flipfeeds.com"