@devite/nuxt-sanity 1.5.3 → 2.0.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 (53) hide show
  1. package/README.md +3 -3
  2. package/dist/module.d.mts +62 -14
  3. package/dist/module.d.ts +62 -14
  4. package/dist/module.json +3 -3
  5. package/dist/module.mjs +98 -4
  6. package/dist/runtime/client/DefaultSanityClient.d.ts +15 -0
  7. package/dist/runtime/client/DefaultSanityClient.js +44 -0
  8. package/dist/runtime/client/MinimalSanityClient.d.ts +15 -0
  9. package/dist/runtime/client/MinimalSanityClient.js +59 -0
  10. package/dist/runtime/client/SanityClient.d.ts +10 -0
  11. package/dist/runtime/client/SanityClient.js +7 -0
  12. package/dist/runtime/components/SanityComponent.vue +6 -4
  13. package/dist/runtime/components/SanityImageAsset.vue +9 -5
  14. package/dist/runtime/components/SanityLinkExternal.vue +2 -1
  15. package/dist/runtime/components/SanityLinkInternal.vue +5 -7
  16. package/dist/runtime/components/SanityPage.vue +23 -14
  17. package/dist/runtime/components/SanityRichText.vue +3 -3
  18. package/dist/runtime/composables/useLazySanityQuery.d.ts +4 -0
  19. package/dist/runtime/composables/useLazySanityQuery.js +4 -0
  20. package/dist/runtime/composables/useSanityLiveMode.d.ts +1 -0
  21. package/dist/runtime/composables/useSanityLiveMode.js +16 -0
  22. package/dist/runtime/composables/useSanityQuery.d.ts +30 -0
  23. package/dist/runtime/composables/useSanityQuery.js +69 -0
  24. package/dist/runtime/composables/useSanityVisualEditing.d.ts +8 -0
  25. package/dist/runtime/composables/useSanityVisualEditing.js +44 -0
  26. package/dist/runtime/composables/useSanityVisualEditingState.d.ts +4 -0
  27. package/dist/runtime/composables/useSanityVisualEditingState.js +12 -0
  28. package/dist/runtime/plugins/visual-editing.d.ts +2 -0
  29. package/dist/runtime/plugins/visual-editing.js +30 -0
  30. package/dist/runtime/server/routes/preview/disable.d.ts +2 -0
  31. package/dist/runtime/server/routes/preview/disable.js +6 -0
  32. package/dist/runtime/server/routes/preview/enable.d.ts +2 -0
  33. package/dist/runtime/server/routes/preview/enable.js +20 -0
  34. package/dist/runtime/server/routes/proxy.d.ts +2 -0
  35. package/dist/runtime/server/routes/proxy.js +19 -0
  36. package/dist/runtime/server/tsconfig.json +3 -0
  37. package/dist/runtime/server/utils/useSanityClient.d.ts +3 -0
  38. package/dist/runtime/server/utils/useSanityClient.js +17 -0
  39. package/dist/runtime/utils/getOrCreateSanityClient.d.ts +4 -0
  40. package/dist/runtime/utils/getOrCreateSanityClient.js +15 -0
  41. package/dist/runtime/utils/groq.d.ts +8 -0
  42. package/dist/runtime/utils/groq.js +6 -0
  43. package/dist/runtime/utils/projections.d.ts +4 -4
  44. package/dist/runtime/utils/projections.js +1 -1
  45. package/dist/runtime/utils/resolveImageAssetById.d.ts +2 -2
  46. package/dist/runtime/utils/resolveImageAssetById.js +2 -2
  47. package/dist/runtime/utils/resolveInternalLink.d.ts +2 -2
  48. package/dist/runtime/utils/resolveInternalLink.js +2 -2
  49. package/dist/runtime/utils/useSanityClient.d.ts +2 -0
  50. package/dist/runtime/utils/useSanityClient.js +8 -0
  51. package/dist/types.d.mts +1 -7
  52. package/dist/types.d.ts +1 -7
  53. package/package.json +28 -14
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <main v-if="sanityData?.modules?.length > 0">
2
+ <main v-if="sanityData?.modules?.length">
3
3
  <SanityComponent
4
4
  v-for="module in sanityData.modules"
5
5
  :key="module._key"
@@ -9,24 +9,35 @@
9
9
  </template>
10
10
 
11
11
  <script setup lang="ts">
12
- import { useSanityQuery } from '@nuxtjs/sanity/runtime/composables/visual-editing'
13
- import { groq } from '@nuxtjs/sanity/runtime/groq'
14
- import type { ComputedRef } from 'vue'
12
+ import { computed, type ComputedRef } from 'vue'
15
13
  import type { ImageAsset } from '@sanity/types'
