nuxt-og-image 6.10.4 → 7.0.1
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 +10 -14
- package/dist/chunks/tw4.mjs +6 -6
- package/dist/chunks/uno.mjs +7 -7
- package/dist/cli.mjs +4 -4
- package/dist/devtools/components/og-image/RendererSelectModal.vue +1 -1
- package/dist/devtools/lib/og-image/fonts.ts +38 -0
- package/dist/devtools/lib/og-image/types.ts +7 -0
- package/dist/devtools/pages/og-image/index.vue +19 -14
- package/dist/module.d.mts +14 -10
- package/dist/module.d.ts +14 -10
- package/dist/module.json +2 -2
- package/dist/module.mjs +6 -6
- package/dist/runtime/app/client-utils.js +7 -4
- package/dist/runtime/app/components/Templates/Community/SaaS.satori.vue +1 -1
- package/dist/runtime/app/components/Templates/Community/SimpleBlog.satori.vue +1 -1
- package/dist/runtime/app/disabled/components.d.ts +1 -0
- package/dist/runtime/app/disabled/components.js +0 -0
- package/dist/runtime/app/disabled/composables/defineOgImage.d.ts +1 -0
- package/dist/runtime/app/disabled/composables/defineOgImage.js +1 -0
- package/dist/runtime/app/disabled/composables/defineOgImageComponent.d.ts +1 -0
- package/dist/runtime/app/disabled/composables/defineOgImageComponent.js +1 -0
- package/dist/runtime/app/disabled/composables/defineOgImageScreenshot.d.ts +1 -0
- package/dist/runtime/app/disabled/composables/defineOgImageScreenshot.js +1 -0
- package/dist/runtime/app/disabled/composables/mock.d.ts +1 -0
- package/dist/runtime/app/disabled/composables/mock.js +1 -0
- package/dist/runtime/app/disabled/index.d.ts +3 -0
- package/dist/runtime/app/disabled/index.js +3 -0
- package/dist/runtime/app/index.d.ts +4 -0
- package/dist/runtime/app/index.js +4 -0
- package/dist/runtime/app/utils/plugins.js +1 -1
- package/dist/runtime/app/utils.js +2 -2
- package/dist/runtime/server/index.d.ts +1 -0
- package/dist/runtime/server/index.js +1 -0
- package/dist/runtime/server/middleware/signing.d.ts +2 -0
- package/dist/runtime/server/middleware/signing.js +19 -0
- package/dist/runtime/server/nitro.d.ts +3 -3
- package/dist/runtime/server/nitro.js +4 -4
- package/dist/runtime/server/og-image/bindings/font-assets/dev-prerender.js +8 -49
- package/dist/runtime/server/og-image/bindings/font-assets/node.js +3 -2
- package/dist/runtime/server/og-image/bindings/satori/node.d.ts +1 -2
- package/dist/runtime/server/og-image/bindings/satori/wasm-fs.d.ts +1 -2
- package/dist/runtime/server/og-image/bindings/satori/wasm-fs.js +1 -1
- package/dist/runtime/server/og-image/bindings/satori/wasm.d.ts +1 -2
- package/dist/runtime/server/og-image/bindings/satori/wasm.js +1 -1
- package/dist/runtime/server/og-image/browser/screenshot.js +5 -3
- package/dist/runtime/server/og-image/cache/publish.d.ts +46 -0
- package/dist/runtime/server/og-image/cache/publish.js +91 -0
- package/dist/runtime/server/og-image/cache/published.d.ts +17 -0
- package/dist/runtime/server/og-image/cache/published.js +49 -0
- package/dist/runtime/server/og-image/context.js +1 -1
- package/dist/runtime/server/og-image/core/plugins/imageSrc.js +2 -5
- package/dist/runtime/server/og-image/core/transforms/emojis/index.d.ts +3 -2
- package/dist/runtime/server/og-image/core/vnodes.js +19 -1
- package/dist/runtime/server/og-image/font-source.d.ts +1 -0
- package/dist/runtime/server/og-image/font-source.js +1 -0
- package/dist/runtime/server/og-image/fonts.d.ts +1 -1
- package/dist/runtime/server/og-image/fonts.js +1 -1
- package/dist/runtime/server/og-image/satori/filters.d.ts +1 -0
- package/dist/runtime/server/og-image/satori/filters.js +14 -0
- package/dist/runtime/server/og-image/satori/instances.d.ts +1 -2
- package/dist/runtime/server/og-image/satori/plugins/classes.js +0 -7
- package/dist/runtime/server/og-image/satori/renderer.js +2 -1
- package/dist/runtime/server/og-image/satori/vnodes.js +1 -4
- package/dist/runtime/server/og-image/takumi/renderer.js +11 -47
- package/dist/runtime/server/og-image/utils/css.d.ts +0 -5
- package/dist/runtime/server/og-image/utils/css.js +0 -5
- package/dist/runtime/server/plugins/auto-eject-nitro3.d.ts +2 -0
- package/dist/runtime/server/plugins/auto-eject-nitro3.js +9 -0
- package/dist/runtime/server/plugins/auto-eject.js +3 -31
- package/dist/runtime/server/plugins/prerender.js +67 -2
- package/dist/runtime/server/plugins/publish.d.ts +2 -0
- package/dist/runtime/server/plugins/publish.js +44 -0
- package/dist/runtime/server/routes/debug.json.d.ts +10 -1
- package/dist/runtime/server/routes/debug.json.js +4 -4
- package/dist/runtime/server/routes/static-font.d.ts +2 -0
- package/dist/runtime/server/routes/static-font.js +22 -0
- package/dist/runtime/server/signing-secret.d.ts +8 -0
- package/dist/runtime/server/signing-secret.js +75 -0
- package/dist/runtime/server/util/auto-eject-lifecycle.d.ts +13 -0
- package/dist/runtime/server/util/auto-eject-lifecycle.js +31 -0
- package/dist/runtime/server/util/cache.d.ts +1 -0
- package/dist/runtime/server/util/cache.js +12 -6
- package/dist/runtime/server/util/cloudflare.d.ts +2 -2
- package/dist/runtime/server/util/eventHandlers.js +68 -3
- package/dist/runtime/server/util/fetchLocalAsset.js +2 -2
- package/dist/runtime/server/util/origin.d.ts +3 -0
- package/dist/runtime/server/util/origin.js +4 -0
- package/dist/runtime/server/util/publishWarnings.d.ts +6 -0
- package/dist/runtime/server/util/publishWarnings.js +6 -0
- package/dist/runtime/server/utils.d.ts +3 -3
- package/dist/runtime/server/utils.js +5 -10
- package/dist/runtime/shared/publish.d.ts +13 -0
- package/dist/runtime/shared/publish.js +17 -0
- package/dist/runtime/shared/urlEncoding.js +9 -4
- package/dist/runtime/types.d.ts +11 -16
- package/dist/shared/{nuxt-og-image.Bcegsloy.mjs → nuxt-og-image.DR_SxdDv.mjs} +1224 -1109
- package/package.json +60 -62
- package/skills/nuxt-og-image/SKILL.md +31 -14
- package/types/virtual.d.ts +8 -0
- package/dist/runtime/server/og-image/satori/plugins/emojis.d.ts +0 -2
- package/dist/runtime/server/og-image/satori/plugins/emojis.js +0 -112
- package/dist/runtime/server/og-image/satori/plugins/flex.d.ts +0 -2
- package/dist/runtime/server/og-image/satori/plugins/flex.js +0 -48
|
@@ -1,12 +1,16 @@
|
|
|
1
|
-
import { appendResponseHeader, createError, getRequestHost, H3Error, setHeader } from "#nuxtseo/h3";
|
|
1
|
+
import { appendResponseHeader, createError, getRequestHost, H3Error, sendRedirect, setHeader } from "#nuxtseo/h3";
|
|
2
|
+
import { useStorage } from "#nuxtseo/nitro";
|
|
2
3
|
import { getSiteConfig } from "#site-config/server/composables/getSiteConfig";
|
|
3
4
|
import { logger } from "../../logger.js";
|
|
4
5
|
import { getBuildCachedImage, setBuildCachedImage } from "../og-image/cache/buildCache.js";
|
|
6
|
+
import { getPublishedImage, getPublishKey, publishImage } from "../og-image/cache/publish.js";
|
|
7
|
+
import { getPublishedImageCache, getPublishedImageCacheKey } from "../og-image/cache/published.js";
|
|
5
8
|
import { resolveContext } from "../og-image/context.js";
|
|
6
9
|
import { fetchPathHtmlAndExtractOptions } from "../og-image/devtools.js";
|
|
7
10
|
import { html } from "../og-image/templates/html.js";
|
|
8
11
|
import { useOgImageRuntimeConfig } from "../utils.js";
|
|
9
12
|
import { useOgImageBufferCache } from "./cache.js";
|
|
13
|
+
import { warnPublishUnavailable } from "./publishWarnings.js";
|
|
10
14
|
import { parsePurgeRequest } from "./purge.js";
|
|
11
15
|
import { getEventQuery } from "./query.js";
|
|
12
16
|
export async function imageEventHandler(e) {
|
|
@@ -31,7 +35,8 @@ export async function imageEventHandler(e) {
|
|
|
31
35
|
async function renderOgImage(e, ctx) {
|
|
32
36
|
const timings = ctx.timings;
|
|
33
37
|
const { isDevToolsContextRequest, extension, renderer } = ctx;
|
|
34
|
-
const
|
|
38
|
+
const config = useOgImageRuntimeConfig(e);
|
|
39
|
+
const { debug, baseCacheKey, security, publish } = config;
|
|
35
40
|
if (!import.meta.prerender && !import.meta.dev && security?.restrictRuntimeImagesToOrigin) {
|
|
36
41
|
const requestHost = getRequestHost(e, { xForwardedHost: true });
|
|
37
42
|
let requestHostname;
|
|
@@ -67,6 +72,7 @@ async function renderOgImage(e, ctx) {
|
|
|
67
72
|
statusMessage: "[Nuxt OG Image] Invalid purge token. Provide the signing secret as ?purge=<secret>."
|
|
68
73
|
});
|
|
69
74
|
}
|
|
75
|
+
const purge = purgeRequest._tag === "Authorized";
|
|
70
76
|
if ((import.meta.dev || debug) && isDevToolsContextRequest) {
|
|
71
77
|
setHeader(e, "Content-Type", "application/json");
|
|
72
78
|
const [extract, rendererDebug] = await Promise.all([
|
|
@@ -125,15 +131,48 @@ async function renderOgImage(e, ctx) {
|
|
|
125
131
|
timings.record("cache-hit", 0);
|
|
126
132
|
return buildCachedImage;
|
|
127
133
|
}
|
|
134
|
+
let publication = publish && !import.meta.dev && !import.meta.prerender ? (() => {
|
|
135
|
+
const key = getPublishKey(new URL(e.path, getSiteConfig(e).url).href, config.defaults, publish.cacheVersion);
|
|
136
|
+
return {
|
|
137
|
+
cache: getPublishedImageCache(ctx._nitro),
|
|
138
|
+
cacheKey: getPublishedImageCacheKey(publish, key, extension),
|
|
139
|
+
input: {
|
|
140
|
+
storage: useStorage(),
|
|
141
|
+
mount: publish.storage,
|
|
142
|
+
baseURL: publish.baseURL,
|
|
143
|
+
key,
|
|
144
|
+
extension,
|
|
145
|
+
maxAgeSeconds: Number(ctx.options.cacheMaxAgeSeconds),
|
|
146
|
+
timeoutMs: security.renderTimeout,
|
|
147
|
+
now: Date.now
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
})() : void 0;
|
|
151
|
+
if (publication && !purge && !publication.cache.isPublishing(publication.cacheKey, Date.now())) {
|
|
152
|
+
const result = await getPublishedImage(publication.input);
|
|
153
|
+
if (result._tag === "Published" && result.expiresAt > Date.now()) {
|
|
154
|
+
publication.cache.remember(publication.cacheKey, result, Date.now());
|
|
155
|
+
const remainingAge = Math.max(0, Math.floor((result.expiresAt - Date.now()) / 1e3));
|
|
156
|
+
setHeader(e, "Cache-Control", `public, max-age=${remainingAge}, s-maxage=${remainingAge}`);
|
|
157
|
+
return sendRedirect(e, result.url, 302);
|
|
158
|
+
}
|
|
159
|
+
publication.cache.forget(publication.cacheKey);
|
|
160
|
+
if (result._tag === "Unavailable") {
|
|
161
|
+
warnPublishUnavailable(ctx._nitro, result.reason, logger);
|
|
162
|
+
publication = void 0;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
128
165
|
const endCacheLookup = timings.start("cache-lookup");
|
|
129
166
|
const cacheApi = await useOgImageBufferCache(ctx, {
|
|
130
167
|
cacheMaxAgeSeconds: ctx.options.cacheMaxAgeSeconds,
|
|
131
168
|
baseCacheKey,
|
|
132
|
-
purge
|
|
169
|
+
purge
|
|
133
170
|
}).finally(endCacheLookup);
|
|
134
171
|
if (typeof cacheApi === "undefined") {
|
|
135
172
|
return;
|
|
136
173
|
}
|
|
174
|
+
if (publication && purge)
|
|
175
|
+
publication.cache.forget(publication.cacheKey);
|
|
137
176
|
let image = cacheApi.cachedItem;
|
|
138
177
|
if (image) {
|
|
139
178
|
timings.record("cache-hit", 0);
|
|
@@ -172,5 +211,31 @@ async function renderOgImage(e, ctx) {
|
|
|
172
211
|
setBuildCachedImage(ctx.options, extension, image, ctx.options.cacheMaxAgeSeconds);
|
|
173
212
|
}
|
|
174
213
|
}
|
|
214
|
+
if (publication) {
|
|
215
|
+
const maxAge = Number(ctx.options.cacheMaxAgeSeconds);
|
|
216
|
+
const expiresAt = cacheApi.expiresAt || Date.now() + (Number.isFinite(maxAge) ? Math.max(0, maxAge) : 0) * 1e3;
|
|
217
|
+
const remainingAge = Math.max(0, (expiresAt - Date.now()) / 1e3);
|
|
218
|
+
const { cache, cacheKey, input } = publication;
|
|
219
|
+
const token = cache.begin(cacheKey, Date.now(), input.timeoutMs);
|
|
220
|
+
if (token) {
|
|
221
|
+
const bytes = new Uint8Array(image);
|
|
222
|
+
const app = ctx._nitro;
|
|
223
|
+
const task = publishImage({
|
|
224
|
+
...input,
|
|
225
|
+
maxAgeSeconds: remainingAge,
|
|
226
|
+
expiresAt,
|
|
227
|
+
force: true,
|
|
228
|
+
render: async () => bytes
|
|
229
|
+
}).then((result) => {
|
|
230
|
+
cache.complete(cacheKey, token, result, Date.now());
|
|
231
|
+
if (result._tag === "Unavailable")
|
|
232
|
+
warnPublishUnavailable(app, result.reason, logger);
|
|
233
|
+
}).catch((reason) => {
|
|
234
|
+
cache.complete(cacheKey, token, { _tag: "Unavailable" }, Date.now());
|
|
235
|
+
warnPublishUnavailable(app, reason, logger);
|
|
236
|
+
});
|
|
237
|
+
e.waitUntil(task);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
175
240
|
return image;
|
|
176
241
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { $fetch } from "ofetch";
|
|
2
2
|
import { fetchWithEvent } from "#nuxtseo/nitro";
|
|
3
|
-
import { getNitroOrigin } from "#site-config/server/composables";
|
|
4
3
|
import { tryCloudflareAssetsFetch } from "./cloudflareAssets.js";
|
|
4
|
+
import { getOgImageOrigin } from "./origin.js";
|
|
5
5
|
export async function fetchLocalAsset(event, path, options) {
|
|
6
6
|
const { fetchTimeout, headers, includeExternalFallback = false, onStepFailure } = options;
|
|
7
7
|
const deadline = AbortSignal.timeout(fetchTimeout);
|
|
@@ -30,7 +30,7 @@ export async function fetchLocalAsset(event, path, options) {
|
|
|
30
30
|
}));
|
|
31
31
|
if (result || expired || !includeExternalFallback)
|
|
32
32
|
return result;
|
|
33
|
-
const absolute = `${
|
|
33
|
+
const absolute = `${getOgImageOrigin(event)}${path}`;
|
|
34
34
|
return await race($fetch(absolute, {
|
|
35
35
|
responseType: "arrayBuffer",
|
|
36
36
|
signal: deadline,
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { OgImageRenderEventContext } from '../../types.js';
|
|
2
|
+
export declare function warnPublishUnavailable(app: OgImageRenderEventContext['_nitro'] & {
|
|
3
|
+
_ogImagePublishWarned?: boolean;
|
|
4
|
+
}, reason: unknown, logger: {
|
|
5
|
+
warn: (message: string, reason: unknown) => void;
|
|
6
|
+
}): void;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export function warnPublishUnavailable(app, reason, logger) {
|
|
2
|
+
if (app._ogImagePublishWarned)
|
|
3
|
+
return;
|
|
4
|
+
app._ogImagePublishWarned = true;
|
|
5
|
+
logger.warn("[Nuxt OG Image] Publish storage is unavailable. Keeping app image URLs. Check the storage driver and credentials.", reason);
|
|
6
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { RequestEvent } from 'nuxt/server';
|
|
2
2
|
import type { OgImageOptionsInternal, OgImageRuntimeConfig } from '../types.js';
|
|
3
3
|
export interface GetOgImagePathResult {
|
|
4
4
|
path: string;
|
|
5
5
|
hash?: string;
|
|
6
6
|
}
|
|
7
|
-
export declare function getOgImagePath(event:
|
|
8
|
-
export declare function useOgImageRuntimeConfig(e?:
|
|
7
|
+
export declare function getOgImagePath(event: Pick<RequestEvent, 'context'>, _pagePath: string, _options?: Partial<OgImageOptionsInternal>): GetOgImagePathResult;
|
|
8
|
+
export declare function useOgImageRuntimeConfig(e?: Pick<RequestEvent, 'context'>): OgImageRuntimeConfig;
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
+
import { useRuntimeConfig } from "nuxt/server";
|
|
1
2
|
import { joinURL } from "ufo";
|
|
2
|
-
import { useRuntimeConfig } from "#nuxtseo/nitro";
|
|
3
3
|
import { componentNames } from "#og-image-virtual/component-names.mjs";
|
|
4
4
|
import { buildOgImageUrl } from "../shared.js";
|
|
5
|
-
import { getCloudflareEnv } from "./util/cloudflare.js";
|
|
6
5
|
export function getOgImagePath(event, _pagePath, _options) {
|
|
7
|
-
const baseURL = useRuntimeConfig(
|
|
6
|
+
const baseURL = useRuntimeConfig().app.baseURL;
|
|
8
7
|
const { defaults, security } = useOgImageRuntimeConfig(event);
|
|
9
8
|
const extension = _options?.extension || defaults.extension;
|
|
10
9
|
const isStatic = import.meta.prerender && !(security?.secret && security?.strict);
|
|
@@ -20,15 +19,11 @@ export function getOgImagePath(event, _pagePath, _options) {
|
|
|
20
19
|
};
|
|
21
20
|
}
|
|
22
21
|
export function useOgImageRuntimeConfig(e) {
|
|
23
|
-
const c = useRuntimeConfig(
|
|
22
|
+
const c = useRuntimeConfig();
|
|
24
23
|
const moduleCfg = c["nuxt-og-image"];
|
|
25
|
-
const
|
|
26
|
-
const
|
|
27
|
-
const cloudflareSecret = cloudflareEnv?.NUXT_OG_IMAGE_SECRET;
|
|
28
|
-
const overrideSecret = typeof runtimeSecret === "string" && runtimeSecret ? runtimeSecret : typeof cloudflareSecret === "string" ? cloudflareSecret : void 0;
|
|
29
|
-
const security = overrideSecret ? { ...moduleCfg.security || {}, secret: overrideSecret } : moduleCfg.security;
|
|
24
|
+
const secret = e?.context._ogImageSigningSecret;
|
|
25
|
+
const security = secret ? { ...moduleCfg.security, secret } : moduleCfg.security;
|
|
30
26
|
return {
|
|
31
|
-
defaults: {},
|
|
32
27
|
...moduleCfg,
|
|
33
28
|
security,
|
|
34
29
|
app: {
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
interface PublishConfig {
|
|
2
|
+
storage: string;
|
|
3
|
+
baseURL: string;
|
|
4
|
+
}
|
|
5
|
+
export declare function parsePublishConfig(input: unknown): {
|
|
6
|
+
_tag: 'Ok';
|
|
7
|
+
value: PublishConfig;
|
|
8
|
+
} | {
|
|
9
|
+
_tag: 'Err';
|
|
10
|
+
reason: string;
|
|
11
|
+
};
|
|
12
|
+
export declare function hasPublishMount(mount: string, storage: Record<string, unknown>): boolean;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { normalizeKey } from "unstorage";
|
|
2
|
+
export function parsePublishConfig(input) {
|
|
3
|
+
if (!input || typeof input !== "object")
|
|
4
|
+
return { _tag: "Err", reason: "Set publish.storage and publish.baseURL." };
|
|
5
|
+
const config = input;
|
|
6
|
+
if (typeof config.storage !== "string" || !config.storage.trim() || !normalizeKey(config.storage))
|
|
7
|
+
return { _tag: "Err", reason: "Set publish.storage to a Nitro storage mount name." };
|
|
8
|
+
if (typeof config.baseURL !== "string" || !URL.canParse(config.baseURL))
|
|
9
|
+
return { _tag: "Err", reason: "Set publish.baseURL to the public HTTP URL for uploaded images." };
|
|
10
|
+
const url = new URL(config.baseURL);
|
|
11
|
+
if (!["https:", "http:"].includes(url.protocol) || url.username || url.password || url.href.includes("?") || url.href.includes("#"))
|
|
12
|
+
return { _tag: "Err", reason: "Set publish.baseURL to an HTTP URL without credentials, query, or fragment." };
|
|
13
|
+
return { _tag: "Ok", value: { storage: normalizeKey(config.storage), baseURL: url.href.replace(/\/+$/, "") } };
|
|
14
|
+
}
|
|
15
|
+
export function hasPublishMount(mount, storage) {
|
|
16
|
+
return Object.keys(storage).some((key) => normalizeKey(key) === normalizeKey(mount));
|
|
17
|
+
}
|
|
@@ -9,6 +9,8 @@ const RE_UNDERSCORE = /_/g;
|
|
|
9
9
|
const RE_DOUBLE_UNDERSCORE = /__/g;
|
|
10
10
|
const RE_PERCENT20 = /%20/g;
|
|
11
11
|
const RE_PLUS = /\+/g;
|
|
12
|
+
const RE_ENCODED_COMMA = /%2c/gi;
|
|
13
|
+
const RE_ENCODED_PLUS = /%2b/gi;
|
|
12
14
|
const RE_SINGLE_UNDERSCORE = /(?<!_)_(?!_)/;
|
|
13
15
|
const RE_OG_PATH_PREFIX = /^\/_og\/[ds]\//;
|
|
14
16
|
const RE_OG_ROUTE_PREFIX = /\/_og\/[ds]\//;
|
|
@@ -263,9 +265,12 @@ export function buildOgImageUrl(options, extension = "png", isStatic = false, de
|
|
|
263
265
|
const segment = encoded || "default";
|
|
264
266
|
const signed = secret && !isStatic ? `${segment},s_${signEncodedParams(segment, secret)}` : segment;
|
|
265
267
|
return {
|
|
266
|
-
url: `${prefix}/${signed}.${extension}`
|
|
268
|
+
url: `${prefix}/${signed.replace(/,/g, "%2C").replace(RE_PLUS, "%2B")}.${extension}`
|
|
267
269
|
};
|
|
268
270
|
}
|
|
271
|
+
function normalizeUrlSegment(segment) {
|
|
272
|
+
return segment.replace(RE_ENCODED_COMMA, ",").replace(RE_ENCODED_PLUS, "+");
|
|
273
|
+
}
|
|
269
274
|
export function signEncodedParams(encoded, secret) {
|
|
270
275
|
return digest(`${secret}:${encoded}`).slice(0, 16);
|
|
271
276
|
}
|
|
@@ -283,7 +288,7 @@ export function parseOgImageUrl(url) {
|
|
|
283
288
|
const path = url.replace(RE_OG_PATH_PREFIX, "");
|
|
284
289
|
const extMatch = path.match(RE_FILE_EXTENSION_WITH_CAPTURE);
|
|
285
290
|
const extension = extMatch?.[1] || "png";
|
|
286
|
-
const encoded = path.replace(RE_FILE_EXTENSION, "");
|
|
291
|
+
const encoded = normalizeUrlSegment(path.replace(RE_FILE_EXTENSION, ""));
|
|
287
292
|
const hashMatch = encoded.match(RE_HASH_SEGMENT);
|
|
288
293
|
if (hashMatch) {
|
|
289
294
|
return {
|
|
@@ -303,7 +308,7 @@ export function parseOgImageUrl(url) {
|
|
|
303
308
|
export function extractEncodedSegment(path, extension) {
|
|
304
309
|
const match = path.match(RE_OG_ROUTE_PREFIX);
|
|
305
310
|
if (match?.index != null) {
|
|
306
|
-
return path.slice(match.index + match[0].length).replace(new RegExp(`\\.${extension}$`), "");
|
|
311
|
+
return normalizeUrlSegment(path.slice(match.index + match[0].length).replace(new RegExp(`\\.${extension}$`), ""));
|
|
307
312
|
}
|
|
308
|
-
return path.split("/").pop().replace(new RegExp(`\\.${extension}$`), "");
|
|
313
|
+
return normalizeUrlSegment(path.split("/").pop().replace(new RegExp(`\\.${extension}$`), ""));
|
|
309
314
|
}
|
package/dist/runtime/types.d.ts
CHANGED
|
@@ -41,16 +41,21 @@ export interface OgImageRuntimeConfig {
|
|
|
41
41
|
debug: boolean;
|
|
42
42
|
/** Whether twitter:* meta tags are emitted alongside og:image tags */
|
|
43
43
|
includeTwitter: boolean;
|
|
44
|
-
baseCacheKey: string;
|
|
44
|
+
baseCacheKey: string | false;
|
|
45
45
|
hasNuxtIcon: boolean;
|
|
46
46
|
hasNuxtContent?: boolean;
|
|
47
47
|
colorPreference: 'light' | 'dark';
|
|
48
|
-
isNuxtContentDocumentDriven: boolean;
|
|
49
48
|
zeroRuntime: boolean;
|
|
50
49
|
cssFramework: 'tailwind' | 'unocss' | 'none';
|
|
51
50
|
componentDirs?: string[];
|
|
52
51
|
/** Directory for persistent build cache (CI caching) */
|
|
53
52
|
buildCacheDir?: string;
|
|
53
|
+
/** Publish rendered images to a public storage mount. */
|
|
54
|
+
publish?: {
|
|
55
|
+
storage: string;
|
|
56
|
+
baseURL: string;
|
|
57
|
+
cacheVersion: string;
|
|
58
|
+
};
|
|
54
59
|
/** Source directory for auto-eject (dev only) */
|
|
55
60
|
srcDir?: string;
|
|
56
61
|
/** Root directory for relative path display (dev only) */
|
|
@@ -69,7 +74,7 @@ export interface OgImageRuntimeConfig {
|
|
|
69
74
|
imageFetchTimeout: number;
|
|
70
75
|
maxQueryParamSize: number | null;
|
|
71
76
|
restrictRuntimeImagesToOrigin: false | string[];
|
|
72
|
-
secret: string;
|
|
77
|
+
secret: string | false;
|
|
73
78
|
strict: boolean;
|
|
74
79
|
};
|
|
75
80
|
app: {
|
|
@@ -164,15 +169,6 @@ export interface OgImageOptions {
|
|
|
164
169
|
src: string;
|
|
165
170
|
data: ArrayBuffer | Uint8Array;
|
|
166
171
|
}>;
|
|
167
|
-
fetchedResources?: Array<{
|
|
168
|
-
src: string;
|
|
169
|
-
data: ArrayBuffer | Uint8Array;
|
|
170
|
-
}>;
|
|
171
|
-
/** @deprecated Use `images` instead. */
|
|
172
|
-
persistentImages?: Array<{
|
|
173
|
-
src: string;
|
|
174
|
-
data: ArrayBuffer;
|
|
175
|
-
}>;
|
|
176
172
|
devicePixelRatio?: number;
|
|
177
173
|
};
|
|
178
174
|
/** @deprecated Legacy font override — no longer used at runtime */
|
|
@@ -208,6 +204,8 @@ export interface OgImageOptions {
|
|
|
208
204
|
* Extends OgImageOptions with fields set by defineOgImage() and the module internals.
|
|
209
205
|
*/
|
|
210
206
|
export interface OgImageOptionsInternal extends OgImageOptions {
|
|
207
|
+
/** Completed page content supplied during prerender publishing. */
|
|
208
|
+
_prerenderHtml?: string;
|
|
211
209
|
/** Set by defineOgImage() — the resolved component PascalName */
|
|
212
210
|
component?: string;
|
|
213
211
|
/** Determined by component filename suffix (.satori.vue, .takumi.vue, .browser.vue) */
|
|
@@ -246,10 +244,7 @@ export interface RuntimeCompatibilitySchema {
|
|
|
246
244
|
fetch?: 'node' | 'web';
|
|
247
245
|
wasm?: any;
|
|
248
246
|
}
|
|
249
|
-
export
|
|
250
|
-
takumiVersion?: 1 | 2;
|
|
251
|
-
}
|
|
252
|
-
export type RuntimeCompatibilityPayload = Partial<Omit<RuntimeCompatibilitySchema, 'wasm'>> & RuntimeCompatibilityMeta;
|
|
247
|
+
export type RuntimeCompatibilityPayload = Partial<Omit<RuntimeCompatibilitySchema, 'wasm'>>;
|
|
253
248
|
export type CompatibilityFlags = Partial<Omit<RuntimeCompatibilitySchema, 'wasm'>>;
|
|
254
249
|
export interface CompatibilityFlagEnvOverrides {
|
|
255
250
|
dev?: CompatibilityFlags;
|