@gaulatti/giorgia 0.1.57

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 (194) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +45 -0
  3. package/dist/carousels.d.ts +1 -0
  4. package/dist/carousels.js +65 -0
  5. package/dist/components/live-program/LiveProgram.d.ts +9 -0
  6. package/dist/components/live-program/LiveProgram.js +751 -0
  7. package/dist/components/live-program/assets.d.ts +14 -0
  8. package/dist/components/live-program/assets.js +14 -0
  9. package/dist/components/live-program/components/Marquee.d.ts +16 -0
  10. package/dist/components/live-program/components/Marquee.js +88 -0
  11. package/dist/components/live-program/components/MarqueeCurtain.d.ts +5 -0
  12. package/dist/components/live-program/components/MarqueeCurtain.js +30 -0
  13. package/dist/components/live-program/components/WorldClocks.d.ts +19 -0
  14. package/dist/components/live-program/components/WorldClocks.js +101 -0
  15. package/dist/components/live-program/components/slides/ArticleSlide.d.ts +14 -0
  16. package/dist/components/live-program/components/slides/ArticleSlide.js +32 -0
  17. package/dist/components/live-program/components/slides/CallsignSlide.d.ts +6 -0
  18. package/dist/components/live-program/components/slides/CallsignSlide.js +49 -0
  19. package/dist/components/live-program/components/slides/LiveEventSlide.d.ts +9 -0
  20. package/dist/components/live-program/components/slides/LiveEventSlide.js +86 -0
  21. package/dist/components/live-program/components/slides/slideStyles.d.ts +1 -0
  22. package/dist/components/live-program/components/slides/slideStyles.js +64 -0
  23. package/dist/components/live-program/events.d.ts +34 -0
  24. package/dist/components/live-program/events.js +167 -0
  25. package/dist/components/live-program/hooks/useSSE.d.ts +11 -0
  26. package/dist/components/live-program/hooks/useSSE.js +107 -0
  27. package/dist/components/live-program/i18n.d.ts +4 -0
  28. package/dist/components/live-program/i18n.js +305 -0
  29. package/dist/components/live-program/segments/ArticlesSegment.d.ts +6 -0
  30. package/dist/components/live-program/segments/ArticlesSegment.js +160 -0
  31. package/dist/components/live-program/segments/EarthquakeSegment.d.ts +16 -0
  32. package/dist/components/live-program/segments/EarthquakeSegment.js +130 -0
  33. package/dist/components/live-program/segments/LiveEventSegment.d.ts +4 -0
  34. package/dist/components/live-program/segments/LiveEventSegment.js +27 -0
  35. package/dist/components/live-program/segments/MarketsSegment.d.ts +12 -0
  36. package/dist/components/live-program/segments/MarketsSegment.js +76 -0
  37. package/dist/components/live-program/segments/WeatherSegment.d.ts +15 -0
  38. package/dist/components/live-program/segments/WeatherSegment.js +119 -0
  39. package/dist/components/live-program/segments/fetchLiveEvents.d.ts +20 -0
  40. package/dist/components/live-program/segments/fetchLiveEvents.js +76 -0
  41. package/dist/components/live-program/segments/index.d.ts +8 -0
  42. package/dist/components/live-program/segments/index.js +8 -0
  43. package/dist/components/live-program/segments/types.d.ts +23 -0
  44. package/dist/components/live-program/segments/types.js +1 -0
  45. package/dist/components/live-program/segments/usePlaylistEngine.d.ts +9 -0
  46. package/dist/components/live-program/segments/usePlaylistEngine.js +108 -0
  47. package/dist/components/live-program/utils/broadcastTime.d.ts +12 -0
  48. package/dist/components/live-program/utils/broadcastTime.js +33 -0
  49. package/dist/fonts/LDIcapOFNxEwR-Bd1O9uYNmnUQomAgE25imKSbHhROjLsZBWTSrQGD_jZtU.ttf +0 -0
  50. package/dist/fonts/LDIcapOFNxEwR-Bd1O9uYNmnUQomAgE25imKSbHhROjLsZBWTSrQGFPjZtU.ttf +0 -0
  51. package/dist/fonts/LDIcapOFNxEwR-Bd1O9uYNmnUQomAgE25imKSbHhROjLsZBWTSrQGGHiZtU.ttf +0 -0
  52. package/dist/fonts/LDIcapOFNxEwR-Bd1O9uYNmnUQomAgE25imKSbHhROjLsZBWTSrQGGHjZtU.ttf +0 -0
  53. package/dist/fonts/LDIcapOFNxEwR-Bd1O9uYNmnUQomAgE25imKSbHhROjLsZBWTSrQGIbkZtU.ttf +0 -0
  54. package/dist/fonts/LDIcapOFNxEwR-Bd1O9uYNmnUQomAgE25imKSbHhROjLsZBWTSrQGL_kZtU.ttf +0 -0
  55. package/dist/fonts/LDIcapOFNxEwR-Bd1O9uYNmnUQomAgE25imKSbHhROjLsZBWTSrQGMjkZtU.ttf +0 -0
  56. package/dist/fonts/LDIcapOFNxEwR-Bd1O9uYNmnUQomAgE25imKSbHhROjLsZBWTSrQGOHjZtU.ttf +0 -0
  57. package/dist/fonts/LDIcapOFNxEwR-Bd1O9uYNmnUQomAgE25imKSbHhROjLsZBWTSrQGOHkZtU.ttf +0 -0
  58. package/dist/fonts/SlGDmQSNjdsmc35JDF1K5E55YMjF_7DPuGi-2fRUAw.ttf +0 -0
  59. package/dist/fonts/SlGDmQSNjdsmc35JDF1K5E55YMjF_7DPuGi-6_RUAw.ttf +0 -0
  60. package/dist/fonts/SlGDmQSNjdsmc35JDF1K5E55YMjF_7DPuGi-DPNUAw.ttf +0 -0
  61. package/dist/fonts/SlGDmQSNjdsmc35JDF1K5E55YMjF_7DPuGi-NfNUAw.ttf +0 -0
  62. package/dist/fonts/SlGDmQSNjdsmc35JDF1K5E55YMjF_7DPuGi-a_NUAw.ttf +0 -0
  63. package/dist/fonts/SlGFmQSNjdsmc35JDF1K5GRwUjcdlttVFm-rI7c8R496.ttf +0 -0
  64. package/dist/fonts/SlGFmQSNjdsmc35JDF1K5GRwUjcdlttVFm-rI7dbR496.ttf +0 -0
  65. package/dist/fonts/SlGFmQSNjdsmc35JDF1K5GRwUjcdlttVFm-rI7diR496.ttf +0 -0
  66. package/dist/fonts/SlGFmQSNjdsmc35JDF1K5GRwUjcdlttVFm-rI7e8QI96.ttf +0 -0
  67. package/dist/fonts/SlGFmQSNjdsmc35JDF1K5GRwUjcdlttVFm-rI7eOQI96.ttf +0 -0
  68. package/dist/fonts/TK3_WkUHHAIjg75cFRf3bXL8LICs13FvgUE.ttf +0 -0
  69. package/dist/fonts/TK3_WkUHHAIjg75cFRf3bXL8LICs169vgUE.ttf +0 -0
  70. package/dist/fonts/TK3_WkUHHAIjg75cFRf3bXL8LICs18NvgUE.ttf +0 -0
  71. package/dist/fonts/TK3_WkUHHAIjg75cFRf3bXL8LICs1_FvgUE.ttf +0 -0
  72. package/dist/fonts/TK3_WkUHHAIjg75cFRf3bXL8LICs1xZogUE.ttf +0 -0
  73. package/dist/fonts/TK3_WkUHHAIjg75cFRf3bXL8LICs1y9ogUE.ttf +0 -0
  74. package/dist/fonts/fonts.css +378 -0
  75. package/dist/fonts/j8_16_LD37rqfuwxyIuaZhE6cRXOLtm2gfTGgQ.ttf +0 -0
  76. package/dist/fonts/j8_46_LD37rqfuwxyIuaZhE6cRXOLtm2gfT-BYipBw.ttf +0 -0
  77. package/dist/fonts/j8_46_LD37rqfuwxyIuaZhE6cRXOLtm2gfT-IYmpBw.ttf +0 -0
  78. package/dist/fonts/j8_46_LD37rqfuwxyIuaZhE6cRXOLtm2gfT-PYqpBw.ttf +0 -0
  79. package/dist/fonts/j8_46_LD37rqfuwxyIuaZhE6cRXOLtm2gfT-WYupBw.ttf +0 -0
  80. package/dist/fonts/jizMREVItHgc8qDIbSTKq4XkRiUawTk7f45UM9y05oYiRNDM.ttf +0 -0
  81. package/dist/fonts/jizMREVItHgc8qDIbSTKq4XkRiUawTk7f45UM9y05oZ8RNDM.ttf +0 -0
  82. package/dist/fonts/jizMREVItHgc8qDIbSTKq4XkRiUawTk7f45UM9y05oZ8RdDM.ttf +0 -0
  83. package/dist/fonts/jizMREVItHgc8qDIbSTKq4XkRiUawTk7f45UM9y05oZORNDM.ttf +0 -0
  84. package/dist/fonts/jizMREVItHgc8qDIbSTKq4XkRiUawTk7f45UM9y05oabQ9DM.ttf +0 -0
  85. package/dist/fonts/jizMREVItHgc8qDIbSTKq4XkRiUawTk7f45UM9y05oaiQ9DM.ttf +0 -0
  86. package/dist/fonts/jizMREVItHgc8qDIbSTKq4XkRiUawTk7f45UM9y05ob8Q9DM.ttf +0 -0
  87. package/dist/fonts/jizMREVItHgc8qDIbSTKq4XkRiUawTk7f45UM9y05ob8RNDM.ttf +0 -0
  88. package/dist/fonts/jizMREVItHgc8qDIbSTKq4XkRiUawTk7f45UM9y05obVQ9DM.ttf +0 -0
  89. package/dist/fonts/jizOREVItHgc8qDIbSTKq4XkRg8T88bjFuXOnduh8MKUBw.ttf +0 -0
  90. package/dist/fonts/jizOREVItHgc8qDIbSTKq4XkRg8T88bjFuXOnduhHMWUBw.ttf +0 -0
  91. package/dist/fonts/jizOREVItHgc8qDIbSTKq4XkRg8T88bjFuXOnduhLsSUBw.ttf +0 -0
  92. package/dist/fonts/jizOREVItHgc8qDIbSTKq4XkRg8T88bjFuXOnduhLsWUBw.ttf +0 -0
  93. package/dist/fonts/jizOREVItHgc8qDIbSTKq4XkRg8T88bjFuXOnduhcMWUBw.ttf +0 -0
  94. package/dist/fonts/jizOREVItHgc8qDIbSTKq4XkRg8T88bjFuXOnduhh8KUBw.ttf +0 -0
  95. package/dist/fonts/jizOREVItHgc8qDIbSTKq4XkRg8T88bjFuXOnduhrsKUBw.ttf +0 -0
  96. package/dist/fonts/jizOREVItHgc8qDIbSTKq4XkRg8T88bjFuXOnduhrsWUBw.ttf +0 -0
  97. package/dist/fonts/jizOREVItHgc8qDIbSTKq4XkRg8T88bjFuXOnduhycKUBw.ttf +0 -0
  98. package/dist/homepage-distributor.d.ts +55 -0
  99. package/dist/homepage-distributor.js +68 -0
  100. package/dist/instagram-image-template.d.ts +9 -0
  101. package/dist/instagram-image-template.js +51 -0
  102. package/dist/live-program/main.d.ts +1 -0
  103. package/dist/live-program/main.js +10 -0
  104. package/dist/live-program-page/fifthbell/audio/pipes.ogg +0 -0
  105. package/dist/live-program-page/fifthbell/images/berlin.jpg +0 -0
  106. package/dist/live-program-page/fifthbell/images/fifthbell.png +0 -0
  107. package/dist/live-program-page/fifthbell/images/nyc.jpg +0 -0
  108. package/dist/live-program-page/fifthbell/images/nyse.jpg +0 -0
  109. package/dist/live-program-page/fifthbell/images/santiago.jpg +0 -0
  110. package/dist/live-program-page/fifthbell/images/seismograph.jpg +0 -0
  111. package/dist/live-program-page/fifthbell/images/tokyo.jpg +0 -0
  112. package/dist/live-program-page/index.html +16 -0
  113. package/dist/live-program-page/live-program.css +3 -0
  114. package/dist/live-program-page/live-program.js +76 -0
  115. package/dist/outlet-config.d.ts +29 -0
  116. package/dist/outlet-config.js +29 -0
  117. package/dist/renderer.browser.d.ts +2 -0
  118. package/dist/renderer.browser.js +132 -0
  119. package/dist/renderer.core.d.ts +9 -0
  120. package/dist/renderer.core.js +354 -0
  121. package/dist/renderer.d.ts +6 -0
  122. package/dist/renderer.js +4 -0
  123. package/dist/renderer.node.d.ts +16 -0
  124. package/dist/renderer.node.js +166 -0
  125. package/dist/types/canonical-article.d.ts +249 -0
  126. package/dist/types/canonical-article.js +236 -0
  127. package/dist/utils/sofascore.d.ts +3 -0
  128. package/dist/utils/sofascore.js +31 -0
  129. package/dist/version.d.ts +1 -0
  130. package/dist/version.js +4 -0
  131. package/package.json +89 -0
  132. package/src/partial-deps.json +53 -0
  133. package/src/styles/compiled.css +2 -0
  134. package/src/templates/layouts/404.hbs +5 -0
  135. package/src/templates/layouts/article-page.hbs +5 -0
  136. package/src/templates/layouts/category-page.hbs +5 -0
  137. package/src/templates/layouts/homepage.hbs +5 -0
  138. package/src/templates/layouts/link-in-bio.hbs +226 -0
  139. package/src/templates/layouts/live-story.hbs +5 -0
  140. package/src/templates/layouts/media-page.hbs +5 -0
  141. package/src/templates/layouts/search-page.hbs +5 -0
  142. package/src/templates/partials/blocks/audio.hbs +12 -0
  143. package/src/templates/partials/blocks/data-table.hbs +23 -0
  144. package/src/templates/partials/blocks/divider.hbs +1 -0
  145. package/src/templates/partials/blocks/heading.hbs +9 -0
  146. package/src/templates/partials/blocks/image.hbs +6 -0
  147. package/src/templates/partials/blocks/info-box.hbs +8 -0
  148. package/src/templates/partials/blocks/instagram.hbs +28 -0
  149. package/src/templates/partials/blocks/key-points.hbs +8 -0
  150. package/src/templates/partials/blocks/list.hbs +13 -0
  151. package/src/templates/partials/blocks/live-update.hbs +24 -0
  152. package/src/templates/partials/blocks/pull-quote.hbs +6 -0
  153. package/src/templates/partials/blocks/rich-text.hbs +1 -0
  154. package/src/templates/partials/blocks/tiktok.hbs +15 -0
  155. package/src/templates/partials/blocks/x.hbs +74 -0
  156. package/src/templates/partials/blocks/youtube.hbs +12 -0
  157. package/src/templates/partials/components/article-main.hbs +159 -0
  158. package/src/templates/partials/components/breaking-news/live-updates-column.hbs +29 -0
  159. package/src/templates/partials/components/breaking-news.hbs +56 -0
  160. package/src/templates/partials/components/category/header.hbs +5 -0
  161. package/src/templates/partials/components/category/main-grid.hbs +55 -0
  162. package/src/templates/partials/components/category/main.hbs +7 -0
  163. package/src/templates/partials/components/category/more-grid.hbs +26 -0
  164. package/src/templates/partials/components/editorial-hero.hbs +73 -0
  165. package/src/templates/partials/components/headline.hbs +15 -0
  166. package/src/templates/partials/components/hero-editorial.hbs +1 -0
  167. package/src/templates/partials/components/hero.hbs +1 -0
  168. package/src/templates/partials/components/home/landing.hbs +111 -0
  169. package/src/templates/partials/components/home/main.hbs +63 -0
  170. package/src/templates/partials/components/home/more-stories.hbs +23 -0
  171. package/src/templates/partials/components/home/must-read.hbs +77 -0
  172. package/src/templates/partials/components/live-story/main.hbs +229 -0
  173. package/src/templates/partials/components/media/main.hbs +220 -0
  174. package/src/templates/partials/components/not-found/main.hbs +28 -0
  175. package/src/templates/partials/components/search/main.hbs +420 -0
  176. package/src/templates/partials/components/snack.hbs +92 -0
  177. package/src/templates/partials/components/spotlight-hero.hbs +59 -0
  178. package/src/templates/partials/components/trending.hbs +14 -0
  179. package/src/templates/partials/components/ui/accordion.hbs +30 -0
  180. package/src/templates/partials/components/ui/breadcrumb.hbs +16 -0
  181. package/src/templates/partials/components/ui/icon-button.hbs +19 -0
  182. package/src/templates/partials/components/ui/loading-spinner.hbs +27 -0
  183. package/src/templates/partials/components/ui/pagination.hbs +56 -0
  184. package/src/templates/partials/components/ui/scroll-area.hbs +12 -0
  185. package/src/templates/partials/components/ui/status-badge.hbs +21 -0
  186. package/src/templates/partials/footers/footer-full.hbs +79 -0
  187. package/src/templates/partials/footers/footer-minimal.hbs +5 -0
  188. package/src/templates/partials/headers/header-main.hbs +400 -0
  189. package/src/templates/partials/headers/header-minimal.hbs +16 -0
  190. package/src/templates/partials/nav/nav-categories.hbs +5 -0
  191. package/src/templates/partials/shell/doc-end.hbs +282 -0
  192. package/src/templates/partials/shell/doc-start-404.hbs +41 -0
  193. package/src/templates/partials/shell/doc-start-standard.hbs +86 -0
  194. package/src/templates/templates/instagram-image.hbs +175 -0
