nuxt-og-image 3.0.0-beta.4 → 3.0.0-beta.40

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 (136) hide show
  1. package/README.md +4 -4
  2. package/dist/client/200.html +5 -5
  3. package/dist/client/404.html +5 -5
  4. package/dist/client/_nuxt/{IconCSS.6583687a.js → IconCSS.783314f6.js} +1 -1
  5. package/dist/client/_nuxt/IconCSS.7e8f1f7b.css +1 -0
  6. package/dist/client/_nuxt/builds/latest.json +1 -1
  7. package/dist/client/_nuxt/builds/meta/88cd699e-6f5a-4788-a59e-8158fb29f04b.json +1 -0
  8. package/dist/client/_nuxt/entry.47aab0b4.css +1 -0
  9. package/dist/client/_nuxt/entry.e11cb5fa.js +137 -0
  10. package/dist/client/_nuxt/{error-404.214d08e9.js → error-404.c187917f.js} +1 -1
  11. package/dist/client/_nuxt/{error-500.f9a9234a.js → error-500.a1ce074a.js} +1 -1
  12. package/dist/client/index.html +5 -5
  13. package/dist/module.d.mts +45 -26
  14. package/dist/module.d.ts +45 -26
  15. package/dist/module.json +2 -2
  16. package/dist/module.mjs +176 -100
  17. package/dist/runtime/cache.d.ts +7 -10
  18. package/dist/runtime/cache.mjs +40 -27
  19. package/dist/runtime/components/OgImage/OgImage.d.ts +5 -0
  20. package/dist/runtime/components/OgImage/{index.mjs → OgImage.mjs} +1 -1
  21. package/dist/runtime/components/OgImage/OgImageScreenshot.d.ts +5 -0
  22. package/dist/runtime/components/OgImage/{Screenshot.mjs → OgImageScreenshot.mjs} +1 -1
  23. package/dist/runtime/components/Templates/{Official → Community}/BrandedLogo.vue +3 -2
  24. package/dist/runtime/components/Templates/Community/Nuxt.vue +6 -5
  25. package/dist/runtime/components/Templates/Community/NuxtSeo.vue +137 -0
  26. package/dist/runtime/components/Templates/{Official → Community}/SimpleBlog.vue +7 -5
  27. package/dist/runtime/components/Templates/Community/UnJs.vue +108 -0
  28. package/dist/runtime/components/Templates/{Official → Community}/Wave.vue +3 -2
  29. package/dist/runtime/components/Templates/{Official → Community}/WithEmoji.vue +3 -2
  30. package/dist/runtime/composables/defineOgImage.d.ts +2 -23
  31. package/dist/runtime/composables/defineOgImage.mjs +33 -116
  32. package/dist/runtime/composables/defineOgImageComponent.d.ts +3 -0
  33. package/dist/runtime/composables/defineOgImageComponent.mjs +8 -0
  34. package/dist/runtime/composables/defineOgImageScreenshot.d.ts +2 -0
  35. package/dist/runtime/composables/defineOgImageScreenshot.mjs +14 -0
  36. package/dist/runtime/core/bindings/css-inline/node.d.ts +2 -5
  37. package/dist/runtime/core/bindings/css-inline/node.mjs +2 -10
  38. package/dist/runtime/core/bindings/resvg/stackblitz.d.ts +40 -0
  39. package/dist/runtime/core/bindings/resvg/stackblitz.mjs +6 -0
  40. package/dist/runtime/core/bindings/resvg/wasm.mjs +2 -3
  41. package/dist/runtime/core/bindings/satori/stackblitz.mjs +13 -0
  42. package/dist/runtime/core/bindings/satori/wasm.d.ts +6 -0
  43. package/dist/runtime/core/bindings/satori/wasm.mjs +14 -0
  44. package/dist/runtime/core/cache/emojis.d.ts +1 -0
  45. package/dist/runtime/core/cache/emojis.mjs +5 -0
  46. package/dist/runtime/core/cache/htmlPayload.d.ts +5 -0
  47. package/dist/runtime/core/cache/htmlPayload.mjs +6 -0
  48. package/dist/runtime/core/cache/prerender.d.ts +1 -1
  49. package/dist/runtime/core/cache/prerender.mjs +1 -1
  50. package/dist/runtime/core/env/assets.d.ts +0 -1
  51. package/dist/runtime/core/env/assets.mjs +0 -4
  52. package/dist/runtime/core/font/fetch.d.ts +2 -3
  53. package/dist/runtime/core/font/fetch.mjs +32 -15
  54. package/dist/runtime/core/html/applyEmojis.d.ts +3 -0
  55. package/dist/runtime/core/html/applyEmojis.mjs +37 -0
  56. package/dist/runtime/core/html/applyInlineCss.d.ts +3 -0
  57. package/dist/runtime/core/html/applyInlineCss.mjs +32 -0
  58. package/dist/runtime/core/html/devIframeTemplate.d.ts +2 -0
  59. package/dist/runtime/core/html/{fetch.mjs → devIframeTemplate.mjs} +33 -42
  60. package/dist/runtime/core/html/fetchIsland.d.ts +3 -0
  61. package/dist/runtime/core/html/fetchIsland.mjs +17 -0
  62. package/dist/runtime/core/options/fetch.d.ts +1 -1
  63. package/dist/runtime/core/options/fetch.mjs +10 -5
  64. package/dist/runtime/core/options/normalise.d.ts +2 -2
  65. package/dist/runtime/core/options/normalise.mjs +3 -2
  66. package/dist/runtime/core/renderers/chromium/index.mjs +6 -7
  67. package/dist/runtime/core/renderers/chromium/screenshot.d.ts +2 -3
  68. package/dist/runtime/core/renderers/chromium/screenshot.mjs +8 -8
  69. package/dist/runtime/core/renderers/satori/fonts.d.ts +2 -2
  70. package/dist/runtime/core/renderers/satori/fonts.mjs +2 -2
  71. package/dist/runtime/core/renderers/satori/index.d.ts +2 -3
  72. package/dist/runtime/core/renderers/satori/index.mjs +25 -22
  73. package/dist/runtime/core/renderers/satori/instances.d.ts +3 -0
  74. package/dist/runtime/core/renderers/satori/instances.mjs +15 -0
  75. package/dist/runtime/core/renderers/satori/plugins/emojis.mjs +15 -13
  76. package/dist/runtime/core/renderers/satori/plugins/imageSrc.mjs +23 -10
  77. package/dist/runtime/core/renderers/satori/plugins/unocss.d.ts +2 -0
  78. package/dist/runtime/core/renderers/satori/plugins/unocss.mjs +45 -0
  79. package/dist/runtime/core/renderers/satori/utils.d.ts +2 -3
  80. package/dist/runtime/core/renderers/satori/vnodes.d.ts +2 -3
  81. package/dist/runtime/core/renderers/satori/vnodes.mjs +16 -6
  82. package/dist/runtime/core/utils/resolveRendererContext.d.ts +2 -6
  83. package/dist/runtime/core/utils/resolveRendererContext.mjs +42 -27
  84. package/dist/runtime/core/utils/wasm.d.ts +3 -0
  85. package/dist/runtime/core/utils/wasm.mjs +16 -0
  86. package/dist/runtime/nitro/plugins/nuxt-content.mjs +3 -4
  87. package/dist/runtime/nitro/plugins/prerender.d.ts +1 -1
  88. package/dist/runtime/nitro/plugins/prerender.mjs +20 -12
  89. package/dist/runtime/nitro/utils.d.ts +2 -0
  90. package/dist/runtime/nitro/utils.mjs +17 -0
  91. package/dist/runtime/nuxt/plugins/og-image-canonical-urls.server.mjs +31 -0
  92. package/dist/runtime/nuxt/plugins/route-rule-og-image.server.mjs +16 -50
  93. package/dist/runtime/nuxt/utils.d.ts +2 -0
  94. package/dist/runtime/nuxt/utils.mjs +53 -0
  95. package/dist/runtime/server/routes/__og-image__/debug.json.d.ts +1 -3
  96. package/dist/runtime/server/routes/__og-image__/debug.json.mjs +4 -8
  97. package/dist/runtime/server/routes/__og-image__/image.mjs +87 -0
  98. package/dist/runtime/types.d.ts +75 -25
  99. package/dist/runtime/utils.d.ts +4 -0
  100. package/dist/runtime/utils.mjs +11 -0
  101. package/dist/runtime/utils.pure.d.ts +5 -0
  102. package/dist/runtime/utils.pure.mjs +43 -0
  103. package/package.json +28 -30
  104. package/virtual.d.ts +49 -0
  105. package/dist/client/_nuxt/IconCSS.8f429b14.css +0 -1
  106. package/dist/client/_nuxt/builds/meta/0ca67bfd-95de-4c16-8f0a-055751cdca51.json +0 -1
  107. package/dist/client/_nuxt/entry.089f6f0f.js +0 -137
  108. package/dist/client/_nuxt/entry.434c2c45.css +0 -1
  109. package/dist/client/grid.png +0 -0
  110. package/dist/runtime/components/OgImage/Cached.d.ts +0 -5
  111. package/dist/runtime/components/OgImage/Cached.mjs +0 -10
  112. package/dist/runtime/components/OgImage/Dynamic.d.ts +0 -8
  113. package/dist/runtime/components/OgImage/Dynamic.mjs +0 -10
  114. package/dist/runtime/components/OgImage/Screenshot.d.ts +0 -6
  115. package/dist/runtime/components/OgImage/Static.d.ts +0 -8
  116. package/dist/runtime/components/OgImage/Static.mjs +0 -10
  117. package/dist/runtime/components/OgImage/WithoutCache.d.ts +0 -5
  118. package/dist/runtime/components/OgImage/WithoutCache.mjs +0 -10
  119. package/dist/runtime/components/OgImage/index.d.ts +0 -5
  120. package/dist/runtime/components/Templates/Official/Fallback.vue +0 -147
  121. package/dist/runtime/core/bindings/css-inline/mock.d.ts +0 -5
  122. package/dist/runtime/core/bindings/css-inline/mock.mjs +0 -3
  123. package/dist/runtime/core/bindings/satori/yoga-wasm.mjs +0 -7
  124. package/dist/runtime/core/bindings/sharp/wasm.d.ts +0 -2
  125. package/dist/runtime/core/bindings/sharp/wasm.mjs +0 -2
  126. package/dist/runtime/core/html/fetch.d.ts +0 -3
  127. package/dist/runtime/nuxt/plugins/nuxt-content-canonical-urls.mjs +0 -29
  128. package/dist/runtime/public-assets/__nuxt_og_image__/browser-provider-not-supported.png +0 -0
  129. package/dist/runtime/server/routes/__og-image__/image-[path]-og.[extension].mjs +0 -45
  130. package/dist/runtime/utilts.d.ts +0 -2
  131. package/dist/runtime/utilts.mjs +0 -8
  132. /package/dist/runtime/core/bindings/satori/{yoga-wasm.d.ts → stackblitz.d.ts} +0 -0
  133. /package/dist/runtime/nuxt/plugins/{nuxt-content-canonical-urls.d.ts → og-image-canonical-urls.server.d.ts} +0 -0
  134. /package/dist/runtime/{public-assets-optional/inter-font → server/assets}/inter-latin-ext-400-normal.woff +0 -0
  135. /package/dist/runtime/{public-assets-optional/inter-font → server/assets}/inter-latin-ext-700-normal.woff +0 -0
  136. /package/dist/runtime/server/routes/__og-image__/{image-[path]-og.[extension].d.ts → image.d.ts} +0 -0
