@financial-times/cp-content-pipeline-schema 1.4.3 → 1.5.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.
Files changed (87) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/lib/fixtures/capiObject.js +1 -1
  3. package/lib/fixtures/capiObject.js.map +1 -1
  4. package/lib/fixtures/clipSet.d.ts +2 -0
  5. package/lib/fixtures/clipSet.js +70 -0
  6. package/lib/fixtures/clipSet.js.map +1 -0
  7. package/lib/generated/index.d.ts +136 -3
  8. package/lib/model/CapiResponse.d.ts +3 -2
  9. package/lib/model/CapiResponse.js +10 -1
  10. package/lib/model/CapiResponse.js.map +1 -1
  11. package/lib/model/Clip.d.ts +28 -0
  12. package/lib/model/Clip.js +51 -0
  13. package/lib/model/Clip.js.map +1 -0
  14. package/lib/model/schemas/capi/article.d.ts +605 -9
  15. package/lib/model/schemas/capi/article.js +1 -0
  16. package/lib/model/schemas/capi/article.js.map +1 -1
  17. package/lib/model/schemas/capi/audio.d.ts +34 -31
  18. package/lib/model/schemas/capi/audio.js +1 -0
  19. package/lib/model/schemas/capi/audio.js.map +1 -1
  20. package/lib/model/schemas/capi/base-schema.d.ts +1358 -14
  21. package/lib/model/schemas/capi/base-schema.js +46 -2
  22. package/lib/model/schemas/capi/base-schema.js.map +1 -1
  23. package/lib/model/schemas/capi/content-package.d.ts +6 -3
  24. package/lib/model/schemas/capi/content-package.js +1 -0
  25. package/lib/model/schemas/capi/content-package.js.map +1 -1
  26. package/lib/model/schemas/capi/live-blog-package.d.ts +605 -9
  27. package/lib/model/schemas/capi/live-blog-package.js +1 -0
  28. package/lib/model/schemas/capi/live-blog-package.js.map +1 -1
  29. package/lib/model/schemas/capi/placeholder.d.ts +605 -9
  30. package/lib/model/schemas/capi/placeholder.js +1 -0
  31. package/lib/model/schemas/capi/placeholder.js.map +1 -1
  32. package/lib/resolvers/clip.d.ts +10 -0
  33. package/lib/resolvers/clip.js +13 -0
  34. package/lib/resolvers/clip.js.map +1 -0
  35. package/lib/resolvers/content-tree/Workarounds.d.ts +10 -2
  36. package/lib/resolvers/content-tree/nodePredicates.d.ts +3 -3
  37. package/lib/resolvers/content-tree/references/ClipSet.d.ts +27 -0
  38. package/lib/resolvers/content-tree/references/ClipSet.js +37 -0
  39. package/lib/resolvers/content-tree/references/ClipSet.js.map +1 -0
  40. package/lib/resolvers/content-tree/references/ImageSet.js +3 -2
  41. package/lib/resolvers/content-tree/references/ImageSet.js.map +1 -1
  42. package/lib/resolvers/content-tree/references/Reference.d.ts +1 -1
  43. package/lib/resolvers/content-tree/references/ScrollyImage.js +3 -2
  44. package/lib/resolvers/content-tree/references/ScrollyImage.js.map +1 -1
  45. package/lib/resolvers/content-tree/references/index.d.ts +4 -1
  46. package/lib/resolvers/content-tree/references/index.js +4 -0
  47. package/lib/resolvers/content-tree/references/index.js.map +1 -1
  48. package/lib/resolvers/content-tree/tagMappings.js +9 -0
  49. package/lib/resolvers/content-tree/tagMappings.js.map +1 -1
  50. package/lib/resolvers/content.d.ts +1 -0
  51. package/lib/resolvers/content.js +1 -0
  52. package/lib/resolvers/content.js.map +1 -1
  53. package/lib/resolvers/index.d.ts +10 -0
  54. package/lib/resolvers/index.js +2 -0
  55. package/lib/resolvers/index.js.map +1 -1
  56. package/lib/resolvers/scalars.d.ts +2 -0
  57. package/lib/resolvers/scalars.js +6 -1
  58. package/lib/resolvers/scalars.js.map +1 -1
  59. package/package.json +1 -1
  60. package/src/fixtures/capiObject.ts +1 -1
  61. package/src/fixtures/clipSet.ts +72 -0
  62. package/src/generated/index.ts +144 -3
  63. package/src/model/CapiResponse.ts +12 -2
  64. package/src/model/Clip.ts +75 -0
  65. package/src/model/__snapshots__/RichText.test.ts.snap +25 -0
  66. package/src/model/schemas/capi/article.ts +1 -0
  67. package/src/model/schemas/capi/audio.ts +1 -0
  68. package/src/model/schemas/capi/base-schema.ts +50 -1
  69. package/src/model/schemas/capi/content-package.ts +1 -0
  70. package/src/model/schemas/capi/live-blog-package.ts +1 -0
  71. package/src/model/schemas/capi/placeholder.ts +1 -0
  72. package/src/resolvers/clip.ts +13 -0
  73. package/src/resolvers/content-tree/Workarounds.ts +13 -2
  74. package/src/resolvers/content-tree/references/ClipSet.ts +49 -0
  75. package/src/resolvers/content-tree/references/ImageSet.ts +9 -5
  76. package/src/resolvers/content-tree/references/ScrollyImage.ts +9 -5
  77. package/src/resolvers/content-tree/references/index.ts +6 -0
  78. package/src/resolvers/content-tree/tagMappings.ts +10 -0
  79. package/src/resolvers/content.ts +1 -0
  80. package/src/resolvers/index.ts +2 -0
  81. package/src/resolvers/scalars.ts +8 -0
  82. package/src/types/internal-content.d.ts +4 -0
  83. package/tsconfig.tsbuildinfo +1 -1
  84. package/typedefs/clip.graphql +28 -0
  85. package/typedefs/content.graphql +8 -2
  86. package/typedefs/references/clipSet.graphql +19 -0
  87. package/typedefs/scalars.graphql +1 -0