@@ -0,0 +1,166 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { renderWithAssets } from './renderer.core.js';
5
+ const layoutFiles = {
6
+ 'article-page': 'article-page.hbs',
7
+ homepage: 'homepage.hbs',
8
+ 'category-page': 'category-page.hbs',
9
+ 'search-page': 'search-page.hbs',
10
+ '404': '404.hbs',
11
+ 'live-story': 'live-story.hbs',
12
+ 'link-in-bio': 'link-in-bio.hbs',
13
+ 'media-page': 'media-page.hbs'
14
+ };
15
+ function getPaths() {
16
+ const currentFile = fileURLToPath(import.meta.url);
17
+ const currentDir = path.dirname(currentFile);
18
+ const projectRoot = path.resolve(currentDir, '..');
19
+ return {
20
+ layoutsDir: path.join(projectRoot, 'src', 'templates', 'layouts'),
21
+ partialsDir: path.join(projectRoot, 'src', 'templates', 'partials'),
22
+ compiledStylesPath: path.join(projectRoot, 'src', 'styles', 'compiled.css')
23
+ };
24
+ }
25
+ function readPartialsRecursively(dir, root, partials) {
26
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
27
+ for (const entry of entries) {
28
+ const fullPath = path.join(dir, entry.name);
29
+ if (entry.isDirectory()) {
30
+ readPartialsRecursively(fullPath, root, partials);
31
+ continue;
32
+ }
33
+ if (!entry.isFile() || !entry.name.endsWith('.hbs')) {
34
+ continue;
35
+ }
36
+ const partialName = path
37
+ .relative(root, fullPath)
38
+ .replace(/\\/g, '/')
39
+ .replace(/\.hbs$/, '');
40
+ partials[partialName] = fs.readFileSync(fullPath, 'utf8');
41
+ }
42
+ }
43
+ function loadAssetsFromDisk() {
44
+ const { layoutsDir, partialsDir, compiledStylesPath } = getPaths();
45
+ if (!fs.existsSync(compiledStylesPath)) {
46
+ throw new Error('compiled.css not found — run npm run build:css first');
47
+ }
48
+ const layouts = Object.fromEntries(Object.entries(layoutFiles).map(([layout, fileName]) => {
49
+ const fullPath = path.join(layoutsDir, fileName);
50
+ if (!fs.existsSync(fullPath)) {
51
+ throw new Error(`Layout template missing for \"${layout}\": ${fullPath}`);
52
+ }
53
+ return [layout, fs.readFileSync(fullPath, 'utf8')];
54
+ }));
55
+ const partials = {};
56
+ readPartialsRecursively(partialsDir, partialsDir, partials);
57
+ return {
58
+ layouts,
59
+ partials,
60
+ styles: fs.readFileSync(compiledStylesPath, 'utf8')
61
+ };
62
+ }
63
+ let cachedAssets = null;
64
+ function getAssets() {
65
+ if (!cachedAssets) {
66
+ cachedAssets = loadAssetsFromDisk();
67
+ }
68
+ return cachedAssets;
69
+ }
70
+ export function render(document) {
71
+ return renderWithAssets(document, getAssets());
72
+ }
73
+ function liveProgramPageDir() {
74
+ const currentFile = fileURLToPath(import.meta.url);
75
+ const currentDir = path.dirname(currentFile);
76
+ return path.join(currentDir, 'live-program-page');
77
+ }
78
+ export function liveProgramPageHtml() {
79
+ const pageDir = liveProgramPageDir();
80
+ const htmlPath = path.join(pageDir, 'index.html');
81
+ if (!fs.existsSync(htmlPath)) {
82
+ throw new Error(`live-program-page/index.html not found at ${htmlPath} — run npm run build:live-program first`);
83
+ }
84
+ return fs.readFileSync(htmlPath, 'utf-8');
85
+ }
86
+ function fontsDir() {
87
+ const currentFile = fileURLToPath(import.meta.url);
88
+ const currentDir = path.dirname(currentFile);
89
+ return path.join(currentDir, 'fonts');
90
+ }
91
+ export function fontFiles() {
92
+ const dir = fontsDir();
93
+ if (!fs.existsSync(dir)) {
94
+ throw new Error(`fonts directory not found at ${dir} — run npm run build first`);
95
+ }
96
+ const entries = [];
97
+ const items = fs.readdirSync(dir, { withFileTypes: true });
98
+ for (const item of items) {
99
+ if (!item.isFile())
100
+ continue;
101
+ const fullPath = path.join(dir, item.name);
102
+ entries.push({
103
+ key: `content/fonts/${item.name}`,
104
+ body: fs.readFileSync(fullPath),
105
+ contentType: contentTypeForFile(item.name),
106
+ });
107
+ }
108
+ // Also include fonts.css
109
+ const cssPath = path.join(dir, 'fonts.css');
110
+ if (fs.existsSync(cssPath)) {
111
+ entries.push({
112
+ key: 'content/fonts/fonts.css',
113
+ body: fs.readFileSync(cssPath),
114
+ contentType: 'text/css',
115
+ });
116
+ }
117
+ return entries;
118
+ }
119
+ export function liveProgramPageAsset(filename) {
120
+ const pageDir = liveProgramPageDir();
121
+ const assetPath = path.join(pageDir, filename);
122
+ if (!fs.existsSync(assetPath)) {
123
+ throw new Error(`live-program-page/${filename} not found at ${assetPath} — run npm run build:live-program first`);
124
+ }
125
+ return fs.readFileSync(assetPath, 'utf-8');
126
+ }
127
+ const CONTENT_TYPE_MAP = {
128
+ '.html': 'text/html; charset=utf-8',
129
+ '.js': 'application/javascript',
130
+ '.css': 'text/css',
131
+ '.jpg': 'image/jpeg',
132
+ '.jpeg': 'image/jpeg',
133
+ '.png': 'image/png',
134
+ '.ogg': 'audio/ogg',
135
+ '.mp3': 'audio/mpeg',
136
+ };
137
+ function contentTypeForFile(filename) {
138
+ const ext = path.extname(filename).toLowerCase();
139
+ return CONTENT_TYPE_MAP[ext] || 'application/octet-stream';
140
+ }
141
+ export function liveProgramPageFiles() {
142
+ const pageDir = liveProgramPageDir();
143
+ if (!fs.existsSync(pageDir)) {
144
+ throw new Error(`live-program-page directory not found at ${pageDir} — run npm run build:live-program first`);
145
+ }
146
+ const entries = [];
147
+ function walk(dir, prefix) {
148
+ const items = fs.readdirSync(dir, { withFileTypes: true });
149
+ for (const item of items) {
150
+ const fullPath = path.join(dir, item.name);
151
+ const relativeKey = prefix ? `${prefix}/${item.name}` : item.name;
152
+ if (item.isDirectory()) {
153
+ walk(fullPath, relativeKey);
154
+ }
155
+ else if (item.isFile()) {
156
+ entries.push({
157
+ key: relativeKey,
158
+ body: fs.readFileSync(fullPath),
159
+ contentType: contentTypeForFile(item.name),
160
+ });
161
+ }
162
+ }
163
+ }
164
+ walk(pageDir, '');
165
+ return entries;
166
+ }
@@ -0,0 +1,249 @@
1
+ import { z } from 'zod';
2
+ declare const articleReferenceSchema: z.ZodObject<{
3
+ id: z.ZodString;
4
+ url: z.ZodString;
5
+ title: z.ZodString;
6
+ excerpt: z.ZodOptional<z.ZodString>;
7
+ time: z.ZodOptional<z.ZodString>;
8
+ categories: z.ZodDefault<z.ZodArray<z.ZodObject<{
9
+ name: z.ZodString;
10
+ slug: z.ZodString;
11
+ }, z.core.$strip>>>;
12
+ hero: z.ZodOptional<z.ZodObject<{
13
+ url: z.ZodString;
14
+ alt: z.ZodString;
15
+ }, z.core.$strip>>;
16
+ featuredImage: z.ZodOptional<z.ZodObject<{
17
+ url: z.ZodString;
18
+ alt: z.ZodString;
19
+ caption: z.ZodOptional<z.ZodString>;
20
+ }, z.core.$strip>>;
21
+ updatedAt: z.ZodOptional<z.ZodString>;
22
+ publishedAt: z.ZodOptional<z.ZodString>;
23
+ featured: z.ZodOptional<z.ZodBoolean>;
24
+ }, z.core.$loose>;
25
+ export declare const canonicalArticleSchema: z.ZodObject<{
26
+ id: z.ZodCoercedString<unknown>;
27
+ slug: z.ZodString;
28
+ layout: z.ZodEnum<{
29
+ "article-page": "article-page";
30
+ homepage: "homepage";
31
+ "category-page": "category-page";
32
+ "search-page": "search-page";
33
+ 404: "404";
34
+ "live-story": "live-story";
35
+ "link-in-bio": "link-in-bio";
36
+ "media-page": "media-page";
37
+ }>;
38
+ canonicalUrl: z.ZodString;
39
+ contentVersion: z.ZodString;
40
+ publishedAt: z.ZodString;
41
+ updatedAt: z.ZodString;
42
+ status: z.ZodEnum<{
43
+ draft: "draft";
44
+ published: "published";
45
+ }>;
46
+ title: z.ZodString;
47
+ dek: z.ZodOptional<z.ZodString>;
48
+ excerpt: z.ZodOptional<z.ZodString>;
49
+ language: z.ZodEnum<{
50
+ en: "en";
51
+ es: "es";
52
+ it: "it";
53
+ }>;
54
+ sofascore_id: z.ZodOptional<z.ZodNumber>;
55
+ originalArticleId: z.ZodOptional<z.ZodString>;
56
+ featured: z.ZodBoolean;
57
+ authors: z.ZodArray<z.ZodObject<{
58
+ name: z.ZodString;
59
+ slug: z.ZodString;
60
+ }, z.core.$strip>>;
61
+ categories: z.ZodArray<z.ZodObject<{
62
+ name: z.ZodString;
63
+ slug: z.ZodString;
64
+ }, z.core.$strip>>;
65
+ featuredImage: z.ZodOptional<z.ZodObject<{
66
+ url: z.ZodString;
67
+ alt: z.ZodString;
68
+ caption: z.ZodOptional<z.ZodString>;
69
+ }, z.core.$strip>>;
70
+ media: z.ZodOptional<z.ZodArray<z.ZodObject<{
71
+ url: z.ZodString;
72
+ alt: z.ZodString;
73
+ caption: z.ZodOptional<z.ZodString>;
74
+ }, z.core.$strip>>>;
75
+ hero: z.ZodOptional<z.ZodObject<{
76
+ url: z.ZodString;
77
+ alt: z.ZodString;
78
+ }, z.core.$strip>>;
79
+ body: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
80
+ type: z.ZodLiteral<"richText">;
81
+ html: z.ZodString;
82
+ }, z.core.$strip>, z.ZodObject<{
83
+ type: z.ZodLiteral<"heading">;
84
+ text: z.ZodString;
85
+ level: z.ZodDefault<z.ZodUnion<readonly [z.ZodLiteral<2>, z.ZodLiteral<3>, z.ZodLiteral<4>]>>;
86
+ }, z.core.$strip>, z.ZodObject<{
87
+ type: z.ZodLiteral<"image">;
88
+ url: z.ZodString;
89
+ alt: z.ZodString;
90
+ caption: z.ZodOptional<z.ZodString>;
91
+ }, z.core.$strip>, z.ZodObject<{
92
+ type: z.ZodLiteral<"list">;
93
+ ordered: z.ZodDefault<z.ZodBoolean>;
94
+ items: z.ZodArray<z.ZodString>;
95
+ }, z.core.$strip>, z.ZodObject<{
96
+ type: z.ZodLiteral<"divider">;
97
+ }, z.core.$strip>, z.ZodObject<{
98
+ type: z.ZodLiteral<"infoBox">;
99
+ title: z.ZodOptional<z.ZodString>;
100
+ tone: z.ZodDefault<z.ZodEnum<{
101
+ success: "success";
102
+ neutral: "neutral";
103
+ info: "info";
104
+ warning: "warning";
105
+ }>>;
106
+ html: z.ZodString;
107
+ }, z.core.$strip>, z.ZodObject<{
108
+ type: z.ZodLiteral<"keyPoints">;
109
+ title: z.ZodDefault<z.ZodString>;
110
+ points: z.ZodArray<z.ZodString>;
111
+ }, z.core.$strip>, z.ZodObject<{
112
+ type: z.ZodLiteral<"dataTable">;
113
+ caption: z.ZodOptional<z.ZodString>;
114
+ headers: z.ZodArray<z.ZodString>;
115
+ rows: z.ZodArray<z.ZodArray<z.ZodString>>;
116
+ }, z.core.$strip>, z.ZodObject<{
117
+ type: z.ZodLiteral<"liveUpdate">;
118
+ timestamp: z.ZodString;
119
+ headline: z.ZodString;
120
+ html: z.ZodOptional<z.ZodString>;
121
+ media: z.ZodOptional<z.ZodArray<z.ZodObject<{
122
+ url: z.ZodString;
123
+ alt: z.ZodString;
124
+ caption: z.ZodOptional<z.ZodString>;
125
+ }, z.core.$strip>>>;
126
+ }, z.core.$strip>, z.ZodObject<{
127
+ type: z.ZodLiteral<"audio">;
128
+ url: z.ZodString;
129
+ title: z.ZodOptional<z.ZodString>;
130
+ caption: z.ZodOptional<z.ZodString>;
131
+ }, z.core.$strip>, z.ZodObject<{
132
+ type: z.ZodLiteral<"youtube">;
133
+ videoId: z.ZodString;
134
+ }, z.core.$strip>, z.ZodObject<{
135
+ type: z.ZodLiteral<"x">;
136
+ url: z.ZodString;
137
+ }, z.core.$strip>, z.ZodObject<{
138
+ type: z.ZodLiteral<"instagram">;
139
+ url: z.ZodString;
140
+ }, z.core.$strip>, z.ZodObject<{
141
+ type: z.ZodLiteral<"tiktok">;
142
+ url: z.ZodString;
143
+ }, z.core.$strip>, z.ZodObject<{
144
+ type: z.ZodLiteral<"pullQuote">;
145
+ text: z.ZodString;
146
+ attribution: z.ZodOptional<z.ZodString>;
147
+ }, z.core.$strip>], "type">>;
148
+ seo: z.ZodOptional<z.ZodObject<{
149
+ metaTitle: z.ZodOptional<z.ZodString>;
150
+ metaDescription: z.ZodOptional<z.ZodString>;
151
+ ogImage: z.ZodOptional<z.ZodString>;
152
+ }, z.core.$strip>>;
153
+ navigation: z.ZodOptional<z.ZodObject<{
154
+ categories: z.ZodArray<z.ZodObject<{
155
+ name: z.ZodString;
156
+ slug: z.ZodString;
157
+ }, z.core.$strip>>;
158
+ }, z.core.$strip>>;
159
+ articles: z.ZodOptional<z.ZodArray<z.ZodObject<{
160
+ id: z.ZodString;
161
+ url: z.ZodString;
162
+ title: z.ZodString;
163
+ excerpt: z.ZodOptional<z.ZodString>;
164
+ time: z.ZodOptional<z.ZodString>;
165
+ categories: z.ZodDefault<z.ZodArray<z.ZodObject<{
166
+ name: z.ZodString;
167
+ slug: z.ZodString;
168
+ }, z.core.$strip>>>;
169
+ hero: z.ZodOptional<z.ZodObject<{
170
+ url: z.ZodString;
171
+ alt: z.ZodString;
172
+ }, z.core.$strip>>;
173
+ featuredImage: z.ZodOptional<z.ZodObject<{
174
+ url: z.ZodString;
175
+ alt: z.ZodString;
176
+ caption: z.ZodOptional<z.ZodString>;
177
+ }, z.core.$strip>>;
178
+ updatedAt: z.ZodOptional<z.ZodString>;
179
+ publishedAt: z.ZodOptional<z.ZodString>;
180
+ featured: z.ZodOptional<z.ZodBoolean>;
181
+ }, z.core.$loose>>>;
182
+ heroSlides: z.ZodOptional<z.ZodArray<z.ZodObject<{
183
+ image: z.ZodString;
184
+ alt: z.ZodOptional<z.ZodString>;
185
+ }, z.core.$strip>>>;
186
+ heroLayout: z.ZodOptional<z.ZodEnum<{
187
+ spotlight: "spotlight";
188
+ editorial: "editorial";
189
+ }>>;
190
+ heroCategories: z.ZodOptional<z.ZodArray<z.ZodObject<{
191
+ name: z.ZodString;
192
+ slug: z.ZodString;
193
+ }, z.core.$strip>>>;
194
+ showHero: z.ZodOptional<z.ZodBoolean>;
195
+ showEditorialHero: z.ZodOptional<z.ZodBoolean>;
196
+ breakingNews: z.ZodOptional<z.ZodObject<{
197
+ displayClass: z.ZodOptional<z.ZodString>;
198
+ sidebarFeature: z.ZodOptional<z.ZodObject<{
199
+ category: z.ZodString;
200
+ title: z.ZodString;
201
+ url: z.ZodString;
202
+ image: z.ZodString;
203
+ excerpt: z.ZodOptional<z.ZodString>;
204
+ publishedAt: z.ZodOptional<z.ZodString>;
205
+ }, z.core.$strip>>;
206
+ sidebarSub: z.ZodOptional<z.ZodObject<{
207
+ category: z.ZodString;
208
+ title: z.ZodString;
209
+ url: z.ZodString;
210
+ image: z.ZodString;
211
+ alt: z.ZodOptional<z.ZodString>;
212
+ readTime: z.ZodOptional<z.ZodString>;
213
+ excerpt: z.ZodOptional<z.ZodString>;
214
+ }, z.core.$strip>>;
215
+ main: z.ZodOptional<z.ZodObject<{
216
+ category: z.ZodString;
217
+ title: z.ZodString;
218
+ url: z.ZodString;
219
+ liveUrl: z.ZodOptional<z.ZodString>;
220
+ sofascore_id: z.ZodOptional<z.ZodNumber>;
221
+ image: z.ZodString;
222
+ alt: z.ZodOptional<z.ZodString>;
223
+ excerpt: z.ZodOptional<z.ZodString>;
224
+ }, z.core.$strip>>;
225
+ updates: z.ZodOptional<z.ZodArray<z.ZodObject<{
226
+ timestamp: z.ZodOptional<z.ZodString>;
227
+ time: z.ZodOptional<z.ZodString>;
228
+ text: z.ZodOptional<z.ZodString>;
229
+ html: z.ZodOptional<z.ZodString>;
230
+ }, z.core.$strip>>>;
231
+ snacks: z.ZodOptional<z.ZodArray<z.ZodObject<{
232
+ category: z.ZodOptional<z.ZodString>;
233
+ readTime: z.ZodOptional<z.ZodString>;
234
+ title: z.ZodString;
235
+ url: z.ZodString;
236
+ excerpt: z.ZodOptional<z.ZodString>;
237
+ image: z.ZodOptional<z.ZodString>;
238
+ alt: z.ZodOptional<z.ZodString>;
239
+ }, z.core.$strip>>>;
240
+ }, z.core.$strip>>;
241
+ liveStory: z.ZodOptional<z.ZodObject<{
242
+ lastUpdated: z.ZodOptional<z.ZodString>;
243
+ keyPoints: z.ZodOptional<z.ZodArray<z.ZodString>>;
244
+ }, z.core.$strip>>;
245
+ }, z.core.$loose>;
246
+ export type SelfReference = z.infer<typeof articleReferenceSchema>;
247
+ export type CanonicalArticle = z.infer<typeof canonicalArticleSchema>;
248
+ export type CanonicalDocument = CanonicalArticle;
249
+ export {};
@@ -0,0 +1,236 @@
1
+ import { z } from 'zod';
2
+ const isoDateTime = z.string().datetime();
3
+ const authorSchema = z.object({
4
+ name: z.string(),
5
+ slug: z.string()
6
+ });
7
+ const categorySchema = z.object({
8
+ name: z.string(),
9
+ slug: z.string()
10
+ });
11
+ const featuredImageSchema = z.object({
12
+ url: z.string(),
13
+ alt: z.string(),
14
+ caption: z.string().optional()
15
+ });
16
+ const heroSchema = z.object({
17
+ url: z.string(),
18
+ alt: z.string()
19
+ });
20
+ const bodyBlockSchema = z.discriminatedUnion('type', [
21
+ z.object({
22
+ type: z.literal('richText'),
23
+ html: z.string()
24
+ }),
25
+ z.object({
26
+ type: z.literal('heading'),
27
+ text: z.string(),
28
+ level: z.union([z.literal(2), z.literal(3), z.literal(4)]).default(2)
29
+ }),
30
+ z.object({
31
+ type: z.literal('image'),
32
+ url: z.string(),
33
+ alt: z.string(),
34
+ caption: z.string().optional()
35
+ }),
36
+ z.object({
37
+ type: z.literal('list'),
38
+ ordered: z.boolean().default(false),
39
+ items: z.array(z.string()).min(1)
40
+ }),
41
+ z.object({
42
+ type: z.literal('divider')
43
+ }),
44
+ z.object({
45
+ type: z.literal('infoBox'),
46
+ title: z.string().optional(),
47
+ tone: z.enum(['neutral', 'info', 'warning', 'success']).default('neutral'),
48
+ html: z.string()
49
+ }),
50
+ z.object({
51
+ type: z.literal('keyPoints'),
52
+ title: z.string().default('Key Points'),
53
+ points: z.array(z.string()).min(1)
54
+ }),
55
+ z.object({
56
+ type: z.literal('dataTable'),
57
+ caption: z.string().optional(),
58
+ headers: z.array(z.string()).min(1),
59
+ rows: z.array(z.array(z.string())).min(1)
60
+ }),
61
+ z.object({
62
+ type: z.literal('liveUpdate'),
63
+ timestamp: isoDateTime,
64
+ headline: z.string(),
65
+ html: z.string().optional(),
66
+ media: z
67
+ .array(z.object({
68
+ url: z.string(),
69
+ alt: z.string(),
70
+ caption: z.string().optional()
71
+ }))
72
+ .optional()
73
+ }),
74
+ z.object({
75
+ type: z.literal('audio'),
76
+ url: z.string().url(),
77
+ title: z.string().optional(),
78
+ caption: z.string().optional()
79
+ }),
80
+ z.object({
81
+ type: z.literal('youtube'),
82
+ videoId: z.string()
83
+ }),
84
+ z.object({
85
+ type: z.literal('x'),
86
+ url: z.string().url()
87
+ }),
88
+ z.object({
89
+ type: z.literal('instagram'),
90
+ url: z.string().url()
91
+ }),
92
+ z.object({
93
+ type: z.literal('tiktok'),
94
+ url: z.string().url()
95
+ }),
96
+ z.object({
97
+ type: z.literal('pullQuote'),
98
+ text: z.string(),
99
+ attribution: z.string().optional()
100
+ })
101
+ ]);
102
+ const articleReferenceSchema = z
103
+ .object({
104
+ id: z.string().uuid(),
105
+ url: z.string(),
106
+ title: z.string(),
107
+ excerpt: z.string().optional(),
108
+ time: z.string().optional(),
109
+ categories: z.array(categorySchema).default([]),
110
+ hero: heroSchema.optional(),
111
+ featuredImage: featuredImageSchema.optional(),
112
+ updatedAt: isoDateTime.optional(),
113
+ publishedAt: isoDateTime.optional(),
114
+ featured: z.boolean().optional()
115
+ })
116
+ .passthrough();
117
+ export const canonicalArticleSchema = z
118
+ .object({
119
+ id: z.coerce.string(),
120
+ slug: z.string(),
121
+ layout: z.enum([
122
+ 'article-page',
123
+ 'homepage',
124
+ 'category-page',
125
+ 'search-page',
126
+ '404',
127
+ 'live-story',
128
+ 'link-in-bio',
129
+ 'media-page',
130
+ ]),
131
+ canonicalUrl: z.string(),
132
+ contentVersion: isoDateTime,
133
+ publishedAt: isoDateTime,
134
+ updatedAt: isoDateTime,
135
+ status: z.enum(['draft', 'published']),
136
+ title: z.string(),
137
+ dek: z.string().optional(),
138
+ excerpt: z.string().optional(),
139
+ language: z.enum(['en', 'es', 'it']),
140
+ sofascore_id: z.number().int().positive().optional(),
141
+ originalArticleId: z.string().optional(),
142
+ featured: z.boolean(),
143
+ authors: z.array(authorSchema),
144
+ categories: z.array(categorySchema),
145
+ featuredImage: featuredImageSchema.optional(),
146
+ media: z.array(featuredImageSchema).optional(),
147
+ hero: heroSchema.optional(),
148
+ body: z.array(bodyBlockSchema),
149
+ seo: z
150
+ .object({
151
+ metaTitle: z.string().optional(),
152
+ metaDescription: z.string().optional(),
153
+ ogImage: z.string().optional()
154
+ })
155
+ .optional(),
156
+ navigation: z
157
+ .object({
158
+ categories: z.array(categorySchema)
159
+ })
160
+ .optional(),
161
+ articles: z.array(articleReferenceSchema).optional(),
162
+ heroSlides: z
163
+ .array(z.object({
164
+ image: z.string(),
165
+ alt: z.string().optional()
166
+ }))
167
+ .optional(),
168
+ heroLayout: z.enum(['spotlight', 'editorial']).optional(),
169
+ heroCategories: z.array(categorySchema).optional(),
170
+ showHero: z.boolean().optional(),
171
+ showEditorialHero: z.boolean().optional(),
172
+ breakingNews: z
173
+ .object({
174
+ displayClass: z.string().optional(),
175
+ sidebarFeature: z
176
+ .object({
177
+ category: z.string(),
178
+ title: z.string(),
179
+ url: z.string(),
180
+ image: z.string(),
181
+ excerpt: z.string().optional(),
182
+ publishedAt: isoDateTime.optional()
183
+ })
184
+ .optional(),
185
+ sidebarSub: z
186
+ .object({
187
+ category: z.string(),
188
+ title: z.string(),
189
+ url: z.string(),
190
+ image: z.string(),
191
+ alt: z.string().optional(),
192
+ readTime: z.string().optional(),
193
+ excerpt: z.string().optional()
194
+ })
195
+ .optional(),
196
+ main: z
197
+ .object({
198
+ category: z.string(),
199
+ title: z.string(),
200
+ url: z.string(),
201
+ liveUrl: z.string().optional(),
202
+ sofascore_id: z.number().int().positive().optional(),
203
+ image: z.string(),
204
+ alt: z.string().optional(),
205
+ excerpt: z.string().optional()
206
+ })
207
+ .optional(),
208
+ updates: z
209
+ .array(z.object({
210
+ timestamp: isoDateTime.optional(),
211
+ time: z.string().optional(),
212
+ text: z.string().optional(),
213
+ html: z.string().optional()
214
+ }))
215
+ .optional(),
216
+ snacks: z
217
+ .array(z.object({
218
+ category: z.string().optional(),
219
+ readTime: z.string().optional(),
220
+ title: z.string(),
221
+ url: z.string(),
222
+ excerpt: z.string().optional(),
223
+ image: z.string().optional(),
224
+ alt: z.string().optional()
225
+ }))
226
+ .optional()
227
+ })
228
+ .optional(),
229
+ liveStory: z
230
+ .object({
231
+ lastUpdated: z.string().optional(),
232
+ keyPoints: z.array(z.string()).optional()
233
+ })
234
+ .optional()
235
+ })
236
+ .passthrough();
@@ -0,0 +1,3 @@
1
+ export declare function normalizeSofascoreId(value: unknown): string | null;
2
+ export declare function buildSofascoreAttackMomentumUrl(value: unknown, theme?: 'light' | 'dark'): string;
3
+ export declare function buildSofascoreMatchUrl(value: unknown): string;
@@ -0,0 +1,31 @@
1
+ const SOFASCORE_WIDGET_BASE = 'https://widgets.sofascore.com/embed/attackMomentum';
2
+ const SOFASCORE_MATCH_BASE = 'https://www.sofascore.com/football/match';
3
+ export function normalizeSofascoreId(value) {
4
+ if (typeof value === 'number') {
5
+ if (!Number.isInteger(value) || value <= 0)
6
+ return null;
7
+ return String(value);
8
+ }
9
+ if (typeof value === 'string') {
10
+ const trimmed = value.trim();
11
+ if (!/^\d+$/.test(trimmed))
12
+ return null;
13
+ const numeric = Number.parseInt(trimmed, 10);
14
+ if (!Number.isFinite(numeric) || numeric <= 0)
15
+ return null;
16
+ return String(numeric);
17
+ }
18
+ return null;
19
+ }
20
+ export function buildSofascoreAttackMomentumUrl(value, theme = 'light') {
21
+ const normalizedId = normalizeSofascoreId(value);
22
+ if (!normalizedId)
23
+ return '';
24
+ return `${SOFASCORE_WIDGET_BASE}?id=${normalizedId}&widgetTheme=${theme}`;
25
+ }
26
+ export function buildSofascoreMatchUrl(value) {
27
+ const normalizedId = normalizeSofascoreId(value);
28
+ if (!normalizedId)
29
+ return '';
30
+ return `${SOFASCORE_MATCH_BASE}#id:${normalizedId}`;
31
+ }
@@ -0,0 +1 @@
1
+ export declare const version: string;
@@ -0,0 +1,4 @@
1
+ import { createRequire } from 'node:module';
2
+ const require = createRequire(import.meta.url);
3
+ const packageJson = require('../package.json');
4
+ export const version = packageJson.version;