@financial-times/cp-content-pipeline-schema 1.4.2 → 1.4.4

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.
Files changed (52) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/lib/generated/index.d.ts +47 -20
  3. package/lib/model/CapiResponse.d.ts +5 -5
  4. package/lib/model/CapiResponse.js +29 -11
  5. package/lib/model/CapiResponse.js.map +1 -1
  6. package/lib/model/schemas/capi/article.d.ts +3 -0
  7. package/lib/model/schemas/capi/article.js +1 -0
  8. package/lib/model/schemas/capi/article.js.map +1 -1
  9. package/lib/model/schemas/capi/audio.d.ts +3 -0
  10. package/lib/model/schemas/capi/audio.js +1 -0
  11. package/lib/model/schemas/capi/audio.js.map +1 -1
  12. package/lib/model/schemas/capi/base-schema.d.ts +3 -0
  13. package/lib/model/schemas/capi/base-schema.js +5 -0
  14. package/lib/model/schemas/capi/base-schema.js.map +1 -1
  15. package/lib/model/schemas/capi/content-package.d.ts +3 -0
  16. package/lib/model/schemas/capi/content-package.js +1 -0
  17. package/lib/model/schemas/capi/content-package.js.map +1 -1
  18. package/lib/model/schemas/capi/live-blog-package.d.ts +3 -0
  19. package/lib/model/schemas/capi/live-blog-package.js +1 -0
  20. package/lib/model/schemas/capi/live-blog-package.js.map +1 -1
  21. package/lib/model/schemas/capi/placeholder.d.ts +3 -0
  22. package/lib/model/schemas/capi/placeholder.js +1 -0
  23. package/lib/model/schemas/capi/placeholder.js.map +1 -1
  24. package/lib/resolvers/content.d.ts +1 -0
  25. package/lib/resolvers/content.js +1 -0
  26. package/lib/resolvers/content.js.map +1 -1
  27. package/lib/resolvers/index.d.ts +14 -12
  28. package/lib/resolvers/index.js +3 -1
  29. package/lib/resolvers/index.js.map +1 -1
  30. package/lib/resolvers/meta-link.d.ts +5 -0
  31. package/lib/resolvers/meta-link.js +15 -0
  32. package/lib/resolvers/meta-link.js.map +1 -0
  33. package/lib/resolvers/teaser.d.ts +3 -3
  34. package/lib/resolvers/teaser.js +6 -4
  35. package/lib/resolvers/teaser.js.map +1 -1
  36. package/package.json +1 -1
  37. package/src/generated/index.ts +49 -20
  38. package/src/model/CapiResponse.ts +35 -17
  39. package/src/model/schemas/capi/article.ts +1 -0
  40. package/src/model/schemas/capi/audio.ts +1 -0
  41. package/src/model/schemas/capi/base-schema.ts +5 -0
  42. package/src/model/schemas/capi/content-package.ts +1 -0
  43. package/src/model/schemas/capi/live-blog-package.ts +1 -0
  44. package/src/model/schemas/capi/placeholder.ts +1 -0
  45. package/src/resolvers/content.ts +1 -0
  46. package/src/resolvers/index.ts +3 -1
  47. package/src/resolvers/meta-link.ts +16 -0
  48. package/src/resolvers/teaser.ts +6 -4
  49. package/src/types/n-display-metadata.d.ts +15 -8
  50. package/tsconfig.tsbuildinfo +1 -1
  51. package/typedefs/content.graphql +16 -10
  52. package/typedefs/teaser.graphql +4 -2
@@ -1,13 +1,11 @@
1
1
  import type {
2
2
  ImageSet,
3
- Annotation,
4
3
  ContentTypeSchemas,
5
4
  MainImage,
6
5
  } from '../types/internal-content'
7
6
  import conceptIds from '@financial-times/n-concept-ids'
8
- import metadata, { TeaserMetadata } from '@financial-times/n-display-metadata'
7
+ import metadata from '@financial-times/n-display-metadata'
9
8
  import cloneDeep from 'clone-deep'
10
- import { ConditionalKeys } from 'type-fest'
11
9
  import { OperationalError } from '@dotcom-reliability-kit/errors'
12
10
 
13
11
  import type { QueryContext } from '..'
