nuxt-og-image 2.0.4 → 2.0.6
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/dist/client/200.html +2 -2
- package/dist/client/404.html +2 -2
- package/dist/client/_nuxt/{IconCSS.b4882023.js → IconCSS.acbfc761.js} +1 -1
- package/dist/client/_nuxt/{ImageLoader.b68e14b5.js → ImageLoader.45e71895.js} +1 -1
- package/dist/client/_nuxt/{entry.fb0efd99.js → entry.f886005d.js} +63 -63
- package/dist/client/_nuxt/{error-404.644be599.js → error-404.0a0b8ce2.js} +1 -1
- package/dist/client/_nuxt/{error-500.a96819db.js → error-500.20847d33.js} +1 -1
- package/dist/client/_nuxt/{index.60e5b582.js → index.0cbeeabd.js} +1 -1
- package/dist/client/_nuxt/{options.727a8560.js → options.1070a0ba.js} +1 -1
- package/dist/client/_nuxt/{png.42d9c3d5.js → png.e3b1ce6b.js} +1 -1
- package/dist/client/_nuxt/shiki.4671d705.js +7 -0
- package/dist/client/_nuxt/{svg.c50d59f2.js → svg.26cfe41e.js} +1 -1
- package/dist/client/_nuxt/{vnodes.12ed942f.js → vnodes.7d34f085.js} +1 -1
- package/dist/client/index.html +2 -2
- package/dist/module.json +1 -1
- package/dist/module.mjs +45 -31
- package/dist/runtime/browserUtil.d.ts +1 -1
- package/dist/runtime/cache.d.ts +11 -0
- package/dist/runtime/cache.mjs +42 -0
- package/dist/runtime/components/OgImage/Cached.d.ts +1 -1
- package/dist/runtime/components/OgImage/Dynamic.d.ts +1 -1
- package/dist/runtime/components/OgImage/Screenshot.d.ts +1 -1
- package/dist/runtime/components/OgImage/Static.d.ts +1 -1
- package/dist/runtime/components/OgImage/WithoutCache.d.ts +1 -1
- package/dist/runtime/components/OgImage/index.d.ts +1 -1
- package/dist/runtime/composables/defineOgImage.d.ts +1 -1
- package/dist/runtime/composables/defineOgImage.mjs +2 -2
- package/dist/runtime/composables/util.d.ts +1 -1
- package/dist/runtime/composables/util.mjs +5 -9
- package/dist/runtime/nitro/middleware/og.png.mjs +21 -23
- package/dist/runtime/nitro/middleware/playground.mjs +2 -2
- package/dist/runtime/nitro/providers/png/resvg-node.d.ts +1 -1
- package/dist/runtime/nitro/providers/png/resvg-wasm.d.ts +1 -1
- package/dist/runtime/nitro/providers/png/svg2png.d.ts +1 -1
- package/dist/runtime/nitro/providers/satori/yoga-wasm.d.ts +1 -1
- package/dist/runtime/nitro/renderers/browser.d.ts +1 -1
- package/dist/runtime/nitro/renderers/satori/index.d.ts +1 -1
- package/dist/runtime/nitro/renderers/satori/plugins/emojis.d.ts +1 -1
- package/dist/runtime/nitro/renderers/satori/plugins/encoding.d.ts +1 -1
- package/dist/runtime/nitro/renderers/satori/plugins/flex.d.ts +1 -1
- package/dist/runtime/nitro/renderers/satori/plugins/imageSrc.d.ts +1 -1
- package/dist/runtime/nitro/renderers/satori/plugins/twClasses.d.ts +1 -1
- package/dist/runtime/nitro/renderers/satori/utils.d.ts +1 -1
- package/dist/runtime/nitro/routes/html.mjs +2 -2
- package/dist/runtime/nitro/routes/options.d.ts +1 -1
- package/dist/runtime/nitro/routes/options.mjs +8 -8
- package/dist/runtime/nitro/routes/svg.mjs +2 -2
- package/dist/runtime/nitro/routes/vnode.mjs +2 -2
- package/dist/runtime/nitro/utils-pure.d.ts +2 -2
- package/dist/runtime/nitro/utils-pure.mjs +9 -3
- package/dist/runtime/nitro/utils.d.ts +2 -1
- package/dist/runtime/nitro/utils.mjs +33 -34
- package/dist/runtime/types.d.ts +69 -0
- package/dist/runtime/types.mjs +0 -0
- package/package.json +14 -11
- package/dist/client/_nuxt/shiki.4d6ce36e.js +0 -7
- package/dist/client/options/index.html +0 -7
- package/dist/client/png/index.html +0 -7
- package/dist/client/svg/index.html +0 -7
- package/dist/client/vnodes/index.html +0 -7
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { prefixStorage } from "unstorage";
|
|
2
|
+
import { getQuery, setHeader } from "h3";
|
|
3
|
+
import { useRuntimeConfig, useStorage } from "#imports";
|
|
4
|
+
export async function useNitroCache(e, module, options) {
|
|
5
|
+
const { runtimeCacheStorage, version } = useRuntimeConfig()[module];
|
|
6
|
+
const enabled = runtimeCacheStorage && options.cacheTtl && options.cacheTtl > 0 && options.cache;
|
|
7
|
+
const baseCacheKey = runtimeCacheStorage === "default" ? `/cache/${module}@${version}` : `/${module}@${version}`;
|
|
8
|
+
const cache = prefixStorage(useStorage(), `${baseCacheKey}/`);
|
|
9
|
+
const key = options.key;
|
|
10
|
+
let xCacheHeader = "MISS";
|
|
11
|
+
let xCacheExpires = 0;
|
|
12
|
+
const purge = typeof getQuery(e).purge !== "undefined";
|
|
13
|
+
let cachedItem = false;
|
|
14
|
+
if (enabled && await cache.hasItem(key).catch(() => false)) {
|
|
15
|
+
const { value, expiresAt } = await cache.getItem(key).catch(() => ({ value: null, expiresAt: Date.now() }));
|
|
16
|
+
if (expiresAt > Date.now()) {
|
|
17
|
+
if (purge) {
|
|
18
|
+
xCacheHeader = "PURGE";
|
|
19
|
+
await cache.removeItem(key).catch(() => {
|
|
20
|
+
});
|
|
21
|
+
} else {
|
|
22
|
+
xCacheHeader = "HIT";
|
|
23
|
+
xCacheExpires = expiresAt;
|
|
24
|
+
cachedItem = value;
|
|
25
|
+
}
|
|
26
|
+
} else {
|
|
27
|
+
await cache.removeItem(key).catch(() => {
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
if (options.headers) {
|
|
32
|
+
setHeader(e, `x-${module}-cache`, xCacheHeader);
|
|
33
|
+
setHeader(e, `x-${module}-expires`, xCacheExpires.toString());
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
enabled,
|
|
37
|
+
cachedItem,
|
|
38
|
+
async update(item) {
|
|
39
|
+
enabled && await cache.setItem(key, { value: item, expiresAt: Date.now() + (options.cacheTtl || 0) });
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { OgImageOptions } from '
|
|
1
|
+
import type { OgImageOptions } from '../../types';
|
|
2
2
|
declare const _default: import("vue").DefineComponent<OgImageOptions, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<OgImageOptions>>, {
|
|
3
3
|
[x: string]: any;
|
|
4
4
|
}, {}>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { OgImageScreenshotOptions } from '
|
|
1
|
+
import type { OgImageScreenshotOptions } from '../../types';
|
|
2
2
|
declare const _default: import("vue").DefineComponent<OgImageScreenshotOptions, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<OgImageScreenshotOptions>>, {
|
|
3
3
|
[x: string]: any;
|
|
4
4
|
[x: number]: any;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { OgImageOptions } from '
|
|
1
|
+
import type { OgImageOptions } from '../../types';
|
|
2
2
|
declare const _default: import("vue").DefineComponent<OgImageOptions, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<OgImageOptions>>, {
|
|
3
3
|
[x: string]: any;
|
|
4
4
|
}, {}>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { OgImageOptions } from '
|
|
1
|
+
import type { OgImageOptions } from '../../types';
|
|
2
2
|
declare const _default: import("vue").DefineComponent<OgImageOptions, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<OgImageOptions>>, {
|
|
3
3
|
[x: string]: any;
|
|
4
4
|
}, {}>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { OgImageOptions, OgImageScreenshotOptions } from '
|
|
1
|
+
import type { OgImageOptions, OgImageScreenshotOptions } from '../types';
|
|
2
2
|
export declare function defineOgImageScreenshot(options?: OgImageScreenshotOptions): Promise<void>;
|
|
3
3
|
/**
|
|
4
4
|
* @deprecated Use `defineOgImage` or `defineOgImageCached` instead
|
|
@@ -26,9 +26,9 @@ export function defineOgImageCached(options = {}) {
|
|
|
26
26
|
}
|
|
27
27
|
export function defineOgImageWithoutCache(options = {}) {
|
|
28
28
|
return defineOgImage({
|
|
29
|
+
...options,
|
|
29
30
|
cache: false,
|
|
30
|
-
cacheTtl: 0
|
|
31
|
-
...options
|
|
31
|
+
cacheTtl: 0
|
|
32
32
|
});
|
|
33
33
|
}
|
|
34
34
|
export function defineOgImageDynamic(options = {}) {
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type { OgImageOptions } from '
|
|
1
|
+
import type { OgImageOptions } from '../types';
|
|
2
2
|
export declare function normaliseOgImageOptions(_options: OgImageOptions): any;
|
|
@@ -11,15 +11,11 @@ export function normaliseOgImageOptions(_options) {
|
|
|
11
11
|
options.provider = "browser";
|
|
12
12
|
if (options.component && componentNames) {
|
|
13
13
|
const originalName = options.component;
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
options.componentHash = component.hash;
|
|
20
|
-
isValid = true;
|
|
21
|
-
break;
|
|
22
|
-
}
|
|
14
|
+
for (const component of componentNames) {
|
|
15
|
+
if (component.pascalName.endsWith(originalName) || component.kebabName.endsWith(originalName)) {
|
|
16
|
+
options.component = component.pascalName;
|
|
17
|
+
options.componentHash = component.hash;
|
|
18
|
+
break;
|
|
23
19
|
}
|
|
24
20
|
}
|
|
25
21
|
}
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import { Buffer } from "node:buffer";
|
|
2
2
|
import { createError, defineEventHandler, sendRedirect, setHeader } from "h3";
|
|
3
|
-
import { joinURL, parseURL, withoutTrailingSlash } from "ufo";
|
|
4
|
-
import { prefixStorage } from "unstorage";
|
|
3
|
+
import { joinURL, parseURL, withoutLeadingSlash, withoutTrailingSlash } from "ufo";
|
|
5
4
|
import { hash } from "ohash";
|
|
6
|
-
import {
|
|
5
|
+
import { fetchOptionsCached } from "../utils.mjs";
|
|
6
|
+
import { useNitroCache } from "../../cache.mjs";
|
|
7
7
|
import { useProvider } from "#nuxt-og-image/provider";
|
|
8
|
-
import { useNitroOrigin, useRuntimeConfig
|
|
8
|
+
import { useNitroOrigin, useRuntimeConfig } from "#imports";
|
|
9
9
|
export default defineEventHandler(async (e) => {
|
|
10
|
-
const { runtimeBrowser
|
|
10
|
+
const { runtimeBrowser } = useRuntimeConfig()["nuxt-og-image"];
|
|
11
11
|
const path = parseURL(e.path).pathname;
|
|
12
12
|
if (!path.endsWith("__og_image__/og.png"))
|
|
13
13
|
return;
|
|
14
14
|
const basePath = withoutTrailingSlash(
|
|
15
15
|
path.replace("__og_image__/og.png", "")
|
|
16
16
|
);
|
|
17
|
-
const options = await
|
|
17
|
+
const options = await fetchOptionsCached(e, basePath);
|
|
18
18
|
if (process.env.NODE_ENV === "production" && !process.env.prerender && !runtimeBrowser && options.provider === "browser")
|
|
19
19
|
return sendRedirect(e, joinURL(useNitroOrigin(e), "__nuxt_og_image__/browser-provider-not-supported.png"));
|
|
20
20
|
const provider = await useProvider(options.provider);
|
|
@@ -24,27 +24,25 @@ export default defineEventHandler(async (e) => {
|
|
|
24
24
|
statusMessage: `Provider ${options.provider} is missing.`
|
|
25
25
|
});
|
|
26
26
|
}
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
const key = [
|
|
28
|
+
withoutLeadingSlash(options.path === "/" || !options.path ? "index" : options.path).replaceAll("/", "-"),
|
|
29
|
+
`og-${hash(options)}`
|
|
30
|
+
].join(":");
|
|
31
|
+
const { enabled: cacheEnabled, cachedItem, update } = await useNitroCache(e, "nuxt-og-image", {
|
|
32
|
+
key,
|
|
33
|
+
cacheTtl: options.cacheTtl || 0,
|
|
34
|
+
cache: process.dev && options.cache,
|
|
35
|
+
headers: true
|
|
36
|
+
});
|
|
31
37
|
let png;
|
|
32
|
-
if (
|
|
33
|
-
|
|
34
|
-
if (expiresAt > Date.now()) {
|
|
35
|
-
setHeader(e, "Cache-Control", "public, max-age=31536000");
|
|
36
|
-
setHeader(e, "Content-Type", "image/png");
|
|
37
|
-
png = Buffer.from(value, "base64");
|
|
38
|
-
} else {
|
|
39
|
-
await cache.removeItem(key);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
38
|
+
if (cachedItem)
|
|
39
|
+
png = Buffer.from(cachedItem, "base64");
|
|
42
40
|
if (!png) {
|
|
43
41
|
try {
|
|
44
42
|
png = await provider.createPng(options);
|
|
45
|
-
if (
|
|
43
|
+
if (png) {
|
|
46
44
|
const base64png = Buffer.from(png).toString("base64");
|
|
47
|
-
await
|
|
45
|
+
await update(base64png);
|
|
48
46
|
}
|
|
49
47
|
} catch (err) {
|
|
50
48
|
throw createError({
|
|
@@ -54,7 +52,7 @@ export default defineEventHandler(async (e) => {
|
|
|
54
52
|
}
|
|
55
53
|
}
|
|
56
54
|
if (png) {
|
|
57
|
-
if (
|
|
55
|
+
if (cacheEnabled) {
|
|
58
56
|
setHeader(e, "Cache-Control", "public, max-age=31536000");
|
|
59
57
|
} else {
|
|
60
58
|
setHeader(e, "Cache-Control", "no-cache, no-store, must-revalidate");
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { defineEventHandler } from "h3";
|
|
2
2
|
import { parseURL, withBase, withoutTrailingSlash } from "ufo";
|
|
3
|
-
import {
|
|
3
|
+
import { fetchOptionsCached } from "../utils.mjs";
|
|
4
4
|
import { useRuntimeConfig } from "#imports";
|
|
5
5
|
export default defineEventHandler(async (e) => {
|
|
6
6
|
const path = withoutTrailingSlash(parseURL(e.path).pathname);
|
|
7
7
|
if (!path.endsWith("/__og_image__"))
|
|
8
8
|
return;
|
|
9
9
|
const basePath = withBase(path.replace("/__og_image__", ""), useRuntimeConfig().app.baseURL);
|
|
10
|
-
const options = await
|
|
10
|
+
const options = await fetchOptionsCached(e, basePath === "" ? "/" : basePath);
|
|
11
11
|
if (!options)
|
|
12
12
|
return `The route ${basePath} has not been set up for og:image generation.`;
|
|
13
13
|
return `
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import type { ResvgRenderOptions } from '@resvg/resvg-js';
|
|
3
|
-
import type { RuntimeOgImageOptions } from '
|
|
3
|
+
import type { RuntimeOgImageOptions } from '../../../types';
|
|
4
4
|
export default function (svg: string, options: ResvgRenderOptions & RuntimeOgImageOptions): Promise<Buffer>;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { ResvgRenderOptions } from '@resvg/resvg-wasm';
|
|
2
|
-
import type { RuntimeOgImageOptions } from '
|
|
2
|
+
import type { RuntimeOgImageOptions } from '../../../types';
|
|
3
3
|
export default function (svg: string, options: ResvgRenderOptions & RuntimeOgImageOptions): Promise<Uint8Array>;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { ConvertOptions } from 'svg2png-wasm';
|
|
2
|
-
import type { RuntimeOgImageOptions } from '
|
|
2
|
+
import type { RuntimeOgImageOptions } from '../../../types';
|
|
3
3
|
export default function (svg: string, options: ConvertOptions & RuntimeOgImageOptions): Promise<Uint8Array>;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { SatoriOptions } from 'satori';
|
|
2
|
-
import type { RuntimeOgImageOptions } from '
|
|
2
|
+
import type { RuntimeOgImageOptions } from '../../../types';
|
|
3
3
|
export default function (nodes: string, options: SatoriOptions & RuntimeOgImageOptions): Promise<string>;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare const _default: import("
|
|
1
|
+
declare const _default: import("../../../../types").SatoriTransformer | import("../../../../types").SatoriTransformer[];
|
|
2
2
|
export default _default;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare const _default: import("
|
|
1
|
+
declare const _default: import("../../../../types").SatoriTransformer | import("../../../../types").SatoriTransformer[];
|
|
2
2
|
export default _default;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare const _default: import("
|
|
1
|
+
declare const _default: import("../../../../types").SatoriTransformer | import("../../../../types").SatoriTransformer[];
|
|
2
2
|
export default _default;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare const _default: import("
|
|
1
|
+
declare const _default: import("../../../../types").SatoriTransformer | import("../../../../types").SatoriTransformer[];
|
|
2
2
|
export default _default;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare const _default: import("
|
|
1
|
+
declare const _default: import("../../../../types").SatoriTransformer | import("../../../../types").SatoriTransformer[];
|
|
2
2
|
export default _default;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { FontConfig, RuntimeOgImageOptions, SatoriTransformer, VNode } from '
|
|
1
|
+
import type { FontConfig, RuntimeOgImageOptions, SatoriTransformer, VNode } from '../../../types';
|
|
2
2
|
export declare function loadFont(requestOrigin: string, font: FontConfig): Promise<any>;
|
|
3
3
|
export declare function walkSatoriTree(node: VNode, plugins: (SatoriTransformer | SatoriTransformer[])[], props: RuntimeOgImageOptions): Promise<void>;
|
|
4
4
|
export declare function defineSatoriTransformer(transformer: SatoriTransformer | SatoriTransformer[]): SatoriTransformer | SatoriTransformer[];
|
|
@@ -5,7 +5,7 @@ import { createError, defineEventHandler, getQuery, sendRedirect } from "h3";
|
|
|
5
5
|
import { hash } from "ohash";
|
|
6
6
|
import twemoji from "twemoji";
|
|
7
7
|
import { defu } from "defu";
|
|
8
|
-
import {
|
|
8
|
+
import { fetchOptionsCached } from "../utils.mjs";
|
|
9
9
|
import { useNitroOrigin, useRuntimeConfig } from "#imports";
|
|
10
10
|
import loadInlineCSS from "#nuxt-og-image/inline-css";
|
|
11
11
|
export default defineEventHandler(async (e) => {
|
|
@@ -22,7 +22,7 @@ export default defineEventHandler(async (e) => {
|
|
|
22
22
|
} catch {
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
|
-
let options = await
|
|
25
|
+
let options = await fetchOptionsCached(e, path);
|
|
26
26
|
if (queryOptions)
|
|
27
27
|
options = defu(queryOptions, options);
|
|
28
28
|
if (options.provider === "browser" && !options.component) {
|
|
@@ -16,21 +16,21 @@ export default defineEventHandler(async (e) => {
|
|
|
16
16
|
statusMessage: `Failed to read the path ${path} for og-image extraction. ${err.message}.`
|
|
17
17
|
});
|
|
18
18
|
}
|
|
19
|
-
const extractedPayload = extractOgImageOptions(html);
|
|
20
|
-
if (!extractedPayload) {
|
|
21
|
-
throw createError({
|
|
22
|
-
statusCode: 500,
|
|
23
|
-
statusMessage: `The path ${path} is missing the og-image payload.`
|
|
24
|
-
});
|
|
25
|
-
}
|
|
26
19
|
e.node.req.url = path;
|
|
27
20
|
const oldRouteRules = e.context._nitro.routeRules;
|
|
28
21
|
e.context._nitro.routeRules = void 0;
|
|
29
|
-
const routeRules = getRouteRules(e)?.ogImage;
|
|
22
|
+
const routeRules = getRouteRules(e)?.ogImage || {};
|
|
30
23
|
e.context._nitro.routeRules = oldRouteRules;
|
|
31
24
|
e.node.req.url = e.path;
|
|
32
25
|
if (routeRules === false)
|
|
33
26
|
return false;
|
|
27
|
+
const extractedPayload = extractOgImageOptions(html, routeRules);
|
|
28
|
+
if (!extractedPayload) {
|
|
29
|
+
throw createError({
|
|
30
|
+
statusCode: 500,
|
|
31
|
+
statusMessage: `The path ${path} is missing the og-image payload.`
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
34
|
const { defaults } = useRuntimeConfig()["nuxt-og-image"];
|
|
35
35
|
return defu(
|
|
36
36
|
extractedPayload,
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { createError, defineEventHandler, getQuery, setHeader } from "h3";
|
|
2
2
|
import { withBase } from "ufo";
|
|
3
|
-
import {
|
|
3
|
+
import { fetchOptionsCached } from "../utils.mjs";
|
|
4
4
|
import { useProvider } from "#nuxt-og-image/provider";
|
|
5
5
|
import { useRuntimeConfig } from "#imports";
|
|
6
6
|
export default defineEventHandler(async (e) => {
|
|
7
7
|
const query = getQuery(e);
|
|
8
8
|
const path = withBase(query.path || "/", useRuntimeConfig().app.baseURL);
|
|
9
|
-
const options = await
|
|
9
|
+
const options = await fetchOptionsCached(e, path);
|
|
10
10
|
setHeader(e, "Content-Type", "image/svg+xml");
|
|
11
11
|
const provider = await useProvider(options.provider);
|
|
12
12
|
if (!provider) {
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { createError, defineEventHandler, getQuery, setHeader } from "h3";
|
|
2
2
|
import { withBase } from "ufo";
|
|
3
|
-
import {
|
|
3
|
+
import { fetchOptionsCached } from "../utils.mjs";
|
|
4
4
|
import { useProvider } from "#nuxt-og-image/provider";
|
|
5
5
|
import { useRuntimeConfig } from "#imports";
|
|
6
6
|
export default defineEventHandler(async (e) => {
|
|
7
7
|
const query = getQuery(e);
|
|
8
8
|
const path = withBase(query.path || "/", useRuntimeConfig().app.baseURL);
|
|
9
|
-
const options = await
|
|
9
|
+
const options = await fetchOptionsCached(e, path);
|
|
10
10
|
setHeader(e, "Content-Type", "application/json");
|
|
11
11
|
const provider = await useProvider(options.provider);
|
|
12
12
|
if (!provider) {
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import type { OgImageOptions } from '
|
|
1
|
+
import type { OgImageOptions } from '../types';
|
|
2
2
|
export declare function decodeHtml(html: string): string;
|
|
3
|
-
export declare function extractOgImageOptions(html: string): OgImageOptions | false;
|
|
3
|
+
export declare function extractOgImageOptions(html: string, routeRules: OgImageOptions): OgImageOptions | false;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { defu } from "defu";
|
|
1
2
|
export function decodeHtml(html) {
|
|
2
3
|
return html.replace(/</g, "<").replace(/>/g, ">").replace(/&/g, "&").replace(/¢/g, "\xA2").replace(/£/g, "\xA3").replace(/¥/g, "\xA5").replace(/€/g, "\u20AC").replace(/©/g, "\xA9").replace(/®/g, "\xAE").replace(/"/g, '"').replace(/'/g, "'").replace(/'/g, "'").replace(///g, "/").replace(/&#([0-9]+);/g, (full, int) => {
|
|
3
4
|
return String.fromCharCode(Number.parseInt(int));
|
|
@@ -10,15 +11,20 @@ function decodeObjectHtmlEntities(obj) {
|
|
|
10
11
|
});
|
|
11
12
|
return obj;
|
|
12
13
|
}
|
|
13
|
-
export function extractOgImageOptions(html) {
|
|
14
|
+
export function extractOgImageOptions(html, routeRules) {
|
|
14
15
|
const htmlPayload = html.match(/<script id="nuxt-og-image-options" type="application\/json">(.+?)<\/script>/)?.[1];
|
|
15
16
|
if (!htmlPayload)
|
|
16
17
|
return false;
|
|
17
18
|
let options;
|
|
18
19
|
try {
|
|
19
|
-
|
|
20
|
+
const payload = JSON.parse(htmlPayload);
|
|
21
|
+
Object.entries(payload).forEach(([key, value]) => {
|
|
22
|
+
if (!value)
|
|
23
|
+
delete payload[key];
|
|
24
|
+
});
|
|
25
|
+
options = defu(payload, routeRules);
|
|
20
26
|
} catch (e) {
|
|
21
|
-
options =
|
|
27
|
+
options = routeRules;
|
|
22
28
|
if (process.dev)
|
|
23
29
|
console.warn("Failed to parse #nuxt-og-image-options", e, options);
|
|
24
30
|
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import { Buffer } from 'node:buffer';
|
|
3
3
|
import type { H3Event } from 'h3';
|
|
4
|
-
import type { RuntimeOgImageOptions } from '
|
|
4
|
+
import type { RuntimeOgImageOptions } from '../types';
|
|
5
5
|
export declare function wasmLoader(asyncModuleLoad: Promise<any> | Buffer | string, fallback: string): {
|
|
6
6
|
load(options: RuntimeOgImageOptions): Promise<any>;
|
|
7
7
|
};
|
|
8
|
+
export declare function fetchOptionsCached(e: H3Event, path: string): Promise<RuntimeOgImageOptions>;
|
|
8
9
|
export declare function fetchOptions(e: H3Event, path: string): Promise<RuntimeOgImageOptions>;
|
|
9
10
|
export declare function base64ToArrayBuffer(base64: string): ArrayBuffer;
|
|
10
11
|
export declare function readPublicAsset(file: string, encoding?: BufferEncoding): Promise<string | Buffer | undefined>;
|
|
@@ -2,9 +2,11 @@ import { existsSync, promises as fsp } from "node:fs";
|
|
|
2
2
|
import { Buffer } from "node:buffer";
|
|
3
3
|
import { getQuery } from "h3";
|
|
4
4
|
import { join } from "pathe";
|
|
5
|
-
import { prefixStorage } from "unstorage";
|
|
6
5
|
import sizeOf from "image-size";
|
|
7
|
-
import {
|
|
6
|
+
import { defu } from "defu";
|
|
7
|
+
import { withoutLeadingSlash } from "ufo";
|
|
8
|
+
import { useNitroCache } from "../cache.mjs";
|
|
9
|
+
import { useNitroOrigin, useRuntimeConfig } from "#imports";
|
|
8
10
|
export function wasmLoader(asyncModuleLoad, fallback) {
|
|
9
11
|
let promise;
|
|
10
12
|
let wasm;
|
|
@@ -36,40 +38,37 @@ export function wasmLoader(asyncModuleLoad, fallback) {
|
|
|
36
38
|
}
|
|
37
39
|
};
|
|
38
40
|
}
|
|
41
|
+
export async function fetchOptionsCached(e, path) {
|
|
42
|
+
const key = [
|
|
43
|
+
withoutLeadingSlash(path === "/" || !path ? "index" : path).replaceAll("/", "-"),
|
|
44
|
+
"options"
|
|
45
|
+
].join(":");
|
|
46
|
+
const { cachedItem, update } = await useNitroCache(e, "nuxt-og-image", {
|
|
47
|
+
key,
|
|
48
|
+
// allow internal requests to be cached
|
|
49
|
+
cacheTtl: 5 * 1e3,
|
|
50
|
+
cache: !process.dev,
|
|
51
|
+
headers: false
|
|
52
|
+
});
|
|
53
|
+
if (cachedItem)
|
|
54
|
+
return cachedItem;
|
|
55
|
+
const options = await fetchOptions(e, path);
|
|
56
|
+
await update(options);
|
|
57
|
+
return options;
|
|
58
|
+
}
|
|
39
59
|
export async function fetchOptions(e, path) {
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
else
|
|
50
|
-
await cache.removeItem(key);
|
|
51
|
-
}
|
|
52
|
-
if (!options) {
|
|
53
|
-
options = await globalThis.$fetch("/api/og-image-options", {
|
|
54
|
-
query: {
|
|
55
|
-
path
|
|
56
|
-
},
|
|
57
|
-
responseType: "json"
|
|
58
|
-
});
|
|
59
|
-
if (cache) {
|
|
60
|
-
await cache.setItem(key, {
|
|
61
|
-
value: options,
|
|
62
|
-
// cache for 1 minute or 5 seconds, avoids subsequent internal fetches
|
|
63
|
-
expiresAt: Date.now() + (options.cache ? 60 * 1e3 : 5 * 1e3)
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
return {
|
|
68
|
-
...options,
|
|
60
|
+
const options = await globalThis.$fetch("/api/og-image-options", {
|
|
61
|
+
query: {
|
|
62
|
+
path
|
|
63
|
+
},
|
|
64
|
+
responseType: "json"
|
|
65
|
+
});
|
|
66
|
+
return defu(
|
|
67
|
+
{ requestOrigin: useNitroOrigin(e) },
|
|
68
|
+
options,
|
|
69
69
|
// use query data
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
};
|
|
70
|
+
getQuery(e)
|
|
71
|
+
);
|
|
73
72
|
}
|
|
74
73
|
export function base64ToArrayBuffer(base64) {
|
|
75
74
|
const buffer = Buffer.from(base64, "base64");
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import type { Buffer } from 'node:buffer';
|
|
3
|
+
import type { html } from 'satori-html';
|
|
4
|
+
import type { ModuleOptions } from '../module';
|
|
5
|
+
export interface ScreenshotOptions {
|
|
6
|
+
colorScheme?: 'dark' | 'light';
|
|
7
|
+
selector?: string;
|
|
8
|
+
mask?: string;
|
|
9
|
+
/**
|
|
10
|
+
* The width of the screenshot.
|
|
11
|
+
*
|
|
12
|
+
* @default 1200
|
|
13
|
+
*/
|
|
14
|
+
width: number;
|
|
15
|
+
/**
|
|
16
|
+
* The height of the screenshot.
|
|
17
|
+
*
|
|
18
|
+
* @default 630
|
|
19
|
+
*/
|
|
20
|
+
height: number;
|
|
21
|
+
/**
|
|
22
|
+
* How long to wait before taking the screenshot. Useful for waiting for animations.
|
|
23
|
+
*/
|
|
24
|
+
delay?: number;
|
|
25
|
+
}
|
|
26
|
+
export interface OgImageOptions extends Partial<ScreenshotOptions> {
|
|
27
|
+
provider?: 'browser' | 'satori';
|
|
28
|
+
title?: string;
|
|
29
|
+
description?: string;
|
|
30
|
+
component?: string | null;
|
|
31
|
+
alt?: string;
|
|
32
|
+
cache?: boolean;
|
|
33
|
+
cacheKey?: string;
|
|
34
|
+
cacheTtl?: number;
|
|
35
|
+
/**
|
|
36
|
+
* @deprecated Use `cache` instead
|
|
37
|
+
*/
|
|
38
|
+
static?: boolean;
|
|
39
|
+
[key: string]: any;
|
|
40
|
+
}
|
|
41
|
+
export interface RuntimeOgImageOptions extends OgImageOptions {
|
|
42
|
+
path: string;
|
|
43
|
+
requestOrigin: string;
|
|
44
|
+
}
|
|
45
|
+
export interface FontConfig {
|
|
46
|
+
name: string;
|
|
47
|
+
weight: number;
|
|
48
|
+
path?: string;
|
|
49
|
+
}
|
|
50
|
+
export type InputFontConfig = (`${string}:${number}` | FontConfig);
|
|
51
|
+
export interface Renderer {
|
|
52
|
+
name: 'browser' | 'satori';
|
|
53
|
+
createSvg: (options: RuntimeOgImageOptions) => Promise<string>;
|
|
54
|
+
createPng: (options: RuntimeOgImageOptions) => Promise<Buffer>;
|
|
55
|
+
createVNode: (options: RuntimeOgImageOptions) => Promise<VNode>;
|
|
56
|
+
}
|
|
57
|
+
export type OgImageScreenshotOptions = Omit<OgImageOptions, 'component'>;
|
|
58
|
+
export interface PlaygroundServerFunctions {
|
|
59
|
+
openInEditor(filepath: string): void;
|
|
60
|
+
getConfig(): ModuleOptions;
|
|
61
|
+
}
|
|
62
|
+
export interface PlaygroundClientFunctions {
|
|
63
|
+
refresh(type: string): void;
|
|
64
|
+
}
|
|
65
|
+
export type VNode = ReturnType<typeof html>;
|
|
66
|
+
export interface SatoriTransformer {
|
|
67
|
+
filter: (node: VNode) => boolean;
|
|
68
|
+
transform: (node: VNode, props: RuntimeOgImageOptions) => Promise<void>;
|
|
69
|
+
}
|
|
File without changes
|