nuxt-og-image 5.1.13 → 6.0.0-beta.2

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 (233) hide show
  1. package/README.md +1 -1
  2. package/bin/cli.mjs +2 -0
  3. package/dist/chunks/tw4-classes.cjs +116 -0
  4. package/dist/chunks/tw4-classes.mjs +113 -0
  5. package/dist/chunks/tw4-generator.cjs +118 -0
  6. package/dist/chunks/tw4-generator.mjs +110 -0
  7. package/dist/cli.cjs +433 -0
  8. package/dist/cli.d.cts +1 -0
  9. package/dist/cli.d.mts +1 -0
  10. package/dist/cli.d.ts +1 -0
  11. package/dist/cli.mjs +416 -0
  12. package/dist/client/200.html +1 -1
  13. package/dist/client/404.html +1 -1
  14. package/dist/client/_fonts/0xp3SbCWC1OhX7q1-uF6kilMZFm-alJNkUtkLTPCy_A-tN9KwPUWhhXvtqh74sU9FIkI4W6hsbm85r0X24hjOfM.woff2 +0 -0
  15. package/dist/client/_fonts/1ZTlEDqU4DtwDJiND8f6qaugUpa0RIDvQl-v7iM6l54-D6hedAgqRfOCLZzaShnyeAvlEnMzk4Wm7g9WDKWFHIc.woff +0 -0
  16. package/dist/client/_fonts/4HA9tc4y8BVQeLXvLn3JgQqilAj1xrAnUSprQGHIPSw-ZPswEL_UDOYaxTLQDUySPjoOHDxhD83pD19HMfKfK9s.woff2 +0 -0
  17. package/dist/client/_fonts/Bmul3LaKlc7BUKqJHE_UmEoF40Sg_2ga52yJjwyDcKs-TnYmYl1DNYkiWMu0Vx49DakCPBuiCCj9zoLIuQjUdKY.woff2 +0 -0
  18. package/dist/client/_fonts/DfgmjWGpWte3Q3a54Nevr_BYmMM5YEJXRI1CdI2VwO0-ox5RadQfCyVTmKl_hubTaIJjtRw9oaQz2GDBeZR6l1M.woff2 +0 -0
  19. package/dist/client/_fonts/Lc_5lWuBuZcZ166p1-s-mnGkMJwIYJE_QDCkws8iCkI-r45Qbm2hCykrfOZ0kowz__uTTTUOPDN9hz34QcRNTY4.woff2 +0 -0
  20. package/dist/client/_fonts/iEvApgDRmzKzNqOYocBTrmcHZmuGAJloawKDP1S0nyE-T3oc_9We24QGwfw5naik4cM0g7VxylWVaQwKm4dy3cw.woff2 +0 -0
  21. package/dist/client/_nuxt/0kYTU2a7.js +2 -0
  22. package/dist/client/_nuxt/B0QDx5EE.js +2 -0
  23. package/dist/client/_nuxt/BKqzYw6x.js +3 -0
  24. package/dist/client/_nuxt/C-Ivr2Rl.js +1 -0
  25. package/dist/client/_nuxt/CLgn8DCr.js +1 -0
  26. package/dist/client/_nuxt/CwWm-XE3.js +1 -0
  27. package/dist/client/_nuxt/D9eL2h5z.js +1 -0
  28. package/dist/client/_nuxt/DJXHIJSq.js +1 -0
  29. package/dist/client/_nuxt/DVnX3Z-O.js +1 -0
  30. package/dist/client/_nuxt/DXObZt09.js +184 -0
  31. package/dist/client/_nuxt/Dxi6QG7I.js +1 -0
  32. package/dist/client/_nuxt/E8AZ6HoH.js +1 -0
  33. package/dist/client/_nuxt/IFrameLoader.CGrV1TpP.css +1 -0
  34. package/dist/client/_nuxt/JAMwWy1K.js +3864 -0
  35. package/dist/client/_nuxt/OSectionBlock.BVHnMsIr.css +1 -0
  36. package/dist/client/_nuxt/PONEy9N-.js +1 -0
  37. package/dist/client/_nuxt/UdkqSAsD.js +1 -0
  38. package/dist/client/_nuxt/builds/latest.json +1 -1
  39. package/dist/client/_nuxt/builds/meta/8e2df3bd-1df7-4172-a3c9-b46cdb9070e5.json +1 -0
  40. package/dist/client/_nuxt/entry.BEExJd9R.css +2 -0
  41. package/dist/client/_nuxt/error-404.B79WD2X-.css +1 -0
  42. package/dist/client/_nuxt/error-500.DT3Sd0Wu.css +1 -0
  43. package/dist/client/_nuxt/pages.eW3hi7XF.css +1 -0
  44. package/dist/client/_nuxt/templates.dUiUBaip.css +1 -0
  45. package/dist/client/_payload.json +1 -0
  46. package/dist/client/debug/_payload.json +1 -0
  47. package/dist/client/debug/index.html +1 -0
  48. package/dist/client/docs/_payload.json +1 -0
  49. package/dist/client/docs/index.html +1 -0
  50. package/dist/client/fonts/HubotSans-Regular.woff2 +0 -0
  51. package/dist/client/index.html +1 -1
  52. package/dist/client/templates/_payload.json +1 -0
  53. package/dist/client/templates/index.html +1 -0
  54. package/dist/module.cjs +36 -1027
  55. package/dist/module.d.cts +63 -25
  56. package/dist/module.d.mts +63 -25
  57. package/dist/module.d.ts +63 -25
  58. package/dist/module.json +1 -1
  59. package/dist/module.mjs +32 -1009
  60. package/dist/runtime/app/components/Templates/Community/Brutalist.satori.d.vue.ts +14 -0
  61. package/dist/runtime/app/components/Templates/Community/Brutalist.satori.vue +51 -0
  62. package/dist/runtime/app/components/Templates/Community/Brutalist.satori.vue.d.ts +14 -0
  63. package/dist/runtime/app/components/Templates/Community/{Frame.vue.d.ts → Frame.satori.d.vue.ts} +2 -2
  64. package/dist/runtime/app/components/Templates/Community/Frame.satori.vue +71 -0
  65. package/dist/runtime/app/components/Templates/Community/{Frame.d.vue.ts → Frame.satori.vue.d.ts} +2 -2
  66. package/dist/runtime/app/components/Templates/Community/Newspaper.satori.d.vue.ts +12 -0
  67. package/dist/runtime/app/components/Templates/Community/Newspaper.satori.vue +70 -0
  68. package/dist/runtime/app/components/Templates/Community/Newspaper.satori.vue.d.ts +12 -0
  69. package/dist/runtime/app/components/Templates/Community/Nuxt.satori.d.vue.ts +12 -0
  70. package/dist/runtime/app/components/Templates/Community/{Nuxt.vue → Nuxt.satori.vue} +3 -3
  71. package/dist/runtime/app/components/Templates/Community/Nuxt.satori.vue.d.ts +12 -0
  72. package/dist/runtime/app/components/Templates/Community/NuxtSeo.satori.d.vue.ts +12 -0
  73. package/dist/runtime/app/components/Templates/Community/NuxtSeo.satori.vue +69 -0
  74. package/dist/runtime/app/components/Templates/Community/NuxtSeo.satori.vue.d.ts +12 -0
  75. package/dist/runtime/app/components/Templates/Community/Pergel.satori.d.vue.ts +12 -0
  76. package/dist/runtime/app/components/Templates/Community/{Pergel.vue → Pergel.satori.vue} +14 -11
  77. package/dist/runtime/app/components/Templates/Community/Pergel.satori.vue.d.ts +12 -0
  78. package/dist/runtime/app/components/Templates/Community/Retro.satori.d.vue.ts +12 -0
  79. package/dist/runtime/app/components/Templates/Community/Retro.satori.vue +64 -0
  80. package/dist/runtime/app/components/Templates/Community/Retro.satori.vue.d.ts +12 -0
  81. package/dist/runtime/app/components/Templates/Community/SaaS.satori.d.vue.ts +12 -0
  82. package/dist/runtime/app/components/Templates/Community/SaaS.satori.vue +60 -0
  83. package/dist/runtime/app/components/Templates/Community/SaaS.satori.vue.d.ts +12 -0
  84. package/dist/runtime/app/components/Templates/Community/SimpleBlog.satori.d.vue.ts +9 -0
  85. package/dist/runtime/app/components/Templates/Community/SimpleBlog.satori.vue +38 -0
  86. package/dist/runtime/app/components/Templates/Community/SimpleBlog.satori.vue.d.ts +9 -0
  87. package/dist/runtime/app/components/Templates/Community/{UnJs.d.vue.ts → UnJs.satori.d.vue.ts} +2 -2
  88. package/dist/runtime/app/components/Templates/Community/{UnJs.vue → UnJs.satori.vue} +41 -33
  89. package/dist/runtime/app/components/Templates/Community/{UnJs.vue.d.ts → UnJs.satori.vue.d.ts} +2 -2
  90. package/dist/runtime/app/components/Templates/Community/WithEmoji.satori.d.vue.ts +13 -0
  91. package/dist/runtime/app/components/Templates/Community/WithEmoji.satori.vue +27 -0
  92. package/dist/runtime/app/components/Templates/Community/WithEmoji.satori.vue.d.ts +13 -0
  93. package/dist/runtime/app/composables/_defineOgImageRaw.d.ts +6 -0
  94. package/dist/runtime/app/composables/_defineOgImageRaw.js +70 -0
  95. package/dist/runtime/app/composables/defineOgImage.d.ts +14 -2
  96. package/dist/runtime/app/composables/defineOgImage.js +13 -42
  97. package/dist/runtime/app/composables/defineOgImageComponent.d.ts +5 -1
  98. package/dist/runtime/app/composables/defineOgImageComponent.js +4 -5
  99. package/dist/runtime/app/composables/defineOgImageScreenshot.d.ts +1 -1
  100. package/dist/runtime/app/composables/defineOgImageScreenshot.js +2 -2
  101. package/dist/runtime/app/composables/mock.d.ts +7 -4
  102. package/dist/runtime/app/composables/mock.js +4 -4
  103. package/dist/runtime/app/utils/plugins.js +22 -28
  104. package/dist/runtime/app/utils.d.ts +15 -1
  105. package/dist/runtime/app/utils.js +74 -46
  106. package/dist/runtime/pure.d.ts +7 -0
  107. package/dist/runtime/pure.js +105 -0
  108. package/dist/runtime/server/og-image/bindings/css-inline/wasm-fs.d.ts +3 -2
  109. package/dist/runtime/server/og-image/bindings/css-inline/wasm.d.ts +3 -2
  110. package/dist/runtime/server/og-image/bindings/font-assets/cloudflare.d.ts +3 -0
  111. package/dist/runtime/server/og-image/bindings/font-assets/cloudflare.js +22 -0
  112. package/dist/runtime/server/og-image/bindings/font-assets/dev-prerender.d.ts +3 -0
  113. package/dist/runtime/server/og-image/bindings/font-assets/dev-prerender.js +49 -0
  114. package/dist/runtime/server/og-image/bindings/font-assets/node.d.ts +3 -0
  115. package/dist/runtime/server/og-image/bindings/font-assets/node.js +14 -0
  116. package/dist/runtime/server/og-image/bindings/resvg/node-dev.d.ts +5 -0
  117. package/dist/runtime/server/og-image/bindings/resvg/node-dev.js +70 -0
  118. package/dist/runtime/server/og-image/bindings/takumi/node.d.ts +6 -0
  119. package/dist/runtime/server/og-image/bindings/takumi/node.js +5 -0
  120. package/dist/runtime/server/og-image/bindings/takumi/wasm.d.ts +6 -0
  121. package/dist/runtime/server/og-image/bindings/takumi/wasm.js +6 -0
  122. package/dist/runtime/server/og-image/cache/buildCache.d.ts +16 -0
  123. package/dist/runtime/server/og-image/cache/buildCache.js +48 -0
  124. package/dist/runtime/server/og-image/cache/lru.d.ts +2 -2
  125. package/dist/runtime/server/og-image/cache/lru.js +3 -3
  126. package/dist/runtime/server/og-image/cache/mock.d.ts +1 -2
  127. package/dist/runtime/server/og-image/cache/mock.js +0 -1
  128. package/dist/runtime/server/og-image/chromium/screenshot.js +4 -3
  129. package/dist/runtime/server/og-image/context.d.ts +2 -3
  130. package/dist/runtime/server/og-image/context.js +55 -193
  131. package/dist/runtime/server/og-image/devtools.d.ts +10 -0
  132. package/dist/runtime/server/og-image/devtools.js +74 -0
  133. package/dist/runtime/server/og-image/fonts.d.ts +6 -0
  134. package/dist/runtime/server/og-image/fonts.js +41 -0
  135. package/dist/runtime/server/og-image/instances.d.ts +1 -0
  136. package/dist/runtime/server/og-image/instances.js +5 -0
  137. package/dist/runtime/server/og-image/satori/instances.d.ts +1 -36
  138. package/dist/runtime/server/og-image/satori/plugins/emojis.js +83 -4
  139. package/dist/runtime/server/og-image/satori/plugins/encoding.js +11 -1
  140. package/dist/runtime/server/og-image/satori/plugins/imageSrc.js +5 -1
  141. package/dist/runtime/server/og-image/satori/plugins/twClasses.js +35 -0
  142. package/dist/runtime/server/og-image/satori/renderer.js +16 -53
  143. package/dist/runtime/server/og-image/satori/transforms/emojis/emoji-names-minimal.d.ts +1 -0
  144. package/dist/runtime/server/og-image/satori/transforms/emojis/emoji-names-minimal.js +223 -0
  145. package/dist/runtime/server/og-image/satori/transforms/emojis/emoji-utils.d.ts +45 -0
  146. package/dist/runtime/server/og-image/satori/transforms/emojis/emoji-utils.js +13 -0
  147. package/dist/runtime/server/og-image/satori/transforms/emojis/fetch.d.ts +6 -0
  148. package/dist/runtime/server/og-image/satori/transforms/emojis/fetch.js +38 -0
  149. package/dist/runtime/server/og-image/satori/transforms/emojis/index.d.ts +7 -0
  150. package/dist/runtime/server/og-image/satori/transforms/emojis/index.js +64 -0
  151. package/dist/runtime/server/og-image/satori/transforms/emojis/local.d.ts +7 -0
  152. package/dist/runtime/server/og-image/satori/transforms/emojis/local.js +32 -0
  153. package/dist/runtime/server/og-image/satori/utils.js +5 -4
  154. package/dist/runtime/server/og-image/satori/vnodes.js +7 -6
  155. package/dist/runtime/server/og-image/takumi/instances.d.ts +1 -0
  156. package/dist/runtime/server/og-image/takumi/instances.js +6 -0
  157. package/dist/runtime/server/og-image/takumi/nodes.d.ts +12 -0
  158. package/dist/runtime/server/og-image/takumi/nodes.js +86 -0
  159. package/dist/runtime/server/og-image/takumi/renderer.d.ts +3 -0
  160. package/dist/runtime/server/og-image/takumi/renderer.js +45 -0
  161. package/dist/runtime/server/og-image/templates/html.js +32 -23
  162. package/dist/runtime/server/plugins/prerender.d.ts +1 -1
  163. package/dist/runtime/server/plugins/prerender.js +17 -7
  164. package/dist/runtime/server/util/auto-eject.d.ts +2 -0
  165. package/dist/runtime/server/util/auto-eject.js +30 -0
  166. package/dist/runtime/server/util/eventHandlers.d.ts +0 -1
  167. package/dist/runtime/server/util/eventHandlers.js +15 -85
  168. package/dist/runtime/server/util/options.d.ts +7 -2
  169. package/dist/runtime/server/util/options.js +40 -6
  170. package/dist/runtime/server/utils.d.ts +6 -2
  171. package/dist/runtime/server/utils.js +12 -8
  172. package/dist/runtime/shared/urlEncoding.d.ts +64 -0
  173. package/dist/runtime/shared/urlEncoding.js +194 -0
  174. package/dist/runtime/shared.d.ts +4 -9
  175. package/dist/runtime/shared.js +31 -50
  176. package/dist/runtime/types.d.ts +71 -25
  177. package/dist/shared/nuxt-og-image.D-QhzI76.mjs +2831 -0
  178. package/dist/shared/nuxt-og-image.iluFGbPR.cjs +2858 -0
  179. package/dist/types.d.mts +2 -0
  180. package/package.json +108 -44
  181. package/types/virtual.d.ts +7 -1
  182. package/dist/client/_nuxt/B3LgXoKV.js +0 -2
  183. package/dist/client/_nuxt/B8PEiB0p.js +0 -1
  184. package/dist/client/_nuxt/CPsbVDfV.js +0 -1
  185. package/dist/client/_nuxt/CVO1_9PV.js +0 -1
  186. package/dist/client/_nuxt/CjQm5wk3.js +0 -4029
  187. package/dist/client/_nuxt/Cp-IABpG.js +0 -1
  188. package/dist/client/_nuxt/D0TMZt8T.js +0 -1
  189. package/dist/client/_nuxt/D0r3Knsf.js +0 -1
  190. package/dist/client/_nuxt/builds/meta/eb2c0390-3125-4af7-b189-e76a7dfe3017.json +0 -1
  191. package/dist/client/_nuxt/entry.cdy4VsCK.css +0 -1
  192. package/dist/client/_nuxt/error-404.Cu4JbXd7.css +0 -1
  193. package/dist/client/_nuxt/error-500.B79uceR7.css +0 -1
  194. package/dist/runtime/app/components/OgImage/OgImage.d.ts +0 -3
  195. package/dist/runtime/app/components/OgImage/OgImage.js +0 -10
  196. package/dist/runtime/app/components/Templates/Community/BrandedLogo.d.vue.ts +0 -13
  197. package/dist/runtime/app/components/Templates/Community/BrandedLogo.vue +0 -22
  198. package/dist/runtime/app/components/Templates/Community/BrandedLogo.vue.d.ts +0 -13
  199. package/dist/runtime/app/components/Templates/Community/Frame.vue +0 -58
  200. package/dist/runtime/app/components/Templates/Community/Nuxt.d.vue.ts +0 -12
  201. package/dist/runtime/app/components/Templates/Community/Nuxt.vue.d.ts +0 -12
  202. package/dist/runtime/app/components/Templates/Community/NuxtSeo.d.vue.ts +0 -15
  203. package/dist/runtime/app/components/Templates/Community/NuxtSeo.vue +0 -103
  204. package/dist/runtime/app/components/Templates/Community/NuxtSeo.vue.d.ts +0 -15
  205. package/dist/runtime/app/components/Templates/Community/Pergel.d.vue.ts +0 -12
  206. package/dist/runtime/app/components/Templates/Community/Pergel.vue.d.ts +0 -12
  207. package/dist/runtime/app/components/Templates/Community/SimpleBlog.d.vue.ts +0 -9
  208. package/dist/runtime/app/components/Templates/Community/SimpleBlog.vue +0 -27
  209. package/dist/runtime/app/components/Templates/Community/SimpleBlog.vue.d.ts +0 -9
  210. package/dist/runtime/app/components/Templates/Community/Wave.d.vue.ts +0 -11
  211. package/dist/runtime/app/components/Templates/Community/Wave.vue +0 -28
  212. package/dist/runtime/app/components/Templates/Community/Wave.vue.d.ts +0 -11
  213. package/dist/runtime/app/components/Templates/Community/WithEmoji.d.vue.ts +0 -13
  214. package/dist/runtime/app/components/Templates/Community/WithEmoji.vue +0 -21
  215. package/dist/runtime/app/components/Templates/Community/WithEmoji.vue.d.ts +0 -13
  216. package/dist/runtime/assets/Inter-normal-400.ttf.base64 +0 -1
  217. package/dist/runtime/assets/Inter-normal-700.ttf.base64 +0 -1
  218. package/dist/runtime/server/og-image/satori/font.d.ts +0 -3
  219. package/dist/runtime/server/og-image/satori/font.js +0 -40
  220. package/dist/runtime/server/og-image/satori/plugins/unocss.js +0 -55
  221. package/dist/runtime/server/og-image/satori/transforms/emojis.d.ts +0 -3
  222. package/dist/runtime/server/og-image/satori/transforms/emojis.js +0 -3595
  223. package/dist/runtime/server/plugins/__zero-runtime/nuxt-content-v2.d.ts +0 -2
  224. package/dist/runtime/server/plugins/__zero-runtime/nuxt-content-v2.js +0 -9
  225. package/dist/runtime/server/plugins/nuxt-content-v2.d.ts +0 -2
  226. package/dist/runtime/server/plugins/nuxt-content-v2.js +0 -5
  227. package/dist/runtime/server/routes/__zero-runtime/font.d.ts +0 -2
  228. package/dist/runtime/server/routes/__zero-runtime/font.js +0 -8
  229. package/dist/runtime/server/routes/font.d.ts +0 -2
  230. package/dist/runtime/server/routes/font.js +0 -3
  231. package/dist/runtime/server/util/plugins.d.ts +0 -2
  232. package/dist/runtime/server/util/plugins.js +0 -56
  233. /package/dist/runtime/server/og-image/satori/plugins/{unocss.d.ts → twClasses.d.ts} +0 -0
