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.
Files changed (63) hide show
  1. package/lib/_chunks-cjs/PostMessageSchema.js.map +1 -1
  2. package/lib/_chunks-cjs/PostMessageTelemetry.js +1 -1
  3. package/lib/_chunks-cjs/PostMessageTelemetry.js.map +1 -1
  4. package/lib/_chunks-cjs/PresentationToolGrantsCheck.js +429 -1417
  5. package/lib/_chunks-cjs/PresentationToolGrantsCheck.js.map +1 -1
  6. package/lib/_chunks-cjs/presentation.js +70 -22
  7. package/lib/_chunks-cjs/presentation.js.map +1 -1
  8. package/lib/_chunks-cjs/resources6.js +0 -8
  9. package/lib/_chunks-cjs/resources6.js.map +1 -1
  10. package/lib/_chunks-cjs/version.js +1 -1
  11. package/lib/_chunks-es/PostMessageSchema.mjs.map +1 -1
  12. package/lib/_chunks-es/PostMessageTelemetry.mjs +1 -1
  13. package/lib/_chunks-es/PostMessageTelemetry.mjs.map +1 -1
  14. package/lib/_chunks-es/PresentationToolGrantsCheck.mjs +437 -1406
  15. package/lib/_chunks-es/PresentationToolGrantsCheck.mjs.map +1 -1
  16. package/lib/_chunks-es/presentation.mjs +73 -24
  17. package/lib/_chunks-es/presentation.mjs.map +1 -1
  18. package/lib/_chunks-es/resources6.mjs +0 -8
  19. package/lib/_chunks-es/resources6.mjs.map +1 -1
  20. package/lib/_chunks-es/version.mjs +1 -1
  21. package/lib/_singletons.d.mts +61 -2889
  22. package/lib/_singletons.d.ts +61 -2889
  23. package/lib/presentation.d.mts +57 -2887
  24. package/lib/presentation.d.ts +57 -2887
  25. package/lib/presentation.js +4 -0
  26. package/lib/presentation.js.map +1 -1
  27. package/lib/presentation.mjs +5 -1
  28. package/package.json +15 -16
  29. package/src/presentation/PostMessageTelemetry.tsx +1 -1
  30. package/src/presentation/PresentationTool.tsx +76 -85
  31. package/src/presentation/PresentationToolGrantsCheck.tsx +75 -39
  32. package/src/presentation/document/LocationsBanner.tsx +13 -52
  33. package/src/presentation/i18n/resources.ts +0 -10
  34. package/src/presentation/index.ts +13 -0
  35. package/src/presentation/{util → lib}/parse.ts +1 -2
  36. package/src/presentation/overlays/schema/PostMessageSchema.tsx +0 -1
  37. package/src/presentation/panels/usePanelsStorage.ts +1 -1
  38. package/src/presentation/preview/IFrame.tsx +35 -83
  39. package/src/presentation/preview/Preview.tsx +56 -172
  40. package/src/presentation/preview/PreviewHeader.tsx +10 -43
  41. package/src/presentation/preview/PreviewLocationInput.tsx +24 -48
  42. package/src/presentation/preview/SharePreviewMenu.tsx +2 -2
  43. package/src/presentation/reducers/presentationReducer.ts +134 -0
  44. package/src/presentation/types.ts +7 -139
  45. package/src/presentation/useMainDocument.ts +12 -4
  46. package/src/presentation/useParams.ts +3 -2
  47. package/src/presentation/usePreviewUrl.ts +133 -0
  48. package/src/presentation/actors/create-preview-secret.ts +0 -19
  49. package/src/presentation/actors/read-shared-secret.ts +0 -18
  50. package/src/presentation/actors/resolve-allow-patterns.ts +0 -55
  51. package/src/presentation/actors/resolve-initial-url.ts +0 -65
  52. package/src/presentation/actors/resolve-preview-mode-url.ts +0 -72
  53. package/src/presentation/actors/resolve-preview-mode.ts +0 -66
  54. package/src/presentation/actors/resolve-url-from-preview-search-param.ts +0 -29
  55. package/src/presentation/machines/presentation-machine.ts +0 -101
  56. package/src/presentation/machines/preview-url.ts +0 -568
  57. package/src/presentation/useAllowPatterns.ts +0 -12
  58. package/src/presentation/useId.ts +0 -7
  59. package/src/presentation/usePresentationPerspective.ts +0 -14
  60. package/src/presentation/usePreviewUrlActorRef.ts +0 -96
  61. package/src/presentation/useReportInvalidPreviewSearchParam.tsx +0 -43
  62. package/src/presentation/useTargetOrigin.ts +0 -11
  63. /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
- }