kmcom-nuxt-layers 2.2.5 → 2.2.8

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 (218) hide show
  1. package/docs/FEEDS.md +197 -0
  2. package/docs/LAYERS-FIXES.md +101 -0
  3. package/docs/MIGRATION.md +627 -0
  4. package/docs/feed-layer.md +374 -0
  5. package/docs/patch-picture-provider-type.md +52 -0
  6. package/docs/shaderGuide.md +2071 -0
  7. package/docs/types-architecture.md +234 -0
  8. package/layers/animations/app/components/Motion/CountUp.vue +1 -1
  9. package/layers/animations/app/components/Motion/Magnetic.vue +1 -1
  10. package/layers/animations/app/components/Motion/Marquee.vue +3 -2
  11. package/layers/animations/app/components/Motion/MarqueeText.vue +3 -2
  12. package/layers/animations/app/components/Motion/Tilt.vue +1 -1
  13. package/layers/animations/app/composables/useCountUp.ts +4 -1
  14. package/layers/animations/app/composables/useMagneticElement.ts +2 -4
  15. package/layers/animations/app/composables/useMarqueeCopies.ts +4 -4
  16. package/layers/animations/app/composables/useTiltEffect.ts +1 -1
  17. package/layers/animations/app/types/animations.ts +8 -0
  18. package/layers/animations/app/types/index.ts +1 -0
  19. package/layers/animations/package.json +4 -1
  20. package/layers/canvas/app/components/ShaderCanvas.vue +4 -4
  21. package/layers/canvas/app/composables/useRendererCapabilities.ts +19 -15
  22. package/layers/canvas/app/types/index.ts +1 -0
  23. package/layers/canvas/package.json +2 -1
  24. package/layers/canvas/tsconfig.json +2 -1
  25. package/layers/content/app/components/Blog/Card.vue +5 -5
  26. package/layers/content/app/components/Gallery/AmbientImage.vue +3 -3
  27. package/layers/content/app/components/Gallery/Card.vue +3 -3
  28. package/layers/content/app/components/Gallery/Lightbox.vue +5 -1
  29. package/layers/content/app/components/NuxtContent/Detail.vue +5 -1
  30. package/layers/content/app/components/NuxtContent/Surround.vue +5 -3
  31. package/layers/content/app/components/NuxtContent/Toc.vue +1 -1
  32. package/layers/content/app/components/Portfolio/Card.vue +5 -5
  33. package/layers/content/app/components/content/Figure.vue +3 -3
  34. package/layers/content/app/composables/useBlogPosts.ts +2 -2
  35. package/layers/content/app/composables/useCollectionItem.ts +1 -3
  36. package/layers/content/app/composables/useGalleryItems.ts +2 -2
  37. package/layers/content/app/types/index.ts +1 -0
  38. package/layers/content/package.json +2 -1
  39. package/layers/core/app/composables/useCache.ts +0 -1
  40. package/layers/core/app/composables/useErrorLog.ts +9 -11
  41. package/layers/core/app/plugins/error-handler.ts +36 -36
  42. package/layers/core/app/plugins/feature-detection.client.ts +15 -15
  43. package/layers/core/app/plugins/init.ts +121 -129
  44. package/layers/core/app/plugins/loading.client.ts +27 -27
  45. package/layers/core/app/plugins/scroll-guard.client.ts +26 -26
  46. package/layers/core/app/utils/helpers.ts +14 -12
  47. package/layers/core/nuxt.config.ts +1 -0
  48. package/layers/feeds/app/plugins/feed-head.ts +62 -63
  49. package/layers/feeds/package.json +2 -1
  50. package/layers/feeds/server/routes/feed/discovery.get.ts +1 -2
  51. package/layers/feeds/server/utils/content-adapter.ts +3 -2
  52. package/layers/forms/app/components/Form/Field.vue +4 -4
  53. package/layers/forms/app/types/index.ts +1 -0
  54. package/layers/forms/package.json +2 -1
  55. package/layers/forms/server/api/contact.post.ts +1 -1
  56. package/layers/layout/app/components/Layout/Grid/Item.vue +33 -19
  57. package/layers/layout/app/components/Layout/Page/Container.vue +11 -11
  58. package/layers/layout/app/components/Layout/Page/Header.vue +1 -1
  59. package/layers/layout/app/components/Layout/Page/index.vue +1 -1
  60. package/layers/layout/app/components/Layout/Section/Gallery.vue +6 -1
  61. package/layers/layout/app/components/Layout/Section/Title.vue +1 -1
  62. package/layers/layout/app/types/index.ts +1 -0
  63. package/layers/layout/package.json +2 -1
  64. package/layers/mailer/app/types/index.ts +1 -0
  65. package/layers/mailer/app/types/mailer.ts +25 -0
  66. package/layers/mailer/package.json +2 -1
  67. package/layers/motion/package.json +2 -1
  68. package/layers/navigation/app/components/Links/Group.vue +1 -0
  69. package/layers/navigation/app/components/Links/Named.vue +2 -0
  70. package/layers/navigation/app/types/index.ts +1 -0
  71. package/layers/navigation/package.json +4 -1
  72. package/layers/page-transitions/app/plugins/page-transitions.client.ts +9 -9
  73. package/layers/page-transitions/package.json +4 -1
  74. package/layers/routing/app/plugins/feature-flags.client.ts +9 -9
  75. package/layers/routing/app/types/app-config.d.ts +3 -1
  76. package/layers/routing/app/types/index.ts +1 -0
  77. package/layers/routing/package.json +2 -1
  78. package/layers/scripts/app/composables/useGtm.ts +1 -1
  79. package/layers/scripts/app/types/index.ts +1 -0
  80. package/layers/scripts/app/types/scripts.ts +14 -0
  81. package/layers/scripts/package.json +2 -1
  82. package/layers/scroll/app/components/Motion/ScrollScene.vue +3 -1
  83. package/layers/scroll/app/composables/useScrollSteps.ts +2 -9
  84. package/layers/scroll/app/composables/useSectionProgress.ts +2 -1
  85. package/layers/scroll/app/plugins/locomotive-scroll.client.ts +54 -61
  86. package/layers/scroll/app/types/index.ts +1 -0
  87. package/layers/scroll/app/types/scroll.ts +32 -0
  88. package/layers/scroll/package.json +3 -0
  89. package/layers/seo/package.json +2 -1
  90. package/layers/shader/app/components/Material/Fresnel.client.vue +1 -1
  91. package/layers/shader/app/components/Material/Image.client.vue +1 -1
  92. package/layers/shader/app/components/Material/Node.client.vue +7 -7
  93. package/layers/shader/app/components/Material/Noise.client.vue +1 -1
  94. package/layers/shader/app/components/Node/Color.client.vue +17 -20
  95. package/layers/shader/app/components/Node/Noise.client.vue +31 -34
  96. package/layers/shader/app/components/Pipeline/Aurora.client.vue +4 -8
  97. package/layers/shader/app/components/Pipeline/BilinearGradient.client.vue +8 -11
  98. package/layers/shader/app/components/Pipeline/BillowNoise.client.vue +4 -8
  99. package/layers/shader/app/components/Pipeline/BrightnessContrast.client.vue +6 -2
  100. package/layers/shader/app/components/Pipeline/CellularNoise.client.vue +4 -8
  101. package/layers/shader/app/components/Pipeline/Checkerboard.client.vue +4 -8
  102. package/layers/shader/app/components/Pipeline/Circle.client.vue +5 -8
  103. package/layers/shader/app/components/Pipeline/Clouds.client.vue +4 -8
  104. package/layers/shader/app/components/Pipeline/ColorBurnBlend.client.vue +2 -19
  105. package/layers/shader/app/components/Pipeline/ColorDodgeBlend.client.vue +2 -19
  106. package/layers/shader/app/components/Pipeline/ColourRamp.client.vue +5 -9
  107. package/layers/shader/app/components/Pipeline/ConicGradient.client.vue +5 -8
  108. package/layers/shader/app/components/Pipeline/Cross.client.vue +4 -8
  109. package/layers/shader/app/components/Pipeline/CurlNoise.client.vue +3 -7
  110. package/layers/shader/app/components/Pipeline/DarkenBlend.client.vue +2 -19
  111. package/layers/shader/app/components/Pipeline/DayNightCycle.client.vue +5 -8
  112. package/layers/shader/app/components/Pipeline/DiagonalGradient.client.vue +5 -8
  113. package/layers/shader/app/components/Pipeline/DiamondGradient.client.vue +5 -8
  114. package/layers/shader/app/components/Pipeline/DifferenceBlend.client.vue +2 -19
  115. package/layers/shader/app/components/Pipeline/DomainWarpedNoise.client.vue +4 -8
  116. package/layers/shader/app/components/Pipeline/Dots.client.vue +4 -8
  117. package/layers/shader/app/components/Pipeline/DuoTone.client.vue +5 -9
  118. package/layers/shader/app/components/Pipeline/ExclusionBlend.client.vue +3 -23
  119. package/layers/shader/app/components/Pipeline/ExponentialFog.client.vue +4 -7
  120. package/layers/shader/app/components/Pipeline/FilmBurn.client.vue +4 -7
  121. package/layers/shader/app/components/Pipeline/Flame.client.vue +4 -8
  122. package/layers/shader/app/components/Pipeline/FocalGradient.client.vue +5 -8
  123. package/layers/shader/app/components/Pipeline/GodRays.client.vue +4 -7
  124. package/layers/shader/app/components/Pipeline/GradientNoise.client.vue +4 -8
  125. package/layers/shader/app/components/Pipeline/Grid.client.vue +4 -8
  126. package/layers/shader/app/components/Pipeline/Halation.client.vue +3 -7
  127. package/layers/shader/app/components/Pipeline/HardLightBlend.client.vue +2 -19
  128. package/layers/shader/app/components/Pipeline/Haze.client.vue +4 -7
  129. package/layers/shader/app/components/Pipeline/Hexagon.client.vue +4 -8
  130. package/layers/shader/app/components/Pipeline/LensFlare.client.vue +4 -7
  131. package/layers/shader/app/components/Pipeline/LightenBlend.client.vue +2 -19
  132. package/layers/shader/app/components/Pipeline/LinearGradient4.client.vue +2 -2
  133. package/layers/shader/app/components/Pipeline/Marble.client.vue +4 -8
  134. package/layers/shader/app/components/Pipeline/MonochromeTint.client.vue +3 -7
  135. package/layers/shader/app/components/Pipeline/MultiplyBlend.client.vue +2 -19
  136. package/layers/shader/app/components/Pipeline/NoisyGradient.client.vue +4 -8
  137. package/layers/shader/app/components/Pipeline/NoisyGradientBlend.client.vue +4 -8
  138. package/layers/shader/app/components/Pipeline/OverlayBlend.client.vue +2 -19
  139. package/layers/shader/app/components/Pipeline/Polygon.client.vue +4 -8
  140. package/layers/shader/app/components/Pipeline/RaymarchTunnel.client.vue +4 -7
  141. package/layers/shader/app/components/Pipeline/Rectangle.client.vue +4 -8
  142. package/layers/shader/app/components/Pipeline/RidgedNoise.client.vue +4 -8
  143. package/layers/shader/app/components/Pipeline/Ring.client.vue +4 -8
  144. package/layers/shader/app/components/Pipeline/ScreenBlend.client.vue +2 -19
  145. package/layers/shader/app/components/Pipeline/SkyAtmosphere.client.vue +6 -9
  146. package/layers/shader/app/components/Pipeline/SoftLightBlend.client.vue +2 -19
  147. package/layers/shader/app/components/Pipeline/SplitTone.client.vue +4 -8
  148. package/layers/shader/app/components/Pipeline/Star.client.vue +4 -8
  149. package/layers/shader/app/components/Pipeline/Stripes.client.vue +4 -8
  150. package/layers/shader/app/components/Pipeline/Tint.client.vue +4 -7
  151. package/layers/shader/app/components/Pipeline/Triangle.client.vue +4 -8
  152. package/layers/shader/app/components/Pipeline/ValueNoise.client.vue +4 -8
  153. package/layers/shader/app/components/Pipeline/VoronoiEdges.client.vue +4 -8
  154. package/layers/shader/app/components/Pipeline/Water.client.vue +5 -8
  155. package/layers/shader/app/components/Pipeline/WaveBendLayer.client.vue +4 -7
  156. package/layers/shader/app/components/Pipeline/WaveColourLayer.client.vue +3 -7
  157. package/layers/shader/app/components/Pipeline/Wood.client.vue +4 -8
  158. package/layers/shader/app/components/Preset/Aurora.client.vue +15 -21
  159. package/layers/shader/app/components/Preset/Flow.client.vue +2 -1
  160. package/layers/shader/app/components/Preset/GradientMesh.client.vue +2 -1
  161. package/layers/shader/app/components/Preset/Nebula.client.vue +2 -1
  162. package/layers/shader/app/components/Preset/Ocean.client.vue +2 -1
  163. package/layers/shader/app/components/Preset/ThemeAurora.client.vue +30 -90
  164. package/layers/shader/app/components/Preset/ThemeBubble.client.vue +30 -91
  165. package/layers/shader/app/components/Preset/ThemeFlow.client.vue +30 -90
  166. package/layers/shader/app/components/Preset/ThemeGradient.client.vue +30 -91
  167. package/layers/shader/app/components/Preset/ThemeLavaLamp.client.vue +30 -90
  168. package/layers/shader/app/components/Preset/ThemePlasma.client.vue +30 -90
  169. package/layers/shader/app/components/Preset/ThemeWave.client.vue +30 -90
  170. package/layers/shader/app/components/Shader/Background.client.vue +4 -4
  171. package/layers/shader/app/components/Shader/Host.client.vue +31 -33
  172. package/layers/shader/app/components/Shader/Runtime.client.vue +15 -23
  173. package/layers/shader/app/composables/useAmbientMaterials.ts +53 -51
  174. package/layers/shader/app/composables/useShaderMixBlend.ts +26 -0
  175. package/layers/shader/app/composables/useThemePreset.ts +75 -0
  176. package/layers/shader/app/plugins/shader.client.ts +21 -21
  177. package/layers/shader/app/shaders/common/noise.ts +2 -7
  178. package/layers/shader/app/shaders/types.ts +6 -6
  179. package/layers/shader/app/types/tsl.ts +7 -25
  180. package/layers/shader/app/types/uniforms.ts +2 -1
  181. package/layers/shader/app/utils/tsl/color.ts +7 -1
  182. package/layers/shader/package.json +2 -1
  183. package/layers/theme/app/components/ThemePicker/Colors.vue +1 -3
  184. package/layers/theme/app/plugins/theme.client.ts +54 -51
  185. package/layers/theme/app/types/app-config.d.ts +4 -2
  186. package/layers/theme/app/types/index.ts +1 -0
  187. package/layers/theme/app/types/theme.ts +3 -18
  188. package/layers/theme/package.json +2 -1
  189. package/layers/theme/server/plugins/theme-fouc.ts +1 -1
  190. package/layers/transitions/package.json +4 -1
  191. package/layers/typography/app/components/Typography/CodeBlock.vue +2 -2
  192. package/layers/typography/app/components/Typography/Headline.vue +2 -2
  193. package/layers/typography/app/components/Typography/HeadlineScreen.vue +1 -1
  194. package/layers/typography/app/components/Typography/QuoteBlock.vue +4 -1
  195. package/layers/typography/app/components/Typography/TextStroke.vue +2 -0
  196. package/layers/typography/app/components/Typography/index.vue +36 -27
  197. package/layers/typography/app/composables/typography.ts +27 -21
  198. package/layers/typography/app/types/colors.ts +9 -29
  199. package/layers/typography/app/types/index.ts +2 -0
  200. package/layers/typography/package.json +4 -1
  201. package/layers/ui/package.json +2 -1
  202. package/layers/visual/app/app.config.ts +5 -2
  203. package/layers/visual/app/components/Accent/Blob.vue +20 -20
  204. package/layers/visual/app/components/Accent/Scene.vue +2 -2
  205. package/layers/visual/app/components/Base/Modal.vue +2 -2
  206. package/layers/visual/app/components/Gradient/Background.vue +2 -2
  207. package/layers/visual/app/components/Gradient/Text.vue +2 -2
  208. package/layers/visual/app/components/Media/Picture.vue +3 -1
  209. package/layers/visual/app/components/Progress/Bar.vue +6 -6
  210. package/layers/visual/app/components/Tint/Overlay.vue +14 -14
  211. package/layers/visual/app/composables/accent.ts +10 -8
  212. package/layers/visual/app/composables/gradient.ts +2 -3
  213. package/layers/visual/app/composables/tint.ts +7 -7
  214. package/layers/visual/app/types/index.ts +6 -0
  215. package/layers/visual/app/types/media.ts +4 -2
  216. package/layers/visual/app/types/tint.ts +2 -1
  217. package/layers/visual/package.json +4 -1
  218. package/package.json +5 -2
