@fourtwelvelabs/fetch-contentful 0.1.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +71 -0
- package/README.md +95 -2
- package/dist/cli/index.mjs +949 -0
- package/dist/cli/index.mjs.map +1 -0
- package/dist/index.cjs +20 -26
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +91 -10
- package/dist/index.d.ts +91 -10
- package/dist/index.mjs +20 -26
- 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 +301 -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
|
/**
|
|
@@ -85,7 +86,16 @@ interface FetchContentfulOptions<TVariables extends GraphQLVariables = GraphQLVa
|
|
|
85
86
|
* Automatically split nested reference collections (any `*Collection`
|
|
86
87
|
* field that is not a root query field) into their own subqueries to stay
|
|
87
88
|
* under Contentful's query complexity limits. Defaults to `true`.
|
|
88
|
-
*
|
|
89
|
+
*
|
|
90
|
+
* This gates **automatic detection only**. The `@split` directive is an
|
|
91
|
+
* independent, explicit trigger: it always splits the field it annotates —
|
|
92
|
+
* a nested collection just as much as a one-to-one reference — whatever
|
|
93
|
+
* this option is set to. Setting it to `false` and annotating only the
|
|
94
|
+
* fields that actually exceed the limit gives you a manual mode in which
|
|
95
|
+
* every other query is a single round trip.
|
|
96
|
+
*
|
|
97
|
+
* `@split` on a root field throws a `CONFIG` error: there is no parent
|
|
98
|
+
* entry to stitch the result back onto.
|
|
89
99
|
*/
|
|
90
100
|
autoSplitNestedCollections?: boolean;
|
|
91
101
|
/** How many parent entry ids to resolve per subquery request. Defaults to `50`. */
|
|
@@ -114,6 +124,51 @@ interface FetchContentfulOptions<TVariables extends GraphQLVariables = GraphQLVa
|
|
|
114
124
|
/** Standard fetch cache mode, forwarded to fetch. */
|
|
115
125
|
cache?: RequestCache;
|
|
116
126
|
}
|
|
127
|
+
/**
|
|
128
|
+
* Variables {@link FetchContentfulOptions.autoInjectArgs} fills in on the
|
|
129
|
+
* caller's behalf, so a typed document that declares `$preview` / `$locale`
|
|
130
|
+
* never forces the caller to pass them.
|
|
131
|
+
*/
|
|
132
|
+
type AutoInjectedVariable = 'preview' | 'locale';
|
|
133
|
+
/** The variables a caller still has to supply for a typed document. */
|
|
134
|
+
type CallerVariables<TVariables> = Omit<TVariables, AutoInjectedVariable>;
|
|
135
|
+
/** `true` when nothing is left for the caller to pass. */
|
|
136
|
+
type VariablesAreOptional<TVariables> = Record<string, never> extends CallerVariables<TVariables> ? true : false;
|
|
137
|
+
/**
|
|
138
|
+
* Makes `variables` required exactly when the document declares one the
|
|
139
|
+
* caller must provide, and optional otherwise (including when every
|
|
140
|
+
* remaining variable is nullable, or when the only ones left are
|
|
141
|
+
* auto-injected).
|
|
142
|
+
*
|
|
143
|
+
* The conditional deliberately sits in *key* position rather than wrapping
|
|
144
|
+
* the whole object. TypeScript skips excess-property checks when a
|
|
145
|
+
* parameter's type is a conditional over a type argument it is still
|
|
146
|
+
* inferring, so `{ variables: { slgu: '…' } }` would slip through a
|
|
147
|
+
* `… ? { variables: T } : { variables?: T }` formulation. Selecting the key
|
|
148
|
+
* instead keeps the property's type a plain `TVariables`, and typos are
|
|
149
|
+
* caught.
|
|
150
|
+
*/
|
|
151
|
+
type VariablesOption<TVariables> = {
|
|
152
|
+
[K in VariablesAreOptional<TVariables> extends true ? never : 'variables']: TVariables;
|
|
153
|
+
} & {
|
|
154
|
+
[K in VariablesAreOptional<TVariables> extends true ? 'variables' : never]?: TVariables;
|
|
155
|
+
};
|
|
156
|
+
/**
|
|
157
|
+
* {@link FetchContentfulOptions} for a call that passes a typed document:
|
|
158
|
+
* identical, except `variables` is typed by — and required by — the
|
|
159
|
+
* document itself.
|
|
160
|
+
*/
|
|
161
|
+
type TypedFetchContentfulOptions<TVariables> = Omit<FetchContentfulOptions<GraphQLVariables>, 'variables'> & VariablesOption<TVariables>;
|
|
162
|
+
/**
|
|
163
|
+
* The result type a document carries, falling back to the historical
|
|
164
|
+
* default for a plain, untyped `DocumentNode`.
|
|
165
|
+
*
|
|
166
|
+
* `TypedDocumentNode`'s type brand is an optional property, so an untyped
|
|
167
|
+
* `DocumentNode` structurally satisfies it and infers `unknown`. Mapping
|
|
168
|
+
* that back to `Record<string, unknown>` keeps pre-existing
|
|
169
|
+
* `fetchContentful(parse(query))` calls typed exactly as they were.
|
|
170
|
+
*/
|
|
171
|
+
type DocumentResult<TResult> = unknown extends TResult ? Record<string, unknown> : TResult;
|
|
117
172
|
/** A single locale as configured in Contentful. */
|
|
118
173
|
interface ContentfulLocale {
|
|
119
174
|
code: string;
|
|
@@ -278,18 +333,33 @@ declare function collectAtPath(data: unknown, path: string[]): Record<string, un
|
|
|
278
333
|
* query has succeeded.
|
|
279
334
|
* - Shapes the response so every `fooCollection.items` becomes `foo`
|
|
280
335
|
* (disable with `shapeResponseData: false` to receive the raw wire shape).
|
|
336
|
+
*
|
|
337
|
+
* Pass a typed document — from gql.tada, graphql-codegen's client preset, or
|
|
338
|
+
* anything else producing a `TypedDocumentNode` — and both the result and
|
|
339
|
+
* the variables are inferred, with no type arguments to write by hand.
|
|
281
340
|
*/
|
|
282
|
-
declare function fetchContentful<
|
|
341
|
+
declare function fetchContentful<TResult, TVariables = GraphQLVariables>(document: TypedDocumentNode<TResult, TVariables>, options: TypedFetchContentfulOptions<TVariables> & {
|
|
342
|
+
shapeResponseData: false;
|
|
343
|
+
unwrapRootField: false;
|
|
344
|
+
}): Promise<DocumentResult<TResult>>;
|
|
345
|
+
declare function fetchContentful<TResult, TVariables = GraphQLVariables>(document: TypedDocumentNode<TResult, TVariables>, options: TypedFetchContentfulOptions<TVariables> & {
|
|
346
|
+
shapeResponseData: false;
|
|
347
|
+
}): Promise<UnwrapSingleRoot<DocumentResult<TResult>>>;
|
|
348
|
+
declare function fetchContentful<TResult, TVariables = GraphQLVariables>(document: TypedDocumentNode<TResult, TVariables>, options: TypedFetchContentfulOptions<TVariables> & {
|
|
349
|
+
unwrapRootField: false;
|
|
350
|
+
}): Promise<ShapeCollections<DocumentResult<TResult>>>;
|
|
351
|
+
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>>>>;
|
|
352
|
+
declare function fetchContentful<TData = Record<string, unknown>, TVariables extends GraphQLVariables = GraphQLVariables>(query: string, options: FetchContentfulOptions<TVariables> & {
|
|
283
353
|
shapeResponseData: false;
|
|
284
354
|
unwrapRootField: false;
|
|
285
355
|
}): Promise<TData>;
|
|
286
|
-
declare function fetchContentful<TData = Record<string, unknown>, TVariables extends GraphQLVariables = GraphQLVariables>(query: string
|
|
356
|
+
declare function fetchContentful<TData = Record<string, unknown>, TVariables extends GraphQLVariables = GraphQLVariables>(query: string, options: FetchContentfulOptions<TVariables> & {
|
|
287
357
|
shapeResponseData: false;
|
|
288
358
|
}): Promise<UnwrapSingleRoot<TData>>;
|
|
289
|
-
declare function fetchContentful<TData = Record<string, unknown>, TVariables extends GraphQLVariables = GraphQLVariables>(query: string
|
|
359
|
+
declare function fetchContentful<TData = Record<string, unknown>, TVariables extends GraphQLVariables = GraphQLVariables>(query: string, options: FetchContentfulOptions<TVariables> & {
|
|
290
360
|
unwrapRootField: false;
|
|
291
361
|
}): Promise<ShapeCollections<TData>>;
|
|
292
|
-
declare function fetchContentful<TData = Record<string, unknown>, TVariables extends GraphQLVariables = GraphQLVariables>(query: string
|
|
362
|
+
declare function fetchContentful<TData = Record<string, unknown>, TVariables extends GraphQLVariables = GraphQLVariables>(query: string, options?: FetchContentfulOptions<TVariables>): Promise<UnwrapSingleRoot<ShapeCollections<TData>>>;
|
|
293
363
|
/**
|
|
294
364
|
* Creates a `fetchContentful` bound to default options — the recommended way
|
|
295
365
|
* to configure the utility once per project:
|
|
@@ -308,17 +378,28 @@ declare function fetchContentful<TData = Record<string, unknown>, TVariables ext
|
|
|
308
378
|
* the call itself, so prefer setting it per call.
|
|
309
379
|
*/
|
|
310
380
|
declare function createFetchContentful<TDefaultVariables extends GraphQLVariables = GraphQLVariables>(defaults?: FetchContentfulOptions<TDefaultVariables>): {
|
|
311
|
-
<
|
|
381
|
+
<TResult, TVariables = GraphQLVariables>(document: TypedDocumentNode<TResult, TVariables>, options: TypedFetchContentfulOptions<TVariables> & {
|
|
382
|
+
shapeResponseData: false;
|
|
383
|
+
unwrapRootField: false;
|
|
384
|
+
}): Promise<DocumentResult<TResult>>;
|
|
385
|
+
<TResult, TVariables = GraphQLVariables>(document: TypedDocumentNode<TResult, TVariables>, options: TypedFetchContentfulOptions<TVariables> & {
|
|
386
|
+
shapeResponseData: false;
|
|
387
|
+
}): Promise<UnwrapSingleRoot<DocumentResult<TResult>>>;
|
|
388
|
+
<TResult, TVariables = GraphQLVariables>(document: TypedDocumentNode<TResult, TVariables>, options: TypedFetchContentfulOptions<TVariables> & {
|
|
389
|
+
unwrapRootField: false;
|
|
390
|
+
}): Promise<ShapeCollections<DocumentResult<TResult>>>;
|
|
391
|
+
<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>>>>;
|
|
392
|
+
<TData = Record<string, unknown>, TVariables extends GraphQLVariables = GraphQLVariables>(query: string, options: FetchContentfulOptions<TVariables> & {
|
|
312
393
|
shapeResponseData: false;
|
|
313
394
|
unwrapRootField: false;
|
|
314
395
|
}): Promise<TData>;
|
|
315
|
-
<TData = Record<string, unknown>, TVariables extends GraphQLVariables = GraphQLVariables>(query: string
|
|
396
|
+
<TData = Record<string, unknown>, TVariables extends GraphQLVariables = GraphQLVariables>(query: string, options: FetchContentfulOptions<TVariables> & {
|
|
316
397
|
shapeResponseData: false;
|
|
317
398
|
}): Promise<UnwrapSingleRoot<TData>>;
|
|
318
|
-
<TData = Record<string, unknown>, TVariables extends GraphQLVariables = GraphQLVariables>(query: string
|
|
399
|
+
<TData = Record<string, unknown>, TVariables extends GraphQLVariables = GraphQLVariables>(query: string, options: FetchContentfulOptions<TVariables> & {
|
|
319
400
|
unwrapRootField: false;
|
|
320
401
|
}): Promise<ShapeCollections<TData>>;
|
|
321
|
-
<TData = Record<string, unknown>, TVariables extends GraphQLVariables = GraphQLVariables>(query: string
|
|
402
|
+
<TData = Record<string, unknown>, TVariables extends GraphQLVariables = GraphQLVariables>(query: string, options?: FetchContentfulOptions<TVariables>): Promise<UnwrapSingleRoot<ShapeCollections<TData>>>;
|
|
322
403
|
};
|
|
323
404
|
|
|
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 };
|
|
405
|
+
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),
|
|
@@ -867,12 +875,15 @@ async function executeDocument(document, variables, context) {
|
|
|
867
875
|
cleanupMarkers(data, plans);
|
|
868
876
|
return data;
|
|
869
877
|
}
|
|
878
|
+
function isDocumentNode(query) {
|
|
879
|
+
return typeof query === "object" && query !== null && query.kind === Kind.DOCUMENT && Array.isArray(query.definitions);
|
|
880
|
+
}
|
|
870
881
|
function toDocument(query) {
|
|
871
|
-
if (
|
|
882
|
+
if (isDocumentNode(query)) {
|
|
872
883
|
return query;
|
|
873
884
|
}
|
|
874
885
|
try {
|
|
875
|
-
return parse(query);
|
|
886
|
+
return parse(typeof query === "string" ? query : String(query));
|
|
876
887
|
} catch (cause) {
|
|
877
888
|
throw new FetchContentfulError(
|
|
878
889
|
`Failed to parse GraphQL query: ${String(cause)}`,
|
|
@@ -895,7 +906,7 @@ function withAutoVariables(document, variables, context) {
|
|
|
895
906
|
}
|
|
896
907
|
return merged;
|
|
897
908
|
}
|
|
898
|
-
async function
|
|
909
|
+
async function runFetchContentful(query, options) {
|
|
899
910
|
const context = resolveContext(options);
|
|
900
911
|
let document = inlineFragments(toDocument(query));
|
|
901
912
|
if (options.autoInjectArgs ?? true) {
|
|
@@ -925,32 +936,15 @@ async function fetchContentful(query, options = {}) {
|
|
|
925
936
|
}
|
|
926
937
|
return unwrapSingleRoot(result);
|
|
927
938
|
}
|
|
939
|
+
async function fetchContentful(query, options = {}) {
|
|
940
|
+
return runFetchContentful(query, options);
|
|
941
|
+
}
|
|
928
942
|
function createFetchContentful(defaults = {}) {
|
|
929
943
|
function bound(query, options = {}) {
|
|
930
|
-
|
|
944
|
+
return runFetchContentful(query, {
|
|
931
945
|
...defaults,
|
|
932
946
|
...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);
|
|
947
|
+
});
|
|
954
948
|
}
|
|
955
949
|
return bound;
|
|
956
950
|
}
|