16
- import type { Home, Page, NotFound, GlobalSEO } from '@devite/nuxt-sanity'
14
+ import type { GlobalSEO, Home, NotFound, Page } from '@devite/nuxt-sanity'
17
15
  import { IMAGE_WITHOUT_PREVIEW_PROJECTION } from '../utils/projections'
18
- import { useHead, useRoute, useRuntimeConfig, useSeoMeta, computed } from '#imports'
16
+ import { useSanityQuery } from '../composables/useSanityQuery'
17
+ import { groq } from '../utils/groq'
18
+ import { useHead, useRoute, useRuntimeConfig, useSeoMeta } from '#imports'
19
19
 
20
20
  const path = useRoute().fullPath
21
21
  const groqFilter = path === '/' ? '_type == "home"' : `_type == "page" && slug.current == $slug`
22
- const { data: sanityData } = await useSanityQuery<Home | Page | NotFound>(groq`*[(${groqFilter}) || _type == "notFound"][0] { _id, _type, title, modules, seo { _type, indexable, title, shortTitle, description, image ${IMAGE_WITHOUT_PREVIEW_PROJECTION} } }`, { slug: path.substring(1) })
22
+ const { data: sanityData } = await useSanityQuery<Home | Page | NotFound>(
23
+ groq`*[(${groqFilter}) || _type == "notFound"][0] { _id, _type, title, modules, seo { _type, indexable, title, shortTitle, description, image ${IMAGE_WITHOUT_PREVIEW_PROJECTION} } }`,
24
+ { slug: path.substring(1) },
25
+ )
23
26
 
24
27
  const { baseURL } = useRuntimeConfig().public
25
28
  const seo = computed(() => sanityData.value?.seo)
26
- const url = computed(() => baseURL + (sanityData.value?.slug || '/'))
29
+ const url = computed(
30
+ () =>
31
+ ((baseURL as string) || '')
32
+ + ((sanityData.value && ('slug' in sanityData.value ? sanityData.value.slug.current : null)) || '/'),
33
+ )
27
34
 
28
- const { data: globalSEO } = await useSanityQuery<GlobalSEO>(groq`*[_type == 'settings'][0].seo { siteName, image ${IMAGE_WITHOUT_PREVIEW_PROJECTION} }`)
29
- const image: ComputedRef<ImageAsset> = computed(() => sanityData.value?.image?.asset || globalSEO.value?.image?.asset)
35
+ const { data: globalSEO } = await useSanityQuery<GlobalSEO>(
36
+ groq`*[_type == 'settings'][0].seo { siteName, image ${IMAGE_WITHOUT_PREVIEW_PROJECTION} }`,
37
+ )
38
+ const image: ComputedRef<ImageAsset | undefined> = computed(
39
+ () => sanityData.value?.seo.image?.asset || globalSEO.value?.image?.asset,
40
+ )
30
41
  const imageUrl = computed(() => image.value?.url)
31
42
  const imageDimensions = computed(() => image.value?.metadata.dimensions)
32
43
 
@@ -42,14 +53,12 @@ useHead({
42
53
  { name: 'og:url', content: () => url.value },
43
54
  { name: 'twitter:url', content: () => url.value },
44
55
  ],
45
- link: [
46
- { rel: 'canonical', href: () => url.value },
47
- ],
56
+ link: [{ rel: 'canonical', href: () => url.value }],
48
57
  })
49
58
 
