hydrogen-sanity 1.1.0 → 2.0.1
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/README.md +20 -18
- package/dist/index.d.ts +42 -47
- package/dist/index.js +1 -202
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +21 -21
- package/src/client.ts +22 -11
- package/src/preview/PreviewProvider.tsx +43 -0
- package/src/preview/PreviewSession.ts +54 -0
- package/src/preview/SanityPreview.tsx +55 -0
- package/src/preview/context.tsx +6 -0
- package/src/preview/getPreview.ts +12 -0
- package/src/preview/index.ts +5 -0
- package/dist/index.esm.js +0 -190
- package/dist/index.esm.js.map +0 -1
- package/src/preview.tsx +0 -177
package/README.md
CHANGED
|
@@ -63,6 +63,9 @@ export default () => {
|
|
|
63
63
|
? {
|
|
64
64
|
session: previewSession,
|
|
65
65
|
token: env.SANITY_API_TOKEN,
|
|
66
|
+
// Optionally, provide an alternative to the default `previewDrafts` perspective when in preview mode
|
|
67
|
+
// See https://www.sanity.io/docs/perspectives
|
|
68
|
+
// perspective: "raw"
|
|
66
69
|
}
|
|
67
70
|
: undefined,
|
|
68
71
|
// Pass configuration options for Sanity client
|
|
@@ -71,7 +74,7 @@ export default () => {
|
|
|
71
74
|
dataset: env.SANITY_DATASET,
|
|
72
75
|
apiVersion: env.SANITY_API_VERSION ?? '2023-03-30',
|
|
73
76
|
useCdn: process.env.NODE_ENV === 'production',
|
|
74
|
-
}
|
|
77
|
+
}
|
|
75
78
|
});
|
|
76
79
|
|
|
77
80
|
// 3. Add Sanity client to the request handler inside getLoadContext
|
|
@@ -176,16 +179,10 @@ First setup your root route to enable preview mode across the entire application
|
|
|
176
179
|
// ./app/root.tsx
|
|
177
180
|
|
|
178
181
|
// ...other imports
|
|
179
|
-
import {
|
|
182
|
+
import {PreviewProvider, getPreview} from 'hydrogen-sanity'
|
|
180
183
|
|
|
181
184
|
export async function loader({context}: LoaderArgs) {
|
|
182
|
-
const preview
|
|
183
|
-
? {
|
|
184
|
-
projectId: context.sanity.preview.projectId,
|
|
185
|
-
dataset: context.sanity.preview.dataset,
|
|
186
|
-
token: context.sanity.preview.token,
|
|
187
|
-
}
|
|
188
|
-
: undefined
|
|
185
|
+
const preview = getPreview(context)
|
|
189
186
|
|
|
190
187
|
return json({
|
|
191
188
|
// ... other loader data
|
|
@@ -205,8 +202,8 @@ export default function App() {
|
|
|
205
202
|
<Links />
|
|
206
203
|
</head>
|
|
207
204
|
<body>
|
|
208
|
-
{/* 👇 Wrap <Outlet /> in
|
|
209
|
-
<
|
|
205
|
+
{/* 👇 Wrap <Outlet /> in PreviewProvider component */}
|
|
206
|
+
<PreviewProvider {...preview}>
|
|
210
207
|
<Outlet />
|
|
211
208
|
</Preview>
|
|
212
209
|
<ScrollRestoration />
|
|
@@ -217,18 +214,20 @@ export default function App() {
|
|
|
217
214
|
}
|
|
218
215
|
```
|
|
219
216
|
|
|
220
|
-
|
|
217
|
+
`PreviewProvider` wraps the `LiveQueryProvider` component of `@sanity/preview-kit` - props passed to `PreviewProvider` will be passed to `LiveQueryProvider`. For more information, see the [`@sanity/preview-kit` documentation](https://github.com/sanity-io/preview-kit).
|
|
218
|
+
|
|
219
|
+
By default, `PreviewProvider` will passthrough rendering to its children if you don't provide a fallback; however you can also pass a `ReactNode` to render a loading indicator or message:
|
|
221
220
|
|
|
222
221
|
```tsx
|
|
223
222
|
import {PreviewLoading} from '~/components/PreviewLoading';
|
|
224
223
|
|
|
225
|
-
// pass a string or your own React component to show while data is loading
|
|
226
|
-
<
|
|
224
|
+
// (Optional) pass a string or your own React component to show while data is loading
|
|
225
|
+
<PreviewProvider {...preview} fallback={<PreviewLoading />}>
|
|
227
226
|
```
|
|
228
227
|
|
|
229
|
-
Next, for any route that needs to render a preview, wrap it in a `
|
|
228
|
+
Next, for any route that needs to render a preview, wrap it in a `SanityPreview` component which re-runs the same query client-side but will render draft content in place of published content, if it exists. Updating in real-time as changes are streamed in.
|
|
230
229
|
|
|
231
|
-
The
|
|
230
|
+
The component will be rendered with live preview if the preview session is found, otherwise, it renders the component with static content.
|
|
232
231
|
|
|
233
232
|
```tsx
|
|
234
233
|
// Any route file, such as ./app/routes/index.tsx
|
|
@@ -295,8 +294,11 @@ export const loader: LoaderFunction = async function ({request, context}) {
|
|
|
295
294
|
|
|
296
295
|
## Limits
|
|
297
296
|
|
|
298
|
-
The real-time preview
|
|
299
|
-
|
|
297
|
+
The real-time preview comes with a configured limit of 3000 documents. You can experiment with larger datasets by configuring `cache.maxDocuments: <Integer>` in your `PreviewProvider`. Be aware that this might affect the preview performance.
|
|
298
|
+
|
|
299
|
+
You can also use the `cache.includeTypes` option to reduce the amount of documents and reduce the risk of hitting the document limit.
|
|
300
|
+
|
|
301
|
+
If you're a Sanity Enterprise user with Content Source Maps enabled, you can optimize further by enabling `turboSourceMap` which opts-in to a faster and smarter cache. It'll only listen for mutations on the documents that you are using in your queries, and apply the mutations to the cache in real-time.
|
|
300
302
|
|
|
301
303
|
## Using `@sanity/client` directly
|
|
302
304
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
|
|
1
3
|
import type {CacheShort} from '@shopify/hydrogen'
|
|
2
4
|
import {ClientConfig} from '@sanity/client'
|
|
3
|
-
import {
|
|
5
|
+
import {ClientPerspective} from '@sanity/client'
|
|
4
6
|
import {JSX as JSX_2} from 'react/jsx-runtime'
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
+
import type {LiveQueryProviderProps} from '@sanity/preview-kit'
|
|
8
|
+
import {QueryParams} from '@sanity/client'
|
|
7
9
|
import {ReactNode} from 'react'
|
|
8
10
|
import {SanityClient} from '@sanity/client'
|
|
9
11
|
import {Session} from '@shopify/remix-oxygen'
|
|
@@ -22,6 +24,7 @@ declare type CreateSanityClientOptions = EnvironmentOptions & {
|
|
|
22
24
|
preview?: {
|
|
23
25
|
session: PreviewSession
|
|
24
26
|
token: string
|
|
27
|
+
perspective?: ClientPerspective
|
|
25
28
|
}
|
|
26
29
|
}
|
|
27
30
|
|
|
@@ -42,38 +45,40 @@ declare interface ExecutionContext {
|
|
|
42
45
|
waitUntil(promise: Promise<any>): void
|
|
43
46
|
}
|
|
44
47
|
|
|
48
|
+
/** TODO: inline documentation */
|
|
49
|
+
export declare function getPreview<
|
|
50
|
+
T extends {
|
|
51
|
+
sanity: Sanity
|
|
52
|
+
}
|
|
53
|
+
>(context: T): ClientConfig | undefined
|
|
54
|
+
|
|
45
55
|
export declare function isPreviewModeEnabled(preview?: Sanity['preview']): preview is {
|
|
46
56
|
session: PreviewSession
|
|
47
|
-
} & PreviewData
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Conditionally apply `PreviewSuspense` boundary
|
|
51
|
-
* @see https://www.sanity.io/docs/preview-content-on-site
|
|
52
|
-
*/
|
|
53
|
-
export declare function Preview(props: PreviewProps): JSX_2.Element
|
|
54
|
-
|
|
55
|
-
export declare type PreviewData = {
|
|
56
57
|
projectId: string
|
|
57
58
|
dataset: string
|
|
58
59
|
token: string
|
|
59
60
|
}
|
|
60
61
|
|
|
61
|
-
declare type
|
|
62
|
+
declare type PreviewProps<T> = {
|
|
62
63
|
data: T
|
|
63
|
-
children: ReactNode | ((data
|
|
64
|
+
children: ReactNode | ((data?: T | null) => ReactNode)
|
|
64
65
|
query?: string | null
|
|
65
|
-
params?:
|
|
66
|
+
params?: QueryParams
|
|
66
67
|
}
|
|
67
68
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
69
|
+
/**
|
|
70
|
+
* TODO: inline documentation
|
|
71
|
+
* @see https://www.sanity.io/docs/preview-content-on-site
|
|
72
|
+
*/
|
|
73
|
+
export declare function PreviewProvider(
|
|
74
|
+
props: SanityPreviewProps
|
|
75
|
+
): string | number | boolean | Iterable<ReactNode> | JSX_2.Element | null | undefined
|
|
73
76
|
|
|
77
|
+
/**
|
|
78
|
+
* TODO: needs inline documentation
|
|
79
|
+
*/
|
|
74
80
|
export declare class PreviewSession {
|
|
75
|
-
private
|
|
76
|
-
private session
|
|
81
|
+
#private
|
|
77
82
|
constructor(sessionStorage: SessionStorage, session: Session)
|
|
78
83
|
static init(request: Request, secrets: string[]): Promise<PreviewSession>
|
|
79
84
|
has(key: string): boolean
|
|
@@ -85,9 +90,12 @@ export declare class PreviewSession {
|
|
|
85
90
|
export declare type Sanity = {
|
|
86
91
|
client: SanityClient
|
|
87
92
|
preview?:
|
|
88
|
-
|
|
|
93
|
+
| {
|
|
89
94
|
session: PreviewSession
|
|
90
|
-
|
|
95
|
+
projectId: string
|
|
96
|
+
dataset: string
|
|
97
|
+
token: string
|
|
98
|
+
}
|
|
91
99
|
| {
|
|
92
100
|
session: PreviewSession
|
|
93
101
|
}
|
|
@@ -101,8 +109,13 @@ export declare type Sanity = {
|
|
|
101
109
|
* changes will be streamed in the client
|
|
102
110
|
*/
|
|
103
111
|
export declare function SanityPreview<T = unknown>(
|
|
104
|
-
props:
|
|
105
|
-
): string | number | boolean |
|
|
112
|
+
props: PreviewProps<T>
|
|
113
|
+
): string | number | boolean | Iterable<ReactNode> | JSX_2.Element | null | undefined
|
|
114
|
+
|
|
115
|
+
declare type SanityPreviewProps = Omit<LiveQueryProviderProps, 'client'> & {
|
|
116
|
+
fallback?: ReactNode
|
|
117
|
+
previewConfig?: ClientConfig
|
|
118
|
+
}
|
|
106
119
|
|
|
107
120
|
/**
|
|
108
121
|
* Create an SHA-256 hash as a hex string
|
|
@@ -110,34 +123,16 @@ export declare function SanityPreview<T = unknown>(
|
|
|
110
123
|
*/
|
|
111
124
|
export declare function sha256(message: string): Promise<string>
|
|
112
125
|
|
|
113
|
-
|
|
114
|
-
query: Q,
|
|
115
|
-
params?: P,
|
|
116
|
-
serverSnapshot?: R
|
|
117
|
-
) => R
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Select and memoize which component to render based on preview mode
|
|
121
|
-
* @deprecated use `SanityPreview` instead
|
|
122
|
-
*/
|
|
123
|
-
export declare function usePreviewComponent<T>(
|
|
124
|
-
component: ElementType<T>,
|
|
125
|
-
preview: ElementType<T>
|
|
126
|
-
): ElementType<T>
|
|
127
|
-
|
|
126
|
+
/** TODO: needs inline documentation */
|
|
128
127
|
export declare const usePreviewContext: () =>
|
|
129
128
|
| {
|
|
130
|
-
|
|
131
|
-
* Query Sanity and subscribe to changes, optionally
|
|
132
|
-
* passing a server snapshot to speed up hydration
|
|
133
|
-
*/
|
|
134
|
-
usePreview: UsePreview
|
|
129
|
+
projectId: string
|
|
135
130
|
}
|
|
136
131
|
| undefined
|
|
137
132
|
|
|
138
133
|
declare type useSanityQuery = {
|
|
139
134
|
query: string
|
|
140
|
-
params?:
|
|
135
|
+
params?: QueryParams
|
|
141
136
|
cache?: CachingStrategy
|
|
142
137
|
}
|
|
143
138
|
|
package/dist/index.js
CHANGED
|
@@ -1,202 +1 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, '__esModule', {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
var client = require('@sanity/client');
|
|
7
|
-
var hydrogen = require('@shopify/hydrogen');
|
|
8
|
-
var jsxRuntime = require('react/jsx-runtime');
|
|
9
|
-
var previewKit = require('@sanity/preview-kit');
|
|
10
|
-
var remixOxygen = require('@shopify/remix-oxygen');
|
|
11
|
-
var react = require('react');
|
|
12
|
-
function createSanityClient(options) {
|
|
13
|
-
const {
|
|
14
|
-
cache,
|
|
15
|
-
waitUntil,
|
|
16
|
-
preview,
|
|
17
|
-
config
|
|
18
|
-
} = options;
|
|
19
|
-
const withCache = hydrogen.createWithCache_unstable({
|
|
20
|
-
cache,
|
|
21
|
-
waitUntil
|
|
22
|
-
});
|
|
23
|
-
const sanity = {
|
|
24
|
-
client: client.createClient(config),
|
|
25
|
-
async query(_ref) {
|
|
26
|
-
let {
|
|
27
|
-
query,
|
|
28
|
-
params,
|
|
29
|
-
cache: strategy = hydrogen.CacheLong()
|
|
30
|
-
} = _ref;
|
|
31
|
-
const queryHash = await hashQuery(query, params);
|
|
32
|
-
return withCache(queryHash, strategy, () => sanity.client.fetch(query, params));
|
|
33
|
-
}
|
|
34
|
-
};
|
|
35
|
-
if (preview) {
|
|
36
|
-
sanity.preview = {
|
|
37
|
-
session: preview.session
|
|
38
|
-
};
|
|
39
|
-
if (preview.session.has("projectId")) {
|
|
40
|
-
sanity.preview = {
|
|
41
|
-
...sanity.preview,
|
|
42
|
-
projectId: config.projectId,
|
|
43
|
-
dataset: config.dataset,
|
|
44
|
-
token: preview.token
|
|
45
|
-
};
|
|
46
|
-
sanity.client = sanity.client.withConfig({
|
|
47
|
-
useCdn: false,
|
|
48
|
-
token: preview.token
|
|
49
|
-
});
|
|
50
|
-
sanity.query = _ref2 => {
|
|
51
|
-
let {
|
|
52
|
-
query,
|
|
53
|
-
params
|
|
54
|
-
} = _ref2;
|
|
55
|
-
return sanity.client.fetch(query, params);
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
return sanity;
|
|
60
|
-
}
|
|
61
|
-
function isPreviewModeEnabled(preview) {
|
|
62
|
-
return preview && preview.token !== null;
|
|
63
|
-
}
|
|
64
|
-
async function sha256(message) {
|
|
65
|
-
const messageBuffer = await new TextEncoder().encode(message);
|
|
66
|
-
const hashBuffer = await crypto.subtle.digest("SHA-256", messageBuffer);
|
|
67
|
-
return Array.from(new Uint8Array(hashBuffer)).map(b => b.toString(16).padStart(2, "0")).join("");
|
|
68
|
-
}
|
|
69
|
-
function hashQuery(query, params) {
|
|
70
|
-
let hash = query;
|
|
71
|
-
if (params !== null) {
|
|
72
|
-
hash += JSON.stringify(params);
|
|
73
|
-
}
|
|
74
|
-
return sha256(hash);
|
|
75
|
-
}
|
|
76
|
-
class PreviewSession {
|
|
77
|
-
// eslint-disable-next-line no-useless-constructor, no-empty-function
|
|
78
|
-
constructor(sessionStorage, session) {
|
|
79
|
-
this.sessionStorage = sessionStorage;
|
|
80
|
-
this.session = session;
|
|
81
|
-
}
|
|
82
|
-
static async init(request, secrets) {
|
|
83
|
-
const storage = remixOxygen.createCookieSessionStorage({
|
|
84
|
-
cookie: {
|
|
85
|
-
name: "__preview",
|
|
86
|
-
httpOnly: true,
|
|
87
|
-
sameSite: true,
|
|
88
|
-
secrets
|
|
89
|
-
}
|
|
90
|
-
});
|
|
91
|
-
const session = await storage.getSession(request.headers.get("Cookie"));
|
|
92
|
-
return new this(storage, session);
|
|
93
|
-
}
|
|
94
|
-
has(key) {
|
|
95
|
-
return this.session.has(key);
|
|
96
|
-
}
|
|
97
|
-
// get(key: string) {
|
|
98
|
-
// return this.session.get(key);
|
|
99
|
-
// }
|
|
100
|
-
destroy() {
|
|
101
|
-
return this.sessionStorage.destroySession(this.session);
|
|
102
|
-
}
|
|
103
|
-
// unset(key: string) {
|
|
104
|
-
// this.session.unset(key);
|
|
105
|
-
// }
|
|
106
|
-
set(key, value) {
|
|
107
|
-
this.session.set(key, value);
|
|
108
|
-
}
|
|
109
|
-
commit() {
|
|
110
|
-
return this.sessionStorage.commitSession(this.session);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
const PreviewContext = react.createContext(void 0);
|
|
114
|
-
const usePreviewContext = () => react.useContext(PreviewContext);
|
|
115
|
-
function Preview(props) {
|
|
116
|
-
var _a;
|
|
117
|
-
const {
|
|
118
|
-
children,
|
|
119
|
-
preview
|
|
120
|
-
} = props;
|
|
121
|
-
if (!(preview == null ? void 0 : preview.token)) {
|
|
122
|
-
return /* @__PURE__ */jsxRuntime.jsx(jsxRuntime.Fragment, {
|
|
123
|
-
children
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
const fallback = (_a = props.fallback) != null ? _a : /* @__PURE__ */jsxRuntime.jsx("div", {
|
|
127
|
-
children: "Loading preview..."
|
|
128
|
-
});
|
|
129
|
-
const {
|
|
130
|
-
projectId,
|
|
131
|
-
dataset,
|
|
132
|
-
token
|
|
133
|
-
} = preview;
|
|
134
|
-
const _usePreview = previewKit.definePreview({
|
|
135
|
-
projectId,
|
|
136
|
-
dataset,
|
|
137
|
-
overlayDrafts: true
|
|
138
|
-
});
|
|
139
|
-
function usePreview(query, params, serverSnapshot) {
|
|
140
|
-
return _usePreview(token, query, params, serverSnapshot);
|
|
141
|
-
}
|
|
142
|
-
return /* @__PURE__ */jsxRuntime.jsx(PreviewContext.Provider, {
|
|
143
|
-
value: {
|
|
144
|
-
usePreview
|
|
145
|
-
},
|
|
146
|
-
children: /* @__PURE__ */jsxRuntime.jsx(previewKit.PreviewSuspense, {
|
|
147
|
-
fallback,
|
|
148
|
-
children
|
|
149
|
-
})
|
|
150
|
-
});
|
|
151
|
-
}
|
|
152
|
-
function usePreviewComponent(component, preview) {
|
|
153
|
-
const isPreview = Boolean(usePreviewContext());
|
|
154
|
-
return react.useMemo(() => isPreview ? preview : component, [component, isPreview, preview]);
|
|
155
|
-
}
|
|
156
|
-
function SanityPreview(props) {
|
|
157
|
-
const {
|
|
158
|
-
data,
|
|
159
|
-
children,
|
|
160
|
-
query,
|
|
161
|
-
params
|
|
162
|
-
} = props;
|
|
163
|
-
const isPreview = Boolean(usePreviewContext());
|
|
164
|
-
if (typeof children !== "function") {
|
|
165
|
-
return children;
|
|
166
|
-
}
|
|
167
|
-
if (isPreview && query) {
|
|
168
|
-
return /* @__PURE__ */jsxRuntime.jsx(ResolvePreview, {
|
|
169
|
-
query,
|
|
170
|
-
params,
|
|
171
|
-
serverSnapshot: data,
|
|
172
|
-
children
|
|
173
|
-
});
|
|
174
|
-
}
|
|
175
|
-
return /* @__PURE__ */jsxRuntime.jsx(jsxRuntime.Fragment, {
|
|
176
|
-
children: children(data)
|
|
177
|
-
});
|
|
178
|
-
}
|
|
179
|
-
function ResolvePreview(props) {
|
|
180
|
-
const {
|
|
181
|
-
serverSnapshot,
|
|
182
|
-
query,
|
|
183
|
-
params,
|
|
184
|
-
children
|
|
185
|
-
} = props;
|
|
186
|
-
const {
|
|
187
|
-
usePreview
|
|
188
|
-
} = usePreviewContext();
|
|
189
|
-
const data = usePreview(query, params, serverSnapshot);
|
|
190
|
-
return /* @__PURE__ */jsxRuntime.jsx(jsxRuntime.Fragment, {
|
|
191
|
-
children: children(data)
|
|
192
|
-
});
|
|
193
|
-
}
|
|
194
|
-
exports.Preview = Preview;
|
|
195
|
-
exports.PreviewSession = PreviewSession;
|
|
196
|
-
exports.SanityPreview = SanityPreview;
|
|
197
|
-
exports.createSanityClient = createSanityClient;
|
|
198
|
-
exports.isPreviewModeEnabled = isPreviewModeEnabled;
|
|
199
|
-
exports.sha256 = sha256;
|
|
200
|
-
exports.usePreviewComponent = usePreviewComponent;
|
|
201
|
-
exports.usePreviewContext = usePreviewContext;
|
|
202
|
-
//# sourceMappingURL=index.js.map
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("@sanity/client"),t=require("@shopify/hydrogen"),r=require("react"),i=require("react/jsx-runtime"),n=require("@shopify/remix-oxygen"),s=require("@sanity/preview-kit");function a(e){return Boolean(e&&e.token&&null!==e.token)}async function o(e){const t=await(new TextEncoder).encode(e),r=await crypto.subtle.digest("SHA-256",t);return Array.from(new Uint8Array(r)).map((e=>e.toString(16).padStart(2,"0"))).join("")}const c=r.createContext(void 0),u=()=>r.useContext(c);const l=r.lazy((()=>import("@sanity/preview-kit").then((e=>({default:e.LiveQueryProvider})))));var p,d,h=(e,t,r)=>{if(!t.has(e))throw TypeError("Cannot "+r)},y=(e,t,r)=>(h(e,t,"read from private field"),r?r.call(e):t.get(e)),f=(e,t,r)=>{if(t.has(e))throw TypeError("Cannot add the same private member more than once");t instanceof WeakSet?t.add(e):t.set(e,r)},v=(e,t,r,i)=>(h(e,t,"write to private field"),i?i.call(e,r):t.set(e,r),r);function w(e){const{initialData:t,query:r,params:n,children:a}=e,[o]=s.useLiveQuery(t,r,n);return i.jsx(i.Fragment,{children:a(o)})}p=new WeakMap,d=new WeakMap,exports.PreviewProvider=function(t){const{children:n,previewConfig:s,fallback:a=n,...o}=t,[,u]=r.useTransition(),[p,d]=r.useState(!1);if(r.useEffect((()=>u((()=>d(!0)))),[]),!p||!s||!s.projectId)return n;const h=e.createClient(s);return i.jsx(c.Provider,{value:{projectId:s.projectId},children:i.jsx(r.Suspense,{fallback:a,children:i.jsx(l,{...o,client:h,children:n})})})},exports.PreviewSession=class{constructor(e,t){f(this,p,void 0),f(this,d,void 0),v(this,p,e),v(this,d,t)}static async init(e,t){const r=n.createCookieSessionStorage({cookie:{name:"__preview",httpOnly:!0,sameSite:!0,secrets:t}}),i=await r.getSession(e.headers.get("Cookie"));return new this(r,i)}has(e){return y(this,d).has(e)}destroy(){return y(this,p).destroySession(y(this,d))}set(e,t){y(this,d).set(e,t)}commit(){return y(this,p).commitSession(y(this,d))}},exports.SanityPreview=function(e){const{data:t,children:r,query:n,params:s}=e,a=Boolean(u());return"function"!=typeof r?r:a&&n?i.jsx(w,{query:n,params:s,initialData:t,children:r}):i.jsx(i.Fragment,{children:r(t)})},exports.createSanityClient=function(r){const{cache:i,waitUntil:n,preview:s,config:a}=r,c={client:e.createClient(a),async query(e){let{query:r,params:s,cache:a=t.CacheLong()}=e;const u=await function(e,t){let r=e;null!==t&&(r+=JSON.stringify(t));return o(r)}(r,s);return t.createWithCache_unstable({cache:i,waitUntil:n})(u,a,(()=>c.client.fetch(r,s)))}};return s&&(c.preview={session:s.session},s.session.has("projectId")&&(c.preview={...c.preview,projectId:a.projectId,dataset:a.dataset,token:s.token},c.client=c.client.withConfig({useCdn:!1,token:s.token,perspective:s.perspective||"previewDrafts",ignoreBrowserTokenWarning:!0}),c.query=e=>{let{query:t,params:r}=e;return c.client.fetch(t,r)})),c},exports.getPreview=function(e){return a(e.sanity.preview)?{...e.sanity.client.config()}:void 0},exports.isPreviewModeEnabled=a,exports.sha256=o,exports.usePreviewContext=u;//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/client.ts","../src/preview.tsx"],"sourcesContent":["import {type ClientConfig, createClient, type SanityClient} from '@sanity/client'\n// eslint-disable-next-line camelcase\nimport {CacheLong, createWithCache_unstable} from '@shopify/hydrogen'\n\nimport type {PreviewData, PreviewSession} from './preview'\nimport type {CachingStrategy, EnvironmentOptions} from './types'\n\ntype CreateSanityClientOptions = EnvironmentOptions & {\n config: ClientConfig & Required<Pick<ClientConfig, 'projectId' | 'dataset'>>\n preview?: {\n session: PreviewSession\n token: string\n }\n}\n\ntype useSanityQuery = {\n query: string\n params?: Record<string, unknown>\n cache?: CachingStrategy\n}\n\nexport type Sanity = {\n client: SanityClient\n preview?: ({session: PreviewSession} & PreviewData) | {session: PreviewSession}\n query<T>(options: useSanityQuery): Promise<T>\n}\n\n/**\n * Create Sanity provider with API client.\n */\nexport function createSanityClient(options: CreateSanityClientOptions): Sanity {\n const {cache, waitUntil, preview, config} = options\n const withCache = createWithCache_unstable({\n cache,\n waitUntil,\n })\n\n const sanity: Sanity = {\n client: createClient(config),\n async query({query, params, cache: strategy = CacheLong()}) {\n const queryHash = await hashQuery(query, params)\n\n return withCache(queryHash, strategy, () => sanity.client.fetch(query, params))\n },\n }\n\n if (preview) {\n sanity.preview = {session: preview.session}\n\n if (preview.session.has('projectId')) {\n sanity.preview = {\n ...sanity.preview,\n projectId: config.projectId,\n dataset: config.dataset,\n token: preview.token,\n }\n\n sanity.client = sanity.client.withConfig({\n useCdn: false,\n token: preview.token,\n })\n\n sanity.query = ({query, params}) => {\n return sanity.client.fetch(query, params)\n }\n }\n }\n\n return sanity\n}\n\nexport function isPreviewModeEnabled(\n preview?: Sanity['preview']\n): preview is {session: PreviewSession} & PreviewData {\n // @ts-expect-error\n return preview && preview.token !== null\n}\n\n/**\n * Create an SHA-256 hash as a hex string\n * @see https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest#converting_a_digest_to_a_hex_string\n */\nexport async function sha256(message: string): Promise<string> {\n // encode as UTF-8\n const messageBuffer = await new TextEncoder().encode(message)\n // hash the message\n const hashBuffer = await crypto.subtle.digest('SHA-256', messageBuffer)\n // convert bytes to hex string\n return Array.from(new Uint8Array(hashBuffer))\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('')\n}\n\n/**\n * Hash query and its parameters for use as cache key\n * NOTE: Oxygen deployment will break if the cache key is long or contains `\\n`\n */\nfunction hashQuery(\n query: useSanityQuery['query'],\n params: useSanityQuery['params']\n): Promise<string> {\n let hash = query\n\n if (params !== null) {\n hash += JSON.stringify(params)\n }\n\n return sha256(hash)\n}\n","/* eslint-disable react/require-default-props */\nimport {definePreview, type Params, PreviewSuspense} from '@sanity/preview-kit'\nimport {createCookieSessionStorage, type Session, type SessionStorage} from '@shopify/remix-oxygen'\nimport {createContext, ElementType, type ReactNode, useContext, useMemo} from 'react'\n\ntype UsePreview = <R = any, P extends Params = Params, Q extends string = string>(\n query: Q,\n params?: P,\n serverSnapshot?: R\n) => R\n\nexport type PreviewData = {\n projectId: string\n dataset: string\n token: string\n}\n\nexport type PreviewProps = {\n children: ReactNode\n fallback?: ReactNode\n preview?: PreviewData\n}\n\nexport class PreviewSession {\n // eslint-disable-next-line no-useless-constructor, no-empty-function\n constructor(private sessionStorage: SessionStorage, private session: Session) {}\n\n static async init(request: Request, secrets: string[]) {\n const storage = createCookieSessionStorage({\n cookie: {\n name: '__preview',\n httpOnly: true,\n sameSite: true,\n secrets,\n },\n })\n\n const session = await storage.getSession(request.headers.get('Cookie'))\n\n return new this(storage, session)\n }\n\n has(key: string) {\n return this.session.has(key)\n }\n\n // get(key: string) {\n // return this.session.get(key);\n // }\n\n destroy() {\n return this.sessionStorage.destroySession(this.session)\n }\n\n // unset(key: string) {\n // this.session.unset(key);\n // }\n\n set(key: string, value: any) {\n this.session.set(key, value)\n }\n\n commit() {\n return this.sessionStorage.commitSession(this.session)\n }\n}\n\nconst PreviewContext = createContext<\n | {\n /**\n * Query Sanity and subscribe to changes, optionally\n * passing a server snapshot to speed up hydration\n */\n usePreview: UsePreview\n }\n | undefined\n>(undefined)\n\nexport const usePreviewContext = () => useContext(PreviewContext)\n\n/**\n * Conditionally apply `PreviewSuspense` boundary\n * @see https://www.sanity.io/docs/preview-content-on-site\n */\nexport function Preview(props: PreviewProps) {\n const {children, preview} = props\n\n if (!preview?.token) {\n return <>{children}</>\n }\n\n const fallback = props.fallback ?? <div>Loading preview...</div>\n const {projectId, dataset, token} = preview\n const _usePreview = definePreview({\n projectId,\n dataset,\n overlayDrafts: true,\n })\n\n function usePreview<R = any, P extends Params = Params, Q extends string = string>(\n query: Q,\n params?: P,\n serverSnapshot?: R\n ): R {\n return _usePreview(token, query, params, serverSnapshot)\n }\n usePreview satisfies UsePreview\n\n return (\n <PreviewContext.Provider value={{usePreview}}>\n <PreviewSuspense fallback={fallback}>{children}</PreviewSuspense>\n </PreviewContext.Provider>\n )\n}\n\n/**\n * Select and memoize which component to render based on preview mode\n * @deprecated use `SanityPreview` instead\n */\nexport function usePreviewComponent<T>(component: ElementType<T>, preview: ElementType<T>) {\n const isPreview = Boolean(usePreviewContext())\n\n return useMemo(() => (isPreview ? preview : component), [component, isPreview, preview])\n}\n\ntype PreviewDataProps<T> = {\n data: T\n children: ReactNode | ((data: T | null) => ReactNode)\n query?: string | null\n params?: Params\n}\n\n/**\n * Component to use for rendering in preview mode\n *\n * When provided a Sanity query and render prop,\n * changes will be streamed in the client\n */\nexport function SanityPreview<T = unknown>(props: PreviewDataProps<T>) {\n const {data, children, query, params} = props\n const isPreview = Boolean(usePreviewContext())\n\n if (typeof children !== 'function') {\n return children\n }\n\n if (isPreview && query) {\n return (\n <ResolvePreview<typeof data> query={query} params={params} serverSnapshot={data}>\n {children}\n </ResolvePreview>\n )\n }\n\n return <>{children(data)}</>\n}\n\ntype ResolvePreviewProps<T> = {\n serverSnapshot?: T | null\n query: string\n params?: Params\n children: (data: T | null) => ReactNode\n}\n\n/**\n * Subscribe to live preview and delegate rendering to consumer\n */\nfunction ResolvePreview<T = unknown>(props: ResolvePreviewProps<T>) {\n const {serverSnapshot, query, params, children} = props\n // This won't break the conditional rule of hooks,\n // **but** it relies on the assumption that this component\n // will only be used in preview mode 👇🏻\n const {usePreview} = usePreviewContext()!\n const data = usePreview(query, params, serverSnapshot)\n\n return <>{children(data)}</>\n}\n"],"names":["createSanityClient","options","cache","waitUntil","preview","config","withCache","createWithCache_unstable","sanity","client","createClient","query","params","strategy","CacheLong","_ref","queryHash","hashQuery","fetch","session","has","projectId","dataset","token","withConfig","useCdn","_ref2","isPreviewModeEnabled","sha256","message","messageBuffer","TextEncoder","encode","hashBuffer","crypto","subtle","digest","Array","from","Uint8Array","map","b","toString","padStart","join","hash","JSON","stringify","PreviewSession","constructor","sessionStorage","init","request","secrets","storage","createCookieSessionStorage","cookie","name","httpOnly","sameSite","getSession","headers","get","key","destroy","destroySession","set","value","commit","commitSession","PreviewContext","createContext","usePreviewContext","useContext","Preview","props","_a","children","fallback","jsx","_usePreview","definePreview","overlayDrafts","usePreview","serverSnapshot","Provider","PreviewSuspense","usePreviewComponent","component","isPreview","Boolean","useMemo","SanityPreview","data","ResolvePreview","Fragment"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/client.ts","../src/preview/context.tsx","../src/preview/PreviewProvider.tsx","../src/preview/PreviewSession.ts","../src/preview/SanityPreview.tsx","../src/preview/getPreview.ts"],"sourcesContent":["import {\n type ClientConfig,\n type ClientPerspective,\n createClient,\n type QueryParams,\n type SanityClient,\n} from '@sanity/client'\n// eslint-disable-next-line camelcase\nimport {CacheLong, createWithCache_unstable} from '@shopify/hydrogen'\n\nimport type {PreviewSession} from './preview'\nimport type {CachingStrategy, EnvironmentOptions} from './types'\n\ntype CreateSanityClientOptions = EnvironmentOptions & {\n config: ClientConfig & Required<Pick<ClientConfig, 'projectId' | 'dataset'>>\n preview?: {\n session: PreviewSession\n token: string\n perspective?: ClientPerspective\n }\n}\n\ntype useSanityQuery = {\n query: string\n params?: QueryParams\n cache?: CachingStrategy\n}\n\nexport type Sanity = {\n client: SanityClient\n preview?:\n | {session: PreviewSession; projectId: string; dataset: string; token: string}\n | {session: PreviewSession}\n query<T>(options: useSanityQuery): Promise<T>\n}\n\n/**\n * Create Sanity provider with API client.\n */\nexport function createSanityClient(options: CreateSanityClientOptions): Sanity {\n const {cache, waitUntil, preview, config} = options\n\n const sanity: Sanity = {\n client: createClient(config),\n async query<T = any>({query, params, cache: strategy = CacheLong()}: useSanityQuery) {\n const queryHash = await hashQuery(query, params)\n const withCache = createWithCache_unstable<T>({\n cache,\n waitUntil,\n })\n\n return withCache(queryHash, strategy, () => sanity.client.fetch(query, params))\n },\n }\n\n if (preview) {\n sanity.preview = {session: preview.session}\n\n if (preview.session.has('projectId')) {\n sanity.preview = {\n ...sanity.preview,\n projectId: config.projectId,\n dataset: config.dataset,\n token: preview.token,\n }\n\n sanity.client = sanity.client.withConfig({\n useCdn: false,\n token: preview.token,\n perspective: preview.perspective || 'previewDrafts',\n ignoreBrowserTokenWarning: true,\n })\n\n sanity.query = ({query, params}) => {\n return sanity.client.fetch(query, params)\n }\n }\n }\n\n return sanity\n}\n\nexport function isPreviewModeEnabled(\n preview?: Sanity['preview']\n): preview is {session: PreviewSession; projectId: string; dataset: string; token: string} {\n // @ts-expect-error\n return Boolean(preview && preview.token && preview.token !== null)\n}\n\n/**\n * Create an SHA-256 hash as a hex string\n * @see https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest#converting_a_digest_to_a_hex_string\n */\nexport async function sha256(message: string): Promise<string> {\n // encode as UTF-8\n const messageBuffer = await new TextEncoder().encode(message)\n // hash the message\n const hashBuffer = await crypto.subtle.digest('SHA-256', messageBuffer)\n // convert bytes to hex string\n return Array.from(new Uint8Array(hashBuffer))\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('')\n}\n\n/**\n * Hash query and its parameters for use as cache key\n * NOTE: Oxygen deployment will break if the cache key is long or contains `\\n`\n */\nfunction hashQuery(\n query: useSanityQuery['query'],\n params: useSanityQuery['params']\n): Promise<string> {\n let hash = query\n\n if (params !== null) {\n hash += JSON.stringify(params)\n }\n\n return sha256(hash)\n}\n","import {createContext, useContext} from 'react'\n\nexport const PreviewContext = createContext<{projectId: string} | undefined>(undefined)\n\n/** TODO: needs inline documentation */\nexport const usePreviewContext = () => useContext(PreviewContext)\n","/* eslint-disable react/require-default-props */\nimport {type ClientConfig, createClient} from '@sanity/client'\nimport type {LiveQueryProviderProps} from '@sanity/preview-kit'\nimport {lazy, type ReactNode, Suspense, useEffect, useState, useTransition} from 'react'\n\nimport {PreviewContext} from './context'\n\nconst LiveQueryProvider = lazy(() =>\n import('@sanity/preview-kit').then((m) => ({default: m.LiveQueryProvider}))\n)\n\ntype SanityPreviewProps = Omit<LiveQueryProviderProps, 'client'> & {\n fallback?: ReactNode\n previewConfig?: ClientConfig\n}\n\n/**\n * TODO: inline documentation\n * @see https://www.sanity.io/docs/preview-content-on-site\n */\nexport function PreviewProvider(props: SanityPreviewProps) {\n const {children, previewConfig, fallback = children, ...rest} = props\n\n const [, startTransition] = useTransition()\n const [hydrated, setHydrated] = useState(false)\n useEffect(() => startTransition(() => setHydrated(true)), [])\n\n if (!hydrated || !previewConfig || !previewConfig.projectId) {\n return children\n }\n\n const client = createClient(previewConfig)\n\n return (\n <PreviewContext.Provider value={{projectId: previewConfig.projectId}}>\n <Suspense fallback={fallback}>\n <LiveQueryProvider {...rest} client={client}>\n {children}\n </LiveQueryProvider>\n </Suspense>\n </PreviewContext.Provider>\n )\n}\n","import {createCookieSessionStorage, type Session, type SessionStorage} from '@shopify/remix-oxygen'\n\n/**\n * TODO: needs inline documentation\n */\nexport class PreviewSession {\n #sessionStorage: SessionStorage\n #session: Session\n\n constructor(sessionStorage: SessionStorage, session: Session) {\n this.#sessionStorage = sessionStorage\n this.#session = session\n }\n\n static async init(request: Request, secrets: string[]): Promise<PreviewSession> {\n const storage = createCookieSessionStorage({\n cookie: {\n name: '__preview',\n httpOnly: true,\n sameSite: true,\n secrets,\n },\n })\n\n const session = await storage.getSession(request.headers.get('Cookie'))\n\n return new this(storage, session)\n }\n\n has(key: string): boolean {\n return this.#session.has(key)\n }\n\n // get(key: string) {\n // return this.session.get(key);\n // }\n\n destroy(): Promise<string> {\n return this.#sessionStorage.destroySession(this.#session)\n }\n\n // unset(key: string) {\n // this.session.unset(key);\n // }\n\n // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types\n set(key: string, value: any): void {\n this.#session.set(key, value)\n }\n\n commit(): Promise<string> {\n return this.#sessionStorage.commitSession(this.#session)\n }\n}\n","/* eslint-disable react/require-default-props */\nimport type {QueryParams} from '@sanity/client'\nimport {useLiveQuery} from '@sanity/preview-kit'\nimport {type ReactNode} from 'react'\n\nimport {usePreviewContext} from './context'\n\ntype PreviewProps<T> = {\n data: T\n children: ReactNode | ((data?: T | null) => ReactNode)\n query?: string | null\n params?: QueryParams\n}\n\n/**\n * Component to use for rendering in preview mode\n *\n * When provided a Sanity query and render prop,\n * changes will be streamed in the client\n */\nexport function SanityPreview<T = unknown>(props: PreviewProps<T>) {\n const {data, children, query, params} = props\n const isPreview = Boolean(usePreviewContext())\n\n if (typeof children !== 'function') {\n return children\n }\n\n if (isPreview && query) {\n return (\n <ResolvePreview<typeof data> query={query} params={params} initialData={data}>\n {children}\n </ResolvePreview>\n )\n }\n\n return <>{children(data)}</>\n}\n\ntype ResolvePreviewProps<T> = {\n initialData?: T | null\n query: string\n params?: QueryParams\n children: (data?: T | null) => ReactNode\n}\n\n/**\n * Subscribe to live preview and delegate rendering to consumer\n */\nfunction ResolvePreview<T = unknown>(props: ResolvePreviewProps<T>) {\n const {initialData, query, params, children} = props\n const [data] = useLiveQuery(initialData, query, params)\n\n return <>{children(data)}</>\n}\n","import type {ClientConfig} from '@sanity/client'\n\nimport {isPreviewModeEnabled, Sanity} from '../client'\n\n/** TODO: inline documentation */\nexport function getPreview<T extends {sanity: Sanity}>(context: T): ClientConfig | undefined {\n return isPreviewModeEnabled(context.sanity.preview)\n ? {\n ...context.sanity.client.config(),\n }\n : undefined\n}\n"],"names":["isPreviewModeEnabled","preview","Boolean","token","async","sha256","message","messageBuffer","TextEncoder","encode","hashBuffer","crypto","subtle","digest","Array","from","Uint8Array","map","b","toString","padStart","join","PreviewContext","createContext","usePreviewContext","useContext","LiveQueryProvider","lazy","import","then","m","default","_sessionStorage","_session","ResolvePreview","props","initialData","query","params","children","data","useLiveQuery","jsx","Fragment","WeakMap","exports","PreviewProvider","previewConfig","fallback","rest","startTransition","useTransition","hydrated","setHydrated","useState","useEffect","projectId","client","createClient","Provider","value","Suspense","PreviewSession","constructor","sessionStorage","session","__privateAdd","this","__privateSet","static","request","secrets","storage","createCookieSessionStorage","cookie","name","httpOnly","sameSite","getSession","headers","get","has","key","__privateGet","destroy","destroySession","set","commit","commitSession","SanityPreview","isPreview","createSanityClient","options","cache","waitUntil","config","sanity","strategy","CacheLong","_ref","queryHash","hash","JSON","stringify","hashQuery","createWithCache_unstable","withCache","fetch","dataset","withConfig","useCdn","perspective","ignoreBrowserTokenWarning","_ref2","getPreview","context"],"mappings":"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"}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createClient as e}from"@sanity/client";import{createWithCache_unstable as t,CacheLong as r}from"@shopify/hydrogen";import{createContext as i,useContext as n,lazy as o,useTransition as a,useState as s,useEffect as c,Suspense as p}from"react";import{jsx as l,Fragment as d}from"react/jsx-runtime";import{createCookieSessionStorage as h}from"@shopify/remix-oxygen";import{useLiveQuery as u}from"@sanity/preview-kit";function f(i){const{cache:n,waitUntil:o,preview:a,config:s}=i,c={client:e(s),async query(e){let{query:i,params:a,cache:s=r()}=e;const p=await function(e,t){let r=e;null!==t&&(r+=JSON.stringify(t));return y(r)}(i,a);return t({cache:n,waitUntil:o})(p,s,(()=>c.client.fetch(i,a)))}};return a&&(c.preview={session:a.session},a.session.has("projectId")&&(c.preview={...c.preview,projectId:s.projectId,dataset:s.dataset,token:a.token},c.client=c.client.withConfig({useCdn:!1,token:a.token,perspective:a.perspective||"previewDrafts",ignoreBrowserTokenWarning:!0}),c.query=e=>{let{query:t,params:r}=e;return c.client.fetch(t,r)})),c}function m(e){return Boolean(e&&e.token&&null!==e.token)}async function y(e){const t=await(new TextEncoder).encode(e),r=await crypto.subtle.digest("SHA-256",t);return Array.from(new Uint8Array(r)).map((e=>e.toString(16).padStart(2,"0"))).join("")}const w=i(void 0),v=()=>n(w);function k(e){return m(e.sanity.preview)?{...e.sanity.client.config()}:void 0}const g=o((()=>import("@sanity/preview-kit").then((e=>({default:e.LiveQueryProvider})))));function S(t){const{children:r,previewConfig:i,fallback:n=r,...o}=t,[,d]=a(),[h,u]=s(!1);if(c((()=>d((()=>u(!0)))),[]),!h||!i||!i.projectId)return r;const f=e(i);return l(w.Provider,{value:{projectId:i.projectId},children:l(p,{fallback:n,children:l(g,{...o,client:f,children:r})})})}var j,q,C=(e,t,r)=>{if(!t.has(e))throw TypeError("Cannot "+r)},I=(e,t,r)=>(C(e,t,"read from private field"),r?r.call(e):t.get(e)),x=(e,t,r)=>{if(t.has(e))throw TypeError("Cannot add the same private member more than once");t instanceof WeakSet?t.add(e):t.set(e,r)},b=(e,t,r,i)=>(C(e,t,"write to private field"),i?i.call(e,r):t.set(e,r),r);class T{constructor(e,t){x(this,j,void 0),x(this,q,void 0),b(this,j,e),b(this,q,t)}static async init(e,t){const r=h({cookie:{name:"__preview",httpOnly:!0,sameSite:!0,secrets:t}}),i=await r.getSession(e.headers.get("Cookie"));return new this(r,i)}has(e){return I(this,q).has(e)}destroy(){return I(this,j).destroySession(I(this,q))}set(e,t){I(this,q).set(e,t)}commit(){return I(this,j).commitSession(I(this,q))}}function W(e){const{data:t,children:r,query:i,params:n}=e,o=Boolean(v());return"function"!=typeof r?r:o&&i?l(A,{query:i,params:n,initialData:t,children:r}):l(d,{children:r(t)})}function A(e){const{initialData:t,query:r,params:i,children:n}=e,[o]=u(t,r,i);return l(d,{children:n(o)})}j=new WeakMap,q=new WeakMap;export{S as PreviewProvider,T as PreviewSession,W as SanityPreview,f as createSanityClient,k as getPreview,m as isPreviewModeEnabled,y as sha256,v as usePreviewContext};//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","sources":["../src/client.ts","../src/preview/context.tsx","../src/preview/getPreview.ts","../src/preview/PreviewProvider.tsx","../src/preview/PreviewSession.ts","../src/preview/SanityPreview.tsx"],"sourcesContent":["import {\n type ClientConfig,\n type ClientPerspective,\n createClient,\n type QueryParams,\n type SanityClient,\n} from '@sanity/client'\n// eslint-disable-next-line camelcase\nimport {CacheLong, createWithCache_unstable} from '@shopify/hydrogen'\n\nimport type {PreviewSession} from './preview'\nimport type {CachingStrategy, EnvironmentOptions} from './types'\n\ntype CreateSanityClientOptions = EnvironmentOptions & {\n config: ClientConfig & Required<Pick<ClientConfig, 'projectId' | 'dataset'>>\n preview?: {\n session: PreviewSession\n token: string\n perspective?: ClientPerspective\n }\n}\n\ntype useSanityQuery = {\n query: string\n params?: QueryParams\n cache?: CachingStrategy\n}\n\nexport type Sanity = {\n client: SanityClient\n preview?:\n | {session: PreviewSession; projectId: string; dataset: string; token: string}\n | {session: PreviewSession}\n query<T>(options: useSanityQuery): Promise<T>\n}\n\n/**\n * Create Sanity provider with API client.\n */\nexport function createSanityClient(options: CreateSanityClientOptions): Sanity {\n const {cache, waitUntil, preview, config} = options\n\n const sanity: Sanity = {\n client: createClient(config),\n async query<T = any>({query, params, cache: strategy = CacheLong()}: useSanityQuery) {\n const queryHash = await hashQuery(query, params)\n const withCache = createWithCache_unstable<T>({\n cache,\n waitUntil,\n })\n\n return withCache(queryHash, strategy, () => sanity.client.fetch(query, params))\n },\n }\n\n if (preview) {\n sanity.preview = {session: preview.session}\n\n if (preview.session.has('projectId')) {\n sanity.preview = {\n ...sanity.preview,\n projectId: config.projectId,\n dataset: config.dataset,\n token: preview.token,\n }\n\n sanity.client = sanity.client.withConfig({\n useCdn: false,\n token: preview.token,\n perspective: preview.perspective || 'previewDrafts',\n ignoreBrowserTokenWarning: true,\n })\n\n sanity.query = ({query, params}) => {\n return sanity.client.fetch(query, params)\n }\n }\n }\n\n return sanity\n}\n\nexport function isPreviewModeEnabled(\n preview?: Sanity['preview']\n): preview is {session: PreviewSession; projectId: string; dataset: string; token: string} {\n // @ts-expect-error\n return Boolean(preview && preview.token && preview.token !== null)\n}\n\n/**\n * Create an SHA-256 hash as a hex string\n * @see https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest#converting_a_digest_to_a_hex_string\n */\nexport async function sha256(message: string): Promise<string> {\n // encode as UTF-8\n const messageBuffer = await new TextEncoder().encode(message)\n // hash the message\n const hashBuffer = await crypto.subtle.digest('SHA-256', messageBuffer)\n // convert bytes to hex string\n return Array.from(new Uint8Array(hashBuffer))\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('')\n}\n\n/**\n * Hash query and its parameters for use as cache key\n * NOTE: Oxygen deployment will break if the cache key is long or contains `\\n`\n */\nfunction hashQuery(\n query: useSanityQuery['query'],\n params: useSanityQuery['params']\n): Promise<string> {\n let hash = query\n\n if (params !== null) {\n hash += JSON.stringify(params)\n }\n\n return sha256(hash)\n}\n","import {createContext, useContext} from 'react'\n\nexport const PreviewContext = createContext<{projectId: string} | undefined>(undefined)\n\n/** TODO: needs inline documentation */\nexport const usePreviewContext = () => useContext(PreviewContext)\n","import type {ClientConfig} from '@sanity/client'\n\nimport {isPreviewModeEnabled, Sanity} from '../client'\n\n/** TODO: inline documentation */\nexport function getPreview<T extends {sanity: Sanity}>(context: T): ClientConfig | undefined {\n return isPreviewModeEnabled(context.sanity.preview)\n ? {\n ...context.sanity.client.config(),\n }\n : undefined\n}\n","/* eslint-disable react/require-default-props */\nimport {type ClientConfig, createClient} from '@sanity/client'\nimport type {LiveQueryProviderProps} from '@sanity/preview-kit'\nimport {lazy, type ReactNode, Suspense, useEffect, useState, useTransition} from 'react'\n\nimport {PreviewContext} from './context'\n\nconst LiveQueryProvider = lazy(() =>\n import('@sanity/preview-kit').then((m) => ({default: m.LiveQueryProvider}))\n)\n\ntype SanityPreviewProps = Omit<LiveQueryProviderProps, 'client'> & {\n fallback?: ReactNode\n previewConfig?: ClientConfig\n}\n\n/**\n * TODO: inline documentation\n * @see https://www.sanity.io/docs/preview-content-on-site\n */\nexport function PreviewProvider(props: SanityPreviewProps) {\n const {children, previewConfig, fallback = children, ...rest} = props\n\n const [, startTransition] = useTransition()\n const [hydrated, setHydrated] = useState(false)\n useEffect(() => startTransition(() => setHydrated(true)), [])\n\n if (!hydrated || !previewConfig || !previewConfig.projectId) {\n return children\n }\n\n const client = createClient(previewConfig)\n\n return (\n <PreviewContext.Provider value={{projectId: previewConfig.projectId}}>\n <Suspense fallback={fallback}>\n <LiveQueryProvider {...rest} client={client}>\n {children}\n </LiveQueryProvider>\n </Suspense>\n </PreviewContext.Provider>\n )\n}\n","import {createCookieSessionStorage, type Session, type SessionStorage} from '@shopify/remix-oxygen'\n\n/**\n * TODO: needs inline documentation\n */\nexport class PreviewSession {\n #sessionStorage: SessionStorage\n #session: Session\n\n constructor(sessionStorage: SessionStorage, session: Session) {\n this.#sessionStorage = sessionStorage\n this.#session = session\n }\n\n static async init(request: Request, secrets: string[]): Promise<PreviewSession> {\n const storage = createCookieSessionStorage({\n cookie: {\n name: '__preview',\n httpOnly: true,\n sameSite: true,\n secrets,\n },\n })\n\n const session = await storage.getSession(request.headers.get('Cookie'))\n\n return new this(storage, session)\n }\n\n has(key: string): boolean {\n return this.#session.has(key)\n }\n\n // get(key: string) {\n // return this.session.get(key);\n // }\n\n destroy(): Promise<string> {\n return this.#sessionStorage.destroySession(this.#session)\n }\n\n // unset(key: string) {\n // this.session.unset(key);\n // }\n\n // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types\n set(key: string, value: any): void {\n this.#session.set(key, value)\n }\n\n commit(): Promise<string> {\n return this.#sessionStorage.commitSession(this.#session)\n }\n}\n","/* eslint-disable react/require-default-props */\nimport type {QueryParams} from '@sanity/client'\nimport {useLiveQuery} from '@sanity/preview-kit'\nimport {type ReactNode} from 'react'\n\nimport {usePreviewContext} from './context'\n\ntype PreviewProps<T> = {\n data: T\n children: ReactNode | ((data?: T | null) => ReactNode)\n query?: string | null\n params?: QueryParams\n}\n\n/**\n * Component to use for rendering in preview mode\n *\n * When provided a Sanity query and render prop,\n * changes will be streamed in the client\n */\nexport function SanityPreview<T = unknown>(props: PreviewProps<T>) {\n const {data, children, query, params} = props\n const isPreview = Boolean(usePreviewContext())\n\n if (typeof children !== 'function') {\n return children\n }\n\n if (isPreview && query) {\n return (\n <ResolvePreview<typeof data> query={query} params={params} initialData={data}>\n {children}\n </ResolvePreview>\n )\n }\n\n return <>{children(data)}</>\n}\n\ntype ResolvePreviewProps<T> = {\n initialData?: T | null\n query: string\n params?: QueryParams\n children: (data?: T | null) => ReactNode\n}\n\n/**\n * Subscribe to live preview and delegate rendering to consumer\n */\nfunction ResolvePreview<T = unknown>(props: ResolvePreviewProps<T>) {\n const {initialData, query, params, children} = props\n const [data] = useLiveQuery(initialData, query, params)\n\n return <>{children(data)}</>\n}\n"],"names":["createSanityClient","options","cache","waitUntil","preview","config","sanity","client","createClient","async","query","params","strategy","CacheLong","_ref","queryHash","hash","JSON","stringify","sha256","hashQuery","createWithCache_unstable","withCache","fetch","session","has","projectId","dataset","token","withConfig","useCdn","perspective","ignoreBrowserTokenWarning","_ref2","isPreviewModeEnabled","Boolean","message","messageBuffer","TextEncoder","encode","hashBuffer","crypto","subtle","digest","Array","from","Uint8Array","map","b","toString","padStart","join","PreviewContext","createContext","usePreviewContext","useContext","getPreview","context","LiveQueryProvider","lazy","import","then","m","default","PreviewProvider","props","children","previewConfig","fallback","rest","startTransition","useTransition","hydrated","setHydrated","useState","useEffect","jsx","Provider","value","Suspense","_sessionStorage","_session","PreviewSession","constructor","sessionStorage","__privateAdd","this","__privateSet","static","request","secrets","storage","createCookieSessionStorage","cookie","name","httpOnly","sameSite","getSession","headers","get","key","__privateGet","destroy","destroySession","set","commit","commitSession","SanityPreview","data","isPreview","ResolvePreview","initialData","Fragment","useLiveQuery","WeakMap"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hydrogen-sanity",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "Sanity.io toolkit for Hydrogen",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sanity",
|
|
@@ -20,20 +20,20 @@
|
|
|
20
20
|
"url": "git+ssh://git@github.com/sanity-io/hydrogen-sanity.git"
|
|
21
21
|
},
|
|
22
22
|
"license": "MIT",
|
|
23
|
-
"author": "Sanity.io <hello@sanity.io>
|
|
23
|
+
"author": "Sanity.io <hello@sanity.io>",
|
|
24
24
|
"sideEffects": false,
|
|
25
25
|
"exports": {
|
|
26
26
|
".": {
|
|
27
27
|
"types": "./dist/index.d.ts",
|
|
28
28
|
"source": "./src/index.ts",
|
|
29
29
|
"require": "./dist/index.js",
|
|
30
|
-
"import": "./dist/index.
|
|
31
|
-
"default": "./dist/index.
|
|
30
|
+
"import": "./dist/index.mjs",
|
|
31
|
+
"default": "./dist/index.mjs"
|
|
32
32
|
},
|
|
33
33
|
"./package.json": "./package.json"
|
|
34
34
|
},
|
|
35
35
|
"main": "./dist/index.js",
|
|
36
|
-
"module": "./dist/index.
|
|
36
|
+
"module": "./dist/index.mjs",
|
|
37
37
|
"source": "./src/index.ts",
|
|
38
38
|
"types": "./dist/index.d.ts",
|
|
39
39
|
"files": [
|
|
@@ -45,27 +45,27 @@
|
|
|
45
45
|
"clean": "rimraf dist",
|
|
46
46
|
"format": "prettier --write --cache --ignore-unknown .",
|
|
47
47
|
"link-watch": "plugin-kit link-watch",
|
|
48
|
-
"lint": "eslint .",
|
|
48
|
+
"lint": "eslint --ignore-path .gitignore .",
|
|
49
49
|
"prepublishOnly": "run-s build",
|
|
50
50
|
"watch": "pkg-utils watch --strict",
|
|
51
51
|
"prepare": "husky install"
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
|
-
"@sanity/client": "^6.
|
|
55
|
-
"@sanity/preview-kit": "^
|
|
54
|
+
"@sanity/client": "^6.1.6",
|
|
55
|
+
"@sanity/preview-kit": "^2.3.0"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
|
-
"@commitlint/cli": "^17.6.
|
|
59
|
-
"@commitlint/config-conventional": "^17.6.
|
|
60
|
-
"@sanity/pkg-utils": "^2.
|
|
58
|
+
"@commitlint/cli": "^17.6.6",
|
|
59
|
+
"@commitlint/config-conventional": "^17.6.6",
|
|
60
|
+
"@sanity/pkg-utils": "^2.3.3",
|
|
61
61
|
"@sanity/plugin-kit": "^3.1.7",
|
|
62
62
|
"@sanity/semantic-release-preset": "^4.1.1",
|
|
63
|
-
"@shopify/hydrogen": "^2023.4.
|
|
64
|
-
"@shopify/remix-oxygen": "^1.
|
|
65
|
-
"@types/react": "^18.2.
|
|
66
|
-
"@typescript-eslint/eslint-plugin": "^5.
|
|
67
|
-
"@typescript-eslint/parser": "^5.
|
|
68
|
-
"eslint": "^8.
|
|
63
|
+
"@shopify/hydrogen": "^2023.4.6",
|
|
64
|
+
"@shopify/remix-oxygen": "^1.1.1",
|
|
65
|
+
"@types/react": "^18.2.14",
|
|
66
|
+
"@typescript-eslint/eslint-plugin": "^5.61.0",
|
|
67
|
+
"@typescript-eslint/parser": "^5.61.0",
|
|
68
|
+
"eslint": "^8.44.0",
|
|
69
69
|
"eslint-config-prettier": "^8.8.0",
|
|
70
70
|
"eslint-config-sanity": "^6.0.0",
|
|
71
71
|
"eslint-plugin-prettier": "^4.2.1",
|
|
@@ -73,14 +73,14 @@
|
|
|
73
73
|
"eslint-plugin-react-hooks": "^4.6.0",
|
|
74
74
|
"eslint-plugin-simple-import-sort": "^10.0.0",
|
|
75
75
|
"husky": "^8.0.3",
|
|
76
|
-
"lint-staged": "^13.2.
|
|
76
|
+
"lint-staged": "^13.2.3",
|
|
77
77
|
"npm-run-all": "^4.1.5",
|
|
78
78
|
"prettier": "^2.8.8",
|
|
79
|
-
"prettier-plugin-packagejson": "^2.4.
|
|
79
|
+
"prettier-plugin-packagejson": "^2.4.4",
|
|
80
80
|
"react": "^18.2.0",
|
|
81
81
|
"react-dom": "^18.2.0",
|
|
82
|
-
"rimraf": "^5.0.
|
|
83
|
-
"typescript": "^5.
|
|
82
|
+
"rimraf": "^5.0.1",
|
|
83
|
+
"typescript": "^5.1.6"
|
|
84
84
|
},
|
|
85
85
|
"peerDependencies": {
|
|
86
86
|
"@shopify/hydrogen": "^2023.4.0",
|
package/src/client.ts
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
type ClientConfig,
|
|
3
|
+
type ClientPerspective,
|
|
4
|
+
createClient,
|
|
5
|
+
type QueryParams,
|
|
6
|
+
type SanityClient,
|
|
7
|
+
} from '@sanity/client'
|
|
2
8
|
// eslint-disable-next-line camelcase
|
|
3
9
|
import {CacheLong, createWithCache_unstable} from '@shopify/hydrogen'
|
|
4
10
|
|
|
5
|
-
import type {
|
|
11
|
+
import type {PreviewSession} from './preview'
|
|
6
12
|
import type {CachingStrategy, EnvironmentOptions} from './types'
|
|
7
13
|
|
|
8
14
|
type CreateSanityClientOptions = EnvironmentOptions & {
|
|
@@ -10,18 +16,21 @@ type CreateSanityClientOptions = EnvironmentOptions & {
|
|
|
10
16
|
preview?: {
|
|
11
17
|
session: PreviewSession
|
|
12
18
|
token: string
|
|
19
|
+
perspective?: ClientPerspective
|
|
13
20
|
}
|
|
14
21
|
}
|
|
15
22
|
|
|
16
23
|
type useSanityQuery = {
|
|
17
24
|
query: string
|
|
18
|
-
params?:
|
|
25
|
+
params?: QueryParams
|
|
19
26
|
cache?: CachingStrategy
|
|
20
27
|
}
|
|
21
28
|
|
|
22
29
|
export type Sanity = {
|
|
23
30
|
client: SanityClient
|
|
24
|
-
preview?:
|
|
31
|
+
preview?:
|
|
32
|
+
| {session: PreviewSession; projectId: string; dataset: string; token: string}
|
|
33
|
+
| {session: PreviewSession}
|
|
25
34
|
query<T>(options: useSanityQuery): Promise<T>
|
|
26
35
|
}
|
|
27
36
|
|
|
@@ -30,15 +39,15 @@ export type Sanity = {
|
|
|
30
39
|
*/
|
|
31
40
|
export function createSanityClient(options: CreateSanityClientOptions): Sanity {
|
|
32
41
|
const {cache, waitUntil, preview, config} = options
|
|
33
|
-
const withCache = createWithCache_unstable({
|
|
34
|
-
cache,
|
|
35
|
-
waitUntil,
|
|
36
|
-
})
|
|
37
42
|
|
|
38
43
|
const sanity: Sanity = {
|
|
39
44
|
client: createClient(config),
|
|
40
|
-
async query({query, params, cache: strategy = CacheLong()}) {
|
|
45
|
+
async query<T = any>({query, params, cache: strategy = CacheLong()}: useSanityQuery) {
|
|
41
46
|
const queryHash = await hashQuery(query, params)
|
|
47
|
+
const withCache = createWithCache_unstable<T>({
|
|
48
|
+
cache,
|
|
49
|
+
waitUntil,
|
|
50
|
+
})
|
|
42
51
|
|
|
43
52
|
return withCache(queryHash, strategy, () => sanity.client.fetch(query, params))
|
|
44
53
|
},
|
|
@@ -58,6 +67,8 @@ export function createSanityClient(options: CreateSanityClientOptions): Sanity {
|
|
|
58
67
|
sanity.client = sanity.client.withConfig({
|
|
59
68
|
useCdn: false,
|
|
60
69
|
token: preview.token,
|
|
70
|
+
perspective: preview.perspective || 'previewDrafts',
|
|
71
|
+
ignoreBrowserTokenWarning: true,
|
|
61
72
|
})
|
|
62
73
|
|
|
63
74
|
sanity.query = ({query, params}) => {
|
|
@@ -71,9 +82,9 @@ export function createSanityClient(options: CreateSanityClientOptions): Sanity {
|
|
|
71
82
|
|
|
72
83
|
export function isPreviewModeEnabled(
|
|
73
84
|
preview?: Sanity['preview']
|
|
74
|
-
): preview is {session: PreviewSession
|
|
85
|
+
): preview is {session: PreviewSession; projectId: string; dataset: string; token: string} {
|
|
75
86
|
// @ts-expect-error
|
|
76
|
-
return preview && preview.token !== null
|
|
87
|
+
return Boolean(preview && preview.token && preview.token !== null)
|
|
77
88
|
}
|
|
78
89
|
|
|
79
90
|
/**
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/* eslint-disable react/require-default-props */
|
|
2
|
+
import {type ClientConfig, createClient} from '@sanity/client'
|
|
3
|
+
import type {LiveQueryProviderProps} from '@sanity/preview-kit'
|
|
4
|
+
import {lazy, type ReactNode, Suspense, useEffect, useState, useTransition} from 'react'
|
|
5
|
+
|
|
6
|
+
import {PreviewContext} from './context'
|
|
7
|
+
|
|
8
|
+
const LiveQueryProvider = lazy(() =>
|
|
9
|
+
import('@sanity/preview-kit').then((m) => ({default: m.LiveQueryProvider}))
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
type SanityPreviewProps = Omit<LiveQueryProviderProps, 'client'> & {
|
|
13
|
+
fallback?: ReactNode
|
|
14
|
+
previewConfig?: ClientConfig
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* TODO: inline documentation
|
|
19
|
+
* @see https://www.sanity.io/docs/preview-content-on-site
|
|
20
|
+
*/
|
|
21
|
+
export function PreviewProvider(props: SanityPreviewProps) {
|
|
22
|
+
const {children, previewConfig, fallback = children, ...rest} = props
|
|
23
|
+
|
|
24
|
+
const [, startTransition] = useTransition()
|
|
25
|
+
const [hydrated, setHydrated] = useState(false)
|
|
26
|
+
useEffect(() => startTransition(() => setHydrated(true)), [])
|
|
27
|
+
|
|
28
|
+
if (!hydrated || !previewConfig || !previewConfig.projectId) {
|
|
29
|
+
return children
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const client = createClient(previewConfig)
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<PreviewContext.Provider value={{projectId: previewConfig.projectId}}>
|
|
36
|
+
<Suspense fallback={fallback}>
|
|
37
|
+
<LiveQueryProvider {...rest} client={client}>
|
|
38
|
+
{children}
|
|
39
|
+
</LiveQueryProvider>
|
|
40
|
+
</Suspense>
|
|
41
|
+
</PreviewContext.Provider>
|
|
42
|
+
)
|
|
43
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import {createCookieSessionStorage, type Session, type SessionStorage} from '@shopify/remix-oxygen'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* TODO: needs inline documentation
|
|
5
|
+
*/
|
|
6
|
+
export class PreviewSession {
|
|
7
|
+
#sessionStorage: SessionStorage
|
|
8
|
+
#session: Session
|
|
9
|
+
|
|
10
|
+
constructor(sessionStorage: SessionStorage, session: Session) {
|
|
11
|
+
this.#sessionStorage = sessionStorage
|
|
12
|
+
this.#session = session
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
static async init(request: Request, secrets: string[]): Promise<PreviewSession> {
|
|
16
|
+
const storage = createCookieSessionStorage({
|
|
17
|
+
cookie: {
|
|
18
|
+
name: '__preview',
|
|
19
|
+
httpOnly: true,
|
|
20
|
+
sameSite: true,
|
|
21
|
+
secrets,
|
|
22
|
+
},
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
const session = await storage.getSession(request.headers.get('Cookie'))
|
|
26
|
+
|
|
27
|
+
return new this(storage, session)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
has(key: string): boolean {
|
|
31
|
+
return this.#session.has(key)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// get(key: string) {
|
|
35
|
+
// return this.session.get(key);
|
|
36
|
+
// }
|
|
37
|
+
|
|
38
|
+
destroy(): Promise<string> {
|
|
39
|
+
return this.#sessionStorage.destroySession(this.#session)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// unset(key: string) {
|
|
43
|
+
// this.session.unset(key);
|
|
44
|
+
// }
|
|
45
|
+
|
|
46
|
+
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
|
47
|
+
set(key: string, value: any): void {
|
|
48
|
+
this.#session.set(key, value)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
commit(): Promise<string> {
|
|
52
|
+
return this.#sessionStorage.commitSession(this.#session)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/* eslint-disable react/require-default-props */
|
|
2
|
+
import type {QueryParams} from '@sanity/client'
|
|
3
|
+
import {useLiveQuery} from '@sanity/preview-kit'
|
|
4
|
+
import {type ReactNode} from 'react'
|
|
5
|
+
|
|
6
|
+
import {usePreviewContext} from './context'
|
|
7
|
+
|
|
8
|
+
type PreviewProps<T> = {
|
|
9
|
+
data: T
|
|
10
|
+
children: ReactNode | ((data?: T | null) => ReactNode)
|
|
11
|
+
query?: string | null
|
|
12
|
+
params?: QueryParams
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Component to use for rendering in preview mode
|
|
17
|
+
*
|
|
18
|
+
* When provided a Sanity query and render prop,
|
|
19
|
+
* changes will be streamed in the client
|
|
20
|
+
*/
|
|
21
|
+
export function SanityPreview<T = unknown>(props: PreviewProps<T>) {
|
|
22
|
+
const {data, children, query, params} = props
|
|
23
|
+
const isPreview = Boolean(usePreviewContext())
|
|
24
|
+
|
|
25
|
+
if (typeof children !== 'function') {
|
|
26
|
+
return children
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (isPreview && query) {
|
|
30
|
+
return (
|
|
31
|
+
<ResolvePreview<typeof data> query={query} params={params} initialData={data}>
|
|
32
|
+
{children}
|
|
33
|
+
</ResolvePreview>
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return <>{children(data)}</>
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
type ResolvePreviewProps<T> = {
|
|
41
|
+
initialData?: T | null
|
|
42
|
+
query: string
|
|
43
|
+
params?: QueryParams
|
|
44
|
+
children: (data?: T | null) => ReactNode
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Subscribe to live preview and delegate rendering to consumer
|
|
49
|
+
*/
|
|
50
|
+
function ResolvePreview<T = unknown>(props: ResolvePreviewProps<T>) {
|
|
51
|
+
const {initialData, query, params, children} = props
|
|
52
|
+
const [data] = useLiveQuery(initialData, query, params)
|
|
53
|
+
|
|
54
|
+
return <>{children(data)}</>
|
|
55
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type {ClientConfig} from '@sanity/client'
|
|
2
|
+
|
|
3
|
+
import {isPreviewModeEnabled, Sanity} from '../client'
|
|
4
|
+
|
|
5
|
+
/** TODO: inline documentation */
|
|
6
|
+
export function getPreview<T extends {sanity: Sanity}>(context: T): ClientConfig | undefined {
|
|
7
|
+
return isPreviewModeEnabled(context.sanity.preview)
|
|
8
|
+
? {
|
|
9
|
+
...context.sanity.client.config(),
|
|
10
|
+
}
|
|
11
|
+
: undefined
|
|
12
|
+
}
|
package/dist/index.esm.js
DELETED
|
@@ -1,190 +0,0 @@
|
|
|
1
|
-
import { createClient } from '@sanity/client';
|
|
2
|
-
import { createWithCache_unstable, CacheLong } from '@shopify/hydrogen';
|
|
3
|
-
import { jsx, Fragment } from 'react/jsx-runtime';
|
|
4
|
-
import { definePreview, PreviewSuspense } from '@sanity/preview-kit';
|
|
5
|
-
import { createCookieSessionStorage } from '@shopify/remix-oxygen';
|
|
6
|
-
import { createContext, useContext, useMemo } from 'react';
|
|
7
|
-
function createSanityClient(options) {
|
|
8
|
-
const {
|
|
9
|
-
cache,
|
|
10
|
-
waitUntil,
|
|
11
|
-
preview,
|
|
12
|
-
config
|
|
13
|
-
} = options;
|
|
14
|
-
const withCache = createWithCache_unstable({
|
|
15
|
-
cache,
|
|
16
|
-
waitUntil
|
|
17
|
-
});
|
|
18
|
-
const sanity = {
|
|
19
|
-
client: createClient(config),
|
|
20
|
-
async query(_ref) {
|
|
21
|
-
let {
|
|
22
|
-
query,
|
|
23
|
-
params,
|
|
24
|
-
cache: strategy = CacheLong()
|
|
25
|
-
} = _ref;
|
|
26
|
-
const queryHash = await hashQuery(query, params);
|
|
27
|
-
return withCache(queryHash, strategy, () => sanity.client.fetch(query, params));
|
|
28
|
-
}
|
|
29
|
-
};
|
|
30
|
-
if (preview) {
|
|
31
|
-
sanity.preview = {
|
|
32
|
-
session: preview.session
|
|
33
|
-
};
|
|
34
|
-
if (preview.session.has("projectId")) {
|
|
35
|
-
sanity.preview = {
|
|
36
|
-
...sanity.preview,
|
|
37
|
-
projectId: config.projectId,
|
|
38
|
-
dataset: config.dataset,
|
|
39
|
-
token: preview.token
|
|
40
|
-
};
|
|
41
|
-
sanity.client = sanity.client.withConfig({
|
|
42
|
-
useCdn: false,
|
|
43
|
-
token: preview.token
|
|
44
|
-
});
|
|
45
|
-
sanity.query = _ref2 => {
|
|
46
|
-
let {
|
|
47
|
-
query,
|
|
48
|
-
params
|
|
49
|
-
} = _ref2;
|
|
50
|
-
return sanity.client.fetch(query, params);
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
return sanity;
|
|
55
|
-
}
|
|
56
|
-
function isPreviewModeEnabled(preview) {
|
|
57
|
-
return preview && preview.token !== null;
|
|
58
|
-
}
|
|
59
|
-
async function sha256(message) {
|
|
60
|
-
const messageBuffer = await new TextEncoder().encode(message);
|
|
61
|
-
const hashBuffer = await crypto.subtle.digest("SHA-256", messageBuffer);
|
|
62
|
-
return Array.from(new Uint8Array(hashBuffer)).map(b => b.toString(16).padStart(2, "0")).join("");
|
|
63
|
-
}
|
|
64
|
-
function hashQuery(query, params) {
|
|
65
|
-
let hash = query;
|
|
66
|
-
if (params !== null) {
|
|
67
|
-
hash += JSON.stringify(params);
|
|
68
|
-
}
|
|
69
|
-
return sha256(hash);
|
|
70
|
-
}
|
|
71
|
-
class PreviewSession {
|
|
72
|
-
// eslint-disable-next-line no-useless-constructor, no-empty-function
|
|
73
|
-
constructor(sessionStorage, session) {
|
|
74
|
-
this.sessionStorage = sessionStorage;
|
|
75
|
-
this.session = session;
|
|
76
|
-
}
|
|
77
|
-
static async init(request, secrets) {
|
|
78
|
-
const storage = createCookieSessionStorage({
|
|
79
|
-
cookie: {
|
|
80
|
-
name: "__preview",
|
|
81
|
-
httpOnly: true,
|
|
82
|
-
sameSite: true,
|
|
83
|
-
secrets
|
|
84
|
-
}
|
|
85
|
-
});
|
|
86
|
-
const session = await storage.getSession(request.headers.get("Cookie"));
|
|
87
|
-
return new this(storage, session);
|
|
88
|
-
}
|
|
89
|
-
has(key) {
|
|
90
|
-
return this.session.has(key);
|
|
91
|
-
}
|
|
92
|
-
// get(key: string) {
|
|
93
|
-
// return this.session.get(key);
|
|
94
|
-
// }
|
|
95
|
-
destroy() {
|
|
96
|
-
return this.sessionStorage.destroySession(this.session);
|
|
97
|
-
}
|
|
98
|
-
// unset(key: string) {
|
|
99
|
-
// this.session.unset(key);
|
|
100
|
-
// }
|
|
101
|
-
set(key, value) {
|
|
102
|
-
this.session.set(key, value);
|
|
103
|
-
}
|
|
104
|
-
commit() {
|
|
105
|
-
return this.sessionStorage.commitSession(this.session);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
const PreviewContext = createContext(void 0);
|
|
109
|
-
const usePreviewContext = () => useContext(PreviewContext);
|
|
110
|
-
function Preview(props) {
|
|
111
|
-
var _a;
|
|
112
|
-
const {
|
|
113
|
-
children,
|
|
114
|
-
preview
|
|
115
|
-
} = props;
|
|
116
|
-
if (!(preview == null ? void 0 : preview.token)) {
|
|
117
|
-
return /* @__PURE__ */jsx(Fragment, {
|
|
118
|
-
children
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
const fallback = (_a = props.fallback) != null ? _a : /* @__PURE__ */jsx("div", {
|
|
122
|
-
children: "Loading preview..."
|
|
123
|
-
});
|
|
124
|
-
const {
|
|
125
|
-
projectId,
|
|
126
|
-
dataset,
|
|
127
|
-
token
|
|
128
|
-
} = preview;
|
|
129
|
-
const _usePreview = definePreview({
|
|
130
|
-
projectId,
|
|
131
|
-
dataset,
|
|
132
|
-
overlayDrafts: true
|
|
133
|
-
});
|
|
134
|
-
function usePreview(query, params, serverSnapshot) {
|
|
135
|
-
return _usePreview(token, query, params, serverSnapshot);
|
|
136
|
-
}
|
|
137
|
-
return /* @__PURE__ */jsx(PreviewContext.Provider, {
|
|
138
|
-
value: {
|
|
139
|
-
usePreview
|
|
140
|
-
},
|
|
141
|
-
children: /* @__PURE__ */jsx(PreviewSuspense, {
|
|
142
|
-
fallback,
|
|
143
|
-
children
|
|
144
|
-
})
|
|
145
|
-
});
|
|
146
|
-
}
|
|
147
|
-
function usePreviewComponent(component, preview) {
|
|
148
|
-
const isPreview = Boolean(usePreviewContext());
|
|
149
|
-
return useMemo(() => isPreview ? preview : component, [component, isPreview, preview]);
|
|
150
|
-
}
|
|
151
|
-
function SanityPreview(props) {
|
|
152
|
-
const {
|
|
153
|
-
data,
|
|
154
|
-
children,
|
|
155
|
-
query,
|
|
156
|
-
params
|
|
157
|
-
} = props;
|
|
158
|
-
const isPreview = Boolean(usePreviewContext());
|
|
159
|
-
if (typeof children !== "function") {
|
|
160
|
-
return children;
|
|
161
|
-
}
|
|
162
|
-
if (isPreview && query) {
|
|
163
|
-
return /* @__PURE__ */jsx(ResolvePreview, {
|
|
164
|
-
query,
|
|
165
|
-
params,
|
|
166
|
-
serverSnapshot: data,
|
|
167
|
-
children
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
|
-
return /* @__PURE__ */jsx(Fragment, {
|
|
171
|
-
children: children(data)
|
|
172
|
-
});
|
|
173
|
-
}
|
|
174
|
-
function ResolvePreview(props) {
|
|
175
|
-
const {
|
|
176
|
-
serverSnapshot,
|
|
177
|
-
query,
|
|
178
|
-
params,
|
|
179
|
-
children
|
|
180
|
-
} = props;
|
|
181
|
-
const {
|
|
182
|
-
usePreview
|
|
183
|
-
} = usePreviewContext();
|
|
184
|
-
const data = usePreview(query, params, serverSnapshot);
|
|
185
|
-
return /* @__PURE__ */jsx(Fragment, {
|
|
186
|
-
children: children(data)
|
|
187
|
-
});
|
|
188
|
-
}
|
|
189
|
-
export { Preview, PreviewSession, SanityPreview, createSanityClient, isPreviewModeEnabled, sha256, usePreviewComponent, usePreviewContext };
|
|
190
|
-
//# sourceMappingURL=index.esm.js.map
|
package/dist/index.esm.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.esm.js","sources":["../src/client.ts","../src/preview.tsx"],"sourcesContent":["import {type ClientConfig, createClient, type SanityClient} from '@sanity/client'\n// eslint-disable-next-line camelcase\nimport {CacheLong, createWithCache_unstable} from '@shopify/hydrogen'\n\nimport type {PreviewData, PreviewSession} from './preview'\nimport type {CachingStrategy, EnvironmentOptions} from './types'\n\ntype CreateSanityClientOptions = EnvironmentOptions & {\n config: ClientConfig & Required<Pick<ClientConfig, 'projectId' | 'dataset'>>\n preview?: {\n session: PreviewSession\n token: string\n }\n}\n\ntype useSanityQuery = {\n query: string\n params?: Record<string, unknown>\n cache?: CachingStrategy\n}\n\nexport type Sanity = {\n client: SanityClient\n preview?: ({session: PreviewSession} & PreviewData) | {session: PreviewSession}\n query<T>(options: useSanityQuery): Promise<T>\n}\n\n/**\n * Create Sanity provider with API client.\n */\nexport function createSanityClient(options: CreateSanityClientOptions): Sanity {\n const {cache, waitUntil, preview, config} = options\n const withCache = createWithCache_unstable({\n cache,\n waitUntil,\n })\n\n const sanity: Sanity = {\n client: createClient(config),\n async query({query, params, cache: strategy = CacheLong()}) {\n const queryHash = await hashQuery(query, params)\n\n return withCache(queryHash, strategy, () => sanity.client.fetch(query, params))\n },\n }\n\n if (preview) {\n sanity.preview = {session: preview.session}\n\n if (preview.session.has('projectId')) {\n sanity.preview = {\n ...sanity.preview,\n projectId: config.projectId,\n dataset: config.dataset,\n token: preview.token,\n }\n\n sanity.client = sanity.client.withConfig({\n useCdn: false,\n token: preview.token,\n })\n\n sanity.query = ({query, params}) => {\n return sanity.client.fetch(query, params)\n }\n }\n }\n\n return sanity\n}\n\nexport function isPreviewModeEnabled(\n preview?: Sanity['preview']\n): preview is {session: PreviewSession} & PreviewData {\n // @ts-expect-error\n return preview && preview.token !== null\n}\n\n/**\n * Create an SHA-256 hash as a hex string\n * @see https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest#converting_a_digest_to_a_hex_string\n */\nexport async function sha256(message: string): Promise<string> {\n // encode as UTF-8\n const messageBuffer = await new TextEncoder().encode(message)\n // hash the message\n const hashBuffer = await crypto.subtle.digest('SHA-256', messageBuffer)\n // convert bytes to hex string\n return Array.from(new Uint8Array(hashBuffer))\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('')\n}\n\n/**\n * Hash query and its parameters for use as cache key\n * NOTE: Oxygen deployment will break if the cache key is long or contains `\\n`\n */\nfunction hashQuery(\n query: useSanityQuery['query'],\n params: useSanityQuery['params']\n): Promise<string> {\n let hash = query\n\n if (params !== null) {\n hash += JSON.stringify(params)\n }\n\n return sha256(hash)\n}\n","/* eslint-disable react/require-default-props */\nimport {definePreview, type Params, PreviewSuspense} from '@sanity/preview-kit'\nimport {createCookieSessionStorage, type Session, type SessionStorage} from '@shopify/remix-oxygen'\nimport {createContext, ElementType, type ReactNode, useContext, useMemo} from 'react'\n\ntype UsePreview = <R = any, P extends Params = Params, Q extends string = string>(\n query: Q,\n params?: P,\n serverSnapshot?: R\n) => R\n\nexport type PreviewData = {\n projectId: string\n dataset: string\n token: string\n}\n\nexport type PreviewProps = {\n children: ReactNode\n fallback?: ReactNode\n preview?: PreviewData\n}\n\nexport class PreviewSession {\n // eslint-disable-next-line no-useless-constructor, no-empty-function\n constructor(private sessionStorage: SessionStorage, private session: Session) {}\n\n static async init(request: Request, secrets: string[]) {\n const storage = createCookieSessionStorage({\n cookie: {\n name: '__preview',\n httpOnly: true,\n sameSite: true,\n secrets,\n },\n })\n\n const session = await storage.getSession(request.headers.get('Cookie'))\n\n return new this(storage, session)\n }\n\n has(key: string) {\n return this.session.has(key)\n }\n\n // get(key: string) {\n // return this.session.get(key);\n // }\n\n destroy() {\n return this.sessionStorage.destroySession(this.session)\n }\n\n // unset(key: string) {\n // this.session.unset(key);\n // }\n\n set(key: string, value: any) {\n this.session.set(key, value)\n }\n\n commit() {\n return this.sessionStorage.commitSession(this.session)\n }\n}\n\nconst PreviewContext = createContext<\n | {\n /**\n * Query Sanity and subscribe to changes, optionally\n * passing a server snapshot to speed up hydration\n */\n usePreview: UsePreview\n }\n | undefined\n>(undefined)\n\nexport const usePreviewContext = () => useContext(PreviewContext)\n\n/**\n * Conditionally apply `PreviewSuspense` boundary\n * @see https://www.sanity.io/docs/preview-content-on-site\n */\nexport function Preview(props: PreviewProps) {\n const {children, preview} = props\n\n if (!preview?.token) {\n return <>{children}</>\n }\n\n const fallback = props.fallback ?? <div>Loading preview...</div>\n const {projectId, dataset, token} = preview\n const _usePreview = definePreview({\n projectId,\n dataset,\n overlayDrafts: true,\n })\n\n function usePreview<R = any, P extends Params = Params, Q extends string = string>(\n query: Q,\n params?: P,\n serverSnapshot?: R\n ): R {\n return _usePreview(token, query, params, serverSnapshot)\n }\n usePreview satisfies UsePreview\n\n return (\n <PreviewContext.Provider value={{usePreview}}>\n <PreviewSuspense fallback={fallback}>{children}</PreviewSuspense>\n </PreviewContext.Provider>\n )\n}\n\n/**\n * Select and memoize which component to render based on preview mode\n * @deprecated use `SanityPreview` instead\n */\nexport function usePreviewComponent<T>(component: ElementType<T>, preview: ElementType<T>) {\n const isPreview = Boolean(usePreviewContext())\n\n return useMemo(() => (isPreview ? preview : component), [component, isPreview, preview])\n}\n\ntype PreviewDataProps<T> = {\n data: T\n children: ReactNode | ((data: T | null) => ReactNode)\n query?: string | null\n params?: Params\n}\n\n/**\n * Component to use for rendering in preview mode\n *\n * When provided a Sanity query and render prop,\n * changes will be streamed in the client\n */\nexport function SanityPreview<T = unknown>(props: PreviewDataProps<T>) {\n const {data, children, query, params} = props\n const isPreview = Boolean(usePreviewContext())\n\n if (typeof children !== 'function') {\n return children\n }\n\n if (isPreview && query) {\n return (\n <ResolvePreview<typeof data> query={query} params={params} serverSnapshot={data}>\n {children}\n </ResolvePreview>\n )\n }\n\n return <>{children(data)}</>\n}\n\ntype ResolvePreviewProps<T> = {\n serverSnapshot?: T | null\n query: string\n params?: Params\n children: (data: T | null) => ReactNode\n}\n\n/**\n * Subscribe to live preview and delegate rendering to consumer\n */\nfunction ResolvePreview<T = unknown>(props: ResolvePreviewProps<T>) {\n const {serverSnapshot, query, params, children} = props\n // This won't break the conditional rule of hooks,\n // **but** it relies on the assumption that this component\n // will only be used in preview mode 👇🏻\n const {usePreview} = usePreviewContext()!\n const data = usePreview(query, params, serverSnapshot)\n\n return <>{children(data)}</>\n}\n"],"names":["createSanityClient","options","cache","waitUntil","preview","config","withCache","createWithCache_unstable","sanity","client","createClient","query","params","strategy","CacheLong","_ref","queryHash","hashQuery","fetch","session","has","projectId","dataset","token","withConfig","useCdn","_ref2","isPreviewModeEnabled","sha256","message","messageBuffer","TextEncoder","encode","hashBuffer","crypto","subtle","digest","Array","from","Uint8Array","map","b","toString","padStart","join","hash","JSON","stringify","PreviewSession","constructor","sessionStorage","init","request","secrets","storage","createCookieSessionStorage","cookie","name","httpOnly","sameSite","getSession","headers","get","key","destroy","destroySession","set","value","commit","commitSession","PreviewContext","createContext","usePreviewContext","useContext","Preview","props","_a","children","fallback","jsx","_usePreview","definePreview","overlayDrafts","usePreview","serverSnapshot","Provider","PreviewSuspense","usePreviewComponent","component","isPreview","Boolean","useMemo","SanityPreview","data","ResolvePreview","Fragment"],"mappings":"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"}
|
package/src/preview.tsx
DELETED
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
/* eslint-disable react/require-default-props */
|
|
2
|
-
import {definePreview, type Params, PreviewSuspense} from '@sanity/preview-kit'
|
|
3
|
-
import {createCookieSessionStorage, type Session, type SessionStorage} from '@shopify/remix-oxygen'
|
|
4
|
-
import {createContext, ElementType, type ReactNode, useContext, useMemo} from 'react'
|
|
5
|
-
|
|
6
|
-
type UsePreview = <R = any, P extends Params = Params, Q extends string = string>(
|
|
7
|
-
query: Q,
|
|
8
|
-
params?: P,
|
|
9
|
-
serverSnapshot?: R
|
|
10
|
-
) => R
|
|
11
|
-
|
|
12
|
-
export type PreviewData = {
|
|
13
|
-
projectId: string
|
|
14
|
-
dataset: string
|
|
15
|
-
token: string
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export type PreviewProps = {
|
|
19
|
-
children: ReactNode
|
|
20
|
-
fallback?: ReactNode
|
|
21
|
-
preview?: PreviewData
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export class PreviewSession {
|
|
25
|
-
// eslint-disable-next-line no-useless-constructor, no-empty-function
|
|
26
|
-
constructor(private sessionStorage: SessionStorage, private session: Session) {}
|
|
27
|
-
|
|
28
|
-
static async init(request: Request, secrets: string[]) {
|
|
29
|
-
const storage = createCookieSessionStorage({
|
|
30
|
-
cookie: {
|
|
31
|
-
name: '__preview',
|
|
32
|
-
httpOnly: true,
|
|
33
|
-
sameSite: true,
|
|
34
|
-
secrets,
|
|
35
|
-
},
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
const session = await storage.getSession(request.headers.get('Cookie'))
|
|
39
|
-
|
|
40
|
-
return new this(storage, session)
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
has(key: string) {
|
|
44
|
-
return this.session.has(key)
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// get(key: string) {
|
|
48
|
-
// return this.session.get(key);
|
|
49
|
-
// }
|
|
50
|
-
|
|
51
|
-
destroy() {
|
|
52
|
-
return this.sessionStorage.destroySession(this.session)
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// unset(key: string) {
|
|
56
|
-
// this.session.unset(key);
|
|
57
|
-
// }
|
|
58
|
-
|
|
59
|
-
set(key: string, value: any) {
|
|
60
|
-
this.session.set(key, value)
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
commit() {
|
|
64
|
-
return this.sessionStorage.commitSession(this.session)
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const PreviewContext = createContext<
|
|
69
|
-
| {
|
|
70
|
-
/**
|
|
71
|
-
* Query Sanity and subscribe to changes, optionally
|
|
72
|
-
* passing a server snapshot to speed up hydration
|
|
73
|
-
*/
|
|
74
|
-
usePreview: UsePreview
|
|
75
|
-
}
|
|
76
|
-
| undefined
|
|
77
|
-
>(undefined)
|
|
78
|
-
|
|
79
|
-
export const usePreviewContext = () => useContext(PreviewContext)
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Conditionally apply `PreviewSuspense` boundary
|
|
83
|
-
* @see https://www.sanity.io/docs/preview-content-on-site
|
|
84
|
-
*/
|
|
85
|
-
export function Preview(props: PreviewProps) {
|
|
86
|
-
const {children, preview} = props
|
|
87
|
-
|
|
88
|
-
if (!preview?.token) {
|
|
89
|
-
return <>{children}</>
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
const fallback = props.fallback ?? <div>Loading preview...</div>
|
|
93
|
-
const {projectId, dataset, token} = preview
|
|
94
|
-
const _usePreview = definePreview({
|
|
95
|
-
projectId,
|
|
96
|
-
dataset,
|
|
97
|
-
overlayDrafts: true,
|
|
98
|
-
})
|
|
99
|
-
|
|
100
|
-
function usePreview<R = any, P extends Params = Params, Q extends string = string>(
|
|
101
|
-
query: Q,
|
|
102
|
-
params?: P,
|
|
103
|
-
serverSnapshot?: R
|
|
104
|
-
): R {
|
|
105
|
-
return _usePreview(token, query, params, serverSnapshot)
|
|
106
|
-
}
|
|
107
|
-
usePreview satisfies UsePreview
|
|
108
|
-
|
|
109
|
-
return (
|
|
110
|
-
<PreviewContext.Provider value={{usePreview}}>
|
|
111
|
-
<PreviewSuspense fallback={fallback}>{children}</PreviewSuspense>
|
|
112
|
-
</PreviewContext.Provider>
|
|
113
|
-
)
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Select and memoize which component to render based on preview mode
|
|
118
|
-
* @deprecated use `SanityPreview` instead
|
|
119
|
-
*/
|
|
120
|
-
export function usePreviewComponent<T>(component: ElementType<T>, preview: ElementType<T>) {
|
|
121
|
-
const isPreview = Boolean(usePreviewContext())
|
|
122
|
-
|
|
123
|
-
return useMemo(() => (isPreview ? preview : component), [component, isPreview, preview])
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
type PreviewDataProps<T> = {
|
|
127
|
-
data: T
|
|
128
|
-
children: ReactNode | ((data: T | null) => ReactNode)
|
|
129
|
-
query?: string | null
|
|
130
|
-
params?: Params
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Component to use for rendering in preview mode
|
|
135
|
-
*
|
|
136
|
-
* When provided a Sanity query and render prop,
|
|
137
|
-
* changes will be streamed in the client
|
|
138
|
-
*/
|
|
139
|
-
export function SanityPreview<T = unknown>(props: PreviewDataProps<T>) {
|
|
140
|
-
const {data, children, query, params} = props
|
|
141
|
-
const isPreview = Boolean(usePreviewContext())
|
|
142
|
-
|
|
143
|
-
if (typeof children !== 'function') {
|
|
144
|
-
return children
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
if (isPreview && query) {
|
|
148
|
-
return (
|
|
149
|
-
<ResolvePreview<typeof data> query={query} params={params} serverSnapshot={data}>
|
|
150
|
-
{children}
|
|
151
|
-
</ResolvePreview>
|
|
152
|
-
)
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
return <>{children(data)}</>
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
type ResolvePreviewProps<T> = {
|
|
159
|
-
serverSnapshot?: T | null
|
|
160
|
-
query: string
|
|
161
|
-
params?: Params
|
|
162
|
-
children: (data: T | null) => ReactNode
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
/**
|
|
166
|
-
* Subscribe to live preview and delegate rendering to consumer
|
|
167
|
-
*/
|
|
168
|
-
function ResolvePreview<T = unknown>(props: ResolvePreviewProps<T>) {
|
|
169
|
-
const {serverSnapshot, query, params, children} = props
|
|
170
|
-
// This won't break the conditional rule of hooks,
|
|
171
|
-
// **but** it relies on the assumption that this component
|
|
172
|
-
// will only be used in preview mode 👇🏻
|
|
173
|
-
const {usePreview} = usePreviewContext()!
|
|
174
|
-
const data = usePreview(query, params, serverSnapshot)
|
|
175
|
-
|
|
176
|
-
return <>{children(data)}</>
|
|
177
|
-
}
|