Skip to content

Commit 1952af9

Browse files
authored
feat: add integration for locale based publishing in CDA [TOL-3653] (#2649)
* feat: add integration for locale based publishing in CDA [TOL-3653] * chore: update readme to include new modifier * fix: spread config.headers
1 parent af346f2 commit 1952af9

8 files changed

Lines changed: 556 additions & 16 deletions

README.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -340,12 +340,13 @@ When initialising a client, you will receive an instance of the [`ContentfulClie
340340

341341
#### Entries
342342

343-
| Chain | Modifier |
344-
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
345-
| _none (default)_ | Returns entries in a single locale. Resolvable linked entries will be inlined while unresolvable links will be kept as link objects. [Read more on link resolution](ADVANCED.md#link-resolution) |
346-
| `withAllLocales` | Returns entries in all locales. |
347-
| `withoutLinkResolution` | All linked entries will be rendered as link objects. [Read more on link resolution](ADVANCED.md#link-resolution) |
348-
| `withoutUnresolvableLinks` | If linked entries are not resolvable, the corresponding link objects are removed from the response. |
343+
| Chain | Modifier |
344+
| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
345+
| _none (default)_ | Returns entries in a single locale. Resolvable linked entries will be inlined while unresolvable links will be kept as link objects. [Read more on link resolution](ADVANCED.md#link-resolution) |
346+
| `withAllLocales` | Returns entries in all locales. |
347+
| `withoutLinkResolution` | All linked entries will be rendered as link objects. [Read more on link resolution](ADVANCED.md#link-resolution) |
348+
| `withoutUnresolvableLinks` | If linked entries are not resolvable, the corresponding link objects are removed from the response. |
349+
| `withLocaleBasedPublishing` | Fetched entries & assets will be returned with only content from published locales. |
349350

350351
##### Example
351352

lib/create-contentful-api.ts

Lines changed: 54 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ import validateSearchParameters from './utils/validate-search-parameters.js'
5050
import { getTimelinePreviewParams } from './utils/timeline-preview-helpers.js'
5151
import { normalizeCursorPaginationParameters } from './utils/normalize-cursor-pagination-parameters.js'
5252
import { normalizeCursorPaginationResponse } from './utils/normalize-cursor-pagination-response.js'
53+
import type { AxiosRequestConfig } from 'axios'
5354

5455
const ASSET_KEY_MAX_LIFETIME = 48 * 60 * 60
5556

@@ -230,6 +231,7 @@ export default function createContentfulApi<OptionType extends ChainOptions>(
230231
withAllLocales: false,
231232
withoutLinkResolution: false,
232233
withoutUnresolvableLinks: false,
234+
withLocaleBasedPublishing: false,
233235
},
234236
) {
235237
const { withAllLocales } = options
@@ -280,6 +282,7 @@ export default function createContentfulApi<OptionType extends ChainOptions>(
280282
withAllLocales: false,
281283
withoutLinkResolution: false,
282284
withoutUnresolvableLinks: false,
285+
withLocaleBasedPublishing: false,
283286
},
284287
) {
285288
const { withAllLocales } = options
@@ -318,14 +321,22 @@ export default function createContentfulApi<OptionType extends ChainOptions>(
318321
): Promise<
319322
CollectionForQuery<Entry<EntrySkeleton, ModifiersFromOptions<Options>, Locales>, Query>
320323
> {
321-
const { withoutLinkResolution, withoutUnresolvableLinks } = options
324+
const { withoutLinkResolution, withoutUnresolvableLinks, withLocaleBasedPublishing } = options
322325
try {
326+
const baseConfig = createRequestConfig({
327+
query: prepareQuery(query),
328+
})
329+
const config: AxiosRequestConfig = baseConfig
330+
if (withLocaleBasedPublishing) {
331+
config.headers = {
332+
...config.headers,
333+
'X-Contentful-Locale-Based-Publishing': true,
334+
}
335+
}
323336
const entries = await get({
324337
context: 'environment',
325338
path: maybeEnableTimelinePreview('entries'),
326-
config: createRequestConfig({
327-
query: prepareQuery(query),
328-
}),
339+
config,
329340
})
330341

331342
return resolveCircular(entries, {
@@ -358,6 +369,7 @@ export default function createContentfulApi<OptionType extends ChainOptions>(
358369
withAllLocales: false,
359370
withoutLinkResolution: false,
360371
withoutUnresolvableLinks: false,
372+
withLocaleBasedPublishing: false,
361373
},
362374
) {
363375
const { withAllLocales } = options
@@ -367,18 +379,33 @@ export default function createContentfulApi<OptionType extends ChainOptions>(
367379

368380
const localeSpecificQuery = withAllLocales ? { ...query, locale: '*' } : query
369381

370-
return internalGetAssets<any, Extract<ChainOptions, typeof options>, Query>(localeSpecificQuery)
382+
return internalGetAssets<any, Extract<ChainOptions, typeof options>, Query>(
383+
localeSpecificQuery,
384+
options,
385+
)
371386
}
372387

373388
async function internalGetAsset<Locales extends LocaleCode, Options extends ChainOptions>(
374389
id: string,
375390
query: Record<string, any>,
391+
options: Options,
376392
): Promise<Asset<ModifiersFromOptions<Options>, Locales>> {
393+
const { withLocaleBasedPublishing } = options
377394
try {
395+
const baseConfig = createRequestConfig({
396+
query: prepareQuery(query),
397+
})
398+
const config: AxiosRequestConfig = baseConfig
399+
if (withLocaleBasedPublishing) {
400+
config.headers = {
401+
...config.headers,
402+
'X-Contentful-Locale-Based-Publishing': true,
403+
}
404+
}
378405
return get({
379406
context: 'environment',
380407
path: maybeEnableTimelinePreview(`assets/${id}`),
381-
config: createRequestConfig({ query: prepareQuery(query) }),
408+
config,
382409
})
383410
} catch (error) {
384411
errorHandler(error)
@@ -392,6 +419,7 @@ export default function createContentfulApi<OptionType extends ChainOptions>(
392419
withAllLocales: false,
393420
withoutLinkResolution: false,
394421
withoutUnresolvableLinks: false,
422+
withLocaleBasedPublishing: false,
395423
},
396424
) {
397425
const { withAllLocales } = options
@@ -401,7 +429,11 @@ export default function createContentfulApi<OptionType extends ChainOptions>(
401429

402430
const localeSpecificQuery = withAllLocales ? { ...query, locale: '*' } : query
403431

404-
return internalGetAsset<any, Extract<ChainOptions, typeof options>>(id, localeSpecificQuery)
432+
return internalGetAsset<any, Extract<ChainOptions, typeof options>>(
433+
id,
434+
localeSpecificQuery,
435+
options,
436+
)
405437
}
406438

407439
async function internalGetAssets<
@@ -410,14 +442,24 @@ export default function createContentfulApi<OptionType extends ChainOptions>(
410442
Query extends Record<string, any>,
411443
>(
412444
query: Query,
445+
options: Options,
413446
): Promise<CollectionForQuery<Asset<ModifiersFromOptions<Options>, Locales>, Query>> {
447+
const { withLocaleBasedPublishing } = options
414448
try {
449+
const baseConfig = createRequestConfig({
450+
query: prepareQuery(query),
451+
})
452+
const config: AxiosRequestConfig = baseConfig
453+
if (withLocaleBasedPublishing) {
454+
config.headers = {
455+
...config.headers,
456+
'X-Contentful-Locale-Based-Publishing': true,
457+
}
458+
}
415459
return get({
416460
context: 'environment',
417461
path: maybeEnableTimelinePreview('assets'),
418-
config: createRequestConfig({
419-
query: prepareQuery(query),
420-
}),
462+
config,
421463
})
422464
} catch (error) {
423465
errorHandler(error)
@@ -481,6 +523,7 @@ export default function createContentfulApi<OptionType extends ChainOptions>(
481523
withAllLocales: false,
482524
withoutLinkResolution: false,
483525
withoutUnresolvableLinks: false,
526+
withLocaleBasedPublishing: false,
484527
},
485528
) {
486529
validateResolveLinksParam(query)
@@ -508,6 +551,7 @@ export default function createContentfulApi<OptionType extends ChainOptions>(
508551
withAllLocales: false,
509552
withoutLinkResolution: false,
510553
withoutUnresolvableLinks: false,
554+
withLocaleBasedPublishing: false,
511555
},
512556
) {
513557
return internalParseEntries<EntrySkeleton, any, Extract<ChainOptions, typeof options>>(

lib/make-client.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ function create<OptionsType extends ChainOptions>(
3131
Object.defineProperty(response, 'withoutUnresolvableLinks', {
3232
get: () => makeInnerClient({ ...options, withoutUnresolvableLinks: true }),
3333
})
34+
Object.defineProperty(response, 'withLocaleBasedPublishing', {
35+
get: () => makeInnerClient({ ...options, withLocaleBasedPublishing: true }),
36+
})
3437
return Object.create(response) as ContentfulClientApi<ModifiersFromOptions<OptionsType>>
3538
}
3639

@@ -50,6 +53,7 @@ export const makeClient = ({
5053
withoutLinkResolution: false,
5154
withAllLocales: false,
5255
withoutUnresolvableLinks: false,
56+
withLocaleBasedPublishing: false,
5357
},
5458
)
5559

@@ -60,20 +64,31 @@ export const makeClient = ({
6064
withAllLocales: true,
6165
withoutLinkResolution: false,
6266
withoutUnresolvableLinks: false,
67+
withLocaleBasedPublishing: false,
6368
})
6469
},
6570
get withoutLinkResolution() {
6671
return makeInnerClient<ChainOption<'WITHOUT_LINK_RESOLUTION'>>({
6772
withAllLocales: false,
6873
withoutLinkResolution: true,
6974
withoutUnresolvableLinks: false,
75+
withLocaleBasedPublishing: false,
7076
})
7177
},
7278
get withoutUnresolvableLinks() {
7379
return makeInnerClient<ChainOption<'WITHOUT_UNRESOLVABLE_LINKS'>>({
7480
withAllLocales: false,
7581
withoutLinkResolution: false,
7682
withoutUnresolvableLinks: true,
83+
withLocaleBasedPublishing: false,
84+
})
85+
},
86+
get withLocaleBasedPublishing() {
87+
return makeInnerClient<ChainOption<'WITH_LOCALE_BASED_PUBLISHING'>>({
88+
withAllLocales: false,
89+
withoutLinkResolution: false,
90+
withoutUnresolvableLinks: false,
91+
withLocaleBasedPublishing: true,
7792
})
7893
},
7994
}

lib/types/client.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ export type ChainModifiers =
3636
| 'WITH_ALL_LOCALES'
3737
| 'WITHOUT_LINK_RESOLUTION'
3838
| 'WITHOUT_UNRESOLVABLE_LINKS'
39+
| 'WITH_LOCALE_BASED_PUBLISHING'
3940
| undefined
4041

4142
/**
@@ -581,6 +582,10 @@ export interface ContentfulClientApi<Modifiers extends ChainModifiers> {
581582
? never
582583
: ContentfulClientApi<AddChainModifier<Modifiers, 'WITHOUT_UNRESOLVABLE_LINKS'>>
583584

585+
withLocaleBasedPublishing: 'WITH_LOCALE_BASED_PUBLISHING' extends Modifiers
586+
? never
587+
: ContentfulClientApi<AddChainModifier<Modifiers, 'WITH_LOCALE_BASED_PUBLISHING'>>
588+
584589
/**
585590
* The current Contentful.js version
586591
*/

lib/utils/client-helpers.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ export type ChainOption<Modifiers extends ChainModifiers = ChainModifiers> = {
1616
: 'WITHOUT_UNRESOLVABLE_LINKS' extends Modifiers
1717
? true
1818
: false
19+
withLocaleBasedPublishing: ChainModifiers extends Modifiers
20+
? boolean
21+
: 'WITH_LOCALE_BASED_PUBLISHING' extends Modifiers
22+
? true
23+
: false
1924
}
2025

2126
export type DefaultChainOption = ChainOption<undefined>

test/types/chain-options.test-d.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,40 +8,47 @@ expectAssignable<ChainOptions>({
88
withoutLinkResolution: true as boolean,
99
withAllLocales: true as boolean,
1010
withoutUnresolvableLinks: true as boolean,
11+
withLocaleBasedPublishing: true as boolean,
1112
})
1213

1314
expectType<ChainOption<undefined>>({
1415
withoutLinkResolution: false,
1516
withAllLocales: false,
1617
withoutUnresolvableLinks: false,
18+
withLocaleBasedPublishing: false,
1719
})
1820

1921
expectType<ChainOption<'WITHOUT_UNRESOLVABLE_LINKS'>>({
2022
withoutLinkResolution: false,
2123
withAllLocales: false,
24+
withLocaleBasedPublishing: false,
2225
withoutUnresolvableLinks: true,
2326
})
2427

2528
expectType<ChainOption<'WITHOUT_LINK_RESOLUTION'>>({
2629
withoutLinkResolution: true,
2730
withAllLocales: false,
31+
withLocaleBasedPublishing: false,
2832
withoutUnresolvableLinks: false,
2933
})
3034

3135
expectType<ChainOption<'WITH_ALL_LOCALES'>>({
3236
withoutLinkResolution: false,
3337
withAllLocales: true,
38+
withLocaleBasedPublishing: false,
3439
withoutUnresolvableLinks: false,
3540
})
3641

3742
expectType<ChainOption<'WITH_ALL_LOCALES' | 'WITHOUT_UNRESOLVABLE_LINKS'>>({
3843
withoutLinkResolution: false,
44+
withLocaleBasedPublishing: false,
3945
withAllLocales: true,
4046
withoutUnresolvableLinks: true,
4147
})
4248

4349
expectNotType<ChainOption<'WITH_ALL_LOCALES' | 'WITHOUT_UNRESOLVABLE_LINKS'>>({
4450
withoutLinkResolution: false,
51+
withLocaleBasedPublishing: false,
4552
withAllLocales: true,
4653
withoutUnresolvableLinks: false,
4754
})
@@ -50,4 +57,33 @@ expectType<ChainOption<'WITH_ALL_LOCALES' | 'WITHOUT_LINK_RESOLUTION'>>({
5057
withoutLinkResolution: true,
5158
withAllLocales: true,
5259
withoutUnresolvableLinks: false,
60+
withLocaleBasedPublishing: false,
61+
})
62+
63+
expectType<ChainOption<'WITH_LOCALE_BASED_PUBLISHING'>>({
64+
withoutLinkResolution: false,
65+
withAllLocales: false,
66+
withoutUnresolvableLinks: false,
67+
withLocaleBasedPublishing: true,
68+
})
69+
70+
expectType<ChainOption<'WITH_LOCALE_BASED_PUBLISHING' | 'WITH_ALL_LOCALES'>>({
71+
withoutLinkResolution: false,
72+
withAllLocales: true,
73+
withoutUnresolvableLinks: false,
74+
withLocaleBasedPublishing: true,
75+
})
76+
77+
expectType<ChainOption<'WITH_LOCALE_BASED_PUBLISHING' | 'WITHOUT_LINK_RESOLUTION'>>({
78+
withoutLinkResolution: true,
79+
withAllLocales: false,
80+
withoutUnresolvableLinks: false,
81+
withLocaleBasedPublishing: true,
82+
})
83+
84+
expectType<ChainOption<'WITH_LOCALE_BASED_PUBLISHING' | 'WITHOUT_UNRESOLVABLE_LINKS'>>({
85+
withoutLinkResolution: false,
86+
withAllLocales: false,
87+
withoutUnresolvableLinks: true,
88+
withLocaleBasedPublishing: true,
5389
})

test/types/client/createClient.test-d.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,29 @@ expectType<ContentfulClientApi<'WITH_ALL_LOCALES' | 'WITHOUT_LINK_RESOLUTION'>>(
5555
expectType<ContentfulClientApi<'WITH_ALL_LOCALES' | 'WITHOUT_UNRESOLVABLE_LINKS'>>(
5656
createClient(CLIENT_OPTIONS).withAllLocales.withoutUnresolvableLinks,
5757
)
58+
expectType<ContentfulClientApi<'WITH_LOCALE_BASED_PUBLISHING'>>(
59+
createClient(CLIENT_OPTIONS).withLocaleBasedPublishing,
60+
)
61+
expectType<never>(createClient(CLIENT_OPTIONS).withLocaleBasedPublishing.withLocaleBasedPublishing)
62+
63+
expectType<ContentfulClientApi<'WITH_LOCALE_BASED_PUBLISHING' | 'WITH_ALL_LOCALES'>>(
64+
createClient(CLIENT_OPTIONS).withLocaleBasedPublishing.withAllLocales,
65+
)
66+
67+
expectType<ContentfulClientApi<'WITH_LOCALE_BASED_PUBLISHING' | 'WITHOUT_LINK_RESOLUTION'>>(
68+
createClient(CLIENT_OPTIONS).withLocaleBasedPublishing.withoutLinkResolution,
69+
)
70+
71+
expectType<ContentfulClientApi<'WITH_LOCALE_BASED_PUBLISHING' | 'WITHOUT_UNRESOLVABLE_LINKS'>>(
72+
createClient(CLIENT_OPTIONS).withLocaleBasedPublishing.withoutUnresolvableLinks,
73+
)
74+
75+
expectType<
76+
ContentfulClientApi<
77+
'WITH_LOCALE_BASED_PUBLISHING' | 'WITH_ALL_LOCALES' | 'WITHOUT_LINK_RESOLUTION'
78+
>
79+
>(createClient(CLIENT_OPTIONS).withLocaleBasedPublishing.withAllLocales.withoutLinkResolution)
80+
81+
expectType<ContentfulClientApi<'WITH_ALL_LOCALES' | 'WITH_LOCALE_BASED_PUBLISHING'>>(
82+
createClient(CLIENT_OPTIONS).withAllLocales.withLocaleBasedPublishing,
83+
)

0 commit comments

Comments
 (0)