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
8 changes: 6 additions & 2 deletions apps/sanity/sanity.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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({
Expand Down
14 changes: 14 additions & 0 deletions apps/site/src/components/DraftModeToggle.astro
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,17 @@ const returnTo = Astro.url.pathname + Astro.url.search;
Exit draft mode
</button>
</form>

<script>
import { enableVisualEditing } from "@sanity/visual-editing-standalone";

enableVisualEditing({
refresh: (payload) => {
if (payload.source === "mutation" || payload.source === "manual") {
window.location.reload();
return Promise.resolve();
}
return false;
},
});
</script>
2 changes: 1 addition & 1 deletion apps/site/src/lib/sanity/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
6 changes: 4 additions & 2 deletions apps/site/src/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
20 changes: 18 additions & 2 deletions apps/site/src/pages/api/draft-mode/disable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
};
22 changes: 17 additions & 5 deletions apps/site/src/pages/api/draft-mode/enable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,15 @@ export const GET: APIRoute = async ({ url, cookies, redirect }) => {
(import.meta.env as Record<string, string | undefined>)
?.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(
Expand All @@ -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);
Expand Down
3 changes: 2 additions & 1 deletion apps/site/tests/tier1-features.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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 () => {
Expand Down
4 changes: 2 additions & 2 deletions apps/site/wrangler.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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"
Expand Down
Loading