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
@@ -1,568 +0,0 @@
|
|
1
|
-
import {
|
2
|
-
schemaIdSingleton,
|
3
|
-
schemaType,
|
4
|
-
schemaTypeSingleton,
|
5
|
-
} from '@sanity/preview-url-secret/constants'
|
6
|
-
import {type SanityDocument} from '@sanity/types'
|
7
|
-
import {uuid} from '@sanity/uuid'
|
8
|
-
import {throwError} from 'rxjs'
|
9
|
-
import {type DocumentValuePermission, type PermissionCheckResult} from 'sanity'
|
10
|
-
import {type ActorRefFrom, assign, fromObservable, fromPromise, log, setup} from 'xstate'
|
11
|
-
|
12
|
-
import {type ResolvePreviewModeUrlInput} from '../actors/resolve-preview-mode-url'
|
13
|
-
import {resolveUrlFromPreviewSearchParamActor} from '../actors/resolve-url-from-preview-search-param'
|
14
|
-
import {type PreviewUrlPreviewMode} from '../types'
|
15
|
-
|
16
|
-
interface Context {
|
17
|
-
initialUrl: URL | null
|
18
|
-
previewUrl: URL | null
|
19
|
-
allowOrigins: URLPattern[] | null
|
20
|
-
error: Error | null
|
21
|
-
previewSearchParam: string | null
|
22
|
-
previewUrlSecret: {secret: string; expiresAt: Date} | null
|
23
|
-
previewAccessSharingCreatePermission: PermissionCheckResult | null
|
24
|
-
previewAccessSharingReadPermission: PermissionCheckResult | null
|
25
|
-
previewAccessSharingUpdatePermission: PermissionCheckResult | null
|
26
|
-
previewUrlSecretPermission: PermissionCheckResult | null
|
27
|
-
previewMode: PreviewUrlPreviewMode | null
|
28
|
-
}
|
29
|
-
|
30
|
-
type SetPreviewSearchParamEvent = {
|
31
|
-
type: 'set preview search param'
|
32
|
-
previewSearchParam: string | null
|
33
|
-
}
|
34
|
-
type Event = SetPreviewSearchParamEvent
|
35
|
-
|
36
|
-
type Input = Omit<SetPreviewSearchParamEvent, 'type'>
|
37
|
-
|
38
|
-
export interface CheckPermissionInput {
|
39
|
-
checkPermissionName: DocumentValuePermission
|
40
|
-
document: Partial<SanityDocument> | null
|
41
|
-
}
|
42
|
-
|
43
|
-
/**
|
44
|
-
* Used for permissions checks
|
45
|
-
*/
|
46
|
-
export const shareAccessSingletonDocument = {_id: schemaIdSingleton, _type: schemaTypeSingleton}
|
47
|
-
export const previewUrlSecretDocument = {
|
48
|
-
_id: `drafts.${uuid()}`,
|
49
|
-
_type: schemaType,
|
50
|
-
}
|
51
|
-
|
52
|
-
export const previewUrlMachine = setup({
|
53
|
-
types: {} as {
|
54
|
-
context: Context
|
55
|
-
events: Event
|
56
|
-
input: Input
|
57
|
-
tags: 'busy' | 'error'
|
58
|
-
},
|
59
|
-
actions: {
|
60
|
-
'notify preview will likely fail': log(
|
61
|
-
`Missing permissions to create preview secret, or read shared preview secret. Preview will likely fail loading.`,
|
62
|
-
),
|
63
|
-
'assign preview search param': assign({
|
64
|
-
previewSearchParam: (_, params: {previewSearchParam: string | null}) =>
|
65
|
-
params.previewSearchParam,
|
66
|
-
}),
|
67
|
-
'assign error': assign({
|
68
|
-
error: (_, params: {message: string; error: unknown}) => {
|
69
|
-
return params.error instanceof Error
|
70
|
-
? params.error
|
71
|
-
: new Error(params.message, {cause: params.error})
|
72
|
-
},
|
73
|
-
}),
|
74
|
-
},
|
75
|
-
actors: {
|
76
|
-
'check permission': fromObservable<PermissionCheckResult, CheckPermissionInput>(() =>
|
77
|
-
throwError(
|
78
|
-
() =>
|
79
|
-
new Error(
|
80
|
-
`The 'check permission' actor is not implemented. Add it to previewUrlMachine.provide({actors: {'check permission': fromObservable(({input}: {input: CheckPermissionInput}) => ...)}})`,
|
81
|
-
),
|
82
|
-
),
|
83
|
-
),
|
84
|
-
'resolve initial url': fromPromise<URL, {previewSearchParam: string | null}>(() =>
|
85
|
-
Promise.reject(
|
86
|
-
new Error(
|
87
|
-
`The 'resolve initial url' actor is not implemented. Add it to previewUrlMachine.provide({actors: {'resolve initial url': fromPromise(...)}})`,
|
88
|
-
),
|
89
|
-
),
|
90
|
-
),
|
91
|
-
'resolve allow patterns': fromPromise<URLPattern[], {initialUrl: URL}>(() =>
|
92
|
-
Promise.reject(
|
93
|
-
new Error(
|
94
|
-
`The 'resolve allow patterns' actor is not implemented. Add it to previewUrlMachine.provide({actors: {'resolve allow pattern': fromPromise(...)}})`,
|
95
|
-
),
|
96
|
-
),
|
97
|
-
),
|
98
|
-
'resolve url from preview search param': resolveUrlFromPreviewSearchParamActor,
|
99
|
-
'resolve preview mode': fromPromise<PreviewUrlPreviewMode | false, {targetOrigin: string}>(() =>
|
100
|
-
Promise.reject(
|
101
|
-
new Error(
|
102
|
-
`The 'resolve preview mode' actor is not implemented. Add it to previewUrlMachine.provide({actors: {'resolve preview mode': fromPromise(...)}})`,
|
103
|
-
),
|
104
|
-
),
|
105
|
-
),
|
106
|
-
'create preview secret': fromPromise<{
|
107
|
-
secret: string
|
108
|
-
expiresAt: Date
|
109
|
-
}>(async () =>
|
110
|
-
Promise.reject(
|
111
|
-
new Error(
|
112
|
-
`The 'create preview secret' actor is not implemented. Add it to previewUrlMachine.provide({actors: {'create preview secret': fromPromise(...)}})`,
|
113
|
-
),
|
114
|
-
),
|
115
|
-
),
|
116
|
-
'read shared preview secret': fromPromise<string | null>(async () =>
|
117
|
-
Promise.reject(
|
118
|
-
new Error(
|
119
|
-
`The 'read shared preview secret' actor is not implemented. Add it to previewUrlMachine.provide({actors: {'read shared preview secret': fromPromise(...)}})`,
|
120
|
-
),
|
121
|
-
),
|
122
|
-
),
|
123
|
-
'resolve preview mode url': fromPromise<URL, ResolvePreviewModeUrlInput>(() =>
|
124
|
-
Promise.reject(
|
125
|
-
new Error(
|
126
|
-
`The 'resolve preview mode url' actor is not implemented. Add it to previewUrlMachine.provide({actors: {'resolve preview mode url': fromPromise(...)}})`,
|
127
|
-
),
|
128
|
-
),
|
129
|
-
),
|
130
|
-
},
|
131
|
-
guards: {
|
132
|
-
'has checked permissions': ({context}) => {
|
133
|
-
return Boolean(
|
134
|
-
context.previewAccessSharingCreatePermission &&
|
135
|
-
context.previewAccessSharingReadPermission &&
|
136
|
-
context.previewAccessSharingUpdatePermission &&
|
137
|
-
context.previewUrlSecretPermission,
|
138
|
-
)
|
139
|
-
},
|
140
|
-
'search param has new origin': ({context, event}) => {
|
141
|
-
if (!context.previewUrl || !event.previewSearchParam) {
|
142
|
-
return false
|
143
|
-
}
|
144
|
-
try {
|
145
|
-
const previewSearchParamUrl = new URL(event.previewSearchParam, context.previewUrl)
|
146
|
-
return context.previewUrl.origin !== previewSearchParamUrl.origin
|
147
|
-
} catch {
|
148
|
-
return false
|
149
|
-
}
|
150
|
-
},
|
151
|
-
'can create preview secret': ({context}) => {
|
152
|
-
return context.previewUrlSecretPermission?.granted === true
|
153
|
-
},
|
154
|
-
|
155
|
-
'has preview mode with created secret': ({context}, params: PreviewUrlPreviewMode | false) => {
|
156
|
-
if (params === false) {
|
157
|
-
return false
|
158
|
-
}
|
159
|
-
return context.previewUrlSecretPermission?.granted === true
|
160
|
-
},
|
161
|
-
'has preview mode with share access': ({context}, params: PreviewUrlPreviewMode | false) => {
|
162
|
-
if (params === false) {
|
163
|
-
return false
|
164
|
-
}
|
165
|
-
return context.previewAccessSharingReadPermission?.granted === true
|
166
|
-
},
|
167
|
-
'has preview mode without permissions': ({context}, params: PreviewUrlPreviewMode | false) => {
|
168
|
-
if (params === false) {
|
169
|
-
return false
|
170
|
-
}
|
171
|
-
return (
|
172
|
-
context.previewAccessSharingReadPermission?.granted === false &&
|
173
|
-
context.previewUrlSecretPermission?.granted === false
|
174
|
-
)
|
175
|
-
},
|
176
|
-
},
|
177
|
-
delays: {
|
178
|
-
expiredSecret: ({context}) => {
|
179
|
-
if (!context.previewUrlSecret?.expiresAt) {
|
180
|
-
return 0
|
181
|
-
}
|
182
|
-
const now = Date.now()
|
183
|
-
const expiresAt = context.previewUrlSecret.expiresAt.getTime()
|
184
|
-
return Math.max(expiresAt - now, 0)
|
185
|
-
},
|
186
|
-
},
|
187
|
-
}).createMachine({
|
188
|
-
// eslint-disable-next-line tsdoc/syntax
|
189
|
-
/** @xstate-layout N4IgpgJg5mDOIC5QAUBOYBuBLMB3ABAKoBKAMgMRiqoD2qAdAA4A2AhgC4BmdAtvWphwESpBFgB2GGgGMOWGuIDaABgC6K1YlCMasLO3nitIAB6IArAA56AZgCcAdkcBGS8vMAmO+YBszgDQgAJ6Izs4+9M7KACzKztGWHg4OPubmAL7pgQLYeERklNR0TGxcvPzoucJkYpIycgqKzupqxjp6BgrGZggAtM520ZHRdjZjNjFe7oEhCGERUbHxicmpGVkgOUL5FFS0DCwc3Kh8W3kitVKynUoeLZpIIO36ht2IvV62Hl7elmE2lh83xmoXCkRicQSSRS5gSmWylW2IkK+xKR3KZ2qogkVwaShs9zauheXUePV6gPo3jSUyi-xBczBi0hKxh5mc8M2iPOBVgYHY+EY3IIfNYqGkAAtBWLWDwNESOq8yaCbM56A4bB5fGllHYvD4fAz4h56CNfG5LKqHMpLdFOZidvRJWBpABrCRQZBUHhYWB6BSwcjyx7PG5vPrs5TqjWqyyjTXRDwMjwxei68J2ZQ2nyWXN2jYOkT0dCwGjMbDiKAASXEL1YzEIqGY5AgCjA9BxNFd7cLZGLcDLFertYM9cbzEu9RuGmD2mJYeVfRGdipyh86Yc0XiE3MDK3JssIwcrmtPjGSXzCMEPNI-dL5Y9NbrDabKOKhzKJwq16xd8Hj5HLAxybSdrkMGdWhDeclVAclN3odlzBsKwBjSSxjwcZM7DVeJ1w8P4xmidk7HtYVHRLf9KwAQWYZgaFwZAOHYKhxEDVtxHbTtu2-KpyIHB9qNo+jGPYZjUFY0C8Qgh450VUlYPedkHHoHwnDSZDVOiGwfGiBlUhXXwwjsQYtKSYzSJ-Pj7yHGi6IYpiWMDPZ31KY5TjIosKIEqBbOEhzxNgSTpzUWcnmg+TTHePV6Hw3MYgzaItJ0hlYRNTNkLiHxBl1GILN4zz+KHccADFaB4TEAGUwDFSVGNQWUWzbDs6m43tby8oqm1KmhyuFKqaolOrZSC8CQsg2SSSMRdel8ZSNUTdlcw8M07AZQZrDXdaDRtUZnHWK98r7DqPRKsrKuq8VBplHg3wOVyMQ8o7CpOrqzr6i7auukbGjGmSwrkqaFL6MJlLiWFlC1EGty0hknAiXVVPMRx12UJwOQLR72ueytMQAWRoCAwEajjmqkVrMb-by8YJsBvqUX6FUm8Nem2+hbWPUZErGTcjS8NUJg8AE9T1ZwHHwvKkSe6yPWpwnic4lqewp46ceFfHCbpmdmkZhcgZmyxzFsDmTPcXUUiNRKDy3ZQJlVLSkYlm9KaHWWifYhWyaVyyCul1Wf3V2nOzAn71DuHWYMivovGsBxPCy74beWaJDWCUJzBSFTrUcQYdMzIFHd-FXPTVmn5dJrsvcOrHfeL-2ac1kKCXDiLyWcNKJiiHM-BtONwgtnMEM1DVNwhhI7B8AurMo2uqgD260U-dzval6fXYbwkoIB5moijLLkm5tvYRBo1nGQtND11ZaIdzEiMeX6vV5LuW+QFIVLNFS7pXquVxv+pnF1FtYP4OY7AG3QohJMqcEDeGUq4NwYQBhLEnkWWAABXaQ0g4CBhfoKMiH9JRf1lKFUMEceiizVPA0+7gtQQy8LzXU6obaJTFtEJwHhXDIL7G-WepccHcO2PgqUjBrrEPCoDSOFI3C2AGHtQ8sIiJJGTILZS7JRaeGSKw7CnDbz8LwAHJ06AOBgHOtIdA7Ay5cUrpLHRT92ymOqsxExZj16iK3gAqI6oaQ6QtE4YylhkynzmkCBGNgNR7VvgdaxTBbEGIccY969jzHOTuuiL8bVol10JrEoxTj+QuN-iQlu7xwjKX1P8bSTC0hGhcKaBIOZAQGkBKE7RGSeFZMMRACqEoxRgCohgrBFjFY8Sibo3A+iOldJ6X0zBfp8l-UKeIshjgqTGTiPYPaGotS7igd8QWtgsp6iQnFOEd8q6tKEOM6qnTunoGmQM5JC83LDKdqMy5rBrlTP6bMoOUkGab3-kDU+ERVEpnsEjDRVSdljBXKeQY3h5gOBaa8mmzt4k-nHIMz2zzfzIvaYVNFVRxxzObosxAfg1Q2jSOERIh5kIBNGKaNZ2lvjhFhEimJHUCVCAxQ8j8Tz0m4vbJyzERKfnBQ3hNXWkdyWeJsCMVhqNsK6mTO4Q2Q9DysLCEhDw7LMntjQV8wMJhYDsCMfQVgnAxIAAowAmEYFgdAnSXRmIAJTkAFTEg1MzYCuIBZHKYKlUiqWwrCMJkDZgDAYceRMfwUisPYZYTIGxxA03gI8NqJLmZ6msKqENcjErqIZL0cethvDGXLew9hiYWnOjdDLb0vp-SsUzdNcwEMEJ7WTohDMfgU4RpTCpUJnhYrHghuEFpRcnyjhfMwFtet2Q2FNOwsWZarBan8TsuMkRvhIzPJGDwmkWnJLnf6g0aZl0mQTURDdsxYiGwwsRIEgwEwTuxj5IS9lRKORPeSJCOF4XgrUZqbZsxwZszcJtbC4RUg2FfTXU6PVzoDSGjwH9ik-gxRGG4NtxkkZblhgyxIhFQG5lSPEODj89VoYjKqGKURkij0zImXSUCwiozZuDLUCQQY6tOVEr1WDqMsxNCkP4RFPBZj+I4I0qoRMODjIlceBzkK6raWAIT7DDZlNPhUuVkKI0pEXbHBISF1yAiIqpi5KL7E5ISWYoTna2b6Qg+DcFN7EAphLdpdOWVoPJ0RXxl5HKrmTNuYahzaQviaQPVERa8mlGeBUnnQyDStSwcCzi4L1kuV4HHNR4DCFdRaVVFSzcZ4VVIVsDEVhZ5QnWlYZZvRKLj3-KlT0FIKjVRZghkCXwqkjQGzVFxvOMisoWYy46QV9ABN+mo3mFZZ427lp032jzVa2bJGtCUtciak1AA */
|
190
|
-
id: 'Preview URL',
|
191
|
-
context: ({input}) => ({
|
192
|
-
initialUrl: null,
|
193
|
-
previewUrl: null,
|
194
|
-
error: null,
|
195
|
-
allowOrigins: null,
|
196
|
-
previewSearchParam: input.previewSearchParam,
|
197
|
-
previewUrlSecret: null,
|
198
|
-
previewAccessSharingCreatePermission: null,
|
199
|
-
previewAccessSharingReadPermission: null,
|
200
|
-
previewAccessSharingUpdatePermission: null,
|
201
|
-
previewUrlSecretPermission: null,
|
202
|
-
previewMode: null,
|
203
|
-
}),
|
204
|
-
|
205
|
-
invoke: [
|
206
|
-
{
|
207
|
-
src: 'check permission',
|
208
|
-
input: () => ({checkPermissionName: 'read', document: shareAccessSingletonDocument}),
|
209
|
-
onError: {
|
210
|
-
target: '.error',
|
211
|
-
actions: {
|
212
|
-
type: 'assign error',
|
213
|
-
params: ({event}) => ({
|
214
|
-
message: 'Failed to check permission',
|
215
|
-
error: event.error,
|
216
|
-
}),
|
217
|
-
},
|
218
|
-
},
|
219
|
-
onSnapshot: {
|
220
|
-
actions: assign({
|
221
|
-
previewAccessSharingReadPermission: ({event}) => event.snapshot.context ?? null,
|
222
|
-
}),
|
223
|
-
},
|
224
|
-
},
|
225
|
-
{
|
226
|
-
src: 'check permission',
|
227
|
-
input: () => ({checkPermissionName: 'create', document: shareAccessSingletonDocument}),
|
228
|
-
onError: {
|
229
|
-
target: '.error',
|
230
|
-
actions: {
|
231
|
-
type: 'assign error',
|
232
|
-
params: ({event}) => ({
|
233
|
-
message: 'Failed to check permission',
|
234
|
-
error: event.error,
|
235
|
-
}),
|
236
|
-
},
|
237
|
-
},
|
238
|
-
onSnapshot: {
|
239
|
-
actions: assign({
|
240
|
-
previewAccessSharingCreatePermission: ({event}) => event.snapshot.context ?? null,
|
241
|
-
}),
|
242
|
-
},
|
243
|
-
},
|
244
|
-
{
|
245
|
-
src: 'check permission',
|
246
|
-
input: () => ({checkPermissionName: 'update', document: shareAccessSingletonDocument}),
|
247
|
-
onError: {
|
248
|
-
target: '.error',
|
249
|
-
actions: {
|
250
|
-
type: 'assign error',
|
251
|
-
params: ({event}) => ({
|
252
|
-
message: 'Failed to check permission',
|
253
|
-
error: event.error,
|
254
|
-
}),
|
255
|
-
},
|
256
|
-
},
|
257
|
-
onSnapshot: {
|
258
|
-
actions: assign({
|
259
|
-
previewAccessSharingUpdatePermission: ({event}) => event.snapshot.context ?? null,
|
260
|
-
}),
|
261
|
-
},
|
262
|
-
},
|
263
|
-
{
|
264
|
-
src: 'check permission',
|
265
|
-
input: () => ({checkPermissionName: 'create', document: previewUrlSecretDocument}),
|
266
|
-
onError: {
|
267
|
-
target: '.error',
|
268
|
-
actions: {
|
269
|
-
type: 'assign error',
|
270
|
-
params: ({event}) => ({
|
271
|
-
message: 'Failed to check permission',
|
272
|
-
error: event.error,
|
273
|
-
}),
|
274
|
-
},
|
275
|
-
},
|
276
|
-
onSnapshot: {
|
277
|
-
actions: assign({
|
278
|
-
previewUrlSecretPermission: ({event}) => event.snapshot.context ?? null,
|
279
|
-
}),
|
280
|
-
},
|
281
|
-
},
|
282
|
-
],
|
283
|
-
|
284
|
-
on: {
|
285
|
-
'set preview search param': {
|
286
|
-
actions: {
|
287
|
-
type: 'assign preview search param',
|
288
|
-
params: ({event}) => ({previewSearchParam: event.previewSearchParam}),
|
289
|
-
},
|
290
|
-
},
|
291
|
-
},
|
292
|
-
|
293
|
-
states: {
|
294
|
-
checkingPermissions: {
|
295
|
-
always: {
|
296
|
-
guard: 'has checked permissions',
|
297
|
-
target: 'resolvingInitialUrl',
|
298
|
-
},
|
299
|
-
tags: 'busy',
|
300
|
-
},
|
301
|
-
|
302
|
-
resolvingInitialUrl: {
|
303
|
-
invoke: {
|
304
|
-
src: 'resolve initial url',
|
305
|
-
input: ({context}) => ({previewSearchParam: context.previewSearchParam}),
|
306
|
-
onError: {
|
307
|
-
target: 'error',
|
308
|
-
actions: {
|
309
|
-
type: 'assign error',
|
310
|
-
params: ({event}) => ({
|
311
|
-
message: 'Failed to resolve initial url',
|
312
|
-
error: event.error,
|
313
|
-
}),
|
314
|
-
},
|
315
|
-
},
|
316
|
-
onDone: {
|
317
|
-
target: 'resolvingAllowPatterns',
|
318
|
-
actions: assign({initialUrl: ({event}) => event.output}),
|
319
|
-
},
|
320
|
-
},
|
321
|
-
|
322
|
-
tags: 'busy',
|
323
|
-
},
|
324
|
-
|
325
|
-
error: {
|
326
|
-
type: 'final',
|
327
|
-
tags: 'error',
|
328
|
-
},
|
329
|
-
|
330
|
-
resolvingAllowPatterns: {
|
331
|
-
invoke: {
|
332
|
-
src: 'resolve allow patterns',
|
333
|
-
input: ({context}) => ({initialUrl: context.initialUrl!}),
|
334
|
-
onError: {
|
335
|
-
target: 'error',
|
336
|
-
actions: {
|
337
|
-
type: 'assign error',
|
338
|
-
params: ({event}) => ({
|
339
|
-
message: 'Failed to resolve preview url allow patterns',
|
340
|
-
error: event.error,
|
341
|
-
}),
|
342
|
-
},
|
343
|
-
},
|
344
|
-
onDone: {
|
345
|
-
target: 'resolvingUrlFromPreviewSearchParam',
|
346
|
-
actions: assign({allowOrigins: ({event}) => event.output}),
|
347
|
-
},
|
348
|
-
},
|
349
|
-
tags: ['busy'],
|
350
|
-
},
|
351
|
-
|
352
|
-
resolvingUrlFromPreviewSearchParam: {
|
353
|
-
id: 'loop',
|
354
|
-
invoke: {
|
355
|
-
src: 'resolve url from preview search param',
|
356
|
-
input: ({context}) => ({
|
357
|
-
initialUrl: context.initialUrl!,
|
358
|
-
allowOrigins: context.allowOrigins!,
|
359
|
-
previewSearchParam: context.previewSearchParam,
|
360
|
-
}),
|
361
|
-
onError: {
|
362
|
-
target: 'error',
|
363
|
-
actions: {
|
364
|
-
type: 'assign error',
|
365
|
-
params: ({event}) => ({
|
366
|
-
message: 'Failed to resolve preview url from search param',
|
367
|
-
error: event.error,
|
368
|
-
}),
|
369
|
-
},
|
370
|
-
},
|
371
|
-
onDone: {
|
372
|
-
target: 'resolvingPreviewMode',
|
373
|
-
actions: assign({initialUrl: ({event}) => event.output}),
|
374
|
-
},
|
375
|
-
},
|
376
|
-
tags: ['busy'],
|
377
|
-
},
|
378
|
-
|
379
|
-
resolvingPreviewMode: {
|
380
|
-
on: {
|
381
|
-
'set preview search param': {
|
382
|
-
guard: 'search param has new origin',
|
383
|
-
actions: {
|
384
|
-
type: 'assign preview search param',
|
385
|
-
params: ({event}) => ({previewSearchParam: event.previewSearchParam}),
|
386
|
-
},
|
387
|
-
target: '#loop',
|
388
|
-
reenter: true,
|
389
|
-
},
|
390
|
-
},
|
391
|
-
invoke: {
|
392
|
-
src: 'resolve preview mode',
|
393
|
-
input: ({context}) => ({targetOrigin: context.initialUrl!.origin}),
|
394
|
-
onError: {
|
395
|
-
target: 'error',
|
396
|
-
actions: {
|
397
|
-
type: 'assign error',
|
398
|
-
params: ({event}) => ({
|
399
|
-
message: 'Failed to resolve preview url allow patterns',
|
400
|
-
error: event.error,
|
401
|
-
}),
|
402
|
-
},
|
403
|
-
},
|
404
|
-
onDone: [
|
405
|
-
{
|
406
|
-
guard: {
|
407
|
-
type: 'has preview mode with created secret',
|
408
|
-
params: ({event}) => event.output,
|
409
|
-
},
|
410
|
-
actions: assign({
|
411
|
-
previewMode: ({event}) => event.output as unknown as PreviewUrlPreviewMode,
|
412
|
-
}),
|
413
|
-
target: 'previewMode.createPreviewSecret',
|
414
|
-
},
|
415
|
-
{
|
416
|
-
guard: {
|
417
|
-
type: 'has preview mode with share access',
|
418
|
-
params: ({event}) => event.output,
|
419
|
-
},
|
420
|
-
actions: assign({
|
421
|
-
previewMode: ({event}) => event.output as unknown as PreviewUrlPreviewMode,
|
422
|
-
}),
|
423
|
-
target: 'previewMode.readShareAccess',
|
424
|
-
},
|
425
|
-
{
|
426
|
-
guard: {
|
427
|
-
type: 'has preview mode without permissions',
|
428
|
-
params: ({event}) => event.output,
|
429
|
-
},
|
430
|
-
actions: [
|
431
|
-
assign({
|
432
|
-
previewUrl: ({context}) => context.initialUrl,
|
433
|
-
}),
|
434
|
-
'notify preview will likely fail',
|
435
|
-
],
|
436
|
-
target: 'success',
|
437
|
-
},
|
438
|
-
{
|
439
|
-
actions: assign({
|
440
|
-
previewUrl: ({context}) => context.initialUrl,
|
441
|
-
}),
|
442
|
-
target: 'success',
|
443
|
-
},
|
444
|
-
],
|
445
|
-
},
|
446
|
-
tags: ['busy'],
|
447
|
-
},
|
448
|
-
|
449
|
-
success: {
|
450
|
-
on: {
|
451
|
-
'set preview search param': {
|
452
|
-
guard: 'search param has new origin',
|
453
|
-
actions: {
|
454
|
-
type: 'assign preview search param',
|
455
|
-
params: ({event}) => ({previewSearchParam: event.previewSearchParam}),
|
456
|
-
},
|
457
|
-
target: '#loop',
|
458
|
-
reenter: true,
|
459
|
-
},
|
460
|
-
},
|
461
|
-
},
|
462
|
-
|
463
|
-
previewMode: {
|
464
|
-
on: {
|
465
|
-
'set preview search param': {
|
466
|
-
guard: 'search param has new origin',
|
467
|
-
actions: {
|
468
|
-
type: 'assign preview search param',
|
469
|
-
params: ({event}) => ({previewSearchParam: event.previewSearchParam}),
|
470
|
-
},
|
471
|
-
target: '#loop',
|
472
|
-
reenter: true,
|
473
|
-
},
|
474
|
-
},
|
475
|
-
|
476
|
-
states: {
|
477
|
-
createPreviewSecret: {
|
478
|
-
invoke: {
|
479
|
-
src: 'create preview secret',
|
480
|
-
onError: {
|
481
|
-
target: 'error',
|
482
|
-
actions: {
|
483
|
-
type: 'assign error',
|
484
|
-
params: ({event}) => ({
|
485
|
-
message: 'Failed to create preview secret',
|
486
|
-
error: event.error,
|
487
|
-
}),
|
488
|
-
},
|
489
|
-
},
|
490
|
-
onDone: {
|
491
|
-
target: 'resolvePreviewUrl',
|
492
|
-
actions: assign({previewUrlSecret: ({event}) => event.output}),
|
493
|
-
},
|
494
|
-
},
|
495
|
-
tags: ['busy'],
|
496
|
-
},
|
497
|
-
readShareAccess: {
|
498
|
-
invoke: {
|
499
|
-
src: 'read shared preview secret',
|
500
|
-
onError: {
|
501
|
-
target: 'error',
|
502
|
-
actions: {
|
503
|
-
type: 'assign error',
|
504
|
-
params: ({event}) => ({
|
505
|
-
message: 'Failed to read shared preview secret',
|
506
|
-
error: event.error,
|
507
|
-
}),
|
508
|
-
},
|
509
|
-
},
|
510
|
-
onDone: {
|
511
|
-
target: 'resolvePreviewUrl',
|
512
|
-
actions: assign({
|
513
|
-
previewUrlSecret: ({event}) => ({
|
514
|
-
secret: event.output!,
|
515
|
-
expiresAt: new Date(Date.now() + 1000 * 60 * 60 * 60 * 24),
|
516
|
-
}),
|
517
|
-
}),
|
518
|
-
},
|
519
|
-
},
|
520
|
-
tags: ['busy'],
|
521
|
-
},
|
522
|
-
resolvePreviewUrl: {
|
523
|
-
invoke: {
|
524
|
-
src: 'resolve preview mode url',
|
525
|
-
input: ({context}) => ({
|
526
|
-
initialUrl: context.initialUrl!,
|
527
|
-
resolvedPreviewMode: context.previewMode!,
|
528
|
-
previewUrlSecret: context.previewUrlSecret!.secret,
|
529
|
-
}),
|
530
|
-
onError: {
|
531
|
-
target: 'error',
|
532
|
-
actions: {
|
533
|
-
type: 'assign error',
|
534
|
-
params: ({event}) => ({
|
535
|
-
message: 'Failed to resolve preview url',
|
536
|
-
error: event.error,
|
537
|
-
}),
|
538
|
-
},
|
539
|
-
},
|
540
|
-
onDone: {
|
541
|
-
target: 'success',
|
542
|
-
actions: assign({previewUrl: ({event}) => event.output}),
|
543
|
-
},
|
544
|
-
},
|
545
|
-
tags: ['busy'],
|
546
|
-
},
|
547
|
-
error: {
|
548
|
-
type: 'final',
|
549
|
-
tags: ['error'],
|
550
|
-
},
|
551
|
-
success: {
|
552
|
-
after: {
|
553
|
-
expiredSecret: {
|
554
|
-
guard: 'can create preview secret',
|
555
|
-
actions: assign({previewUrlSecret: null}),
|
556
|
-
target: 'createPreviewSecret',
|
557
|
-
reenter: true,
|
558
|
-
},
|
559
|
-
},
|
560
|
-
},
|
561
|
-
},
|
562
|
-
initial: 'readShareAccess',
|
563
|
-
},
|
564
|
-
},
|
565
|
-
|
566
|
-
initial: 'checkingPermissions',
|
567
|
-
})
|
568
|
-
export type PreviewUrlRef = ActorRefFrom<typeof previewUrlMachine>
|
@@ -1,12 +0,0 @@
|
|
1
|
-
import {useSelector} from '@xstate/react'
|
2
|
-
|
3
|
-
import {type PreviewUrlRef} from './machines/preview-url'
|
4
|
-
|
5
|
-
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
6
|
-
export function useAllowPatterns(previewUrlRef: PreviewUrlRef) {
|
7
|
-
const allowPatterns = useSelector(previewUrlRef, (state) => state.context.allowOrigins)
|
8
|
-
if (!Array.isArray(allowPatterns)) {
|
9
|
-
throw new TypeError('allowPatterns must be an array')
|
10
|
-
}
|
11
|
-
return allowPatterns
|
12
|
-
}
|
@@ -1,7 +0,0 @@
|
|
1
|
-
import {useId as useReactId} from 'react'
|
2
|
-
|
3
|
-
export function useId(): string {
|
4
|
-
const id = useReactId()
|
5
|
-
// Uses the new format introduced in: https://github.com/facebook/react/pull/32001
|
6
|
-
return id.startsWith(':') ? id.replace(/^:(.+):$/, '\u00AB$1\u00BB') : id
|
7
|
-
}
|
@@ -1,14 +0,0 @@
|
|
1
|
-
import {usePerspective} from 'sanity'
|
2
|
-
|
3
|
-
import {type PresentationPerspective} from './types'
|
4
|
-
|
5
|
-
/**
|
6
|
-
* @internal
|
7
|
-
*/
|
8
|
-
export function usePresentationPerspective(): PresentationPerspective {
|
9
|
-
const {perspectiveStack, selectedPerspectiveName = 'drafts', selectedReleaseId} = usePerspective()
|
10
|
-
const perspective = (
|
11
|
-
selectedReleaseId ? perspectiveStack : selectedPerspectiveName
|
12
|
-
) as PresentationPerspective
|
13
|
-
return perspective
|
14
|
-
}
|
@@ -1,96 +0,0 @@
|
|
1
|
-
import {useToast} from '@sanity/ui'
|
2
|
-
import {useActorRef, useSelector} from '@xstate/react'
|
3
|
-
import {useEffect} from 'react'
|
4
|
-
import {useActiveWorkspace, useClient, useCurrentUser, useGrantsStore, useTranslation} from 'sanity'
|
5
|
-
import {useRouter} from 'sanity/router'
|
6
|
-
import {fromObservable} from 'xstate'
|
7
|
-
|
8
|
-
import {defineCreatePreviewSecretActor} from './actors/create-preview-secret'
|
9
|
-
import {defineReadSharedSecretActor} from './actors/read-shared-secret'
|
10
|
-
import {defineResolveAllowPatternsActor} from './actors/resolve-allow-patterns'
|
11
|
-
import {defineResolveInitialUrlActor} from './actors/resolve-initial-url'
|
12
|
-
import {defineResolvePreviewModeActor} from './actors/resolve-preview-mode'
|
13
|
-
import {defineResolvePreviewModeUrlActor} from './actors/resolve-preview-mode-url'
|
14
|
-
import {API_VERSION} from './constants'
|
15
|
-
import {presentationLocaleNamespace} from './i18n'
|
16
|
-
import {previewUrlMachine, type PreviewUrlRef} from './machines/preview-url'
|
17
|
-
import {type PreviewUrlAllowOption, type PreviewUrlOption} from './types'
|
18
|
-
import {usePresentationPerspective} from './usePresentationPerspective'
|
19
|
-
|
20
|
-
export function usePreviewUrlActorRef(
|
21
|
-
previewUrlOption: PreviewUrlOption | undefined,
|
22
|
-
allowOption: PreviewUrlAllowOption | undefined,
|
23
|
-
): PreviewUrlRef {
|
24
|
-
const grantsStore = useGrantsStore()
|
25
|
-
const client = useClient({apiVersion: API_VERSION})
|
26
|
-
const currentUser = useCurrentUser()
|
27
|
-
const currentUserId = currentUser?.id
|
28
|
-
const workspace = useActiveWorkspace()
|
29
|
-
const studioBasePath = workspace?.activeWorkspace?.basePath || '/'
|
30
|
-
const router = useRouter()
|
31
|
-
const routerSearchParams = new URLSearchParams(router.state._searchParams)
|
32
|
-
const previewSearchParam = routerSearchParams.get('preview')
|
33
|
-
const {push: pushToast} = useToast()
|
34
|
-
const {t} = useTranslation(presentationLocaleNamespace)
|
35
|
-
const perspective = usePresentationPerspective()
|
36
|
-
|
37
|
-
const actorRef = useActorRef(
|
38
|
-
previewUrlMachine.provide({
|
39
|
-
actions: {
|
40
|
-
'notify preview will likely fail': () =>
|
41
|
-
pushToast({
|
42
|
-
id: 'preview-url-secret.missing-grants',
|
43
|
-
closable: true,
|
44
|
-
status: 'error',
|
45
|
-
duration: Infinity,
|
46
|
-
title: t('preview-url-secret.missing-grants'),
|
47
|
-
}),
|
48
|
-
},
|
49
|
-
actors: {
|
50
|
-
'create preview secret': defineCreatePreviewSecretActor({client, currentUserId}),
|
51
|
-
'read shared preview secret': defineReadSharedSecretActor({client}),
|
52
|
-
'resolve allow patterns': defineResolveAllowPatternsActor({
|
53
|
-
client,
|
54
|
-
allowOption,
|
55
|
-
}),
|
56
|
-
'resolve initial url': defineResolveInitialUrlActor({
|
57
|
-
client,
|
58
|
-
studioBasePath,
|
59
|
-
previewUrlOption,
|
60
|
-
perspective,
|
61
|
-
}),
|
62
|
-
'resolve preview mode': defineResolvePreviewModeActor({
|
63
|
-
client,
|
64
|
-
previewUrlOption,
|
65
|
-
}),
|
66
|
-
'resolve preview mode url': defineResolvePreviewModeUrlActor({
|
67
|
-
client,
|
68
|
-
studioBasePath,
|
69
|
-
previewUrlOption,
|
70
|
-
perspective,
|
71
|
-
}),
|
72
|
-
'check permission': fromObservable(({input}) =>
|
73
|
-
grantsStore.checkDocumentPermission(input.checkPermissionName, input.document),
|
74
|
-
),
|
75
|
-
},
|
76
|
-
}),
|
77
|
-
{input: {previewSearchParam}},
|
78
|
-
)
|
79
|
-
|
80
|
-
/**
|
81
|
-
* Sync changes to router state for the preview search param
|
82
|
-
*/
|
83
|
-
useEffect(() => {
|
84
|
-
actorRef.send({type: 'set preview search param', previewSearchParam})
|
85
|
-
}, [actorRef, previewSearchParam])
|
86
|
-
|
87
|
-
const error = useSelector(actorRef, (state) =>
|
88
|
-
// eslint-disable-next-line no-nested-ternary
|
89
|
-
state.status === 'error' ? state.error : state.hasTag('error') ? state.context.error : null,
|
90
|
-
)
|
91
|
-
|
92
|
-
// Propagate the error to the nearest error boundary
|
93
|
-
if (error) throw error
|
94
|
-
|
95
|
-
return actorRef
|
96
|
-
}
|