Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: release @sanity/next-loader #1996

Merged
merged 5 commits into from
Oct 21, 2024
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
2 changes: 1 addition & 1 deletion packages/@repo/env/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export const datasets = {
'blog': 'blog',
} as const

export const apiVersion = 'X' as const
export const apiVersion = '2024-10-21' as const

export const workspaces = {
'astro': {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,6 @@ function PresentationComlink(props: {
setPerspectiveCookie(perspective)
.then(() => {
if (signal.aborted) return
// eslint-disable-next-line no-console
console.log('refresh on perspective change', perspective)
router.refresh()
})
// eslint-disable-next-line no-console
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ export default function RefreshOnFocus(): null {
const callback = () => {
const now = Date.now()
if (now > nextFocusRevalidatedAt && document.visibilityState !== 'hidden') {
// eslint-disable-next-line no-console
console.log('refreshing on focus')
router.refresh()
nextFocusRevalidatedAt = now + focusThrottleInterval
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ export default function RefreshOnMount(): null {
useEffect(() => {
if (!mounted) {
mount()
// eslint-disable-next-line no-console
console.log('refreshing on mount')
router.refresh()
}
}, [mounted, router])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,7 @@ export default function RefreshOnReconnect(): null {
useEffect(() => {
const controller = new AbortController()
const {signal} = controller
window.addEventListener(
'online',
() => {
// eslint-disable-next-line no-console
console.log('refreshing on reconnect')
router.refresh()
},
{passive: true, signal},
)
window.addEventListener('online', () => router.refresh(), {passive: true, signal})
return () => controller.abort()
}, [router])

Expand Down
44 changes: 30 additions & 14 deletions packages/next-loader/src/client-components/live/SanityLive.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
import {createClient, type ClientPerspective, type InitializedClientConfig} from '@sanity/client'
import {
createClient,
type ClientPerspective,
type InitializedClientConfig,
type LiveEventMessage,
type LiveEventRestart,
} from '@sanity/client'
import {revalidateSyncTags} from '@sanity/next-loader/server-actions'
import dynamic from 'next/dynamic'
import {useRouter} from 'next/navigation.js'
import {useEffect, useMemo, useRef, useState} from 'react'
import {useEffectEvent} from 'use-effect-event'
import {setEnvironment, setPerspective} from '../../hooks/context'

const PresentationComlink = dynamic(() => import('./PresentationComlink'), {ssr: false})
Expand Down Expand Up @@ -103,6 +111,9 @@ export function SanityLive(props: SanityLiveProps): React.JSX.Element | null {
],
)

/**
* 2. Validate CORS before setting up the Event Source for the Server Sent Events
*/
useEffect(() => {
// @TODO move this validation logic to `@sanity/client`
// and include CORS detection https://github.com/sanity-io/sanity/blob/9848f2069405e5d06f82a61a902f141e53099493/packages/sanity/src/core/store/_legacy/authStore/createAuthStore.ts#L92-L102
Expand Down Expand Up @@ -168,26 +179,31 @@ export function SanityLive(props: SanityLiveProps): React.JSX.Element | null {
return () => controller.abort()
}, [tag, client, requestTagPrefix, token])

/**
* 3. Handle Live Events and call revalidateTag or router.refresh when needed
*/
const router = useRouter()
const handleLiveEvent = useEffectEvent((event: LiveEventMessage | LiveEventRestart) => {
if (event.type === 'message') {
revalidateSyncTags(event.tags)
} else if (event.type === 'restart') {
router.refresh()
}
})
useEffect(() => {
const subscription = client.live.events({includeDrafts: !!token, tag}).subscribe({
next: (event) => {
if (event.type === 'message') {
revalidateSyncTags(event.tags)
} else if (event.type === 'reconnect') {
// eslint-disable-next-line no-console
console.log('TODO: handle reconnect')
} else if (event.type === 'restart') {
// eslint-disable-next-line no-console
console.log('TODO: handle restart')
if (event.type === 'message' || event.type === 'restart') {
handleLiveEvent(event)
}
},
error: setError,
})
return () => subscription.unsubscribe()
}, [client, tag, token])
}, [client.live, handleLiveEvent, tag, token])

/**
* 2. Notify what perspective we're in, when in Draft Mode
* 4. Notify what perspective we're in, when in Draft Mode
*/
useEffect(() => {
if (draftModeEnabled && draftModePerspective) {
Expand All @@ -199,7 +215,7 @@ export function SanityLive(props: SanityLiveProps): React.JSX.Element | null {

const [loadComlink, setLoadComlink] = useState(false)
/**
* 3. Notify what environment we're in, when in Draft Mode
* 5. Notify what environment we're in, when in Draft Mode
*/
useEffect(() => {
if (draftModeEnabled && loadComlink) {
Expand All @@ -212,7 +228,7 @@ export function SanityLive(props: SanityLiveProps): React.JSX.Element | null {
}, [draftModeEnabled, loadComlink, token])

/**
* 4. If Presentation Tool is detected, load up the comlink and integrate with it
* 6. If Presentation Tool is detected, load up the comlink and integrate with it
*/
useEffect(() => {
if (window === parent && !opener) return
Expand All @@ -238,7 +254,7 @@ export function SanityLive(props: SanityLiveProps): React.JSX.Element | null {
}, [])

/**
* 5. Warn if draft mode is being disabled
* 7. Warn if draft mode is being disabled
* @TODO move logic into PresentationComlink, or maybe VisualEditing?
*/
const draftModeEnabledWarnRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined)
Expand Down
42 changes: 31 additions & 11 deletions packages/next-loader/src/defineLive.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,19 @@ export interface DefineSanityLiveOptions {
* @public
*/
export function defineLive(config: DefineSanityLiveOptions): {
/**
* Use this function to fetch data from Sanity in your React Server Components.
* @public
*/
sanityFetch: DefinedSanityFetchType
/**
* Render this in your root layout.tsx to make your page revalidate on new content live, automatically.
* @public
*/
SanityLive: React.ComponentType<DefinedSanityLiveProps>
/**
* @alpha experimental, it may change or even be removed at any time
*/
SanityLiveStream: DefinedSanityLiveStreamType
// verifyPreviewSecret: VerifyPreviewSecretType
} {
Expand All @@ -137,14 +148,14 @@ export function defineLive(config: DefineSanityLiveOptions): {
throw new Error('`client` is required for `defineLive` to function')
}

if (!serverToken) {
if (process.env.NODE_ENV !== 'production' && !serverToken) {
// eslint-disable-next-line no-console
console.warn(
'No `serverToken` provided to `defineLive`. This means that only published content will be fetched and respond to live events',
)
}

if (!browserToken) {
if (process.env.NODE_ENV !== 'production' && !browserToken) {
// eslint-disable-next-line no-console
console.warn(
'No `browserToken` provided to `defineLive`. This means that live previewing drafts will only work when using the Presentation Tool in your Sanity Studio. To support live previewing drafts stand-alone, provide a `browserToken`. It is shared with the browser so it should only have Viewer rights or lower',
Expand Down Expand Up @@ -237,8 +248,21 @@ export function defineLive(config: DefineSanityLiveOptions): {
refreshOnReconnect,
tag = 'next-loader.live',
} = props
const {projectId, dataset, apiHost, apiVersion, useProjectHostname, requestTagPrefix} =
client.config()
const {
projectId,
dataset,
apiHost,
apiVersion: _apiVersion,
useProjectHostname,
requestTagPrefix,
} = client.config()
const {isEnabled: isDraftModeEnabled} = await draftMode()

let apiVersion = _apiVersion
// @TODO temporarily handle the Live Draft Content API only being available on vX
if (typeof browserToken === 'string' && isDraftModeEnabled) {
apiVersion = 'vX'
}

return (
<SanityLiveClientComponent
Expand All @@ -249,16 +273,12 @@ export function defineLive(config: DefineSanityLiveOptions): {
useProjectHostname={useProjectHostname}
requestTagPrefix={requestTagPrefix}
tag={tag}
token={
typeof browserToken === 'string' && (await draftMode()).isEnabled
? browserToken
: undefined
}
token={typeof browserToken === 'string' && isDraftModeEnabled ? browserToken : undefined}
ignoreBrowserTokenWarning={ignoreBrowserTokenWarning}
draftModeEnabled={(await draftMode()).isEnabled}
draftModeEnabled={isDraftModeEnabled}
// handleDraftModeAction={handleDraftModeAction}
draftModePerspective={
(await draftMode()).isEnabled
isDraftModeEnabled
? (await cookies()).has(perspectiveCookieName)
? sanitizePerspective(
(await cookies()).get(perspectiveCookieName)?.value,
Expand Down
18 changes: 9 additions & 9 deletions packages/next-loader/src/server-actions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,21 @@ import {revalidateTag} from 'next/cache.js'
import {cookies, draftMode} from 'next/headers.js'
import {sanitizePerspective} from '../utils'

export async function disableDraftMode(): Promise<void> {
'use server'
await Promise.allSettled([
(await draftMode()).disable(),
// Simulate a delay to show the loading state
new Promise((resolve) => setTimeout(resolve, 1000)),
])
}
// export async function disableDraftMode(): Promise<void> {
// 'use server'
// await Promise.allSettled([
// (await draftMode()).disable(),
// // Simulate a delay to show the loading state
// new Promise((resolve) => setTimeout(resolve, 1000)),
// ])
// }

export async function revalidateSyncTags(tags: SyncTag[]): Promise<void> {
for (const _tag of tags) {
const tag = `sanity:${_tag}`
await revalidateTag(tag)
// eslint-disable-next-line no-console
console.log(`Revalidated tag: ${tag}`)
console.log(`<SanityLive /> revalidated tag: ${tag}`)
}
}

Expand Down