@fourtwelvelabs/fetch-contentful 0.4.1 → 1.1.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/dist/index.d.ts CHANGED
@@ -25,6 +25,21 @@ interface ContentfulGraphQLError {
25
25
  path?: Array<string | number>;
26
26
  extensions?: Record<string, unknown>;
27
27
  }
28
+ /**
29
+ * What to do about a link Contentful could not resolve — a reference whose
30
+ * target was deleted, or (on the Delivery API) never published.
31
+ *
32
+ * Contentful answers these with HTTP 200, usable `data`, a `null` where the
33
+ * link should have been, and an `UNRESOLVABLE_LINK` object in `errors`. In a
34
+ * collection the null takes the *position* of the missing entry, so
35
+ * `items` is `(Entry | null)[]` and the obvious `.map()` over it throws on
36
+ * a day an editor happened to unpublish something.
37
+ *
38
+ * - `'omit'` — drop the null positions and resolve. The default.
39
+ * - `'null'` — resolve with the holes intact (Contentful's raw behavior).
40
+ * - `'error'` — reject the whole call, as this library did before 1.0.
41
+ */
42
+ type UnresolvableLinkMode = 'omit' | 'null' | 'error';
28
43
  /** Options accepted by {@link fetchContentful}. */
29
44
  interface FetchContentfulOptions<TVariables extends GraphQLVariables = GraphQLVariables> {
30
45
  /** GraphQL variables for the query. */
@@ -90,15 +105,6 @@ interface FetchContentfulOptions<TVariables extends GraphQLVariables = GraphQLVa
90
105
  * shipping it to the browser is acceptable for your app.
91
106
  */
92
107
  previewToken?: string;
93
- /**
94
- * Access token for whichever mode is active.
95
- *
96
- * @deprecated Use {@link FetchContentfulOptions.deliveryToken} and
97
- * {@link FetchContentfulOptions.previewToken}. A single `token` cannot
98
- * serve both modes, so a factory configured with one sends the wrong
99
- * token as soon as a call passes `preview: true`.
100
- */
101
- token?: string;
102
108
  /**
103
109
  * Number of retry attempts after the first failed request (per network
104
110
  * request, including subqueries). Defaults to `5`.
@@ -124,6 +130,29 @@ interface FetchContentfulOptions<TVariables extends GraphQLVariables = GraphQLVa
124
130
  * entry to stitch the result back onto.
125
131
  */
126
132
  autoSplitNestedCollections?: boolean;
133
+ /**
134
+ * When the outer query — after minification, and after the splitting
135
+ * above — still exceeds {@link FetchContentfulOptions.maxQuerySize}, keep
136
+ * peeling off the single largest remaining field (any field with a
137
+ * selection set, one-to-one references included, not just `*Collection`
138
+ * fields) into its own subquery until it fits or nothing splittable is
139
+ * left. Defaults to `true`.
140
+ *
141
+ * Independent of `autoSplitNestedCollections`: that option controls which
142
+ * fields split *by shape*, this one adds more splits *by measured size* as
143
+ * a last resort. A query that still doesn't fit after every splittable
144
+ * field has been removed is sent as-is — at that point there is nothing
145
+ * left for this library to do, and Contentful's own `QUERY_TOO_BIG` is the
146
+ * accurate error to see.
147
+ */
148
+ autoSplitOnSize?: boolean;
149
+ /**
150
+ * Byte budget that triggers {@link FetchContentfulOptions.autoSplitOnSize}.
151
+ * Defaults to `7500` — comfortably under Contentful's published 8 KB
152
+ * query size limit — or `15500` when `automaticPersistedQueries` is
153
+ * enabled, which raises Contentful's own ceiling to 16 KB.
154
+ */
155
+ maxQuerySize?: number;
127
156
  /** How many parent entry ids to resolve per subquery request. Defaults to `50`. */
128
157
  splitBatchSize?: number;
129
158
  /**
@@ -141,6 +170,77 @@ interface FetchContentfulOptions<TVariables extends GraphQLVariables = GraphQLVa
141
170
  * that. Defaults to `true`.
142
171
  */
143
172
  shapeResponseData?: boolean;
173
+ /**
174
+ * How to treat a reference Contentful could not resolve — a link whose
175
+ * target was deleted, or (on the Delivery API) is still a draft. Defaults
176
+ * to `'omit'`: the null positions are dropped from every collection and
177
+ * the call resolves with the entries that do exist.
178
+ *
179
+ * See {@link UnresolvableLinkMode} for the other two modes. Pair any of
180
+ * them with {@link FetchContentfulOptions.onUnresolvableLink} so a broken
181
+ * reference still reaches your logs.
182
+ *
183
+ * Two limits are worth knowing. A *one-to-one* reference has no position
184
+ * to drop, so an unresolvable one stays `null` on its field in every mode
185
+ * but `'error'`. And because the Preview API resolves drafts, a preview
186
+ * build sees links a production build does not — the same query can
187
+ * legitimately return different array lengths in the two modes.
188
+ *
189
+ * Written on the call itself, this narrows the return type: `'omit'`
190
+ * types collection items as `Entry[]` rather than `(Entry | null)[]`.
191
+ * Set on a factory it still applies at runtime, but the return type
192
+ * assumes the default — so prefer setting a non-default mode per call.
193
+ */
194
+ unresolvableLinks?: UnresolvableLinkMode;
195
+ /**
196
+ * Called once per request that returned an unresolvable link, with the
197
+ * `UNRESOLVABLE_LINK` errors Contentful reported. Each carries the
198
+ * `linkId`, `field` and `type` of the missing reference under
199
+ * `extensions.contentful.details`.
200
+ *
201
+ * Dropping a broken reference silently hides a real editorial mistake, so
202
+ * this is the way to keep one visible. It is never called when
203
+ * `unresolvableLinks` is `'error'` (the call rejects with those same
204
+ * errors instead), and anything it throws is swallowed — a logger must
205
+ * not be able to fail a fetch that otherwise succeeded.
206
+ */
207
+ onUnresolvableLink?: (errors: ContentfulGraphQLError[]) => void;
208
+ /**
209
+ * When Contentful rejects a query, append the query itself to the error
210
+ * message with a caret under the line and column it complained about.
211
+ * Defaults to `true`.
212
+ *
213
+ * ANSI color is used only when the environment looks like a terminal
214
+ * (`NO_COLOR` and `FORCE_COLOR` are honored), so log pipelines receive
215
+ * plain text. Set this to `false` to keep error messages to a single
216
+ * line — the query is still on the error as
217
+ * {@link FetchContentfulError.query}, and `annotateQuery` can format it
218
+ * on demand.
219
+ */
220
+ annotateQueryOnError?: boolean;
221
+ /**
222
+ * Strip insignificant whitespace from every outgoing query before it's
223
+ * sent — the same effect a tool like GQLMin has, applied automatically.
224
+ * Defaults to `true`; the only reason to disable it is to read a raw
225
+ * request off the wire while debugging, since {@link
226
+ * FetchContentfulError.query} and the annotated caret display always
227
+ * reflect whatever text was actually transmitted.
228
+ */
229
+ minifyQuery?: boolean;
230
+ /**
231
+ * Send every request as an Automatic Persisted Query: the optimistic first
232
+ * attempt sends only a hash of the query, and the query text itself is
233
+ * sent (once) only the first time Contentful reports that hash unknown.
234
+ * This is what actually lifts Contentful's query size ceiling from 8 KB to
235
+ * 16 KB, and every request after a query's first use no longer transmits
236
+ * the query text at all.
237
+ *
238
+ * **Requires the Premium plan or above** — see
239
+ * https://www.contentful.com/developers/docs/references/graphql/automatic-persisted-queries/.
240
+ * On any other plan this doubles every request's round trips for no
241
+ * benefit, which is why it defaults to `false`.
242
+ */
243
+ automaticPersistedQueries?: boolean;
144
244
  /** Custom fetch implementation (useful for tests). Defaults to `globalThis.fetch`. */
145
245
  fetch?: typeof fetch;
146
246
  /** AbortSignal forwarded to every underlying fetch call. */
@@ -213,12 +313,33 @@ type ShapeCollections<T> = T extends ReadonlyArray<infer U> ? Array<ShapeCollect
213
313
  type IsCollectionEntry<K, V> = K extends `${infer Base}Collection` ? Base extends '' ? false : NonNullable<V> extends {
214
314
  items: ReadonlyArray<unknown>;
215
315
  } ? true : false : false;
216
- type ShapedKey<K, V> = IsCollectionEntry<K, V> extends true ? K extends `${infer Base}Collection` ? Base : K : K;
316
+ type ShapedKey<K, V> = IsCollectionEntry<K, V> extends true ? (K extends `${infer Base}Collection` ? Base : K) : K;
217
317
  type ShapedValue<K, V> = IsCollectionEntry<K, V> extends true ? NonNullable<V> extends {
218
318
  items: ReadonlyArray<infer I>;
219
319
  } ? Array<ShapeCollections<I>> | Extract<V, null | undefined> : never : ShapeCollections<V>;
320
+ /**
321
+ * The type-level twin of `omitUnresolvedLinks`: drops `null` from the items
322
+ * of every collection, recursively, leaving the rest of the response alone.
323
+ *
324
+ * It runs on the *raw* wire shape, exactly where the runtime pass runs — so
325
+ * `ShapeCollections` composes on top of it unchanged, and a caller who
326
+ * disabled shaping gets the same guarantee about `items`.
327
+ *
328
+ * Nullability is stripped from the entries, never from the collection
329
+ * wrapper itself: a `fooCollection` that is entirely absent is still `null`.
330
+ */
331
+ type OmitUnresolvedLinks<T> = T extends ReadonlyArray<infer U> ? Array<OmitUnresolvedLinks<U>> : T extends object ? {
332
+ [K in keyof T]: IsCollectionEntry<K, T[K]> extends true ? OmitItemNulls<T[K]> : OmitUnresolvedLinks<T[K]>;
333
+ } : T;
334
+ /**
335
+ * Rewrites one collection wrapper's `items` to a non-nullable array, keeping
336
+ * its other fields (`total`, `skip`, `limit`) and its own nullability.
337
+ */
338
+ type OmitItemNulls<V> = {
339
+ [K in keyof NonNullable<V>]: K extends 'items' ? NonNullable<V>[K] extends ReadonlyArray<infer I> ? Array<OmitUnresolvedLinks<NonNullable<I>>> : NonNullable<V>[K] : OmitUnresolvedLinks<NonNullable<V>[K]>;
340
+ } | Extract<V, null | undefined>;
220
341
  /** `true` when `T` is a union of two or more members. */
221
- type IsUnion<T, U = T> = T extends unknown ? [U] extends [T] ? false : true : never;
342
+ type IsUnion<T, U = T> = T extends unknown ? ([U] extends [T] ? false : true) : never;
222
343
  /**
223
344
  * The type-level twin of the single-root unwrap: when `T` is an object with
224
345
  * exactly one statically-known key, resolves to that key's value type;
@@ -228,11 +349,64 @@ type IsUnion<T, U = T> = T extends unknown ? [U] extends [T] ? false : true : ne
228
349
  */
229
350
  type UnwrapSingleRoot<T> = T extends ReadonlyArray<unknown> ? T : T extends object ? string extends keyof T ? T : [keyof T] extends [never] ? T : IsUnion<keyof T> extends true ? T : T[keyof T] : T;
230
351
 
352
+ /**
353
+ * Rendering a rejected query back to the developer.
354
+ *
355
+ * Contentful's GraphQL errors carry `locations` — a line and column into
356
+ * the query **as sent**. That text is rarely the text anyone wrote: by the
357
+ * time it leaves this package, fragments have been inlined, `preview` and
358
+ * `locale` arguments injected, and split fields hoisted into generated
359
+ * subqueries. "Cannot query field X" plus a line number into a document you
360
+ * have never seen is a dead end, so this module prints that document back
361
+ * and puts a caret under the column Contentful named.
362
+ *
363
+ * Color is emitted as bare ANSI escapes rather than through a dependency:
364
+ * this package ships CJS as well as ESM, and the obvious candidate (chalk
365
+ * v5) is ESM-only. The four codes below are the entire surface we need.
366
+ */
367
+
368
+ interface AnnotateQueryOptions {
369
+ /**
370
+ * How many source lines to show above and below each marked line.
371
+ * Defaults to `3`; pass `Infinity` to print the whole query.
372
+ */
373
+ contextLines?: number;
374
+ /**
375
+ * Whether to emit ANSI color. Defaults to {@link supportsColor}, so a
376
+ * developer watching a terminal gets color while a log pipeline gets
377
+ * plain text it can store.
378
+ */
379
+ color?: boolean;
380
+ }
381
+ /**
382
+ * Renders `query` with a caret under every position the errors reported:
383
+ *
384
+ * ```text
385
+ * 2 | pageCollection(where: { slug: $slug }, limit: 1) {
386
+ * 3 | items {
387
+ * > 4 | titel
388
+ * | ^ Cannot query field "titel" on type "Page". Did you mean "title"?
389
+ * 5 | }
390
+ * ```
391
+ *
392
+ * Returns an empty string when no error carries a usable location — there
393
+ * is nothing to point at, and dumping the whole query would only bury the
394
+ * message that matters.
395
+ */
396
+ declare function annotateQuery(query: string, errors: readonly ContentfulGraphQLError[], options?: AnnotateQueryOptions): string;
397
+
231
398
  /** Error thrown (i.e. the rejection value) for every failure in fetch-contentful. */
232
399
  declare class FetchContentfulError extends Error {
233
400
  readonly code: FetchContentfulErrorCode;
234
401
  readonly status: number | undefined;
235
402
  readonly errors: ContentfulGraphQLError[] | undefined;
403
+ /**
404
+ * The GraphQL query exactly as it was sent to Contentful — fragments
405
+ * inlined, arguments injected, and (for a subquery) generated. This is
406
+ * the text the `line`/`column` in {@link FetchContentfulError.errors}
407
+ * point into, so it is the text to annotate; see `annotateQuery`.
408
+ */
409
+ readonly query: string | undefined;
236
410
  /** Internal: whether a retry may succeed. */
237
411
  readonly retryable: boolean;
238
412
  /** Internal: server-requested retry delay (from Retry-After), in ms. */
@@ -241,6 +415,7 @@ declare class FetchContentfulError extends Error {
241
415
  code: FetchContentfulErrorCode;
242
416
  status?: number;
243
417
  errors?: ContentfulGraphQLError[];
418
+ query?: string;
244
419
  retryable?: boolean;
245
420
  retryAfterMs?: number;
246
421
  cause?: unknown;
@@ -286,13 +461,6 @@ interface EnvSettings {
286
461
  environment: string | undefined;
287
462
  /** Content Delivery API token, for published content. */
288
463
  deliveryToken: string | undefined;
289
- /**
290
- * Content Delivery API token.
291
- *
292
- * @deprecated Renamed to {@link EnvSettings.deliveryToken}, which says
293
- * which of the two tokens it is. Kept as an alias; same value.
294
- */
295
- token: string | undefined;
296
464
  /** Content Preview API token, for draft content. Server-side only. */
297
465
  previewToken: string | undefined;
298
466
  }
@@ -346,6 +514,13 @@ declare function getLocales(context: LocalesContext): Promise<ContentfulLocale[]
346
514
  /** Clears the in-module locale cache (mainly useful in tests). */
347
515
  declare function clearLocaleCache(): void;
348
516
 
517
+ /**
518
+ * Minifies an already-valid GraphQL document string to the shortest text
519
+ * that still lexes to the same tokens. Safe to call on `print()` output or
520
+ * on a hand-written query; comments are dropped either way.
521
+ */
522
+ declare function minifyQuery(query: string): string;
523
+
349
524
  /**
350
525
  * Recursively rewrites Contentful collection wrappers:
351
526
  * `{ fooCollection: { items: [...] } }` becomes `{ foo: [...] }`.
@@ -359,6 +534,42 @@ declare function shapeData<T>(data: T): ShapeCollections<T>;
359
534
  */
360
535
  declare function unwrapSingleRoot<T>(data: T): UnwrapSingleRoot<T>;
361
536
 
537
+ /**
538
+ * The `extensions.contentful.code` Contentful sets on a link it could not
539
+ * resolve — the target was deleted, or is a draft the Delivery API cannot
540
+ * see. It arrives on an HTTP 200 alongside usable `data`.
541
+ */
542
+ declare const UNRESOLVABLE_LINK_CODE = "UNRESOLVABLE_LINK";
543
+ /** Whether one GraphQL error is Contentful's `UNRESOLVABLE_LINK`. */
544
+ declare function isUnresolvableLinkError(error: ContentfulGraphQLError): boolean;
545
+ /**
546
+ * Splits Contentful's `errors` into the links that merely could not be
547
+ * resolved and everything else.
548
+ *
549
+ * The distinction is the whole point: an unresolvable link describes content
550
+ * that is missing, and leaves the rest of the response intact and correct. A
551
+ * validation or complexity error describes a query that was wrong, and there
552
+ * is nothing to salvage. Only the first kind is ever tolerated.
553
+ */
554
+ declare function partitionUnresolvableLinks(errors: ContentfulGraphQLError[]): {
555
+ unresolvable: ContentfulGraphQLError[];
556
+ fatal: ContentfulGraphQLError[];
557
+ };
558
+ /**
559
+ * Removes the `null` positions an unresolvable link leaves behind in every
560
+ * `fooCollection.items`, recursively. Everything else is returned untouched
561
+ * (deeply copied), including a `null` on a one-to-one reference field —
562
+ * there is no position there to drop, only a field that has no value.
563
+ *
564
+ * This runs on the raw wire shape, before `shapeData`, so it applies just as
565
+ * much to a caller who passed `shapeResponseData: false`. A null inside
566
+ * `items` is never legitimate data — Contentful puts one there only for a
567
+ * link it could not resolve — so the walk is structural and needs no
568
+ * cross-referencing against the `errors` array, which matters because a
569
+ * split subquery reports its own errors against its own generated query.
570
+ */
571
+ declare function omitUnresolvedLinks<T>(data: T): OmitUnresolvedLinks<T>;
572
+
362
573
  /**
363
574
  * Replaces every named fragment spread with an equivalent inline fragment so
364
575
  * split planning can see the whole query shape uniformly.
@@ -376,36 +587,72 @@ declare function collectAtPath(data: unknown, path: string[]): Record<string, un
376
587
  * stitches everything back together.
377
588
  * - Retries transient failures with exponential backoff.
378
589
  * - Rejects if any request in the tree fails; resolves only when the full
379
- * query has succeeded.
590
+ * query has succeeded. A link Contentful could not resolve is the one
591
+ * thing that does not count as a failure — see below.
380
592
  * - Shapes the response so every `fooCollection.items` becomes `foo`
381
593
  * (disable with `shapeResponseData: false` to receive the raw wire shape).
594
+ * - Drops the `null` positions an unresolvable link leaves in a collection,
595
+ * in the data *and* in the return type, so `items` is safe to map over
596
+ * (change with `unresolvableLinks`; report them with `onUnresolvableLink`).
382
597
  *
383
598
  * Pass a typed document — from gql.tada, graphql-codegen's client preset, or
384
599
  * anything else producing a `TypedDocumentNode` — and both the result and
385
600
  * the variables are inferred, with no type arguments to write by hand.
386
601
  */
387
602
  declare function fetchContentful<TResult, TVariables = GraphQLVariables>(document: TypedDocumentNode<TResult, TVariables>, options: TypedFetchContentfulOptions<TVariables> & {
603
+ unresolvableLinks: 'null';
388
604
  shapeResponseData: false;
389
605
  unwrapRootField: false;
390
606
  }): Promise<DocumentResult<TResult>>;
391
607
  declare function fetchContentful<TResult, TVariables = GraphQLVariables>(document: TypedDocumentNode<TResult, TVariables>, options: TypedFetchContentfulOptions<TVariables> & {
608
+ unresolvableLinks: 'null';
392
609
  shapeResponseData: false;
393
610
  }): Promise<UnwrapSingleRoot<DocumentResult<TResult>>>;
394
611
  declare function fetchContentful<TResult, TVariables = GraphQLVariables>(document: TypedDocumentNode<TResult, TVariables>, options: TypedFetchContentfulOptions<TVariables> & {
612
+ unresolvableLinks: 'null';
395
613
  unwrapRootField: false;
396
614
  }): Promise<ShapeCollections<DocumentResult<TResult>>>;
397
- declare function fetchContentful<TResult, TVariables = GraphQLVariables>(document: TypedDocumentNode<TResult, TVariables>, ...args: Record<string, never> extends CallerVariables<TVariables> ? [options?: TypedFetchContentfulOptions<TVariables>] : [options: TypedFetchContentfulOptions<TVariables>]): Promise<UnwrapSingleRoot<ShapeCollections<DocumentResult<TResult>>>>;
615
+ declare function fetchContentful<TResult, TVariables = GraphQLVariables>(document: TypedDocumentNode<TResult, TVariables>, options: TypedFetchContentfulOptions<TVariables> & {
616
+ unresolvableLinks: 'null';
617
+ }): Promise<UnwrapSingleRoot<ShapeCollections<DocumentResult<TResult>>>>;
398
618
  declare function fetchContentful<TData = Record<string, unknown>, TVariables extends GraphQLVariables = GraphQLVariables>(query: string, options: FetchContentfulOptions<TVariables> & {
619
+ unresolvableLinks: 'null';
399
620
  shapeResponseData: false;
400
621
  unwrapRootField: false;
401
622
  }): Promise<TData>;
402
623
  declare function fetchContentful<TData = Record<string, unknown>, TVariables extends GraphQLVariables = GraphQLVariables>(query: string, options: FetchContentfulOptions<TVariables> & {
624
+ unresolvableLinks: 'null';
403
625
  shapeResponseData: false;
404
626
  }): Promise<UnwrapSingleRoot<TData>>;
405
627
  declare function fetchContentful<TData = Record<string, unknown>, TVariables extends GraphQLVariables = GraphQLVariables>(query: string, options: FetchContentfulOptions<TVariables> & {
628
+ unresolvableLinks: 'null';
406
629
  unwrapRootField: false;
407
630
  }): Promise<ShapeCollections<TData>>;
408
- declare function fetchContentful<TData = Record<string, unknown>, TVariables extends GraphQLVariables = GraphQLVariables>(query: string, options?: FetchContentfulOptions<TVariables>): Promise<UnwrapSingleRoot<ShapeCollections<TData>>>;
631
+ declare function fetchContentful<TData = Record<string, unknown>, TVariables extends GraphQLVariables = GraphQLVariables>(query: string, options: FetchContentfulOptions<TVariables> & {
632
+ unresolvableLinks: 'null';
633
+ }): Promise<UnwrapSingleRoot<ShapeCollections<TData>>>;
634
+ declare function fetchContentful<TResult, TVariables = GraphQLVariables>(document: TypedDocumentNode<TResult, TVariables>, options: TypedFetchContentfulOptions<TVariables> & {
635
+ shapeResponseData: false;
636
+ unwrapRootField: false;
637
+ }): Promise<OmitUnresolvedLinks<DocumentResult<TResult>>>;
638
+ declare function fetchContentful<TResult, TVariables = GraphQLVariables>(document: TypedDocumentNode<TResult, TVariables>, options: TypedFetchContentfulOptions<TVariables> & {
639
+ shapeResponseData: false;
640
+ }): Promise<UnwrapSingleRoot<OmitUnresolvedLinks<DocumentResult<TResult>>>>;
641
+ declare function fetchContentful<TResult, TVariables = GraphQLVariables>(document: TypedDocumentNode<TResult, TVariables>, options: TypedFetchContentfulOptions<TVariables> & {
642
+ unwrapRootField: false;
643
+ }): Promise<ShapeCollections<OmitUnresolvedLinks<DocumentResult<TResult>>>>;
644
+ declare function fetchContentful<TResult, TVariables = GraphQLVariables>(document: TypedDocumentNode<TResult, TVariables>, ...args: Record<string, never> extends CallerVariables<TVariables> ? [options?: TypedFetchContentfulOptions<TVariables>] : [options: TypedFetchContentfulOptions<TVariables>]): Promise<UnwrapSingleRoot<ShapeCollections<OmitUnresolvedLinks<DocumentResult<TResult>>>>>;
645
+ declare function fetchContentful<TData = Record<string, unknown>, TVariables extends GraphQLVariables = GraphQLVariables>(query: string, options: FetchContentfulOptions<TVariables> & {
646
+ shapeResponseData: false;
647
+ unwrapRootField: false;
648
+ }): Promise<OmitUnresolvedLinks<TData>>;
649
+ declare function fetchContentful<TData = Record<string, unknown>, TVariables extends GraphQLVariables = GraphQLVariables>(query: string, options: FetchContentfulOptions<TVariables> & {
650
+ shapeResponseData: false;
651
+ }): Promise<UnwrapSingleRoot<OmitUnresolvedLinks<TData>>>;
652
+ declare function fetchContentful<TData = Record<string, unknown>, TVariables extends GraphQLVariables = GraphQLVariables>(query: string, options: FetchContentfulOptions<TVariables> & {
653
+ unwrapRootField: false;
654
+ }): Promise<ShapeCollections<OmitUnresolvedLinks<TData>>>;
655
+ declare function fetchContentful<TData = Record<string, unknown>, TVariables extends GraphQLVariables = GraphQLVariables>(query: string, options?: FetchContentfulOptions<TVariables>): Promise<UnwrapSingleRoot<ShapeCollections<OmitUnresolvedLinks<TData>>>>;
409
656
  /**
410
657
  * Creates a `fetchContentful` bound to default options — the recommended way
411
658
  * to configure the utility once per project:
@@ -420,32 +667,66 @@ declare function fetchContentful<TData = Record<string, unknown>, TVariables ext
420
667
  * ```
421
668
  *
422
669
  * Per-call options win over defaults (top-level shallow merge). Note that
423
- * `shapeResponseData: false` only changes the *return type* when written on
424
- * the call itself, so prefer setting it per call.
670
+ * `shapeResponseData: false`, `unwrapRootField: false` and
671
+ * `unresolvableLinks: 'null'` only change the *return type* when written on
672
+ * the call itself, so prefer setting those per call. Set on the factory they
673
+ * still take effect at runtime — the type just assumes the default.
425
674
  */
426
675
  declare function createFetchContentful<TDefaultVariables extends GraphQLVariables = GraphQLVariables>(defaults?: FetchContentfulOptions<TDefaultVariables>): {
427
676
  <TResult, TVariables = GraphQLVariables>(document: TypedDocumentNode<TResult, TVariables>, options: TypedFetchContentfulOptions<TVariables> & {
677
+ unresolvableLinks: "null";
428
678
  shapeResponseData: false;
429
679
  unwrapRootField: false;
430
680
  }): Promise<DocumentResult<TResult>>;
431
681
  <TResult, TVariables = GraphQLVariables>(document: TypedDocumentNode<TResult, TVariables>, options: TypedFetchContentfulOptions<TVariables> & {
682
+ unresolvableLinks: "null";
432
683
  shapeResponseData: false;
433
684
  }): Promise<UnwrapSingleRoot<DocumentResult<TResult>>>;
434
685
  <TResult, TVariables = GraphQLVariables>(document: TypedDocumentNode<TResult, TVariables>, options: TypedFetchContentfulOptions<TVariables> & {
686
+ unresolvableLinks: "null";
435
687
  unwrapRootField: false;
436
688
  }): Promise<ShapeCollections<DocumentResult<TResult>>>;
437
- <TResult, TVariables = GraphQLVariables>(document: TypedDocumentNode<TResult, TVariables>, ...args: Record<string, never> extends CallerVariables<TVariables> ? [options?: TypedFetchContentfulOptions<TVariables>] : [options: TypedFetchContentfulOptions<TVariables>]): Promise<UnwrapSingleRoot<ShapeCollections<DocumentResult<TResult>>>>;
689
+ <TResult, TVariables = GraphQLVariables>(document: TypedDocumentNode<TResult, TVariables>, options: TypedFetchContentfulOptions<TVariables> & {
690
+ unresolvableLinks: "null";
691
+ }): Promise<UnwrapSingleRoot<ShapeCollections<DocumentResult<TResult>>>>;
438
692
  <TData = Record<string, unknown>, TVariables extends GraphQLVariables = GraphQLVariables>(query: string, options: FetchContentfulOptions<TVariables> & {
693
+ unresolvableLinks: "null";
439
694
  shapeResponseData: false;
440
695
  unwrapRootField: false;
441
696
  }): Promise<TData>;
442
697
  <TData = Record<string, unknown>, TVariables extends GraphQLVariables = GraphQLVariables>(query: string, options: FetchContentfulOptions<TVariables> & {
698
+ unresolvableLinks: "null";
443
699
  shapeResponseData: false;
444
700
  }): Promise<UnwrapSingleRoot<TData>>;
445
701
  <TData = Record<string, unknown>, TVariables extends GraphQLVariables = GraphQLVariables>(query: string, options: FetchContentfulOptions<TVariables> & {
702
+ unresolvableLinks: "null";
446
703
  unwrapRootField: false;
447
704
  }): Promise<ShapeCollections<TData>>;
448
- <TData = Record<string, unknown>, TVariables extends GraphQLVariables = GraphQLVariables>(query: string, options?: FetchContentfulOptions<TVariables>): Promise<UnwrapSingleRoot<ShapeCollections<TData>>>;
705
+ <TData = Record<string, unknown>, TVariables extends GraphQLVariables = GraphQLVariables>(query: string, options: FetchContentfulOptions<TVariables> & {
706
+ unresolvableLinks: "null";
707
+ }): Promise<UnwrapSingleRoot<ShapeCollections<TData>>>;
708
+ <TResult, TVariables = GraphQLVariables>(document: TypedDocumentNode<TResult, TVariables>, options: TypedFetchContentfulOptions<TVariables> & {
709
+ shapeResponseData: false;
710
+ unwrapRootField: false;
711
+ }): Promise<OmitUnresolvedLinks<DocumentResult<TResult>>>;
712
+ <TResult, TVariables = GraphQLVariables>(document: TypedDocumentNode<TResult, TVariables>, options: TypedFetchContentfulOptions<TVariables> & {
713
+ shapeResponseData: false;
714
+ }): Promise<UnwrapSingleRoot<OmitUnresolvedLinks<DocumentResult<TResult>>>>;
715
+ <TResult, TVariables = GraphQLVariables>(document: TypedDocumentNode<TResult, TVariables>, options: TypedFetchContentfulOptions<TVariables> & {
716
+ unwrapRootField: false;
717
+ }): Promise<ShapeCollections<OmitUnresolvedLinks<DocumentResult<TResult>>>>;
718
+ <TResult, TVariables = GraphQLVariables>(document: TypedDocumentNode<TResult, TVariables>, ...args: Record<string, never> extends CallerVariables<TVariables> ? [options?: TypedFetchContentfulOptions<TVariables>] : [options: TypedFetchContentfulOptions<TVariables>]): Promise<UnwrapSingleRoot<ShapeCollections<OmitUnresolvedLinks<DocumentResult<TResult>>>>>;
719
+ <TData = Record<string, unknown>, TVariables extends GraphQLVariables = GraphQLVariables>(query: string, options: FetchContentfulOptions<TVariables> & {
720
+ shapeResponseData: false;
721
+ unwrapRootField: false;
722
+ }): Promise<OmitUnresolvedLinks<TData>>;
723
+ <TData = Record<string, unknown>, TVariables extends GraphQLVariables = GraphQLVariables>(query: string, options: FetchContentfulOptions<TVariables> & {
724
+ shapeResponseData: false;
725
+ }): Promise<UnwrapSingleRoot<OmitUnresolvedLinks<TData>>>;
726
+ <TData = Record<string, unknown>, TVariables extends GraphQLVariables = GraphQLVariables>(query: string, options: FetchContentfulOptions<TVariables> & {
727
+ unwrapRootField: false;
728
+ }): Promise<ShapeCollections<OmitUnresolvedLinks<TData>>>;
729
+ <TData = Record<string, unknown>, TVariables extends GraphQLVariables = GraphQLVariables>(query: string, options?: FetchContentfulOptions<TVariables>): Promise<UnwrapSingleRoot<ShapeCollections<OmitUnresolvedLinks<TData>>>>;
449
730
  };
450
731
 
451
- export { type AutoInjectedVariable, type CallerVariables, type ContentfulGraphQLError, type ContentfulLocale, type DocumentResult, FetchContentfulError, type FetchContentfulErrorCode, type FetchContentfulOptions, type GraphQLVariables, type NextFetchOptions, type ShapeCollections, type TypedFetchContentfulOptions, type UnwrapSingleRoot, type VariablesOption, clearLocaleCache, collectAtPath, createFetchContentful, fetchContentful as default, fetchContentful, getLocales, injectRootArgs, inlineFragments, isFetchContentfulError, readEnvSettings, shapeData, unwrapSingleRoot };
732
+ export { type AnnotateQueryOptions, type AutoInjectedVariable, type CallerVariables, type ContentfulGraphQLError, type ContentfulLocale, type DocumentResult, FetchContentfulError, type FetchContentfulErrorCode, type FetchContentfulOptions, type GraphQLVariables, type NextFetchOptions, type OmitUnresolvedLinks, type ShapeCollections, type TypedFetchContentfulOptions, UNRESOLVABLE_LINK_CODE, type UnresolvableLinkMode, type UnwrapSingleRoot, type VariablesOption, annotateQuery, clearLocaleCache, collectAtPath, createFetchContentful, fetchContentful as default, fetchContentful, getLocales, injectRootArgs, inlineFragments, isFetchContentfulError, isUnresolvableLinkError, minifyQuery, omitUnresolvedLinks, partitionUnresolvableLinks, readEnvSettings, shapeData, unwrapSingleRoot };