@financial-times/cp-content-pipeline-schema 2.9.2 → 2.10.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 +13 -0
- package/lib/generated/index.d.ts +87 -2
- package/lib/model/CapiResponse.d.ts +6 -0
- package/lib/model/CapiResponse.js +5 -0
- package/lib/model/CapiResponse.js.map +1 -1
- package/lib/model/FlourishSource.d.ts +22 -0
- package/lib/model/FlourishSource.js +89 -0
- package/lib/model/FlourishSource.js.map +1 -0
- package/lib/model/FlourishSource.test.d.ts +1 -0
- package/lib/model/FlourishSource.test.js +67 -0
- package/lib/model/FlourishSource.test.js.map +1 -0
- package/lib/model/LeadFlourish.d.ts +13 -0
- package/lib/model/LeadFlourish.js +35 -0
- package/lib/model/LeadFlourish.js.map +1 -0
- package/lib/model/LeadFlourish.test.d.ts +1 -0
- package/lib/model/LeadFlourish.test.js +62 -0
- package/lib/model/LeadFlourish.test.js.map +1 -0
- package/lib/model/Topper.d.ts +4 -1
- package/lib/model/Topper.js +15 -0
- package/lib/model/Topper.js.map +1 -1
- package/lib/model/Topper.test.js +21 -0
- package/lib/model/Topper.test.js.map +1 -1
- package/lib/model/schemas/capi/article.d.ts +28 -0
- package/lib/model/schemas/capi/article.js +1 -0
- package/lib/model/schemas/capi/article.js.map +1 -1
- package/lib/model/schemas/capi/base-schema.d.ts +41 -0
- package/lib/model/schemas/capi/base-schema.js +8 -1
- package/lib/model/schemas/capi/base-schema.js.map +1 -1
- package/lib/model/schemas/capi/content-package.d.ts +28 -0
- package/lib/model/schemas/capi/content-package.js +1 -0
- package/lib/model/schemas/capi/content-package.js.map +1 -1
- package/lib/model/schemas/capi/live-blog-package.d.ts +5 -0
- package/lib/model/schemas/capi/placeholder.d.ts +5 -0
- package/lib/resolvers/content-tree/references/Flourish.d.ts +8 -2
- package/lib/resolvers/content-tree/references/Flourish.js +15 -40
- package/lib/resolvers/content-tree/references/Flourish.js.map +1 -1
- package/lib/resolvers/content-tree/references/Flourish.test.js +0 -30
- package/lib/resolvers/content-tree/references/Flourish.test.js.map +1 -1
- package/lib/resolvers/index.d.ts +36 -9
- package/lib/resolvers/index.js +2 -0
- package/lib/resolvers/index.js.map +1 -1
- package/lib/resolvers/leadFlourish.d.ts +16 -0
- package/lib/resolvers/leadFlourish.js +28 -0
- package/lib/resolvers/leadFlourish.js.map +1 -0
- package/lib/resolvers/topper.d.ts +23 -9
- package/lib/resolvers/topper.js +6 -0
- package/lib/resolvers/topper.js.map +1 -1
- package/package.json +1 -1
- package/queries/article.graphql +26 -0
- package/src/generated/index.ts +93 -2
- package/src/model/CapiResponse.ts +6 -0
- package/src/model/FlourishSource.test.ts +93 -0
- package/src/model/FlourishSource.ts +103 -0
- package/src/model/LeadFlourish.test.ts +71 -0
- package/src/model/LeadFlourish.ts +30 -0
- package/src/model/Topper.test.ts +26 -0
- package/src/model/Topper.ts +18 -0
- package/src/model/schemas/capi/article.ts +1 -0
- package/src/model/schemas/capi/base-schema.ts +8 -0
- package/src/model/schemas/capi/content-package.ts +1 -0
- package/src/resolvers/content-tree/references/Flourish.test.ts +2 -49
- package/src/resolvers/content-tree/references/Flourish.ts +15 -59
- package/src/resolvers/index.ts +2 -0
- package/src/resolvers/leadFlourish.ts +31 -0
- package/src/resolvers/topper.ts +10 -0
- package/src/types/internal-content.d.ts +2 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/typedefs/leadFlouish.graphql +29 -0
- package/typedefs/topper.graphql +35 -0
|
@@ -21,6 +21,7 @@ const Topper = z.object({
|
|
|
21
21
|
backgroundBox: z.boolean().optional(),
|
|
22
22
|
textShadow: z.boolean().optional(),
|
|
23
23
|
layout: z.string(),
|
|
24
|
+
layoutWidth: z.string().optional(),
|
|
24
25
|
})
|
|
25
26
|
|
|
26
27
|
const BaseImage = z.object({
|
|
@@ -88,6 +89,12 @@ const AlternativeImage = z.object({
|
|
|
88
89
|
promotionalImage: BaseImage,
|
|
89
90
|
})
|
|
90
91
|
|
|
92
|
+
export const LeadFlourish = z.object({
|
|
93
|
+
id: z.string(),
|
|
94
|
+
type: z.string(),
|
|
95
|
+
description: z.string(),
|
|
96
|
+
})
|
|
97
|
+
|
|
91
98
|
const ClipSource = z.object({
|
|
92
99
|
audioCodec: z.string().optional(),
|
|
93
100
|
binaryUrl: z.string().optional(),
|
|
@@ -261,6 +268,7 @@ export const baseMediaSchema = z.object({
|
|
|
261
268
|
mainImage: MainImage.optional(),
|
|
262
269
|
leadImages: LeadImage.array().optional(),
|
|
263
270
|
alternativeImages: AlternativeImage.optional(),
|
|
271
|
+
leadFlourish: LeadFlourish.optional(),
|
|
264
272
|
embeds: z.array(z.union([ImageSet, ClipSet])).optional(),
|
|
265
273
|
dataSource: DataSource.array().optional(),
|
|
266
274
|
})
|
|
@@ -44,6 +44,7 @@ const contentPackageMetadataSchema = baseMetadataSchema.pick({
|
|
|
44
44
|
const contentPackageMediaSchema = baseMediaSchema.pick({
|
|
45
45
|
mainImage: true,
|
|
46
46
|
leadImages: true,
|
|
47
|
+
leadFlourish: true,
|
|
47
48
|
})
|
|
48
49
|
|
|
49
50
|
export const contentPackageSchema = contentPackageContentSchema
|
|
@@ -42,7 +42,7 @@ describe('Flourish Model', () => {
|
|
|
42
42
|
/https:\/\/public.flourish.studio\/.*\/.*\/thumbnail/
|
|
43
43
|
)
|
|
44
44
|
|
|
45
|
-
expect(decodeURIComponent(fallbackResponse.url)).toMatch(
|
|
45
|
+
expect(decodeURIComponent(fallbackResponse.url as string)).toMatch(
|
|
46
46
|
flourishImageUrlRegex
|
|
47
47
|
)
|
|
48
48
|
})
|
|
@@ -66,7 +66,7 @@ describe('Flourish Model', () => {
|
|
|
66
66
|
/https:\/\/public.flourish.studio\/.*\/example-id/
|
|
67
67
|
)
|
|
68
68
|
|
|
69
|
-
expect(decodeURIComponent(fallbackResponse.url)).toMatch(
|
|
69
|
+
expect(decodeURIComponent(fallbackResponse.url as string)).toMatch(
|
|
70
70
|
flourishImageUrlRegex
|
|
71
71
|
)
|
|
72
72
|
})
|
|
@@ -92,53 +92,6 @@ describe('Flourish Model', () => {
|
|
|
92
92
|
encodeURIComponent(flourishImageUrl)
|
|
93
93
|
)
|
|
94
94
|
})
|
|
95
|
-
describe('the flourish timestamp is present', () => {
|
|
96
|
-
it('The Flourish cache buster is appended to the flourish image url', async () => {
|
|
97
|
-
const reference: ContentTree.Flourish = {
|
|
98
|
-
type: 'flourish',
|
|
99
|
-
id: 'example-id',
|
|
100
|
-
flourishType: 'example-type',
|
|
101
|
-
layoutWidth: 'grid',
|
|
102
|
-
timestamp: '2022-01-06T14:41:01.102Z',
|
|
103
|
-
description: 'Example description',
|
|
104
|
-
}
|
|
105
|
-
const fallbackResponse = await Flourish.fallbackImage(
|
|
106
|
-
{ reference },
|
|
107
|
-
{},
|
|
108
|
-
context
|
|
109
|
-
)
|
|
110
|
-
|
|
111
|
-
const flourishImageCacheBuster =
|
|
112
|
-
'?cacheBuster=2022-01-06T14:41:01.102Z'
|
|
113
|
-
|
|
114
|
-
expect(fallbackResponse.url).toContain(
|
|
115
|
-
encodeURIComponent(flourishImageCacheBuster)
|
|
116
|
-
)
|
|
117
|
-
})
|
|
118
|
-
})
|
|
119
|
-
describe('the flourish timestamp is missing', () => {
|
|
120
|
-
it('The Flourish cache buster is not appended to the flourish image url', async () => {
|
|
121
|
-
const reference: ContentTree.Flourish = {
|
|
122
|
-
type: 'flourish',
|
|
123
|
-
id: 'example-id',
|
|
124
|
-
flourishType: 'example-type',
|
|
125
|
-
layoutWidth: 'grid',
|
|
126
|
-
timestamp: '',
|
|
127
|
-
description: 'Example description',
|
|
128
|
-
}
|
|
129
|
-
const fallbackResponse = await Flourish.fallbackImage(
|
|
130
|
-
{ reference },
|
|
131
|
-
{},
|
|
132
|
-
context
|
|
133
|
-
)
|
|
134
|
-
|
|
135
|
-
const flourishImageCacheBuster = '?cacheBuster='
|
|
136
|
-
|
|
137
|
-
expect(fallbackResponse.url).not.toContain(
|
|
138
|
-
encodeURIComponent(flourishImageCacheBuster)
|
|
139
|
-
)
|
|
140
|
-
})
|
|
141
|
-
})
|
|
142
95
|
})
|
|
143
96
|
})
|
|
144
97
|
})
|
|
@@ -3,37 +3,32 @@ import {
|
|
|
3
3
|
FlourishFallbackResolvers,
|
|
4
4
|
FlourishResolvers,
|
|
5
5
|
} from '../../../generated'
|
|
6
|
-
import {
|
|
7
|
-
import isError from '../../../helpers/isError'
|
|
8
|
-
import { OperationalError } from '@dotcom-reliability-kit/errors'
|
|
6
|
+
import { FlourishSource } from '../../../model/FlourishSource'
|
|
9
7
|
|
|
10
8
|
export const Flourish = {
|
|
11
9
|
async fallbackImage(parent, _args, context) {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
const width = imageMetadata.width
|
|
25
|
-
const height = imageMetadata.height
|
|
10
|
+
if (!parent.reference) {
|
|
11
|
+
return {}
|
|
12
|
+
}
|
|
13
|
+
const flourishData = {
|
|
14
|
+
id: parent.reference.id,
|
|
15
|
+
type: parent.reference.flourishType,
|
|
16
|
+
description: parent.reference.description,
|
|
17
|
+
}
|
|
18
|
+
const flourishSource = new FlourishSource(flourishData, context)
|
|
19
|
+
const width = await flourishSource.width()
|
|
20
|
+
const height = await flourishSource.height()
|
|
26
21
|
|
|
27
22
|
const imageServiceWrappedUrl = imageServiceUrl({
|
|
28
|
-
url: flourishUrl,
|
|
23
|
+
url: flourishSource.flourishUrl(),
|
|
29
24
|
systemCode: context.systemCode ?? 'cp-content-pipeline',
|
|
30
25
|
width,
|
|
31
26
|
})
|
|
32
27
|
|
|
33
28
|
return {
|
|
34
29
|
url: imageServiceWrappedUrl,
|
|
35
|
-
type:
|
|
36
|
-
format:
|
|
30
|
+
type: flourishSource.type(),
|
|
31
|
+
format: flourishSource.format(),
|
|
37
32
|
sourceSet: [],
|
|
38
33
|
width,
|
|
39
34
|
height,
|
|
@@ -56,42 +51,3 @@ export const FlourishFallback = {
|
|
|
56
51
|
return parent.url ?? null
|
|
57
52
|
},
|
|
58
53
|
} satisfies FlourishFallbackResolvers
|
|
59
|
-
|
|
60
|
-
type ImageMetadata = {
|
|
61
|
-
width: number
|
|
62
|
-
height: number
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const getImageMetadata = async (
|
|
66
|
-
context: QueryContext,
|
|
67
|
-
flourishUrl: string
|
|
68
|
-
): Promise<ImageMetadata> => {
|
|
69
|
-
const DEFAULT_WIDTH = 2626
|
|
70
|
-
const DEFAULT_HEIGHT = 1459
|
|
71
|
-
|
|
72
|
-
try {
|
|
73
|
-
const imageMetadata = await context.dataSources.origami.getImageMetadata(
|
|
74
|
-
flourishUrl
|
|
75
|
-
)
|
|
76
|
-
|
|
77
|
-
return {
|
|
78
|
-
width: imageMetadata?.width || DEFAULT_WIDTH,
|
|
79
|
-
height: imageMetadata?.height || DEFAULT_HEIGHT,
|
|
80
|
-
}
|
|
81
|
-
} catch (error) {
|
|
82
|
-
if (isError(error)) {
|
|
83
|
-
context.logger.warn({
|
|
84
|
-
event: 'RECOVERABLE_ERROR',
|
|
85
|
-
error: new OperationalError({
|
|
86
|
-
code: 'FLOURISH_IMAGE_METADATA_ERROR',
|
|
87
|
-
message: `Error getting image dimensions for Flourish fallback image ${flourishUrl}`,
|
|
88
|
-
cause: error,
|
|
89
|
-
}),
|
|
90
|
-
})
|
|
91
|
-
}
|
|
92
|
-
return {
|
|
93
|
-
width: DEFAULT_WIDTH,
|
|
94
|
-
height: DEFAULT_HEIGHT,
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
package/src/resolvers/index.ts
CHANGED
|
@@ -10,6 +10,7 @@ import { default as scalars } from './scalars'
|
|
|
10
10
|
import { default as teaser } from './teaser'
|
|
11
11
|
import { default as topper } from './topper'
|
|
12
12
|
import { default as person } from './person'
|
|
13
|
+
import { default as leadFlourish } from './leadFlourish'
|
|
13
14
|
import { resolvers as references } from './content-tree/references'
|
|
14
15
|
import { Resolvers } from '../generated'
|
|
15
16
|
|
|
@@ -27,6 +28,7 @@ const resolvers = {
|
|
|
27
28
|
...teaser,
|
|
28
29
|
...topper,
|
|
29
30
|
...person,
|
|
31
|
+
...leadFlourish,
|
|
30
32
|
} satisfies Resolvers
|
|
31
33
|
|
|
32
34
|
export default resolvers
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { LeadFlourishResolvers, FlourishSourceResolvers } from '../generated'
|
|
2
|
+
|
|
3
|
+
const resolvers = {
|
|
4
|
+
LeadFlourish: {
|
|
5
|
+
type: (flourish) => flourish.type(),
|
|
6
|
+
id: (flourish) => flourish.id(),
|
|
7
|
+
description: (flourish) => flourish.description(),
|
|
8
|
+
fallbackImage: (flourish) => flourish.fallbackImage(),
|
|
9
|
+
},
|
|
10
|
+
FlourishSource: {
|
|
11
|
+
url: async (parent) => {
|
|
12
|
+
const url = await parent.url()
|
|
13
|
+
return url
|
|
14
|
+
},
|
|
15
|
+
height: async (parent) => {
|
|
16
|
+
const height = await parent.height()
|
|
17
|
+
return height
|
|
18
|
+
},
|
|
19
|
+
width: async (parent) => {
|
|
20
|
+
const width = await parent.width()
|
|
21
|
+
return width
|
|
22
|
+
},
|
|
23
|
+
type: (parent) => parent.type(),
|
|
24
|
+
format: (parent) => parent.format(),
|
|
25
|
+
},
|
|
26
|
+
} satisfies {
|
|
27
|
+
LeadFlourish: LeadFlourishResolvers
|
|
28
|
+
FlourishSource: FlourishSourceResolvers
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export default resolvers
|
package/src/resolvers/topper.ts
CHANGED
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
TopperWithImagesResolvers,
|
|
6
6
|
TopperWithPackageResolvers,
|
|
7
7
|
TopperWithThemeResolvers,
|
|
8
|
+
TopperWithFlourishResolvers,
|
|
8
9
|
PodcastTopperResolvers,
|
|
9
10
|
TopperWithHeadshotResolvers,
|
|
10
11
|
BasicTopperResolvers,
|
|
@@ -101,6 +102,13 @@ const resolvers = {
|
|
|
101
102
|
images: (topper) => topper.images(),
|
|
102
103
|
},
|
|
103
104
|
|
|
105
|
+
TopperWithFlourish: {
|
|
106
|
+
...topperResolvers,
|
|
107
|
+
layout: (topper) => topper.layout(),
|
|
108
|
+
layoutWidth: (topper) => topper.layoutWidth(),
|
|
109
|
+
leadFlourish: (topper) => topper.leadFlourish(),
|
|
110
|
+
},
|
|
111
|
+
|
|
104
112
|
FullBleedTopper: {
|
|
105
113
|
...topperResolvers,
|
|
106
114
|
brandConcept: (topper) => topper.brandConcept(),
|
|
@@ -119,10 +127,12 @@ const resolvers = {
|
|
|
119
127
|
fallbackImage: (topper) => topper.fallbackImage(),
|
|
120
128
|
images: (topper) => topper.images(),
|
|
121
129
|
},
|
|
130
|
+
|
|
122
131
|
} satisfies {
|
|
123
132
|
Topper: TopperResolvers
|
|
124
133
|
TopperWithImages: TopperWithImagesResolvers
|
|
125
134
|
TopperWithTheme: TopperWithThemeResolvers
|
|
135
|
+
TopperWithFlourish: TopperWithFlourishResolvers
|
|
126
136
|
TopperWithBrand: TopperWithBrandResolvers
|
|
127
137
|
TopperWithHeadshot: TopperWithHeadshotResolvers
|
|
128
138
|
TopperWithPackage: TopperWithPackageResolvers
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
ClipSet,
|
|
12
12
|
MainImage,
|
|
13
13
|
LeadImage,
|
|
14
|
+
LeadFlourish,
|
|
14
15
|
capiNotificationResponse,
|
|
15
16
|
} from '../model/schemas/capi/base-schema'
|
|
16
17
|
|
|
@@ -40,6 +41,7 @@ type Annotation = z.infer<typeof Annotation>
|
|
|
40
41
|
type Image = z.infer<typeof Image>
|
|
41
42
|
type LeadImage = z.infer<typeof LeadImage>
|
|
42
43
|
type ImageSet = z.infer<typeof ImageSet>
|
|
44
|
+
type LeadFlourish = z.infer<typeof LeadFlourish>
|
|
43
45
|
type MainImage = z.infer<typeof MainImage>
|
|
44
46
|
type Clip = z.infer<typeof Clip>
|
|
45
47
|
type ClipSet = z.infer<typeof ClipSet>
|