sanity 3.83.1-canary.23 → 3.84.1-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/_chunks-cjs/PostMessageSchema.js.map +1 -1
- package/lib/_chunks-cjs/PostMessageTelemetry.js +1 -1
- package/lib/_chunks-cjs/PostMessageTelemetry.js.map +1 -1
- package/lib/_chunks-cjs/PresentationToolGrantsCheck.js +429 -1417
- package/lib/_chunks-cjs/PresentationToolGrantsCheck.js.map +1 -1
- package/lib/_chunks-cjs/presentation.js +70 -22
- package/lib/_chunks-cjs/presentation.js.map +1 -1
- package/lib/_chunks-cjs/resources6.js +0 -8
- package/lib/_chunks-cjs/resources6.js.map +1 -1
- package/lib/_chunks-cjs/version.js +1 -1
- package/lib/_chunks-es/PostMessageSchema.mjs.map +1 -1
- package/lib/_chunks-es/PostMessageTelemetry.mjs +1 -1
- package/lib/_chunks-es/PostMessageTelemetry.mjs.map +1 -1
- package/lib/_chunks-es/PresentationToolGrantsCheck.mjs +437 -1406
- package/lib/_chunks-es/PresentationToolGrantsCheck.mjs.map +1 -1
- package/lib/_chunks-es/presentation.mjs +73 -24
- package/lib/_chunks-es/presentation.mjs.map +1 -1
- package/lib/_chunks-es/resources6.mjs +0 -8
- package/lib/_chunks-es/resources6.mjs.map +1 -1
- package/lib/_chunks-es/version.mjs +1 -1
- package/lib/_singletons.d.mts +61 -2889
- package/lib/_singletons.d.ts +61 -2889
- package/lib/presentation.d.mts +57 -2887
- package/lib/presentation.d.ts +57 -2887
- package/lib/presentation.js +4 -0
- package/lib/presentation.js.map +1 -1
- package/lib/presentation.mjs +5 -1
- package/package.json +15 -16
- package/src/presentation/PostMessageTelemetry.tsx +1 -1
- package/src/presentation/PresentationTool.tsx +76 -85
- package/src/presentation/PresentationToolGrantsCheck.tsx +75 -39
- package/src/presentation/document/LocationsBanner.tsx +13 -52
- package/src/presentation/i18n/resources.ts +0 -10
- package/src/presentation/index.ts +13 -0
- package/src/presentation/{util → lib}/parse.ts +1 -2
- package/src/presentation/overlays/schema/PostMessageSchema.tsx +0 -1
- package/src/presentation/panels/usePanelsStorage.ts +1 -1
- package/src/presentation/preview/IFrame.tsx +35 -83
- package/src/presentation/preview/Preview.tsx +56 -172
- package/src/presentation/preview/PreviewHeader.tsx +10 -43
- package/src/presentation/preview/PreviewLocationInput.tsx +24 -48
- package/src/presentation/preview/SharePreviewMenu.tsx +2 -2
- package/src/presentation/reducers/presentationReducer.ts +134 -0
- package/src/presentation/types.ts +7 -139
- package/src/presentation/useMainDocument.ts +12 -4
- package/src/presentation/useParams.ts +3 -2
- package/src/presentation/usePreviewUrl.ts +133 -0
- package/src/presentation/actors/create-preview-secret.ts +0 -19
- package/src/presentation/actors/read-shared-secret.ts +0 -18
- package/src/presentation/actors/resolve-allow-patterns.ts +0 -55
- package/src/presentation/actors/resolve-initial-url.ts +0 -65
- package/src/presentation/actors/resolve-preview-mode-url.ts +0 -72
- package/src/presentation/actors/resolve-preview-mode.ts +0 -66
- package/src/presentation/actors/resolve-url-from-preview-search-param.ts +0 -29
- package/src/presentation/machines/presentation-machine.ts +0 -101
- package/src/presentation/machines/preview-url.ts +0 -568
- package/src/presentation/useAllowPatterns.ts +0 -12
- package/src/presentation/useId.ts +0 -7
- package/src/presentation/usePresentationPerspective.ts +0 -14
- package/src/presentation/usePreviewUrlActorRef.ts +0 -96
- package/src/presentation/useReportInvalidPreviewSearchParam.tsx +0 -43
- package/src/presentation/useTargetOrigin.ts +0 -11
- /package/src/presentation/{util → lib}/debounce.ts +0 -0
@@ -0,0 +1,133 @@
|
|
1
|
+
import {createPreviewSecret} from '@sanity/preview-url-secret/create-secret'
|
2
|
+
import {definePreviewUrl} from '@sanity/preview-url-secret/define-preview-url'
|
3
|
+
import {startTransition, useEffect, useMemo, useRef, useState} from 'react'
|
4
|
+
import {type SanityClient, useActiveWorkspace, useClient, useCurrentUser} from 'sanity'
|
5
|
+
import {suspend} from 'suspend-react'
|
6
|
+
|
7
|
+
import {API_VERSION} from './constants'
|
8
|
+
import {type PresentationPerspective, type PreviewUrlOption} from './types'
|
9
|
+
import {encodeStudioPerspective} from './util/encodeStudioPerspective'
|
10
|
+
|
11
|
+
export function usePreviewUrl(
|
12
|
+
previewUrl: PreviewUrlOption,
|
13
|
+
toolName: string,
|
14
|
+
studioPreviewPerspective: PresentationPerspective,
|
15
|
+
previewSearchParam: string | null,
|
16
|
+
canCreateUrlPreviewSecrets: boolean,
|
17
|
+
): URL {
|
18
|
+
const client = useClient({apiVersion: API_VERSION})
|
19
|
+
const workspace = useActiveWorkspace()
|
20
|
+
const basePath = workspace?.activeWorkspace?.basePath || '/'
|
21
|
+
const workspaceName = workspace?.activeWorkspace?.name || 'default'
|
22
|
+
const deps = useSuspendCacheKeys(toolName, basePath, workspaceName, previewSearchParam)
|
23
|
+
const previewUrlSecret = usePreviewUrlSecret(
|
24
|
+
(canCreateUrlPreviewSecrets && typeof previewUrl === 'object') ||
|
25
|
+
typeof previewUrl === 'function',
|
26
|
+
deps,
|
27
|
+
)
|
28
|
+
|
29
|
+
return suspend(async () => {
|
30
|
+
if (typeof previewUrl === 'string') {
|
31
|
+
const resolvedUrl = new URL(previewUrl, location.origin)
|
32
|
+
let resultUrl = resolvedUrl
|
33
|
+
try {
|
34
|
+
if (previewSearchParam) {
|
35
|
+
const restoredUrl = new URL(previewSearchParam, resolvedUrl)
|
36
|
+
if (restoredUrl.origin === resolvedUrl.origin) {
|
37
|
+
resultUrl = restoredUrl
|
38
|
+
}
|
39
|
+
}
|
40
|
+
} catch {
|
41
|
+
// ignore
|
42
|
+
}
|
43
|
+
// Prevent infinite recursion
|
44
|
+
if (
|
45
|
+
location.origin === resultUrl.origin &&
|
46
|
+
(resultUrl.pathname.startsWith(`${basePath}/`) || resultUrl.pathname === basePath)
|
47
|
+
) {
|
48
|
+
return resolvedUrl
|
49
|
+
}
|
50
|
+
return resultUrl
|
51
|
+
}
|
52
|
+
const resolvePreviewUrl =
|
53
|
+
typeof previewUrl === 'object' ? definePreviewUrl<SanityClient>(previewUrl) : previewUrl
|
54
|
+
const resolvedUrl = await resolvePreviewUrl({
|
55
|
+
client,
|
56
|
+
previewUrlSecret: previewUrlSecret!,
|
57
|
+
studioPreviewPerspective: encodeStudioPerspective(studioPreviewPerspective),
|
58
|
+
previewSearchParam,
|
59
|
+
studioBasePath: basePath,
|
60
|
+
})
|
61
|
+
return new URL(resolvedUrl, location.origin)
|
62
|
+
}, [...deps, previewUrlSecret]) satisfies URL
|
63
|
+
}
|
64
|
+
|
65
|
+
// https://github.com/pmndrs/suspend-react?tab=readme-ov-file#making-cache-keys-unique
|
66
|
+
const resolveUUID = Symbol('sanity/presentation/resolveUUID')
|
67
|
+
|
68
|
+
function useSuspendCacheKeys(
|
69
|
+
toolName: string,
|
70
|
+
basePath: string,
|
71
|
+
workspaceName: string,
|
72
|
+
previewSearchParam: string | null,
|
73
|
+
) {
|
74
|
+
// Allow busting the cache when the Presentation Tool is reloaded, without causing it to suspend on every render that changes the `preview` parameter
|
75
|
+
const [cachedPreviewSearchParam, setCachedPreviewSearchParam] = useState(
|
76
|
+
() => previewSearchParam || '',
|
77
|
+
)
|
78
|
+
const timeoutRef = useRef(0)
|
79
|
+
useEffect(() => {
|
80
|
+
if (cachedPreviewSearchParam && previewSearchParam) {
|
81
|
+
// Handle resets, like when the Presentation Tool is clicked in the navbar
|
82
|
+
window.clearTimeout(timeoutRef.current)
|
83
|
+
return () => {
|
84
|
+
timeoutRef.current = window.setTimeout(() => {
|
85
|
+
setCachedPreviewSearchParam('')
|
86
|
+
}, 100)
|
87
|
+
}
|
88
|
+
}
|
89
|
+
return undefined
|
90
|
+
}, [cachedPreviewSearchParam, previewSearchParam])
|
91
|
+
|
92
|
+
const currentUser = useCurrentUser()
|
93
|
+
return useMemo(
|
94
|
+
() => [
|
95
|
+
// Cache based on a few specific conditions
|
96
|
+
'sanity/presentation',
|
97
|
+
basePath,
|
98
|
+
workspaceName,
|
99
|
+
toolName,
|
100
|
+
currentUser?.id,
|
101
|
+
resolveUUID,
|
102
|
+
cachedPreviewSearchParam,
|
103
|
+
],
|
104
|
+
[basePath, currentUser?.id, toolName, workspaceName, cachedPreviewSearchParam],
|
105
|
+
)
|
106
|
+
}
|
107
|
+
|
108
|
+
function usePreviewUrlSecret(enabled: boolean, deps: (string | symbol | undefined)[]) {
|
109
|
+
const client = useClient({apiVersion: API_VERSION})
|
110
|
+
const currentUser = useCurrentUser()
|
111
|
+
const [secretLastExpiredAt, setSecretLastExpiredAt] = useState<string>('')
|
112
|
+
|
113
|
+
const previewUrlSecret = enabled
|
114
|
+
? suspend(async () => {
|
115
|
+
return await createPreviewSecret(
|
116
|
+
client,
|
117
|
+
'@sanity/presentation',
|
118
|
+
typeof window === 'undefined' ? '' : location.href,
|
119
|
+
currentUser?.id,
|
120
|
+
)
|
121
|
+
}, [...deps, secretLastExpiredAt])
|
122
|
+
: null
|
123
|
+
|
124
|
+
useEffect(() => {
|
125
|
+
if (!previewUrlSecret) return undefined
|
126
|
+
const timeout = setTimeout(() => {
|
127
|
+
startTransition(() => setSecretLastExpiredAt(previewUrlSecret.expiresAt.toString()))
|
128
|
+
}, previewUrlSecret.expiresAt.getTime() - Date.now())
|
129
|
+
return () => clearTimeout(timeout)
|
130
|
+
}, [previewUrlSecret])
|
131
|
+
|
132
|
+
return previewUrlSecret?.secret || null
|
133
|
+
}
|
@@ -1,19 +0,0 @@
|
|
1
|
-
import {createPreviewSecret} from '@sanity/preview-url-secret/create-secret'
|
2
|
-
import {type SanityClient} from 'sanity'
|
3
|
-
import {fromPromise, type PromiseActorLogic} from 'xstate'
|
4
|
-
|
5
|
-
/** @internal */
|
6
|
-
export function defineCreatePreviewSecretActor({
|
7
|
-
client,
|
8
|
-
currentUserId,
|
9
|
-
}: {
|
10
|
-
client: SanityClient
|
11
|
-
currentUserId: string | undefined
|
12
|
-
}): PromiseActorLogic<{
|
13
|
-
secret: string
|
14
|
-
expiresAt: Date
|
15
|
-
}> {
|
16
|
-
return fromPromise(async () => {
|
17
|
-
return await createPreviewSecret(client, 'sanity/presentation', location.href, currentUserId)
|
18
|
-
})
|
19
|
-
}
|
@@ -1,18 +0,0 @@
|
|
1
|
-
import {fetchSharedAccessQuery} from '@sanity/preview-url-secret/constants'
|
2
|
-
import {type SanityClient} from 'sanity'
|
3
|
-
import {fromPromise, type PromiseActorLogic} from 'xstate'
|
4
|
-
|
5
|
-
/** @internal */
|
6
|
-
export function defineReadSharedSecretActor({
|
7
|
-
client,
|
8
|
-
}: {
|
9
|
-
client: SanityClient
|
10
|
-
}): PromiseActorLogic<string | null> {
|
11
|
-
return fromPromise(async () => {
|
12
|
-
return client.fetch<string | null>(
|
13
|
-
fetchSharedAccessQuery,
|
14
|
-
{},
|
15
|
-
{tag: 'presentation.fallback-to-shared-access-secret'},
|
16
|
-
)
|
17
|
-
})
|
18
|
-
}
|
@@ -1,55 +0,0 @@
|
|
1
|
-
import {fromPromise, type PromiseActorLogic} from 'xstate'
|
2
|
-
|
3
|
-
import {type PreviewUrlAllowOption, type PreviewUrlAllowOptionContext} from '../types'
|
4
|
-
|
5
|
-
interface Context extends Pick<PreviewUrlAllowOptionContext, 'client'> {
|
6
|
-
allowOption: PreviewUrlAllowOption | undefined
|
7
|
-
}
|
8
|
-
type Input = Omit<PreviewUrlAllowOptionContext, 'client' | 'origin'>
|
9
|
-
|
10
|
-
/** @internal */
|
11
|
-
export function defineResolveAllowPatternsActor({
|
12
|
-
client,
|
13
|
-
allowOption,
|
14
|
-
}: Context): PromiseActorLogic<URLPattern[], Input> {
|
15
|
-
return fromPromise<URLPattern[], Input>(async ({input}) => {
|
16
|
-
const {initialUrl} = input
|
17
|
-
|
18
|
-
/**
|
19
|
-
* Lazy load the URLPattern polyfill on-demand, if needed
|
20
|
-
*/
|
21
|
-
if (typeof URLPattern === 'undefined') {
|
22
|
-
await import('urlpattern-polyfill')
|
23
|
-
}
|
24
|
-
|
25
|
-
/**
|
26
|
-
* If no allow option is provided, we use the initial URL to infer the pattern
|
27
|
-
*/
|
28
|
-
if (!allowOption) {
|
29
|
-
return [new URLPattern(initialUrl.origin)]
|
30
|
-
}
|
31
|
-
|
32
|
-
const maybePatterns =
|
33
|
-
typeof allowOption === 'function'
|
34
|
-
? await allowOption({client, origin, initialUrl})
|
35
|
-
: allowOption
|
36
|
-
const patterns = Array.isArray(maybePatterns) ? maybePatterns : [maybePatterns]
|
37
|
-
const urlPatterns = patterns.map((value) => {
|
38
|
-
const urlPattern = new URLPattern(value)
|
39
|
-
if (urlPattern.hostname === '*') {
|
40
|
-
throw new Error(
|
41
|
-
`It's insecure to allow any hostname, it could disclose data to a malicious site`,
|
42
|
-
)
|
43
|
-
}
|
44
|
-
return urlPattern
|
45
|
-
})
|
46
|
-
/**
|
47
|
-
* If the declared patterns don't consider the initial URL valid, we add it to the list of patterns
|
48
|
-
*/
|
49
|
-
if (!urlPatterns.some((pattern) => pattern.test(initialUrl.origin))) {
|
50
|
-
return [...urlPatterns, new URLPattern(initialUrl.origin)]
|
51
|
-
}
|
52
|
-
|
53
|
-
return urlPatterns
|
54
|
-
})
|
55
|
-
}
|
@@ -1,65 +0,0 @@
|
|
1
|
-
import {type SanityClient} from 'sanity'
|
2
|
-
import {fromPromise, type PromiseActorLogic} from 'xstate'
|
3
|
-
|
4
|
-
import {type PresentationPerspective, type PreviewUrlOption} from '../types'
|
5
|
-
import {encodeStudioPerspective} from '../util/encodeStudioPerspective'
|
6
|
-
|
7
|
-
/** @internal */
|
8
|
-
export function defineResolveInitialUrlActor({
|
9
|
-
client,
|
10
|
-
studioBasePath,
|
11
|
-
previewUrlOption,
|
12
|
-
perspective,
|
13
|
-
}: {
|
14
|
-
client: SanityClient
|
15
|
-
studioBasePath: string
|
16
|
-
previewUrlOption: PreviewUrlOption | undefined
|
17
|
-
perspective: PresentationPerspective
|
18
|
-
}): PromiseActorLogic<URL, {previewSearchParam: string | null}> {
|
19
|
-
return fromPromise<URL, {previewSearchParam: string | null}>(
|
20
|
-
async ({input}: {input: {previewSearchParam: string | null}}) => {
|
21
|
-
const {origin} = location
|
22
|
-
/**
|
23
|
-
* If the previewUrlOption is a function, we need to resolve it and maintain backwards compatibility
|
24
|
-
*/
|
25
|
-
if (typeof previewUrlOption === 'function') {
|
26
|
-
const initial = await previewUrlOption({
|
27
|
-
client,
|
28
|
-
studioBasePath,
|
29
|
-
// @TODO handle checking permissions here, and then generating a secret
|
30
|
-
previewUrlSecret: '',
|
31
|
-
studioPreviewPerspective: encodeStudioPerspective(perspective),
|
32
|
-
previewSearchParam: input.previewSearchParam,
|
33
|
-
})
|
34
|
-
return new URL(initial, origin)
|
35
|
-
}
|
36
|
-
|
37
|
-
/**
|
38
|
-
* Provide backwards compatibility for versions where `previewUrl` where optional
|
39
|
-
*/
|
40
|
-
if (!previewUrlOption) {
|
41
|
-
return new URL('/', origin)
|
42
|
-
}
|
43
|
-
/**
|
44
|
-
* Support setting `previewUrl` as a string shorthand
|
45
|
-
*/
|
46
|
-
if (typeof previewUrlOption === 'string') {
|
47
|
-
return new URL(previewUrlOption, origin)
|
48
|
-
}
|
49
|
-
|
50
|
-
if (typeof previewUrlOption.initial === 'function') {
|
51
|
-
const initial = await previewUrlOption.initial({
|
52
|
-
client,
|
53
|
-
origin,
|
54
|
-
})
|
55
|
-
return new URL(initial, origin)
|
56
|
-
}
|
57
|
-
|
58
|
-
if (typeof previewUrlOption.initial === 'string') {
|
59
|
-
return new URL(previewUrlOption.initial, origin)
|
60
|
-
}
|
61
|
-
|
62
|
-
return new URL(previewUrlOption.preview || '/', previewUrlOption.origin || origin)
|
63
|
-
},
|
64
|
-
)
|
65
|
-
}
|
@@ -1,72 +0,0 @@
|
|
1
|
-
import {
|
2
|
-
urlSearchParamPreviewPathname,
|
3
|
-
urlSearchParamPreviewPerspective,
|
4
|
-
urlSearchParamPreviewSecret,
|
5
|
-
} from '@sanity/preview-url-secret/constants'
|
6
|
-
import {type SanityClient} from 'sanity'
|
7
|
-
import {fromPromise, type PromiseActorLogic} from 'xstate'
|
8
|
-
|
9
|
-
import {
|
10
|
-
type PresentationPerspective,
|
11
|
-
type PreviewUrlOption,
|
12
|
-
type PreviewUrlPreviewMode,
|
13
|
-
} from '../types'
|
14
|
-
import {encodeStudioPerspective} from '../util/encodeStudioPerspective'
|
15
|
-
|
16
|
-
/** @internal */
|
17
|
-
export interface ResolvePreviewModeUrlInput {
|
18
|
-
previewUrlSecret: string
|
19
|
-
resolvedPreviewMode: PreviewUrlPreviewMode
|
20
|
-
initialUrl: URL
|
21
|
-
}
|
22
|
-
|
23
|
-
/** @internal */
|
24
|
-
export function defineResolvePreviewModeUrlActor({
|
25
|
-
client,
|
26
|
-
studioBasePath,
|
27
|
-
previewUrlOption,
|
28
|
-
perspective,
|
29
|
-
}: {
|
30
|
-
client: SanityClient
|
31
|
-
studioBasePath: string
|
32
|
-
previewUrlOption: PreviewUrlOption | undefined
|
33
|
-
perspective: PresentationPerspective
|
34
|
-
}): PromiseActorLogic<URL, ResolvePreviewModeUrlInput> {
|
35
|
-
return fromPromise<URL, ResolvePreviewModeUrlInput>(async ({input}) => {
|
36
|
-
const {previewUrlSecret, resolvedPreviewMode, initialUrl} = input
|
37
|
-
|
38
|
-
/**
|
39
|
-
* If the previewUrlOption is a function, we need to resolve it and maintain backwards compatibility
|
40
|
-
*/
|
41
|
-
if (typeof previewUrlOption === 'function') {
|
42
|
-
const initial = await previewUrlOption({
|
43
|
-
client,
|
44
|
-
studioBasePath,
|
45
|
-
previewUrlSecret,
|
46
|
-
studioPreviewPerspective: encodeStudioPerspective(perspective),
|
47
|
-
previewSearchParam: initialUrl.toString(),
|
48
|
-
})
|
49
|
-
return new URL(initial, initialUrl)
|
50
|
-
}
|
51
|
-
|
52
|
-
/**
|
53
|
-
* If the resolved preview mode is false then we have an unexpected state that shouldn't be possible
|
54
|
-
*/
|
55
|
-
if (!resolvedPreviewMode) {
|
56
|
-
throw new Error('Resolved preview mode is false')
|
57
|
-
}
|
58
|
-
|
59
|
-
const url = new URL(resolvedPreviewMode.enable, initialUrl)
|
60
|
-
|
61
|
-
url.searchParams.set(urlSearchParamPreviewSecret, previewUrlSecret)
|
62
|
-
url.searchParams.set(urlSearchParamPreviewPerspective, encodeStudioPerspective(perspective))
|
63
|
-
if (initialUrl.pathname !== url.pathname) {
|
64
|
-
url.searchParams.set(
|
65
|
-
urlSearchParamPreviewPathname,
|
66
|
-
`${initialUrl.pathname}${initialUrl.search}${initialUrl.hash}`,
|
67
|
-
)
|
68
|
-
}
|
69
|
-
|
70
|
-
return url
|
71
|
-
})
|
72
|
-
}
|
@@ -1,66 +0,0 @@
|
|
1
|
-
import {fromPromise, type PromiseActorLogic} from 'xstate'
|
2
|
-
|
3
|
-
import {
|
4
|
-
type PreviewUrlOption,
|
5
|
-
type PreviewUrlPreviewMode,
|
6
|
-
type PreviewUrlPreviewModeOptionContext,
|
7
|
-
} from '../types'
|
8
|
-
|
9
|
-
type Options = Omit<PreviewUrlPreviewModeOptionContext, 'origin'>
|
10
|
-
|
11
|
-
interface Context extends Pick<Options, 'client'> {
|
12
|
-
previewUrlOption: PreviewUrlOption | undefined
|
13
|
-
}
|
14
|
-
type Input = Omit<Options, 'client'>
|
15
|
-
|
16
|
-
/** @internal */
|
17
|
-
export function defineResolvePreviewModeActor({
|
18
|
-
client,
|
19
|
-
previewUrlOption,
|
20
|
-
}: Context): PromiseActorLogic<PreviewUrlPreviewMode | false, Input> {
|
21
|
-
return fromPromise<PreviewUrlPreviewMode | false, Input>(async ({input}) => {
|
22
|
-
const {targetOrigin} = input
|
23
|
-
|
24
|
-
/**
|
25
|
-
* Handle legacy draftMode options
|
26
|
-
*/
|
27
|
-
if (typeof previewUrlOption === 'object' && previewUrlOption?.draftMode) {
|
28
|
-
return {
|
29
|
-
enable: previewUrlOption.draftMode.enable,
|
30
|
-
shareAccess: previewUrlOption.draftMode.shareAccess ?? true,
|
31
|
-
}
|
32
|
-
}
|
33
|
-
|
34
|
-
/**
|
35
|
-
* If no preview mode option is provided, we disable preview mode
|
36
|
-
*/
|
37
|
-
if (
|
38
|
-
!previewUrlOption ||
|
39
|
-
typeof previewUrlOption === 'string' ||
|
40
|
-
typeof previewUrlOption === 'function' ||
|
41
|
-
!previewUrlOption.previewMode
|
42
|
-
) {
|
43
|
-
return false
|
44
|
-
}
|
45
|
-
|
46
|
-
/**
|
47
|
-
* If the option is a function, we resolve it
|
48
|
-
*/
|
49
|
-
const previewMode =
|
50
|
-
typeof previewUrlOption.previewMode === 'function'
|
51
|
-
? await previewUrlOption.previewMode({client, origin, targetOrigin})
|
52
|
-
: previewUrlOption.previewMode
|
53
|
-
|
54
|
-
if (previewMode === false) {
|
55
|
-
return false
|
56
|
-
}
|
57
|
-
|
58
|
-
/**
|
59
|
-
* Return only supported preview mode options, filter out unknowns
|
60
|
-
*/
|
61
|
-
return {
|
62
|
-
enable: previewMode.enable,
|
63
|
-
shareAccess: previewMode.shareAccess ?? true,
|
64
|
-
}
|
65
|
-
})
|
66
|
-
}
|
@@ -1,29 +0,0 @@
|
|
1
|
-
import {fromPromise} from 'xstate'
|
2
|
-
|
3
|
-
/** @internal */
|
4
|
-
export const resolveUrlFromPreviewSearchParamActor = fromPromise<
|
5
|
-
URL,
|
6
|
-
{initialUrl: URL; previewSearchParam: string | null | undefined; allowOrigins: URLPattern[]}
|
7
|
-
>(async ({input}) => {
|
8
|
-
const {previewSearchParam, initialUrl, allowOrigins} = input
|
9
|
-
|
10
|
-
/**
|
11
|
-
* If the preview search param is falsy we can skip
|
12
|
-
*/
|
13
|
-
if (!previewSearchParam) {
|
14
|
-
return initialUrl
|
15
|
-
}
|
16
|
-
|
17
|
-
/**
|
18
|
-
* Validate the previewSearchParam
|
19
|
-
*/
|
20
|
-
try {
|
21
|
-
const previewSearchParamUrl = new URL(previewSearchParam, initialUrl.origin)
|
22
|
-
if (!allowOrigins.some((pattern) => pattern.test(previewSearchParamUrl.origin))) {
|
23
|
-
return initialUrl
|
24
|
-
}
|
25
|
-
return previewSearchParamUrl
|
26
|
-
} catch (err) {
|
27
|
-
return initialUrl
|
28
|
-
}
|
29
|
-
})
|
@@ -1,101 +0,0 @@
|
|
1
|
-
import {type ActorRefFrom, assign, setup} from 'xstate'
|
2
|
-
|
3
|
-
interface Context {
|
4
|
-
url: URL | null
|
5
|
-
error: Error | null
|
6
|
-
visualEditingOverlaysEnabled: boolean
|
7
|
-
}
|
8
|
-
|
9
|
-
type Event =
|
10
|
-
| {type: 'toggle visual editing overlays'; enabled: boolean}
|
11
|
-
| {type: 'iframe loaded'}
|
12
|
-
| {type: 'iframe refresh'}
|
13
|
-
| {type: 'iframe reload'}
|
14
|
-
|
15
|
-
export const presentationMachine = setup({
|
16
|
-
types: {} as {
|
17
|
-
context: Context
|
18
|
-
events: Event
|
19
|
-
tags: 'busy' | 'error'
|
20
|
-
},
|
21
|
-
actions: {
|
22
|
-
//
|
23
|
-
},
|
24
|
-
actors: {
|
25
|
-
//
|
26
|
-
},
|
27
|
-
guards: {
|
28
|
-
//
|
29
|
-
},
|
30
|
-
}).createMachine({
|
31
|
-
// eslint-disable-next-line tsdoc/syntax
|
32
|
-
/** @xstate-layout N4IgpgJg5mDOIC5QAUBOcwDsAuBDbAlgPaYAEAKkUQDYDEBAZqrgLZinrVG4QDaADAF1EoAA5FYBQiREgAHogAsAJgA0IAJ6IAHAEYAdIoCcJowFY9R-vzPLlAX3vq0GHPmJlKNfVx4FMUPRMrOy+EJACwkgg4pLSmLIKCLoAbIr6Zoop2tqKAMxpJnnF6loIZkbK+uZ5umapKXmK-Cm6js7osFh48RRU1D7c4RC02ERQUNTsAG4EsACuuNSkkFL+UKRE02Co1LgasJGysWsy0UnaZinVyrpGAOx1Rim2efeliPe3hma1Zvy6XT8W4OJwgFxdNy9LwDMKQILMNgcMBMOAACyO0RO8USiAK930LWU-3uiiB9yaKXemkQjW01V+txS-GKqUe7XBnW67hIfW8cJGjER7E4Q0xYgkpwS5zxVMJKWJ-FJ5Mp1LKFn4Pz+DSaLTaYIh3Oh-UGPEg+nQqNgaPWCJCpAF4pikpxMoQKWZ+gp+TSZLy1hSH3deXpNSZLNqVP1HVcPQ8fNhQ3Nor8ATtSMdQmOLo8uPdnu9BUUfoDQY1WrqOuarUcYMwRHC8Gihqh8Zh2biubdAFpAzSEL2OS247yYfodqgiKgO1K8yog7ptATFL9dFljMDrHkh1zW6OTWF1jPXaAkmY1YgKnktfxtC9dPd+Io9DvYzzPAekxBj13T3i7vKirKkqqpBsYVQ1HUFjFs0t6KK+kIjh+-JfvoBAQFMP5nH+CDaMo16KjYyjMvUNh5GWOT6MoLL8A8ygrk0dQIUabafmaEAWiinQ2gEWHSjhjJUYuj73Pcd63noQaNEYFb-Dk2S0cxe7IYm7GcYevFYjm2HyJeeQQb8tFkikVjGNoFGajUt73o+z61vYQA */
|
33
|
-
id: 'Presentation Tool',
|
34
|
-
context: {
|
35
|
-
url: null,
|
36
|
-
error: null,
|
37
|
-
visualEditingOverlaysEnabled: false,
|
38
|
-
},
|
39
|
-
|
40
|
-
on: {
|
41
|
-
'iframe reload': {
|
42
|
-
actions: assign({url: null}),
|
43
|
-
target: '.loading',
|
44
|
-
},
|
45
|
-
},
|
46
|
-
|
47
|
-
states: {
|
48
|
-
error: {
|
49
|
-
description:
|
50
|
-
'Failed to load, either because of a misconfiguration, a network error, or an unexpected error',
|
51
|
-
tags: ['error'],
|
52
|
-
},
|
53
|
-
loading: {
|
54
|
-
on: {
|
55
|
-
'iframe loaded': {
|
56
|
-
target: 'loaded',
|
57
|
-
},
|
58
|
-
},
|
59
|
-
tags: ['busy'],
|
60
|
-
},
|
61
|
-
loaded: {
|
62
|
-
on: {
|
63
|
-
'toggle visual editing overlays': {
|
64
|
-
actions: assign({
|
65
|
-
visualEditingOverlaysEnabled: ({event}) => event.enabled,
|
66
|
-
}),
|
67
|
-
},
|
68
|
-
'iframe refresh': {
|
69
|
-
target: '.refreshing',
|
70
|
-
},
|
71
|
-
'iframe reload': {
|
72
|
-
target: '.reloading',
|
73
|
-
},
|
74
|
-
},
|
75
|
-
|
76
|
-
states: {
|
77
|
-
idle: {},
|
78
|
-
refreshing: {
|
79
|
-
on: {
|
80
|
-
'iframe loaded': {
|
81
|
-
target: 'idle',
|
82
|
-
},
|
83
|
-
},
|
84
|
-
tags: ['busy'],
|
85
|
-
},
|
86
|
-
reloading: {
|
87
|
-
on: {
|
88
|
-
'iframe loaded': {
|
89
|
-
target: 'idle',
|
90
|
-
},
|
91
|
-
},
|
92
|
-
tags: ['busy'],
|
93
|
-
},
|
94
|
-
},
|
95
|
-
initial: 'idle',
|
96
|
-
},
|
97
|
-
},
|
98
|
-
initial: 'loading',
|
99
|
-
})
|
100
|
-
|
101
|
-
export type PresentationMachineRef = ActorRefFrom<typeof presentationMachine>
|