@@ -1,13 +1,14 @@
1
1
  import { defu } from "defu";
2
+ import { useOgImageRuntimeConfig } from "../../../utils.mjs";
2
3
  import { createVNodes } from "./vnodes.mjs";
3
4
  import { loadFonts, satoriFonts } from "./fonts.mjs";
4
5
  import { useResvg, useSatori, useSharp } from "./instances.mjs";
5
- import { useRuntimeConfig } from "#imports";
6
- export async function createSvg(e, options) {
7
- const { fonts, satoriOptions } = useRuntimeConfig()["nuxt-og-image"];
8
- const vnodes = await createVNodes(e, options);
6
+ export async function createSvg(event) {
7
+ const { options } = event;
8
+ const { fonts, satoriOptions } = useOgImageRuntimeConfig();
9
+ const vnodes = await createVNodes(event);
9
10
  if (!satoriFonts.length)
10
- satoriFonts.push(...await loadFonts(e, fonts));
11
+ satoriFonts.push(...await loadFonts(event, fonts));
11
12
  const satori = await useSatori();
12
13
  return satori(vnodes, defu(options.satori, satoriOptions, {
13
14
  fonts: satoriFonts,
@@ -16,38 +17,40 @@ export async function createSvg(e, options) {
16
17
  height: options.height
17
18
  }));
18
19
  }
19
- async function createPng(e, options) {
20
- const { resvgOptions } = useRuntimeConfig()["nuxt-og-image"];
21
- const svg = await createSvg(e, options);
20
+ async function createPng(event) {
21
+ const { resvgOptions } = useOgImageRuntimeConfig();
22
+ const svg = await createSvg(event);
22
23
  const Resvg = await useResvg();
23
24
  const resvg = new Resvg(svg, defu(
24
- options.resvg,
25
+ event.options.resvg,
25
26
  resvgOptions
26
27
  ));
27
28
  const pngData = resvg.render();
28
29
  return pngData.asPng();
29
30
  }
30
- async function createJpeg(e, options) {
31
- const { sharpOptions } = useRuntimeConfig()["nuxt-og-image"];
32
- const png = await createPng(e, options);
31
+ async function createJpeg(event) {
32
+ const { sharpOptions } = useOgImageRuntimeConfig();
33
+ const png = await createPng(event);
33
34
  const sharp = await useSharp();
34
- return sharp(png, defu(options.sharp, sharpOptions)).jpeg(defu(options.sharp, sharpOptions)).toBuffer();
35
+ return sharp(png, defu(event.options.sharp, sharpOptions)).jpeg().toBuffer();
35
36
  }
36
37
  const SatoriRenderer = {
37
38
  name: "satori",
38
- supportedFormats: ["svg", "png", "jpeg", "jpg", "json"],
39
- async createImage(e, options) {
40
- switch (options.extension) {
41
- case "json":
42
- return createVNodes(e, options);
43
- case "svg":
44
- return createSvg(e, options);
39
+ supportedFormats: ["png", "jpeg", "jpg", "json"],
40
+ async createImage(e) {
41
+ switch (e.extension) {
45
42
  case "png":
46
- return createPng(e, options);
43
+ return createPng(e);
47
44
  case "jpeg":
48
45
  case "jpg":
49
- return createJpeg(e, options);
46
+ return createJpeg(e);
50
47
  }
48
+ },
49
+ async debug(e) {
50
+ return {
51
+ vnodes: await createVNodes(e),
52
+ svg: await createSvg(e)
53
+ };
51
54
  }
52
55
  };
53
56
  export default SatoriRenderer;
@@ -1,4 +1,6 @@
1
1
  import type _satori from 'satori';
2
+ export declare function useSatoriRenderer(): Promise<import("../../../types").Renderer>;
3
+ export declare function useChromiumRenderer(): Promise<import("../../../types").Renderer>;
2
4
  export declare function useResvg(): Promise<new (svg: string | Uint8Array, options?: import("@resvg/resvg-wasm").ResvgRenderOptions | undefined) => {
3
5
  free(): void;
4
6
  render(): {
@@ -37,3 +39,4 @@ export declare function useResvg(): Promise<new (svg: string | Uint8Array, optio
37
39
  }>;
38
40
  export declare function useSatori(): Promise<typeof _satori>;
39
41
  export declare function useSharp(): Promise<any>;
42
+ export declare function useCssInline(): Promise<any>;
@@ -1,6 +1,17 @@
1
+ const cssInlineInstance = { instance: void 0 };
1
2
  const sharpInstance = { instance: void 0 };
2
3
  const resvgInstance = { instance: void 0 };
3
4
  const satoriInstance = { instance: void 0 };
5
+ const satoriRendererInstance = { instance: void 0 };
6
+ const chromiumRendererInstance = { instance: void 0 };
7
+ export async function useSatoriRenderer() {
8
+ satoriRendererInstance.instance = satoriRendererInstance.instance || await import("#nuxt-og-image/renderers/satori").then((m) => m.default);
9
+ return satoriRendererInstance.instance;
10
+ }
11
+ export async function useChromiumRenderer() {
12
+ chromiumRendererInstance.instance = chromiumRendererInstance.instance || await import("#nuxt-og-image/renderers/chromium").then((m) => m.default);
13
+ return chromiumRendererInstance.instance;
14
+ }
4
15
  export async function useResvg() {
5
16
  resvgInstance.instance = resvgInstance.instance || await import("#nuxt-og-image/bindings/resvg").then((m) => m.default);
6
17
  await resvgInstance.instance.initWasmPromise;
@@ -15,3 +26,7 @@ export async function useSharp() {
15
26
  sharpInstance.instance = sharpInstance.instance || await import("#nuxt-og-image/bindings/sharp").then((m) => m.default);
16
27
  return sharpInstance.instance;
17
28
  }
29
+ export async function useCssInline() {
30
+ cssInlineInstance.instance = cssInlineInstance.instance || await import("#nuxt-og-image/bindings/css-inline").then((m) => m.default);
31
+ return cssInlineInstance.instance;
32
+ }
@@ -1,26 +1,28 @@
1
1
  import { defineSatoriTransformer } from "../utils.mjs";
2
2
  function isEmojiFilter(node) {
3
- return node.type === "img" && node.props?.class?.includes("emoji");
3
+ return node.type === "svg" && typeof node.props?.["data-emoji"] !== "undefined";
4
4
  }
5
5
  export default defineSatoriTransformer([
6
6
  // need to make sure parent div has flex for the emoji to render inline
7
7
  {
8
- filter: (node) => node.type === "div" && Array.isArray(node.props?.children) && node.props.children.some(isEmojiFilter),
8
+ filter: (node) => ["div", "p"].includes(node.type) && Array.isArray(node.props?.children) && node.props.children.some(isEmojiFilter),
9
9
  transform: async (node) => {
10
10
  node.props.style = node.props.style || {};
11
11
  node.props.style.display = "flex";
12
12
  node.props.style.alignItems = "center";
13
- }
14
- },
15
- {
16
- filter: isEmojiFilter,
17
- transform: async (node) => {
18
- node.props.style = node.props.style || {};
19
- node.props.style.height = "1em";
20
- node.props.style.width = "1em";
21
- node.props.style.margin = "0 .3em 0 .3em";
22
- node.props.style.verticalAlign = "0.1em";
23
- node.props.class = "";
13
+ node.props.children = node.props.children.map((child) => {
14
+ if (typeof child === "string") {
15
+ return {
16
+ type: "div",
17
+ props: {
18
+ children: child
19
+ }
20
+ };
21
+ }
22
+ if (child.props.class?.includes("emoji"))
23
+ delete child.props.class;
24
+ return child;
25
+ });
24
26
  }
25
27
  }
26
28
  ]);
@@ -3,28 +3,41 @@ import { withBase } from "ufo";
3
3
  import sizeOf from "image-size";
4
4
  import { defineSatoriTransformer } from "../utils.mjs";
5
5
  import { toBase64Image } from "../../../env/assets.mjs";
6
- import { useNitroOrigin } from "#imports";
6
+ import { useNitroOrigin, useStorage } from "#imports";
7
7
  export default defineSatoriTransformer({
8
8
  filter: (node) => node.type === "img",
9
- transform: async (node, e) => {
9
+ transform: async (node, { e }) => {
10
10
  const src = node.props?.src;
11
+ const isRelative = src?.startsWith("/");
11
12
  if (src) {
12
13
  let updated = false;
13
14
  let dimensions;
14
- if (!updated) {
15
- let valid = true;
16
- const response = await e.$fetch(src, {
15
+ let imageBuffer;
16
+ let valid = true;
17
+ if (import.meta.prerender || import.meta.dev) {
18
+ const key = `root:public${src.replace("./", ":").replace("/", ":")}`;
19
+ if (await useStorage().hasItem(key)) {
20
+ imageBuffer = await useStorage().getItemRaw(key);
21
+ updated = !!imageBuffer;
22
+ }
23
+ }
24
+ if (!import.meta.prerender && !updated) {
25
+ imageBuffer = await e.$fetch(src, {
17
26
  baseURL: useNitroOrigin(e),
18
27
  responseType: "arrayBuffer"
19
28
  }).catch(() => {
20
29
  valid = false;
21
30
  });
22
- if (valid) {
23
- node.props.src = toBase64Image(src, response);
24
- const imageSize = sizeOf(Buffer.from(response));
31
+ valid = !!imageBuffer;
32
+ }
33
+ if (valid) {
34
+ node.props.src = toBase64Image(src, imageBuffer);
35
+ try {
36
+ const imageSize = sizeOf(Buffer.from(imageBuffer));
25
37
  dimensions = { width: imageSize.width, height: imageSize.height };
26
- updated = true;
38
+ } catch (e2) {
27
39
  }
40
+ updated = true;
28
41
  }
29
42
  if (dimensions?.width && dimensions?.height) {
30
43
  const naturalAspectRatio = dimensions.width / dimensions.height;
@@ -37,7 +50,7 @@ export default defineSatoriTransformer({
37
50
  node.props.height = dimensions.height;
38
51
  }
39
52
  }
40
- if (!updated) {
53
+ if (!updated && isRelative) {
41
54
  node.props.src = `${withBase(src, `${useNitroOrigin(e)}`)}?${Date.now()}`;
42
55
  }
43
56
  }
@@ -0,0 +1,2 @@
1
+ declare const _default: import("../../../../types").SatoriTransformer | import("../../../../types").SatoriTransformer[];
2
+ export default _default;
@@ -0,0 +1,45 @@
1
+ import { createGenerator } from "@unocss/core";
2
+ import presetWind from "@unocss/preset-wind";
3
+ import { defineSatoriTransformer } from "../utils.mjs";
4
+ import { theme } from "#nuxt-og-image/unocss-config.mjs";
5
+ const uno = createGenerator({ theme }, {
6
+ presets: [
7
+ presetWind()
8
+ ]
9
+ });
10
+ export default defineSatoriTransformer({
11
+ filter: (node) => !!node.props?.class,
12
+ transform: async (node) => {
13
+ const classes = node.props.class || "";
14
+ const styles = node.props.style || {};
15
+ const replacedClasses = /* @__PURE__ */ new Set();
16
+ for (const token of classes.split(" ").filter((c) => c.trim())) {
17
+ const parsedToken = await uno.parseToken(token);
18
+ if (parsedToken) {
19
+ const inlineStyles = parsedToken[0][2].split(";").filter((s) => !!s?.trim());
20
+ const vars = {};
21
+ inlineStyles.filter((s) => s.startsWith("--")).forEach((s) => {
22
+ const [key, value] = s.split(":");
23
+ vars[key] = value;
24
+ });
25
+ inlineStyles.filter((s) => !s.startsWith("--")).forEach((s) => {
26
+ const [key, value] = s.split(":");
27
+ const camelCasedKey = key.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
28
+ if (!styles[camelCasedKey])
29
+ styles[camelCasedKey] = value.replace(/var\((.*?)\)/g, (_, k) => vars[k.trim()]);
30
+ if (styles[camelCasedKey] && styles[camelCasedKey].includes("/")) {
31
+ const [rgb, opacity] = styles[camelCasedKey].split("/");
32
+ if (opacity.trim() === "1)")
33
+ styles[camelCasedKey] = rgb.replace(/(\d+) (\d+) (\d+).*/, (_, r, g, b) => `${r}, ${g}, ${b})`);
34
+ else
35
+ styles[camelCasedKey] = `${rgb.replace("rgb", "rgba").replaceAll(" ", ", ")}${opacity.trim()}`;
36
+ }
37
+ });
38
+ replacedClasses.add(token);
39
+ }
40
+ }
41
+ node.props.class = classes.split(" ").filter((c) => !replacedClasses.has(c)).join(" ");
42
+ node.props.tw = classes.split(" ").filter((c) => !replacedClasses.has(c)).join(" ");
43
+ node.props.style = styles;
44
+ }
45
+ });
@@ -1,4 +1,3 @@
1
- import type { H3Event } from 'h3';
2
- import type { SatoriTransformer, VNode } from '../../../types';
3
- export declare function walkSatoriTree(e: H3Event, node: VNode, plugins: (SatoriTransformer | SatoriTransformer[])[]): Promise<void>;
1
+ import type { H3EventOgImageRender, SatoriTransformer, VNode } from '../../../types';
2
+ export declare function walkSatoriTree(e: H3EventOgImageRender, node: VNode, plugins: (SatoriTransformer | SatoriTransformer[])[]): Promise<void>;
4
3
  export declare function defineSatoriTransformer(transformer: SatoriTransformer | SatoriTransformer[]): SatoriTransformer | SatoriTransformer[];
@@ -1,3 +1,2 @@
1
- import type { H3Event } from 'h3';
2
- import type { RendererOptions, VNode } from '../../../types';
3
- export declare function createVNodes(e: H3Event, options: RendererOptions): Promise<VNode>;
1
+ import type { H3EventOgImageRender, VNode } from '../../../types';
2
+ export declare function createVNodes(ctx: H3EventOgImageRender): Promise<VNode>;
@@ -1,16 +1,26 @@
1
1
  import { html as convertHtmlToSatori } from "satori-html";
2
- import { fetchHTML } from "../../html/fetch.mjs";
2
+ import { fetchIsland } from "../../html/fetchIsland.mjs";
3
+ import { applyInlineCss } from "../../html/applyInlineCss.mjs";
4
+ import { applyEmojis } from "../../html/applyEmojis.mjs";
3
5
  import { walkSatoriTree } from "./utils.mjs";
6
+ import unocss from "./plugins/unocss.mjs";
4
7
  import emojis from "./plugins/emojis.mjs";
5
8
  import twClasses from "./plugins/twClasses.mjs";
6
9
  import imageSrc from "./plugins/imageSrc.mjs";
7
10
  import flex from "./plugins/flex.mjs";
8
11
  import encoding from "./plugins/encoding.mjs";
9
- export async function createVNodes(e, options) {
10
- const html = options.html || await fetchHTML(e, options);
11
- const body = html.match(/<body[^>]*>([\s\S]*)<\/body>/)?.[1] || html;
12
- const satoriTree = convertHtmlToSatori(body);
13
- await walkSatoriTree(e, satoriTree, [
12
+ export async function createVNodes(ctx) {
13
+ let html = ctx.options.html;
14
+ if (!html) {
15
+ const island = await fetchIsland(ctx);
16
+ await applyInlineCss(ctx, island);
17
+ await applyEmojis(ctx, island);
18
+ html = island.html;
19
+ }
20
+ const template = `<div data-v-inspector-ignore="true" style="position: relative; display: flex; margin: 0 auto; width: ${ctx.options.width}px; height: ${ctx.options.height}px; overflow: hidden;">${html}</div>`;
21
+ const satoriTree = convertHtmlToSatori(template);
22
+ await walkSatoriTree(ctx, satoriTree, [
23
+ unocss,
14
24
  emojis,
15
25
  twClasses,
16
26
  imageSrc,
@@ -1,7 +1,3 @@
1
1
  import type { H3Error, H3Event } from 'h3';
2
- import type { Renderer, RuntimeOgImageOptions } from '../../types';
3
- export declare function resolveRendererContext(e: H3Event): Promise<H3Error | {
4
- extension: RuntimeOgImageOptions['extension'];
5
- renderer: Renderer;
6
- options: RuntimeOgImageOptions;
7
- }>;
2
+ import type { H3EventOgImageRender } from '../../types';
3
+ export declare function resolveRendererContext(e: H3Event): Promise<H3Error | H3EventOgImageRender>;
@@ -1,14 +1,15 @@
1
- import { parseURL, withoutBase, withoutLeadingSlash, withoutTrailingSlash } from "ufo";
1
+ import { parseURL, withoutBase, withoutTrailingSlash } from "ufo";
2
2
  import { createError, getQuery } from "h3";
3
3
  import { defu } from "defu";
4
4
  import { createRouter as createRadixRouter, toRouteMatcher } from "radix3";
5
5
  import { fetchPathHtmlAndExtractOptions } from "../options/fetch.mjs";
6
- import { prerenderCache } from "../cache/prerender.mjs";
6
+ import { prerenderOptionsCache } from "../cache/prerender.mjs";
7
+ import { useChromiumRenderer, useSatoriRenderer } from "../renderers/satori/instances.mjs";
8
+ import { separateProps, useOgImageRuntimeConfig } from "../../utils.mjs";
9
+ import { resolvePathCacheKey } from "../../nitro/utils.mjs";
7
10
  import { useRuntimeConfig } from "#imports";
8
- const satoriRendererInstance = { instance: void 0 };
9
- const chromiumRendererInstance = { instance: void 0 };
10
11
  export async function resolveRendererContext(e) {
11
- const runtimeConfig = useRuntimeConfig()["nuxt-og-image"];
12
+ const runtimeConfig = useOgImageRuntimeConfig();
12
13
  const path = parseURL(e.path).pathname;
13
14
  const extension = path.split(".").pop();
14
15
  if (!extension) {
@@ -17,22 +18,29 @@ export async function resolveRendererContext(e) {
17
18
  statusMessage: `Missing OG Image type.`
18
19
  });
19
20
  }
21
+ if (!["png", "jpeg", "jpg", "svg", "html", "json"].includes(extension)) {
22
+ return createError({
23
+ statusCode: 400,
24
+ statusMessage: `Unknown OG Image type ${extension}.`
25
+ });
26
+ }
20
27
  const basePath = withoutTrailingSlash(
21
- path.replace("/__og-image__/image", "").replace(`/og.${extension}`, "")
28
+ path.replace(`/__og-image__/image`, "").replace(`/og.${extension}`, "")
22
29
  );
23
- const queryParams = { ...getQuery(e) };
30
+ let queryParams = { ...getQuery(e) };
31
+ queryParams.props = JSON.parse(queryParams.props || "{}");
32
+ queryParams = separateProps(queryParams);
33
+ const isDebugJsonPayload = extension === "json" && runtimeConfig.debug;
34
+ const key = resolvePathCacheKey(e, basePath);
24
35
  let options = queryParams.options;
25
36
  if (!options) {
26
- if (import.meta.prerender) {
27
- const key = [
28
- withoutLeadingSlash(basePath === "/" || !basePath ? "index" : basePath).replaceAll("/", "-")
29
- ].join(":");
30
- options = await prerenderCache?.getItem(key);
31
- } else {
32
- const payloadOptions = await fetchPathHtmlAndExtractOptions(e, basePath);
33
- if (payloadOptions instanceof Error)
34
- return payloadOptions;
35
- options = payloadOptions;
37
+ if (import.meta.prerender)
38
+ options = await prerenderOptionsCache?.getItem(key);
39
+ if (!options) {
40
+ const payload = await fetchPathHtmlAndExtractOptions(e, basePath, key);
41
+ if (payload instanceof Error)
42
+ return payload;
43
+ options = payload;
36
44
  }
37
45
  }
38
46
  delete queryParams.options;
@@ -41,8 +49,15 @@ export async function resolveRendererContext(e) {
41
49
  );
42
50
  const routeRules = defu({}, ..._routeRulesMatcher.matchAll(
43
51
  withoutBase(basePath.split("?")[0], useRuntimeConfig().app.baseURL)
44
- ).reverse()).ogImage;
45
- options = defu(queryParams, routeRules, options, runtimeConfig.defaults);
52
+ ).reverse());
53
+ if (typeof routeRules.ogImage === "undefined" && !options) {
54
+ return createError({
55
+ statusCode: 400,
56
+ statusMessage: "The route is missing the Nuxt OG Image payload or route rules."
57
+ });
58
+ }
59
+ const ogImageRouteRules = separateProps(routeRules.ogImage);
60
+ options = defu(queryParams, ogImageRouteRules, options, runtimeConfig.defaults);
46
61
  if (!options) {
47
62
  return createError({
48
63
  statusCode: 404,
@@ -52,25 +67,25 @@ export async function resolveRendererContext(e) {
52
67
  let renderer;
53
68
  switch (options.renderer) {
54
69
  case "satori":
55
- renderer = satoriRendererInstance.instance = satoriRendererInstance.instance || await import("#nuxt-og-image/renderers/satori").then((m) => Object.keys(m.default).length ? m.default : false);
70
+ renderer = await useSatoriRenderer();
56
71
  break;
57
72
  case "chromium":
58
- renderer = chromiumRendererInstance.instance = chromiumRendererInstance.instance || await import("#nuxt-og-image/renderers/chromium").then((m) => Object.keys(m.default).length ? m.default : false);
73
+ renderer = await useChromiumRenderer();
59
74
  break;
60
75
  }
61
- if (!renderer) {
76
+ if (!renderer || renderer.__unenv__) {
62
77
  throw createError({
63
78
  statusCode: 400,
64
79
  statusMessage: `Renderer ${options.renderer} is missing.`
65
80
  });
66
81
  }
67
82
  return {
83
+ e,
84
+ key,
68
85
  renderer,
86
+ isDebugJsonPayload,
69
87
  extension,
70
- options: {
71
- ...options,
72
- extension: extension === "json" ? options.extension : extension,
73
- path: basePath
74
- }
88
+ basePath,
89
+ options
75
90
  };
76
91
  }
@@ -0,0 +1,3 @@
1
+ /// <reference types="node" />
2
+ export declare function importWasm(input: any): Promise<any>;
3
+ export declare function readWasmFile(input: string): Promise<Buffer>;
@@ -0,0 +1,16 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { resolvePath } from "mlly";
3
+ export async function importWasm(input) {
4
+ const _input = await input;
5
+ const _module = _input.default || _input;
6
+ if (typeof _module === "function") {
7
+ const fnRes = await _module();
8
+ const _instance = fnRes.instance || fnRes;
9
+ return _instance.exports || _instance || _module;
10
+ }
11
+ return _module;
12
+ }
13
+ export async function readWasmFile(input) {
14
+ const path = await resolvePath(input);
15
+ return readFile(path);
16
+ }
@@ -1,16 +1,15 @@
1
1
  import { defineNitroPlugin } from "nitropack/dist/runtime/plugin";
2
2
  import { defu } from "defu";
3
- import { getOgImagePath } from "../../utilts.mjs";
4
- import { useRuntimeConfig } from "#imports";
3
+ import { getOgImagePath, useOgImageRuntimeConfig } from "../../utils.mjs";
5
4
  export default defineNitroPlugin((nitroApp) => {
6
5
  nitroApp.hooks.hook("content:file:afterParse", async (content) => {
7
6
  if (content._draft || content._extension !== "md" || content._partial || content.indexable === false || content.index === false)
8
7
  return;
9
8
  if (content.path && content.ogImage) {
10
9
  const ogImageConfig = typeof content.ogImage === "object" ? content.ogImage : {};
11
- const { defaults } = useRuntimeConfig()["nuxt-og-image"];
10
+ const { defaults } = useOgImageRuntimeConfig();
12
11
  const optionsWithDefault = defu(ogImageConfig, defaults);
13
- const src = getOgImagePath(content.path, optionsWithDefault.extension);
12
+ const src = getOgImagePath(content.path, optionsWithDefault);
14
13
  const payload = {
15
14
  title: content.title,
16
15
  excerpt: content.description || content.excerpt,
@@ -1,2 +1,2 @@
1
- declare const _default: import("nitropack/dist/runtime/plugin").NitroAppPlugin;
1
+ declare const _default: import("nitropack").NitroAppPlugin;
2
2
  export default _default;
@@ -1,17 +1,27 @@
1
- import { parseURL, withoutLeadingSlash } from "ufo";
2
- import { getRouteRules } from "nitropack/dist/runtime/route-rules";
3
- import { extractAndNormaliseOgImageOptions } from "../../core/options/extract.mjs";
4
- import { prerenderCache, prerenderChromiumContext } from "../../core/cache/prerender.mjs";
5
- import { isInternalRoute } from "../../utilts.mjs";
1
+ import { parseURL, withoutBase } from "ufo";
6
2
  import { defineNitroPlugin } from "nitropack/dist/runtime/plugin";
3
+ import { createRouter as createRadixRouter, toRouteMatcher } from "radix3";
4
+ import { defu } from "defu";
5
+ import { extractAndNormaliseOgImageOptions } from "../../core/options/extract.mjs";
6
+ import { prerenderChromiumContext, prerenderOptionsCache } from "../../core/cache/prerender.mjs";
7
+ import { isInternalRoute } from "../../utils.pure.mjs";
8
+ import { resolvePathCacheKey } from "../utils.mjs";
9
+ import { useRuntimeConfig } from "#imports";
7
10
  export default defineNitroPlugin(async (nitro) => {
8
11
  if (!import.meta.prerender)
9
12
  return;
10
- nitro.hooks.hook("render:html", async ({ head, bodyAppend }, e) => {
11
- const path = parseURL(e.event.path).pathname;
13
+ nitro.hooks.hook("render:html", async (html, ctx) => {
14
+ const { head, bodyAppend } = html;
15
+ const path = parseURL(ctx.event.path).pathname;
12
16
  if (isInternalRoute(path))
13
17
  return;
14
- const routeRules = getRouteRules(e)?.ogImage || {};
18
+ const runtimeConfig = useRuntimeConfig();
19
+ const _routeRulesMatcher = toRouteMatcher(
20
+ createRadixRouter({ routes: runtimeConfig.nitro?.routeRules })
21
+ );
22
+ const routeRules = defu({}, ..._routeRulesMatcher.matchAll(
23
+ withoutBase(path.split("?")[0], runtimeConfig.app.baseURL)
24
+ ).reverse()).ogImage;
15
25
  if (routeRules === false)
16
26
  return;
17
27
  const options = extractAndNormaliseOgImageOptions([
@@ -20,10 +30,8 @@ export default defineNitroPlugin(async (nitro) => {
20
30
  ].join("\n"));
21
31
  if (!options)
22
32
  return;
23
- const key = [
24
- withoutLeadingSlash(path === "/" || !path ? "index" : path).replaceAll("/", "-")
25
- ].join(":");
26
- await prerenderCache.setItem(key, options);
33
+ const key = resolvePathCacheKey(ctx.event);
34
+ await prerenderOptionsCache.setItem(key, options);
27
35
  });
28
36
  nitro.hooks.hook("close", () => {
29
37
  if (prerenderChromiumContext.browser) {
@@ -0,0 +1,2 @@
1
+ import type { H3Event } from 'h3';
2
+ export declare function resolvePathCacheKey(e: H3Event, path?: string): string;
@@ -0,0 +1,17 @@
1
+ import { withoutLeadingSlash, withoutTrailingSlash } from "ufo";
2
+ import { hash } from "ohash";
3
+ import { normalizeKey } from "unstorage";
4
+ import { getQuery } from "h3";
5
+ import { useSiteConfig } from "#imports";
6
+ export function resolvePathCacheKey(e, path) {
7
+ const siteConfig = useSiteConfig(e);
8
+ const basePath = withoutTrailingSlash(withoutLeadingSlash(normalizeKey(path || e.path)));
9
+ return [
10
+ !basePath ? "index" : basePath,
11
+ hash([
12
+ basePath,
13
+ siteConfig.url,
14
+ hash(getQuery(e))
15
+ ])
16
+ ].join(":");
17
+ }
@@ -0,0 +1,31 @@
1
+ import { parseURL } from "ufo";
2
+ import { toValue } from "vue";
3
+ import { isInternalRoute } from "../../utils.pure.mjs";
4
+ import { defineNuxtPlugin, useRequestEvent, withSiteUrl } from "#imports";
5
+ export default defineNuxtPlugin({
6
+ setup(nuxtApp) {
7
+ nuxtApp.hooks.hook("app:rendered", async (ctx) => {
8
+ const { ssrContext } = ctx;
9
+ const e = useRequestEvent();
10
+ const path = parseURL(e.path).pathname;
11
+ if (isInternalRoute(path))
12
+ return;
13
+ ssrContext?.head.use({
14
+ key: "nuxt-og-image:canonical-urls",
15
+ hooks: {
16
+ "tags:resolve": async ({ tags }) => {
17
+ for (const tag of tags) {
18
+ if (tag.tag === "meta" && (tag.props.property === "og:image" || tag.props.name === "twitter:image:src")) {
19
+ if (!tag.props.content.startsWith("https")) {
20
+ await nuxtApp.runWithContext(() => {
21
+ tag.props.content = toValue(withSiteUrl(tag.props.content));
22
+ });
23
+ }
24
+ }
25
+ }
26
+ }
27
+ }
28
+ });
29
+ });
30
+ }
31
+ });