@laioutr/app-hygraph 1.9.0 → 1.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -24,6 +24,10 @@ Other Laioutr apps that also talk to Hygraph can import the client, middleware,
24
24
 
25
25
  The module also includes a demo blog implementation with orchestr-handlers for blog content: query handlers and query template providers for blog collections and posts, link handlers for connecting posts to collections, and component resolvers for rendering both.
26
26
 
27
+ ### Content Preview
28
+
29
+ When a request is marked as a preview (`clientEnv.isPreview`, set by Laioutr's content-preview gate), the connector reads Hygraph's **Draft** stage instead of **Published**, so editors see unpublished changes. This requires a [`previewToken`](#configuration) with Draft-stage permission; without one the connector fails soft and keeps serving published content.
30
+
27
31
  ## Configuration
28
32
 
29
33
  Add the module to your `nuxt.config.ts` and provide your Hygraph credentials:
@@ -44,6 +48,8 @@ export default defineNuxtConfig({
44
48
  | `contentApiUrl` | Hygraph Content API endpoint |
45
49
  | `imageBaseUrl` | Hygraph image CDN base URL (used by [`@nuxt/image`](https://image.nuxt.com/providers/hygraph)). Region-specific; find yours by querying `{ assets(first: 1) { url } }` against your Content API and taking the domain + first path-segment, e.g. `https://eu-west-2.graphassets.com/cmh4jxx7w1fce07l80dils2d1` |
46
50
  | `token` | Permanent auth token for the Content API |
51
+ | `previewToken` | Optional. Separate PAT with Draft-stage read permission, used only for preview requests. Kept distinct from `token` so published reads keep a least-privileged credential. Without it the connector always serves published content, even for requests marked as preview. |
52
+ | `previewApiUrl` | Optional. Alternate Content API endpoint for preview (Draft) reads. Hygraph's Content API already serves both stages, so this is only needed if a project observes CDN staleness on drafts. |
47
53
 
48
54
  ## Exports
49
55
 
@@ -132,6 +138,7 @@ npx @laioutr/cli rc fetch -p <org-slug>/<project-slug> -s <secret-key>
132
138
  export HYGRAPH_CONTENT_API_URL=<your-content-api-url>
133
139
  export HYGRAPH_TOKEN=<your-token>
134
140
  export HYGRAPH_IMAGE_BASE_URL=<your-image-base-url>
141
+ export HYGRAPH_PREVIEW_TOKEN=<your-draft-stage-token> # optional, enables preview/draft reads
135
142
  pnpm dev
136
143
  ```
137
144
 
package/dist/module.d.mts CHANGED
@@ -7,6 +7,14 @@ interface ModuleOptions {
7
7
  contentApiUrl: string;
8
8
  imageBaseUrl: string;
9
9
  token: string;
10
+ /**
11
+ * Optional. PAT with Draft-stage read permission. Separate from `token` so published reads keep a
12
+ * least-privileged credential. Without it the connector always serves published content, even when
13
+ * a verified preview token marks the request as a preview.
14
+ */
15
+ previewToken?: string;
16
+ /** Optional. Hygraph's Content API serves both stages; only needed if a project observes CDN staleness on drafts. */
17
+ previewApiUrl?: string;
10
18
  }
11
19
  /**
12
20
  * The config the module adds to nuxt.runtimeConfig.public['@laioutr/app-hygraph']
package/dist/module.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@laioutr/app-hygraph",
3
- "version": "1.9.0",
3
+ "version": "1.10.0",
4
4
  "configKey": "@laioutr/app-hygraph",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.1",
package/dist/module.mjs CHANGED
@@ -3,7 +3,7 @@ import { defu } from 'defu';
3
3
  import { registerLaioutrApp } from '@laioutr-core/kit';
4
4
 
5
5
  const name = "@laioutr/app-hygraph";
6
- const version = "1.9.0";
6
+ const version = "1.10.0";
7
7
 
8
8
  const module = defineNuxtModule({
9
9
  meta: {
@@ -1,5 +1,7 @@
1
1
  import type { HygraphClientConfig, HygraphResponse } from '../types/hygraph.js';
2
2
  export type { HygraphResponse };
3
- export declare const hygraphClientFactory: (explicitConfig?: HygraphClientConfig) => {
3
+ export declare const hygraphClientFactory: (explicitConfig?: HygraphClientConfig, options?: {
4
+ isPreview?: boolean;
5
+ }) => {
4
6
  request: <TData = unknown>(query: string, variables?: unknown) => Promise<HygraphResponse<TData>>;
5
7
  };
@@ -1,13 +1,25 @@
1
1
  import { useRuntimeConfig } from "#imports";
2
- export const hygraphClientFactory = (explicitConfig) => {
2
+ import { Stage } from "../generated/graphql.js";
3
+ export const hygraphClientFactory = (explicitConfig, options) => {
3
4
  const config = explicitConfig ?? useRuntimeConfig()["@laioutr/app-hygraph"];
5
+ let isPreview = options?.isPreview ?? false;
6
+ const previewToken = config.previewToken?.trim();
7
+ if (isPreview && !previewToken) {
8
+ console.warn("[app-hygraph] preview requested but previewToken is not configured \u2014 serving published content.");
9
+ isPreview = false;
10
+ }
4
11
  const request = async (query, variables = null) => {
5
- const res = await fetch(config.contentApiUrl, {
12
+ const res = await fetch(isPreview ? config.previewApiUrl ?? config.contentApiUrl : config.contentApiUrl, {
6
13
  method: "POST",
7
14
  headers: {
8
- Authorization: `Bearer ${config.token}`
15
+ Authorization: `Bearer ${isPreview ? previewToken : config.token}`
9
16
  },
10
- body: JSON.stringify({ query, variables })
17
+ // Every document in `queries/` declares `$stage: Stage = PUBLISHED`, so the variable can be
18
+ // injected unconditionally without the client knowing which operation it is sending.
19
+ body: JSON.stringify({
20
+ query,
21
+ variables: { ...variables, stage: isPreview ? Stage.Draft : Stage.Published }
22
+ })
11
23
  });
12
24
  return res.json();
13
25
  };
@@ -5720,6 +5720,7 @@ export type Glossary = Entity & Node & {
5720
5720
  /** Get the other localizations for this document */
5721
5721
  localizations: Array<Glossary>;
5722
5722
  metaDescription?: Maybe<Scalars['String']['output']>;
5723
+ metaKeywords?: Maybe<Scalars['String']['output']>;
5723
5724
  metaTitle?: Maybe<Scalars['String']['output']>;
5724
5725
  /** The time the document was published. Null on documents in draft stage. */
5725
5726
  publishedAt?: Maybe<Scalars['DateTime']['output']>;
@@ -5822,6 +5823,8 @@ export type GlossaryCreateInput = {
5822
5823
  localizations?: InputMaybe<GlossaryCreateLocalizationsInput>;
5823
5824
  /** metaDescription input for default locale (en) */
5824
5825
  metaDescription?: InputMaybe<Scalars['String']['input']>;
5826
+ /** metaKeywords input for default locale (en) */
5827
+ metaKeywords?: InputMaybe<Scalars['String']['input']>;
5825
5828
  /** metaTitle input for default locale (en) */
5826
5829
  metaTitle?: InputMaybe<Scalars['String']['input']>;
5827
5830
  slug: Scalars['String']['input'];
@@ -5833,6 +5836,7 @@ export type GlossaryCreateLocalizationDataInput = {
5833
5836
  content: Scalars['RichTextAST']['input'];
5834
5837
  createdAt?: InputMaybe<Scalars['DateTime']['input']>;
5835
5838
  metaDescription?: InputMaybe<Scalars['String']['input']>;
5839
+ metaKeywords?: InputMaybe<Scalars['String']['input']>;
5836
5840
  metaTitle?: InputMaybe<Scalars['String']['input']>;
5837
5841
  title: Scalars['String']['input'];
5838
5842
  updatedAt?: InputMaybe<Scalars['DateTime']['input']>;
@@ -5975,6 +5979,8 @@ export declare enum GlossaryOrderByInput {
5975
5979
  IdDesc = "id_DESC",
5976
5980
  MetaDescriptionAsc = "metaDescription_ASC",
5977
5981
  MetaDescriptionDesc = "metaDescription_DESC",
5982
+ MetaKeywordsAsc = "metaKeywords_ASC",
5983
+ MetaKeywordsDesc = "metaKeywords_DESC",
5978
5984
  MetaTitleAsc = "metaTitle_ASC",
5979
5985
  MetaTitleDesc = "metaTitle_DESC",
5980
5986
  PublishedAtAsc = "publishedAt_ASC",
@@ -5993,6 +5999,8 @@ export type GlossaryUpdateInput = {
5993
5999
  localizations?: InputMaybe<GlossaryUpdateLocalizationsInput>;
5994
6000
  /** metaDescription input for default locale (en) */
5995
6001
  metaDescription?: InputMaybe<Scalars['String']['input']>;
6002
+ /** metaKeywords input for default locale (en) */
6003
+ metaKeywords?: InputMaybe<Scalars['String']['input']>;
5996
6004
  /** metaTitle input for default locale (en) */
5997
6005
  metaTitle?: InputMaybe<Scalars['String']['input']>;
5998
6006
  slug?: InputMaybe<Scalars['String']['input']>;
@@ -6002,6 +6010,7 @@ export type GlossaryUpdateInput = {
6002
6010
  export type GlossaryUpdateLocalizationDataInput = {
6003
6011
  content?: InputMaybe<Scalars['RichTextAST']['input']>;
6004
6012
  metaDescription?: InputMaybe<Scalars['String']['input']>;
6013
+ metaKeywords?: InputMaybe<Scalars['String']['input']>;
6005
6014
  metaTitle?: InputMaybe<Scalars['String']['input']>;
6006
6015
  title?: InputMaybe<Scalars['String']['input']>;
6007
6016
  };
@@ -6041,6 +6050,8 @@ export type GlossaryUpdateManyInput = {
6041
6050
  localizations?: InputMaybe<GlossaryUpdateManyLocalizationsInput>;
6042
6051
  /** metaDescription input for default locale (en) */
6043
6052
  metaDescription?: InputMaybe<Scalars['String']['input']>;
6053
+ /** metaKeywords input for default locale (en) */
6054
+ metaKeywords?: InputMaybe<Scalars['String']['input']>;
6044
6055
  /** metaTitle input for default locale (en) */
6045
6056
  metaTitle?: InputMaybe<Scalars['String']['input']>;
6046
6057
  /** title input for default locale (en) */
@@ -6049,6 +6060,7 @@ export type GlossaryUpdateManyInput = {
6049
6060
  export type GlossaryUpdateManyLocalizationDataInput = {
6050
6061
  content?: InputMaybe<Scalars['RichTextAST']['input']>;
6051
6062
  metaDescription?: InputMaybe<Scalars['String']['input']>;
6063
+ metaKeywords?: InputMaybe<Scalars['String']['input']>;
6052
6064
  metaTitle?: InputMaybe<Scalars['String']['input']>;
6053
6065
  title?: InputMaybe<Scalars['String']['input']>;
6054
6066
  };
@@ -6175,6 +6187,25 @@ export type GlossaryWhereInput = {
6175
6187
  metaDescription_not_starts_with?: InputMaybe<Scalars['String']['input']>;
6176
6188
  /** All values starting with the given string. */
6177
6189
  metaDescription_starts_with?: InputMaybe<Scalars['String']['input']>;
6190
+ metaKeywords?: InputMaybe<Scalars['String']['input']>;
6191
+ /** All values containing the given string. */
6192
+ metaKeywords_contains?: InputMaybe<Scalars['String']['input']>;
6193
+ /** All values ending with the given string. */
6194
+ metaKeywords_ends_with?: InputMaybe<Scalars['String']['input']>;
6195
+ /** All values that are contained in given list. */
6196
+ metaKeywords_in?: InputMaybe<Array<InputMaybe<Scalars['String']['input']>>>;
6197
+ /** Any other value that exists and is not equal to the given value. */
6198
+ metaKeywords_not?: InputMaybe<Scalars['String']['input']>;
6199
+ /** All values not containing the given string. */
6200
+ metaKeywords_not_contains?: InputMaybe<Scalars['String']['input']>;
6201
+ /** All values not ending with the given string */
6202
+ metaKeywords_not_ends_with?: InputMaybe<Scalars['String']['input']>;
6203
+ /** All values that are not contained in given list. */
6204
+ metaKeywords_not_in?: InputMaybe<Array<InputMaybe<Scalars['String']['input']>>>;
6205
+ /** All values not starting with the given string. */
6206
+ metaKeywords_not_starts_with?: InputMaybe<Scalars['String']['input']>;
6207
+ /** All values starting with the given string. */
6208
+ metaKeywords_starts_with?: InputMaybe<Scalars['String']['input']>;
6178
6209
  metaTitle?: InputMaybe<Scalars['String']['input']>;
6179
6210
  /** All values containing the given string. */
6180
6211
  metaTitle_contains?: InputMaybe<Scalars['String']['input']>;
@@ -7621,6 +7652,7 @@ export declare enum Locale {
7621
7652
  De = "de",
7622
7653
  /** System locale */
7623
7654
  En = "en",
7655
+ Es = "es",
7624
7656
  Fr = "fr"
7625
7657
  }
7626
7658
  /** Representing a geolocation point with latitude and longitude */
@@ -12629,7 +12661,7 @@ export type BlogTopicsQuery = {
12629
12661
  export type MediaLibraryListQueryVariables = Exact<{
12630
12662
  skip?: InputMaybe<Scalars['Int']['input']>;
12631
12663
  first?: InputMaybe<Scalars['Int']['input']>;
12632
- search?: InputMaybe<Scalars['String']['input']>;
12664
+ where?: InputMaybe<AssetWhereInput>;
12633
12665
  }>;
12634
12666
  export type MediaLibraryListQuery = {
12635
12667
  assets: Array<{
@@ -215,6 +215,8 @@ export var GlossaryOrderByInput = /* @__PURE__ */ ((GlossaryOrderByInput2) => {
215
215
  GlossaryOrderByInput2["IdDesc"] = "id_DESC";
216
216
  GlossaryOrderByInput2["MetaDescriptionAsc"] = "metaDescription_ASC";
217
217
  GlossaryOrderByInput2["MetaDescriptionDesc"] = "metaDescription_DESC";
218
+ GlossaryOrderByInput2["MetaKeywordsAsc"] = "metaKeywords_ASC";
219
+ GlossaryOrderByInput2["MetaKeywordsDesc"] = "metaKeywords_DESC";
218
220
  GlossaryOrderByInput2["MetaTitleAsc"] = "metaTitle_ASC";
219
221
  GlossaryOrderByInput2["MetaTitleDesc"] = "metaTitle_DESC";
220
222
  GlossaryOrderByInput2["PublishedAtAsc"] = "publishedAt_ASC";
@@ -275,6 +277,7 @@ export var LearningResourceOrderByInput = /* @__PURE__ */ ((LearningResourceOrde
275
277
  export var Locale = /* @__PURE__ */ ((Locale2) => {
276
278
  Locale2["De"] = "de";
277
279
  Locale2["En"] = "en";
280
+ Locale2["Es"] = "es";
278
281
  Locale2["Fr"] = "fr";
279
282
  return Locale2;
280
283
  })(Locale || {});
@@ -11,7 +11,8 @@ export default defineMediaLibraryProvider({
11
11
  const result = await client.request(MEDIA_LIBRARY_LIST_QUERY, {
12
12
  skip: offset,
13
13
  first: limit,
14
- search
14
+ // Only constrain by `_search` when a term is present; an empty filter lists all assets (browse).
15
+ where: search ? { _search: search } : {}
15
16
  });
16
17
  const items = result.data.assets.map(
17
18
  (asset) => ({
@@ -4,4 +4,6 @@ export const defineHygraph = defineOrchestr.meta({
4
4
  app: "@laioutr/app-hygraph",
5
5
  logoUrl: "/app-hygraph/logo.svg",
6
6
  label: "Hygraph"
7
- }).extendRequest(async () => ({ context: { hygraph: hygraphClientFactory() } }));
7
+ }).extendRequest(async ({ clientEnv }) => ({
8
+ context: { hygraph: hygraphClientFactory(void 0, { isPreview: clientEnv.isPreview }) }
9
+ }));
@@ -1,10 +1,10 @@
1
- import { BlogCollectionBase } from "@laioutr-core/canonical-types/entity/blog-collection";
1
+ import { BlogCollectionBase, BlogCollectionSeo } from "@laioutr-core/canonical-types/entity/blog-collection";
2
2
  import { blogCollectionToken } from "../../const/passthroughTokens.js";
3
3
  import { defineHygraph } from "../../middleware/defineHygraph.js";
4
4
  export default defineHygraph.componentResolver({
5
5
  entityType: "BlogCollection",
6
6
  label: "Blog Collection",
7
- provides: [BlogCollectionBase],
7
+ provides: [BlogCollectionBase, BlogCollectionSeo],
8
8
  resolve: async ({ passthrough, $entity }) => {
9
9
  const collection = passthrough.require(blogCollectionToken);
10
10
  return {
@@ -14,6 +14,14 @@ export default defineHygraph.componentResolver({
14
14
  base: {
15
15
  slug: collection.slug,
16
16
  title: collection.title
17
+ },
18
+ // Resolve `seo` locally so BlogCollection seo requests stay in the
19
+ // Hygraph app. Without a Hygraph provider, the shared `BlogCollection`
20
+ // entity type routes seo to another app's resolver (e.g. Shopify's
21
+ // `nodes(ids:)` query), which rejects the Hygraph id as an invalid
22
+ // global id. Hygraph blog collections/topics only carry `title`.
23
+ seo: {
24
+ title: collection.title
17
25
  }
18
26
  })
19
27
  ]
@@ -1,7 +1,7 @@
1
- export declare const BLOGS_QUERY = "\n #graphql\n \n #graphql\n \n #graphql\n fragment Asset on Asset {\n url\n fileName\n mimeType\n width\n height\n handle\n }\n\n fragment Blog on Blog {\n id\n title\n slug\n content {\n html\n }\n image {\n ...Asset\n }\n publishedAt\n metaTitle\n metaDescription\n }\n\n query Blogs($skip: Int, $first: Int, $collectionId: ID, $locales: [Locale!]!) {\n blogs(\n skip: $skip\n first: $first\n orderBy: createdAt_DESC\n where: { blogCollection: { id: $collectionId } }\n locales: $locales\n ) {\n ...Blog\n }\n blogsConnection(where: { blogCollection: { id: $collectionId } }, locales: $locales) {\n aggregate {\n count\n }\n }\n }\n";
2
- export declare const BLOGS_BY_TOPIC_QUERY = "\n #graphql\n \n #graphql\n \n #graphql\n fragment Asset on Asset {\n url\n fileName\n mimeType\n width\n height\n handle\n }\n\n fragment Blog on Blog {\n id\n title\n slug\n content {\n html\n }\n image {\n ...Asset\n }\n publishedAt\n metaTitle\n metaDescription\n }\n\n query BlogsByTopic($skip: Int, $first: Int, $topicId: ID, $locales: [Locale!]!) {\n blogs(\n skip: $skip\n first: $first\n orderBy: createdAt_DESC\n where: { topics_some: { id: $topicId } }\n locales: $locales\n ) {\n ...Blog\n }\n blogsConnection(where: { topics_some: { id: $topicId } }, locales: $locales) {\n aggregate {\n count\n }\n }\n }\n";
3
- export declare const BLOG_POST_BY_SLUG_QUERY = "\n #graphql\n \n #graphql\n \n #graphql\n fragment Asset on Asset {\n url\n fileName\n mimeType\n width\n height\n handle\n }\n\n fragment Blog on Blog {\n id\n title\n slug\n content {\n html\n }\n image {\n ...Asset\n }\n publishedAt\n metaTitle\n metaDescription\n }\n\n query BlogPostBySlug($slug: String!, $locales: [Locale!]!) {\n blog(where: { slug: $slug }, locales: $locales) {\n ...Blog\n }\n }\n";
4
- export declare const BLOG_COLLECTION_BY_SLUG_QUERY = "\n #graphql\n query BlogCollectionBySlug($slug: String!, $locales: [Locale!]!) {\n blogCollection(where: { slug: $slug }, locales: $locales) {\n id\n slug\n title\n }\n }\n";
5
- export declare const BLOG_COLLECTIONS_QUERY = "\n #graphql\n query BlogCollections($locales: [Locale!]!) {\n blogCollections(locales: $locales) {\n slug\n title\n }\n }\n";
6
- export declare const BLOG_TOPIC_BY_SLUG_QUERY = "\n #graphql\n query BlogTopicBySlug($slug: String!, $locales: [Locale!]!) {\n topic(where: { slug: $slug }, locales: $locales) {\n id\n slug\n title\n }\n }\n";
7
- export declare const BLOG_TOPICS_QUERY = "\n #graphql\n query BlogTopics($locales: [Locale!]!, $first: Int, $where: TopicWhereInput) {\n topics(locales: $locales, first: $first, where: $where) {\n slug\n title\n }\n }\n";
1
+ export declare const BLOGS_QUERY = "\n #graphql\n \n #graphql\n \n #graphql\n fragment Asset on Asset {\n url\n fileName\n mimeType\n width\n height\n handle\n }\n\n fragment Blog on Blog {\n id\n title\n slug\n content {\n html\n }\n image {\n ...Asset\n }\n publishedAt\n metaTitle\n metaDescription\n }\n\n query Blogs($skip: Int, $first: Int, $collectionId: ID, $locales: [Locale!]!, $stage: Stage = PUBLISHED) {\n blogs(\n skip: $skip\n first: $first\n orderBy: createdAt_DESC\n where: { blogCollection: { id: $collectionId } }\n locales: $locales\n stage: $stage\n ) {\n ...Blog\n }\n blogsConnection(where: { blogCollection: { id: $collectionId } }, locales: $locales, stage: $stage) {\n aggregate {\n count\n }\n }\n }\n";
2
+ export declare const BLOGS_BY_TOPIC_QUERY = "\n #graphql\n \n #graphql\n \n #graphql\n fragment Asset on Asset {\n url\n fileName\n mimeType\n width\n height\n handle\n }\n\n fragment Blog on Blog {\n id\n title\n slug\n content {\n html\n }\n image {\n ...Asset\n }\n publishedAt\n metaTitle\n metaDescription\n }\n\n query BlogsByTopic($skip: Int, $first: Int, $topicId: ID, $locales: [Locale!]!, $stage: Stage = PUBLISHED) {\n blogs(\n skip: $skip\n first: $first\n orderBy: createdAt_DESC\n where: { topics_some: { id: $topicId } }\n locales: $locales\n stage: $stage\n ) {\n ...Blog\n }\n blogsConnection(where: { topics_some: { id: $topicId } }, locales: $locales, stage: $stage) {\n aggregate {\n count\n }\n }\n }\n";
3
+ export declare const BLOG_POST_BY_SLUG_QUERY = "\n #graphql\n \n #graphql\n \n #graphql\n fragment Asset on Asset {\n url\n fileName\n mimeType\n width\n height\n handle\n }\n\n fragment Blog on Blog {\n id\n title\n slug\n content {\n html\n }\n image {\n ...Asset\n }\n publishedAt\n metaTitle\n metaDescription\n }\n\n query BlogPostBySlug($slug: String!, $locales: [Locale!]!, $stage: Stage = PUBLISHED) {\n blog(where: { slug: $slug }, locales: $locales, stage: $stage) {\n ...Blog\n }\n }\n";
4
+ export declare const BLOG_COLLECTION_BY_SLUG_QUERY = "\n #graphql\n query BlogCollectionBySlug($slug: String!, $locales: [Locale!]!, $stage: Stage = PUBLISHED) {\n blogCollection(where: { slug: $slug }, locales: $locales, stage: $stage) {\n id\n slug\n title\n }\n }\n";
5
+ export declare const BLOG_COLLECTIONS_QUERY = "\n #graphql\n query BlogCollections($locales: [Locale!]!, $stage: Stage = PUBLISHED) {\n blogCollections(locales: $locales, stage: $stage) {\n slug\n title\n }\n }\n";
6
+ export declare const BLOG_TOPIC_BY_SLUG_QUERY = "\n #graphql\n query BlogTopicBySlug($slug: String!, $locales: [Locale!]!, $stage: Stage = PUBLISHED) {\n topic(where: { slug: $slug }, locales: $locales, stage: $stage) {\n id\n slug\n title\n }\n }\n";
7
+ export declare const BLOG_TOPICS_QUERY = "\n #graphql\n query BlogTopics($locales: [Locale!]!, $first: Int, $where: TopicWhereInput, $stage: Stage = PUBLISHED) {\n topics(locales: $locales, first: $first, where: $where, stage: $stage) {\n slug\n title\n }\n }\n";
@@ -25,17 +25,18 @@ export const BLOGS_QUERY = (
25
25
  `
26
26
  #graphql
27
27
  ${BlogFragment}
28
- query Blogs($skip: Int, $first: Int, $collectionId: ID, $locales: [Locale!]!) {
28
+ query Blogs($skip: Int, $first: Int, $collectionId: ID, $locales: [Locale!]!, $stage: Stage = PUBLISHED) {
29
29
  blogs(
30
30
  skip: $skip
31
31
  first: $first
32
32
  orderBy: createdAt_DESC
33
33
  where: { blogCollection: { id: $collectionId } }
34
34
  locales: $locales
35
+ stage: $stage
35
36
  ) {
36
37
  ...Blog
37
38
  }
38
- blogsConnection(where: { blogCollection: { id: $collectionId } }, locales: $locales) {
39
+ blogsConnection(where: { blogCollection: { id: $collectionId } }, locales: $locales, stage: $stage) {
39
40
  aggregate {
40
41
  count
41
42
  }
@@ -48,17 +49,18 @@ export const BLOGS_BY_TOPIC_QUERY = (
48
49
  `
49
50
  #graphql
50
51
  ${BlogFragment}
51
- query BlogsByTopic($skip: Int, $first: Int, $topicId: ID, $locales: [Locale!]!) {
52
+ query BlogsByTopic($skip: Int, $first: Int, $topicId: ID, $locales: [Locale!]!, $stage: Stage = PUBLISHED) {
52
53
  blogs(
53
54
  skip: $skip
54
55
  first: $first
55
56
  orderBy: createdAt_DESC
56
57
  where: { topics_some: { id: $topicId } }
57
58
  locales: $locales
59
+ stage: $stage
58
60
  ) {
59
61
  ...Blog
60
62
  }
61
- blogsConnection(where: { topics_some: { id: $topicId } }, locales: $locales) {
63
+ blogsConnection(where: { topics_some: { id: $topicId } }, locales: $locales, stage: $stage) {
62
64
  aggregate {
63
65
  count
64
66
  }
@@ -71,8 +73,8 @@ export const BLOG_POST_BY_SLUG_QUERY = (
71
73
  `
72
74
  #graphql
73
75
  ${BlogFragment}
74
- query BlogPostBySlug($slug: String!, $locales: [Locale!]!) {
75
- blog(where: { slug: $slug }, locales: $locales) {
76
+ query BlogPostBySlug($slug: String!, $locales: [Locale!]!, $stage: Stage = PUBLISHED) {
77
+ blog(where: { slug: $slug }, locales: $locales, stage: $stage) {
76
78
  ...Blog
77
79
  }
78
80
  }
@@ -82,8 +84,8 @@ export const BLOG_COLLECTION_BY_SLUG_QUERY = (
82
84
  /* GraphQL */
83
85
  `
84
86
  #graphql
85
- query BlogCollectionBySlug($slug: String!, $locales: [Locale!]!) {
86
- blogCollection(where: { slug: $slug }, locales: $locales) {
87
+ query BlogCollectionBySlug($slug: String!, $locales: [Locale!]!, $stage: Stage = PUBLISHED) {
88
+ blogCollection(where: { slug: $slug }, locales: $locales, stage: $stage) {
87
89
  id
88
90
  slug
89
91
  title
@@ -95,8 +97,8 @@ export const BLOG_COLLECTIONS_QUERY = (
95
97
  /* GraphQL */
96
98
  `
97
99
  #graphql
98
- query BlogCollections($locales: [Locale!]!) {
99
- blogCollections(locales: $locales) {
100
+ query BlogCollections($locales: [Locale!]!, $stage: Stage = PUBLISHED) {
101
+ blogCollections(locales: $locales, stage: $stage) {
100
102
  slug
101
103
  title
102
104
  }
@@ -107,8 +109,8 @@ export const BLOG_TOPIC_BY_SLUG_QUERY = (
107
109
  /* GraphQL */
108
110
  `
109
111
  #graphql
110
- query BlogTopicBySlug($slug: String!, $locales: [Locale!]!) {
111
- topic(where: { slug: $slug }, locales: $locales) {
112
+ query BlogTopicBySlug($slug: String!, $locales: [Locale!]!, $stage: Stage = PUBLISHED) {
113
+ topic(where: { slug: $slug }, locales: $locales, stage: $stage) {
112
114
  id
113
115
  slug
114
116
  title
@@ -120,8 +122,8 @@ export const BLOG_TOPICS_QUERY = (
120
122
  /* GraphQL */
121
123
  `
122
124
  #graphql
123
- query BlogTopics($locales: [Locale!]!, $first: Int, $where: TopicWhereInput) {
124
- topics(locales: $locales, first: $first, where: $where) {
125
+ query BlogTopics($locales: [Locale!]!, $first: Int, $where: TopicWhereInput, $stage: Stage = PUBLISHED) {
126
+ topics(locales: $locales, first: $first, where: $where, stage: $stage) {
125
127
  slug
126
128
  title
127
129
  }
@@ -1 +1 @@
1
- export declare const MEDIA_LIBRARY_LIST_QUERY = "\n #graphql\n \n #graphql\n fragment Asset on Asset {\n url\n fileName\n mimeType\n width\n height\n handle\n }\n\n query MediaLibraryList($skip: Int, $first: Int, $search: String) {\n assets(skip: $skip, first: $first, orderBy: createdAt_DESC, where: { _search: $search }) {\n ...Asset\n }\n }\n";
1
+ export declare const MEDIA_LIBRARY_LIST_QUERY = "\n #graphql\n \n #graphql\n fragment Asset on Asset {\n url\n fileName\n mimeType\n width\n height\n handle\n }\n\n query MediaLibraryList($skip: Int, $first: Int, $where: AssetWhereInput, $stage: Stage = PUBLISHED) {\n assets(skip: $skip, first: $first, orderBy: createdAt_DESC, where: $where, stage: $stage) {\n ...Asset\n }\n }\n";
@@ -4,8 +4,8 @@ export const MEDIA_LIBRARY_LIST_QUERY = (
4
4
  `
5
5
  #graphql
6
6
  ${AssetFragment}
7
- query MediaLibraryList($skip: Int, $first: Int, $search: String) {
8
- assets(skip: $skip, first: $first, orderBy: createdAt_DESC, where: { _search: $search }) {
7
+ query MediaLibraryList($skip: Int, $first: Int, $where: AssetWhereInput, $stage: Stage = PUBLISHED) {
8
+ assets(skip: $skip, first: $first, orderBy: createdAt_DESC, where: $where, stage: $stage) {
9
9
  ...Asset
10
10
  }
11
11
  }
@@ -9,6 +9,14 @@ export interface HygraphAsset {
9
9
  export interface HygraphClientConfig {
10
10
  contentApiUrl: string;
11
11
  token: string;
12
+ /**
13
+ * Optional. PAT with Draft-stage read permission. Separate from `token` so published reads keep a
14
+ * least-privileged credential. Without it the connector always serves published content, even when
15
+ * a verified preview token marks the request as a preview.
16
+ */
17
+ previewToken?: string;
18
+ /** Optional. Hygraph's Content API serves both stages; only needed if a project observes CDN staleness on drafts. */
19
+ previewApiUrl?: string;
12
20
  }
13
21
  export interface HygraphResponse<TData> {
14
22
  data: TData;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@laioutr/app-hygraph",
3
- "version": "1.9.0",
3
+ "version": "1.10.0",
4
4
  "description": "Laioutr Hygraph App",
5
5
  "repository": "your-org/@laioutr/app-hygraph",
6
6
  "license": "MIT",
@@ -43,17 +43,6 @@
43
43
  "files": [
44
44
  "dist"
45
45
  ],
46
- "scripts": {
47
- "dev": "npm run dev:prepare && nuxi dev playground",
48
- "dev:build": "nuxi build playground",
49
- "dev:prepare": "nuxt-module-build build --stub && nuxt-module-build prepare && nuxi prepare playground",
50
- "lint": "eslint .",
51
- "prepack": "nuxt-module-build build",
52
- "release": "npm run lint && npm run test && npm run prepack && changelogen --release && npm publish --access public && git push --follow-tags",
53
- "test": "vitest run",
54
- "test:types": "vue-tsc --noEmit && cd playground && vue-tsc --noEmit",
55
- "test:watch": "vitest watch"
56
- },
57
46
  "dependencies": {
58
47
  "@nuxt/kit": "3.16.2",
59
48
  "zod": "3.25.61"
@@ -87,9 +76,9 @@
87
76
  "peerDependencies": {
88
77
  "@graphql-codegen/cli": "^6.0.0",
89
78
  "@laioutr-core/canonical-types": ">=0.25.0",
90
- "@laioutr-core/core-types": ">=0.33.1",
91
- "@laioutr-core/frontend-core": ">=0.33.1",
92
- "@laioutr-core/kit": ">=0.33.1",
79
+ "@laioutr-core/core-types": ">=0.35.0",
80
+ "@laioutr-core/frontend-core": ">=0.35.0",
81
+ "@laioutr-core/kit": ">=0.35.0",
93
82
  "graphql": "^16.0.0"
94
83
  },
95
84
  "peerDependenciesMeta": {
@@ -103,5 +92,15 @@
103
92
  "engines": {
104
93
  "node": ">=22.12.0",
105
94
  "pnpm": ">=10.15.0"
95
+ },
96
+ "scripts": {
97
+ "dev": "npm run dev:prepare && nuxi dev playground",
98
+ "dev:build": "nuxi build playground",
99
+ "dev:prepare": "nuxt-module-build build --stub && nuxt-module-build prepare && nuxi prepare playground",
100
+ "lint": "eslint .",
101
+ "release": "npm run lint && npm run test && npm run prepack && changelogen --release && npm publish --access public && git push --follow-tags",
102
+ "test": "vitest run",
103
+ "test:types": "vue-tsc --noEmit && cd playground && vue-tsc --noEmit",
104
+ "test:watch": "vitest watch"
106
105
  }
107
- }
106
+ }