50
59
  useSeoMeta({
51
60
  robots: () => `${seo.value?.indexable ? '' : 'no'}index,follow`,
52
- title: () => seo.value?.title,
61
+ title: () => seo.value?.title || '',
53
62
  description: () => seo.value?.description,
54
63
  ogTitle: () => seo.value?.shortTitle,
55
64
  ogDescription: () => seo.value?.description,
@@ -7,9 +7,9 @@
7
7
 
8
8
  <script setup lang="ts">
9
9
  import { PortableText, type PortableTextComponents } from '@portabletext/vue'
10
- import type { RichText } from '@devite/nuxt-sanity'
11
10
  import type { PortableTextChild, PortableTextSpan } from '@sanity/types'
12
- import { computed, h } from '#imports'
11
+ import type { RichText } from '@devite/nuxt-sanity'
12
+ import { computed, h } from 'vue'
13
13
  import { SanityLinkExternal, SanityLinkInternal } from '#components'
14
14
 
15
15
  const props = defineProps<{ data: RichText, placeholders?: Record<string, string> }>()
@@ -36,7 +36,7 @@ function replaceChildren(children: PortableTextChild[]): PortableTextChild[] {
36
36
  }
37
37
 
38
38
  function replacePlaceholders(text: string) {
39
- return text.replace(/\{\{(.*?)\}\}/g, (match, key) => {
39
+ return text.replace(/\{\{(.*?)}}/g, (match, key) => {
40
40
  if (!props.placeholders || !Object.prototype.hasOwnProperty.call(props.placeholders, key)) return match
41
41
 
42
42
  return props.placeholders[key]
@@ -0,0 +1,4 @@
1
+ import type { AsyncDataOptions } from 'nuxt/app';
2
+ import type { QueryParams } from '@sanity/client';
3
+ import { type AsyncSanityData, type SanityQueryResponse } from './useSanityQuery.js';
4
+ export declare const useLazySanityQuery: <T = unknown, E = Error>(query: string, _params?: QueryParams, options?: AsyncDataOptions<SanityQueryResponse<T | null>>) => AsyncSanityData<T | null, E>;
@@ -0,0 +1,4 @@
1
+ import { useSanityQuery } from "./useSanityQuery.js";
2
+ export const useLazySanityQuery = (query, _params = {}, options = {}) => {
3
+ return useSanityQuery(query, _params, options, true);
4
+ };
@@ -0,0 +1 @@
1
+ export declare const useSanityLiveMode: () => () => void;
@@ -0,0 +1,16 @@
1
+ import { onScopeDispose } from "vue";
2
+ import useSanityClient from "../utils/useSanityClient.js";
3
+ export const useSanityLiveMode = () => {
4
+ let disable = () => {
5
+ };
6
+ if (import.meta.client) {
7
+ const client = useSanityClient("default");
8
+ if (client.queryStore) {
9
+ disable = client.queryStore.enableLiveMode({
10
+ client: client.client
11
+ });
12
+ }
13
+ }
14
+ onScopeDispose(disable);
15
+ return disable;
16
+ };
@@ -0,0 +1,30 @@
1
+ import type { ContentSourceMap, QueryParams } from '@sanity/client';
2
+ import type { EncodeDataAttributeFunction } from '@sanity/core-loader/encode-data-attribute';
3
+ import type { AsyncDataOptions, AsyncDataRequestStatus } from 'nuxt/app';
4
+ import { type Ref } from 'vue';
5
+ export interface SanityQueryResponse<T> {
6
+ data: T;
7
+ sourceMap?: ContentSourceMap;
8
+ encodeDataAttribute?: EncodeDataAttributeFunction;
9
+ }
10
+ interface AsyncDataExecuteOptions {
11
+ _initial?: boolean;
12
+ dedupe?: boolean;
13
+ }
14
+ export interface _AsyncSanityData<T, E> {
15
+ data: Ref<T>;
16
+ sourceMap: Ref<ContentSourceMap | null>;
17
+ encodeDataAttribute: Ref<EncodeDataAttributeFunction | (() => void)>;
18
+ pending: Ref<boolean>;
19
+ refresh: (opts?: AsyncDataExecuteOptions) => Promise<void>;
20
+ execute: (opts?: AsyncDataExecuteOptions) => Promise<void>;
21
+ error: Ref<E | null>;
22
+ status: Ref<AsyncDataRequestStatus>;
23
+ }
24
+ export type AsyncSanityData<T, E> = _AsyncSanityData<T, E> & Promise<_AsyncSanityData<T, E>>;
25
+ export interface UseSanityQueryOptions<T> extends AsyncDataOptions<T> {
26
+ client?: 'default' | 'minimal';
27
+ perspective?: 'previewDrafts' | 'published' | 'raw';
28
+ }
29
+ export declare const useSanityQuery: <T = unknown, E = Error>(query: string, _params?: QueryParams, _options?: UseSanityQueryOptions<SanityQueryResponse<T | null>>, lazy?: boolean) => AsyncSanityData<T | null, E>;
30
+ export {};
@@ -0,0 +1,69 @@
1
+ import { hash } from "ohash";
2
+ import { defineEncodeDataAttribute } from "@sanity/core-loader/encode-data-attribute";
3
+ import { onScopeDispose, reactive, ref } from "vue";
4
+ import useSanityClient from "../utils/useSanityClient.js";
5
+ import { useAsyncData, useLazyAsyncData } from "#imports";
6
+ export const useSanityQuery = (query, _params = {}, _options = {}, lazy = false) => {
7
+ const { client: clientType, perspective: _perspective, ...options } = _options;
8
+ const client = clientType ? useSanityClient(clientType) : useSanityClient();
9
+ const hasQueryStore = "queryStore" in client && client.queryStore !== null;
10
+ const perspective = _perspective || (hasQueryStore ? "previewDrafts" : "published");
11
+ const key = "sanity-" + hash(query + (_params ? JSON.stringify(_params) : ""));
12
+ const reactiveParams = _params ? reactive(_params) : void 0;
13
+ if (reactiveParams) {
14
+ options.watch ||= [];
15
+ options.watch.push(reactiveParams);
16
+ }
17
+ const data = ref(null);
18
+ const sourceMap = ref(null);
19
+ const encodeDataAttribute = ref(() => {
20
+ });
21
+ function updateResult(newData, newSourceMap) {
22
+ data.value = newData;
23
+ sourceMap.value = newSourceMap || null;
24
+ if (client.config.visualEditing) {
25
+ encodeDataAttribute.value = defineEncodeDataAttribute(newData, newSourceMap, client.config.visualEditing?.studioUrl);
26
+ }
27
+ }
28
+ let fetchFunc = async () => {
29
+ return { data: await client.fetch(query, reactiveParams || {}, { perspective }) };
30
+ };
31
+ if (hasQueryStore) {
32
+ let setupFetcher = function(cb) {
33
+ unsubscribe();
34
+ const deepClonedParams = JSON.parse(JSON.stringify(_params));
35
+ const fetcher = defaultClient.queryStore.createFetcherStore(query, deepClonedParams, void 0);
36
+ unsubscribe = fetcher.subscribe((newSnapshot) => {
37
+ if (newSnapshot.data) {
38
+ updateResult(newSnapshot.data, newSnapshot.sourceMap);
39
+ cb?.(newSnapshot);
40
+ }
41
+ });
42
+ };
43
+ const defaultClient = client;
44
+ let unsubscribe = () => {
45
+ };
46
+ const proxyClient = {
47
+ fetch: (query2, params, options2) => $fetch(defaultClient.config.visualEditing.proxyEndpoint || "/_sanity/fetch", {
48
+ method: "POST",
49
+ body: { query: query2, params, options: options2 }
50
+ })
51
+ };
52
+ fetchFunc = async () => {
53
+ const currentClient = import.meta.server ? defaultClient.queryStore.unstable__serverClient.instance || defaultClient.client : proxyClient;
54
+ const { result: fetchData, resultSourceMap: sourceMap2 } = await currentClient.fetch(query, reactiveParams || {}, {
55
+ perspective,
56
+ filterResponse: false,
57
+ resultSourceMap: "withKeyArraySelector"
58
+ });
59
+ return sourceMap2 ? { data: fetchData, sourceMap: sourceMap2 } : { data: fetchData };
60
+ };
61
+ if (import.meta.client) setupFetcher();
62
+ onScopeDispose(unsubscribe);
63
+ }
64
+ const pendingData = lazy ? useLazyAsyncData(key, fetchFunc, options) : useAsyncData(key, fetchFunc, options);
65
+ return Object.assign(new Promise((resolve) => pendingData.then(({ data: { value } }) => {
66
+ updateResult(value.data, value.sourceMap);
67
+ resolve({ ...pendingData, data, sourceMap, encodeDataAttribute });
68
+ })), { ...pendingData, data, sourceMap, encodeDataAttribute });
69
+ };
@@ -0,0 +1,8 @@
1
+ import type { DisableVisualEditing, VisualEditingOptions } from '@sanity/visual-editing';
2
+ import type { SanityVisualEditingRefreshHandler } from '@devite/nuxt-sanity';
3
+ export interface VisualEditingProps {
4
+ refresh?: SanityVisualEditingRefreshHandler;
5
+ zIndex?: VisualEditingOptions['zIndex'];
6
+ }
7
+ /** @return A function to disable visual editing */
8
+ export declare const useSanityVisualEditing: (options?: VisualEditingProps) => DisableVisualEditing;
@@ -0,0 +1,44 @@
1
+ import { enableVisualEditing } from "@sanity/visual-editing";
2
+ import { onScopeDispose } from "vue";
3
+ import { reloadNuxtApp, useRouter } from "#imports";
4
+ export const useSanityVisualEditing = (options = {}) => {
5
+ const { refresh, zIndex } = options;
6
+ let disable = () => {
7
+ };
8
+ if (import.meta.client) {
9
+ const router = useRouter();
10
+ disable = enableVisualEditing({
11
+ zIndex,
12
+ refresh: (payload) => {
13
+ function refreshDefault() {
14
+ if (payload.source === "mutation" && payload.livePreviewEnabled)
15
+ return false;
16
+ return new Promise((resolve) => {
17
+ reloadNuxtApp({ ttl: 1e3 });
18
+ resolve();
19
+ });
20
+ }
21
+ return refresh ? refresh(payload, refreshDefault) : refreshDefault();
22
+ },
23
+ history: {
24
+ subscribe(navigate) {
25
+ router.isReady().then(() => navigate({ type: "replace", url: router.currentRoute.value.fullPath }));
26
+ return router.afterEach((to) => navigate({ type: "push", url: to.fullPath }));
27
+ },
28
+ update(update) {
29
+ switch (update.type) {
30
+ case "push":
31
+ case "replace":
32
+ router[update.type](update.url);
33
+ break;
34
+ case "pop":
35
+ router.back();
36
+ break;
37
+ }
38
+ }
39
+ }
40
+ });
41
+ }
42
+ onScopeDispose(disable);
43
+ return disable;
44
+ };
@@ -0,0 +1,4 @@
1
+ export declare const useSanityVisualEditingState: () => {
2
+ enabled: boolean;
3
+ isInFrame: () => boolean | undefined;
4
+ };
@@ -0,0 +1,12 @@
1
+ import { reactive } from "vue";
2
+ import { useState } from "#imports";
3
+ export const useSanityVisualEditingState = () => {
4
+ const enabled = useState("_sanity_visualEditing", () => false);
5
+ return reactive({
6
+ enabled,
7
+ isInFrame() {
8
+ if (import.meta.server) return void 0;
9
+ return !!(window.self !== window.top || window.opener);
10
+ }
11
+ });
12
+ };
@@ -0,0 +1,2 @@
1
+ declare const _default: import("nuxt/app").Plugin<Record<string, unknown>> & import("nuxt/app").ObjectPlugin<Record<string, unknown>>;
2
+ export default _default;
@@ -0,0 +1,30 @@
1
+ import { useSanityVisualEditingState } from "../composables/useSanityVisualEditingState.js";
2
+ import { useSanityLiveMode } from "../composables/useSanityLiveMode.js";
3
+ import { useSanityVisualEditing } from "../composables/useSanityVisualEditing.js";
4
+ import {
5
+ defineNuxtPlugin,
6
+ useCookie,
7
+ useRuntimeConfig
8
+ } from "#imports";
9
+ export default defineNuxtPlugin(() => {
10
+ const visualEditingState = useSanityVisualEditingState();
11
+ const $config = useRuntimeConfig();
12
+ const { visualEditing } = $config.public.sanity;
13
+ if (import.meta.server) {
14
+ if (visualEditing?.previewMode) {
15
+ const previewModeCookie = useCookie("__sanity_preview");
16
+ visualEditingState.enabled = visualEditing.previewModeId === previewModeCookie.value;
17
+ }
18
+ } else if (visualEditingState.enabled && visualEditing.mode !== "custom") {
19
+ switch (visualEditing?.mode) {
20
+ case "live-visual-editing":
21
+ case "visual-editing":
22
+ useSanityVisualEditing({
23
+ refresh: visualEditing?.refresh,
24
+ zIndex: visualEditing?.zIndex
25
+ });
26
+ if (visualEditing?.mode === "live-visual-editing") useSanityLiveMode();
27
+ break;
28
+ }
29
+ }
30
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
2
+ export default _default;
@@ -0,0 +1,6 @@
1
+ import { defineEventHandler, deleteCookie, getQuery, sendRedirect } from "h3";
2
+ export default defineEventHandler(async (event) => {
3
+ const { redirect } = getQuery(event);
4
+ deleteCookie(event, "__sanity_preview");
5
+ await sendRedirect(event, redirect?.toString() || "/");
6
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<import("h3").H3Error<unknown> | undefined>>;
2
+ export default _default;
@@ -0,0 +1,20 @@
1
+ import { validatePreviewUrl } from "@sanity/preview-url-secret";
2
+ import { createError, defineEventHandler, getRequestURL, sendRedirect, setCookie } from "h3";
3
+ import useSanityClient from "../../utils/useSanityClient.js";
4
+ export default defineEventHandler(async (event) => {
5
+ const client = useSanityClient("default");
6
+ const { isValid, redirectTo = "/" } = await validatePreviewUrl(client.client, getRequestURL(event).toString());
7
+ if (!isValid) {
8
+ return createError({
9
+ statusCode: 403,
10
+ statusMessage: "Invalid secret"
11
+ });
12
+ }
13
+ setCookie(event, "__sanity_preview", client.config.visualEditing.previewModeId || "", {
14
+ httpOnly: true,
15
+ sameSite: !import.meta.dev ? "none" : "lax",
16
+ secure: !import.meta.dev,
17
+ path: "/"
18
+ });
19
+ await sendRedirect(event, redirectTo, 307);
20
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<unknown>>;
2
+ export default _default;
@@ -0,0 +1,19 @@
1
+ import { createError, defineEventHandler, getCookie, readBody } from "h3";
2
+ import useSanityClient from "../utils/useSanityClient.js";
3
+ export default defineEventHandler(async (event) => {
4
+ const previewModeCookie = getCookie(event, "__sanity_preview");
5
+ if (!previewModeCookie) {
6
+ return createError({
7
+ statusCode: 403,
8
+ statusMessage: "This route is only available in preview mode"
9
+ });
10
+ }
11
+ const { query, params = {} } = await readBody(event);
12
+ if (!query) {
13
+ return createError({
14
+ statusCode: 400,
15
+ statusMessage: `Field "query" is required`
16
+ });
17
+ }
18
+ return await useSanityClient("default").fetch(query, params);
19
+ });
@@ -0,0 +1,3 @@
1
+ {
2
+ "extends": "../../../.nuxt/tsconfig.server.json"
3
+ }
@@ -0,0 +1,3 @@
1
+ import type SanityClient from '../../client/SanityClient.js';
2
+ import type { SanityClientType } from '../../utils/getOrCreateSanityClient.js';
3
+ export default function useSanityClient(type?: SanityClientType): SanityClient;
@@ -0,0 +1,17 @@
1
+ import defu from "defu";
2
+ import getOrCreateSanityClient from "../../utils/getOrCreateSanityClient.js";
3
+ import { useRuntimeConfig } from "#imports";
4
+ export default function useSanityClient(type) {
5
+ const $config = useRuntimeConfig();
6
+ const sanityConfig = defu($config.sanity, $config.public.sanity || {});
7
+ const visualEditingEnabled = sanityConfig.visualEditing && sanityConfig.visualEditing.previewMode !== false;
8
+ return getOrCreateSanityClient(
9
+ visualEditingEnabled || false,
10
+ visualEditingEnabled ? {
11
+ ...sanityConfig,
12
+ token: sanityConfig.visualEditing?.token,
13
+ useCdn: false
14
+ } : sanityConfig,
15
+ type
16
+ );
17
+ }
@@ -0,0 +1,4 @@
1
+ import type { ModuleOptions } from '@devite/nuxt-sanity';
2
+ import type SanityClient from '~/src/runtime/client/SanityClient';
3
+ export type SanityClientType = 'minimal' | 'default';
4
+ export default function getOrCreateSanityClient(visualEditing: boolean, config: ModuleOptions, type?: SanityClientType): SanityClient;
@@ -0,0 +1,15 @@
1
+ import MinimalSanityClient from "../client/MinimalSanityClient.js";
2
+ import DefaultSanityClient from "../client/DefaultSanityClient.js";
3
+ const clients = {};
4
+ export default function getOrCreateSanityClient(visualEditing, config, type) {
5
+ const clientType = visualEditing ? "default" : type || (config.minimalClient ? "minimal" : "default");
6
+ if (clientType in clients) return clients[clientType];
7
+ const clientConfig = {
8
+ ...config,
9
+ stega: visualEditing && config.stega
10
+ };
11
+ const client = clientType === "minimal" ? new MinimalSanityClient(clientConfig) : new DefaultSanityClient(clientConfig);
12
+ if (visualEditing && import.meta.client) client.createQueryStore();
13
+ clients[clientType] = client;
14
+ return client;
15
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * GROQ template string tag that allows for syntax highlighting and linting.
3
+ *
4
+ * Source: https://github.com/sanity-io/sanity/blob/next/packages/groq/src/groq.ts
5
+ */
6
+ export declare const groq: (template: {
7
+ raw: readonly string[] | ArrayLike<string>;
8
+ }, ...substitutions: any[]) => string;
@@ -0,0 +1,6 @@
1
+ export const groq = String.raw || ((strings, ...keys) => {
2
+ const lastIndex = strings.length - 1;
3
+ return strings.slice(0, lastIndex).reduce((acc, str, index) => {
4
+ return acc + str + keys[index];
5
+ }, "") + strings[lastIndex];
6
+ });
@@ -1,4 +1,4 @@
1
- export declare const IMAGE_ASSET_PROJECTION: any;
2
- export declare const IMAGE_WITHOUT_PREVIEW_PROJECTION: any;
3
- export declare const IMAGE_WITH_PREVIEW_PROJECTION: any;
4
- export declare const LINK_PROJECTION: any;
1
+ export declare const IMAGE_ASSET_PROJECTION: string;
2
+ export declare const IMAGE_WITHOUT_PREVIEW_PROJECTION: string;
3
+ export declare const IMAGE_WITH_PREVIEW_PROJECTION: string;
4
+ export declare const LINK_PROJECTION: string;
@@ -1,4 +1,4 @@
1
- import { groq } from "@nuxtjs/sanity/runtime/groq";
1
+ import { groq } from "./groq.js";
2
2
  export const IMAGE_ASSET_PROJECTION = groq`{
3
3
  _type,
4
4
  _id,
@@ -1,3 +1,3 @@
1
1
  import type { ImageAsset } from '@sanity/types';
2
- import type { Ref } from '#imports';
3
- export declare const resolveImageAssetById: (id: string) => Promise<Ref<ImageAsset | undefined>>;
2
+ import type { Ref } from 'vue';
3
+ export declare const resolveImageAssetById: (id: string) => Promise<Ref<ImageAsset | null>>;
@@ -1,5 +1,5 @@
1
- import { useSanityQuery } from "@nuxtjs/sanity/runtime/composables/visual-editing";
1
+ import { useSanityQuery } from "../composables/useSanityQuery.js";
2
2
  import { IMAGE_ASSET_PROJECTION } from "./projections.js";
3
3
  export const resolveImageAssetById = async (id) => {
4
- return (await useSanityQuery(`*[_type == "sanity.imageAsset" && _id == $assetId][0] ${IMAGE_ASSET_PROJECTION}`, { assetId: id })).data;
4
+ return useSanityQuery(`*[_type == "sanity.imageAsset" && _id == $assetId][0] ${IMAGE_ASSET_PROJECTION}`, { assetId: id }).data;
5
5
  };
@@ -1,4 +1,4 @@
1
1
  import type { Reference } from '@sanity/types';
2
2
  import type { LinkInternal } from '@devite/nuxt-sanity';
3
- import type { Ref } from '#imports';
4
- export declare const resolveInternalLink: (reference: Reference) => Promise<Ref<LinkInternal | undefined>>;
3
+ import type { Ref } from 'vue';
4
+ export declare const resolveInternalLink: (reference: Reference) => Promise<Ref<LinkInternal | null>>;
@@ -1,4 +1,4 @@
1
- import { useSanityQuery } from "@nuxtjs/sanity/runtime/composables/visual-editing";
1
+ import { useSanityQuery } from "../composables/useSanityQuery.js";
2
2
  export const resolveInternalLink = async (reference) => {
3
- return (await useSanityQuery(`*[_id == $documentId][0] { '_type': 'linkInternal', 'slug': coalesce(slug.current, '/') }`, { documentId: reference._ref })).data;
3
+ return useSanityQuery(`*[_id == $documentId][0] { '_type': 'linkInternal', 'slug': coalesce(slug.current, '/') }`, { documentId: reference._ref }).data;
4
4
  };
@@ -0,0 +1,2 @@
1
+ import type SanityClient from '../client/SanityClient.js';
2
+ export default function useSanityClient(type?: 'minimal' | 'default'): SanityClient;
@@ -0,0 +1,8 @@
1
+ import { useSanityVisualEditingState } from "../composables/useSanityVisualEditingState.js";
2
+ import getOrCreateSanityClient from "./getOrCreateSanityClient.js";
3
+ import { useRuntimeConfig } from "#imports";
4
+ export default function useSanityClient(type) {
5
+ const $config = useRuntimeConfig();
6
+ const sanityConfig = $config.public.sanity;
7
+ return getOrCreateSanityClient(useSanityVisualEditingState().enabled, sanityConfig, type);
8
+ }
package/dist/types.d.mts CHANGED
@@ -1,7 +1 @@
1
- import type { NuxtModule } from '@nuxt/schema'
2
-
3
- import type { default as Module } from './module.js'
4
-
5
- export type ModuleOptions = typeof Module extends NuxtModule<infer O> ? Partial<O> : Record<string, any>
6
-
7
- export { type GlobalSEO, type Home, type LinkExternal, type LinkInternal, type NotFound, type Page, type RichText, type SEO, default } from './module.js'
1
+ export { type GlobalSEO, type Home, type LinkExternal, type LinkInternal, type ModuleOptions, type NotFound, type Page, type RichText, type SEO, type SanityArray, type SanityModule, type SanityVisualEditingRefreshHandler, type VisualEditingOptions, default } from './module.js'
package/dist/types.d.ts CHANGED
@@ -1,7 +1 @@
1
- import type { NuxtModule } from '@nuxt/schema'
2
-
3
- import type { default as Module } from './module'
4
-
5
- export type ModuleOptions = typeof Module extends NuxtModule<infer O> ? Partial<O> : Record<string, any>
6
-
7
- export { type GlobalSEO, type Home, type LinkExternal, type LinkInternal, type NotFound, type Page, type RichText, type SEO, default } from './module'
1
+ export { type GlobalSEO, type Home, type LinkExternal, type LinkInternal, type ModuleOptions, type NotFound, type Page, type RichText, type SEO, type SanityArray, type SanityModule, type SanityVisualEditingRefreshHandler, type VisualEditingOptions, default } from './module'
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@devite/nuxt-sanity",
3
- "version": "1.5.3",
4
- "description": "Provides additional helper components and utilities for the Nuxt.js Sanity module",
3
+ "version": "2.0.0",
4
+ "description": "Advanced Sanity integration for Nuxt.js.",
5
5
  "repository": "devite-io/nuxt-sanity",
6
6
  "license": "MIT",
7
7
  "author": {
@@ -23,36 +23,50 @@
23
23
  ],
24
24
  "dependencies": {
25
25
  "@nuxt/image": "^1.8.1",
26
- "@nuxt/kit": "^3.13.2",
27
- "@nuxtjs/sanity": "^1.12.2",
26
+ "@nuxt/kit": "^3.14.1592",
28
27
  "@portabletext/vue": "^1.0.11",
29
28
  "@sanity/client": "^6.24.1",
30
- "@sanity/types": "^3.66.1"
29
+ "@sanity/core-loader": "^1.7.19",
30
+ "@sanity/preview-url-secret": "^2.0.5",
31
+ "@sanity/types": "^3.66.1",
32
+ "@sanity/visual-editing": "^2.10.5",
33
+ "defu": "^6.1.4",
34
+ "ofetch": "^1.4.1",
35
+ "ohash": "^1.1.4"
31
36
  },
32
37
  "devDependencies": {
33
- "@devite/nuxt-sanity": "link:",
34
- "@nuxt/eslint-config": "^0.5.7",
38
+ "@nuxt/eslint-config": "^0.7.2",
35
39
  "@nuxt/module-builder": "^0.8.4",
36
- "@nuxt/schema": "^3.13.2",
40
+ "@nuxt/schema": "^3.14.1592",
37
41
  "@nuxt/test-utils": "^3.15.1",
38
- "@types/node": "^22.10.1",
42
+ "@types/node": "latest",
39
43
  "changelogen": "^0.5.7",
40
- "eslint": "^9.12.0",
41
- "nuxt": "^3.13.2",
44
+ "eslint": "^9.16.0",
45
+ "h3": "^1.13.0",
46
+ "nuxt": "^3.14.1592",
42
47
  "prettier": "^3.4.2",
43
- "typescript": "^5.7.2",
48
+ "typescript": "~5.6.3",
44
49
  "vitest": "^2.1.8",
50
+ "vue-router": "^4.5.0",
45
51
  "vue-tsc": "^2.1.10"
46
52
  },
53
+ "resolutions": {
54
+ "@devite/nuxt-sanity": "link:."
55
+ },
56
+ "build": {
57
+ "externals": [
58
+ "@sanity/client"
59
+ ]
60
+ },
47
61
  "scripts": {
48
62
  "dev": "nuxi dev playground",
49
63
  "dev:cms": "cd playground/cms && pnpm dev",
50
64
  "dev:build": "nuxi build playground",
51
65
  "dev:prepare": "nuxt-module-build build --stub && nuxt-module-build prepare && nuxi prepare playground",
52
66
  "release": "pnpm lint && pnpm test && pnpm prepack && changelogen --release && pnpm publish --access=public && git push --follow-tags",
53
- "lint": "eslint .",
67
+ "lint": "eslint --fix .",
54
68
  "test": "vitest run --passWithNoTests",
55
69
  "test:watch": "vitest watch",
56
- "test:types": "vue-tsc --noEmit && cd playground && vue-tsc --noEmit"
70
+ "test:types": "vue-tsc --noEmit"
57
71
  }
58
72
  }