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.
- package/README.md +1 -1
- package/bin/cli.mjs +2 -0
- package/dist/chunks/tw4-classes.cjs +116 -0
- package/dist/chunks/tw4-classes.mjs +113 -0
- package/dist/chunks/tw4-generator.cjs +118 -0
- package/dist/chunks/tw4-generator.mjs +110 -0
- package/dist/cli.cjs +433 -0
- package/dist/cli.d.cts +1 -0
- package/dist/cli.d.mts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.mjs +416 -0
- package/dist/client/200.html +1 -1
- package/dist/client/404.html +1 -1
- package/dist/client/_fonts/0xp3SbCWC1OhX7q1-uF6kilMZFm-alJNkUtkLTPCy_A-tN9KwPUWhhXvtqh74sU9FIkI4W6hsbm85r0X24hjOfM.woff2 +0 -0
- package/dist/client/_fonts/1ZTlEDqU4DtwDJiND8f6qaugUpa0RIDvQl-v7iM6l54-D6hedAgqRfOCLZzaShnyeAvlEnMzk4Wm7g9WDKWFHIc.woff +0 -0
- package/dist/client/_fonts/4HA9tc4y8BVQeLXvLn3JgQqilAj1xrAnUSprQGHIPSw-ZPswEL_UDOYaxTLQDUySPjoOHDxhD83pD19HMfKfK9s.woff2 +0 -0
- package/dist/client/_fonts/Bmul3LaKlc7BUKqJHE_UmEoF40Sg_2ga52yJjwyDcKs-TnYmYl1DNYkiWMu0Vx49DakCPBuiCCj9zoLIuQjUdKY.woff2 +0 -0
- package/dist/client/_fonts/DfgmjWGpWte3Q3a54Nevr_BYmMM5YEJXRI1CdI2VwO0-ox5RadQfCyVTmKl_hubTaIJjtRw9oaQz2GDBeZR6l1M.woff2 +0 -0
- package/dist/client/_fonts/Lc_5lWuBuZcZ166p1-s-mnGkMJwIYJE_QDCkws8iCkI-r45Qbm2hCykrfOZ0kowz__uTTTUOPDN9hz34QcRNTY4.woff2 +0 -0
- package/dist/client/_fonts/iEvApgDRmzKzNqOYocBTrmcHZmuGAJloawKDP1S0nyE-T3oc_9We24QGwfw5naik4cM0g7VxylWVaQwKm4dy3cw.woff2 +0 -0
- package/dist/client/_nuxt/0kYTU2a7.js +2 -0
- package/dist/client/_nuxt/B0QDx5EE.js +2 -0
- package/dist/client/_nuxt/BKqzYw6x.js +3 -0
- package/dist/client/_nuxt/C-Ivr2Rl.js +1 -0
- package/dist/client/_nuxt/CLgn8DCr.js +1 -0
- package/dist/client/_nuxt/CwWm-XE3.js +1 -0
- package/dist/client/_nuxt/D9eL2h5z.js +1 -0
- package/dist/client/_nuxt/DJXHIJSq.js +1 -0
- package/dist/client/_nuxt/DVnX3Z-O.js +1 -0
- package/dist/client/_nuxt/DXObZt09.js +184 -0
- package/dist/client/_nuxt/Dxi6QG7I.js +1 -0
- package/dist/client/_nuxt/E8AZ6HoH.js +1 -0
- package/dist/client/_nuxt/IFrameLoader.CGrV1TpP.css +1 -0
- package/dist/client/_nuxt/JAMwWy1K.js +3864 -0
- package/dist/client/_nuxt/OSectionBlock.BVHnMsIr.css +1 -0
- package/dist/client/_nuxt/PONEy9N-.js +1 -0
- package/dist/client/_nuxt/UdkqSAsD.js +1 -0
- package/dist/client/_nuxt/builds/latest.json +1 -1
- package/dist/client/_nuxt/builds/meta/8e2df3bd-1df7-4172-a3c9-b46cdb9070e5.json +1 -0
- package/dist/client/_nuxt/entry.BEExJd9R.css +2 -0
- package/dist/client/_nuxt/error-404.B79WD2X-.css +1 -0
- package/dist/client/_nuxt/error-500.DT3Sd0Wu.css +1 -0
- package/dist/client/_nuxt/pages.eW3hi7XF.css +1 -0
- package/dist/client/_nuxt/templates.dUiUBaip.css +1 -0
- package/dist/client/_payload.json +1 -0
- package/dist/client/debug/_payload.json +1 -0
- package/dist/client/debug/index.html +1 -0
- package/dist/client/docs/_payload.json +1 -0
- package/dist/client/docs/index.html +1 -0
- package/dist/client/fonts/HubotSans-Regular.woff2 +0 -0
- package/dist/client/index.html +1 -1
- package/dist/client/templates/_payload.json +1 -0
- package/dist/client/templates/index.html +1 -0
- package/dist/module.cjs +36 -1027
- package/dist/module.d.cts +63 -25
- package/dist/module.d.mts +63 -25
- package/dist/module.d.ts +63 -25
- package/dist/module.json +1 -1
- package/dist/module.mjs +32 -1009
- package/dist/runtime/app/components/Templates/Community/Brutalist.satori.d.vue.ts +14 -0
- package/dist/runtime/app/components/Templates/Community/Brutalist.satori.vue +51 -0
- package/dist/runtime/app/components/Templates/Community/Brutalist.satori.vue.d.ts +14 -0
- package/dist/runtime/app/components/Templates/Community/{Frame.vue.d.ts → Frame.satori.d.vue.ts} +2 -2
- package/dist/runtime/app/components/Templates/Community/Frame.satori.vue +71 -0
- package/dist/runtime/app/components/Templates/Community/{Frame.d.vue.ts → Frame.satori.vue.d.ts} +2 -2
- package/dist/runtime/app/components/Templates/Community/Newspaper.satori.d.vue.ts +12 -0
- package/dist/runtime/app/components/Templates/Community/Newspaper.satori.vue +70 -0
- package/dist/runtime/app/components/Templates/Community/Newspaper.satori.vue.d.ts +12 -0
- package/dist/runtime/app/components/Templates/Community/Nuxt.satori.d.vue.ts +12 -0
- package/dist/runtime/app/components/Templates/Community/{Nuxt.vue → Nuxt.satori.vue} +3 -3
- package/dist/runtime/app/components/Templates/Community/Nuxt.satori.vue.d.ts +12 -0
- package/dist/runtime/app/components/Templates/Community/NuxtSeo.satori.d.vue.ts +12 -0
- package/dist/runtime/app/components/Templates/Community/NuxtSeo.satori.vue +69 -0
- package/dist/runtime/app/components/Templates/Community/NuxtSeo.satori.vue.d.ts +12 -0
- package/dist/runtime/app/components/Templates/Community/Pergel.satori.d.vue.ts +12 -0
- package/dist/runtime/app/components/Templates/Community/{Pergel.vue → Pergel.satori.vue} +14 -11
- package/dist/runtime/app/components/Templates/Community/Pergel.satori.vue.d.ts +12 -0
- package/dist/runtime/app/components/Templates/Community/Retro.satori.d.vue.ts +12 -0
- package/dist/runtime/app/components/Templates/Community/Retro.satori.vue +64 -0
- package/dist/runtime/app/components/Templates/Community/Retro.satori.vue.d.ts +12 -0
- package/dist/runtime/app/components/Templates/Community/SaaS.satori.d.vue.ts +12 -0
- package/dist/runtime/app/components/Templates/Community/SaaS.satori.vue +60 -0
- package/dist/runtime/app/components/Templates/Community/SaaS.satori.vue.d.ts +12 -0
- package/dist/runtime/app/components/Templates/Community/SimpleBlog.satori.d.vue.ts +9 -0
- package/dist/runtime/app/components/Templates/Community/SimpleBlog.satori.vue +38 -0
- package/dist/runtime/app/components/Templates/Community/SimpleBlog.satori.vue.d.ts +9 -0
- package/dist/runtime/app/components/Templates/Community/{UnJs.d.vue.ts → UnJs.satori.d.vue.ts} +2 -2
- package/dist/runtime/app/components/Templates/Community/{UnJs.vue → UnJs.satori.vue} +41 -33
- package/dist/runtime/app/components/Templates/Community/{UnJs.vue.d.ts → UnJs.satori.vue.d.ts} +2 -2
- package/dist/runtime/app/components/Templates/Community/WithEmoji.satori.d.vue.ts +13 -0
- package/dist/runtime/app/components/Templates/Community/WithEmoji.satori.vue +27 -0
- package/dist/runtime/app/components/Templates/Community/WithEmoji.satori.vue.d.ts +13 -0
- package/dist/runtime/app/composables/_defineOgImageRaw.d.ts +6 -0
- package/dist/runtime/app/composables/_defineOgImageRaw.js +70 -0
- package/dist/runtime/app/composables/defineOgImage.d.ts +14 -2
- package/dist/runtime/app/composables/defineOgImage.js +13 -42
- package/dist/runtime/app/composables/defineOgImageComponent.d.ts +5 -1
- package/dist/runtime/app/composables/defineOgImageComponent.js +4 -5
- package/dist/runtime/app/composables/defineOgImageScreenshot.d.ts +1 -1
- package/dist/runtime/app/composables/defineOgImageScreenshot.js +2 -2
- package/dist/runtime/app/composables/mock.d.ts +7 -4
- package/dist/runtime/app/composables/mock.js +4 -4
- package/dist/runtime/app/utils/plugins.js +22 -28
- package/dist/runtime/app/utils.d.ts +15 -1
- package/dist/runtime/app/utils.js +74 -46
- package/dist/runtime/pure.d.ts +7 -0
- package/dist/runtime/pure.js +105 -0
- package/dist/runtime/server/og-image/bindings/css-inline/wasm-fs.d.ts +3 -2
- package/dist/runtime/server/og-image/bindings/css-inline/wasm.d.ts +3 -2
- package/dist/runtime/server/og-image/bindings/font-assets/cloudflare.d.ts +3 -0
- package/dist/runtime/server/og-image/bindings/font-assets/cloudflare.js +22 -0
- package/dist/runtime/server/og-image/bindings/font-assets/dev-prerender.d.ts +3 -0
- package/dist/runtime/server/og-image/bindings/font-assets/dev-prerender.js +49 -0
- package/dist/runtime/server/og-image/bindings/font-assets/node.d.ts +3 -0
- package/dist/runtime/server/og-image/bindings/font-assets/node.js +14 -0
- package/dist/runtime/server/og-image/bindings/resvg/node-dev.d.ts +5 -0
- package/dist/runtime/server/og-image/bindings/resvg/node-dev.js +70 -0
- package/dist/runtime/server/og-image/bindings/takumi/node.d.ts +6 -0
- package/dist/runtime/server/og-image/bindings/takumi/node.js +5 -0
- package/dist/runtime/server/og-image/bindings/takumi/wasm.d.ts +6 -0
- package/dist/runtime/server/og-image/bindings/takumi/wasm.js +6 -0
- package/dist/runtime/server/og-image/cache/buildCache.d.ts +16 -0
- package/dist/runtime/server/og-image/cache/buildCache.js +48 -0
- package/dist/runtime/server/og-image/cache/lru.d.ts +2 -2
- package/dist/runtime/server/og-image/cache/lru.js +3 -3
- package/dist/runtime/server/og-image/cache/mock.d.ts +1 -2
- package/dist/runtime/server/og-image/cache/mock.js +0 -1
- package/dist/runtime/server/og-image/chromium/screenshot.js +4 -3
- package/dist/runtime/server/og-image/context.d.ts +2 -3
- package/dist/runtime/server/og-image/context.js +55 -193
- package/dist/runtime/server/og-image/devtools.d.ts +10 -0
- package/dist/runtime/server/og-image/devtools.js +74 -0
- package/dist/runtime/server/og-image/fonts.d.ts +6 -0
- package/dist/runtime/server/og-image/fonts.js +41 -0
- package/dist/runtime/server/og-image/instances.d.ts +1 -0
- package/dist/runtime/server/og-image/instances.js +5 -0
- package/dist/runtime/server/og-image/satori/instances.d.ts +1 -36
- package/dist/runtime/server/og-image/satori/plugins/emojis.js +83 -4
- package/dist/runtime/server/og-image/satori/plugins/encoding.js +11 -1
- package/dist/runtime/server/og-image/satori/plugins/imageSrc.js +5 -1
- package/dist/runtime/server/og-image/satori/plugins/twClasses.js +35 -0
- package/dist/runtime/server/og-image/satori/renderer.js +16 -53
- package/dist/runtime/server/og-image/satori/transforms/emojis/emoji-names-minimal.d.ts +1 -0
- package/dist/runtime/server/og-image/satori/transforms/emojis/emoji-names-minimal.js +223 -0
- package/dist/runtime/server/og-image/satori/transforms/emojis/emoji-utils.d.ts +45 -0
- package/dist/runtime/server/og-image/satori/transforms/emojis/emoji-utils.js +13 -0
- package/dist/runtime/server/og-image/satori/transforms/emojis/fetch.d.ts +6 -0
- package/dist/runtime/server/og-image/satori/transforms/emojis/fetch.js +38 -0
- package/dist/runtime/server/og-image/satori/transforms/emojis/index.d.ts +7 -0
- package/dist/runtime/server/og-image/satori/transforms/emojis/index.js +64 -0
- package/dist/runtime/server/og-image/satori/transforms/emojis/local.d.ts +7 -0
- package/dist/runtime/server/og-image/satori/transforms/emojis/local.js +32 -0
- package/dist/runtime/server/og-image/satori/utils.js +5 -4
- package/dist/runtime/server/og-image/satori/vnodes.js +7 -6
- package/dist/runtime/server/og-image/takumi/instances.d.ts +1 -0
- package/dist/runtime/server/og-image/takumi/instances.js +6 -0
- package/dist/runtime/server/og-image/takumi/nodes.d.ts +12 -0
- package/dist/runtime/server/og-image/takumi/nodes.js +86 -0
- package/dist/runtime/server/og-image/takumi/renderer.d.ts +3 -0
- package/dist/runtime/server/og-image/takumi/renderer.js +45 -0
- package/dist/runtime/server/og-image/templates/html.js +32 -23
- package/dist/runtime/server/plugins/prerender.d.ts +1 -1
- package/dist/runtime/server/plugins/prerender.js +17 -7
- package/dist/runtime/server/util/auto-eject.d.ts +2 -0
- package/dist/runtime/server/util/auto-eject.js +30 -0
- package/dist/runtime/server/util/eventHandlers.d.ts +0 -1
- package/dist/runtime/server/util/eventHandlers.js +15 -85
- package/dist/runtime/server/util/options.d.ts +7 -2
- package/dist/runtime/server/util/options.js +40 -6
- package/dist/runtime/server/utils.d.ts +6 -2
- package/dist/runtime/server/utils.js +12 -8
- package/dist/runtime/shared/urlEncoding.d.ts +64 -0
- package/dist/runtime/shared/urlEncoding.js +194 -0
- package/dist/runtime/shared.d.ts +4 -9
- package/dist/runtime/shared.js +31 -50
- package/dist/runtime/types.d.ts +71 -25
- package/dist/shared/nuxt-og-image.D-QhzI76.mjs +2831 -0
- package/dist/shared/nuxt-og-image.iluFGbPR.cjs +2858 -0
- package/dist/types.d.mts +2 -0
- package/package.json +108 -44
- package/types/virtual.d.ts +7 -1
- package/dist/client/_nuxt/B3LgXoKV.js +0 -2
- package/dist/client/_nuxt/B8PEiB0p.js +0 -1
- package/dist/client/_nuxt/CPsbVDfV.js +0 -1
- package/dist/client/_nuxt/CVO1_9PV.js +0 -1
- package/dist/client/_nuxt/CjQm5wk3.js +0 -4029
- package/dist/client/_nuxt/Cp-IABpG.js +0 -1
- package/dist/client/_nuxt/D0TMZt8T.js +0 -1
- package/dist/client/_nuxt/D0r3Knsf.js +0 -1
- package/dist/client/_nuxt/builds/meta/eb2c0390-3125-4af7-b189-e76a7dfe3017.json +0 -1
- package/dist/client/_nuxt/entry.cdy4VsCK.css +0 -1
- package/dist/client/_nuxt/error-404.Cu4JbXd7.css +0 -1
- package/dist/client/_nuxt/error-500.B79uceR7.css +0 -1
- package/dist/runtime/app/components/OgImage/OgImage.d.ts +0 -3
- package/dist/runtime/app/components/OgImage/OgImage.js +0 -10
- package/dist/runtime/app/components/Templates/Community/BrandedLogo.d.vue.ts +0 -13
- package/dist/runtime/app/components/Templates/Community/BrandedLogo.vue +0 -22
- package/dist/runtime/app/components/Templates/Community/BrandedLogo.vue.d.ts +0 -13
- package/dist/runtime/app/components/Templates/Community/Frame.vue +0 -58
- package/dist/runtime/app/components/Templates/Community/Nuxt.d.vue.ts +0 -12
- package/dist/runtime/app/components/Templates/Community/Nuxt.vue.d.ts +0 -12
- package/dist/runtime/app/components/Templates/Community/NuxtSeo.d.vue.ts +0 -15
- package/dist/runtime/app/components/Templates/Community/NuxtSeo.vue +0 -103
- package/dist/runtime/app/components/Templates/Community/NuxtSeo.vue.d.ts +0 -15
- package/dist/runtime/app/components/Templates/Community/Pergel.d.vue.ts +0 -12
- package/dist/runtime/app/components/Templates/Community/Pergel.vue.d.ts +0 -12
- package/dist/runtime/app/components/Templates/Community/SimpleBlog.d.vue.ts +0 -9
- package/dist/runtime/app/components/Templates/Community/SimpleBlog.vue +0 -27
- package/dist/runtime/app/components/Templates/Community/SimpleBlog.vue.d.ts +0 -9
- package/dist/runtime/app/components/Templates/Community/Wave.d.vue.ts +0 -11
- package/dist/runtime/app/components/Templates/Community/Wave.vue +0 -28
- package/dist/runtime/app/components/Templates/Community/Wave.vue.d.ts +0 -11
- package/dist/runtime/app/components/Templates/Community/WithEmoji.d.vue.ts +0 -13
- package/dist/runtime/app/components/Templates/Community/WithEmoji.vue +0 -21
- package/dist/runtime/app/components/Templates/Community/WithEmoji.vue.d.ts +0 -13
- package/dist/runtime/assets/Inter-normal-400.ttf.base64 +0 -1
- package/dist/runtime/assets/Inter-normal-700.ttf.base64 +0 -1
- package/dist/runtime/server/og-image/satori/font.d.ts +0 -3
- package/dist/runtime/server/og-image/satori/font.js +0 -40
- package/dist/runtime/server/og-image/satori/plugins/unocss.js +0 -55
- package/dist/runtime/server/og-image/satori/transforms/emojis.d.ts +0 -3
- package/dist/runtime/server/og-image/satori/transforms/emojis.js +0 -3595
- package/dist/runtime/server/plugins/__zero-runtime/nuxt-content-v2.d.ts +0 -2
- package/dist/runtime/server/plugins/__zero-runtime/nuxt-content-v2.js +0 -9
- package/dist/runtime/server/plugins/nuxt-content-v2.d.ts +0 -2
- package/dist/runtime/server/plugins/nuxt-content-v2.js +0 -5
- package/dist/runtime/server/routes/__zero-runtime/font.d.ts +0 -2
- package/dist/runtime/server/routes/__zero-runtime/font.js +0 -8
- package/dist/runtime/server/routes/font.d.ts +0 -2
- package/dist/runtime/server/routes/font.js +0 -3
- package/dist/runtime/server/util/plugins.d.ts +0 -2
- package/dist/runtime/server/util/plugins.js +0 -56
- /package/dist/runtime/server/og-image/satori/plugins/{unocss.d.ts → twClasses.d.ts} +0 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { componentNames } from "#og-image-virtual/component-names.mjs";
|
|
3
|
+
import { join } from "pathe";
|
|
4
|
+
import { hashOgImageOptions } from "../../../shared/urlEncoding.js";
|
|
5
|
+
import { useOgImageRuntimeConfig } from "../../utils.js";
|
|
6
|
+
export function getComponentHash(componentName) {
|
|
7
|
+
const components = componentNames;
|
|
8
|
+
const component = components.find(
|
|
9
|
+
(c) => c.pascalName === componentName || c.kebabName === componentName
|
|
10
|
+
);
|
|
11
|
+
return component?.hash || "";
|
|
12
|
+
}
|
|
13
|
+
export function generateBuildCacheKey(options, extension) {
|
|
14
|
+
const { version } = useOgImageRuntimeConfig();
|
|
15
|
+
const componentHash = getComponentHash(options.component || "NuxtSeo");
|
|
16
|
+
const hash = hashOgImageOptions(options, componentHash, version);
|
|
17
|
+
return `${hash}.${extension}`;
|
|
18
|
+
}
|
|
19
|
+
export function getBuildCachedImage(options, extension) {
|
|
20
|
+
const { buildCacheDir } = useOgImageRuntimeConfig();
|
|
21
|
+
if (!buildCacheDir)
|
|
22
|
+
return null;
|
|
23
|
+
const cacheKey = generateBuildCacheKey(options, extension);
|
|
24
|
+
const cachePath = join(buildCacheDir, cacheKey);
|
|
25
|
+
if (!existsSync(cachePath))
|
|
26
|
+
return null;
|
|
27
|
+
const cached = JSON.parse(readFileSync(cachePath, "utf-8"));
|
|
28
|
+
if (cached.expiresAt && cached.expiresAt < Date.now()) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
return Buffer.from(cached.data, "base64");
|
|
32
|
+
}
|
|
33
|
+
export function setBuildCachedImage(options, extension, data, maxAgeSeconds) {
|
|
34
|
+
const { buildCacheDir } = useOgImageRuntimeConfig();
|
|
35
|
+
if (!buildCacheDir)
|
|
36
|
+
return;
|
|
37
|
+
const cacheKey = generateBuildCacheKey(options, extension);
|
|
38
|
+
const cachePath = join(buildCacheDir, cacheKey);
|
|
39
|
+
if (!existsSync(buildCacheDir)) {
|
|
40
|
+
mkdirSync(buildCacheDir, { recursive: true });
|
|
41
|
+
}
|
|
42
|
+
const cached = {
|
|
43
|
+
data: Buffer.from(data).toString("base64"),
|
|
44
|
+
expiresAt: Date.now() + maxAgeSeconds * 1e3,
|
|
45
|
+
createdAt: Date.now()
|
|
46
|
+
};
|
|
47
|
+
writeFileSync(cachePath, JSON.stringify(cached));
|
|
48
|
+
}
|
|
@@ -4,6 +4,6 @@ export declare const htmlPayloadCache: Storage<{
|
|
|
4
4
|
expiresAt: number;
|
|
5
5
|
value: OgImageOptions;
|
|
6
6
|
}>;
|
|
7
|
-
export declare const prerenderOptionsCache: Storage<OgImageOptions> | undefined;
|
|
8
|
-
export declare const fontCache: Storage<BufferSource>;
|
|
7
|
+
export declare const prerenderOptionsCache: Storage<OgImageOptions | [string, OgImageOptions][]> | undefined;
|
|
9
8
|
export declare const emojiCache: Storage<string>;
|
|
9
|
+
export declare const fontCache: Storage<string>;
|
|
@@ -7,9 +7,9 @@ export const htmlPayloadCache = createStorage({
|
|
|
7
7
|
export const prerenderOptionsCache = import.meta.prerender ? createStorage({
|
|
8
8
|
driver: lruCacheDriver({ max: 1e4 })
|
|
9
9
|
}) : void 0;
|
|
10
|
-
export const fontCache = createStorage({
|
|
11
|
-
driver: lruCacheDriver({ max: 10 })
|
|
12
|
-
});
|
|
13
10
|
export const emojiCache = createStorage({
|
|
14
11
|
driver: lruCacheDriver({ max: 1e3 })
|
|
15
12
|
});
|
|
13
|
+
export const fontCache = createStorage({
|
|
14
|
+
driver: lruCacheDriver({ max: 100 })
|
|
15
|
+
});
|
|
@@ -4,6 +4,5 @@ export declare const htmlPayloadCache: Storage<{
|
|
|
4
4
|
expiresAt: number;
|
|
5
5
|
value: OgImageOptions;
|
|
6
6
|
}>;
|
|
7
|
-
export declare const prerenderOptionsCache: Storage<OgImageOptions> | undefined;
|
|
8
|
-
export declare const fontCache: Storage<OgImageOptions<"NuxtSeo">>;
|
|
7
|
+
export declare const prerenderOptionsCache: Storage<OgImageOptions | [string, OgImageOptions][]> | undefined;
|
|
9
8
|
export declare const emojiCache: Storage<string>;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { useNitroOrigin } from "#site-config/server/composables";
|
|
2
|
-
import {
|
|
2
|
+
import { withQuery } from "ufo";
|
|
3
3
|
import { toValue } from "vue";
|
|
4
|
+
import { buildOgImageUrl } from "../../../shared.js";
|
|
4
5
|
import { useOgImageRuntimeConfig } from "../../utils.js";
|
|
5
6
|
export async function createScreenshot({ basePath, e, options, extension }, browser) {
|
|
6
|
-
const { colorPreference } = useOgImageRuntimeConfig();
|
|
7
|
-
const path = options.component === "PageScreenshot" ? basePath :
|
|
7
|
+
const { colorPreference, defaults } = useOgImageRuntimeConfig();
|
|
8
|
+
const path = options.component === "PageScreenshot" ? basePath : buildOgImageUrl(options, "html", false, defaults).url;
|
|
8
9
|
const page = await browser.newPage({
|
|
9
10
|
colorScheme: colorPreference || "no-preference",
|
|
10
11
|
baseURL: useNitroOrigin(e)
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { H3Error, H3Event } from 'h3';
|
|
2
|
-
import type {
|
|
3
|
-
export declare function resolvePathCacheKey(e: H3Event, path: string): string;
|
|
2
|
+
import type { OgImageRenderEventContext } from '../../types.js';
|
|
3
|
+
export declare function resolvePathCacheKey(e: H3Event, path: string, includeQuery?: boolean): string;
|
|
4
4
|
export declare function resolveContext(e: H3Event): Promise<H3Error | OgImageRenderEventContext>;
|
|
5
|
-
export declare function extractAndNormaliseOgImageOptions(html: string): OgImageOptions | false;
|
|
@@ -1,35 +1,32 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { useSiteConfig } from "#site-config/server/composables/useSiteConfig";
|
|
1
|
+
import { prerenderOptionsCache } from "#og-image-cache";
|
|
2
|
+
import { getSiteConfig } from "#site-config/server/composables/getSiteConfig";
|
|
4
3
|
import { createSitePathResolver } from "#site-config/server/composables/utils";
|
|
5
|
-
import { createGenerator } from "@unocss/core";
|
|
6
|
-
import presetWind from "@unocss/preset-wind3";
|
|
7
4
|
import { defu } from "defu";
|
|
8
|
-
import { parse } from "devalue";
|
|
9
5
|
import { createError, getQuery } from "h3";
|
|
10
6
|
import { useNitroApp } from "nitropack/runtime";
|
|
11
7
|
import { hash } from "ohash";
|
|
12
8
|
import { parseURL, withoutLeadingSlash, withoutTrailingSlash, withQuery } from "ufo";
|
|
13
9
|
import { normalizeKey } from "unstorage";
|
|
14
|
-
import { separateProps } from "../../shared.js";
|
|
15
|
-
import {
|
|
10
|
+
import { decodeOgImageParams, separateProps } from "../../shared.js";
|
|
11
|
+
import { autoEjectCommunityTemplate } from "../util/auto-eject.js";
|
|
16
12
|
import { createNitroRouteRuleMatcher } from "../util/kit.js";
|
|
17
|
-
import { logger } from "../util/logger.js";
|
|
18
13
|
import { normaliseOptions } from "../util/options.js";
|
|
19
14
|
import { useOgImageRuntimeConfig } from "../utils.js";
|
|
20
|
-
import { useChromiumRenderer, useSatoriRenderer } from "./instances.js";
|
|
21
|
-
export function resolvePathCacheKey(e, path) {
|
|
22
|
-
const siteConfig =
|
|
15
|
+
import { useChromiumRenderer, useSatoriRenderer, useTakumiRenderer } from "./instances.js";
|
|
16
|
+
export function resolvePathCacheKey(e, path, includeQuery = false) {
|
|
17
|
+
const siteConfig = getSiteConfig(e, {
|
|
23
18
|
resolveRefs: true
|
|
24
19
|
});
|
|
25
20
|
const basePath = withoutTrailingSlash(withoutLeadingSlash(normalizeKey(path)));
|
|
21
|
+
const hashParts = [
|
|
22
|
+
basePath,
|
|
23
|
+
import.meta.prerender ? "" : siteConfig.url
|
|
24
|
+
];
|
|
25
|
+
if (includeQuery)
|
|
26
|
+
hashParts.push(hash(getQuery(e)));
|
|
26
27
|
return [
|
|
27
28
|
!basePath || basePath === "/" ? "index" : basePath,
|
|
28
|
-
hash(
|
|
29
|
-
basePath,
|
|
30
|
-
import.meta.prerender ? "" : siteConfig.url,
|
|
31
|
-
hash(getQuery(e))
|
|
32
|
-
])
|
|
29
|
+
hash(hashParts)
|
|
33
30
|
].join(":");
|
|
34
31
|
}
|
|
35
32
|
export async function resolveContext(e) {
|
|
@@ -52,6 +49,30 @@ export async function resolveContext(e) {
|
|
|
52
49
|
statusMessage: `[Nuxt OG Image] Unknown OG Image type ${extension}.`
|
|
53
50
|
});
|
|
54
51
|
}
|
|
52
|
+
const encodedSegment = path.split("/").pop().replace(`.${extension}`, "");
|
|
53
|
+
const hashMatch = encodedSegment.match(/^o_([a-z0-9]+)$/i);
|
|
54
|
+
let urlOptions = {};
|
|
55
|
+
if (hashMatch) {
|
|
56
|
+
const optionsHash = hashMatch[1];
|
|
57
|
+
if (import.meta.prerender && prerenderOptionsCache) {
|
|
58
|
+
const cached = await prerenderOptionsCache.getItem(`hash:${optionsHash}`);
|
|
59
|
+
if (cached && typeof cached === "object") {
|
|
60
|
+
urlOptions = cached;
|
|
61
|
+
} else {
|
|
62
|
+
return createError({
|
|
63
|
+
statusCode: 404,
|
|
64
|
+
statusMessage: `[Nuxt OG Image] Options not found for hash: ${optionsHash}. This can happen if the page hasn't been prerendered yet.`
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
} else {
|
|
68
|
+
return createError({
|
|
69
|
+
statusCode: 400,
|
|
70
|
+
statusMessage: `[Nuxt OG Image] Hash-based URLs (o_${optionsHash}) are only supported during prerendering. Use encoded params or query params for runtime.`
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
} else {
|
|
74
|
+
urlOptions = decodeOgImageParams(encodedSegment);
|
|
75
|
+
}
|
|
55
76
|
const query = getQuery(e);
|
|
56
77
|
let queryParams = {};
|
|
57
78
|
for (const k in query) {
|
|
@@ -61,222 +82,63 @@ export async function resolveContext(e) {
|
|
|
61
82
|
if (v.startsWith("{")) {
|
|
62
83
|
try {
|
|
63
84
|
queryParams[k] = JSON.parse(v);
|
|
64
|
-
} catch
|
|
65
|
-
if (import.meta.dev) {
|
|
66
|
-
logger.error(`[Nuxt OG Image] Invalid JSON in ${k} parameter: ${error.message}`);
|
|
67
|
-
}
|
|
85
|
+
} catch {
|
|
68
86
|
}
|
|
69
87
|
} else {
|
|
70
88
|
queryParams[k] = v;
|
|
71
89
|
}
|
|
72
90
|
}
|
|
73
91
|
queryParams = separateProps(queryParams);
|
|
74
|
-
const basePath = withoutTrailingSlash(
|
|
75
|
-
|
|
76
|
-
|
|
92
|
+
const basePath = withoutTrailingSlash(urlOptions._path || "/");
|
|
93
|
+
delete urlOptions._path;
|
|
94
|
+
delete urlOptions._hash;
|
|
77
95
|
const basePathWithQuery = queryParams._query && typeof queryParams._query === "object" ? withQuery(basePath, queryParams._query) : basePath;
|
|
78
96
|
const isDebugJsonPayload = extension === "json" && runtimeConfig.debug;
|
|
79
|
-
const key = resolvePathCacheKey(e, basePathWithQuery);
|
|
80
|
-
let options = queryParams.options;
|
|
81
|
-
if (!options) {
|
|
82
|
-
if (import.meta.prerender) {
|
|
83
|
-
options = await prerenderOptionsCache.getItem(key);
|
|
84
|
-
}
|
|
85
|
-
if (!options) {
|
|
86
|
-
const payload = await fetchPathHtmlAndExtractOptions(e, basePathWithQuery, key);
|
|
87
|
-
if (payload instanceof Error)
|
|
88
|
-
return payload;
|
|
89
|
-
options = payload;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
delete queryParams.options;
|
|
93
97
|
const routeRuleMatcher = createNitroRouteRuleMatcher();
|
|
94
98
|
const routeRules = routeRuleMatcher(basePath);
|
|
95
|
-
if (typeof routeRules.ogImage === "undefined" && !options) {
|
|
96
|
-
return createError({
|
|
97
|
-
statusCode: 400,
|
|
98
|
-
statusMessage: "The route is missing the Nuxt OG Image payload or route rules."
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
99
|
const ogImageRouteRules = separateProps(routeRules.ogImage);
|
|
102
|
-
options = defu(queryParams,
|
|
100
|
+
const options = defu(queryParams, urlOptions, ogImageRouteRules, runtimeConfig.defaults);
|
|
103
101
|
if (!options) {
|
|
104
102
|
return createError({
|
|
105
103
|
statusCode: 404,
|
|
106
104
|
statusMessage: "[Nuxt OG Image] OG Image not found."
|
|
107
105
|
});
|
|
108
106
|
}
|
|
107
|
+
const normalised = normaliseOptions(options);
|
|
108
|
+
if (normalised.component?.category === "community")
|
|
109
|
+
autoEjectCommunityTemplate(normalised.component, runtimeConfig);
|
|
110
|
+
const rendererType = normalised.renderer;
|
|
111
|
+
const key = normalised.options.cacheKey || resolvePathCacheKey(e, basePathWithQuery, runtimeConfig.cacheQueryParams);
|
|
109
112
|
let renderer;
|
|
110
|
-
switch (
|
|
113
|
+
switch (rendererType) {
|
|
111
114
|
case "satori":
|
|
112
115
|
renderer = await useSatoriRenderer();
|
|
113
116
|
break;
|
|
114
117
|
case "chromium":
|
|
115
118
|
renderer = await useChromiumRenderer();
|
|
116
119
|
break;
|
|
120
|
+
case "takumi":
|
|
121
|
+
renderer = await useTakumiRenderer();
|
|
122
|
+
break;
|
|
117
123
|
}
|
|
118
124
|
if (!renderer || renderer.__mock__) {
|
|
119
125
|
throw createError({
|
|
120
126
|
statusCode: 400,
|
|
121
|
-
statusMessage: `[Nuxt OG Image] Renderer ${
|
|
127
|
+
statusMessage: `[Nuxt OG Image] Renderer "${rendererType}" is not available. Component "${normalised.component?.pascalName}" requires the ${rendererType} renderer but it's not bundled for this preset.`
|
|
122
128
|
});
|
|
123
129
|
}
|
|
124
|
-
const unocss = await createGenerator({ theme }, {
|
|
125
|
-
presets: [
|
|
126
|
-
presetWind()
|
|
127
|
-
]
|
|
128
|
-
});
|
|
129
130
|
const ctx = {
|
|
130
|
-
unocss,
|
|
131
131
|
e,
|
|
132
132
|
key,
|
|
133
133
|
renderer,
|
|
134
|
-
isDebugJsonPayload,
|
|
134
|
+
isDevToolsContextRequest: isDebugJsonPayload,
|
|
135
135
|
runtimeConfig,
|
|
136
136
|
publicStoragePath: runtimeConfig.publicStoragePath,
|
|
137
137
|
extension,
|
|
138
138
|
basePath,
|
|
139
|
-
options:
|
|
139
|
+
options: normalised.options,
|
|
140
140
|
_nitro: useNitroApp()
|
|
141
141
|
};
|
|
142
142
|
await ctx._nitro.hooks.callHook("nuxt-og-image:context", ctx);
|
|
143
143
|
return ctx;
|
|
144
144
|
}
|
|
145
|
-
const PAYLOAD_REGEX = /<script.+id="nuxt-og-image-options"[^>]*>(.+?)<\/script>/;
|
|
146
|
-
function getPayloadFromHtml(html) {
|
|
147
|
-
const match = String(html).match(PAYLOAD_REGEX);
|
|
148
|
-
return match ? String(match[1]) : null;
|
|
149
|
-
}
|
|
150
|
-
export function extractAndNormaliseOgImageOptions(html) {
|
|
151
|
-
const _payload = getPayloadFromHtml(html);
|
|
152
|
-
let options = false;
|
|
153
|
-
try {
|
|
154
|
-
const payload2 = parse(_payload || "{}");
|
|
155
|
-
Object.entries(payload2).forEach(([key, value]) => {
|
|
156
|
-
if (!value && value !== 0)
|
|
157
|
-
delete payload2[key];
|
|
158
|
-
});
|
|
159
|
-
options = payload2;
|
|
160
|
-
} catch (e) {
|
|
161
|
-
if (import.meta.dev)
|
|
162
|
-
console.warn("Failed to parse #nuxt-og-image-options", e, options);
|
|
163
|
-
}
|
|
164
|
-
if (options && typeof options?.props?.description === "undefined") {
|
|
165
|
-
const description = html.match(/<meta[^>]+name="description"[^>]*>/)?.[0];
|
|
166
|
-
if (description) {
|
|
167
|
-
const [, content] = description.match(/content="([^"]+)"/) || [];
|
|
168
|
-
if (content && !options.props.description)
|
|
169
|
-
options.props.description = content;
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
const payload = decodeObjectHtmlEntities(options || {});
|
|
173
|
-
if (import.meta.dev) {
|
|
174
|
-
const socialPreview = {};
|
|
175
|
-
const socialMetaTags = html.match(/<meta[^>]+(property|name)="(twitter|og):([^"]+)"[^>]*>/g);
|
|
176
|
-
if (socialMetaTags) {
|
|
177
|
-
socialMetaTags.forEach((tag) => {
|
|
178
|
-
const [, , type, key] = tag.match(/(property|name)="(twitter|og):([^"]+)"/);
|
|
179
|
-
const value = tag.match(/content="([^"]+)"/)?.[1];
|
|
180
|
-
if (!value)
|
|
181
|
-
return;
|
|
182
|
-
if (!socialPreview[type])
|
|
183
|
-
socialPreview[type] = {};
|
|
184
|
-
socialPreview[type][key] = value;
|
|
185
|
-
});
|
|
186
|
-
}
|
|
187
|
-
payload.socialPreview = socialPreview;
|
|
188
|
-
}
|
|
189
|
-
return payload;
|
|
190
|
-
}
|
|
191
|
-
async function doFetchWithErrorHandling(fetch, path) {
|
|
192
|
-
const res = await fetch(path, {
|
|
193
|
-
redirect: "follow",
|
|
194
|
-
headers: {
|
|
195
|
-
accept: "text/html"
|
|
196
|
-
}
|
|
197
|
-
}).catch((err) => {
|
|
198
|
-
return err;
|
|
199
|
-
});
|
|
200
|
-
let errorDescription;
|
|
201
|
-
if (res.status >= 300 && res.status < 400) {
|
|
202
|
-
if (res.headers.has("location")) {
|
|
203
|
-
return await doFetchWithErrorHandling(fetch, res.headers.get("location") || "");
|
|
204
|
-
}
|
|
205
|
-
errorDescription = `${res.status} redirected to ${res.headers.get("location") || "unknown"}`;
|
|
206
|
-
} else if (res.status >= 500) {
|
|
207
|
-
errorDescription = `${res.status} error: ${res.statusText}`;
|
|
208
|
-
}
|
|
209
|
-
if (errorDescription) {
|
|
210
|
-
return [null, createError({
|
|
211
|
-
statusCode: 500,
|
|
212
|
-
statusMessage: `[Nuxt OG Image] Failed to parse \`${path}\` for og-image extraction. ${errorDescription}`
|
|
213
|
-
})];
|
|
214
|
-
}
|
|
215
|
-
if (res._data) {
|
|
216
|
-
return [res._data, null];
|
|
217
|
-
} else if (res.text) {
|
|
218
|
-
return [await res.text(), null];
|
|
219
|
-
}
|
|
220
|
-
return ["", null];
|
|
221
|
-
}
|
|
222
|
-
async function fetchPathHtmlAndExtractOptions(e, path, key) {
|
|
223
|
-
const cachedHtmlPayload = await htmlPayloadCache.getItem(key);
|
|
224
|
-
if (!import.meta.dev && cachedHtmlPayload && cachedHtmlPayload.expiresAt < Date.now())
|
|
225
|
-
return cachedHtmlPayload.value;
|
|
226
|
-
let _payload = null;
|
|
227
|
-
let [html, err] = await doFetchWithErrorHandling(e.fetch, path);
|
|
228
|
-
if (err) {
|
|
229
|
-
logger.warn(err);
|
|
230
|
-
} else {
|
|
231
|
-
_payload = getPayloadFromHtml(html);
|
|
232
|
-
}
|
|
233
|
-
if (!_payload) {
|
|
234
|
-
const [fallbackHtml, err2] = await doFetchWithErrorHandling(globalThis.$fetch.raw, path);
|
|
235
|
-
if (err2) {
|
|
236
|
-
return err2;
|
|
237
|
-
}
|
|
238
|
-
_payload = getPayloadFromHtml(fallbackHtml);
|
|
239
|
-
if (_payload) {
|
|
240
|
-
html = fallbackHtml;
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
if (!html) {
|
|
244
|
-
return createError({
|
|
245
|
-
statusCode: 500,
|
|
246
|
-
statusMessage: `[Nuxt OG Image] Failed to read the path ${path} for og-image extraction, returning no HTML.`
|
|
247
|
-
});
|
|
248
|
-
}
|
|
249
|
-
if (!_payload) {
|
|
250
|
-
const payload2 = extractAndNormaliseOgImageOptions(html);
|
|
251
|
-
if (payload2 && typeof payload2 === "object" && payload2.socialPreview?.og?.image) {
|
|
252
|
-
const image = payload2.socialPreview.og.image;
|
|
253
|
-
const p = {
|
|
254
|
-
custom: true,
|
|
255
|
-
url: typeof image === "string" ? image : image
|
|
256
|
-
};
|
|
257
|
-
if (typeof image === "object" && image["image:width"]) {
|
|
258
|
-
p.width = image["image:width"];
|
|
259
|
-
}
|
|
260
|
-
if (typeof image === "object" && image["image:height"]) {
|
|
261
|
-
p.height = image["image:height"];
|
|
262
|
-
}
|
|
263
|
-
return p;
|
|
264
|
-
}
|
|
265
|
-
return createError({
|
|
266
|
-
statusCode: 500,
|
|
267
|
-
statusMessage: `[Nuxt OG Image] HTML response from ${path} is missing the #nuxt-og-image-options script tag. Make sure you have defined an og image for this page.`
|
|
268
|
-
});
|
|
269
|
-
}
|
|
270
|
-
const payload = extractAndNormaliseOgImageOptions(html);
|
|
271
|
-
if (!import.meta.dev && payload) {
|
|
272
|
-
await htmlPayloadCache.setItem(key, {
|
|
273
|
-
// 60 minutes for prerender, 10 seconds for runtime
|
|
274
|
-
expiresAt: Date.now() + 1e3 * (import.meta.prerender ? 60 * 60 : 10),
|
|
275
|
-
value: payload
|
|
276
|
-
});
|
|
277
|
-
}
|
|
278
|
-
return typeof payload === "object" ? payload : createError({
|
|
279
|
-
statusCode: 500,
|
|
280
|
-
statusMessage: "[Nuxt OG Image] Invalid payload type."
|
|
281
|
-
});
|
|
282
|
-
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { H3Error, H3Event } from 'h3';
|
|
2
|
+
import type { DevToolsMetaDataExtraction, OgImageOptions } from '../../types.js';
|
|
3
|
+
export interface DevToolsExtractPayload {
|
|
4
|
+
options: OgImageOptions[];
|
|
5
|
+
socialPreview: {
|
|
6
|
+
root: Record<string, string>;
|
|
7
|
+
images: DevToolsMetaDataExtraction[];
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
export declare function fetchPathHtmlAndExtractOptions(e: H3Event, path: string, cacheKey: string): Promise<H3Error | DevToolsExtractPayload>;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { htmlPayloadCache } from "#og-image-cache";
|
|
2
|
+
import { parse } from "devalue";
|
|
3
|
+
import { createError } from "h3";
|
|
4
|
+
import { extractSocialPreviewTags } from "../../pure.js";
|
|
5
|
+
import { logger } from "../util/logger.js";
|
|
6
|
+
const PAYLOAD_REGEX = /<script.+id="nuxt-og-image-options"[^>]*>(.+?)<\/script>/;
|
|
7
|
+
function extractOptionsFromHtml(html) {
|
|
8
|
+
const match = String(html).match(PAYLOAD_REGEX);
|
|
9
|
+
if (!match?.[1])
|
|
10
|
+
return [];
|
|
11
|
+
return parse(match[1]);
|
|
12
|
+
}
|
|
13
|
+
async function doFetchWithErrorHandling(fetch, path) {
|
|
14
|
+
const res = await fetch(path, {
|
|
15
|
+
redirect: "follow",
|
|
16
|
+
headers: {
|
|
17
|
+
accept: "text/html"
|
|
18
|
+
}
|
|
19
|
+
}).catch((err) => {
|
|
20
|
+
return err;
|
|
21
|
+
});
|
|
22
|
+
let errorDescription;
|
|
23
|
+
if (res.status >= 300 && res.status < 400) {
|
|
24
|
+
if (res.headers.has("location")) {
|
|
25
|
+
return await doFetchWithErrorHandling(fetch, res.headers.get("location") || "");
|
|
26
|
+
}
|
|
27
|
+
errorDescription = `${res.status} redirected to ${res.headers.get("location") || "unknown"}`;
|
|
28
|
+
} else if (res.status >= 400) {
|
|
29
|
+
errorDescription = `${res.status} error: ${res.statusText}`;
|
|
30
|
+
}
|
|
31
|
+
if (errorDescription) {
|
|
32
|
+
return [null, createError({
|
|
33
|
+
statusCode: 500,
|
|
34
|
+
statusMessage: `[Nuxt OG Image] Failed to parse \`${path}\` for og-image extraction. ${errorDescription}`
|
|
35
|
+
})];
|
|
36
|
+
}
|
|
37
|
+
return [res._data || await res.text(), null];
|
|
38
|
+
}
|
|
39
|
+
export async function fetchPathHtmlAndExtractOptions(e, path, cacheKey) {
|
|
40
|
+
const cachedHtmlPayload = await htmlPayloadCache.getItem(cacheKey);
|
|
41
|
+
if (!import.meta.dev && cachedHtmlPayload && cachedHtmlPayload.expiresAt > Date.now())
|
|
42
|
+
return cachedHtmlPayload.value;
|
|
43
|
+
let [html, err] = await doFetchWithErrorHandling(e.fetch, path);
|
|
44
|
+
if (err) {
|
|
45
|
+
logger.warn(err);
|
|
46
|
+
}
|
|
47
|
+
if (!html) {
|
|
48
|
+
const [fallbackHtml, err2] = await doFetchWithErrorHandling(globalThis.$fetch.raw, path);
|
|
49
|
+
if (err2) {
|
|
50
|
+
return err2;
|
|
51
|
+
}
|
|
52
|
+
html = fallbackHtml;
|
|
53
|
+
}
|
|
54
|
+
if (!html) {
|
|
55
|
+
return createError({
|
|
56
|
+
statusCode: 500,
|
|
57
|
+
statusMessage: `[Nuxt OG Image] Failed to read the path ${path} for og-image extraction, returning no HTML.`
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
const [root, images] = extractSocialPreviewTags(html);
|
|
61
|
+
const options = extractOptionsFromHtml(html);
|
|
62
|
+
const payload = {
|
|
63
|
+
options,
|
|
64
|
+
socialPreview: { root, images }
|
|
65
|
+
};
|
|
66
|
+
if (!import.meta.dev && payload) {
|
|
67
|
+
await htmlPayloadCache.setItem(cacheKey, {
|
|
68
|
+
// 60 minutes for prerender, 10 seconds for runtime
|
|
69
|
+
expiresAt: Date.now() + 1e3 * (import.meta.prerender ? 60 * 60 : 10),
|
|
70
|
+
value: payload
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
return payload;
|
|
74
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { H3Event } from 'h3';
|
|
2
|
+
import type { SatoriFontConfig } from '../../types.js';
|
|
3
|
+
export interface LoadFontsOptions {
|
|
4
|
+
supportsWoff2: boolean;
|
|
5
|
+
}
|
|
6
|
+
export declare function loadAllFonts(event: H3Event, options: LoadFontsOptions): Promise<SatoriFontConfig[]>;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { resolve } from "#og-image-virtual/public-assets.mjs";
|
|
2
|
+
import resolvedFonts from "#og-image/fonts";
|
|
3
|
+
import { fontCache } from "./cache/lru.js";
|
|
4
|
+
async function loadFont(event, font) {
|
|
5
|
+
const cacheKey = `${font.family}-${font.weight}-${font.style}`;
|
|
6
|
+
const cached = await fontCache.getItem(cacheKey);
|
|
7
|
+
if (cached) {
|
|
8
|
+
const data2 = Buffer.from(cached, "base64");
|
|
9
|
+
return data2;
|
|
10
|
+
}
|
|
11
|
+
const data = await resolve(event, font).catch((err) => {
|
|
12
|
+
console.warn(`[nuxt-og-image] Failed to load font ${font.family}: ${err.message}`);
|
|
13
|
+
return null;
|
|
14
|
+
});
|
|
15
|
+
if (!data)
|
|
16
|
+
return null;
|
|
17
|
+
const base64 = Buffer.from(data).toString("base64");
|
|
18
|
+
await fontCache.setItem(cacheKey, base64);
|
|
19
|
+
return data;
|
|
20
|
+
}
|
|
21
|
+
export async function loadAllFonts(event, options) {
|
|
22
|
+
const fonts = resolvedFonts.filter((f) => {
|
|
23
|
+
if (options.supportsWoff2)
|
|
24
|
+
return true;
|
|
25
|
+
return !f.src.endsWith(".woff2");
|
|
26
|
+
});
|
|
27
|
+
const results = await Promise.all(
|
|
28
|
+
fonts.map(async (f) => {
|
|
29
|
+
const data = await loadFont(event, f);
|
|
30
|
+
if (!data)
|
|
31
|
+
return null;
|
|
32
|
+
return {
|
|
33
|
+
...f,
|
|
34
|
+
name: f.family,
|
|
35
|
+
cacheKey: `${f.family}-${f.weight}-${f.style}`,
|
|
36
|
+
data
|
|
37
|
+
};
|
|
38
|
+
})
|
|
39
|
+
);
|
|
40
|
+
return results.filter((f) => f !== null);
|
|
41
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const satoriRendererInstance = { instance: void 0 };
|
|
2
2
|
const chromiumRendererInstance = { instance: void 0 };
|
|
3
|
+
const takumiRendererInstance = { instance: void 0 };
|
|
3
4
|
export async function useSatoriRenderer() {
|
|
4
5
|
satoriRendererInstance.instance = satoriRendererInstance.instance || await import("#og-image/renderers/satori").then((m) => m.default);
|
|
5
6
|
return satoriRendererInstance.instance;
|
|
@@ -8,3 +9,7 @@ export async function useChromiumRenderer() {
|
|
|
8
9
|
chromiumRendererInstance.instance = chromiumRendererInstance.instance || await import("#og-image/renderers/chromium").then((m) => m.default);
|
|
9
10
|
return chromiumRendererInstance.instance;
|
|
10
11
|
}
|
|
12
|
+
export async function useTakumiRenderer() {
|
|
13
|
+
takumiRendererInstance.instance = takumiRendererInstance.instance || await import("#og-image/renderers/takumi").then((m) => m.default);
|
|
14
|
+
return takumiRendererInstance.instance;
|
|
15
|
+
}
|
|
@@ -1,41 +1,6 @@
|
|
|
1
1
|
import type _satori from 'satori';
|
|
2
2
|
import type _sharp from 'sharp';
|
|
3
|
-
export declare function useResvg(): Promise<
|
|
4
|
-
free(): void;
|
|
5
|
-
render(): {
|
|
6
|
-
free(): void;
|
|
7
|
-
asPng(): Uint8Array;
|
|
8
|
-
readonly height: number;
|
|
9
|
-
readonly pixels: Uint8Array;
|
|
10
|
-
readonly width: number;
|
|
11
|
-
};
|
|
12
|
-
toString(): string;
|
|
13
|
-
innerBBox(): {
|
|
14
|
-
free(): void;
|
|
15
|
-
height: number;
|
|
16
|
-
width: number;
|
|
17
|
-
x: number;
|
|
18
|
-
y: number;
|
|
19
|
-
} | undefined;
|
|
20
|
-
getBBox(): {
|
|
21
|
-
free(): void;
|
|
22
|
-
height: number;
|
|
23
|
-
width: number;
|
|
24
|
-
x: number;
|
|
25
|
-
y: number;
|
|
26
|
-
} | undefined;
|
|
27
|
-
cropByBBox(bbox: {
|
|
28
|
-
free(): void;
|
|
29
|
-
height: number;
|
|
30
|
-
width: number;
|
|
31
|
-
x: number;
|
|
32
|
-
y: number;
|
|
33
|
-
}): void;
|
|
34
|
-
imagesToResolve(): any[];
|
|
35
|
-
resolveImage(href: string, buffer: Uint8Array): void;
|
|
36
|
-
readonly height: number;
|
|
37
|
-
readonly width: number;
|
|
38
|
-
}>;
|
|
3
|
+
export declare function useResvg(): Promise<any>;
|
|
39
4
|
export declare function useSatori(): Promise<typeof _satori>;
|
|
40
5
|
export declare function useSharp(): Promise<typeof _sharp>;
|
|
41
6
|
export declare function useCssInline(): Promise<any>;
|