nuxt-og-image 3.0.0-beta.12 → 3.0.0-beta.15
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 +5 -5
- package/dist/client/404.html +5 -5
- package/dist/client/_nuxt/{IconCSS.3f011790.js → IconCSS.3a98efc6.js} +1 -1
- package/dist/client/_nuxt/IconCSS.7e8f1f7b.css +1 -0
- package/dist/client/_nuxt/builds/latest.json +1 -1
- package/dist/client/_nuxt/builds/meta/9ab97583-6aef-4d38-9cfe-1a0bb2c6966a.json +1 -0
- package/dist/client/_nuxt/entry.3a009184.css +1 -0
- package/dist/client/_nuxt/entry.95bee607.js +137 -0
- package/dist/client/_nuxt/{error-404.0d8fb510.js → error-404.76a67ecd.js} +1 -1
- package/dist/client/_nuxt/{error-500.cefac4a7.js → error-500.b3ac537c.js} +1 -1
- package/dist/client/index.html +5 -5
- package/dist/module.d.mts +36 -19
- package/dist/module.d.ts +36 -19
- package/dist/module.json +2 -2
- package/dist/module.mjs +54 -41
- package/dist/runtime/cache.d.ts +7 -10
- package/dist/runtime/cache.mjs +38 -26
- package/dist/runtime/components/OgImage/OgImage.d.ts +5 -0
- package/dist/runtime/components/OgImage/{index.mjs → OgImage.mjs} +1 -1
- package/dist/runtime/components/OgImage/OgImageScreenshot.d.ts +5 -0
- package/dist/runtime/components/OgImage/{Screenshot.mjs → OgImageScreenshot.mjs} +1 -1
- package/dist/runtime/components/Templates/Official/SimpleBlog.vue +1 -0
- package/dist/runtime/composables/defineOgImage.d.ts +2 -23
- package/dist/runtime/composables/defineOgImage.mjs +32 -115
- package/dist/runtime/composables/defineOgImageComponent.d.ts +3 -0
- package/dist/runtime/composables/defineOgImageComponent.mjs +8 -0
- package/dist/runtime/composables/defineOgImagePageScreenshot.d.ts +2 -0
- package/dist/runtime/composables/defineOgImagePageScreenshot.mjs +14 -0
- package/dist/runtime/core/bindings/css-inline/node.d.ts +2 -5
- package/dist/runtime/core/bindings/css-inline/node.mjs +2 -10
- package/dist/runtime/core/cache/emojis.d.ts +1 -0
- package/dist/runtime/core/cache/emojis.mjs +5 -0
- package/dist/runtime/core/cache/htmlPayload.d.ts +5 -0
- package/dist/runtime/core/cache/htmlPayload.mjs +6 -0
- package/dist/runtime/core/cache/prerender.d.ts +1 -1
- package/dist/runtime/core/font/fetch.d.ts +2 -3
- package/dist/runtime/core/font/fetch.mjs +10 -4
- package/dist/runtime/core/html/applyEmojis.d.ts +3 -0
- package/dist/runtime/core/html/applyEmojis.mjs +37 -0
- package/dist/runtime/core/html/applyInlineCss.d.ts +3 -0
- package/dist/runtime/core/html/applyInlineCss.mjs +32 -0
- package/dist/runtime/core/html/devIframeTemplate.d.ts +2 -0
- package/dist/runtime/core/html/{fetch.mjs → devIframeTemplate.mjs} +8 -31
- package/dist/runtime/core/html/fetchIsland.d.ts +3 -0
- package/dist/runtime/core/html/fetchIsland.mjs +17 -0
- package/dist/runtime/core/options/fetch.d.ts +1 -1
- package/dist/runtime/core/options/fetch.mjs +10 -5
- package/dist/runtime/core/options/normalise.d.ts +2 -2
- package/dist/runtime/core/renderers/chromium/index.mjs +6 -7
- package/dist/runtime/core/renderers/chromium/screenshot.d.ts +2 -3
- package/dist/runtime/core/renderers/chromium/screenshot.mjs +5 -4
- package/dist/runtime/core/renderers/satori/fonts.d.ts +2 -2
- package/dist/runtime/core/renderers/satori/fonts.mjs +2 -2
- package/dist/runtime/core/renderers/satori/index.d.ts +2 -3
- package/dist/runtime/core/renderers/satori/index.mjs +21 -18
- package/dist/runtime/core/renderers/satori/instances.d.ts +3 -0
- package/dist/runtime/core/renderers/satori/instances.mjs +15 -0
- package/dist/runtime/core/renderers/satori/plugins/emojis.mjs +15 -13
- package/dist/runtime/core/renderers/satori/plugins/imageSrc.mjs +8 -4
- package/dist/runtime/core/renderers/satori/utils.d.ts +2 -3
- package/dist/runtime/core/renderers/satori/vnodes.d.ts +2 -3
- package/dist/runtime/core/renderers/satori/vnodes.mjs +14 -6
- package/dist/runtime/core/utils/resolveRendererContext.d.ts +2 -6
- package/dist/runtime/core/utils/resolveRendererContext.mjs +34 -21
- package/dist/runtime/nitro/plugins/nuxt-content.mjs +2 -2
- package/dist/runtime/nitro/plugins/prerender.mjs +2 -2
- package/dist/runtime/nuxt/plugins/nuxt-content-canonical-urls.mjs +1 -1
- package/dist/runtime/nuxt/plugins/route-rule-og-image.server.mjs +14 -47
- package/dist/runtime/nuxt/utils.d.ts +2 -0
- package/dist/runtime/nuxt/utils.mjs +55 -0
- package/dist/runtime/server/routes/__og-image__/debug.json.d.ts +0 -2
- package/dist/runtime/server/routes/__og-image__/debug.json.mjs +2 -7
- package/dist/runtime/server/routes/__og-image__/image.mjs +86 -0
- package/dist/runtime/types.d.ts +57 -24
- package/dist/runtime/utils.d.ts +3 -0
- package/dist/runtime/utils.mjs +11 -0
- package/package.json +17 -32
- package/virtual.d.ts +49 -0
- package/dist/client/_nuxt/IconCSS.8f429b14.css +0 -1
- package/dist/client/_nuxt/builds/meta/f929037e-e674-4060-8070-9dfb30335a28.json +0 -1
- package/dist/client/_nuxt/entry.434c2c45.css +0 -1
- package/dist/client/_nuxt/entry.6c0001e5.js +0 -137
- package/dist/client/grid.png +0 -0
- package/dist/runtime/components/OgImage/Cached.d.ts +0 -5
- package/dist/runtime/components/OgImage/Cached.mjs +0 -10
- package/dist/runtime/components/OgImage/Dynamic.d.ts +0 -8
- package/dist/runtime/components/OgImage/Dynamic.mjs +0 -10
- package/dist/runtime/components/OgImage/Screenshot.d.ts +0 -6
- package/dist/runtime/components/OgImage/Static.d.ts +0 -8
- package/dist/runtime/components/OgImage/Static.mjs +0 -10
- package/dist/runtime/components/OgImage/WithoutCache.d.ts +0 -5
- package/dist/runtime/components/OgImage/WithoutCache.mjs +0 -10
- package/dist/runtime/components/OgImage/index.d.ts +0 -5
- package/dist/runtime/core/bindings/css-inline/mock.d.ts +0 -5
- package/dist/runtime/core/bindings/css-inline/mock.mjs +0 -3
- package/dist/runtime/core/html/fetch.d.ts +0 -3
- package/dist/runtime/server/routes/__og-image__/image-[path]-og.[extension].mjs +0 -45
- package/dist/runtime/utilts.d.ts +0 -2
- package/dist/runtime/utilts.mjs +0 -8
- /package/dist/runtime/server/routes/__og-image__/{image-[path]-og.[extension].d.ts → image.d.ts} +0 -0
|
@@ -1,124 +1,41 @@
|
|
|
1
1
|
import { defu } from "defu";
|
|
2
2
|
import { appendHeader } from "h3";
|
|
3
|
-
import {
|
|
3
|
+
import { createRouter as createRadixRouter, toRouteMatcher } from "radix3";
|
|
4
|
+
import { withoutBase } from "ufo";
|
|
5
|
+
import { getOgImagePath } from "../utils.mjs";
|
|
4
6
|
import { normaliseOptions } from "../core/options/normalise.mjs";
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
7
|
+
import { createOgImageMeta } from "../nuxt/utils.mjs";
|
|
8
|
+
import { useNuxtApp, useRequestEvent, useRouter, useRuntimeConfig } from "#imports";
|
|
9
|
+
export function defineOgImage(_options = {}) {
|
|
10
|
+
if (!import.meta.server)
|
|
11
|
+
return;
|
|
12
|
+
const nuxtApp = useNuxtApp();
|
|
13
|
+
const ogImageInstances = nuxtApp.ssrContext._ogImageInstances || [];
|
|
14
|
+
const basePath = useRouter().currentRoute.value?.path;
|
|
15
|
+
const _routeRulesMatcher = toRouteMatcher(
|
|
16
|
+
createRadixRouter({ routes: useRuntimeConfig().nitro?.routeRules })
|
|
17
|
+
);
|
|
18
|
+
const routeRules = defu({}, ..._routeRulesMatcher.matchAll(
|
|
19
|
+
withoutBase(basePath.split("?")[0], useRuntimeConfig().app.baseURL)
|
|
20
|
+
).reverse()).ogImage;
|
|
21
|
+
if (!_options || nuxtApp.ssrContext?.event.context._nitro?.routeRules?.ogImage === false || typeof routeRules !== "undefined" && routeRules === false) {
|
|
22
|
+
ogImageInstances.forEach((e) => {
|
|
23
|
+
e.dispose();
|
|
24
|
+
});
|
|
25
|
+
nuxtApp.ssrContext._ogImageInstances = void 0;
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const options = normaliseOptions({
|
|
29
|
+
..._options
|
|
17
30
|
});
|
|
18
|
-
}
|
|
19
|
-
export function defineOgImageStatic(options = {}) {
|
|
20
|
-
return defineOgImageCached(options);
|
|
21
|
-
}
|
|
22
|
-
export function defineOgImageCached(options = {}) {
|
|
23
31
|
const { defaults } = useRuntimeConfig()["nuxt-og-image"];
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
export function defineOgImageWithoutCache(options = {}) {
|
|
32
|
-
return defineOgImage({
|
|
33
|
-
...options,
|
|
34
|
-
cache: false,
|
|
35
|
-
cacheTtl: 0
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
export function defineOgImageDynamic(options = {}) {
|
|
39
|
-
return defineOgImageWithoutCache(options);
|
|
40
|
-
}
|
|
41
|
-
export function defineOgImageComponent(component, props, options = {}) {
|
|
42
|
-
defineOgImage({
|
|
43
|
-
component,
|
|
44
|
-
...props,
|
|
45
|
-
...options
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
export function defineOgImage(_options = {}) {
|
|
49
|
-
if (import.meta.server) {
|
|
50
|
-
if (_options.url) {
|
|
51
|
-
const type = _options.url.endsWith(".png") ? "image/png" : "image/jpeg";
|
|
52
|
-
const meta2 = [
|
|
53
|
-
{ property: "og:image", content: _options.url },
|
|
54
|
-
{ property: "og:image:type", content: type },
|
|
55
|
-
{ name: "twitter:card", content: "summary_large_image" },
|
|
56
|
-
{ name: "twitter:image:src", content: _options.url }
|
|
57
|
-
];
|
|
58
|
-
if (_options.width) {
|
|
59
|
-
meta2.push({ property: "og:image:width", content: _options.width });
|
|
60
|
-
meta2.push({ name: "twitter:image:width", content: _options.width });
|
|
61
|
-
}
|
|
62
|
-
if (_options.height) {
|
|
63
|
-
meta2.push({ property: "og:image:height", content: _options.height });
|
|
64
|
-
meta2.push({ name: "twitter:image:height", content: _options.height });
|
|
65
|
-
}
|
|
66
|
-
if (_options.alt) {
|
|
67
|
-
meta2.push({ property: "og:image:alt", content: _options.alt });
|
|
68
|
-
meta2.push({ name: "twitter:image:alt", content: _options.alt });
|
|
69
|
-
}
|
|
70
|
-
useServerHead({ meta: meta2 }, {
|
|
71
|
-
// after async scripts when capo.js is enabled
|
|
72
|
-
tagPriority: 35
|
|
73
|
-
});
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
const { defaults } = useRuntimeConfig()["nuxt-og-image"];
|
|
77
|
-
const options = normaliseOptions(_options);
|
|
78
|
-
const optionsWithDefault = defu(options, defaults);
|
|
79
|
-
const path = getOgImagePath(useRouter().currentRoute.value?.path, optionsWithDefault.extension);
|
|
80
|
-
const src = withSiteUrl(path);
|
|
32
|
+
const resolvedOptions = normaliseOptions(defu(options, routeRules, defaults));
|
|
33
|
+
if (_options.url) {
|
|
34
|
+
createOgImageMeta(null, options, resolvedOptions, nuxtApp.ssrContext);
|
|
35
|
+
} else {
|
|
36
|
+
const path = getOgImagePath(basePath, resolvedOptions);
|
|
81
37
|
if (import.meta.prerender)
|
|
82
38
|
appendHeader(useRequestEvent(), "x-nitro-prerender", path);
|
|
83
|
-
|
|
84
|
-
{ property: "og:image", content: src },
|
|
85
|
-
{ property: "og:image:width", content: optionsWithDefault.width },
|
|
86
|
-
{ property: "og:image:height", content: optionsWithDefault.height },
|
|
87
|
-
{ property: "og:image:type", content: `image/${optionsWithDefault.extension}` }
|
|
88
|
-
];
|
|
89
|
-
if (optionsWithDefault.alt)
|
|
90
|
-
meta.push({ property: "og:image:alt", content: optionsWithDefault.alt });
|
|
91
|
-
meta.push(...[
|
|
92
|
-
{ name: "twitter:card", content: "summary_large_image" },
|
|
93
|
-
{ name: "twitter:image:src", content: src },
|
|
94
|
-
{ name: "twitter:image:width", content: optionsWithDefault.width },
|
|
95
|
-
{ name: "twitter:image:height", content: optionsWithDefault.height }
|
|
96
|
-
]);
|
|
97
|
-
if (optionsWithDefault.alt)
|
|
98
|
-
meta.push({ name: "twitter:image:alt", content: optionsWithDefault.alt });
|
|
99
|
-
useServerHead({
|
|
100
|
-
meta,
|
|
101
|
-
script: [
|
|
102
|
-
{
|
|
103
|
-
id: "nuxt-og-image-options",
|
|
104
|
-
type: "application/json",
|
|
105
|
-
processTemplateParams: true,
|
|
106
|
-
innerHTML: () => {
|
|
107
|
-
const payload = {
|
|
108
|
-
title: "%s"
|
|
109
|
-
};
|
|
110
|
-
Object.entries(options).forEach(([key, val]) => {
|
|
111
|
-
payload[key.replace(/-([a-z])/g, (g) => g[1].toUpperCase())] = val;
|
|
112
|
-
});
|
|
113
|
-
return payload;
|
|
114
|
-
},
|
|
115
|
-
// we want this to be last in our head
|
|
116
|
-
tagPosition: "bodyClose"
|
|
117
|
-
}
|
|
118
|
-
]
|
|
119
|
-
}, {
|
|
120
|
-
// after async scripts when capo.js is enabled
|
|
121
|
-
tagPriority: 35
|
|
122
|
-
});
|
|
39
|
+
createOgImageMeta(path, options, resolvedOptions, nuxtApp.ssrContext);
|
|
123
40
|
}
|
|
124
41
|
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { ExtractComponentProps, OgImageOptions } from '../types';
|
|
2
|
+
import type { OgImageComponents } from '#nuxt-og-image/components';
|
|
3
|
+
export declare function defineOgImageComponent<T extends keyof OgImageComponents>(component: T, props: ExtractComponentProps<OgImageComponents[T]>, options?: OgImageOptions): void;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { defineOgImage, useRouter } from "#imports";
|
|
2
|
+
export function defineOgImageScreenshot(options = {}) {
|
|
3
|
+
const router = useRouter();
|
|
4
|
+
const route = router.currentRoute.value?.path || "";
|
|
5
|
+
return defineOgImage({
|
|
6
|
+
alt: `Web page screenshot${route ? ` of ${route}` : ""}.`,
|
|
7
|
+
renderer: "chromium",
|
|
8
|
+
extension: "jpeg",
|
|
9
|
+
component: "PageScreenshot",
|
|
10
|
+
// this is an alias
|
|
11
|
+
cache: true,
|
|
12
|
+
...options
|
|
13
|
+
});
|
|
14
|
+
}
|
|
@@ -1,10 +1,2 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
return inline(html, {
|
|
4
|
-
...options,
|
|
5
|
-
load_remote_stylesheets: false,
|
|
6
|
-
keep_style_tags: false
|
|
7
|
-
});
|
|
8
|
-
}
|
|
9
|
-
nodeFn.__mock = false;
|
|
10
|
-
export default nodeFn;
|
|
1
|
+
import cssInline from "css-inline";
|
|
2
|
+
export default cssInline;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const emojiCache: import("unstorage/dist/shared/unstorage.745f9650").a<string>;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { createStorage } from "unstorage";
|
|
2
|
+
import lruCacheDriver from "unstorage/drivers/lru-cache";
|
|
3
|
+
export const htmlPayloadCache = createStorage({
|
|
4
|
+
// short cache time so we don't need many entries at runtime
|
|
5
|
+
driver: lruCacheDriver({ max: import.meta.prerender ? 1e3 : 50 })
|
|
6
|
+
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Browser } from 'playwright-core';
|
|
2
2
|
import type { OgImageOptions } from '../../types';
|
|
3
|
-
export declare const prerenderCache: import("unstorage/dist/shared/unstorage.745f9650").a<OgImageOptions
|
|
3
|
+
export declare const prerenderCache: import("unstorage/dist/shared/unstorage.745f9650").a<OgImageOptions<"Fallback">> | undefined;
|
|
4
4
|
export declare const prerenderChromiumContext: {
|
|
5
5
|
browser?: Browser;
|
|
6
6
|
};
|
|
@@ -1,3 +1,2 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
export declare function loadFont(e: H3Event, font: FontConfig): Promise<any>;
|
|
1
|
+
import type { FontConfig, H3EventOgImageRender } from '../../types';
|
|
2
|
+
export declare function loadFont({ e }: H3EventOgImageRender, font: FontConfig): Promise<any>;
|
|
@@ -2,7 +2,7 @@ import { Buffer } from "node:buffer";
|
|
|
2
2
|
import { base64ToArrayBuffer } from "../env/assets.mjs";
|
|
3
3
|
import { fontCache } from "./cache.mjs";
|
|
4
4
|
import { useNitroOrigin, useStorage } from "#imports";
|
|
5
|
-
export async function loadFont(e, font) {
|
|
5
|
+
export async function loadFont({ e }, font) {
|
|
6
6
|
const fontKey = `${font.name}:${font.weight}`;
|
|
7
7
|
const storageKey = `assets:nuxt-og-image:font:${fontKey}`;
|
|
8
8
|
if (fontCache[fontKey])
|
|
@@ -23,7 +23,13 @@ export async function loadFont(e, font) {
|
|
|
23
23
|
});
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
if (data) {
|
|
27
|
+
fontCache[fontKey] = { name, weight: Number(weight), data, style: "normal" };
|
|
28
|
+
await useStorage().setItem(storageKey, Buffer.from(data).toString("base64"));
|
|
29
|
+
return fontCache[fontKey];
|
|
30
|
+
}
|
|
31
|
+
return createError({
|
|
32
|
+
statusCode: 500,
|
|
33
|
+
statusMessage: `Failed to fetch font: ${fontKey}`
|
|
34
|
+
});
|
|
29
35
|
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import defaultCharMap from "@iconify-json/noto/chars.json";
|
|
2
|
+
import { emojiCache } from "../cache/emojis.mjs";
|
|
3
|
+
const RE_MATCH_EMOJIS = /[#*0-9]\uFE0F?\u20E3|[\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23ED-\u23EF\u23F1\u23F2\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB\u25FC\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u2648-\u2653\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u267F\u2692\u2694-\u2697\u2699\u269B\u269C\u26A0\u26A7\u26AA\u26B0\u26B1\u26BD\u26BE\u26C4\u26C8\u26CF\u26D1\u26E9\u26F0-\u26F5\u26F7\u26F8\u26FA\u2702\u2708\u2709\u270F\u2712\u2714\u2716\u271D\u2721\u2733\u2734\u2744\u2747\u2757\u2763\u27A1\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B55\u3030\u303D\u3297\u3299]\uFE0F?|[\u261D\u270C\u270D](?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?|[\u270A\u270B](?:\uD83C[\uDFFB-\uDFFF])?|[\u23E9-\u23EC\u23F0\u23F3\u25FD\u2693\u26A1\u26AB\u26C5\u26CE\u26D4\u26EA\u26FD\u2705\u2728\u274C\u274E\u2753-\u2755\u2795-\u2797\u27B0\u27BF\u2B50]|\u26D3\uFE0F?(?:\u200D\uD83D\uDCA5)?|\u26F9(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|\u2764\uFE0F?(?:\u200D(?:\uD83D\uDD25|\uD83E\uDE79))?|\uD83C(?:[\uDC04\uDD70\uDD71\uDD7E\uDD7F\uDE02\uDE37\uDF21\uDF24-\uDF2C\uDF36\uDF7D\uDF96\uDF97\uDF99-\uDF9B\uDF9E\uDF9F\uDFCD\uDFCE\uDFD4-\uDFDF\uDFF5\uDFF7]\uFE0F?|[\uDF85\uDFC2\uDFC7](?:\uD83C[\uDFFB-\uDFFF])?|[\uDFC4\uDFCA](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDFCB\uDFCC](?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDCCF\uDD8E\uDD91-\uDD9A\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF43\uDF45-\uDF4A\uDF4C-\uDF7C\uDF7E-\uDF84\uDF86-\uDF93\uDFA0-\uDFC1\uDFC5\uDFC6\uDFC8\uDFC9\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF8-\uDFFF]|\uDDE6\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF]|\uDDE7\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF]|\uDDE8\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF5\uDDF7\uDDFA-\uDDFF]|\uDDE9\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF]|\uDDEA\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA]|\uDDEB\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7]|\uDDEC\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE]|\uDDED\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA]|\uDDEE\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9]|\uDDEF\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5]|\uDDF0\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF]|\uDDF1\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE]|\uDDF2\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF]|\uDDF3\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF]|\uDDF4\uD83C\uDDF2|\uDDF5\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE]|\uDDF6\uD83C\uDDE6|\uDDF7\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC]|\uDDF8\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF]|\uDDF9\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF]|\uDDFA\uD83C[\uDDE6\uDDEC\uDDF2\uDDF3\uDDF8\uDDFE\uDDFF]|\uDDFB\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA]|\uDDFC\uD83C[\uDDEB\uDDF8]|\uDDFD\uD83C\uDDF0|\uDDFE\uD83C[\uDDEA\uDDF9]|\uDDFF\uD83C[\uDDE6\uDDF2\uDDFC]|\uDF44(?:\u200D\uD83D\uDFEB)?|\uDF4B(?:\u200D\uD83D\uDFE9)?|\uDFC3(?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D(?:[\u2640\u2642]\uFE0F?(?:\u200D\u27A1\uFE0F?)?|\u27A1\uFE0F?))?|\uDFF3\uFE0F?(?:\u200D(?:\u26A7\uFE0F?|\uD83C\uDF08))?|\uDFF4(?:\u200D\u2620\uFE0F?|\uDB40\uDC67\uDB40\uDC62\uDB40(?:\uDC65\uDB40\uDC6E\uDB40\uDC67|\uDC73\uDB40\uDC63\uDB40\uDC74|\uDC77\uDB40\uDC6C\uDB40\uDC73)\uDB40\uDC7F)?)|\uD83D(?:[\uDC3F\uDCFD\uDD49\uDD4A\uDD6F\uDD70\uDD73\uDD76-\uDD79\uDD87\uDD8A-\uDD8D\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA\uDECB\uDECD-\uDECF\uDEE0-\uDEE5\uDEE9\uDEF0\uDEF3]\uFE0F?|[\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDC8F\uDC91\uDCAA\uDD7A\uDD95\uDD96\uDE4C\uDE4F\uDEC0\uDECC](?:\uD83C[\uDFFB-\uDFFF])?|[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4\uDEB5](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDD74\uDD90](?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?|[\uDC00-\uDC07\uDC09-\uDC14\uDC16-\uDC25\uDC27-\uDC3A\uDC3C-\uDC3E\uDC40\uDC44\uDC45\uDC51-\uDC65\uDC6A\uDC79-\uDC7B\uDC7D-\uDC80\uDC84\uDC88-\uDC8E\uDC90\uDC92-\uDCA9\uDCAB-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDDA4\uDDFB-\uDE2D\uDE2F-\uDE34\uDE37-\uDE41\uDE43\uDE44\uDE48-\uDE4A\uDE80-\uDEA2\uDEA4-\uDEB3\uDEB7-\uDEBF\uDEC1-\uDEC5\uDED0-\uDED2\uDED5-\uDED7\uDEDC-\uDEDF\uDEEB\uDEEC\uDEF4-\uDEFC\uDFE0-\uDFEB\uDFF0]|\uDC08(?:\u200D\u2B1B)?|\uDC15(?:\u200D\uD83E\uDDBA)?|\uDC26(?:\u200D(?:\u2B1B|\uD83D\uDD25))?|\uDC3B(?:\u200D\u2744\uFE0F?)?|\uDC41\uFE0F?(?:\u200D\uD83D\uDDE8\uFE0F?)?|\uDC68(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDC68\uDC69]\u200D\uD83D(?:\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?)|[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?)|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]))|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFC-\uDFFF])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB\uDFFD-\uDFFF])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB-\uDFFD\uDFFF])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB-\uDFFE])))?))?|\uDC69(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?[\uDC68\uDC69]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?|\uDC69\u200D\uD83D(?:\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?))|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]))|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFC-\uDFFF])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB\uDFFD-\uDFFF])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFD\uDFFF])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFE])))?))?|\uDC6F(?:\u200D[\u2640\u2642]\uFE0F?)?|\uDD75(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|\uDE2E(?:\u200D\uD83D\uDCA8)?|\uDE35(?:\u200D\uD83D\uDCAB)?|\uDE36(?:\u200D\uD83C\uDF2B\uFE0F?)?|\uDE42(?:\u200D[\u2194\u2195]\uFE0F?)?|\uDEB6(?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D(?:[\u2640\u2642]\uFE0F?(?:\u200D\u27A1\uFE0F?)?|\u27A1\uFE0F?))?)|\uD83E(?:[\uDD0C\uDD0F\uDD18-\uDD1F\uDD30-\uDD34\uDD36\uDD77\uDDB5\uDDB6\uDDBB\uDDD2\uDDD3\uDDD5\uDEC3-\uDEC5\uDEF0\uDEF2-\uDEF8](?:\uD83C[\uDFFB-\uDFFF])?|[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD\uDDCF\uDDD4\uDDD6-\uDDDD](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDDDE\uDDDF](?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDD0D\uDD0E\uDD10-\uDD17\uDD20-\uDD25\uDD27-\uDD2F\uDD3A\uDD3F-\uDD45\uDD47-\uDD76\uDD78-\uDDB4\uDDB7\uDDBA\uDDBC-\uDDCC\uDDD0\uDDE0-\uDDFF\uDE70-\uDE7C\uDE80-\uDE88\uDE90-\uDEBD\uDEBF-\uDEC2\uDECE-\uDEDB\uDEE0-\uDEE8]|\uDD3C(?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF])?|\uDDCE(?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D(?:[\u2640\u2642]\uFE0F?(?:\u200D\u27A1\uFE0F?)?|\u27A1\uFE0F?))?|\uDDD1(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83E\uDDD1|\uDDD1\u200D\uD83E\uDDD2(?:\u200D\uD83E\uDDD2)?|\uDDD2(?:\u200D\uD83E\uDDD2)?))|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFC-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB\uDFFD-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB-\uDFFD\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB-\uDFFE]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?))?|\uDEF1(?:\uD83C(?:\uDFFB(?:\u200D\uD83E\uDEF2\uD83C[\uDFFC-\uDFFF])?|\uDFFC(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB\uDFFD-\uDFFF])?|\uDFFD(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])?|\uDFFE(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB-\uDFFD\uDFFF])?|\uDFFF(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB-\uDFFE])?))?)/g;
|
|
4
|
+
export async function applyEmojis(ctx, island) {
|
|
5
|
+
const html = island.html;
|
|
6
|
+
const matches = html.match(RE_MATCH_EMOJIS);
|
|
7
|
+
if (!matches)
|
|
8
|
+
return html;
|
|
9
|
+
const replacements = await Promise.all(matches.map(async (match) => {
|
|
10
|
+
const unicode = match.codePointAt(0).toString(16);
|
|
11
|
+
const emoji = defaultCharMap[unicode];
|
|
12
|
+
if (emoji) {
|
|
13
|
+
const key = ["1", ctx.options.emojis, emoji].join(":");
|
|
14
|
+
let svg;
|
|
15
|
+
if (await emojiCache.hasItem(key))
|
|
16
|
+
svg = await emojiCache.getItem(key);
|
|
17
|
+
if (!svg) {
|
|
18
|
+
svg = await ctx.e.$fetch(`https://api.iconify.design/${ctx.options.emojis}/${emoji}.svg`, {
|
|
19
|
+
responseType: "text"
|
|
20
|
+
});
|
|
21
|
+
if (svg === "404")
|
|
22
|
+
svg = void 0;
|
|
23
|
+
if (svg)
|
|
24
|
+
await emojiCache.setItem(key, svg);
|
|
25
|
+
}
|
|
26
|
+
if (svg)
|
|
27
|
+
return `
|
|
28
|
+
${svg.replace("<svg ", '<svg data-emoji style="margin: 0 .05em 0 .3em; vertical-align: -0.1em;" ')}
|
|
29
|
+
`;
|
|
30
|
+
return match;
|
|
31
|
+
}
|
|
32
|
+
}));
|
|
33
|
+
const finalHtml = html.replace(RE_MATCH_EMOJIS, () => replacements.shift());
|
|
34
|
+
const modified = finalHtml !== island.html;
|
|
35
|
+
island.html = finalHtml;
|
|
36
|
+
return modified;
|
|
37
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { useCssInline } from "../renderers/satori/instances.mjs";
|
|
2
|
+
import { useNitroOrigin } from "#imports";
|
|
3
|
+
import cssInline from "#nuxt-og-image/bindings/css-inline";
|
|
4
|
+
export async function applyInlineCss({ e }, island) {
|
|
5
|
+
let html = island.html;
|
|
6
|
+
const componentInlineStyles = island.head.link.filter((l) => l.href.startsWith("/_nuxt/components"));
|
|
7
|
+
const usingInlineCss = !!componentInlineStyles.length;
|
|
8
|
+
if (!cssInline.__unenv__ && componentInlineStyles.length) {
|
|
9
|
+
const css = island.head.style.map((s) => s.innerHTML).join("\n");
|
|
10
|
+
const linksToCss = (await Promise.all(
|
|
11
|
+
componentInlineStyles.map((l) => {
|
|
12
|
+
return e.$fetch(`${l.href}&hmr=false`, {
|
|
13
|
+
responseType: "text",
|
|
14
|
+
baseURL: useNitroOrigin(e)
|
|
15
|
+
}).then((res) => {
|
|
16
|
+
return res.trim().split("\n").filter((l2) => !l2.startsWith("//")).join("\n").trim();
|
|
17
|
+
});
|
|
18
|
+
})
|
|
19
|
+
)).join("\n");
|
|
20
|
+
const cssToInline = `${linksToCss}${css}`;
|
|
21
|
+
const cssInline2 = await useCssInline();
|
|
22
|
+
html = cssInline2.inline(island.html, {
|
|
23
|
+
load_remote_stylesheets: false,
|
|
24
|
+
extra_css: cssToInline
|
|
25
|
+
});
|
|
26
|
+
const classes = cssToInline.match(/\.([a-zA-Z0-9-_]+)/g)?.map((c) => c.replace(".", ""));
|
|
27
|
+
if (classes)
|
|
28
|
+
html = html.replace(new RegExp(`class="(${classes.join("|")})"`, "g"), "");
|
|
29
|
+
island.html = html;
|
|
30
|
+
}
|
|
31
|
+
return usingInlineCss;
|
|
32
|
+
}
|
|
@@ -1,37 +1,20 @@
|
|
|
1
|
-
import { createError } from "h3";
|
|
2
|
-
import { hash } from "ohash";
|
|
3
1
|
import { createHeadCore } from "@unhead/vue";
|
|
4
|
-
import twemoji from "twemoji";
|
|
5
2
|
import { renderSSRHead } from "@unhead/ssr";
|
|
3
|
+
import { applyEmojis } from "./applyEmojis.mjs";
|
|
4
|
+
import { fetchIsland } from "./fetchIsland.mjs";
|
|
6
5
|
import { useRuntimeConfig } from "#imports";
|
|
7
|
-
export async function
|
|
6
|
+
export async function devIframeTemplate(ctx) {
|
|
7
|
+
const { options } = ctx;
|
|
8
8
|
const { fonts, satoriOptions } = useRuntimeConfig()["nuxt-og-image"];
|
|
9
|
-
|
|
10
|
-
throw createError({
|
|
11
|
-
statusCode: 500,
|
|
12
|
-
statusMessage: `Nuxt OG Image trying to render an invalid component. Received options ${JSON.stringify(options)}`
|
|
13
|
-
});
|
|
14
|
-
}
|
|
15
|
-
const hashId = hash([options.component, options, Math.random() * 100]);
|
|
16
|
-
const island = await e.$fetch(`/__nuxt_island/${options.component}_${hashId}.json`, {
|
|
17
|
-
params: {
|
|
18
|
-
props: JSON.stringify(options)
|
|
19
|
-
}
|
|
20
|
-
});
|
|
9
|
+
const island = await fetchIsland(ctx);
|
|
21
10
|
const head = createHeadCore();
|
|
22
11
|
head.push(island.head);
|
|
23
12
|
let defaultFontFamily = "sans-serif";
|
|
24
13
|
const firstFont = fonts[0];
|
|
25
14
|
if (firstFont)
|
|
26
15
|
defaultFontFamily = firstFont.name;
|
|
16
|
+
await applyEmojis(ctx, island);
|
|
27
17
|
let html = island.html;
|
|
28
|
-
try {
|
|
29
|
-
html = twemoji.parse(html, {
|
|
30
|
-
folder: "svg",
|
|
31
|
-
ext: ".svg"
|
|
32
|
-
});
|
|
33
|
-
} catch (e2) {
|
|
34
|
-
}
|
|
35
18
|
const googleFonts = {};
|
|
36
19
|
fonts.filter((font) => !font.path).forEach((font) => {
|
|
37
20
|
if (!googleFonts[font.name])
|
|
@@ -54,12 +37,6 @@ export async function fetchHTML(e, options) {
|
|
|
54
37
|
height: ${options.height}px;
|
|
55
38
|
overflow: hidden;
|
|
56
39
|
background-color: ${options.mode === "dark" ? "#1b1b1b" : "#fff"};
|
|
57
|
-
}
|
|
58
|
-
img.emoji {
|
|
59
|
-
height: 1em;
|
|
60
|
-
width: 1em;
|
|
61
|
-
margin: 0 .05em 0 .1em;
|
|
62
|
-
vertical-align: -0.1em;
|
|
63
40
|
}`
|
|
64
41
|
},
|
|
65
42
|
...fonts.filter((font) => font.path).map((font) => {
|
|
@@ -98,6 +75,7 @@ img.emoji {
|
|
|
98
75
|
rel: "stylesheet"
|
|
99
76
|
},
|
|
100
77
|
// have to add each weight as their own stylesheet
|
|
78
|
+
// we should use the local font file no?
|
|
101
79
|
...Object.entries(googleFonts).map(([name, fonts2]) => {
|
|
102
80
|
return {
|
|
103
81
|
href: `https://fonts.googleapis.com/css2?family=${name}:wght@${fonts2.map((f) => f.weight).join(";")}&display=swap`,
|
|
@@ -108,10 +86,9 @@ img.emoji {
|
|
|
108
86
|
});
|
|
109
87
|
html = html.replaceAll(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, "");
|
|
110
88
|
const headChunk = await renderSSRHead(head);
|
|
111
|
-
|
|
89
|
+
return `<!DOCTYPE html>
|
|
112
90
|
<html ${headChunk.htmlAttrs}>
|
|
113
91
|
<head>${headChunk.headTags}</head>
|
|
114
92
|
<body ${headChunk.bodyAttrs}>${headChunk.bodyTagsOpen}<div data-v-inspector-ignore="true" style="position: relative; display: flex; margin: 0 auto; width: ${options.width}px; height: ${options.height}px; overflow: hidden;">${html}</div>${headChunk.bodyTags}</body>
|
|
115
93
|
</html>`;
|
|
116
|
-
return htmlTemplate;
|
|
117
94
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { createError } from "h3";
|
|
2
|
+
import { hash } from "ohash";
|
|
3
|
+
export function fetchIsland({ options, e }) {
|
|
4
|
+
if (!options.component) {
|
|
5
|
+
throw createError({
|
|
6
|
+
statusCode: 500,
|
|
7
|
+
statusMessage: `Nuxt OG Image trying to render an invalid component. Received options ${JSON.stringify(options)}`
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
const hashId = hash([options.component, options]);
|
|
11
|
+
const props = typeof options.props !== "undefined" ? options.props : options;
|
|
12
|
+
return e.$fetch(`/__nuxt_island/${options.component}_${hashId}.json`, {
|
|
13
|
+
params: {
|
|
14
|
+
props: JSON.stringify(props)
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { type H3Error, type H3Event } from 'h3';
|
|
2
2
|
import type { OgImageOptions } from '../../types';
|
|
3
|
-
export declare function fetchPathHtmlAndExtractOptions(e: H3Event, path: string): Promise<H3Error | OgImageOptions>;
|
|
3
|
+
export declare function fetchPathHtmlAndExtractOptions(e: H3Event, path: string, key: string): Promise<H3Error | OgImageOptions>;
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { createError } from "h3";
|
|
2
|
+
import { htmlPayloadCache } from "../cache/htmlPayload.mjs";
|
|
2
3
|
import { extractAndNormaliseOgImageOptions } from "./extract.mjs";
|
|
3
|
-
export async function fetchPathHtmlAndExtractOptions(e, path) {
|
|
4
|
+
export async function fetchPathHtmlAndExtractOptions(e, path, key) {
|
|
5
|
+
const cachedHtmlPayload = await htmlPayloadCache.getItem(key);
|
|
6
|
+
if (cachedHtmlPayload && cachedHtmlPayload.expiresAt < Date.now())
|
|
7
|
+
return cachedHtmlPayload.value;
|
|
4
8
|
let html;
|
|
5
9
|
try {
|
|
6
10
|
html = await e.$fetch(path);
|
|
@@ -11,10 +15,11 @@ export async function fetchPathHtmlAndExtractOptions(e, path) {
|
|
|
11
15
|
});
|
|
12
16
|
}
|
|
13
17
|
const payload = extractAndNormaliseOgImageOptions(html);
|
|
14
|
-
if (
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
+
if (payload) {
|
|
19
|
+
await htmlPayloadCache.setItem(key, {
|
|
20
|
+
// 60 minutes for prerender, 10 seconds for runtime
|
|
21
|
+
expiresAt: Date.now() + 1e3 * (import.meta.prerender ? 60 * 60 : 10),
|
|
22
|
+
value: payload
|
|
18
23
|
});
|
|
19
24
|
}
|
|
20
25
|
return payload;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type { OgImageOptions } from '../../types';
|
|
2
|
-
export declare function normaliseOptions(_options:
|
|
1
|
+
import type { DefineOgImageInput, OgImageOptions, OgImagePrebuilt } from '../../types';
|
|
2
|
+
export declare function normaliseOptions(_options: DefineOgImageInput): OgImageOptions | OgImagePrebuilt;
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import { getOgImagePath } from "../../../utilts.mjs";
|
|
2
1
|
import { prerenderChromiumContext } from "../../cache/prerender.mjs";
|
|
3
2
|
import { createScreenshot } from "./screenshot.mjs";
|
|
4
3
|
import { createBrowser } from "#nuxt-og-image/bindings/chromium";
|
|
5
4
|
const ChromiumRenderer = {
|
|
6
5
|
name: "chromium",
|
|
7
|
-
supportedFormats: ["png", "jpeg"],
|
|
8
|
-
async
|
|
6
|
+
supportedFormats: ["png", "jpeg", "jpg"],
|
|
7
|
+
async debug() {
|
|
8
|
+
return {};
|
|
9
|
+
},
|
|
10
|
+
async createImage(ctx) {
|
|
9
11
|
const browser = (import.meta.prerender ? prerenderChromiumContext.browser : null) || await createBrowser();
|
|
10
12
|
if (!browser) {
|
|
11
13
|
return createError({
|
|
@@ -15,10 +17,7 @@ const ChromiumRenderer = {
|
|
|
15
17
|
}
|
|
16
18
|
if (import.meta.prerender)
|
|
17
19
|
prerenderChromiumContext.browser = browser;
|
|
18
|
-
return createScreenshot(
|
|
19
|
-
...options,
|
|
20
|
-
path: options.component === "PageScreenshot" ? options.path : getOgImagePath(options.path, "html")
|
|
21
|
-
}).finally(async () => {
|
|
20
|
+
return createScreenshot(ctx, browser).finally(async () => {
|
|
22
21
|
await browser.close();
|
|
23
22
|
});
|
|
24
23
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import type { Buffer } from 'node:buffer';
|
|
3
3
|
import type { Browser } from 'playwright-core';
|
|
4
|
-
import type {
|
|
5
|
-
|
|
6
|
-
export declare function createScreenshot(e: H3Event, browser: Browser, options: RendererOptions): Promise<Buffer>;
|
|
4
|
+
import type { H3EventOgImageRender } from '../../../types';
|
|
5
|
+
export declare function createScreenshot({ e, options, extension }: H3EventOgImageRender, browser: Browser): Promise<Buffer>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { withQuery } from "ufo";
|
|
1
|
+
import { joinURL, withQuery } from "ufo";
|
|
2
2
|
import { useNitroOrigin } from "#imports";
|
|
3
|
-
export async function createScreenshot(e,
|
|
3
|
+
export async function createScreenshot({ e, options, extension }, browser) {
|
|
4
|
+
const path = options.component === "PageScreenshot" ? options.path : joinURL("/__og-image__/image", options.path, `og.html`);
|
|
4
5
|
const page = await browser.newPage({
|
|
5
6
|
colorScheme: options.colorScheme,
|
|
6
7
|
baseURL: useNitroOrigin(e)
|
|
@@ -23,7 +24,7 @@ export async function createScreenshot(e, browser, options) {
|
|
|
23
24
|
}, html);
|
|
24
25
|
await page.waitForLoadState("networkidle");
|
|
25
26
|
} else {
|
|
26
|
-
await page.goto(withQuery(
|
|
27
|
+
await page.goto(withQuery(path, options.props), {
|
|
27
28
|
timeout: 1e4,
|
|
28
29
|
waitUntil: "networkidle"
|
|
29
30
|
});
|
|
@@ -31,7 +32,7 @@ export async function createScreenshot(e, browser, options) {
|
|
|
31
32
|
const screenshotOptions = {
|
|
32
33
|
timeout: 1e4,
|
|
33
34
|
animations: "disabled",
|
|
34
|
-
type:
|
|
35
|
+
type: extension === "png" ? "png" : "jpeg"
|
|
35
36
|
};
|
|
36
37
|
if (options.mask) {
|
|
37
38
|
await page.evaluate((mask) => {
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import type { FontConfig } from '../../../types';
|
|
1
|
+
import type { FontConfig, H3EventOgImageRender } from '../../../types';
|
|
2
2
|
export declare const satoriFonts: any[];
|
|
3
|
-
export declare function loadFonts(
|
|
3
|
+
export declare function loadFonts(e: H3EventOgImageRender, fonts: FontConfig[]): Promise<any>;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { loadFont } from "../../font/fetch.mjs";
|
|
2
2
|
export const satoriFonts = [];
|
|
3
3
|
let fontLoadPromise = null;
|
|
4
|
-
export function loadFonts(
|
|
4
|
+
export function loadFonts(e, fonts) {
|
|
5
5
|
if (fontLoadPromise)
|
|
6
6
|
return fontLoadPromise;
|
|
7
|
-
return fontLoadPromise = Promise.all(fonts.map((font) => loadFont(
|
|
7
|
+
return fontLoadPromise = Promise.all(fonts.map((font) => loadFont(e, font)));
|
|
8
8
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
export declare function createSvg(e: H3Event, options: RendererOptions): Promise<string>;
|
|
1
|
+
import type { H3EventOgImageRender, Renderer } from '../../../types';
|
|
2
|
+
export declare function createSvg(event: H3EventOgImageRender): Promise<string>;
|
|
4
3
|
declare const SatoriRenderer: Renderer;
|
|
5
4
|
export default SatoriRenderer;
|