From 0d362276bfc0257cd7150a97278405635248590c Mon Sep 17 00:00:00 2001 From: Cody Olsen Date: Mon, 21 Oct 2024 15:31:51 +0200 Subject: [PATCH] feat(validatePreviewUrl): add studioPreviewPerspective --- .../preview-url-secret/src/parsePreviewUrl.test.ts | 11 ++++++++++- packages/preview-url-secret/src/parsePreviewUrl.ts | 9 +++++++-- packages/preview-url-secret/src/types.ts | 7 +++++++ packages/preview-url-secret/src/validatePreviewUrl.ts | 3 ++- 4 files changed, 26 insertions(+), 4 deletions(-) diff --git a/packages/preview-url-secret/src/parsePreviewUrl.test.ts b/packages/preview-url-secret/src/parsePreviewUrl.test.ts index 03f95ee2e..5e9404b19 100644 --- a/packages/preview-url-secret/src/parsePreviewUrl.test.ts +++ b/packages/preview-url-secret/src/parsePreviewUrl.test.ts @@ -1,5 +1,9 @@ import {expect, test} from 'vitest' -import {urlSearchParamPreviewPathname, urlSearchParamPreviewSecret} from './constants' +import { + urlSearchParamPreviewPathname, + urlSearchParamPreviewPerspective, + urlSearchParamPreviewSecret, +} from './constants' import {parsePreviewUrl} from './parsePreviewUrl' test('handles absolute URLs', () => { @@ -9,6 +13,7 @@ test('handles absolute URLs', () => { expect(parsePreviewUrl(unsafe.toString())).toEqual({ redirectTo: '/preview?foo=bar', secret: 'abc123', + studioPreviewPerspective: null, }) }) @@ -16,9 +21,11 @@ test('handles relative URLs', () => { const unsafe = new URL('/api/draft', 'http://localhost') unsafe.searchParams.set(urlSearchParamPreviewSecret, 'abc123') unsafe.searchParams.set(urlSearchParamPreviewPathname, '/preview?foo=bar') + unsafe.searchParams.set(urlSearchParamPreviewPerspective, 'published') expect(parsePreviewUrl(`${unsafe.pathname}${unsafe.search}`)).toEqual({ redirectTo: '/preview?foo=bar', secret: 'abc123', + studioPreviewPerspective: 'published', }) }) @@ -29,6 +36,7 @@ test('includes hash', () => { expect(parsePreviewUrl(unsafe.toString())).toEqual({ redirectTo: '/preview?foo=bar#heading1', secret: 'abc123', + studioPreviewPerspective: null, }) }) @@ -42,5 +50,6 @@ test('strips origin from redirect', () => { expect(parsePreviewUrl(unsafe.toString())).toEqual({ redirectTo: '/preview?foo=bar', secret: 'abc123', + studioPreviewPerspective: null, }) }) diff --git a/packages/preview-url-secret/src/parsePreviewUrl.ts b/packages/preview-url-secret/src/parsePreviewUrl.ts index 230d06d2c..ea257644d 100644 --- a/packages/preview-url-secret/src/parsePreviewUrl.ts +++ b/packages/preview-url-secret/src/parsePreviewUrl.ts @@ -1,4 +1,8 @@ -import {urlSearchParamPreviewPathname, urlSearchParamPreviewSecret} from './constants' +import { + urlSearchParamPreviewPathname, + urlSearchParamPreviewPerspective, + urlSearchParamPreviewSecret, +} from './constants' import type {ParsedPreviewUrl} from './types' /** @@ -10,11 +14,12 @@ export function parsePreviewUrl(unsafeUrl: string): ParsedPreviewUrl { if (!secret) { throw new Error('Missing secret') } + const studioPreviewPerspective = url.searchParams.get(urlSearchParamPreviewPerspective) let redirectTo = undefined const unsafeRedirectTo = url.searchParams.get(urlSearchParamPreviewPathname) if (unsafeRedirectTo) { const {pathname, search, hash} = new URL(unsafeRedirectTo, 'http://localhost') redirectTo = `${pathname}${search}${hash}` } - return {secret, redirectTo} + return {secret, redirectTo, studioPreviewPerspective} } diff --git a/packages/preview-url-secret/src/types.ts b/packages/preview-url-secret/src/types.ts index 987edc1d6..cb344fa5f 100644 --- a/packages/preview-url-secret/src/types.ts +++ b/packages/preview-url-secret/src/types.ts @@ -49,12 +49,19 @@ export interface PreviewUrlValidateUrlResult { * If the URL is valid, and the studio URL is known and valid, then its origin will be here */ studioOrigin?: string + /** + * The initial perspective the Studio was using when starting to load the preview. + * It can change over time and should also be handled with `postMessage` listeners. + * The value can be arbitrary and has to be validated to make sure it's a valid perspective. + */ + studioPreviewPerspective?: string | null } /** @internal */ export interface ParsedPreviewUrl { secret: string redirectTo?: string + studioPreviewPerspective: string | null } /** @public */ diff --git a/packages/preview-url-secret/src/validatePreviewUrl.ts b/packages/preview-url-secret/src/validatePreviewUrl.ts index 0a7aaca68..39d69601d 100644 --- a/packages/preview-url-secret/src/validatePreviewUrl.ts +++ b/packages/preview-url-secret/src/validatePreviewUrl.ts @@ -37,6 +37,7 @@ export async function validatePreviewUrl( disableCacheNoStore, ) const redirectTo = isValid ? parsedPreviewUrl.redirectTo : undefined + const studioPreviewPerspective = isValid ? parsedPreviewUrl.studioPreviewPerspective : undefined let studioOrigin: string | undefined if (isValid) { try { @@ -52,7 +53,7 @@ export async function validatePreviewUrl( } } - return {isValid, redirectTo, studioOrigin} + return {isValid, redirectTo, studioOrigin, studioPreviewPerspective} } export type {PreviewUrlValidateUrlResult, SanityClientLike}