@@ -0,0 +1,374 @@
1
+ # 📡 Production Feed Layer (Nuxt 3)
2
+
3
+ A fully decoupled, format-agnostic syndication system for Nuxt Content.
4
+ Provides:
5
+
6
+ - RSS 2.0
7
+ - Atom 1.0
8
+ - JSON Feed 1.1
9
+ - XSLT human-readable feed UI
10
+ - Tailwind-styled feed interface
11
+ - Collection-aware feed endpoints
12
+ - Fully cacheable server outputs
13
+ Built for Nuxt 3 and Nuxt Content.
14
+
15
+ ---
16
+
17
+ # 🧠 Core Principles
18
+
19
+ ## 1. Canonical model first
20
+
21
+ All formats derive from a single structure:
22
+
23
+ > `FeedItem[]`
24
+
25
+ ## No format-specific logic exists in content queries.
26
+
27
+ ## 2. Format adapters are pure functions
28
+
29
+ Each format is isolated:
30
+
31
+ - RSS → `feed` npm package
32
+ - Atom → manual XML
33
+ - JSON Feed → JSON builder
34
+
35
+ ---
36
+
37
+ ## 3. UI is separate from feed semantics
38
+
39
+ - XSLT transforms RSS → HTML
40
+ - Tailwind styles only the human view
41
+ - Feed consumers never see UI logic
42
+
43
+ ---
44
+
45
+ ## 4. Routes are thin orchestration layers
46
+
47
+ ## All logic lives in runtime/services.
48
+
49
+ ## 5. Fully cacheable outputs
50
+
51
+ Feeds are deterministic and safe for:
52
+
53
+ - CDN caching
54
+ - ETags
55
+ - edge caching
56
+
57
+ ---
58
+
59
+ # 📁 Folder Structure
60
+
61
+ layers/feed/
62
+
63
+ ├── server/
64
+ │ └── routes/
65
+ │ └── feed/
66
+ │ ├── index.get.ts
67
+ │ ├── rss.get.ts
68
+ │ ├── atom.get.ts
69
+ │ ├── json.get.ts
70
+ │ │
71
+ │ └── [collection]/
72
+ │ ├── rss.get.ts
73
+ │ ├── atom.get.ts
74
+ │ └── json.get.ts
75
+
76
+ ├── runtime/
77
+ │ ├── feed.service.ts
78
+ │ ├── content.adapter.ts
79
+ │ ├── feed.builder.ts
80
+ │ └── cache.ts
81
+
82
+ ├── formats/
83
+ │ ├── rss.ts
84
+ │ ├── atom.ts
85
+ │ └── json.ts
86
+
87
+ ├── ui/
88
+ │ ├── feed.css
89
+ │ └── rss.xsl
90
+
91
+ ├── types/
92
+ │ └── feed.ts
93
+
94
+ └── README.md
95
+
96
+ ---
97
+
98
+ # 🧱 Canonical Feed Model
99
+
100
+ ```ts
101
+ export interface FeedItem {
102
+ title: string
103
+ description?: string
104
+ link: string
105
+ id: string
106
+ date: Date
107
+ author?: string
108
+ tags?: string[]
109
+ }
110
+ ```
111
+
112
+
113
+
114
+ 🔌 Content Adapter Layer
115
+
116
+ Fetches content from Nuxt Content and maps to canonical model.
117
+
118
+ ```ts
119
+ import { queryContent } from '#content/server'
120
+
121
+ export async function getFeedItems(collection?: string) {
122
+ const query = queryContent(collection || '')
123
+ const items = await query.where({ _draft: false }).sort({ date: -1 }).limit(30).find()
124
+ return items.map((p) => ({
125
+ title: p.title,
126
+ description: p.description,
127
+ link: p._path,
128
+ id: p._path,
129
+ date: new Date(p.date),
130
+ tags: p.tags,
131
+ }))
132
+ }
133
+ ```
134
+
135
+
136
+
137
+ ⚙️ Feed Service Layer
138
+
139
+ Central orchestration layer.
140
+
141
+ ```ts
142
+ export async function buildFeed(collection?: string) {
143
+ return await getFeedItems(collection)
144
+ }
145
+ ```
146
+
147
+
148
+
149
+ 📦 Format Adapters
150
+
151
+
152
+
153
+ RSS (feed npm package)
154
+
155
+ ```ts
156
+ import { Feed } from 'feed'
157
+
158
+ export function toRSS(items, config) {
159
+ const feed = new Feed({
160
+ title: config.title,
161
+ description: config.description,
162
+ id: config.siteUrl,
163
+ link: config.siteUrl,
164
+ updated: new Date(),
165
+ })
166
+ for (const item of items) {
167
+ feed.addItem({
168
+ title: item.title,
169
+ id: item.id,
170
+ link: `${config.siteUrl}${item.link}`,
171
+ description: item.description,
172
+ date: item.date,
173
+ })
174
+ }
175
+ return feed.rss2()
176
+ }
177
+ ```
178
+
179
+
180
+
181
+ Atom (manual XML)
182
+
183
+ ```ts
184
+ export function toAtom(items, config) {
185
+ return `<?xml version="1.0" encoding="utf-8"?>
186
+ <feed xmlns="http://www.w3.org/2005/Atom">
187
+
188
+ <title>${config.title}</title>
189
+ <id>${config.siteUrl}</id>
190
+ <updated>${new Date().toISOString()}</updated>
191
+ ${items
192
+ .map(
193
+ (i) => `
194
+ <entry>
195
+ <title>${i.title}</title>
196
+ <id>${i.id}</id>
197
+ <link href="${config.siteUrl}${i.link}" />
198
+ <updated>${i.date.toISOString()}</updated>
199
+ <summary>${i.description || ''}</summary>
200
+ </entry>
201
+ `
202
+ )
203
+ .join('')}
204
+ </feed>`
205
+ }
206
+ ```
207
+
208
+
209
+
210
+ JSON Feed
211
+
212
+ ```ts
213
+ export function toJSONFeed(items, config) {
214
+ return {
215
+ version: 'https://jsonfeed.org/version/1',
216
+ title: config.title,
217
+ home_page_url: config.siteUrl,
218
+ feed_url: `${config.siteUrl}/feed/json`,
219
+ items: items.map((i) => ({
220
+ id: i.id,
221
+ url: `${config.siteUrl}${i.link}`,
222
+ title: i.title,
223
+ content_text: i.description,
224
+ date_published: i.date,
225
+ })),
226
+ }
227
+ }
228
+ ```
229
+
230
+
231
+
232
+ 🌍 Route Layer (Thin Orchestration)
233
+
234
+ Global RSS
235
+
236
+ ```ts
237
+ import { toRSS } from '../../formats/rss'
238
+ import { buildFeed } from '../../runtime/feed.service'
239
+
240
+ export default defineEventHandler(async () => {
241
+ const items = await buildFeed()
242
+ return toRSS(items, {
243
+ title: 'Site Feed',
244
+ description: 'Latest content',
245
+ siteUrl: 'https://your-site.com',
246
+ })
247
+ })
248
+ ```
249
+
250
+
251
+
252
+ Collection feeds
253
+
254
+ const collection = event.context.params.collection
255
+ const items = await buildFeed(collection)
256
+
257
+ Same logic applies to all formats.
258
+
259
+
260
+
261
+ 🎨 UI Layer (Human View Only)
262
+
263
+ Feed stylesheet (feed.css)
264
+
265
+ - Tailwind-based utility styling
266
+ - only used in XSLT view
267
+ - not part of feed logic
268
+
269
+
270
+
271
+ XSLT responsibilities
272
+
273
+ - transform RSS → HTML
274
+ - apply /feed.css
275
+ - render:
276
+ - title
277
+ - feed items
278
+ - actions
279
+
280
+
281
+
282
+ Subscribe button
283
+
284
+ `feed://your-domain.com/feed/rss`
285
+
286
+ Fallback:
287
+
288
+ - `/feed/rss`
289
+ - `/feed/atom`
290
+
291
+
292
+
293
+ Copy to clipboard
294
+
295
+ `navigator.clipboard.writeText(window.location.href)`
296
+
297
+
298
+
299
+ ⚡ Caching Strategy
300
+
301
+ ETags
302
+
303
+ `setHeader(event, 'ETag', hash(content))`
304
+
305
+
306
+
307
+ Cache control
308
+
309
+ `cache-control: public, max-age=300, s-maxage=3600`
310
+
311
+
312
+
313
+ Optional Nitro caching
314
+
315
+ - per collection caching
316
+ - invalidation on content update
317
+
318
+
319
+
320
+ 🔐 Rules
321
+
322
+ - No UI logic in formatters
323
+ - No format coupling
324
+ - No mutation of FeedItem in adapters
325
+ - XSLT must not affect feed semantics
326
+
327
+
328
+
329
+ 📡 Final API Surface
330
+
331
+ Global feeds
332
+
333
+ - `/feed/rss`
334
+ - `/feed/atom`
335
+ - `/feed/json`
336
+
337
+ Collection feeds
338
+
339
+ - `/feed/:collection/rss`
340
+ - `/feed/:collection/atom`
341
+ - `/feed/:collection/json`
342
+
343
+ Optional
344
+
345
+ - `/feed` → index of available feeds
346
+
347
+
348
+
349
+ 🧭 Summary
350
+
351
+ This system provides:
352
+
353
+ - Multi-format content syndication
354
+ - Clean separation of concerns
355
+ - Fully cacheable outputs
356
+ - Human-readable XSL feed UI
357
+ - Tailwind-powered styling layer
358
+ - Collection-aware feed generation
359
+
360
+
361
+
362
+ 🚀 Outcome
363
+
364
+ You now have a:
365
+
366
+ Production-grade syndication layer that behaves like an internal publishing API.
367
+
368
+ It is:
369
+
370
+ - extensible
371
+ - framework-aligned
372
+ - cache-friendly
373
+ - UI-enhanced
374
+ - format-agnostic
@@ -0,0 +1,52 @@
1
+ # Patch: Picture.vue provider type cast
2
+
3
+ **Package:** `kmcom-nuxt-layers`
4
+ **Target version:** `2.2.5` (or next patch)
5
+ **Status:** Workaround live via pnpm patch at `patches/kmcom-nuxt-layers@2.2.4.patch`
6
+
7
+ ---
8
+
9
+ ## Problem
10
+
11
+ `layers/visual/app/components/Media/Picture.vue` passes the `provider` prop directly to `<NuxtPicture>`:
12
+
13
+ ```html
14
+ :provider
15
+ ```
16
+
17
+ `PictureProps.provider` is typed as `string | undefined` (correctly widened in 2.2.4), but `NuxtPicture`'s `provider` prop is generated from `ConfiguredImageProviders` — a module-augmentation interface that narrows to the app's actual configured provider names (e.g. `"netlify" | undefined`).
18
+
19
+ Passing `string` to `"netlify"` fails the type check:
20
+
21
+ ```
22
+ error TS2322: Type 'string | undefined' is not assignable to type '"netlify" | undefined'.
23
+ Type 'string' is not assignable to type '"netlify"'.
24
+ ```
25
+
26
+ The error appears in every consuming app that configures a non-`ipx` provider.
27
+
28
+ ---
29
+
30
+ ## Fix
31
+
32
+ **File:** `layers/visual/app/components/Media/Picture.vue`, line 43
33
+
34
+ ```diff
35
+ - :provider
36
+ + :provider="(provider as any)"
37
+ ```
38
+
39
+ The cast is necessary because `NuxtPicture`'s prop type is dynamically generated per-app. The layer cannot know the consuming app's provider set at build time, so any typed pass-through will always fail for non-default providers.
40
+
41
+ ---
42
+
43
+ ## Verification
44
+
45
+ After publishing, in a consuming app using a non-`ipx` provider (e.g. `netlify`):
46
+
47
+ ```sh
48
+ pnpm install
49
+ pnpm typecheck # should pass with zero errors
50
+ ```
51
+
52
+ Once the new version is published, bump `package.json` here and remove `patches/kmcom-nuxt-layers@2.2.4.patch`.