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

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.
@@ -58,7 +58,7 @@ export type Article = Content & {
58
58
  readonly containedIn?: Maybe<Content>;
59
59
  readonly design?: Maybe<Design>;
60
60
  readonly firstPublishedDate: Scalars['String']['output'];
61
- readonly id: Scalars['String']['output'];
61
+ readonly id: Scalars['ID']['output'];
62
62
  readonly mainImage?: Maybe<Image>;
63
63
  readonly publishedDate: Scalars['String']['output'];
64
64
  readonly standfirst?: Maybe<Scalars['String']['output']>;
@@ -92,7 +92,7 @@ export type Audio = Content & {
92
92
  readonly commentsEnabled?: Maybe<Scalars['Boolean']['output']>;
93
93
  readonly design?: Maybe<Design>;
94
94
  readonly firstPublishedDate: Scalars['String']['output'];
95
- readonly id: Scalars['String']['output'];
95
+ readonly id: Scalars['ID']['output'];
96
96
  readonly mainImage?: Maybe<Image>;
97
97
  readonly media?: Maybe<ReadonlyArray<Maybe<Media>>>;
98
98
  readonly publishedDate: Scalars['String']['output'];
@@ -170,7 +170,7 @@ export type Content = {
170
170
  readonly commentsEnabled?: Maybe<Scalars['Boolean']['output']>;
171
171
  readonly design?: Maybe<Design>;
172
172
  readonly firstPublishedDate: Scalars['String']['output'];
173
- readonly id: Scalars['String']['output'];
173
+ readonly id: Scalars['ID']['output'];
174
174
  readonly mainImage?: Maybe<Image>;
175
175
  readonly publishedDate: Scalars['String']['output'];
176
176
  readonly standfirst?: Maybe<Scalars['String']['output']>;
@@ -206,7 +206,7 @@ export type ContentPackage = Content & {
206
206
  readonly containsLength?: Maybe<Scalars['Int']['output']>;
207
207
  readonly design?: Maybe<Design>;
208
208
  readonly firstPublishedDate: Scalars['String']['output'];
209
- readonly id: Scalars['String']['output'];
209
+ readonly id: Scalars['ID']['output'];
210
210
  readonly mainImage?: Maybe<Image>;
211
211
  readonly publishedDate: Scalars['String']['output'];
212
212
  readonly standfirst?: Maybe<Scalars['String']['output']>;
@@ -527,7 +527,7 @@ export type LiveBlogPackage = Content & {
527
527
  readonly commentsEnabled?: Maybe<Scalars['Boolean']['output']>;
528
528
  readonly design?: Maybe<Design>;
529
529
  readonly firstPublishedDate: Scalars['String']['output'];
530
- readonly id: Scalars['String']['output'];
530
+ readonly id: Scalars['ID']['output'];
531
531
  readonly liveBlogPosts?: Maybe<ReadonlyArray<Maybe<Content>>>;
532
532
  readonly mainImage?: Maybe<Image>;
533
533
  readonly pinnedPost?: Maybe<Content>;
@@ -565,7 +565,7 @@ export type LiveBlogPost = Content & {
565
565
  readonly containedIn?: Maybe<Content>;
566
566
  readonly design?: Maybe<Design>;
567
567
  readonly firstPublishedDate: Scalars['String']['output'];
568
- readonly id: Scalars['String']['output'];
568
+ readonly id: Scalars['ID']['output'];
569
569
  readonly mainImage?: Maybe<Image>;
570
570
  readonly publishedDate: Scalars['String']['output'];
571
571
  readonly standfirst?: Maybe<Scalars['String']['output']>;
@@ -599,6 +599,8 @@ export type Media = {
599
599
  readonly url?: Maybe<Scalars['String']['output']>;
600
600
  };
601
601
 
602
+ export type MetaLink = Concept | ContentPackage;
603
+
602
604
  export type Mutation = {
603
605
  readonly invalidateRedisCache?: Maybe<Scalars['String']['output']>;
604
606
  };
@@ -682,7 +684,7 @@ export type Placeholder = Content & {
682
684
  readonly containedIn?: Maybe<Content>;
683
685
  readonly design?: Maybe<Design>;
684
686
  readonly firstPublishedDate: Scalars['String']['output'];
685
- readonly id: Scalars['String']['output'];
687
+ readonly id: Scalars['ID']['output'];
686
688
  readonly mainImage?: Maybe<Image>;
687
689
  readonly publishedDate: Scalars['String']['output'];
688
690
  readonly standfirst?: Maybe<Scalars['String']['output']>;
@@ -800,8 +802,8 @@ export type Teaser = {
800
802
  readonly id?: Maybe<Scalars['String']['output']>;
801
803
  readonly image?: Maybe<Image>;
802
804
  readonly indicators?: Maybe<Indicators>;
803
- readonly metaAltLink?: Maybe<Concept>;
804
- readonly metaLink?: Maybe<Concept>;
805
+ readonly metaAltLink?: Maybe<MetaLink>;
806
+ readonly metaLink?: Maybe<MetaLink>;
805
807
  readonly metaPrefixText?: Maybe<Scalars['String']['output']>;
806
808
  readonly metaSuffixText?: Maybe<Scalars['String']['output']>;
807
809
  readonly publishedDate?: Maybe<Scalars['String']['output']>;
@@ -874,7 +876,7 @@ export type Video = Content & {
874
876
  readonly commentsEnabled?: Maybe<Scalars['Boolean']['output']>;
875
877
  readonly design?: Maybe<Design>;
876
878
  readonly firstPublishedDate: Scalars['String']['output'];
877
- readonly id: Scalars['String']['output'];
879
+ readonly id: Scalars['ID']['output'];
878
880
  readonly mainImage?: Maybe<Image>;
879
881
  readonly publishedDate: Scalars['String']['output'];
880
882
  readonly standfirst?: Maybe<Scalars['String']['output']>;
@@ -970,6 +972,10 @@ export type DirectiveResolverFn<TResult = {}, TParent = {}, TContext = {}, TArgs
970
972
  info: GraphQLResolveInfo
971
973
  ) => TResult | Promise<TResult>;
972
974
 
975
+ /** Mapping of union types */
976
+ export type ResolversUnionTypes<RefType extends Record<string, unknown>> = ResolversObject<{
977
+ MetaLink: ( ConceptModel ) | ( CapiResponse );
978
+ }>;
973
979
 
974
980
  /** Mapping of interface types */
975
981
  export type ResolversInterfaceTypes<RefType extends Record<string, unknown>> = ResolversObject<{
@@ -1030,6 +1036,7 @@ export type ResolversTypes = ResolversObject<{
1030
1036
  LiveBlogPost: ResolverTypeWrapper<CapiResponse>;
1031
1037
  MainImage: ResolverTypeWrapper<ReferenceWithCAPIData<ContentTree.ImageSet>>;
1032
1038
  Media: ResolverTypeWrapper<Media>;
1039
+ MetaLink: ResolverTypeWrapper<ResolversUnionTypes<ResolversTypes>['MetaLink']>;
1033
1040
  Mutation: ResolverTypeWrapper<{}>;
1034
1041
  OpinionTopper: ResolverTypeWrapper<TopperModel>;
1035
1042
  PackageDesign: ResolverTypeWrapper<Scalars['PackageDesign']['output']>;
@@ -1108,6 +1115,7 @@ export type ResolversParentTypes = ResolversObject<{
1108
1115
  LiveBlogPost: CapiResponse;
1109
1116
  MainImage: ReferenceWithCAPIData<ContentTree.ImageSet>;
1110
1117
  Media: Media;
1118
+ MetaLink: ResolversUnionTypes<ResolversParentTypes>['MetaLink'];
1111
1119
  Mutation: {};
1112
1120
  OpinionTopper: TopperModel;
1113
1121
  PackageDesign: Scalars['PackageDesign']['output'];
@@ -1168,7 +1176,7 @@ export type ArticleResolvers<ContextType = QueryContext, ParentType extends Reso
1168
1176
  containedIn?: Resolver<Maybe<ResolversTypes['Content']>, ParentType, ContextType>;
1169
1177
  design?: Resolver<Maybe<ResolversTypes['Design']>, ParentType, ContextType>;
1170
1178
  firstPublishedDate?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
1171
- id?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
1179
+ id?: Resolver<ResolversTypes['ID'], ParentType, ContextType>;
1172
1180
  mainImage?: Resolver<Maybe<ResolversTypes['Image']>, ParentType, ContextType>;
1173
1181
  publishedDate?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
1174
1182
  standfirst?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
@@ -1192,7 +1200,7 @@ export type AudioResolvers<ContextType = QueryContext, ParentType extends Resolv
1192
1200
  commentsEnabled?: Resolver<Maybe<ResolversTypes['Boolean']>, ParentType, ContextType>;
1193
1201
  design?: Resolver<Maybe<ResolversTypes['Design']>, ParentType, ContextType>;
1194
1202
  firstPublishedDate?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
1195
- id?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
1203
+ id?: Resolver<ResolversTypes['ID'], ParentType, ContextType>;
1196
1204
  mainImage?: Resolver<Maybe<ResolversTypes['Image']>, ParentType, ContextType>;
1197
1205
  media?: Resolver<Maybe<ReadonlyArray<Maybe<ResolversTypes['Media']>>>, ParentType, ContextType>;
1198
1206
  publishedDate?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
@@ -1262,7 +1270,7 @@ export type ContentResolvers<ContextType = QueryContext, ParentType extends Reso
1262
1270
  commentsEnabled?: Resolver<Maybe<ResolversTypes['Boolean']>, ParentType, ContextType>;
1263
1271
  design?: Resolver<Maybe<ResolversTypes['Design']>, ParentType, ContextType>;
1264
1272
  firstPublishedDate?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
1265
- id?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
1273
+ id?: Resolver<ResolversTypes['ID'], ParentType, ContextType>;
1266
1274
  mainImage?: Resolver<Maybe<ResolversTypes['Image']>, ParentType, ContextType>;
1267
1275
  publishedDate?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
1268
1276
  standfirst?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
@@ -1287,7 +1295,7 @@ export type ContentPackageResolvers<ContextType = QueryContext, ParentType exten
1287
1295
  containsLength?: Resolver<Maybe<ResolversTypes['Int']>, ParentType, ContextType>;
1288
1296
  design?: Resolver<Maybe<ResolversTypes['Design']>, ParentType, ContextType>;
1289
1297
  firstPublishedDate?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
1290
- id?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
1298
+ id?: Resolver<ResolversTypes['ID'], ParentType, ContextType>;
1291
1299
  mainImage?: Resolver<Maybe<ResolversTypes['Image']>, ParentType, ContextType>;
1292
1300
  publishedDate?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
1293
1301
  standfirst?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
@@ -1572,7 +1580,7 @@ export type LiveBlogPackageResolvers<ContextType = QueryContext, ParentType exte
1572
1580
  commentsEnabled?: Resolver<Maybe<ResolversTypes['Boolean']>, ParentType, ContextType>;
1573
1581
  design?: Resolver<Maybe<ResolversTypes['Design']>, ParentType, ContextType>;
1574
1582
  firstPublishedDate?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
1575
- id?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
1583
+ id?: Resolver<ResolversTypes['ID'], ParentType, ContextType>;
1576
1584
  liveBlogPosts?: Resolver<Maybe<ReadonlyArray<Maybe<ResolversTypes['Content']>>>, ParentType, ContextType>;
1577
1585
  mainImage?: Resolver<Maybe<ResolversTypes['Image']>, ParentType, ContextType>;
1578
1586
  pinnedPost?: Resolver<Maybe<ResolversTypes['Content']>, ParentType, ContextType>;
@@ -1600,7 +1608,7 @@ export type LiveBlogPostResolvers<ContextType = QueryContext, ParentType extends
1600
1608
  containedIn?: Resolver<Maybe<ResolversTypes['Content']>, ParentType, ContextType>;
1601
1609
  design?: Resolver<Maybe<ResolversTypes['Design']>, ParentType, ContextType>;
1602
1610
  firstPublishedDate?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
1603
- id?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
1611
+ id?: Resolver<ResolversTypes['ID'], ParentType, ContextType>;
1604
1612
  mainImage?: Resolver<Maybe<ResolversTypes['Image']>, ParentType, ContextType>;
1605
1613
  publishedDate?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
1606
1614
  standfirst?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
@@ -1626,6 +1634,10 @@ export type MediaResolvers<ContextType = QueryContext, ParentType extends Resolv
1626
1634
  __isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
1627
1635
  }>;
1628
1636
 
1637
+ export type MetaLinkResolvers<ContextType = QueryContext, ParentType extends ResolversParentTypes['MetaLink'] = ResolversParentTypes['MetaLink']> = ResolversObject<{
1638
+ __resolveType?: TypeResolveFn<'Concept' | 'ContentPackage', ParentType, ContextType>;
1639
+ }>;
1640
+
1629
1641
  export type MutationResolvers<ContextType = QueryContext, ParentType extends ResolversParentTypes['Mutation'] = ResolversParentTypes['Mutation']> = ResolversObject<{
1630
1642
  invalidateRedisCache?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType, RequireFields<MutationInvalidateRedisCacheArgs, 'uuid'>>;
1631
1643
  }>;
@@ -1707,7 +1719,7 @@ export type PlaceholderResolvers<ContextType = QueryContext, ParentType extends
1707
1719
  containedIn?: Resolver<Maybe<ResolversTypes['Content']>, ParentType, ContextType>;
1708
1720
  design?: Resolver<Maybe<ResolversTypes['Design']>, ParentType, ContextType>;
1709
1721
  firstPublishedDate?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
1710
- id?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
1722
+ id?: Resolver<ResolversTypes['ID'], ParentType, ContextType>;
1711
1723
  mainImage?: Resolver<Maybe<ResolversTypes['Image']>, ParentType, ContextType>;
1712
1724
  publishedDate?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
1713
1725
  standfirst?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
@@ -1812,8 +1824,8 @@ export type TeaserResolvers<ContextType = QueryContext, ParentType extends Resol
1812
1824
  id?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
1813
1825
  image?: Resolver<Maybe<ResolversTypes['Image']>, ParentType, ContextType>;
1814
1826
  indicators?: Resolver<Maybe<ResolversTypes['Indicators']>, ParentType, ContextType>;
1815
- metaAltLink?: Resolver<Maybe<ResolversTypes['Concept']>, ParentType, ContextType>;
1816
- metaLink?: Resolver<Maybe<ResolversTypes['Concept']>, ParentType, ContextType>;
1827
+ metaAltLink?: Resolver<Maybe<ResolversTypes['MetaLink']>, ParentType, ContextType>;
1828
+ metaLink?: Resolver<Maybe<ResolversTypes['MetaLink']>, ParentType, ContextType>;
1817
1829
  metaPrefixText?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
1818
1830
  metaSuffixText?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
1819
1831
  publishedDate?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
@@ -1887,7 +1899,7 @@ export type VideoResolvers<ContextType = QueryContext, ParentType extends Resolv
1887
1899
  commentsEnabled?: Resolver<Maybe<ResolversTypes['Boolean']>, ParentType, ContextType>;
1888
1900
  design?: Resolver<Maybe<ResolversTypes['Design']>, ParentType, ContextType>;
1889
1901
  firstPublishedDate?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
1890
- id?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
1902
+ id?: Resolver<ResolversTypes['ID'], ParentType, ContextType>;
1891
1903
  mainImage?: Resolver<Maybe<ResolversTypes['Image']>, ParentType, ContextType>;
1892
1904
  publishedDate?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
1893
1905
  standfirst?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
@@ -1947,6 +1959,7 @@ export type Resolvers<ContextType = QueryContext> = ResolversObject<{
1947
1959
  LiveBlogPost?: LiveBlogPostResolvers<ContextType>;
1948
1960
  MainImage?: MainImageResolvers<ContextType>;
1949
1961
  Media?: MediaResolvers<ContextType>;
1962
+ MetaLink?: MetaLinkResolvers<ContextType>;
1950
1963
  Mutation?: MutationResolvers<ContextType>;
1951
1964
  OpinionTopper?: OpinionTopperResolvers<ContextType>;
1952
1965
  PackageDesign?: GraphQLScalarType;
@@ -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 '..'
@@ -309,26 +307,37 @@ export class CapiResponse {
309
307
  })
310
308
  }
311
309
 
312
- async teaserMetadataLink(
313
- field: ConditionalKeys<TeaserMetadata, Annotation | null>
314
- ) {
310
+ async metaLink() {
315
311
  const meta = await this.#teaserMetadata()
316
- const metaField = meta[field]
317
312
 
318
- return metaField ? new Concept(metaField, this.context) : null
313
+ if (!meta.link) {
314
+ return meta.link
315
+ }
316
+
317
+ // TODO:KB:20231017 rewrite n-display-metadata in typescript using our types (lol. lmao)
318
+ // if meta.link has a predicate field, it's a concept, so wrap it in our concept model
319
+ if ('predicate' in meta.link) {
320
+ return new Concept(meta.link, this.context)
321
+ }
322
+
323
+ // otherwise, it's the package container, so return that directly as we already have it
324
+ return this.containedIn()
319
325
  }
320
326
 
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
327
+ async metaAltLink() {
328
+ const meta = await this.#teaserMetadata()
329
+
330
+ if (!meta.altLink) {
330
331
  return null
331
332
  }
333
+
334
+ // unlike meta.link, meta.altLink alwyas returns a Concept
335
+ return new Concept(meta.altLink, this.context)
336
+ }
337
+
338
+ async metaPrefixText() {
339
+ const meta = await this.#teaserMetadata()
340
+ return meta.prefixText
332
341
  }
333
342
 
334
343
  teaser() {
@@ -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
  }