@fourtwelvelabs/fetch-contentful 0.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/LICENSE +21 -0
- package/README.md +301 -0
- package/dist/index.cjs +977 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +324 -0
- package/dist/index.d.ts +324 -0
- package/dist/index.mjs +961 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +76 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,977 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var graphql = require('graphql');
|
|
6
|
+
|
|
7
|
+
// src/index.ts
|
|
8
|
+
|
|
9
|
+
// src/errors.ts
|
|
10
|
+
var FetchContentfulError = class extends Error {
|
|
11
|
+
code;
|
|
12
|
+
status;
|
|
13
|
+
errors;
|
|
14
|
+
/** Internal: whether a retry may succeed. */
|
|
15
|
+
retryable;
|
|
16
|
+
/** Internal: server-requested retry delay (from Retry-After), in ms. */
|
|
17
|
+
retryAfterMs;
|
|
18
|
+
constructor(message, options) {
|
|
19
|
+
super(message, { cause: options.cause });
|
|
20
|
+
this.name = "FetchContentfulError";
|
|
21
|
+
this.code = options.code;
|
|
22
|
+
this.status = options.status;
|
|
23
|
+
this.errors = options.errors;
|
|
24
|
+
this.retryable = options.retryable ?? false;
|
|
25
|
+
this.retryAfterMs = options.retryAfterMs;
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
function isFetchContentfulError(value) {
|
|
29
|
+
return value instanceof FetchContentfulError;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// src/retry.ts
|
|
33
|
+
function defaultSleep(ms) {
|
|
34
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
35
|
+
}
|
|
36
|
+
function backoffDelay(attempt, config) {
|
|
37
|
+
const exponential = config.baseDelayMs * 2 ** attempt;
|
|
38
|
+
const jitter = config.random() * config.baseDelayMs;
|
|
39
|
+
return Math.min(exponential + jitter, config.maxDelayMs);
|
|
40
|
+
}
|
|
41
|
+
async function withRetries(fn, config) {
|
|
42
|
+
const random = config.random ?? Math.random;
|
|
43
|
+
const sleep = config.sleep ?? defaultSleep;
|
|
44
|
+
let attempt = 0;
|
|
45
|
+
while (true) {
|
|
46
|
+
try {
|
|
47
|
+
return await fn(attempt);
|
|
48
|
+
} catch (error) {
|
|
49
|
+
const retryable = isFetchContentfulError(error) && error.retryable;
|
|
50
|
+
if (!retryable || attempt >= config.retries) {
|
|
51
|
+
throw error;
|
|
52
|
+
}
|
|
53
|
+
const delay = error.retryAfterMs ?? backoffDelay(attempt, { ...config, random });
|
|
54
|
+
await sleep(delay);
|
|
55
|
+
attempt += 1;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
var SPLIT_DIRECTIVE = "split";
|
|
60
|
+
var NO_SPLIT_DIRECTIVE = "_noSplit";
|
|
61
|
+
var SYS_ID_ALIAS = "_splitSysId";
|
|
62
|
+
var TYPENAME_ALIAS = "_splitTypename";
|
|
63
|
+
var IDS_VARIABLE = "_splitIds";
|
|
64
|
+
var COLLECTION_SUFFIX = "Collection";
|
|
65
|
+
function lowerFirst(value) {
|
|
66
|
+
return value.charAt(0).toLowerCase() + value.slice(1);
|
|
67
|
+
}
|
|
68
|
+
function chunk(items, size) {
|
|
69
|
+
const chunks = [];
|
|
70
|
+
for (let index = 0; index < items.length; index += size) {
|
|
71
|
+
chunks.push(items.slice(index, index + size));
|
|
72
|
+
}
|
|
73
|
+
return chunks;
|
|
74
|
+
}
|
|
75
|
+
function directivesOf(field) {
|
|
76
|
+
return field.directives ?? [];
|
|
77
|
+
}
|
|
78
|
+
function hasDirective(field, name) {
|
|
79
|
+
return directivesOf(field).some((d) => d.name.value === name);
|
|
80
|
+
}
|
|
81
|
+
function withoutDirective(field, name) {
|
|
82
|
+
return {
|
|
83
|
+
...field,
|
|
84
|
+
directives: directivesOf(field).filter((d) => d.name.value !== name)
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
function withDirective(field, name) {
|
|
88
|
+
const directive = {
|
|
89
|
+
kind: graphql.Kind.DIRECTIVE,
|
|
90
|
+
name: { kind: graphql.Kind.NAME, value: name }
|
|
91
|
+
};
|
|
92
|
+
return { ...field, directives: [...directivesOf(field), directive] };
|
|
93
|
+
}
|
|
94
|
+
function responseKeyOf(field) {
|
|
95
|
+
return field.alias?.value ?? field.name.value;
|
|
96
|
+
}
|
|
97
|
+
function isCollectionField(field) {
|
|
98
|
+
if (!field.name.value.endsWith(COLLECTION_SUFFIX) || field.name.value === COLLECTION_SUFFIX || !field.selectionSet) {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
return field.selectionSet.selections.some(
|
|
102
|
+
(selection) => selection.kind === graphql.Kind.FIELD && selection.name.value === "items"
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
function namedField(name, alias, selections) {
|
|
106
|
+
return {
|
|
107
|
+
kind: graphql.Kind.FIELD,
|
|
108
|
+
name: { kind: graphql.Kind.NAME, value: name },
|
|
109
|
+
...alias ? { alias: { kind: graphql.Kind.NAME, value: alias } } : {},
|
|
110
|
+
...selections ? {
|
|
111
|
+
selectionSet: {
|
|
112
|
+
kind: graphql.Kind.SELECTION_SET,
|
|
113
|
+
selections
|
|
114
|
+
}
|
|
115
|
+
} : {}
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
function sysIdMarker() {
|
|
119
|
+
return namedField("sys", SYS_ID_ALIAS, [namedField("id")]);
|
|
120
|
+
}
|
|
121
|
+
function typenameMarker() {
|
|
122
|
+
return namedField("__typename", TYPENAME_ALIAS);
|
|
123
|
+
}
|
|
124
|
+
function collectVariableNames(field) {
|
|
125
|
+
const names = /* @__PURE__ */ new Set();
|
|
126
|
+
graphql.visit(field, {
|
|
127
|
+
Variable(node) {
|
|
128
|
+
names.add(node.name.value);
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
return names;
|
|
132
|
+
}
|
|
133
|
+
function getOperation(document) {
|
|
134
|
+
const operations = document.definitions.filter(
|
|
135
|
+
(definition) => definition.kind === graphql.Kind.OPERATION_DEFINITION
|
|
136
|
+
);
|
|
137
|
+
const operation = operations[0];
|
|
138
|
+
if (!operation || operations.length > 1) {
|
|
139
|
+
throw new FetchContentfulError(
|
|
140
|
+
"fetch-contentful expects exactly one operation per document.",
|
|
141
|
+
{ code: "CONFIG" }
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
if (operation.operation !== "query") {
|
|
145
|
+
throw new FetchContentfulError(
|
|
146
|
+
"fetch-contentful only supports query operations.",
|
|
147
|
+
{ code: "CONFIG" }
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
return operation;
|
|
151
|
+
}
|
|
152
|
+
function inlineFragments(document) {
|
|
153
|
+
const fragments = /* @__PURE__ */ new Map();
|
|
154
|
+
for (const definition of document.definitions) {
|
|
155
|
+
if (definition.kind === graphql.Kind.FRAGMENT_DEFINITION) {
|
|
156
|
+
fragments.set(definition.name.value, definition);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
function inlineSelectionSet(selectionSet, stack) {
|
|
160
|
+
const selections = selectionSet.selections.map(
|
|
161
|
+
(selection) => {
|
|
162
|
+
if (selection.kind === graphql.Kind.FRAGMENT_SPREAD) {
|
|
163
|
+
const name = selection.name.value;
|
|
164
|
+
const fragment = fragments.get(name);
|
|
165
|
+
if (!fragment) {
|
|
166
|
+
throw new FetchContentfulError(
|
|
167
|
+
`Unknown fragment "${name}" referenced in query.`,
|
|
168
|
+
{ code: "CONFIG" }
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
if (stack.includes(name)) {
|
|
172
|
+
throw new FetchContentfulError(
|
|
173
|
+
`Fragment cycle detected involving "${name}".`,
|
|
174
|
+
{ code: "CONFIG" }
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
return {
|
|
178
|
+
kind: graphql.Kind.INLINE_FRAGMENT,
|
|
179
|
+
typeCondition: fragment.typeCondition,
|
|
180
|
+
selectionSet: inlineSelectionSet(fragment.selectionSet, [
|
|
181
|
+
...stack,
|
|
182
|
+
name
|
|
183
|
+
])
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
if (selection.selectionSet) {
|
|
187
|
+
return {
|
|
188
|
+
...selection,
|
|
189
|
+
selectionSet: inlineSelectionSet(selection.selectionSet, stack)
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
return selection;
|
|
193
|
+
}
|
|
194
|
+
);
|
|
195
|
+
return { ...selectionSet, selections };
|
|
196
|
+
}
|
|
197
|
+
const definitions = document.definitions.filter((definition) => definition.kind !== graphql.Kind.FRAGMENT_DEFINITION).map(
|
|
198
|
+
(definition) => definition.kind === graphql.Kind.OPERATION_DEFINITION ? {
|
|
199
|
+
...definition,
|
|
200
|
+
selectionSet: inlineSelectionSet(definition.selectionSet, [])
|
|
201
|
+
} : definition
|
|
202
|
+
);
|
|
203
|
+
return { ...document, definitions };
|
|
204
|
+
}
|
|
205
|
+
function planSplits(document, options) {
|
|
206
|
+
const operation = getOperation(document);
|
|
207
|
+
const variableDefinitions = operation.variableDefinitions ?? [];
|
|
208
|
+
const plans = [];
|
|
209
|
+
function processSelectionSet(selectionSet, path, depth, typeCondition) {
|
|
210
|
+
const selections = [];
|
|
211
|
+
let needsMarkers = false;
|
|
212
|
+
for (const selection of selectionSet.selections) {
|
|
213
|
+
if (selection.kind === graphql.Kind.INLINE_FRAGMENT) {
|
|
214
|
+
const condition = selection.typeCondition?.name.value;
|
|
215
|
+
selections.push({
|
|
216
|
+
...selection,
|
|
217
|
+
selectionSet: processSelectionSet(
|
|
218
|
+
selection.selectionSet,
|
|
219
|
+
path,
|
|
220
|
+
depth,
|
|
221
|
+
// `Entry` is Contentful's interface type: it never equals a
|
|
222
|
+
// concrete `__typename`, so it must not constrain the plan.
|
|
223
|
+
condition && condition !== "Entry" ? condition : typeCondition
|
|
224
|
+
)
|
|
225
|
+
});
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
228
|
+
if (selection.kind !== graphql.Kind.FIELD) {
|
|
229
|
+
throw new FetchContentfulError(
|
|
230
|
+
"Fragment spreads must be inlined before split planning.",
|
|
231
|
+
{ code: "CONFIG" }
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
const field = selection;
|
|
235
|
+
const shouldSplit = depth > 0 && field.selectionSet !== void 0 && !hasDirective(field, NO_SPLIT_DIRECTIVE) && (hasDirective(field, SPLIT_DIRECTIVE) || options.autoSplitNestedCollections && isCollectionField(field));
|
|
236
|
+
if (shouldSplit) {
|
|
237
|
+
const planned = withDirective(
|
|
238
|
+
withoutDirective(field, SPLIT_DIRECTIVE),
|
|
239
|
+
NO_SPLIT_DIRECTIVE
|
|
240
|
+
);
|
|
241
|
+
plans.push({
|
|
242
|
+
path: [...path],
|
|
243
|
+
responseKey: responseKeyOf(field),
|
|
244
|
+
field: planned,
|
|
245
|
+
variableDefinitions: variableDefinitions.filter(
|
|
246
|
+
(definition) => collectVariableNames(field).has(definition.variable.name.value)
|
|
247
|
+
),
|
|
248
|
+
...typeCondition !== void 0 ? { typeCondition } : {}
|
|
249
|
+
});
|
|
250
|
+
needsMarkers = true;
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
if (field.selectionSet) {
|
|
254
|
+
selections.push({
|
|
255
|
+
...field,
|
|
256
|
+
selectionSet: processSelectionSet(
|
|
257
|
+
field.selectionSet,
|
|
258
|
+
[...path, responseKeyOf(field)],
|
|
259
|
+
depth + 1,
|
|
260
|
+
// Type conditions do not carry across a field boundary: the
|
|
261
|
+
// field's own type governs its children.
|
|
262
|
+
void 0
|
|
263
|
+
)
|
|
264
|
+
});
|
|
265
|
+
} else {
|
|
266
|
+
selections.push(field);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
if (needsMarkers) {
|
|
270
|
+
selections.push(sysIdMarker(), typenameMarker());
|
|
271
|
+
}
|
|
272
|
+
return { ...selectionSet, selections };
|
|
273
|
+
}
|
|
274
|
+
const processedOperation = {
|
|
275
|
+
...operation,
|
|
276
|
+
selectionSet: processSelectionSet(operation.selectionSet, [], 0, void 0)
|
|
277
|
+
};
|
|
278
|
+
return {
|
|
279
|
+
document: {
|
|
280
|
+
...document,
|
|
281
|
+
definitions: document.definitions.map(
|
|
282
|
+
(definition) => definition === operation ? processedOperation : definition
|
|
283
|
+
)
|
|
284
|
+
},
|
|
285
|
+
plans
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
function stringArgument(name, value) {
|
|
289
|
+
return {
|
|
290
|
+
kind: graphql.Kind.ARGUMENT,
|
|
291
|
+
name: { kind: graphql.Kind.NAME, value: name },
|
|
292
|
+
value: { kind: graphql.Kind.STRING, value }
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
function booleanArgument(name, value) {
|
|
296
|
+
return {
|
|
297
|
+
kind: graphql.Kind.ARGUMENT,
|
|
298
|
+
name: { kind: graphql.Kind.NAME, value: name },
|
|
299
|
+
value: { kind: graphql.Kind.BOOLEAN, value }
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
function intArgument(name, value) {
|
|
303
|
+
return {
|
|
304
|
+
kind: graphql.Kind.ARGUMENT,
|
|
305
|
+
name: { kind: graphql.Kind.NAME, value: name },
|
|
306
|
+
value: { kind: graphql.Kind.INT, value: String(value) }
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
function whereIdInArgument() {
|
|
310
|
+
return {
|
|
311
|
+
kind: graphql.Kind.ARGUMENT,
|
|
312
|
+
name: { kind: graphql.Kind.NAME, value: "where" },
|
|
313
|
+
value: {
|
|
314
|
+
kind: graphql.Kind.OBJECT,
|
|
315
|
+
fields: [
|
|
316
|
+
{
|
|
317
|
+
kind: graphql.Kind.OBJECT_FIELD,
|
|
318
|
+
name: { kind: graphql.Kind.NAME, value: "sys" },
|
|
319
|
+
value: {
|
|
320
|
+
kind: graphql.Kind.OBJECT,
|
|
321
|
+
fields: [
|
|
322
|
+
{
|
|
323
|
+
kind: graphql.Kind.OBJECT_FIELD,
|
|
324
|
+
name: { kind: graphql.Kind.NAME, value: "id_in" },
|
|
325
|
+
value: {
|
|
326
|
+
kind: graphql.Kind.VARIABLE,
|
|
327
|
+
name: { kind: graphql.Kind.NAME, value: IDS_VARIABLE }
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
]
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
]
|
|
334
|
+
}
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
function buildSubquery(plan, typename, batchSize, context) {
|
|
338
|
+
const rootKey = `${lowerFirst(typename)}${COLLECTION_SUFFIX}`;
|
|
339
|
+
const args = [
|
|
340
|
+
whereIdInArgument(),
|
|
341
|
+
intArgument("limit", batchSize)
|
|
342
|
+
];
|
|
343
|
+
if (context.preview) {
|
|
344
|
+
args.push(booleanArgument("preview", true));
|
|
345
|
+
}
|
|
346
|
+
if (context.locale !== void 0) {
|
|
347
|
+
args.push(stringArgument("locale", context.locale));
|
|
348
|
+
}
|
|
349
|
+
const rootField = {
|
|
350
|
+
...namedField(rootKey, void 0, [
|
|
351
|
+
namedField("items", void 0, [
|
|
352
|
+
namedField("sys", void 0, [namedField("id")]),
|
|
353
|
+
plan.field
|
|
354
|
+
])
|
|
355
|
+
]),
|
|
356
|
+
arguments: args
|
|
357
|
+
};
|
|
358
|
+
const idsVariable = {
|
|
359
|
+
kind: graphql.Kind.VARIABLE_DEFINITION,
|
|
360
|
+
variable: {
|
|
361
|
+
kind: graphql.Kind.VARIABLE,
|
|
362
|
+
name: { kind: graphql.Kind.NAME, value: IDS_VARIABLE }
|
|
363
|
+
},
|
|
364
|
+
type: {
|
|
365
|
+
kind: graphql.Kind.NON_NULL_TYPE,
|
|
366
|
+
type: {
|
|
367
|
+
kind: graphql.Kind.LIST_TYPE,
|
|
368
|
+
type: {
|
|
369
|
+
kind: graphql.Kind.NON_NULL_TYPE,
|
|
370
|
+
type: {
|
|
371
|
+
kind: graphql.Kind.NAMED_TYPE,
|
|
372
|
+
name: { kind: graphql.Kind.NAME, value: "String" }
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
};
|
|
378
|
+
const operation = {
|
|
379
|
+
kind: graphql.Kind.OPERATION_DEFINITION,
|
|
380
|
+
operation: "query",
|
|
381
|
+
name: { kind: graphql.Kind.NAME, value: "FetchContentfulSplit" },
|
|
382
|
+
variableDefinitions: [idsVariable, ...plan.variableDefinitions],
|
|
383
|
+
selectionSet: {
|
|
384
|
+
kind: graphql.Kind.SELECTION_SET,
|
|
385
|
+
selections: [rootField]
|
|
386
|
+
}
|
|
387
|
+
};
|
|
388
|
+
return {
|
|
389
|
+
document: { kind: graphql.Kind.DOCUMENT, definitions: [operation] },
|
|
390
|
+
rootKey
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
function stripInternalDirectives(document) {
|
|
394
|
+
return graphql.visit(document, {
|
|
395
|
+
Directive(node) {
|
|
396
|
+
if (node.name.value === SPLIT_DIRECTIVE || node.name.value === NO_SPLIT_DIRECTIVE) {
|
|
397
|
+
return null;
|
|
398
|
+
}
|
|
399
|
+
return void 0;
|
|
400
|
+
}
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// src/client.ts
|
|
405
|
+
function graphqlEndpoint(space, environment) {
|
|
406
|
+
return `https://graphql.contentful.com/content/v1/spaces/${encodeURIComponent(
|
|
407
|
+
space
|
|
408
|
+
)}/environments/${encodeURIComponent(environment)}`;
|
|
409
|
+
}
|
|
410
|
+
function parseRetryAfter(header) {
|
|
411
|
+
if (!header) return void 0;
|
|
412
|
+
const seconds = Number(header);
|
|
413
|
+
if (Number.isFinite(seconds)) {
|
|
414
|
+
return Math.max(0, seconds * 1e3);
|
|
415
|
+
}
|
|
416
|
+
const date = Date.parse(header);
|
|
417
|
+
if (Number.isFinite(date)) {
|
|
418
|
+
return Math.max(0, date - Date.now());
|
|
419
|
+
}
|
|
420
|
+
return void 0;
|
|
421
|
+
}
|
|
422
|
+
function pickDeclaredVariables(document, variables) {
|
|
423
|
+
const declared = new Set(
|
|
424
|
+
(getOperation(document).variableDefinitions ?? []).map(
|
|
425
|
+
(definition) => definition.variable.name.value
|
|
426
|
+
)
|
|
427
|
+
);
|
|
428
|
+
const picked = {};
|
|
429
|
+
for (const [name, value] of Object.entries(variables)) {
|
|
430
|
+
if (declared.has(name)) {
|
|
431
|
+
picked[name] = value;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
return picked;
|
|
435
|
+
}
|
|
436
|
+
function isRetryableStatus(status) {
|
|
437
|
+
return status === 408 || status === 429 || status >= 500;
|
|
438
|
+
}
|
|
439
|
+
async function rawRequest(document, variables, context) {
|
|
440
|
+
const query = graphql.print(stripInternalDirectives(document));
|
|
441
|
+
const body = JSON.stringify({
|
|
442
|
+
query,
|
|
443
|
+
variables: pickDeclaredVariables(document, variables)
|
|
444
|
+
});
|
|
445
|
+
const url = graphqlEndpoint(context.space, context.environment);
|
|
446
|
+
return withRetries(async () => {
|
|
447
|
+
let response;
|
|
448
|
+
try {
|
|
449
|
+
const init = {
|
|
450
|
+
method: "POST",
|
|
451
|
+
headers: {
|
|
452
|
+
"Content-Type": "application/json",
|
|
453
|
+
Authorization: `Bearer ${context.token}`
|
|
454
|
+
},
|
|
455
|
+
body
|
|
456
|
+
};
|
|
457
|
+
if (context.signal) init.signal = context.signal;
|
|
458
|
+
if (context.cache) init.cache = context.cache;
|
|
459
|
+
if (context.next) init.next = context.next;
|
|
460
|
+
response = await context.fetch(url, init);
|
|
461
|
+
} catch (cause) {
|
|
462
|
+
throw new FetchContentfulError(
|
|
463
|
+
`Network error while contacting Contentful: ${String(cause)}`,
|
|
464
|
+
{ code: "NETWORK", retryable: true, cause }
|
|
465
|
+
);
|
|
466
|
+
}
|
|
467
|
+
if (!response.ok) {
|
|
468
|
+
const retryable = isRetryableStatus(response.status);
|
|
469
|
+
throw new FetchContentfulError(
|
|
470
|
+
`Contentful responded with HTTP ${response.status}.`,
|
|
471
|
+
{
|
|
472
|
+
code: "HTTP",
|
|
473
|
+
status: response.status,
|
|
474
|
+
retryable,
|
|
475
|
+
retryAfterMs: retryable ? parseRetryAfter(response.headers.get("Retry-After")) : void 0
|
|
476
|
+
}
|
|
477
|
+
);
|
|
478
|
+
}
|
|
479
|
+
let payload;
|
|
480
|
+
try {
|
|
481
|
+
payload = await response.json();
|
|
482
|
+
} catch (cause) {
|
|
483
|
+
throw new FetchContentfulError(
|
|
484
|
+
"Contentful returned an unreadable response body.",
|
|
485
|
+
{ code: "NETWORK", retryable: true, cause }
|
|
486
|
+
);
|
|
487
|
+
}
|
|
488
|
+
if (payload.errors && payload.errors.length > 0) {
|
|
489
|
+
throw new FetchContentfulError(
|
|
490
|
+
`Contentful returned GraphQL errors: ${payload.errors.map((error) => error.message).join("; ")}`,
|
|
491
|
+
{ code: "GRAPHQL", errors: payload.errors }
|
|
492
|
+
);
|
|
493
|
+
}
|
|
494
|
+
if (!payload.data || typeof payload.data !== "object") {
|
|
495
|
+
throw new FetchContentfulError(
|
|
496
|
+
"Contentful returned no data and no errors.",
|
|
497
|
+
{ code: "GRAPHQL" }
|
|
498
|
+
);
|
|
499
|
+
}
|
|
500
|
+
return payload.data;
|
|
501
|
+
}, context.retry);
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
// src/env.ts
|
|
505
|
+
function orUndefined(value) {
|
|
506
|
+
return value || void 0;
|
|
507
|
+
}
|
|
508
|
+
function readEnvSettings() {
|
|
509
|
+
if (typeof process === "undefined" || !process.env) {
|
|
510
|
+
return {
|
|
511
|
+
space: void 0,
|
|
512
|
+
environment: void 0,
|
|
513
|
+
token: void 0,
|
|
514
|
+
previewToken: void 0
|
|
515
|
+
};
|
|
516
|
+
}
|
|
517
|
+
return {
|
|
518
|
+
space: orUndefined(
|
|
519
|
+
process.env.CONTENTFUL_SPACE_ID || process.env.NEXT_PUBLIC_CONTENTFUL_SPACE_ID
|
|
520
|
+
),
|
|
521
|
+
environment: orUndefined(
|
|
522
|
+
process.env.CONTENTFUL_ENVIRONMENT || process.env.NEXT_PUBLIC_CONTENTFUL_ENVIRONMENT
|
|
523
|
+
),
|
|
524
|
+
token: orUndefined(
|
|
525
|
+
process.env.CONTENTFUL_ACCESS_TOKEN || process.env.NEXT_PUBLIC_CONTENTFUL_ACCESS_TOKEN
|
|
526
|
+
),
|
|
527
|
+
previewToken: orUndefined(
|
|
528
|
+
process.env.CONTENTFUL_PREVIEW_ACCESS_TOKEN || process.env.NEXT_PUBLIC_CONTENTFUL_PREVIEW_ACCESS_TOKEN
|
|
529
|
+
)
|
|
530
|
+
};
|
|
531
|
+
}
|
|
532
|
+
function argumentsOf(field) {
|
|
533
|
+
return field.arguments ?? [];
|
|
534
|
+
}
|
|
535
|
+
function hasArgument(field, name) {
|
|
536
|
+
return argumentsOf(field).some((argument) => argument.name.value === name);
|
|
537
|
+
}
|
|
538
|
+
function previewArgument() {
|
|
539
|
+
return {
|
|
540
|
+
kind: graphql.Kind.ARGUMENT,
|
|
541
|
+
name: { kind: graphql.Kind.NAME, value: "preview" },
|
|
542
|
+
value: { kind: graphql.Kind.BOOLEAN, value: true }
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
function localeArgument(locale) {
|
|
546
|
+
return {
|
|
547
|
+
kind: graphql.Kind.ARGUMENT,
|
|
548
|
+
name: { kind: graphql.Kind.NAME, value: "locale" },
|
|
549
|
+
value: { kind: graphql.Kind.STRING, value: locale }
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
function injectIntoField(field, args) {
|
|
553
|
+
if (field.name.value.startsWith("__")) {
|
|
554
|
+
return field;
|
|
555
|
+
}
|
|
556
|
+
const additions = [];
|
|
557
|
+
if (args.preview && !hasArgument(field, "preview")) {
|
|
558
|
+
additions.push(previewArgument());
|
|
559
|
+
}
|
|
560
|
+
if (args.locale !== void 0 && !hasArgument(field, "locale")) {
|
|
561
|
+
additions.push(localeArgument(args.locale));
|
|
562
|
+
}
|
|
563
|
+
if (additions.length === 0) {
|
|
564
|
+
return field;
|
|
565
|
+
}
|
|
566
|
+
return { ...field, arguments: [...argumentsOf(field), ...additions] };
|
|
567
|
+
}
|
|
568
|
+
function injectIntoSelectionSet(selectionSet, args) {
|
|
569
|
+
const selections = selectionSet.selections.map(
|
|
570
|
+
(selection) => {
|
|
571
|
+
if (selection.kind === graphql.Kind.FIELD) {
|
|
572
|
+
return injectIntoField(selection, args);
|
|
573
|
+
}
|
|
574
|
+
if (selection.kind === graphql.Kind.INLINE_FRAGMENT) {
|
|
575
|
+
return {
|
|
576
|
+
...selection,
|
|
577
|
+
selectionSet: injectIntoSelectionSet(selection.selectionSet, args)
|
|
578
|
+
};
|
|
579
|
+
}
|
|
580
|
+
return selection;
|
|
581
|
+
}
|
|
582
|
+
);
|
|
583
|
+
return { ...selectionSet, selections };
|
|
584
|
+
}
|
|
585
|
+
function injectRootArgs(document, args) {
|
|
586
|
+
if (!args.preview && args.locale === void 0) {
|
|
587
|
+
return document;
|
|
588
|
+
}
|
|
589
|
+
const operation = getOperation(document);
|
|
590
|
+
const injected = {
|
|
591
|
+
...operation,
|
|
592
|
+
selectionSet: injectIntoSelectionSet(operation.selectionSet, args)
|
|
593
|
+
};
|
|
594
|
+
return {
|
|
595
|
+
...document,
|
|
596
|
+
definitions: document.definitions.map(
|
|
597
|
+
(definition) => definition === operation ? injected : definition
|
|
598
|
+
)
|
|
599
|
+
};
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
// src/locales.ts
|
|
603
|
+
var cache = /* @__PURE__ */ new Map();
|
|
604
|
+
function cacheKey(context) {
|
|
605
|
+
return `${context.space}:${context.environment}:${context.preview ? 1 : 0}`;
|
|
606
|
+
}
|
|
607
|
+
function localesEndpoint(context) {
|
|
608
|
+
const host = context.preview ? "preview.contentful.com" : "cdn.contentful.com";
|
|
609
|
+
return `https://${host}/spaces/${encodeURIComponent(
|
|
610
|
+
context.space
|
|
611
|
+
)}/environments/${encodeURIComponent(context.environment)}/locales`;
|
|
612
|
+
}
|
|
613
|
+
async function fetchLocales(context) {
|
|
614
|
+
return withRetries(async () => {
|
|
615
|
+
let response;
|
|
616
|
+
try {
|
|
617
|
+
const init = {
|
|
618
|
+
headers: { Authorization: `Bearer ${context.token}` }
|
|
619
|
+
};
|
|
620
|
+
if (context.signal) init.signal = context.signal;
|
|
621
|
+
response = await context.fetch(localesEndpoint(context), init);
|
|
622
|
+
} catch (cause) {
|
|
623
|
+
throw new FetchContentfulError(
|
|
624
|
+
`Network error while fetching locales: ${String(cause)}`,
|
|
625
|
+
{ code: "NETWORK", retryable: true, cause }
|
|
626
|
+
);
|
|
627
|
+
}
|
|
628
|
+
if (!response.ok) {
|
|
629
|
+
throw new FetchContentfulError(
|
|
630
|
+
`Locale request failed with HTTP ${response.status}.`,
|
|
631
|
+
{
|
|
632
|
+
code: "HTTP",
|
|
633
|
+
status: response.status,
|
|
634
|
+
retryable: response.status === 429 || response.status >= 500
|
|
635
|
+
}
|
|
636
|
+
);
|
|
637
|
+
}
|
|
638
|
+
const payload = await response.json();
|
|
639
|
+
if (!Array.isArray(payload.items)) {
|
|
640
|
+
throw new FetchContentfulError(
|
|
641
|
+
"Locale response did not include an items array.",
|
|
642
|
+
{ code: "NETWORK" }
|
|
643
|
+
);
|
|
644
|
+
}
|
|
645
|
+
return payload.items.map((item) => ({
|
|
646
|
+
code: item.code,
|
|
647
|
+
name: item.name,
|
|
648
|
+
default: item.default,
|
|
649
|
+
fallbackCode: item.fallbackCode
|
|
650
|
+
}));
|
|
651
|
+
}, context.retry);
|
|
652
|
+
}
|
|
653
|
+
function getLocales(context) {
|
|
654
|
+
const key = cacheKey(context);
|
|
655
|
+
const cached = cache.get(key);
|
|
656
|
+
if (cached) {
|
|
657
|
+
return cached;
|
|
658
|
+
}
|
|
659
|
+
const pending = fetchLocales(context).catch((error) => {
|
|
660
|
+
cache.delete(key);
|
|
661
|
+
throw error;
|
|
662
|
+
});
|
|
663
|
+
cache.set(key, pending);
|
|
664
|
+
return pending;
|
|
665
|
+
}
|
|
666
|
+
function clearLocaleCache() {
|
|
667
|
+
cache.clear();
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
// src/shape.ts
|
|
671
|
+
var COLLECTION_SUFFIX2 = "Collection";
|
|
672
|
+
function isRecord(value) {
|
|
673
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
674
|
+
}
|
|
675
|
+
function isCollectionValue(value) {
|
|
676
|
+
return isRecord(value) && Array.isArray(value["items"]);
|
|
677
|
+
}
|
|
678
|
+
function shapeData(data) {
|
|
679
|
+
if (Array.isArray(data)) {
|
|
680
|
+
return data.map((item) => shapeData(item));
|
|
681
|
+
}
|
|
682
|
+
if (isRecord(data)) {
|
|
683
|
+
const shaped = {};
|
|
684
|
+
for (const [key, value] of Object.entries(data)) {
|
|
685
|
+
if (key.endsWith(COLLECTION_SUFFIX2) && key !== COLLECTION_SUFFIX2 && isCollectionValue(value)) {
|
|
686
|
+
shaped[key.slice(0, -COLLECTION_SUFFIX2.length)] = shapeData(
|
|
687
|
+
value.items
|
|
688
|
+
);
|
|
689
|
+
} else {
|
|
690
|
+
shaped[key] = shapeData(value);
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
return shaped;
|
|
694
|
+
}
|
|
695
|
+
return data;
|
|
696
|
+
}
|
|
697
|
+
function unwrapSingleRoot(data) {
|
|
698
|
+
if (isRecord(data)) {
|
|
699
|
+
const keys = Object.keys(data);
|
|
700
|
+
if (keys.length === 1) {
|
|
701
|
+
return data[keys[0]];
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
return data;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
// src/index.ts
|
|
708
|
+
var DEFAULT_RETRIES = 5;
|
|
709
|
+
var DEFAULT_RETRY_DELAY_MS = 250;
|
|
710
|
+
var DEFAULT_MAX_RETRY_DELAY_MS = 8e3;
|
|
711
|
+
var DEFAULT_SPLIT_BATCH_SIZE = 50;
|
|
712
|
+
function isRecord2(value) {
|
|
713
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
714
|
+
}
|
|
715
|
+
function collectAtPath(data, path) {
|
|
716
|
+
let current = [data];
|
|
717
|
+
for (const segment of path) {
|
|
718
|
+
const next = [];
|
|
719
|
+
for (const value of current) {
|
|
720
|
+
if (isRecord2(value)) {
|
|
721
|
+
const child = value[segment];
|
|
722
|
+
if (Array.isArray(child)) {
|
|
723
|
+
next.push(...child);
|
|
724
|
+
} else if (child !== null && child !== void 0) {
|
|
725
|
+
next.push(child);
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
current = next;
|
|
730
|
+
}
|
|
731
|
+
return current.filter(isRecord2);
|
|
732
|
+
}
|
|
733
|
+
function resolveContext(options) {
|
|
734
|
+
const env = readEnvSettings();
|
|
735
|
+
const space = options.space ?? env.space;
|
|
736
|
+
const environment = options.environment ?? env.environment ?? "master";
|
|
737
|
+
const preview = options.preview ?? false;
|
|
738
|
+
const token = options.token ?? (preview ? env.previewToken : env.token);
|
|
739
|
+
if (!space || !token) {
|
|
740
|
+
const missing = [];
|
|
741
|
+
if (!space) {
|
|
742
|
+
missing.push(
|
|
743
|
+
"space (pass `space` or set CONTENTFUL_SPACE_ID / NEXT_PUBLIC_CONTENTFUL_SPACE_ID)"
|
|
744
|
+
);
|
|
745
|
+
}
|
|
746
|
+
if (!token) {
|
|
747
|
+
missing.push(
|
|
748
|
+
preview ? "preview access token (pass `token` or set CONTENTFUL_PREVIEW_ACCESS_TOKEN / NEXT_PUBLIC_CONTENTFUL_PREVIEW_ACCESS_TOKEN)" : "access token (pass `token` or set CONTENTFUL_ACCESS_TOKEN / NEXT_PUBLIC_CONTENTFUL_ACCESS_TOKEN)"
|
|
749
|
+
);
|
|
750
|
+
}
|
|
751
|
+
throw new FetchContentfulError(
|
|
752
|
+
`Missing required Contentful configuration: ${missing.join("; ")}.`,
|
|
753
|
+
{ code: "CONFIG" }
|
|
754
|
+
);
|
|
755
|
+
}
|
|
756
|
+
const retry = {
|
|
757
|
+
retries: options.retries ?? DEFAULT_RETRIES,
|
|
758
|
+
baseDelayMs: options.retryDelayMs ?? DEFAULT_RETRY_DELAY_MS,
|
|
759
|
+
maxDelayMs: options.maxRetryDelayMs ?? DEFAULT_MAX_RETRY_DELAY_MS
|
|
760
|
+
};
|
|
761
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
762
|
+
const context = {
|
|
763
|
+
space,
|
|
764
|
+
environment,
|
|
765
|
+
token,
|
|
766
|
+
preview,
|
|
767
|
+
locale: options.locale,
|
|
768
|
+
fetch: fetchImpl,
|
|
769
|
+
retry,
|
|
770
|
+
autoSplitNestedCollections: options.autoSplitNestedCollections ?? true,
|
|
771
|
+
splitBatchSize: options.splitBatchSize ?? DEFAULT_SPLIT_BATCH_SIZE
|
|
772
|
+
};
|
|
773
|
+
if (options.signal) context.signal = options.signal;
|
|
774
|
+
if (options.next) context.next = options.next;
|
|
775
|
+
if (options.cache) context.cache = options.cache;
|
|
776
|
+
return context;
|
|
777
|
+
}
|
|
778
|
+
async function resolvePlan(plan, data, variables, context) {
|
|
779
|
+
const parents = collectAtPath(data, plan.path);
|
|
780
|
+
const relevant = parents.filter(
|
|
781
|
+
(parent) => typeof parent[TYPENAME_ALIAS] === "string" && (plan.typeCondition === void 0 || parent[TYPENAME_ALIAS] === plan.typeCondition)
|
|
782
|
+
);
|
|
783
|
+
if (relevant.length === 0) {
|
|
784
|
+
return;
|
|
785
|
+
}
|
|
786
|
+
const byType = /* @__PURE__ */ new Map();
|
|
787
|
+
for (const parent of relevant) {
|
|
788
|
+
const typename = parent[TYPENAME_ALIAS];
|
|
789
|
+
const sys = parent[SYS_ID_ALIAS];
|
|
790
|
+
if (!isRecord2(sys) || typeof sys["id"] !== "string") {
|
|
791
|
+
throw new FetchContentfulError(
|
|
792
|
+
`Cannot split "${plan.responseKey}": a parent entry is missing its sys id.`,
|
|
793
|
+
{ code: "STITCH" }
|
|
794
|
+
);
|
|
795
|
+
}
|
|
796
|
+
const group = byType.get(typename) ?? [];
|
|
797
|
+
group.push(parent);
|
|
798
|
+
byType.set(typename, group);
|
|
799
|
+
}
|
|
800
|
+
const resolved = /* @__PURE__ */ new Map();
|
|
801
|
+
await Promise.all(
|
|
802
|
+
[...byType.entries()].map(async ([typename, group]) => {
|
|
803
|
+
const ids = [
|
|
804
|
+
...new Set(
|
|
805
|
+
group.map((parent) => {
|
|
806
|
+
const sys = parent[SYS_ID_ALIAS];
|
|
807
|
+
return sys.id;
|
|
808
|
+
})
|
|
809
|
+
)
|
|
810
|
+
];
|
|
811
|
+
await Promise.all(
|
|
812
|
+
chunk(ids, context.splitBatchSize).map(async (idBatch) => {
|
|
813
|
+
const { document, rootKey } = buildSubquery(
|
|
814
|
+
plan,
|
|
815
|
+
typename,
|
|
816
|
+
idBatch.length,
|
|
817
|
+
context
|
|
818
|
+
);
|
|
819
|
+
const subData = await executeDocument(
|
|
820
|
+
document,
|
|
821
|
+
{ ...variables, _splitIds: idBatch },
|
|
822
|
+
context
|
|
823
|
+
);
|
|
824
|
+
const collection = subData[rootKey];
|
|
825
|
+
const items = isRecord2(collection) && Array.isArray(collection["items"]) ? collection["items"] : void 0;
|
|
826
|
+
if (!items) {
|
|
827
|
+
throw new FetchContentfulError(
|
|
828
|
+
`Split subquery for "${typename}" returned no "${rootKey}.items". Check that the content type follows Contentful naming conventions.`,
|
|
829
|
+
{ code: "STITCH" }
|
|
830
|
+
);
|
|
831
|
+
}
|
|
832
|
+
for (const item of items) {
|
|
833
|
+
if (isRecord2(item)) {
|
|
834
|
+
const sys = item["sys"];
|
|
835
|
+
if (isRecord2(sys) && typeof sys["id"] === "string") {
|
|
836
|
+
resolved.set(`${typename}:${sys["id"]}`, item[plan.responseKey]);
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
})
|
|
841
|
+
);
|
|
842
|
+
})
|
|
843
|
+
);
|
|
844
|
+
for (const parent of relevant) {
|
|
845
|
+
const typename = parent[TYPENAME_ALIAS];
|
|
846
|
+
const sys = parent[SYS_ID_ALIAS];
|
|
847
|
+
const key = `${typename}:${sys.id}`;
|
|
848
|
+
if (!resolved.has(key)) {
|
|
849
|
+
throw new FetchContentfulError(
|
|
850
|
+
`Split subquery did not return entry "${sys.id}" of type "${typename}" for field "${plan.responseKey}".`,
|
|
851
|
+
{ code: "STITCH" }
|
|
852
|
+
);
|
|
853
|
+
}
|
|
854
|
+
parent[plan.responseKey] = resolved.get(key);
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
function cleanupMarkers(data, plans) {
|
|
858
|
+
for (const plan of plans) {
|
|
859
|
+
for (const parent of collectAtPath(data, plan.path)) {
|
|
860
|
+
delete parent[SYS_ID_ALIAS];
|
|
861
|
+
delete parent[TYPENAME_ALIAS];
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
async function executeDocument(document, variables, context) {
|
|
866
|
+
const { document: outer, plans } = planSplits(document, context);
|
|
867
|
+
const data = await rawRequest(outer, variables, context);
|
|
868
|
+
await Promise.all(
|
|
869
|
+
plans.map((plan) => resolvePlan(plan, data, variables, context))
|
|
870
|
+
);
|
|
871
|
+
cleanupMarkers(data, plans);
|
|
872
|
+
return data;
|
|
873
|
+
}
|
|
874
|
+
function toDocument(query) {
|
|
875
|
+
if (typeof query !== "string") {
|
|
876
|
+
return query;
|
|
877
|
+
}
|
|
878
|
+
try {
|
|
879
|
+
return graphql.parse(query);
|
|
880
|
+
} catch (cause) {
|
|
881
|
+
throw new FetchContentfulError(
|
|
882
|
+
`Failed to parse GraphQL query: ${String(cause)}`,
|
|
883
|
+
{ code: "CONFIG", cause }
|
|
884
|
+
);
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
function withAutoVariables(document, variables, context) {
|
|
888
|
+
const declared = new Set(
|
|
889
|
+
(getOperation(document).variableDefinitions ?? []).map(
|
|
890
|
+
(definition) => definition.variable.name.value
|
|
891
|
+
)
|
|
892
|
+
);
|
|
893
|
+
const merged = { ...variables };
|
|
894
|
+
if (declared.has("preview") && merged["preview"] === void 0) {
|
|
895
|
+
merged["preview"] = context.preview;
|
|
896
|
+
}
|
|
897
|
+
if (declared.has("locale") && merged["locale"] === void 0 && context.locale !== void 0) {
|
|
898
|
+
merged["locale"] = context.locale;
|
|
899
|
+
}
|
|
900
|
+
return merged;
|
|
901
|
+
}
|
|
902
|
+
async function fetchContentful(query, options = {}) {
|
|
903
|
+
const context = resolveContext(options);
|
|
904
|
+
let document = inlineFragments(toDocument(query));
|
|
905
|
+
if (options.autoInjectArgs ?? true) {
|
|
906
|
+
document = injectRootArgs(document, {
|
|
907
|
+
preview: context.preview,
|
|
908
|
+
locale: context.locale
|
|
909
|
+
});
|
|
910
|
+
}
|
|
911
|
+
if (options.validateLocale && context.locale !== void 0) {
|
|
912
|
+
const locales = await getLocales(context);
|
|
913
|
+
if (!locales.some((locale) => locale.code === context.locale)) {
|
|
914
|
+
throw new FetchContentfulError(
|
|
915
|
+
`Locale "${context.locale}" is not configured in space "${context.space}" (available: ${locales.map((locale) => locale.code).join(", ")}).`,
|
|
916
|
+
{ code: "LOCALE" }
|
|
917
|
+
);
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
const variables = withAutoVariables(
|
|
921
|
+
document,
|
|
922
|
+
options.variables ?? {},
|
|
923
|
+
context
|
|
924
|
+
);
|
|
925
|
+
const data = await executeDocument(document, variables, context);
|
|
926
|
+
const result = options.shapeResponseData === false ? data : shapeData(data);
|
|
927
|
+
if (options.unwrapRootField === false) {
|
|
928
|
+
return result;
|
|
929
|
+
}
|
|
930
|
+
return unwrapSingleRoot(result);
|
|
931
|
+
}
|
|
932
|
+
function createFetchContentful(defaults = {}) {
|
|
933
|
+
function bound(query, options = {}) {
|
|
934
|
+
const merged = {
|
|
935
|
+
...defaults,
|
|
936
|
+
...options
|
|
937
|
+
};
|
|
938
|
+
if (merged.shapeResponseData === false) {
|
|
939
|
+
if (merged.unwrapRootField === false) {
|
|
940
|
+
return fetchContentful(query, {
|
|
941
|
+
...merged,
|
|
942
|
+
shapeResponseData: false,
|
|
943
|
+
unwrapRootField: false
|
|
944
|
+
});
|
|
945
|
+
}
|
|
946
|
+
return fetchContentful(query, {
|
|
947
|
+
...merged,
|
|
948
|
+
shapeResponseData: false
|
|
949
|
+
});
|
|
950
|
+
}
|
|
951
|
+
if (merged.unwrapRootField === false) {
|
|
952
|
+
return fetchContentful(query, {
|
|
953
|
+
...merged,
|
|
954
|
+
unwrapRootField: false
|
|
955
|
+
});
|
|
956
|
+
}
|
|
957
|
+
return fetchContentful(query, merged);
|
|
958
|
+
}
|
|
959
|
+
return bound;
|
|
960
|
+
}
|
|
961
|
+
var index_default = fetchContentful;
|
|
962
|
+
|
|
963
|
+
exports.FetchContentfulError = FetchContentfulError;
|
|
964
|
+
exports.clearLocaleCache = clearLocaleCache;
|
|
965
|
+
exports.collectAtPath = collectAtPath;
|
|
966
|
+
exports.createFetchContentful = createFetchContentful;
|
|
967
|
+
exports.default = index_default;
|
|
968
|
+
exports.fetchContentful = fetchContentful;
|
|
969
|
+
exports.getLocales = getLocales;
|
|
970
|
+
exports.injectRootArgs = injectRootArgs;
|
|
971
|
+
exports.inlineFragments = inlineFragments;
|
|
972
|
+
exports.isFetchContentfulError = isFetchContentfulError;
|
|
973
|
+
exports.readEnvSettings = readEnvSettings;
|
|
974
|
+
exports.shapeData = shapeData;
|
|
975
|
+
exports.unwrapSingleRoot = unwrapSingleRoot;
|
|
976
|
+
//# sourceMappingURL=index.cjs.map
|
|
977
|
+
//# sourceMappingURL=index.cjs.map
|