@fourtwelvelabs/fetch-contentful 0.1.0 → 0.3.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/CHANGELOG.md +102 -0
- package/README.md +124 -7
- package/dist/cli/index.mjs +949 -0
- package/dist/cli/index.mjs.map +1 -0
- package/dist/index.cjs +23 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +98 -12
- package/dist/index.d.ts +98 -12
- package/dist/index.mjs +23 -27
- package/dist/index.mjs.map +1 -1
- package/dist/tada/index.cjs +4 -0
- package/dist/tada/index.cjs.map +1 -0
- package/dist/tada/index.d.cts +106 -0
- package/dist/tada/index.d.ts +106 -0
- package/dist/tada/index.mjs +3 -0
- package/dist/tada/index.mjs.map +1 -0
- package/docs/tada.md +327 -0
- package/package.json +28 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { TypedDocumentNode } from '@graphql-typed-document-node/core';
|
|
1
2
|
import { DocumentNode } from 'graphql';
|
|
2
3
|
|
|
3
4
|
/**
|
|
@@ -51,8 +52,13 @@ interface FetchContentfulOptions<TVariables extends GraphQLVariables = GraphQLVa
|
|
|
51
52
|
* query fields (see {@link FetchContentfulOptions.autoInjectArgs}),
|
|
52
53
|
* auto-fills a `$locale: String` variable when your query declares one,
|
|
53
54
|
* and is applied to generated subqueries.
|
|
55
|
+
*
|
|
56
|
+
* Defaults to `"en-US"`. Pass `null` to send no `locale` at all, which
|
|
57
|
+
* lets Contentful serve whichever locale the space itself defaults to —
|
|
58
|
+
* useful for a space whose default locale is not `en-US`, and the
|
|
59
|
+
* behavior this option had before a default existed.
|
|
54
60
|
*/
|
|
55
|
-
locale?: string;
|
|
61
|
+
locale?: string | null;
|
|
56
62
|
/**
|
|
57
63
|
* Automatically add `preview: true` / `locale: "..."` arguments to the
|
|
58
64
|
* root fields of your query based on the `preview` and `locale` options,
|
|
@@ -85,7 +91,16 @@ interface FetchContentfulOptions<TVariables extends GraphQLVariables = GraphQLVa
|
|
|
85
91
|
* Automatically split nested reference collections (any `*Collection`
|
|
86
92
|
* field that is not a root query field) into their own subqueries to stay
|
|
87
93
|
* under Contentful's query complexity limits. Defaults to `true`.
|
|
88
|
-
*
|
|
94
|
+
*
|
|
95
|
+
* This gates **automatic detection only**. The `@split` directive is an
|
|
96
|
+
* independent, explicit trigger: it always splits the field it annotates —
|
|
97
|
+
* a nested collection just as much as a one-to-one reference — whatever
|
|
98
|
+
* this option is set to. Setting it to `false` and annotating only the
|
|
99
|
+
* fields that actually exceed the limit gives you a manual mode in which
|
|
100
|
+
* every other query is a single round trip.
|
|
101
|
+
*
|
|
102
|
+
* `@split` on a root field throws a `CONFIG` error: there is no parent
|
|
103
|
+
* entry to stitch the result back onto.
|
|
89
104
|
*/
|
|
90
105
|
autoSplitNestedCollections?: boolean;
|
|
91
106
|
/** How many parent entry ids to resolve per subquery request. Defaults to `50`. */
|
|
@@ -114,6 +129,51 @@ interface FetchContentfulOptions<TVariables extends GraphQLVariables = GraphQLVa
|
|
|
114
129
|
/** Standard fetch cache mode, forwarded to fetch. */
|
|
115
130
|
cache?: RequestCache;
|
|
116
131
|
}
|
|
132
|
+
/**
|
|
133
|
+
* Variables {@link FetchContentfulOptions.autoInjectArgs} fills in on the
|
|
134
|
+
* caller's behalf, so a typed document that declares `$preview` / `$locale`
|
|
135
|
+
* never forces the caller to pass them.
|
|
136
|
+
*/
|
|
137
|
+
type AutoInjectedVariable = 'preview' | 'locale';
|
|
138
|
+
/** The variables a caller still has to supply for a typed document. */
|
|
139
|
+
type CallerVariables<TVariables> = Omit<TVariables, AutoInjectedVariable>;
|
|
140
|
+
/** `true` when nothing is left for the caller to pass. */
|
|
141
|
+
type VariablesAreOptional<TVariables> = Record<string, never> extends CallerVariables<TVariables> ? true : false;
|
|
142
|
+
/**
|
|
143
|
+
* Makes `variables` required exactly when the document declares one the
|
|
144
|
+
* caller must provide, and optional otherwise (including when every
|
|
145
|
+
* remaining variable is nullable, or when the only ones left are
|
|
146
|
+
* auto-injected).
|
|
147
|
+
*
|
|
148
|
+
* The conditional deliberately sits in *key* position rather than wrapping
|
|
149
|
+
* the whole object. TypeScript skips excess-property checks when a
|
|
150
|
+
* parameter's type is a conditional over a type argument it is still
|
|
151
|
+
* inferring, so `{ variables: { slgu: '…' } }` would slip through a
|
|
152
|
+
* `… ? { variables: T } : { variables?: T }` formulation. Selecting the key
|
|
153
|
+
* instead keeps the property's type a plain `TVariables`, and typos are
|
|
154
|
+
* caught.
|
|
155
|
+
*/
|
|
156
|
+
type VariablesOption<TVariables> = {
|
|
157
|
+
[K in VariablesAreOptional<TVariables> extends true ? never : 'variables']: TVariables;
|
|
158
|
+
} & {
|
|
159
|
+
[K in VariablesAreOptional<TVariables> extends true ? 'variables' : never]?: TVariables;
|
|
160
|
+
};
|
|
161
|
+
/**
|
|
162
|
+
* {@link FetchContentfulOptions} for a call that passes a typed document:
|
|
163
|
+
* identical, except `variables` is typed by — and required by — the
|
|
164
|
+
* document itself.
|
|
165
|
+
*/
|
|
166
|
+
type TypedFetchContentfulOptions<TVariables> = Omit<FetchContentfulOptions<GraphQLVariables>, 'variables'> & VariablesOption<TVariables>;
|
|
167
|
+
/**
|
|
168
|
+
* The result type a document carries, falling back to the historical
|
|
169
|
+
* default for a plain, untyped `DocumentNode`.
|
|
170
|
+
*
|
|
171
|
+
* `TypedDocumentNode`'s type brand is an optional property, so an untyped
|
|
172
|
+
* `DocumentNode` structurally satisfies it and infers `unknown`. Mapping
|
|
173
|
+
* that back to `Record<string, unknown>` keeps pre-existing
|
|
174
|
+
* `fetchContentful(parse(query))` calls typed exactly as they were.
|
|
175
|
+
*/
|
|
176
|
+
type DocumentResult<TResult> = unknown extends TResult ? Record<string, unknown> : TResult;
|
|
117
177
|
/** A single locale as configured in Contentful. */
|
|
118
178
|
interface ContentfulLocale {
|
|
119
179
|
code: string;
|
|
@@ -278,18 +338,33 @@ declare function collectAtPath(data: unknown, path: string[]): Record<string, un
|
|
|
278
338
|
* query has succeeded.
|
|
279
339
|
* - Shapes the response so every `fooCollection.items` becomes `foo`
|
|
280
340
|
* (disable with `shapeResponseData: false` to receive the raw wire shape).
|
|
341
|
+
*
|
|
342
|
+
* Pass a typed document — from gql.tada, graphql-codegen's client preset, or
|
|
343
|
+
* anything else producing a `TypedDocumentNode` — and both the result and
|
|
344
|
+
* the variables are inferred, with no type arguments to write by hand.
|
|
281
345
|
*/
|
|
282
|
-
declare function fetchContentful<
|
|
346
|
+
declare function fetchContentful<TResult, TVariables = GraphQLVariables>(document: TypedDocumentNode<TResult, TVariables>, options: TypedFetchContentfulOptions<TVariables> & {
|
|
347
|
+
shapeResponseData: false;
|
|
348
|
+
unwrapRootField: false;
|
|
349
|
+
}): Promise<DocumentResult<TResult>>;
|
|
350
|
+
declare function fetchContentful<TResult, TVariables = GraphQLVariables>(document: TypedDocumentNode<TResult, TVariables>, options: TypedFetchContentfulOptions<TVariables> & {
|
|
351
|
+
shapeResponseData: false;
|
|
352
|
+
}): Promise<UnwrapSingleRoot<DocumentResult<TResult>>>;
|
|
353
|
+
declare function fetchContentful<TResult, TVariables = GraphQLVariables>(document: TypedDocumentNode<TResult, TVariables>, options: TypedFetchContentfulOptions<TVariables> & {
|
|
354
|
+
unwrapRootField: false;
|
|
355
|
+
}): Promise<ShapeCollections<DocumentResult<TResult>>>;
|
|
356
|
+
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>>>>;
|
|
357
|
+
declare function fetchContentful<TData = Record<string, unknown>, TVariables extends GraphQLVariables = GraphQLVariables>(query: string, options: FetchContentfulOptions<TVariables> & {
|
|
283
358
|
shapeResponseData: false;
|
|
284
359
|
unwrapRootField: false;
|
|
285
360
|
}): Promise<TData>;
|
|
286
|
-
declare function fetchContentful<TData = Record<string, unknown>, TVariables extends GraphQLVariables = GraphQLVariables>(query: string
|
|
361
|
+
declare function fetchContentful<TData = Record<string, unknown>, TVariables extends GraphQLVariables = GraphQLVariables>(query: string, options: FetchContentfulOptions<TVariables> & {
|
|
287
362
|
shapeResponseData: false;
|
|
288
363
|
}): Promise<UnwrapSingleRoot<TData>>;
|
|
289
|
-
declare function fetchContentful<TData = Record<string, unknown>, TVariables extends GraphQLVariables = GraphQLVariables>(query: string
|
|
364
|
+
declare function fetchContentful<TData = Record<string, unknown>, TVariables extends GraphQLVariables = GraphQLVariables>(query: string, options: FetchContentfulOptions<TVariables> & {
|
|
290
365
|
unwrapRootField: false;
|
|
291
366
|
}): Promise<ShapeCollections<TData>>;
|
|
292
|
-
declare function fetchContentful<TData = Record<string, unknown>, TVariables extends GraphQLVariables = GraphQLVariables>(query: string
|
|
367
|
+
declare function fetchContentful<TData = Record<string, unknown>, TVariables extends GraphQLVariables = GraphQLVariables>(query: string, options?: FetchContentfulOptions<TVariables>): Promise<UnwrapSingleRoot<ShapeCollections<TData>>>;
|
|
293
368
|
/**
|
|
294
369
|
* Creates a `fetchContentful` bound to default options — the recommended way
|
|
295
370
|
* to configure the utility once per project:
|
|
@@ -298,7 +373,7 @@ declare function fetchContentful<TData = Record<string, unknown>, TVariables ext
|
|
|
298
373
|
* // lib/contentful.ts
|
|
299
374
|
* export const fetchContentful = createFetchContentful({
|
|
300
375
|
* space: 'abc123',
|
|
301
|
-
* locale: 'en-US'
|
|
376
|
+
* locale: 'de-DE', // overrides the 'en-US' default for the whole project
|
|
302
377
|
* retries: 3,
|
|
303
378
|
* });
|
|
304
379
|
* ```
|
|
@@ -308,17 +383,28 @@ declare function fetchContentful<TData = Record<string, unknown>, TVariables ext
|
|
|
308
383
|
* the call itself, so prefer setting it per call.
|
|
309
384
|
*/
|
|
310
385
|
declare function createFetchContentful<TDefaultVariables extends GraphQLVariables = GraphQLVariables>(defaults?: FetchContentfulOptions<TDefaultVariables>): {
|
|
311
|
-
<
|
|
386
|
+
<TResult, TVariables = GraphQLVariables>(document: TypedDocumentNode<TResult, TVariables>, options: TypedFetchContentfulOptions<TVariables> & {
|
|
387
|
+
shapeResponseData: false;
|
|
388
|
+
unwrapRootField: false;
|
|
389
|
+
}): Promise<DocumentResult<TResult>>;
|
|
390
|
+
<TResult, TVariables = GraphQLVariables>(document: TypedDocumentNode<TResult, TVariables>, options: TypedFetchContentfulOptions<TVariables> & {
|
|
391
|
+
shapeResponseData: false;
|
|
392
|
+
}): Promise<UnwrapSingleRoot<DocumentResult<TResult>>>;
|
|
393
|
+
<TResult, TVariables = GraphQLVariables>(document: TypedDocumentNode<TResult, TVariables>, options: TypedFetchContentfulOptions<TVariables> & {
|
|
394
|
+
unwrapRootField: false;
|
|
395
|
+
}): Promise<ShapeCollections<DocumentResult<TResult>>>;
|
|
396
|
+
<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>>>>;
|
|
397
|
+
<TData = Record<string, unknown>, TVariables extends GraphQLVariables = GraphQLVariables>(query: string, options: FetchContentfulOptions<TVariables> & {
|
|
312
398
|
shapeResponseData: false;
|
|
313
399
|
unwrapRootField: false;
|
|
314
400
|
}): Promise<TData>;
|
|
315
|
-
<TData = Record<string, unknown>, TVariables extends GraphQLVariables = GraphQLVariables>(query: string
|
|
401
|
+
<TData = Record<string, unknown>, TVariables extends GraphQLVariables = GraphQLVariables>(query: string, options: FetchContentfulOptions<TVariables> & {
|
|
316
402
|
shapeResponseData: false;
|
|
317
403
|
}): Promise<UnwrapSingleRoot<TData>>;
|
|
318
|
-
<TData = Record<string, unknown>, TVariables extends GraphQLVariables = GraphQLVariables>(query: string
|
|
404
|
+
<TData = Record<string, unknown>, TVariables extends GraphQLVariables = GraphQLVariables>(query: string, options: FetchContentfulOptions<TVariables> & {
|
|
319
405
|
unwrapRootField: false;
|
|
320
406
|
}): Promise<ShapeCollections<TData>>;
|
|
321
|
-
<TData = Record<string, unknown>, TVariables extends GraphQLVariables = GraphQLVariables>(query: string
|
|
407
|
+
<TData = Record<string, unknown>, TVariables extends GraphQLVariables = GraphQLVariables>(query: string, options?: FetchContentfulOptions<TVariables>): Promise<UnwrapSingleRoot<ShapeCollections<TData>>>;
|
|
322
408
|
};
|
|
323
409
|
|
|
324
|
-
export { type ContentfulGraphQLError, type ContentfulLocale, FetchContentfulError, type FetchContentfulErrorCode, type FetchContentfulOptions, type GraphQLVariables, type NextFetchOptions, type ShapeCollections, type UnwrapSingleRoot, clearLocaleCache, collectAtPath, createFetchContentful, fetchContentful as default, fetchContentful, getLocales, injectRootArgs, inlineFragments, isFetchContentfulError, readEnvSettings, shapeData, unwrapSingleRoot };
|
|
410
|
+
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 };
|
package/dist/index.mjs
CHANGED
|
@@ -228,7 +228,15 @@ function planSplits(document, options) {
|
|
|
228
228
|
);
|
|
229
229
|
}
|
|
230
230
|
const field = selection;
|
|
231
|
-
const
|
|
231
|
+
const isExplicitSplit = hasDirective(field, SPLIT_DIRECTIVE);
|
|
232
|
+
const isAutoSplit = options.autoSplitNestedCollections && isCollectionField(field);
|
|
233
|
+
if (isExplicitSplit && depth === 0) {
|
|
234
|
+
throw new FetchContentfulError(
|
|
235
|
+
`Cannot split root field "${responseKeyOf(field)}": @split needs a parent entry to stitch the result back onto, and root fields have none. Move the directive to a nested field, or page through this field with its own \`limit\` and \`skip\` arguments.`,
|
|
236
|
+
{ code: "CONFIG" }
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
const shouldSplit = depth > 0 && field.selectionSet !== void 0 && !hasDirective(field, NO_SPLIT_DIRECTIVE) && (isExplicitSplit || isAutoSplit);
|
|
232
240
|
if (shouldSplit) {
|
|
233
241
|
const planned = withDirective(
|
|
234
242
|
withoutDirective(field, SPLIT_DIRECTIVE),
|
|
@@ -701,6 +709,7 @@ function unwrapSingleRoot(data) {
|
|
|
701
709
|
}
|
|
702
710
|
|
|
703
711
|
// src/index.ts
|
|
712
|
+
var DEFAULT_LOCALE = "en-US";
|
|
704
713
|
var DEFAULT_RETRIES = 5;
|
|
705
714
|
var DEFAULT_RETRY_DELAY_MS = 250;
|
|
706
715
|
var DEFAULT_MAX_RETRY_DELAY_MS = 8e3;
|
|
@@ -760,7 +769,8 @@ function resolveContext(options) {
|
|
|
760
769
|
environment,
|
|
761
770
|
token,
|
|
762
771
|
preview,
|
|
763
|
-
|
|
772
|
+
// `null` is the opt-out; `undefined` (or absent) takes the default.
|
|
773
|
+
locale: options.locale === null ? void 0 : options.locale ?? DEFAULT_LOCALE,
|
|
764
774
|
fetch: fetchImpl,
|
|
765
775
|
retry,
|
|
766
776
|
autoSplitNestedCollections: options.autoSplitNestedCollections ?? true,
|
|
@@ -867,12 +877,15 @@ async function executeDocument(document, variables, context) {
|
|
|
867
877
|
cleanupMarkers(data, plans);
|
|
868
878
|
return data;
|
|
869
879
|
}
|
|
880
|
+
function isDocumentNode(query) {
|
|
881
|
+
return typeof query === "object" && query !== null && query.kind === Kind.DOCUMENT && Array.isArray(query.definitions);
|
|
882
|
+
}
|
|
870
883
|
function toDocument(query) {
|
|
871
|
-
if (
|
|
884
|
+
if (isDocumentNode(query)) {
|
|
872
885
|
return query;
|
|
873
886
|
}
|
|
874
887
|
try {
|
|
875
|
-
return parse(query);
|
|
888
|
+
return parse(typeof query === "string" ? query : String(query));
|
|
876
889
|
} catch (cause) {
|
|
877
890
|
throw new FetchContentfulError(
|
|
878
891
|
`Failed to parse GraphQL query: ${String(cause)}`,
|
|
@@ -895,7 +908,7 @@ function withAutoVariables(document, variables, context) {
|
|
|
895
908
|
}
|
|
896
909
|
return merged;
|
|
897
910
|
}
|
|
898
|
-
async function
|
|
911
|
+
async function runFetchContentful(query, options) {
|
|
899
912
|
const context = resolveContext(options);
|
|
900
913
|
let document = inlineFragments(toDocument(query));
|
|
901
914
|
if (options.autoInjectArgs ?? true) {
|
|
@@ -925,32 +938,15 @@ async function fetchContentful(query, options = {}) {
|
|
|
925
938
|
}
|
|
926
939
|
return unwrapSingleRoot(result);
|
|
927
940
|
}
|
|
941
|
+
async function fetchContentful(query, options = {}) {
|
|
942
|
+
return runFetchContentful(query, options);
|
|
943
|
+
}
|
|
928
944
|
function createFetchContentful(defaults = {}) {
|
|
929
945
|
function bound(query, options = {}) {
|
|
930
|
-
|
|
946
|
+
return runFetchContentful(query, {
|
|
931
947
|
...defaults,
|
|
932
948
|
...options
|
|
933
|
-
};
|
|
934
|
-
if (merged.shapeResponseData === false) {
|
|
935
|
-
if (merged.unwrapRootField === false) {
|
|
936
|
-
return fetchContentful(query, {
|
|
937
|
-
...merged,
|
|
938
|
-
shapeResponseData: false,
|
|
939
|
-
unwrapRootField: false
|
|
940
|
-
});
|
|
941
|
-
}
|
|
942
|
-
return fetchContentful(query, {
|
|
943
|
-
...merged,
|
|
944
|
-
shapeResponseData: false
|
|
945
|
-
});
|
|
946
|
-
}
|
|
947
|
-
if (merged.unwrapRootField === false) {
|
|
948
|
-
return fetchContentful(query, {
|
|
949
|
-
...merged,
|
|
950
|
-
unwrapRootField: false
|
|
951
|
-
});
|
|
952
|
-
}
|
|
953
|
-
return fetchContentful(query, merged);
|
|
949
|
+
});
|
|
954
950
|
}
|
|
955
951
|
return bound;
|
|
956
952
|
}
|