@@ -241,6 +239,15 @@ export class CapiResponse {
241
239
  canBeSyndicated(): LiteralUnionScalarValues<typeof CanBeSyndicated> {
242
240
  return this.capiData.canBeSyndicated
243
241
  }
242
+ originatingParty(): string | null {
243
+ return this.capiData.canBeDistributed === 'no' &&
244
+ this.annotations().some((annotation) => {
245
+ annotation.id() ===
246
+ 'http://api.ft.com/things/ed3b6ec5-6466-47ef-b1d8-16952fd522c7'
247
+ })
248
+ ? 'Reuters'
249
+ : 'FT'
250
+ }
244
251
  summary() {
245
252
  if ('summary' in this.capiData) return this.capiData.summary
246
253
  return null
@@ -309,26 +316,37 @@ export class CapiResponse {
309
316
  })
310
317
  }
311
318
 
312
- async teaserMetadataLink(
313
- field: ConditionalKeys<TeaserMetadata, Annotation | null>
314
- ) {
319
+ async metaLink() {
315
320
  const meta = await this.#teaserMetadata()
316
- const metaField = meta[field]
317
321
 
318
- return metaField ? new Concept(metaField, this.context) : null
322
+ if (!meta.link) {
323
+ return meta.link
324
+ }
325
+
326
+ // TODO:KB:20231017 rewrite n-display-metadata in typescript using our types (lol. lmao)
327
+ // if meta.link has a predicate field, it's a concept, so wrap it in our concept model
328
+ if ('predicate' in meta.link) {
329
+ return new Concept(meta.link, this.context)
330
+ }
331
+
332
+ // otherwise, it's the package container, so return that directly as we already have it
333
+ return this.containedIn()
319
334
  }
320
335
 
321
- async teaserMetadataText(
322
- field: ConditionalKeys<TeaserMetadata, string> | 'suffixText'
323
- ) {
324
- if (field === 'prefixText') {
325
- const meta = await this.#teaserMetadata()
326
- return meta[field]
327
- } else {
328
- // HACK 20230629 IM: suffixText doesn't actually exist in the metadata
329
- // type lol but deleting the field would be a breaking change
336
+ async metaAltLink() {
337
+ const meta = await this.#teaserMetadata()
338
+
339
+ if (!meta.altLink) {
330
340
  return null
331
341
  }
342
+
343
+ // unlike meta.link, meta.altLink alwyas returns a Concept
344
+ return new Concept(meta.altLink, this.context)
345
+ }
346
+
347
+ async metaPrefixText() {
348
+ const meta = await this.#teaserMetadata()
349
+ return meta.prefixText
332
350
  }
333
351
 
334
352
  teaser() {
@@ -25,6 +25,7 @@ const articleMetadataSchema = baseMetadataSchema.pick({
25
25
  firstPublishedDate: true,
26
26
  accessLevel: true,
27
27
  canBeSyndicated: true,
28
+ canBeDistributed: true,
28
29
  topper: true,
29
30
  comments: true,
30
31
  containedIn: true,
@@ -20,6 +20,7 @@ const audioMetadataSchema = baseMetadataSchema.pick({
20
20
  firstPublishedDate: true,
21
21
  accessLevel: true,
22
22
  canBeSyndicated: true,
23
+ canBeDistributed: true,
23
24
  })
24
25
 
25
26
  const audioMediaSchema = baseMediaSchema.pick({
@@ -154,6 +154,11 @@ export const baseMetadataSchema = z.object({
154
154
  z.literal('withContributorPayment'),
155
155
  z.literal('unknown'),
156
156
  ]),
157
+ canBeDistributed: z.union([
158
+ z.literal('yes'),
159
+ z.literal('no'),
160
+ z.literal('verify'),
161
+ ]),
157
162
  topper: Topper.optional(),
158
163
  comments: z
159
164
  .object({
@@ -34,6 +34,7 @@ const contentPackageMetadataSchema = baseMetadataSchema.pick({
34
34
  firstPublishedDate: true,
35
35
  accessLevel: true,
36
36
  canBeSyndicated: true,
37
+ canBeDistributed: true,
37
38
  topper: true,
38
39
  comments: true,
39
40
  })
@@ -26,6 +26,7 @@ const liveBlogPackageMetadataSchema = baseMetadataSchema.pick({
26
26
  firstPublishedDate: true,
27
27
  accessLevel: true,
28
28
  canBeSyndicated: true,
29
+ canBeDistributed: true,
29
30
  topper: true,
30
31
  comments: true,
31
32
  })
@@ -25,6 +25,7 @@ const placeholderMetadataSchema = baseMetadataSchema.pick({
25
25
  firstPublishedDate: true,
26
26
  accessLevel: true,
27
27
  canBeSyndicated: true,
28
+ canBeDistributed: true,
28
29
  topper: true,
29
30
  comments: true,
30
31
  containedIn: true,
@@ -55,6 +55,7 @@ const resolvers = {
55
55
  annotations: (parent) => parent.annotations(),
56
56
  accessLevel: (parent) => parent.accessLevel(),
57
57
  canBeSyndicated: (parent) => parent.canBeSyndicated(),
58
+ originatingParty: (parent) => parent.originatingParty(),
58
59
  commentsEnabled: (parent) => parent.commentsEnabled(),
59
60
  design: (parent) => parent.design(),
60
61
  },
@@ -2,6 +2,7 @@ import { default as concept } from './concept'
2
2
  import { default as content } from './content'
3
3
  import { default as core } from './core'
4
4
  import { default as image } from './image'
5
+ import { default as metaLink } from './meta-link'
5
6
  import { default as picture } from './picture'
6
7
  import { default as richText } from './richText'
7
8
  import { default as scalars } from './scalars'
@@ -15,12 +16,13 @@ const resolvers = {
15
16
  ...content,
16
17
  ...core,
17
18
  ...image,
19
+ ...metaLink,
18
20
  ...picture,
21
+ ...references,
19
22
  ...richText,
20
23
  ...scalars,
21
24
  ...teaser,
22
25
  ...topper,
23
- ...references,
24
26
  } satisfies Resolvers
25
27
 
26
28
  export default resolvers
@@ -0,0 +1,16 @@
1
+ import { MetaLinkResolvers } from '../generated'
2
+ import { Concept } from '../model/Concept'
3
+
4
+ const resolvers: { MetaLink: MetaLinkResolvers } = {
5
+ MetaLink: {
6
+ __resolveType(parent) {
7
+ if (parent instanceof Concept) {
8
+ return 'Concept'
9
+ }
10
+
11
+ return 'ContentPackage'
12
+ },
13
+ },
14
+ }
15
+
16
+ export default resolvers
@@ -9,10 +9,12 @@ const resolvers = {
9
9
  .type()
10
10
  .replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`)
11
11
  .slice(1),
12
- metaLink: (parent) => parent.teaserMetadataLink('link'),
13
- metaAltLink: (parent) => parent.teaserMetadataLink('altLink'),
14
- metaPrefixText: (parent) => parent.teaserMetadataText('prefixText'),
15
- metaSuffixText: (parent) => parent.teaserMetadataText('suffixText'),
12
+ metaLink: (parent) => parent.metaLink(),
13
+ metaAltLink: (parent) => parent.metaAltLink(),
14
+ metaPrefixText: (parent) => parent.metaPrefixText(),
15
+ // HACK 20230629 IM: suffixText doesn't actually exist in the metadata
16
+ // type lol but deleting the field would be a breaking change
17
+ metaSuffixText: () => null,
16
18
  image: (parent) => parent.teaserImage(),
17
19
  indicators(parent) {
18
20
  return {
@@ -1,22 +1,29 @@
1
1
  declare module '@financial-times/n-display-metadata' {
2
- import { Annotation, ContentTypeSchemas } from './internal-content'
2
+ export interface MetaLink {
3
+ id?: string
4
+ url?: string
5
+ relativeUrl?: string
6
+ prefLabel?: string
7
+ }
3
8
 
4
9
  export interface FlagsMetadata {
5
10
  isOpinion: boolean
6
11
  isColumn: boolean
7
12
  }
8
13
 
9
- export interface TeaserMetadata {
14
+ export interface TeaserMetadata<ConceptType, ContainedInType> {
10
15
  flags: FlagsMetadata
11
16
  prefixText: string
12
- link: Annotation | null
13
- altLink: Annotation | null
17
+ link: ConceptType | ContainedInType | null
18
+ altLink: ConceptType | null
14
19
  }
15
20
 
16
- export interface Content {
17
- annotations: Annotation[]
18
- containedIn: ContentTypeSchemas | null
21
+ export interface Content<ConceptType, ContainedInType> {
22
+ annotations: ConceptType[]
23
+ containedIn: ContainedInType[] | null
19
24
  }
20
25
 
21
- export function teaser(content: Content): TeaserMetadata
26
+ export function teaser<ConceptType, ContainedInType>(
27
+ content: Content<ConceptType, ContainedInType>
28
+ ): TeaserMetadata<ConceptType, ContainedInType>
22
29
  }