@@ -8,7 +8,7 @@ export const baseCapiObject: InternalContent = {
8
8
  title: 'Kwarteng faces test persuading UK watchdog of fiscal plans',
9
9
  standfirst: '',
10
10
  byline: 'Chris Giles in London',
11
- bodyXML: `<body><ft-content type="http://www.ft.com/ontology/content/ImageSet" url="http://api.ft.com/content/c45f7393-62c8-4a6b-b53d-641725351851" data-embedded="true"></ft-content><p><a href="https://amzn.to/3V3cwPP"><strong>Eliot After The Waste Land</strong></a><strong> (Eliot Biographies, 2)<br/></strong>by Robert Crawford, <em>Jonathan Cape £25</em></p><p>After a six-year wait, Robert Crawford follows up <em>Young Eliot</em> (2016) with his <a href="https://www.ft.com/content/210d7f37-115e-4197-b392-ffb094ed2699">second (and final) volume</a> on the life of TS Eliot in time for the centenary of “The Waste Land”. Here, he explores Eliot’s marriage, religious life and draws on the 1,131 letters written to American friend Emily Hale that were only released from embargo in 2020 to probe the poet’s later years with tact and empathy.</p><ft-content type="http://www.ft.com/ontology/content/ImageSet" url="http://api.ft.com/content/bf48b0fc-ad4b-4ce9-a734-faf3e9aab225" data-embedded="true"></ft-content><p><a href="https://amzn.to/3UFKeul"><strong>All the Knowledge in the World</strong></a><strong>: The Extraordinary History of the Encyclopaedia<br/></strong>by Simon Garfield, <em>Weidenfeld &amp; Nicolson £18.99</em></p><p>Simon Garfield, author of quirky histories on everything from fonts to maps, surveys the publishing phenomenon that is the encyclopedia. Tracing its origins from Ancient Greece right up to its modern incarnation in Wikipedia, his handsome book offers an erudite and amusing exploration of the human quest for knowledge.</p><ft-content type="http://www.ft.com/ontology/content/ImageSet" url="http://api.ft.com/content/cc74e2ec-3314-4b9f-81c1-bcfdf9dbaf99" data-embedded="true"></ft-content><p><a href="https://amzn.to/3VbW1AB"><strong>The Waste Land</strong></a><strong>: A Biography of a Poem<br/></strong>by Matthew Hollis, <em>Faber £20</em></p><p>In the 100 years since TS Eliot penned his famous poem, it has taken on a life of its own. So it’s fitting, perhaps, that Matthew Hollis treats Eliot’s work to its own biography. This richly analytical book locates the poem’s genesis in the aftermath of the first world war and the “nightmare agony” of Eliot’s disastrous marriage.</p><ft-content type="http://www.ft.com/ontology/content/ImageSet" url="http://api.ft.com/content/7393690b-e02e-4cdb-a263-57e7d1a6eedf" data-embedded="true"></ft-content><p><a href="https://amzn.to/3OgAT9M"><strong>Endless Flight</strong></a><strong>: The Life of Joseph Roth<br/></strong>by Keiron Pim, <em>Granta £25</em></p><p>“I paint the portrait of the age,” Joseph Roth once claimed. Certainly, his work as a journalist from 1917-1939, dissecting central and eastern Europe in more than a thousand essays and anticipating the collapse of democracy on the continent as well as 19 novels provides an exceptional anatomy of a tumultuous period of history. Keiron Pim’s <a href="https://www.ft.com/content/fee9056b-277e-41b4-9572-9fbac39f957b">biography</a> goes some way to introducing the great Austro-Hungarian writer to a new age.</p><ft-content type="http://www.ft.com/ontology/content/ImageSet" url="http://api.ft.com/content/6e7b048f-d08f-43f7-b1fa-95e98c8ca811" data-embedded="true"></ft-content><p><a href="https://amzn.to/3hX8PfS"><strong>Super-Infinite</strong></a><strong>: The Transformations of John Donne<br/></strong>by Katherine Rundell, <em>Faber £16.99</em></p><p>Katherine Rundell, a Fellow of All Souls College, Oxford, has produced a remarkable life of John Donne, the great poet of love, sex and death. Winner of this year’s Baillie Gifford Prize, her <a href="https://www.ft.com/content/c229396d-5448-44fa-b423-b018695d65d8">biography</a> of the man who was at once soldier, poet, prisoner and priest is sensitive and witty, capturing the essence of a tricky subject. </p><experimental><div class="n-content-layout" data-layout-name="card" data-layout-width="true"><div class="n-content-layout__container"><h2 theme-style="3">Books of the Year 2022</h2><div class="n-content-layout__slot" data-slot-width="true"><h4></h4><div class="n-content-layout__slot" data-slot-width="true"><img alt="" data-copyright="" data-image-type="image" longdesc="" src="https://d1e00ek4ebabms.cloudfront.net/production/43c41a77-ab10-40ed-a2a2-efa99ef32a10.jpg"/></div></div><div class="n-content-layout__slot" data-slot-width="true"><h4></h4><div class="n-content-layout__slot" data-slot-width="true"><p>All this week, FT writers and critics share <a href="https://www.ft.com/content/2dd61d03-13ac-4278-8214-678c1d9a33c1">their favourites</a>. Some highlights are: <br/><br/><strong>Monday:</strong> <a href="https://www.ft.com/content/416e1e1d-22e7-439b-9388-5d0cd56f5a9c">Business</a> by Andrew Hill<br/><strong>Tuesday:</strong> <a href="https://www.ft.com/content/db8aaeb6-141f-4a7c-b364-2296fb0d8065">Environment</a> by Pilita Clark<br/><strong>Wednesday:</strong> <a href="https://www.ft.com/content/634c1974-bc76-4f56-9548-274816dcc638">Economics</a> by Martin Wolf<br/><strong>Thursday:</strong> Fiction by Laura Battle<br/><strong>Friday:</strong> Politics by Gideon Rachman<br/><strong>Saturday:</strong> Critics’ choice</p></div></div></div></div></experimental><ft-content type="http://www.ft.com/ontology/content/ImageSet" url="http://api.ft.com/content/fde6576e-ab0c-41ec-8e18-bcdb3d6c21c0" data-embedded="true"></ft-content><p><a href="https://amzn.to/3gn2kCl"><strong>The Book of Phobias and Manias</strong></a><strong>: A History of the World in 99 Obsessions<br/></strong>by Kate Summerscale, <em>Profile £16.99</em></p><p>This neat compendium from the prizewinning author of <em>The Suspicions of Mr Whicher</em> charts a broad and intriguing range of fears and madness. Although these phobias and manias are alphabetised, Kate Summerscale suggests groupings (textures, animals, communal crazes) that — accompanied by a lightly erudite introduction — illuminate some of the darker corners of our collective psyche.</p><ft-content type="http://www.ft.com/ontology/content/ImageSet" url="http://api.ft.com/content/a07a6f3b-41cf-47c7-9b79-1c755ebfe54c" data-embedded="true"></ft-content><p><a href="https://amzn.to/3hX9oq0"><strong>Papyrus</strong></a><strong>: The Invention of Books in the Ancient World<br/></strong>by Irene Vallejo, <em>Hodder &amp; Stoughton £25</em></p><p>Described as “a masterpiece” by Mario Vargas Llosa when it was first published in Spain in 2019, this bestselling phenomenon is now available in English. In it, Irene Vallejo recounts the birth of literary culture in the ancient world while interweaving dynamic, thrilling tales that underscore and celebrate the power of words to change the world.</p><ft-content type="http://www.ft.com/ontology/content/ImageSet" url="http://api.ft.com/content/60b81603-654d-46ac-85ef-5865eb7bc1e8" data-embedded="true"></ft-content><p><a href="https://amzn.to/3EIwiKD"><strong>Magnificent Rebels</strong></a><strong>: The First Romantics and the Invention of the Self</strong><br/>by Andrea Wulf, <em>John Murray £25/Knopf $35</em></p><p>Between 1794-1806, the cream of Germany’s intelligentsia descended on the tiny university town of Jena. There, Johann Wolfgang von Goethe mingled with philosophers Friedrich Schelling and Georg Wilhelm Friedrich Hegel, the scientist-explorer Alexander von Humboldt and the playwright Friedrich Schiller during the first flush of Romanticism. Andrea Wulf’s wonderful <a href="https://www.ft.com/content/391e2bcd-f14e-44e5-b6de-40990ce7272f">book</a> brings to life the “Jena set” and a golden age of German culture. </p><experimental><div class="n-content-layout" data-layout-name="card" data-layout-width="fullWidth"><div class="n-content-layout__container"><h3>Tell us what you think</h3><div class="n-content-layout__slot" data-slot-width="true"><p>What are your favourites from this list — and what books have we missed? Tell us in the comments below</p></div></div></div></experimental><p><em>Join our online book group on Facebook at </em><a href="https://www.facebook.com/groups/139838140082304/"><em>FT Books Café</em></a></p></body>`,
11
+ bodyXML: `<body><ft-content type="http://www.ft.com/ontology/content/ImageSet" url="http://api.ft.com/content/c45f7393-62c8-4a6b-b53d-641725351851" data-embedded="true"></ft-content><p><a href="https://amzn.to/3V3cwPP"><strong>Eliot After The Waste Land</strong></a><strong> (Eliot Biographies, 2)<br/></strong>by Robert Crawford, <em>Jonathan Cape £25</em></p><p>After a six-year wait, Robert Crawford follows up <em>Young Eliot</em> (2016) with his <a href="https://www.ft.com/content/210d7f37-115e-4197-b392-ffb094ed2699">second (and final) volume</a> on the life of TS Eliot in time for the centenary of “The Waste Land”. Here, he explores Eliot’s marriage, religious life and draws on the 1,131 letters written to American friend Emily Hale that were only released from embargo in 2020 to probe the poet’s later years with tact and empathy.</p><ft-content type="http://www.ft.com/ontology/content/ImageSet" url="http://api.ft.com/content/bf48b0fc-ad4b-4ce9-a734-faf3e9aab225" data-embedded="true"></ft-content><p><a href="https://amzn.to/3UFKeul"><strong>All the Knowledge in the World</strong></a><strong>: The Extraordinary History of the Encyclopaedia<br/></strong>by Simon Garfield, <em>Weidenfeld &amp; Nicolson £18.99</em></p><p>Simon Garfield, author of quirky histories on everything from fonts to maps, surveys the publishing phenomenon that is the encyclopedia. Tracing its origins from Ancient Greece right up to its modern incarnation in Wikipedia, his handsome book offers an erudite and amusing exploration of the human quest for knowledge.</p><ft-content type="http://www.ft.com/ontology/content/ImageSet" url="http://api.ft.com/content/cc74e2ec-3314-4b9f-81c1-bcfdf9dbaf99" data-embedded="true"></ft-content><p><a href="https://amzn.to/3VbW1AB"><strong>The Waste Land</strong></a><strong>: A Biography of a Poem<br/></strong>by Matthew Hollis, <em>Faber £20</em></p><p>In the 100 years since TS Eliot penned his famous poem, it has taken on a life of its own. So it’s fitting, perhaps, that Matthew Hollis treats Eliot’s work to its own biography. This richly analytical book locates the poem’s genesis in the aftermath of the first world war and the “nightmare agony” of Eliot’s disastrous marriage.</p><ft-content type="http://www.ft.com/ontology/content/ImageSet" url="http://api.ft.com/content/7393690b-e02e-4cdb-a263-57e7d1a6eedf" data-embedded="true"></ft-content><p><a href="https://amzn.to/3OgAT9M"><strong>Endless Flight</strong></a><strong>: The Life of Joseph Roth<br/></strong>by Keiron Pim, <em>Granta £25</em></p><p>“I paint the portrait of the age,” Joseph Roth once claimed. Certainly, his work as a journalist from 1917-1939, dissecting central and eastern Europe in more than a thousand essays and anticipating the collapse of democracy on the continent as well as 19 novels provides an exceptional anatomy of a tumultuous period of history. Keiron Pim’s <a href="https://www.ft.com/content/fee9056b-277e-41b4-9572-9fbac39f957b">biography</a> goes some way to introducing the great Austro-Hungarian writer to a new age.</p><ft-content type="http://www.ft.com/ontology/content/ImageSet" url="http://api.ft.com/content/6e7b048f-d08f-43f7-b1fa-95e98c8ca811" data-embedded="true"></ft-content><p><a href="https://amzn.to/3hX8PfS"><strong>Super-Infinite</strong></a><strong>: The Transformations of John Donne<br/></strong>by Katherine Rundell, <em>Faber £16.99</em></p><p>Katherine Rundell, a Fellow of All Souls College, Oxford, has produced a remarkable life of John Donne, the great poet of love, sex and death. Winner of this year’s Baillie Gifford Prize, her <a href="https://www.ft.com/content/c229396d-5448-44fa-b423-b018695d65d8">biography</a> of the man who was at once soldier, poet, prisoner and priest is sensitive and witty, capturing the essence of a tricky subject. </p><experimental><div class="n-content-layout" data-layout-name="card" data-layout-width="true"><div class="n-content-layout__container"><h2 theme-style="3">Books of the Year 2022</h2><div class="n-content-layout__slot" data-slot-width="true"><h4></h4><div class="n-content-layout__slot" data-slot-width="true"><img alt="" data-copyright="" data-image-type="image" longdesc="" src="https://d1e00ek4ebabms.cloudfront.net/production/43c41a77-ab10-40ed-a2a2-efa99ef32a10.jpg"/></div></div><div class="n-content-layout__slot" data-slot-width="true"><h4></h4><div class="n-content-layout__slot" data-slot-width="true"><p>All this week, FT writers and critics share <a href="https://www.ft.com/content/2dd61d03-13ac-4278-8214-678c1d9a33c1">their favourites</a>. Some highlights are: <br/><br/><strong>Monday:</strong> <a href="https://www.ft.com/content/416e1e1d-22e7-439b-9388-5d0cd56f5a9c">Business</a> by Andrew Hill<br/><strong>Tuesday:</strong> <a href="https://www.ft.com/content/db8aaeb6-141f-4a7c-b364-2296fb0d8065">Environment</a> by Pilita Clark<br/><strong>Wednesday:</strong> <a href="https://www.ft.com/content/634c1974-bc76-4f56-9548-274816dcc638">Economics</a> by Martin Wolf<br/><strong>Thursday:</strong> Fiction by Laura Battle<br/><strong>Friday:</strong> Politics by Gideon Rachman<br/><strong>Saturday:</strong> Critics’ choice</p></div></div></div></div></experimental><ft-content type="http://www.ft.com/ontology/content/ImageSet" url="http://api.ft.com/content/fde6576e-ab0c-41ec-8e18-bcdb3d6c21c0" data-embedded="true"></ft-content><p><a href="https://amzn.to/3gn2kCl"><strong>The Book of Phobias and Manias</strong></a><strong>: A History of the World in 99 Obsessions<br/></strong>by Kate Summerscale, <em>Profile £16.99</em></p><p>This neat compendium from the prizewinning author of <em>The Suspicions of Mr Whicher</em> charts a broad and intriguing range of fears and madness. Although these phobias and manias are alphabetised, Kate Summerscale suggests groupings (textures, animals, communal crazes) that — accompanied by a lightly erudite introduction — illuminate some of the darker corners of our collective psyche.</p><ft-content type="http://www.ft.com/ontology/content/ImageSet" url="http://api.ft.com/content/a07a6f3b-41cf-47c7-9b79-1c755ebfe54c" data-embedded="true"></ft-content><p><a href="https://amzn.to/3hX9oq0"><strong>Papyrus</strong></a><strong>: The Invention of Books in the Ancient World<br/></strong>by Irene Vallejo, <em>Hodder &amp; Stoughton £25</em></p><p>Described as “a masterpiece” by Mario Vargas Llosa when it was first published in Spain in 2019, this bestselling phenomenon is now available in English. In it, Irene Vallejo recounts the birth of literary culture in the ancient world while interweaving dynamic, thrilling tales that underscore and celebrate the power of words to change the world.</p><ft-content type="http://www.ft.com/ontology/content/ImageSet" url="http://api.ft.com/content/60b81603-654d-46ac-85ef-5865eb7bc1e8" data-embedded="true"></ft-content><p><a href="https://amzn.to/3EIwiKD"><strong>Magnificent Rebels</strong></a><strong>: The First Romantics and the Invention of the Self</strong><br/>by Andrea Wulf, <em>John Murray £25/Knopf $35</em></p><ft-content type="http://www.ft.com/ontology/content/ClipSet" url="http://api-t.ft.com/content/f17fe25b-cdea-4d5f-a6af-40e56e33e888" autoplay="true" data-layout="in-line" loop="true" muted="true"></ft-content><p>Between 1794-1806, the cream of Germany’s intelligentsia descended on the tiny university town of Jena. There, Johann Wolfgang von Goethe mingled with philosophers Friedrich Schelling and Georg Wilhelm Friedrich Hegel, the scientist-explorer Alexander von Humboldt and the playwright Friedrich Schiller during the first flush of Romanticism. Andrea Wulf’s wonderful <a href="https://www.ft.com/content/391e2bcd-f14e-44e5-b6de-40990ce7272f">book</a> brings to life the “Jena set” and a golden age of German culture. </p><experimental><div class="n-content-layout" data-layout-name="card" data-layout-width="fullWidth"><div class="n-content-layout__container"><h3>Tell us what you think</h3><div class="n-content-layout__slot" data-slot-width="true"><p>What are your favourites from this list — and what books have we missed? Tell us in the comments below</p></div></div></div></experimental><p><em>Join our online book group on Facebook at </em><a href="https://www.facebook.com/groups/139838140082304/"><em>FT Books Café</em></a></p></body>`,
12
12
  annotations: [
13
13
  {
14
14
  apiUrl: 'http://api.ft.com/things/9bfe954c-e0ec-4716-ae91-24bd0f7860c9',
@@ -0,0 +1,72 @@
1
+ import { ClipSet as ClipSetType } from '../types/internal-content'
2
+
3
+ export const ClipSet: ClipSetType = {
4
+ accessibility: {
5
+ captions: [
6
+ {
7
+ mediaType: 'text/vtt',
8
+ url: 'https://next-media-api.ft.com/captions/16862228218010.vtt',
9
+ },
10
+ ],
11
+ transcript:
12
+ '<p>Hydrogen is this magic molecule which is the lightest, the most energetic and the most abundant in the universe. ... </p>',
13
+ },
14
+ description:
15
+ "The global push for net zero carbon emissions is one of humanity's greatest challenges. ...",
16
+ displayTitle: 'Ukranians fight back',
17
+ contentWarning: ['graphic violence', 'animal cruelty'],
18
+ id: 'http://www.ft.com/thing/f17fe25b-cdea-4d5f-a6af-40e56e33e888',
19
+ members: [
20
+ {
21
+ format: 'standardInline',
22
+ id: 'https://api.ft.com/content/4d000e07-d679-4e3b-bd6d-afa3461243a8',
23
+ type: 'http://www.ft.com/ontology/content/Clip',
24
+ dataSource: [
25
+ {
26
+ audioCodec: 'mp3',
27
+ binaryUrl:
28
+ 'https://next-media-api.ft.com/renditions/16868569859480/0x0.mp3',
29
+ duration: 1057,
30
+ mediaType: 'audio/mpeg',
31
+ pixelHeight: 720,
32
+ pixelWidth: 1280,
33
+ videoCodec: 'h264',
34
+ },
35
+ ],
36
+ poster: {
37
+ id: 'https://api.ft.com/content/2f730c3c-1fb2-4131-9697-c534fe1ee488',
38
+ type: 'http://www.ft.com/ontology/content/ImageSet',
39
+ description: 'Picture for video',
40
+ members: [],
41
+ },
42
+ },
43
+ {
44
+ format: 'mobile',
45
+ id: 'https://api.ft.com/content/b529ba2b-d424-4f85-a93f-8413636dac82',
46
+ type: 'http://www.ft.com/ontology/content/Clip',
47
+ dataSource: [
48
+ {
49
+ audioCodec: 'mp3',
50
+ binaryUrl:
51
+ 'https://next-media-api.ft.com/renditions/16868569859480/0x0.mp3',
52
+ duration: 1057,
53
+ mediaType: 'audio/mpeg',
54
+ pixelHeight: 720,
55
+ pixelWidth: 1280,
56
+ videoCodec: 'h264',
57
+ },
58
+ ],
59
+ poster: {
60
+ id: 'https://api.ft.com/content/2f730c3c-1fb2-4131-9697-c534fe1ee488',
61
+ type: 'http://www.ft.com/ontology/content/ImageSet',
62
+ description: 'Picture for video',
63
+ members: [],
64
+ },
65
+ },
66
+ ],
67
+ noAudio: false,
68
+ publishedDate: '2023-06-14T03:59:47.543Z',
69
+ source: 'YouGov',
70
+ subtitle: 'Drone hits Moscow tower block',
71
+ type: 'http://www.ft.com/ontology/content/ClipSet',
72
+ }
@@ -2,12 +2,13 @@ import type { GraphQLResolveInfo, GraphQLScalarType, GraphQLScalarTypeConfig } f
2
2
  import type { Concept as ConceptModel } from '../model/Concept';
3
3
  import type { CapiResponse } from '../model/CapiResponse';
4
4
  import type { Image as ImageModel } from '../model/Image';
5
+ import type { Clip as ClipModel } from '../model/Clip';
5
6
  import type { Picture as PictureModel } from '../model/Picture';
6
7
  import type { RichText as RichTextModel } from '../model/RichText';
7
8
  import type { Topper as TopperModel } from '../model/Topper';
8
9
  import type { ContentTree } from '@financial-times/content-tree';
9
10
  import type { ReferenceWithCAPIData } from '../resolvers/content-tree/references';
10
- import type { Video as VideoNode, RawImage as RawImageNode } from '../resolvers/content-tree/Workarounds';
11
+ import type { Video as VideoNode, ClipSet as ClipSetNode, OldClip as OldClipNode, RawImage as RawImageNode } from '../resolvers/content-tree/Workarounds';
11
12
  import type { QueryContext } from '../';
12
13
  export type Maybe<T> = T | null;
13
14
  export type InputMaybe<T> = Maybe<T>;
@@ -27,6 +28,7 @@ export type Scalars = {
27
28
  Float: { input: number; output: number; }
28
29
  AccessLevel: { input: 'premium' | 'subscribed' | 'registered' | 'free'; output: 'premium' | 'subscribed' | 'registered' | 'free'; }
29
30
  CanBeSyndicated: { input: 'yes' | 'no' | 'verify' | 'withContributorPayment' | 'unknown'; output: 'yes' | 'no' | 'verify' | 'withContributorPayment' | 'unknown'; }
31
+ ClipFormat: { input: 'standard-inline' | 'mobile'; output: 'standard-inline' | 'mobile'; }
30
32
  ContentType: { input: 'Article' | 'Placeholder' | 'Video' | 'Audio' | 'LiveBlogPackage' | 'LiveBlogPost' | 'ContentPackage' | 'Content' | 'MediaResource'; output: 'Article' | 'Placeholder' | 'Video' | 'Audio' | 'LiveBlogPackage' | 'LiveBlogPost' | 'ContentPackage' | 'Content' | 'MediaResource'; }
31
33
  FollowButtonVariant: { input: 'standard' | 'inverse' | 'opinion' | 'alphaville' | 'monochrome' | 'inverse-monochrome'; output: 'standard' | 'inverse' | 'opinion' | 'alphaville' | 'monochrome' | 'inverse-monochrome'; }
32
34
  ImageFormat: { input: 'standard' | 'standard-inline' | 'desktop' | 'mobile' | 'wide' | 'square' | 'square-ftedit' | 'portrait' | 'landscape'; output: 'standard' | 'standard-inline' | 'desktop' | 'mobile' | 'wide' | 'square' | 'square-ftedit' | 'portrait' | 'landscape'; }
@@ -37,6 +39,11 @@ export type Scalars = {
37
39
  TopperBackgroundColour: { input: 'paper' | 'wheat' | 'white' | 'black' | 'claret' | 'oxford' | 'slate' | 'crimson' | 'sky' | 'matisse'; output: 'paper' | 'wheat' | 'white' | 'black' | 'claret' | 'oxford' | 'slate' | 'crimson' | 'sky' | 'matisse'; }
38
40
  };
39
41
 
42
+ export type Accessibility = {
43
+ readonly captions?: Maybe<ReadonlyArray<Maybe<Caption>>>;
44
+ readonly transcript?: Maybe<Scalars['String']['output']>;
45
+ };
46
+
40
47
  export type AltStandfirst = {
41
48
  readonly promotionalStandfirst?: Maybe<Scalars['String']['output']>;
42
49
  };
@@ -60,6 +67,7 @@ export type Article = Content & {
60
67
  readonly firstPublishedDate: Scalars['String']['output'];
61
68
  readonly id: Scalars['ID']['output'];
62
69
  readonly mainImage?: Maybe<Image>;
70
+ readonly originatingParty?: Maybe<Scalars['String']['output']>;
63
71
  readonly publishedDate: Scalars['String']['output'];
64
72
  readonly standfirst?: Maybe<Scalars['String']['output']>;
65
73
  readonly teaser?: Maybe<Teaser>;
@@ -95,6 +103,7 @@ export type Audio = Content & {
95
103
  readonly id: Scalars['ID']['output'];
96
104
  readonly mainImage?: Maybe<Image>;
97
105
  readonly media?: Maybe<ReadonlyArray<Maybe<Media>>>;
106
+ readonly originatingParty?: Maybe<Scalars['String']['output']>;
98
107
  readonly publishedDate: Scalars['String']['output'];
99
108
  readonly standfirst?: Maybe<Scalars['String']['output']>;
100
109
  readonly teaser?: Maybe<Teaser>;
@@ -140,6 +149,49 @@ export type BrandedTopper = Topper & TopperWithBrand & TopperWithTheme & {
140
149
  readonly textShadow?: Maybe<Scalars['Boolean']['output']>;
141
150
  };
142
151
 
152
+ export type Caption = {
153
+ readonly mediaType?: Maybe<Scalars['String']['output']>;
154
+ readonly url?: Maybe<Scalars['String']['output']>;
155
+ };
156
+
157
+ export type Clip = {
158
+ readonly dataSource: ReadonlyArray<ClipSource>;
159
+ readonly format?: Maybe<Scalars['ClipFormat']['output']>;
160
+ readonly id: Scalars['String']['output'];
161
+ readonly poster?: Maybe<Scalars['String']['output']>;
162
+ readonly type?: Maybe<Scalars['String']['output']>;
163
+ };
164
+
165
+ export type ClipSet = Reference & {
166
+ readonly accessibility?: Maybe<Accessibility>;
167
+ readonly autoplay?: Maybe<Scalars['Boolean']['output']>;
168
+ readonly caption?: Maybe<Scalars['String']['output']>;
169
+ readonly clips?: Maybe<ReadonlyArray<Maybe<Clip>>>;
170
+ readonly contentWarning?: Maybe<ReadonlyArray<Maybe<Scalars['String']['output']>>>;
171
+ readonly credits?: Maybe<Scalars['String']['output']>;
172
+ readonly dataLayout?: Maybe<Scalars['String']['output']>;
173
+ readonly description?: Maybe<Scalars['String']['output']>;
174
+ readonly displayTitle?: Maybe<Scalars['String']['output']>;
175
+ readonly id: Scalars['String']['output'];
176
+ readonly loop?: Maybe<Scalars['Boolean']['output']>;
177
+ readonly muted?: Maybe<Scalars['Boolean']['output']>;
178
+ readonly noAudio?: Maybe<Scalars['Boolean']['output']>;
179
+ readonly publishedDate?: Maybe<Scalars['String']['output']>;
180
+ readonly source?: Maybe<Scalars['String']['output']>;
181
+ readonly subtitle?: Maybe<Scalars['String']['output']>;
182
+ readonly type: Scalars['String']['output'];
183
+ };
184
+
185
+ export type ClipSource = {
186
+ readonly audioCodec?: Maybe<Scalars['String']['output']>;
187
+ readonly binaryUrl: Scalars['String']['output'];
188
+ readonly duration?: Maybe<Scalars['Int']['output']>;
189
+ readonly mediaType: Scalars['String']['output'];
190
+ readonly pixelHeight?: Maybe<Scalars['Int']['output']>;
191
+ readonly pixelWidth?: Maybe<Scalars['Int']['output']>;
192
+ readonly videoCodec?: Maybe<Scalars['String']['output']>;
193
+ };
194
+
143
195
  export type Concept = {
144
196
  readonly apiUrl?: Maybe<Scalars['String']['output']>;
145
197
  readonly directType?: Maybe<Scalars['String']['output']>;
@@ -172,6 +224,7 @@ export type Content = {
172
224
  readonly firstPublishedDate: Scalars['String']['output'];
173
225
  readonly id: Scalars['ID']['output'];
174
226
  readonly mainImage?: Maybe<Image>;
227
+ readonly originatingParty?: Maybe<Scalars['String']['output']>;
175
228
  readonly publishedDate: Scalars['String']['output'];
176
229
  readonly standfirst?: Maybe<Scalars['String']['output']>;
177
230
  readonly teaser?: Maybe<Teaser>;
@@ -208,6 +261,7 @@ export type ContentPackage = Content & {
208
261
  readonly firstPublishedDate: Scalars['String']['output'];
209
262
  readonly id: Scalars['ID']['output'];
210
263
  readonly mainImage?: Maybe<Image>;
264
+ readonly originatingParty?: Maybe<Scalars['String']['output']>;
211
265
  readonly publishedDate: Scalars['String']['output'];
212
266
  readonly standfirst?: Maybe<Scalars['String']['output']>;
213
267
  readonly tableOfContents?: Maybe<TableOfContents>;
@@ -530,6 +584,7 @@ export type LiveBlogPackage = Content & {
530
584
  readonly id: Scalars['ID']['output'];
531
585
  readonly liveBlogPosts?: Maybe<ReadonlyArray<Maybe<Content>>>;
532
586
  readonly mainImage?: Maybe<Image>;
587
+ readonly originatingParty?: Maybe<Scalars['String']['output']>;
533
588
  readonly pinnedPost?: Maybe<Content>;
534
589
  readonly publishedDate: Scalars['String']['output'];
535
590
  readonly realtime?: Maybe<Scalars['Boolean']['output']>;
@@ -567,6 +622,7 @@ export type LiveBlogPost = Content & {
567
622
  readonly firstPublishedDate: Scalars['String']['output'];
568
623
  readonly id: Scalars['ID']['output'];
569
624
  readonly mainImage?: Maybe<Image>;
625
+ readonly originatingParty?: Maybe<Scalars['String']['output']>;
570
626
  readonly publishedDate: Scalars['String']['output'];
571
627
  readonly standfirst?: Maybe<Scalars['String']['output']>;
572
628
  readonly teaser?: Maybe<Teaser>;
@@ -686,6 +742,7 @@ export type Placeholder = Content & {
686
742
  readonly firstPublishedDate: Scalars['String']['output'];
687
743
  readonly id: Scalars['ID']['output'];
688
744
  readonly mainImage?: Maybe<Image>;
745
+ readonly originatingParty?: Maybe<Scalars['String']['output']>;
689
746
  readonly publishedDate: Scalars['String']['output'];
690
747
  readonly standfirst?: Maybe<Scalars['String']['output']>;
691
748
  readonly teaser?: Maybe<Teaser>;
@@ -878,6 +935,7 @@ export type Video = Content & {
878
935
  readonly firstPublishedDate: Scalars['String']['output'];
879
936
  readonly id: Scalars['ID']['output'];
880
937
  readonly mainImage?: Maybe<Image>;
938
+ readonly originatingParty?: Maybe<Scalars['String']['output']>;
881
939
  readonly publishedDate: Scalars['String']['output'];
882
940
  readonly standfirst?: Maybe<Scalars['String']['output']>;
883
941
  readonly teaser?: Maybe<Teaser>;
@@ -982,7 +1040,7 @@ export type ResolversInterfaceTypes<RefType extends Record<string, unknown>> = R
982
1040
  Content: ( CapiResponse ) | ( CapiResponse ) | ( CapiResponse ) | ( CapiResponse ) | ( CapiResponse ) | ( CapiResponse ) | ( CapiResponse );
983
1041
  Image: ( ImageDesktop ) | ( ImageLandscape ) | ( ImageMobile ) | ( ImagePortrait ) | ( ImageSquare ) | ( ImageSquareFtEdit ) | ( ImageStandard ) | ( ImageStandardInline ) | ( ImageWide );
984
1042
  Picture: ( Omit<PictureFullBleed, 'fallbackImage' | 'images'> & { fallbackImage: RefType['Image'], images: ReadonlyArray<RefType['Image']> } ) | ( Omit<PictureInline, 'fallbackImage' | 'images'> & { fallbackImage: RefType['Image'], images: ReadonlyArray<RefType['Image']> } ) | ( Omit<PictureStandard, 'fallbackImage' | 'images'> & { fallbackImage: RefType['Image'], images: ReadonlyArray<RefType['Image']> } );
985
- Reference: ( ReferenceWithCAPIData<ContentTree.Flourish> ) | ( ReferenceWithCAPIData<ContentTree.ImageSet> ) | ( ReferenceWithCAPIData<ContentTree.LayoutImage> ) | ( ReferenceWithCAPIData<ContentTree.ImageSet> ) | ( ReferenceWithCAPIData<RawImageNode> ) | ( ReferenceWithCAPIData<ContentTree.Recommended> ) | ( ReferenceWithCAPIData<ContentTree.ScrollyImage> ) | ( ReferenceWithCAPIData<ContentTree.Tweet> ) | ( ReferenceWithCAPIData<VideoNode> );
1043
+ Reference: ( ReferenceWithCAPIData<ClipSetNode|OldClipNode> ) | ( ReferenceWithCAPIData<ContentTree.Flourish> ) | ( ReferenceWithCAPIData<ContentTree.ImageSet> ) | ( ReferenceWithCAPIData<ContentTree.LayoutImage> ) | ( ReferenceWithCAPIData<ContentTree.ImageSet> ) | ( ReferenceWithCAPIData<RawImageNode> ) | ( ReferenceWithCAPIData<ContentTree.Recommended> ) | ( ReferenceWithCAPIData<ContentTree.ScrollyImage> ) | ( ReferenceWithCAPIData<ContentTree.Tweet> ) | ( ReferenceWithCAPIData<VideoNode> );
986
1044
  Topper: ( Omit<BasicTopper, 'displayConcept' | 'genreConcept' | 'intro'> & { displayConcept?: Maybe<RefType['Concept']>, genreConcept?: Maybe<RefType['Concept']>, intro?: Maybe<RefType['RichText']> } ) | ( Omit<BrandedTopper, 'brandConcept' | 'displayConcept' | 'genreConcept' | 'intro'> & { brandConcept?: Maybe<RefType['Concept']>, displayConcept?: Maybe<RefType['Concept']>, genreConcept?: Maybe<RefType['Concept']>, intro?: Maybe<RefType['RichText']> } ) | ( Omit<DeepLandscapeTopper, 'brandConcept' | 'displayConcept' | 'fallbackImage' | 'genreConcept' | 'images' | 'intro'> & { brandConcept?: Maybe<RefType['Concept']>, displayConcept?: Maybe<RefType['Concept']>, fallbackImage?: Maybe<RefType['Image']>, genreConcept?: Maybe<RefType['Concept']>, images: ReadonlyArray<RefType['Image']>, intro?: Maybe<RefType['RichText']> } ) | ( Omit<DeepPortraitTopper, 'brandConcept' | 'displayConcept' | 'fallbackImage' | 'genreConcept' | 'images' | 'intro'> & { brandConcept?: Maybe<RefType['Concept']>, displayConcept?: Maybe<RefType['Concept']>, fallbackImage?: Maybe<RefType['Image']>, genreConcept?: Maybe<RefType['Concept']>, images: ReadonlyArray<RefType['Image']>, intro?: Maybe<RefType['RichText']> } ) | ( Omit<FullBleedTopper, 'brandConcept' | 'displayConcept' | 'fallbackImage' | 'genreConcept' | 'images' | 'intro'> & { brandConcept?: Maybe<RefType['Concept']>, displayConcept?: Maybe<RefType['Concept']>, fallbackImage?: Maybe<RefType['Image']>, genreConcept?: Maybe<RefType['Concept']>, images: ReadonlyArray<RefType['Image']>, intro?: Maybe<RefType['RichText']> } ) | ( TopperModel ) | ( TopperModel ) | ( Omit<SplitTextTopper, 'brandConcept' | 'displayConcept' | 'fallbackImage' | 'genreConcept' | 'images' | 'intro'> & { brandConcept?: Maybe<RefType['Concept']>, displayConcept?: Maybe<RefType['Concept']>, fallbackImage?: Maybe<RefType['Image']>, genreConcept?: Maybe<RefType['Concept']>, images: ReadonlyArray<RefType['Image']>, intro?: Maybe<RefType['RichText']> } );
987
1045
  TopperWithBrand: ( Omit<BrandedTopper, 'brandConcept' | 'displayConcept' | 'genreConcept' | 'intro'> & { brandConcept?: Maybe<RefType['Concept']>, displayConcept?: Maybe<RefType['Concept']>, genreConcept?: Maybe<RefType['Concept']>, intro?: Maybe<RefType['RichText']> } ) | ( Omit<DeepLandscapeTopper, 'brandConcept' | 'displayConcept' | 'fallbackImage' | 'genreConcept' | 'images' | 'intro'> & { brandConcept?: Maybe<RefType['Concept']>, displayConcept?: Maybe<RefType['Concept']>, fallbackImage?: Maybe<RefType['Image']>, genreConcept?: Maybe<RefType['Concept']>, images: ReadonlyArray<RefType['Image']>, intro?: Maybe<RefType['RichText']> } ) | ( Omit<DeepPortraitTopper, 'brandConcept' | 'displayConcept' | 'fallbackImage' | 'genreConcept' | 'images' | 'intro'> & { brandConcept?: Maybe<RefType['Concept']>, displayConcept?: Maybe<RefType['Concept']>, fallbackImage?: Maybe<RefType['Image']>, genreConcept?: Maybe<RefType['Concept']>, images: ReadonlyArray<RefType['Image']>, intro?: Maybe<RefType['RichText']> } ) | ( Omit<FullBleedTopper, 'brandConcept' | 'displayConcept' | 'fallbackImage' | 'genreConcept' | 'images' | 'intro'> & { brandConcept?: Maybe<RefType['Concept']>, displayConcept?: Maybe<RefType['Concept']>, fallbackImage?: Maybe<RefType['Image']>, genreConcept?: Maybe<RefType['Concept']>, images: ReadonlyArray<RefType['Image']>, intro?: Maybe<RefType['RichText']> } ) | ( TopperModel ) | ( Omit<SplitTextTopper, 'brandConcept' | 'displayConcept' | 'fallbackImage' | 'genreConcept' | 'images' | 'intro'> & { brandConcept?: Maybe<RefType['Concept']>, displayConcept?: Maybe<RefType['Concept']>, fallbackImage?: Maybe<RefType['Image']>, genreConcept?: Maybe<RefType['Concept']>, images: ReadonlyArray<RefType['Image']>, intro?: Maybe<RefType['RichText']> } );
988
1046
  TopperWithHeadshot: ( TopperModel ) | ( TopperModel );
@@ -994,6 +1052,7 @@ export type ResolversInterfaceTypes<RefType extends Record<string, unknown>> = R
994
1052
  /** Mapping between all available schema types and the resolvers types */
995
1053
  export type ResolversTypes = ResolversObject<{
996
1054
  AccessLevel: ResolverTypeWrapper<Scalars['AccessLevel']['output']>;
1055
+ Accessibility: ResolverTypeWrapper<Accessibility>;
997
1056
  AltStandfirst: ResolverTypeWrapper<AltStandfirst>;
998
1057
  AltTitle: ResolverTypeWrapper<AltTitle>;
999
1058
  Article: ResolverTypeWrapper<CapiResponse>;
@@ -1002,6 +1061,11 @@ export type ResolversTypes = ResolversObject<{
1002
1061
  Boolean: ResolverTypeWrapper<Scalars['Boolean']['output']>;
1003
1062
  BrandedTopper: ResolverTypeWrapper<Omit<BrandedTopper, 'brandConcept' | 'displayConcept' | 'genreConcept' | 'intro'> & { brandConcept?: Maybe<ResolversTypes['Concept']>, displayConcept?: Maybe<ResolversTypes['Concept']>, genreConcept?: Maybe<ResolversTypes['Concept']>, intro?: Maybe<ResolversTypes['RichText']> }>;
1004
1063
  CanBeSyndicated: ResolverTypeWrapper<Scalars['CanBeSyndicated']['output']>;
1064
+ Caption: ResolverTypeWrapper<Caption>;
1065
+ Clip: ResolverTypeWrapper<ClipModel>;
1066
+ ClipFormat: ResolverTypeWrapper<Scalars['ClipFormat']['output']>;
1067
+ ClipSet: ResolverTypeWrapper<ReferenceWithCAPIData<ClipSetNode|OldClipNode>>;
1068
+ ClipSource: ResolverTypeWrapper<ClipSource>;
1005
1069
  Concept: ResolverTypeWrapper<ConceptModel>;
1006
1070
  Content: ResolverTypeWrapper<ResolversInterfaceTypes<ResolversTypes>['Content']>;
1007
1071
  ContentPackage: ResolverTypeWrapper<CapiResponse>;
@@ -1073,6 +1137,7 @@ export type ResolversTypes = ResolversObject<{
1073
1137
  /** Mapping between all available schema types and the resolvers parents */
1074
1138
  export type ResolversParentTypes = ResolversObject<{
1075
1139
  AccessLevel: Scalars['AccessLevel']['output'];
1140
+ Accessibility: Accessibility;
1076
1141
  AltStandfirst: AltStandfirst;
1077
1142
  AltTitle: AltTitle;
1078
1143
  Article: CapiResponse;
@@ -1081,6 +1146,11 @@ export type ResolversParentTypes = ResolversObject<{
1081
1146
  Boolean: Scalars['Boolean']['output'];
1082
1147
  BrandedTopper: Omit<BrandedTopper, 'brandConcept' | 'displayConcept' | 'genreConcept' | 'intro'> & { brandConcept?: Maybe<ResolversParentTypes['Concept']>, displayConcept?: Maybe<ResolversParentTypes['Concept']>, genreConcept?: Maybe<ResolversParentTypes['Concept']>, intro?: Maybe<ResolversParentTypes['RichText']> };
1083
1148
  CanBeSyndicated: Scalars['CanBeSyndicated']['output'];
1149
+ Caption: Caption;
1150
+ Clip: ClipModel;
1151
+ ClipFormat: Scalars['ClipFormat']['output'];
1152
+ ClipSet: ReferenceWithCAPIData<ClipSetNode|OldClipNode>;
1153
+ ClipSource: ClipSource;
1084
1154
  Concept: ConceptModel;
1085
1155
  Content: ResolversInterfaceTypes<ResolversParentTypes>['Content'];
1086
1156
  ContentPackage: CapiResponse;
@@ -1153,6 +1223,12 @@ export interface AccessLevelScalarConfig extends GraphQLScalarTypeConfig<Resolve
1153
1223
  name: 'AccessLevel';
1154
1224
  }
1155
1225
 
1226
+ export type AccessibilityResolvers<ContextType = QueryContext, ParentType extends ResolversParentTypes['Accessibility'] = ResolversParentTypes['Accessibility']> = ResolversObject<{
1227
+ captions?: Resolver<Maybe<ReadonlyArray<Maybe<ResolversTypes['Caption']>>>, ParentType, ContextType>;
1228
+ transcript?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
1229
+ __isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
1230
+ }>;
1231
+
1156
1232
  export type AltStandfirstResolvers<ContextType = QueryContext, ParentType extends ResolversParentTypes['AltStandfirst'] = ResolversParentTypes['AltStandfirst']> = ResolversObject<{
1157
1233
  promotionalStandfirst?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
1158
1234
  __isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
@@ -1178,6 +1254,7 @@ export type ArticleResolvers<ContextType = QueryContext, ParentType extends Reso
1178
1254
  firstPublishedDate?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
1179
1255
  id?: Resolver<ResolversTypes['ID'], ParentType, ContextType>;
1180
1256
  mainImage?: Resolver<Maybe<ResolversTypes['Image']>, ParentType, ContextType>;
1257
+ originatingParty?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
1181
1258
  publishedDate?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
1182
1259
  standfirst?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
1183
1260
  teaser?: Resolver<Maybe<ResolversTypes['Teaser']>, ParentType, ContextType>;
@@ -1203,6 +1280,7 @@ export type AudioResolvers<ContextType = QueryContext, ParentType extends Resolv
1203
1280
  id?: Resolver<ResolversTypes['ID'], ParentType, ContextType>;
1204
1281
  mainImage?: Resolver<Maybe<ResolversTypes['Image']>, ParentType, ContextType>;
1205
1282
  media?: Resolver<Maybe<ReadonlyArray<Maybe<ResolversTypes['Media']>>>, ParentType, ContextType>;
1283
+ originatingParty?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
1206
1284
  publishedDate?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
1207
1285
  standfirst?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
1208
1286
  teaser?: Resolver<Maybe<ResolversTypes['Teaser']>, ParentType, ContextType>;
@@ -1244,6 +1322,57 @@ export interface CanBeSyndicatedScalarConfig extends GraphQLScalarTypeConfig<Res
1244
1322
  name: 'CanBeSyndicated';
1245
1323
  }
1246
1324
 
1325
+ export type CaptionResolvers<ContextType = QueryContext, ParentType extends ResolversParentTypes['Caption'] = ResolversParentTypes['Caption']> = ResolversObject<{
1326
+ mediaType?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
1327
+ url?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
1328
+ __isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
1329
+ }>;
1330
+
1331
+ export type ClipResolvers<ContextType = QueryContext, ParentType extends ResolversParentTypes['Clip'] = ResolversParentTypes['Clip']> = ResolversObject<{
1332
+ dataSource?: Resolver<ReadonlyArray<ResolversTypes['ClipSource']>, ParentType, ContextType>;
1333
+ format?: Resolver<Maybe<ResolversTypes['ClipFormat']>, ParentType, ContextType>;
1334
+ id?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
1335
+ poster?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
1336
+ type?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
1337
+ __isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
1338
+ }>;
1339
+
1340
+ export interface ClipFormatScalarConfig extends GraphQLScalarTypeConfig<ResolversTypes['ClipFormat'], any> {
1341
+ name: 'ClipFormat';
1342
+ }
1343
+
1344
+ export type ClipSetResolvers<ContextType = QueryContext, ParentType extends ResolversParentTypes['ClipSet'] = ResolversParentTypes['ClipSet']> = ResolversObject<{
1345
+ accessibility?: Resolver<Maybe<ResolversTypes['Accessibility']>, ParentType, ContextType>;
1346
+ autoplay?: Resolver<Maybe<ResolversTypes['Boolean']>, ParentType, ContextType>;
1347
+ caption?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
1348
+ clips?: Resolver<Maybe<ReadonlyArray<Maybe<ResolversTypes['Clip']>>>, ParentType, ContextType>;
1349
+ contentWarning?: Resolver<Maybe<ReadonlyArray<Maybe<ResolversTypes['String']>>>, ParentType, ContextType>;
1350
+ credits?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
1351
+ dataLayout?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
1352
+ description?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
1353
+ displayTitle?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
1354
+ id?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
1355
+ loop?: Resolver<Maybe<ResolversTypes['Boolean']>, ParentType, ContextType>;
1356
+ muted?: Resolver<Maybe<ResolversTypes['Boolean']>, ParentType, ContextType>;
1357
+ noAudio?: Resolver<Maybe<ResolversTypes['Boolean']>, ParentType, ContextType>;
1358
+ publishedDate?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
1359
+ source?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
1360
+ subtitle?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
1361
+ type?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
1362
+ __isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
1363
+ }>;
1364
+
1365
+ export type ClipSourceResolvers<ContextType = QueryContext, ParentType extends ResolversParentTypes['ClipSource'] = ResolversParentTypes['ClipSource']> = ResolversObject<{
1366
+ audioCodec?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
1367
+ binaryUrl?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
1368
+ duration?: Resolver<Maybe<ResolversTypes['Int']>, ParentType, ContextType>;
1369
+ mediaType?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
1370
+ pixelHeight?: Resolver<Maybe<ResolversTypes['Int']>, ParentType, ContextType>;
1371
+ pixelWidth?: Resolver<Maybe<ResolversTypes['Int']>, ParentType, ContextType>;
1372
+ videoCodec?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
1373
+ __isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
1374
+ }>;
1375
+
1247
1376
  export type ConceptResolvers<ContextType = QueryContext, ParentType extends ResolversParentTypes['Concept'] = ResolversParentTypes['Concept']> = ResolversObject<{
1248
1377
  apiUrl?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
1249
1378
  directType?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
@@ -1272,6 +1401,7 @@ export type ContentResolvers<ContextType = QueryContext, ParentType extends Reso
1272
1401
  firstPublishedDate?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
1273
1402
  id?: Resolver<ResolversTypes['ID'], ParentType, ContextType>;
1274
1403
  mainImage?: Resolver<Maybe<ResolversTypes['Image']>, ParentType, ContextType>;
1404
+ originatingParty?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
1275
1405
  publishedDate?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
1276
1406
  standfirst?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
1277
1407
  teaser?: Resolver<Maybe<ResolversTypes['Teaser']>, ParentType, ContextType>;
@@ -1297,6 +1427,7 @@ export type ContentPackageResolvers<ContextType = QueryContext, ParentType exten
1297
1427
  firstPublishedDate?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
1298
1428
  id?: Resolver<ResolversTypes['ID'], ParentType, ContextType>;
1299
1429
  mainImage?: Resolver<Maybe<ResolversTypes['Image']>, ParentType, ContextType>;
1430
+ originatingParty?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
1300
1431
  publishedDate?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
1301
1432
  standfirst?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
1302
1433
  tableOfContents?: Resolver<Maybe<ResolversTypes['TableOfContents']>, ParentType, ContextType>;
@@ -1583,6 +1714,7 @@ export type LiveBlogPackageResolvers<ContextType = QueryContext, ParentType exte
1583
1714
  id?: Resolver<ResolversTypes['ID'], ParentType, ContextType>;
1584
1715
  liveBlogPosts?: Resolver<Maybe<ReadonlyArray<Maybe<ResolversTypes['Content']>>>, ParentType, ContextType>;
1585
1716
  mainImage?: Resolver<Maybe<ResolversTypes['Image']>, ParentType, ContextType>;
1717
+ originatingParty?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
1586
1718
  pinnedPost?: Resolver<Maybe<ResolversTypes['Content']>, ParentType, ContextType>;
1587
1719
  publishedDate?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
1588
1720
  realtime?: Resolver<Maybe<ResolversTypes['Boolean']>, ParentType, ContextType>;
@@ -1610,6 +1742,7 @@ export type LiveBlogPostResolvers<ContextType = QueryContext, ParentType extends
1610
1742
  firstPublishedDate?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
1611
1743
  id?: Resolver<ResolversTypes['ID'], ParentType, ContextType>;
1612
1744
  mainImage?: Resolver<Maybe<ResolversTypes['Image']>, ParentType, ContextType>;
1745
+ originatingParty?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
1613
1746
  publishedDate?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
1614
1747
  standfirst?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
1615
1748
  teaser?: Resolver<Maybe<ResolversTypes['Teaser']>, ParentType, ContextType>;
@@ -1721,6 +1854,7 @@ export type PlaceholderResolvers<ContextType = QueryContext, ParentType extends
1721
1854
  firstPublishedDate?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
1722
1855
  id?: Resolver<ResolversTypes['ID'], ParentType, ContextType>;
1723
1856
  mainImage?: Resolver<Maybe<ResolversTypes['Image']>, ParentType, ContextType>;
1857
+ originatingParty?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
1724
1858
  publishedDate?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
1725
1859
  standfirst?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
1726
1860
  teaser?: Resolver<Maybe<ResolversTypes['Teaser']>, ParentType, ContextType>;
@@ -1767,7 +1901,7 @@ export type RecommendedResolvers<ContextType = QueryContext, ParentType extends
1767
1901
  }>;
1768
1902
 
1769
1903
  export type ReferenceResolvers<ContextType = QueryContext, ParentType extends ResolversParentTypes['Reference'] = ResolversParentTypes['Reference']> = ResolversObject<{
1770
- __resolveType?: TypeResolveFn<'Flourish' | 'ImageSet' | 'LayoutImage' | 'MainImage' | 'RawImage' | 'Recommended' | 'ScrollyImage' | 'Tweet' | 'VideoReference', ParentType, ContextType>;
1904
+ __resolveType?: TypeResolveFn<'ClipSet' | 'Flourish' | 'ImageSet' | 'LayoutImage' | 'MainImage' | 'RawImage' | 'Recommended' | 'ScrollyImage' | 'Tweet' | 'VideoReference', ParentType, ContextType>;
1771
1905
  type?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
1772
1906
  }>;
1773
1907
 
@@ -1901,6 +2035,7 @@ export type VideoResolvers<ContextType = QueryContext, ParentType extends Resolv
1901
2035
  firstPublishedDate?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
1902
2036
  id?: Resolver<ResolversTypes['ID'], ParentType, ContextType>;
1903
2037
  mainImage?: Resolver<Maybe<ResolversTypes['Image']>, ParentType, ContextType>;
2038
+ originatingParty?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
1904
2039
  publishedDate?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
1905
2040
  standfirst?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
1906
2041
  teaser?: Resolver<Maybe<ResolversTypes['Teaser']>, ParentType, ContextType>;
@@ -1920,6 +2055,7 @@ export type VideoReferenceResolvers<ContextType = QueryContext, ParentType exten
1920
2055
 
1921
2056
  export type Resolvers<ContextType = QueryContext> = ResolversObject<{
1922
2057
  AccessLevel?: GraphQLScalarType;
2058
+ Accessibility?: AccessibilityResolvers<ContextType>;
1923
2059
  AltStandfirst?: AltStandfirstResolvers<ContextType>;
1924
2060
  AltTitle?: AltTitleResolvers<ContextType>;
1925
2061
  Article?: ArticleResolvers<ContextType>;
@@ -1927,6 +2063,11 @@ export type Resolvers<ContextType = QueryContext> = ResolversObject<{
1927
2063
  BasicTopper?: BasicTopperResolvers<ContextType>;
1928
2064
  BrandedTopper?: BrandedTopperResolvers<ContextType>;
1929
2065
  CanBeSyndicated?: GraphQLScalarType;
2066
+ Caption?: CaptionResolvers<ContextType>;
2067
+ Clip?: ClipResolvers<ContextType>;
2068
+ ClipFormat?: GraphQLScalarType;
2069
+ ClipSet?: ClipSetResolvers<ContextType>;
2070
+ ClipSource?: ClipSourceResolvers<ContextType>;
1930
2071
  Concept?: ConceptResolvers<ContextType>;
1931
2072
  Content?: ContentResolvers<ContextType>;
1932
2073
  ContentPackage?: ContentPackageResolvers<ContextType>;
@@ -2,6 +2,7 @@ import type {
2
2
  ImageSet,
3
3
  ContentTypeSchemas,
4
4
  MainImage,
5
+ ClipSet,
5
6
  } from '../types/internal-content'
6
7
  import conceptIds from '@financial-times/n-concept-ids'
7
8
  import metadata from '@financial-times/n-display-metadata'
@@ -125,7 +126,7 @@ export class CapiResponse {
125
126
  /*
126
127
  * Check if the incoming data matches the types defined in our data source schema
127
128
  * Our data source schema should handle all possible response from CAPI
128
- * As there is no agreed schema provided by CAPI there is a chance it will out of date / incorrect at times
129
+ * As there is no agreed schema provided by CAPI there is a chance it will be out of date / incorrect at times
129
130
  * Manual updates will be required at times to keep it in sync with the responses we receive
130
131
  */
131
132
  const schemaResponse = model.schema().safeParse(content)
@@ -177,7 +178,7 @@ export class CapiResponse {
177
178
  }
178
179
  return null
179
180
  }
180
- embeds(): ImageSet[] {
181
+ embeds(): (ImageSet | ClipSet)[] {
181
182
  if ('embeds' in this.capiData && this.capiData.embeds)
182
183
  return this.capiData.embeds
183
184
  return []
@@ -239,6 +240,15 @@ export class CapiResponse {
239
240
  canBeSyndicated(): LiteralUnionScalarValues<typeof CanBeSyndicated> {
240
241
  return this.capiData.canBeSyndicated
241
242
  }
243
+ originatingParty(): string | null {
244
+ return this.capiData.canBeDistributed === 'no' &&
245
+ this.annotations().some((annotation) => {
246
+ annotation.id() ===
247
+ 'http://api.ft.com/things/ed3b6ec5-6466-47ef-b1d8-16952fd522c7'
248
+ })
249
+ ? 'Reuters'
250
+ : 'FT'
251
+ }
242
252
  summary() {
243
253
  if ('summary' in this.capiData) return this.capiData.summary
244
254
  return null
@@ -0,0 +1,75 @@
1
+ import { uuidFromUrl } from '../helpers/metadata'
2
+ import { Clip as ClipMetadata } from '../types/internal-content'
3
+ import {
4
+ LiteralUnionScalarValues,
5
+ validLiteralUnionValue,
6
+ } from '../resolvers/literal-union'
7
+ import { ClipFormat } from '../resolvers/scalars'
8
+
9
+ export type ClipSource = {
10
+ binaryUrl: string
11
+ mediaType: string
12
+ audioCodec?: string
13
+ duration?: number
14
+ pixelHeight?: number
15
+ pixelWidth?: number
16
+ videoCodec?: string
17
+ }
18
+
19
+ export interface ClipVideo {
20
+ id(): string
21
+ type(): string
22
+ format(): LiteralUnionScalarValues<typeof ClipFormat>
23
+ poster(): string
24
+ dataSource(): ClipSource[]
25
+ }
26
+
27
+ export class Clip implements ClipVideo {
28
+ constructor(private clip: ClipMetadata) {}
29
+
30
+ type() {
31
+ return 'clip'
32
+ }
33
+
34
+ id() {
35
+ const uuid = uuidFromUrl(this.clip.id)
36
+ if (!uuid) {
37
+ throw new Error(`${this.clip.id} is not a valid Content API Clip ID`)
38
+ }
39
+ return uuid
40
+ }
41
+
42
+ format(): LiteralUnionScalarValues<typeof ClipFormat> {
43
+ if (this.clip.format) {
44
+ const capiFormat = this.clip.format
45
+
46
+ if (capiFormat === 'standardInline') {
47
+ return 'standard-inline'
48
+ }
49
+
50
+ if (validLiteralUnionValue(this.clip.format, ClipFormat.values)) {
51
+ return capiFormat
52
+ }
53
+ }
54
+
55
+ return 'standard-inline'
56
+ }
57
+
58
+ dataSource() {
59
+ // Order clip dataSource to have an order of video formats first then audio/mpeg, as the browser will first check if it can play the MIME type of the first source
60
+ const dataSource = this.clip.dataSource.slice().sort((a, b) => {
61
+ if (a.mediaType === 'video/mp4' && b.mediaType !== 'video/mp4') {
62
+ return -1
63
+ }
64
+ if (a.mediaType !== 'video/mp4' && b.mediaType === 'video/mp4') {
65
+ return 1
66
+ }
67
+ return 0
68
+ })
69
+ return dataSource as ClipSource[]
70
+ }
71
+
72
+ poster() {
73
+ return this.clip.poster?.members[0].binaryUrl ?? ''
74
+ }
75
+ }