@@ -0,0 +1,64 @@
1
+ import { getEmojiSvg } from "#og-image/emoji-transform";
2
+ import { RE_MATCH_EMOJIS } from "./emoji-utils.js";
3
+ let emojiCounter = 0;
4
+ function wrapDefsElements(svg) {
5
+ const defsElements = ["linearGradient", "radialGradient", "filter", "clipPath", "mask", "pattern"];
6
+ const defsRegex = new RegExp(`<(${defsElements.join("|")})[\\s\\S]*?<\\/\\1>`, "g");
7
+ if (svg.includes("<defs>") || svg.includes("<defs ")) {
8
+ return svg;
9
+ }
10
+ const foundDefs = [];
11
+ let result = svg.replace(defsRegex, (match) => {
12
+ foundDefs.push(match);
13
+ return "";
14
+ });
15
+ if (foundDefs.length > 0) {
16
+ const svgTagEnd = result.indexOf(">") + 1;
17
+ result = `${result.slice(0, svgTagEnd)}<defs>${foundDefs.join("")}</defs>${result.slice(svgTagEnd)}`;
18
+ }
19
+ return result;
20
+ }
21
+ function makeIdsUnique(svg) {
22
+ const prefix = `e${emojiCounter++}_`;
23
+ const ids = /* @__PURE__ */ new Set();
24
+ svg.replace(/\bid="([^"]+)"/g, (_, id) => {
25
+ ids.add(id);
26
+ return "";
27
+ });
28
+ let result = svg;
29
+ for (const id of ids) {
30
+ result = result.replace(new RegExp(`id="${id}"`, "g"), `id="${prefix}${id}"`).replace(new RegExp(`url\\(#${id}\\)`, "g"), `url(#${prefix}${id})`).replace(new RegExp(`href="#${id}"`, "g"), `href="#${prefix}${id}"`);
31
+ }
32
+ return result;
33
+ }
34
+ export async function applyEmojis(ctx, island) {
35
+ if (!island.html || !ctx.options.emojis)
36
+ return;
37
+ const matches = [...island.html.matchAll(RE_MATCH_EMOJIS)];
38
+ if (!matches.length)
39
+ return;
40
+ const emojiToSvg = /* @__PURE__ */ new Map();
41
+ const uniqueEmojis = [...new Set(matches.map((m) => m[0]))];
42
+ await Promise.all(uniqueEmojis.map(async (emoji) => {
43
+ let svg = await getEmojiSvg(ctx, emoji);
44
+ if (svg) {
45
+ svg = makeIdsUnique(svg);
46
+ svg = wrapDefsElements(svg);
47
+ }
48
+ emojiToSvg.set(emoji, svg ?? null);
49
+ }));
50
+ let html = island.html;
51
+ html = html.replace(/>([^<]*)</g, (fullMatch, textContent) => {
52
+ if (!textContent)
53
+ return fullMatch;
54
+ let newTextContent = textContent;
55
+ for (const [emoji, svg] of emojiToSvg) {
56
+ if (svg) {
57
+ const escaped = emoji.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
58
+ newTextContent = newTextContent.replace(new RegExp(escaped, "g"), svg);
59
+ }
60
+ }
61
+ return `>${newTextContent}<`;
62
+ });
63
+ island.html = html;
64
+ }
@@ -0,0 +1,7 @@
1
+ import type { OgImageRenderEventContext } from '../../../../../types.js';
2
+ /**
3
+ * Service function to get emoji SVGs from local iconify JSON files
4
+ * This does not perform HTML replacement - that's handled by the AST plugin
5
+ * This implementation prioritizes local deps over API calls (addresses issue #354)
6
+ */
7
+ export declare function getEmojiSvg(ctx: OgImageRenderEventContext, emojiChar: string): Promise<string | null>;
@@ -0,0 +1,32 @@
1
+ import { icons, height as pkgHeight, width as pkgWidth } from "#og-image-virtual/iconify-json-icons.mjs";
2
+ import { getEmojiCodePoint, getEmojiIconNames } from "./emoji-utils.js";
3
+ function wrapDefsElements(body) {
4
+ const defsElements = ["linearGradient", "radialGradient", "filter", "clipPath", "mask", "pattern"];
5
+ const defsRegex = new RegExp(`<(${defsElements.join("|")})[\\s\\S]*?<\\/\\1>`, "g");
6
+ if (body.includes("<defs>") || body.includes("<defs ")) {
7
+ return body;
8
+ }
9
+ const foundDefs = [];
10
+ const result = body.replace(defsRegex, (match) => {
11
+ foundDefs.push(match);
12
+ return "";
13
+ });
14
+ if (foundDefs.length > 0) {
15
+ return `<defs>${foundDefs.join("")}</defs>${result}`;
16
+ }
17
+ return body;
18
+ }
19
+ export async function getEmojiSvg(ctx, emojiChar) {
20
+ const codePoint = getEmojiCodePoint(emojiChar);
21
+ const possibleNames = getEmojiIconNames(codePoint, ctx.options.emojis);
22
+ for (const iconName of possibleNames) {
23
+ if (icons[iconName]) {
24
+ const iconData = icons[iconName];
25
+ const body = wrapDefsElements(iconData.body || "");
26
+ const width = iconData.width || pkgWidth || 128;
27
+ const height = iconData.height || pkgHeight || 128;
28
+ return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${width} ${height}" width="1em" height="1em" style="display:inline-block;vertical-align:middle">${body}</svg>`;
29
+ }
30
+ }
31
+ return null;
32
+ }
@@ -1,5 +1,10 @@
1
1
  export function walkSatoriTree(e, node, plugins) {
2
2
  const promises = [];
3
+ for (const plugin of plugins.flat()) {
4
+ if (plugin.filter(node)) {
5
+ promises.push(plugin.transform(node, e));
6
+ }
7
+ }
3
8
  if (!node.props?.children || !Array.isArray(node.props.children))
4
9
  return promises;
5
10
  if (node.props.children.length === 0) {
@@ -8,10 +13,6 @@ export function walkSatoriTree(e, node, plugins) {
8
13
  }
9
14
  for (const child of node.props.children || []) {
10
15
  if (child) {
11
- for (const plugin of plugins.flat()) {
12
- if (plugin.filter(child))
13
- promises.push(plugin.transform(child, e));
14
- }
15
16
  promises.push(
16
17
  ...walkSatoriTree(e, child, plugins)
17
18
  );
@@ -7,8 +7,8 @@ import encoding from "./plugins/encoding.js";
7
7
  import flex from "./plugins/flex.js";
8
8
  import imageSrc from "./plugins/imageSrc.js";
9
9
  import nuxtIcon from "./plugins/nuxt-icon.js";
10
- import unocss from "./plugins/unocss.js";
11
- import { applyEmojis } from "./transforms/emojis.js";
10
+ import twClasses from "./plugins/twClasses.js";
11
+ import { applyEmojis } from "./transforms/emojis/index.js";
12
12
  import { applyInlineCss } from "./transforms/inlineCss.js";
13
13
  import { walkSatoriTree } from "./utils.js";
14
14
  export async function createVNodes(ctx) {
@@ -16,8 +16,8 @@ export async function createVNodes(ctx) {
16
16
  if (!html) {
17
17
  const island = await fetchIsland(ctx.e, ctx.options.component, typeof ctx.options.props !== "undefined" ? ctx.options.props : ctx.options);
18
18
  island.html = htmlDecodeQuotes(island.html);
19
- await applyInlineCss(ctx, island);
20
19
  await applyEmojis(ctx, island);
20
+ await applyInlineCss(ctx, island);
21
21
  html = island.html;
22
22
  if (html?.includes("<body>")) {
23
23
  html = html.match(/<body>([\s\S]*)<\/body>/)?.[1] || "";
@@ -26,14 +26,15 @@ export async function createVNodes(ctx) {
26
26
  const template = `<div style="position: relative; display: flex; margin: 0 auto; width: ${ctx.options.width}px; height: ${ctx.options.height}px; overflow: hidden;">${html}</div>`;
27
27
  const satoriTree = convertHtmlToSatori(template);
28
28
  walkSatoriTree(ctx, satoriTree, [
29
- emojis,
30
29
  classes,
31
30
  flex,
32
31
  encoding,
33
- nuxtIcon
32
+ nuxtIcon,
33
+ twClasses
34
+ // Convert class -> tw and handle breakpoints
34
35
  ]);
35
36
  await Promise.all(walkSatoriTree(ctx, satoriTree, [
36
- unocss,
37
+ emojis,
37
38
  imageSrc
38
39
  ]));
39
40
  return satoriTree;
@@ -0,0 +1 @@
1
+ export declare function useTakumi(): Promise<any>;
@@ -0,0 +1,6 @@
1
+ const takumiInstance = { instance: void 0 };
2
+ export async function useTakumi() {
3
+ takumiInstance.instance = takumiInstance.instance || await import("#og-image/bindings/takumi").then((m) => m.default);
4
+ await takumiInstance.instance.initWasmPromise;
5
+ return takumiInstance.instance.Renderer;
6
+ }
@@ -0,0 +1,12 @@
1
+ import type { OgImageRenderEventContext } from '../../../types.js';
2
+ export interface TakumiNode {
3
+ type: 'container' | 'image' | 'text';
4
+ children?: TakumiNode[];
5
+ text?: string;
6
+ src?: string;
7
+ width?: number;
8
+ height?: number;
9
+ style?: Record<string, any>;
10
+ tw?: string;
11
+ }
12
+ export declare function createTakumiNodes(ctx: OgImageRenderEventContext): Promise<TakumiNode>;
@@ -0,0 +1,86 @@
1
+ import { parseHTML } from "linkedom";
2
+ import { htmlDecodeQuotes } from "../../util/encoding.js";
3
+ import { fetchIsland } from "../../util/kit.js";
4
+ import { applyEmojis } from "../satori/transforms/emojis/index.js";
5
+ import { applyInlineCss } from "../satori/transforms/inlineCss.js";
6
+ export async function createTakumiNodes(ctx) {
7
+ let html = ctx.options.html;
8
+ if (!html) {
9
+ const island = await fetchIsland(ctx.e, ctx.options.component, typeof ctx.options.props !== "undefined" ? ctx.options.props : ctx.options);
10
+ island.html = htmlDecodeQuotes(island.html);
11
+ await applyInlineCss(ctx, island);
12
+ await applyEmojis(ctx, island);
13
+ html = island.html;
14
+ if (html?.includes("<body>"))
15
+ html = html.match(/<body>([\s\S]*)<\/body>/)?.[1] || "";
16
+ }
17
+ const template = `<div style="position: relative; display: flex; margin: 0 auto; width: ${ctx.options.width}px; height: ${ctx.options.height}px; overflow: hidden;">${html}</div>`;
18
+ const { document } = parseHTML(template);
19
+ const root = document.documentElement;
20
+ return elementToNode(root, ctx);
21
+ }
22
+ function elementToNode(el, ctx) {
23
+ const tagName = el.tagName.toLowerCase();
24
+ if (tagName === "img") {
25
+ return {
26
+ type: "image",
27
+ src: resolveImageSrc(el.getAttribute("src") || "", ctx),
28
+ width: Number(el.getAttribute("width")) || void 0,
29
+ height: Number(el.getAttribute("height")) || void 0,
30
+ tw: el.getAttribute("class") || void 0,
31
+ style: parseStyleAttr(el.getAttribute("style"))
32
+ };
33
+ }
34
+ if (tagName === "svg") {
35
+ const svgString = el.outerHTML;
36
+ const dataUri = `data:image/svg+xml;base64,${Buffer.from(svgString).toString("base64")}`;
37
+ return {
38
+ type: "image",
39
+ src: dataUri,
40
+ width: Number(el.getAttribute("width")) || void 0,
41
+ height: Number(el.getAttribute("height")) || void 0
42
+ };
43
+ }
44
+ const firstChild = el.childNodes[0];
45
+ if (el.childNodes.length === 1 && firstChild?.nodeType === 3) {
46
+ return {
47
+ type: "text",
48
+ text: el.textContent || "",
49
+ tw: el.getAttribute("class") || void 0,
50
+ style: parseStyleAttr(el.getAttribute("style"))
51
+ };
52
+ }
53
+ const children = [];
54
+ for (const child of el.childNodes) {
55
+ if (child.nodeType === 1)
56
+ children.push(elementToNode(child, ctx));
57
+ else if (child.nodeType === 3 && child.textContent?.trim())
58
+ children.push({ type: "text", text: child.textContent.trim() });
59
+ }
60
+ return {
61
+ type: "container",
62
+ children: children.length ? children : void 0,
63
+ tw: el.getAttribute("class") || void 0,
64
+ style: parseStyleAttr(el.getAttribute("style"))
65
+ };
66
+ }
67
+ function resolveImageSrc(src, _ctx) {
68
+ if (src.startsWith("data:") || src.startsWith("http://") || src.startsWith("https://"))
69
+ return src;
70
+ return src;
71
+ }
72
+ function parseStyleAttr(style) {
73
+ if (!style)
74
+ return void 0;
75
+ const result = {};
76
+ for (const decl of style.split(";")) {
77
+ const [prop, ...valParts] = decl.split(":");
78
+ const val = valParts.join(":").trim();
79
+ if (prop?.trim() && val)
80
+ result[camelCase(prop.trim())] = val;
81
+ }
82
+ return Object.keys(result).length ? result : void 0;
83
+ }
84
+ function camelCase(str) {
85
+ return str.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
86
+ }
@@ -0,0 +1,3 @@
1
+ import type { Renderer } from '../../../types.js';
2
+ declare const TakumiRenderer: Renderer;
3
+ export default TakumiRenderer;
@@ -0,0 +1,45 @@
1
+ import { defu } from "defu";
2
+ import { loadAllFonts } from "../fonts.js";
3
+ import { useTakumi } from "./instances.js";
4
+ import { createTakumiNodes } from "./nodes.js";
5
+ let _takumiRenderer;
6
+ async function getTakumiRenderer(fonts) {
7
+ if (_takumiRenderer)
8
+ return _takumiRenderer;
9
+ const Renderer = await useTakumi();
10
+ _takumiRenderer = new Renderer({ fonts: fonts.filter((f) => f.data) });
11
+ return _takumiRenderer;
12
+ }
13
+ async function createImage(event, format) {
14
+ const { options } = event;
15
+ const [nodes, fonts] = await Promise.all([
16
+ createTakumiNodes(event),
17
+ loadAllFonts(event.e, { supportsWoff2: true })
18
+ ]);
19
+ await event._nitro.hooks.callHook("nuxt-og-image:takumi:nodes", nodes, event);
20
+ const renderer = await getTakumiRenderer(fonts);
21
+ const renderOptions = defu(options.takumi, {
22
+ width: options.width,
23
+ height: options.height,
24
+ format
25
+ });
26
+ return renderer.render(nodes, renderOptions);
27
+ }
28
+ const TakumiRenderer = {
29
+ name: "takumi",
30
+ supportedFormats: ["png", "jpeg", "jpg"],
31
+ async createImage(e) {
32
+ switch (e.extension) {
33
+ case "png":
34
+ return createImage(e, "png");
35
+ case "jpeg":
36
+ case "jpg":
37
+ return createImage(e, "jpeg");
38
+ }
39
+ },
40
+ async debug(e) {
41
+ const nodes = await createTakumiNodes(e);
42
+ return { nodes };
43
+ }
44
+ };
45
+ export default TakumiRenderer;
@@ -1,14 +1,33 @@
1
- import { theme } from "#og-image-virtual/unocss-config.mjs";
1
+ import { tw4Breakpoints, tw4Colors, tw4FontVars } from "#og-image-virtual/tw4-theme.mjs";
2
+ import resolvedFonts from "#og-image/fonts";
2
3
  import { createHeadCore } from "@unhead/vue";
3
4
  import { renderSSRHead } from "@unhead/vue/server";
4
5
  import { createError } from "h3";
5
- import { normaliseFontInput } from "../../../shared.js";
6
6
  import { fetchIsland } from "../../util/kit.js";
7
- import { useOgImageRuntimeConfig } from "../../utils.js";
8
- import { applyEmojis } from "../satori/transforms/emojis.js";
7
+ import { applyEmojis } from "../satori/transforms/emojis/index.js";
8
+ function buildTailwindConfig() {
9
+ const theme = {};
10
+ if (Object.keys(tw4Colors).length > 0)
11
+ theme.colors = tw4Colors;
12
+ const fontFamily = {};
13
+ if (tw4FontVars["font-sans"])
14
+ fontFamily.sans = [tw4FontVars["font-sans"]];
15
+ if (tw4FontVars["font-serif"])
16
+ fontFamily.serif = [tw4FontVars["font-serif"]];
17
+ if (tw4FontVars["font-mono"])
18
+ fontFamily.mono = [tw4FontVars["font-mono"]];
19
+ if (Object.keys(fontFamily).length > 0)
20
+ theme.fontFamily = fontFamily;
21
+ if (Object.keys(tw4Breakpoints).length > 0) {
22
+ theme.screens = Object.fromEntries(
23
+ Object.entries(tw4Breakpoints).map(([k, v]) => [k, `${v}px`])
24
+ );
25
+ }
26
+ return { theme: { extend: theme } };
27
+ }
9
28
  export async function html(ctx) {
10
29
  const { options } = ctx;
11
- const { fonts } = useOgImageRuntimeConfig();
30
+ const fonts = resolvedFonts;
12
31
  if (!options.component) {
13
32
  throw createError({
14
33
  statusCode: 500,
@@ -19,10 +38,9 @@ export async function html(ctx) {
19
38
  const head = createHeadCore();
20
39
  head.push(island.head);
21
40
  let defaultFontFamily = "sans-serif";
22
- const normalisedFonts = normaliseFontInput([...options.fonts || [], ...fonts]);
23
- const firstFont = normalisedFonts[0];
41
+ const firstFont = fonts[0];
24
42
  if (firstFont)
25
- defaultFontFamily = firstFont.name.replaceAll("+", " ");
43
+ defaultFontFamily = firstFont.family.replaceAll("+", " ");
26
44
  await applyEmojis(ctx, island);
27
45
  let html2 = island.html;
28
46
  head.push({
@@ -61,12 +79,13 @@ svg[data-emoji] {
61
79
  `
62
80
  },
63
81
  ...fonts.map((font) => {
82
+ const cacheKey = `${font.family}-${font.weight}-${font.style}`;
64
83
  return `
65
84
  @font-face {
66
- font-family: '${font.name.replaceAll("+", " ")}';
67
- font-style: normal;
85
+ font-family: '${font.family.replaceAll("+", " ")}';
86
+ font-style: ${font.style};
68
87
  font-weight: ${font.weight};
69
- src: url('/__og-image__/font/${font.key}') format('truetype');
88
+ src: url('/_og/f/${cacheKey}') format('truetype');
70
89
  }
71
90
  `;
72
91
  })
@@ -78,20 +97,10 @@ svg[data-emoji] {
78
97
  ],
79
98
  script: [
80
99
  {
81
- src: "https://cdn.jsdelivr.net/npm/@unocss/runtime/preset-wind.global.js"
82
- },
83
- {
84
- innerHTML: `
85
- window.__unocss = {
86
- theme: ${JSON.stringify(theme)},
87
- presets: [
88
- () => window.__unocss_runtime.presets.presetWind(),
89
- ],
90
- }
91
- `
100
+ src: "https://cdn.tailwindcss.com"
92
101
  },
93
102
  {
94
- src: "https://cdn.jsdelivr.net/npm/@unocss/runtime/core.global.js"
103
+ innerHTML: `tailwind.config = ${JSON.stringify(buildTailwindConfig())}`
95
104
  }
96
105
  ],
97
106
  link: [
@@ -1,2 +1,2 @@
1
- declare const _default: import("nitropack").NitroAppPlugin;
1
+ declare const _default: import("nitropack/types").NitroAppPlugin;
2
2
  export default _default;
@@ -1,10 +1,16 @@
1
1
  import { prerenderOptionsCache } from "#og-image-cache";
2
2
  import { createSitePathResolver } from "#site-config/server/composables/utils";
3
+ import { parse } from "devalue";
3
4
  import { defineNitroPlugin } from "nitropack/runtime";
4
5
  import { parseURL } from "ufo";
5
6
  import { isInternalRoute } from "../../shared.js";
6
- import { extractAndNormaliseOgImageOptions, resolvePathCacheKey } from "../og-image/context.js";
7
+ import { resolvePathCacheKey } from "../og-image/context.js";
7
8
  import { createNitroRouteRuleMatcher } from "../util/kit.js";
9
+ const PAYLOAD_REGEX = /<script.+id="nuxt-og-image-options"[^>]*>(.+?)<\/script>/;
10
+ function getPayloadFromHtml(html) {
11
+ const match = String(html).match(PAYLOAD_REGEX);
12
+ return match ? String(match[1]) : null;
13
+ }
8
14
  export default defineNitroPlugin(async (nitro) => {
9
15
  if (!import.meta.prerender)
10
16
  return;
@@ -17,18 +23,22 @@ export default defineNitroPlugin(async (nitro) => {
17
23
  const routeRules = routeRuleMatcher(path);
18
24
  if (routeRules.ogImage === false)
19
25
  return;
20
- const options = extractAndNormaliseOgImageOptions([
21
- head.join("\n"),
22
- bodyAppend.join("\n")
23
- ].join("\n"));
24
- if (!options)
26
+ const _payload = getPayloadFromHtml([head.join("\n"), bodyAppend.join("\n")].join("\n"));
27
+ if (!_payload)
25
28
  return;
29
+ const parsed = parse(_payload);
30
+ const payloads = parsed.map((opt) => [opt.key || "og", opt]);
26
31
  const resolvePathWithBase = createSitePathResolver(ctx.event, {
27
32
  absolute: false,
28
33
  withBase: true
29
34
  });
30
35
  const key = resolvePathCacheKey(ctx.event, resolvePathWithBase(path));
31
- await prerenderOptionsCache.setItem(key, options);
36
+ await prerenderOptionsCache.setItem(key, payloads);
37
+ for (const [_ogKey, opt] of payloads) {
38
+ if (opt._hash) {
39
+ await prerenderOptionsCache.setItem(`hash:${opt._hash}`, opt);
40
+ }
41
+ }
32
42
  const index = html.bodyAppend.findIndex((script) => script.includes('id="nuxt-og-image-options"'));
33
43
  if (index !== -1) {
34
44
  html.bodyAppend[index] = String(html.bodyAppend[index]).replace(/<script id="nuxt-og-image-options" type="application\/json">[\s\S]*?<\/script>/, "");
@@ -0,0 +1,2 @@
1
+ import type { OgImageComponent, OgImageRuntimeConfig } from '../../types.js';
2
+ export declare function autoEjectCommunityTemplate(component: OgImageComponent, runtimeConfig: OgImageRuntimeConfig): void;
@@ -0,0 +1,30 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { logger } from "./logger.js";
4
+ const ejectedTemplates = /* @__PURE__ */ new Set();
5
+ export function autoEjectCommunityTemplate(component, runtimeConfig) {
6
+ if (!import.meta.dev)
7
+ return;
8
+ const { srcDir, communityTemplatesDir } = runtimeConfig;
9
+ if (!srcDir || !communityTemplatesDir)
10
+ return;
11
+ if (ejectedTemplates.has(component.pascalName))
12
+ return;
13
+ ejectedTemplates.add(component.pascalName);
14
+ const baseName = component.pascalName.replace(/^OgImage/, "").replace(/(Satori|Chromium|Takumi)$/, "");
15
+ const filename = `${baseName}.${component.renderer}.vue`;
16
+ const outputDir = join(srcDir, "components", "OgImage");
17
+ const outputPath = join(outputDir, filename);
18
+ if (existsSync(outputPath))
19
+ return;
20
+ const templatePath = join(communityTemplatesDir, filename);
21
+ if (!existsSync(templatePath)) {
22
+ logger.warn(`[nuxt-og-image] Community template not found: ${templatePath}`);
23
+ return;
24
+ }
25
+ if (!existsSync(outputDir))
26
+ mkdirSync(outputDir, { recursive: true });
27
+ const content = readFileSync(templatePath, "utf-8");
28
+ writeFileSync(outputPath, content, "utf-8");
29
+ logger.info(`Auto-ejected community template "${baseName}" to ${outputPath}`);
30
+ }
@@ -1,3 +1,2 @@
1
1
  import type { H3Event } from 'h3';
2
- export declare function fontEventHandler(e: H3Event): Promise<any>;
3
2
  export declare function imageEventHandler(e: H3Event): Promise<any>;
@@ -1,99 +1,22 @@
1
- import { createError, getQuery, H3Error, proxyRequest, sendRedirect, setHeader, setResponseHeader } from "h3";
2
- import { parseURL } from "ufo";
3
- import { normaliseFontInput } from "../../shared.js";
1
+ import { useSiteConfig } from "#site-config/server/composables/useSiteConfig";
2
+ import { createError, H3Error, setHeader } from "h3";
3
+ import { getBuildCachedImage, setBuildCachedImage } from "../og-image/cache/buildCache.js";
4
4
  import { resolveContext } from "../og-image/context.js";
5
- import { assets } from "../og-image/satori/font.js";
5
+ import { fetchPathHtmlAndExtractOptions } from "../og-image/devtools.js";
6
6
  import { html } from "../og-image/templates/html.js";
7
7
  import { useOgImageRuntimeConfig } from "../utils.js";
8
8
  import { useOgImageBufferCache } from "./cache.js";
9
- export async function fontEventHandler(e) {
10
- const path = parseURL(e.path).pathname;
11
- const { fonts } = useOgImageRuntimeConfig();
12
- const key = path.split("/font/")[1];
13
- if (key && key.includes(":")) {
14
- const font2 = fonts.find((f) => f.key === key);
15
- if (font2?.key && await assets.hasItem(font2.key)) {
16
- let fontData = await assets.getItem(font2.key);
17
- if (fontData instanceof Uint8Array) {
18
- const decoder = new TextDecoder();
19
- fontData = decoder.decode(fontData);
20
- }
21
- if (key.includes(".oft")) {
22
- setResponseHeader(e, "Content-Type", "font/otf");
23
- } else if (key.includes(".woff2")) {
24
- setResponseHeader(e, "Content-Type", "font/woff2");
25
- } else if (key.includes(".ttf")) {
26
- setResponseHeader(e, "Content-Type", "font/ttf");
27
- }
28
- return Buffer.from(fontData, "base64");
29
- }
30
- }
31
- const [_name, _weight] = String(key?.split(".")[0]).split("/");
32
- if (!_name || !_weight)
33
- return "Provide a font name and weight";
34
- const name = String(_name[0]).toUpperCase() + _name.slice(1);
35
- const weight = Math.round(Number.parseInt(_weight) / 100) * 100;
36
- const config = useOgImageRuntimeConfig();
37
- const normalisedFonts = normaliseFontInput(config.fonts);
38
- let font;
39
- if (typeof getQuery(e).font === "string")
40
- font = JSON.parse(getQuery(e).font);
41
- if (!font) {
42
- font = normalisedFonts.find((font2) => {
43
- return font2.name.toLowerCase() === name.toLowerCase() && weight === Number(font2.weight);
44
- });
45
- }
46
- if (!font) {
47
- return createError({
48
- statusCode: 404,
49
- statusMessage: `[Nuxt OG Image] Font ${name}:${weight} not found`
50
- });
51
- }
52
- const css = await globalThis.$fetch(`https://fonts.googleapis.com/css2?family=${name}:wght@${weight}`, {
53
- headers: {
54
- // Make sure it returns TTF.
55
- "User-Agent": "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; de-at) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1"
56
- }
57
- });
58
- if (!css) {
59
- return createError({
60
- statusCode: 500,
61
- statusMessage: `[Nuxt OG Image] Invalid Google Font ${name}:${weight}`
62
- });
63
- }
64
- const ttfResource = css.match(/src: url\((.+)\) format\('(opentype|truetype)'\)/);
65
- if (ttfResource?.[1])
66
- return proxyRequest(e, ttfResource[1], {});
67
- const woff2Resource = css.match(/src: url\((.+)\) format\('woff2'\)/);
68
- if (woff2Resource?.[1])
69
- return sendRedirect(e, woff2Resource[1]);
70
- return createError({
71
- statusCode: 500,
72
- statusMessage: `[Nuxt OG Image] Malformed Google Font CSS ${css}`
73
- });
74
- }
75
9
  export async function imageEventHandler(e) {
76
10
  const ctx = await resolveContext(e);
77
11
  if (ctx instanceof H3Error)
78
12
  return ctx;
79
- const { isDebugJsonPayload, extension, options, renderer } = ctx;
13
+ const { isDevToolsContextRequest, extension, renderer } = ctx;
80
14
  const { debug, baseCacheKey } = useOgImageRuntimeConfig();
81
- const compatibilityHints = [];
82
- if (isDebugJsonPayload) {
83
- const queryExtension = getQuery(e).extension || ctx.options.extension;
84
- if (["jpeg", "jpg"].includes(queryExtension) && options.renderer === "satori")
85
- compatibilityHints.push("Converting PNGs to JPEGs requires Sharp which only runs on Node based systems.");
86
- if (options.renderer === "chromium")
87
- compatibilityHints.push("Using Chromium to generate images is only supported in Node based environments. It's recommended to only use this if you're prerendering");
15
+ if (import.meta.dev && isDevToolsContextRequest) {
88
16
  setHeader(e, "Content-Type", "application/json");
89
17
  return {
90
- siteConfig: {
91
- url: e.context.siteConfig.get().url
92
- },
93
- compatibilityHints,
94
- cacheKey: ctx.key,
95
- options: ctx.options,
96
- ...options.renderer === "satori" ? await renderer.debug(ctx) : void 0
18
+ extract: await fetchPathHtmlAndExtractOptions(e, ctx.basePath, ctx.key),
19
+ siteUrl: useSiteConfig(e).url
97
20
  };
98
21
  }
99
22
  switch (extension) {
@@ -131,6 +54,10 @@ export async function imageEventHandler(e) {
131
54
  statusMessage: `[Nuxt OG Image] Invalid request for og.${extension}.`
132
55
  });
133
56
  }
57
+ const buildCachedImage = import.meta.prerender ? getBuildCachedImage(ctx.options, extension) : null;
58
+ if (buildCachedImage) {
59
+ return buildCachedImage;
60
+ }
134
61
  const cacheApi = await useOgImageBufferCache(ctx, {
135
62
  cacheMaxAgeSeconds: ctx.options.cacheMaxAgeSeconds,
136
63
  baseCacheKey
@@ -151,6 +78,9 @@ export async function imageEventHandler(e) {
151
78
  });
152
79
  }
153
80
  await cacheApi.update(image);
81
+ if (import.meta.prerender && ctx.options.cacheMaxAgeSeconds) {
82
+ setBuildCachedImage(ctx.options, extension, image, ctx.options.cacheMaxAgeSeconds);
83
+ }
154
84
  }
155
85
  return image;
156
86
  }
@@ -1,2 +1,7 @@
1
- import type { DefineOgImageInput, OgImageOptions, OgImagePrebuilt } from '../../types.js';
2
- export declare function normaliseOptions(_options: DefineOgImageInput): OgImageOptions | OgImagePrebuilt;
1
+ import type { DefineOgImageInput, OgImageComponent, OgImageOptions, OgImagePrebuilt, RendererType } from '../../types.js';
2
+ export interface NormalisedOptions {
3
+ options: OgImageOptions | OgImagePrebuilt;
4
+ renderer: RendererType;
5
+ component?: OgImageComponent;
6
+ }
7
+ export declare function normaliseOptions(_options: DefineOgImageInput): NormalisedOptions;