nuxt-og-image 6.2.4 → 6.2.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/chunks/tw4.cjs +1 -1
- package/dist/chunks/tw4.mjs +1 -1
- package/dist/chunks/uno.cjs +1 -1
- package/dist/chunks/uno.mjs +1 -1
- package/dist/devtools/200.html +1 -1
- package/dist/devtools/404.html +1 -1
- package/dist/devtools/_nuxt/{B9YJLOLG.js → BXPqj_uX.js} +1 -1
- package/dist/devtools/_nuxt/Bo4lSgm2.js +3 -0
- package/dist/devtools/_nuxt/C9JKABtj.js +1 -0
- package/dist/devtools/_nuxt/CHHO6nw6.js +1 -0
- package/dist/devtools/_nuxt/DevtoolsSnippet.BaNDy_jv.css +1 -0
- package/dist/devtools/_nuxt/Dy0Vu_Hf.js +1 -0
- package/dist/devtools/_nuxt/aOrl9V8N.js +4 -0
- package/dist/devtools/_nuxt/builds/latest.json +1 -1
- package/dist/devtools/_nuxt/builds/meta/116b189e-4f49-45f9-b21c-dfb518abeb03.json +1 -0
- package/dist/devtools/_nuxt/entry.DgipzMgL.css +2 -0
- package/dist/devtools/_nuxt/iJA-9P1Z.js +2 -0
- package/dist/devtools/_nuxt/jJVhk0xb.js +174 -0
- package/dist/devtools/_nuxt/pages.DyP4FhjX.css +1 -0
- package/dist/devtools/debug/index.html +1 -1
- package/dist/devtools/docs/index.html +1 -1
- package/dist/devtools/index.html +1 -1
- package/dist/devtools/templates/index.html +1 -1
- package/dist/module.cjs +1 -1
- package/dist/module.d.cts +33 -0
- package/dist/module.d.mts +33 -0
- package/dist/module.d.ts +33 -0
- package/dist/module.json +1 -1
- package/dist/module.mjs +1 -1
- package/dist/runtime/server/og-image/context.d.ts +1 -1
- package/dist/runtime/server/og-image/context.js +41 -5
- package/dist/runtime/server/og-image/core/plugins/imageSrc.js +73 -12
- package/dist/runtime/server/og-image/takumi/renderer.js +5 -3
- package/dist/runtime/server/util/eventHandlers.js +34 -3
- package/dist/runtime/shared.d.ts +5 -0
- package/dist/runtime/shared.js +10 -0
- package/dist/runtime/types.d.ts +9 -0
- package/dist/shared/{nuxt-og-image.CvPWboEh.mjs → nuxt-og-image.CA6cPvTd.mjs} +48 -3
- package/dist/shared/{nuxt-og-image.Ni0_6XZ0.cjs → nuxt-og-image.DVJetxwr.cjs} +49 -4
- package/package.json +5 -5
- package/dist/devtools/_nuxt/CGddsLij.js +0 -1
- package/dist/devtools/_nuxt/CNPcxXHG.js +0 -173
- package/dist/devtools/_nuxt/D84yDWKI.js +0 -1
- package/dist/devtools/_nuxt/DLPfJAyQ.js +0 -2
- package/dist/devtools/_nuxt/DevtoolsSection.a-2R---I.css +0 -1
- package/dist/devtools/_nuxt/DevtoolsSnippet.D9AS35aC.css +0 -1
- package/dist/devtools/_nuxt/Dy6LapUo.js +0 -4
- package/dist/devtools/_nuxt/Ll4Fy5iv.js +0 -3
- package/dist/devtools/_nuxt/builds/meta/05e8381a-ae36-4c96-9530-7973642e8e38.json +0 -1
- package/dist/devtools/_nuxt/entry._es5B19-.css +0 -2
- package/dist/devtools/_nuxt/pages.CcgChwrv.css +0 -1
- package/dist/devtools/_nuxt/u09lXEfj.js +0 -1
|
@@ -6,6 +6,56 @@ import { decodeHtml } from "../../../util/encoding.js";
|
|
|
6
6
|
import { logger } from "../../../util/logger.js";
|
|
7
7
|
import { getImageDimensions } from "../../utils/image-detector.js";
|
|
8
8
|
import { defineTransformer } from "../plugins.js";
|
|
9
|
+
const RE_IPV6_BRACKETS = /^\[|\]$/g;
|
|
10
|
+
const RE_MAPPED_V4 = /^::ffff:(\d+\.\d+\.\d+\.\d+)$/;
|
|
11
|
+
const RE_DIGIT_ONLY = /^\d+$/;
|
|
12
|
+
const RE_INT_IP = /^(?:0x[\da-f]+|\d+)$/i;
|
|
13
|
+
function isPrivateIPv4(a, b) {
|
|
14
|
+
if (a === 127)
|
|
15
|
+
return true;
|
|
16
|
+
if (a === 10)
|
|
17
|
+
return true;
|
|
18
|
+
if (a === 172 && b >= 16 && b <= 31)
|
|
19
|
+
return true;
|
|
20
|
+
if (a === 192 && b === 168)
|
|
21
|
+
return true;
|
|
22
|
+
if (a === 169 && b === 254)
|
|
23
|
+
return true;
|
|
24
|
+
if (a === 0)
|
|
25
|
+
return true;
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
function isBlockedUrl(url) {
|
|
29
|
+
let parsed;
|
|
30
|
+
try {
|
|
31
|
+
parsed = new URL(url);
|
|
32
|
+
} catch {
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:")
|
|
36
|
+
return true;
|
|
37
|
+
const hostname = parsed.hostname.toLowerCase();
|
|
38
|
+
const bare = hostname.replace(RE_IPV6_BRACKETS, "");
|
|
39
|
+
if (bare === "localhost" || bare.endsWith(".localhost"))
|
|
40
|
+
return true;
|
|
41
|
+
const mappedV4 = bare.match(RE_MAPPED_V4);
|
|
42
|
+
const ip = mappedV4 ? mappedV4[1] : bare;
|
|
43
|
+
const parts = ip.split(".");
|
|
44
|
+
if (parts.length === 4 && parts.every((p) => RE_DIGIT_ONLY.test(p))) {
|
|
45
|
+
const octets = parts.map(Number);
|
|
46
|
+
if (octets.some((o) => o > 255))
|
|
47
|
+
return true;
|
|
48
|
+
return isPrivateIPv4(octets[0], octets[1]);
|
|
49
|
+
}
|
|
50
|
+
if (RE_INT_IP.test(ip)) {
|
|
51
|
+
const num = Number(ip);
|
|
52
|
+
if (!Number.isNaN(num) && num >= 0 && num <= 4294967295)
|
|
53
|
+
return isPrivateIPv4(num >> 24 & 255, num >> 16 & 255);
|
|
54
|
+
}
|
|
55
|
+
if (bare === "::1" || bare.startsWith("fc") || bare.startsWith("fd") || bare.startsWith("fe80"))
|
|
56
|
+
return true;
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
9
59
|
const RE_URL_LEADING = /^url\(['"]?/;
|
|
10
60
|
const RE_URL_TRAILING = /['"]?\)$/;
|
|
11
61
|
async function resolveLocalFilePathImage(publicStoragePath, src) {
|
|
@@ -50,14 +100,19 @@ export default defineTransformer([
|
|
|
50
100
|
}
|
|
51
101
|
} else if (!src.startsWith("data:")) {
|
|
52
102
|
src = decodeHtml(src);
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
103
|
+
if (!import.meta.dev && isBlockedUrl(src)) {
|
|
104
|
+
logger.warn(`Blocked internal image fetch: ${src}`);
|
|
105
|
+
delete node.props.src;
|
|
106
|
+
} else {
|
|
107
|
+
node.props.src = src;
|
|
108
|
+
imageBuffer = await $fetch(src, {
|
|
109
|
+
responseType: "arrayBuffer"
|
|
110
|
+
}).catch(() => {
|
|
111
|
+
});
|
|
112
|
+
if (imageBuffer) {
|
|
113
|
+
const buffer = imageBuffer instanceof ArrayBuffer ? imageBuffer : imageBuffer.buffer;
|
|
114
|
+
node.props.src = toBase64Image(buffer);
|
|
115
|
+
}
|
|
61
116
|
}
|
|
62
117
|
}
|
|
63
118
|
if (typeof node.props.width === "string")
|
|
@@ -115,10 +170,16 @@ export default defineTransformer([
|
|
|
115
170
|
}
|
|
116
171
|
}
|
|
117
172
|
} else {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
173
|
+
const decodedSrc = decodeHtml(src);
|
|
174
|
+
if (!import.meta.dev && isBlockedUrl(decodedSrc)) {
|
|
175
|
+
logger.warn(`Blocked internal background-image fetch: ${decodedSrc}`);
|
|
176
|
+
delete node.props.style.backgroundImage;
|
|
177
|
+
} else {
|
|
178
|
+
imageBuffer = await $fetch(decodedSrc, {
|
|
179
|
+
responseType: "arrayBuffer"
|
|
180
|
+
}).catch(() => {
|
|
181
|
+
});
|
|
182
|
+
}
|
|
122
183
|
}
|
|
123
184
|
if (imageBuffer) {
|
|
124
185
|
const buffer = imageBuffer instanceof ArrayBuffer ? imageBuffer : imageBuffer.buffer;
|
|
@@ -102,10 +102,12 @@ async function createImage(event, format) {
|
|
|
102
102
|
}
|
|
103
103
|
}
|
|
104
104
|
}));
|
|
105
|
-
const
|
|
105
|
+
const maxDpr = event.runtimeConfig.security?.maxDpr || 2;
|
|
106
|
+
const maxDim = event.runtimeConfig.security?.maxDimension || 2048;
|
|
107
|
+
const dpr = Math.min(Math.max(1, options.takumi?.devicePixelRatio ?? 1), maxDpr);
|
|
106
108
|
const renderOptions = defu(options.takumi, {
|
|
107
|
-
width: Number(options.width) * dpr,
|
|
108
|
-
height: Number(options.height) * dpr,
|
|
109
|
+
width: Math.min(Number(options.width) * dpr, maxDim),
|
|
110
|
+
height: Math.min(Number(options.height) * dpr, maxDim),
|
|
109
111
|
format,
|
|
110
112
|
fetchedResources,
|
|
111
113
|
devicePixelRatio: dpr
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { getSiteConfig } from "#site-config/server/composables/getSiteConfig";
|
|
2
|
-
import { createError, H3Error, setHeader } from "h3";
|
|
2
|
+
import { createError, getRequestHost, H3Error, setHeader } from "h3";
|
|
3
3
|
import { logger } from "../../logger.js";
|
|
4
4
|
import { getBuildCachedImage, setBuildCachedImage } from "../og-image/cache/buildCache.js";
|
|
5
5
|
import { resolveContext } from "../og-image/context.js";
|
|
@@ -15,7 +15,24 @@ export async function imageEventHandler(e) {
|
|
|
15
15
|
if (ctx instanceof H3Error)
|
|
16
16
|
return ctx;
|
|
17
17
|
const { isDevToolsContextRequest, extension, renderer } = ctx;
|
|
18
|
-
const { debug, baseCacheKey } = useOgImageRuntimeConfig();
|
|
18
|
+
const { debug, baseCacheKey, security } = useOgImageRuntimeConfig();
|
|
19
|
+
if (!import.meta.prerender && !import.meta.dev && security?.restrictRuntimeImagesToOrigin) {
|
|
20
|
+
const siteHost = new URL(getSiteConfig(e).url).host;
|
|
21
|
+
const allowedHosts = [siteHost, ...security.restrictRuntimeImagesToOrigin.map((o) => {
|
|
22
|
+
try {
|
|
23
|
+
return new URL(o).host;
|
|
24
|
+
} catch {
|
|
25
|
+
return o;
|
|
26
|
+
}
|
|
27
|
+
})];
|
|
28
|
+
const requestHost = getRequestHost(e, { xForwardedHost: true });
|
|
29
|
+
if (!requestHost || !allowedHosts.includes(requestHost)) {
|
|
30
|
+
return createError({
|
|
31
|
+
statusCode: 403,
|
|
32
|
+
statusMessage: "[Nuxt OG Image] Host not allowed."
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
}
|
|
19
36
|
if ((import.meta.dev || debug) && isDevToolsContextRequest) {
|
|
20
37
|
setHeader(e, "Content-Type", "application/json");
|
|
21
38
|
const [extract, rendererDebug] = await Promise.all([
|
|
@@ -82,9 +99,23 @@ export async function imageEventHandler(e) {
|
|
|
82
99
|
return cacheApi;
|
|
83
100
|
let image = cacheApi.cachedItem;
|
|
84
101
|
if (!image) {
|
|
85
|
-
|
|
102
|
+
const { security: security2 } = useOgImageRuntimeConfig();
|
|
103
|
+
const timeout = security2?.renderTimeout || 15e3;
|
|
104
|
+
let timer;
|
|
105
|
+
image = await Promise.race([
|
|
106
|
+
renderer.createImage(ctx),
|
|
107
|
+
new Promise((_, reject) => {
|
|
108
|
+
timer = setTimeout(() => reject(new Error(`OG image render timed out after ${timeout}ms`)), timeout);
|
|
109
|
+
})
|
|
110
|
+
]).catch((err) => {
|
|
111
|
+
if (err?.message?.includes("timed out")) {
|
|
112
|
+
logger.error(`renderer.createImage timeout for ${e.path}`);
|
|
113
|
+
return createError({ statusCode: 408, statusMessage: `[Nuxt OG Image] Request timed out while waiting for OG image render.` });
|
|
114
|
+
}
|
|
86
115
|
logger.error(`renderer.createImage error for ${e.path}:`, err?.stack || err?.message || err);
|
|
87
116
|
throw err;
|
|
117
|
+
}).finally(() => {
|
|
118
|
+
clearTimeout(timer);
|
|
88
119
|
});
|
|
89
120
|
if (image instanceof H3Error)
|
|
90
121
|
return image;
|
package/dist/runtime/shared.d.ts
CHANGED
|
@@ -5,5 +5,10 @@ export { buildOgImageUrl, decodeOgImageParams, encodeOgImageParams, extractEncod
|
|
|
5
5
|
export declare function generateMeta(url: OgImagePrebuilt['url'] | string, resolvedOptions: OgImageOptions | OgImagePrebuilt): ResolvableMeta[];
|
|
6
6
|
export declare function isInternalRoute(path: string): boolean;
|
|
7
7
|
export declare function separateProps(options: OgImageOptions | undefined, ignoreKeys?: string[]): OgImageOptions;
|
|
8
|
+
/**
|
|
9
|
+
* Strip HTML event handlers and dangerous attributes from props to prevent
|
|
10
|
+
* reflected XSS via Vue fallthrough attributes (GHSA-mg36-wvcr-m75h).
|
|
11
|
+
*/
|
|
12
|
+
export declare function sanitizeProps(props: Record<string, any>): Record<string, any>;
|
|
8
13
|
export declare function withoutQuery(path: string): string | undefined;
|
|
9
14
|
export declare function getExtension(path: string): string;
|
package/dist/runtime/shared.js
CHANGED
|
@@ -82,6 +82,16 @@ export function separateProps(options, ignoreKeys = []) {
|
|
|
82
82
|
result.props = props;
|
|
83
83
|
return result;
|
|
84
84
|
}
|
|
85
|
+
const DANGEROUS_ATTRS = /* @__PURE__ */ new Set(["autofocus", "contenteditable", "tabindex", "accesskey"]);
|
|
86
|
+
export function sanitizeProps(props) {
|
|
87
|
+
const clean = {};
|
|
88
|
+
for (const key of Object.keys(props)) {
|
|
89
|
+
if (key.startsWith("on") || DANGEROUS_ATTRS.has(key.toLowerCase()))
|
|
90
|
+
continue;
|
|
91
|
+
clean[key] = props[key];
|
|
92
|
+
}
|
|
93
|
+
return clean;
|
|
94
|
+
}
|
|
85
95
|
export function withoutQuery(path) {
|
|
86
96
|
return path.split("?")[0];
|
|
87
97
|
}
|
package/dist/runtime/types.d.ts
CHANGED
|
@@ -54,6 +54,13 @@ export interface OgImageRuntimeConfig {
|
|
|
54
54
|
provider?: BrowserProvider;
|
|
55
55
|
binding?: string;
|
|
56
56
|
};
|
|
57
|
+
security: {
|
|
58
|
+
maxDimension: number;
|
|
59
|
+
maxDpr: number;
|
|
60
|
+
renderTimeout: number;
|
|
61
|
+
maxQueryParamSize: number | null;
|
|
62
|
+
restrictRuntimeImagesToOrigin: false | string[];
|
|
63
|
+
};
|
|
57
64
|
app: {
|
|
58
65
|
baseURL: string;
|
|
59
66
|
};
|
|
@@ -73,6 +80,8 @@ export interface OgImageComponent {
|
|
|
73
80
|
category: 'app' | 'community' | 'pro';
|
|
74
81
|
credits?: string;
|
|
75
82
|
renderer: RendererType;
|
|
83
|
+
/** Declared prop names extracted from defineProps at build time (used for prop whitelisting) */
|
|
84
|
+
propNames?: string[];
|
|
76
85
|
}
|
|
77
86
|
export interface ScreenshotOptions {
|
|
78
87
|
colorScheme?: 'dark' | 'light';
|
|
@@ -2215,6 +2215,36 @@ function setupPrerenderHandler(options, resolve, getDetectedRenderers, nuxt = us
|
|
|
2215
2215
|
});
|
|
2216
2216
|
}
|
|
2217
2217
|
|
|
2218
|
+
let _parse;
|
|
2219
|
+
let _compileScript;
|
|
2220
|
+
async function loadSfcCompiler() {
|
|
2221
|
+
if (!_parse) {
|
|
2222
|
+
const sfc = await import('@vue/compiler-sfc');
|
|
2223
|
+
_parse = sfc.parse;
|
|
2224
|
+
_compileScript = sfc.compileScript;
|
|
2225
|
+
}
|
|
2226
|
+
}
|
|
2227
|
+
function extractPropNamesFromVue(code) {
|
|
2228
|
+
if (!_parse || !_compileScript)
|
|
2229
|
+
return [];
|
|
2230
|
+
let descriptor;
|
|
2231
|
+
try {
|
|
2232
|
+
descriptor = _parse(code).descriptor;
|
|
2233
|
+
} catch {
|
|
2234
|
+
return [];
|
|
2235
|
+
}
|
|
2236
|
+
if (!descriptor.scriptSetup)
|
|
2237
|
+
return [];
|
|
2238
|
+
try {
|
|
2239
|
+
const compiled = _compileScript(descriptor, { id: "prop-extract" });
|
|
2240
|
+
if (!compiled.bindings)
|
|
2241
|
+
return [];
|
|
2242
|
+
return Object.entries(compiled.bindings).filter(([, type]) => type === "props").map(([name]) => name);
|
|
2243
|
+
} catch {
|
|
2244
|
+
return [];
|
|
2245
|
+
}
|
|
2246
|
+
}
|
|
2247
|
+
|
|
2218
2248
|
function isVue(id, opts = {}) {
|
|
2219
2249
|
const { search } = parseURL(decodeURIComponent(pathToFileURL(id).href));
|
|
2220
2250
|
if (id.endsWith(".vue") && !search) {
|
|
@@ -4123,6 +4153,9 @@ const module$1 = defineNuxtModule({
|
|
|
4123
4153
|
logger.warn("Nuxt OG Image is enabled but SSR is disabled.\n\nYou should enable SSR (`ssr: true`) or disable the module (`ogImage: { enabled: false }`).");
|
|
4124
4154
|
return;
|
|
4125
4155
|
}
|
|
4156
|
+
if (config.debug && !nuxt.options.dev) {
|
|
4157
|
+
logger.warn("`ogImage.debug` is enabled in production. This exposes the `/_og/debug.json` endpoint and should not be enabled in production. Disable it before deploying.");
|
|
4158
|
+
}
|
|
4126
4159
|
const ogImageConfig = config;
|
|
4127
4160
|
for (const key of Object.keys(REMOVED_CONFIG)) {
|
|
4128
4161
|
if (key !== "chromium-node" && key !== "browser-node" && key in ogImageConfig && ogImageConfig[key] !== void 0) {
|
|
@@ -4652,6 +4685,7 @@ ${familyInfo}`);
|
|
|
4652
4685
|
});
|
|
4653
4686
|
}
|
|
4654
4687
|
}
|
|
4688
|
+
await loadSfcCompiler();
|
|
4655
4689
|
nuxt.hook("components:extend", (components) => {
|
|
4656
4690
|
allNuxtComponents = components;
|
|
4657
4691
|
ogImageComponentCtx.components = [];
|
|
@@ -4682,6 +4716,7 @@ ${familyInfo}`);
|
|
|
4682
4716
|
ogImageComponentCtx.detectedRenderers.add(renderer);
|
|
4683
4717
|
const componentFile = fs.readFileSync(component.filePath, "utf-8");
|
|
4684
4718
|
const credits = componentFile.split("\n").find((line) => line.startsWith(" * @credits"))?.replace("* @credits", "").trim();
|
|
4719
|
+
const propNames = extractPropNamesFromVue(componentFile);
|
|
4685
4720
|
ogImageComponentCtx.components.push({
|
|
4686
4721
|
hash: hash(componentFile).replaceAll("_", "-"),
|
|
4687
4722
|
pascalName: component.pascalName,
|
|
@@ -4689,7 +4724,8 @@ ${familyInfo}`);
|
|
|
4689
4724
|
path: component.filePath,
|
|
4690
4725
|
category,
|
|
4691
4726
|
credits,
|
|
4692
|
-
renderer
|
|
4727
|
+
renderer,
|
|
4728
|
+
propNames
|
|
4693
4729
|
});
|
|
4694
4730
|
}
|
|
4695
4731
|
});
|
|
@@ -4713,13 +4749,15 @@ ${familyInfo}`);
|
|
|
4713
4749
|
})) {
|
|
4714
4750
|
return;
|
|
4715
4751
|
}
|
|
4752
|
+
const propNames = fs.statSync(filePath).isFile() ? extractPropNamesFromVue(fs.readFileSync(filePath, "utf-8")) : [];
|
|
4716
4753
|
ogImageComponentCtx.components.push({
|
|
4717
4754
|
hash: "",
|
|
4718
4755
|
pascalName,
|
|
4719
4756
|
kebabName: pascalName.replace(RE_PASCAL_TO_KEBAB, "$1-$2").toLowerCase(),
|
|
4720
4757
|
path: filePath,
|
|
4721
4758
|
category: "community",
|
|
4722
|
-
renderer
|
|
4759
|
+
renderer,
|
|
4760
|
+
propNames
|
|
4723
4761
|
});
|
|
4724
4762
|
});
|
|
4725
4763
|
}
|
|
@@ -4958,7 +4996,14 @@ export const rootDir = ${JSON.stringify(nuxt.options.rootDir)}`;
|
|
|
4958
4996
|
browser: typeof config.browser === "object" ? {
|
|
4959
4997
|
provider: config.browser.provider,
|
|
4960
4998
|
binding: config.browser.binding
|
|
4961
|
-
} : void 0
|
|
4999
|
+
} : void 0,
|
|
5000
|
+
security: {
|
|
5001
|
+
maxDimension: config.security?.maxDimension ?? 2048,
|
|
5002
|
+
maxDpr: config.security?.maxDpr ?? 2,
|
|
5003
|
+
renderTimeout: config.security?.renderTimeout ?? 15e3,
|
|
5004
|
+
maxQueryParamSize: config.security?.maxQueryParamSize ?? null,
|
|
5005
|
+
restrictRuntimeImagesToOrigin: config.security?.restrictRuntimeImagesToOrigin === true ? [] : config.security?.restrictRuntimeImagesToOrigin || false
|
|
5006
|
+
}
|
|
4962
5007
|
};
|
|
4963
5008
|
if (nuxt.options.dev) {
|
|
4964
5009
|
runtimeConfig.componentDirs = config.componentDirs;
|
|
@@ -2235,6 +2235,36 @@ function setupPrerenderHandler(options, resolve, getDetectedRenderers, nuxt = ki
|
|
|
2235
2235
|
});
|
|
2236
2236
|
}
|
|
2237
2237
|
|
|
2238
|
+
let _parse;
|
|
2239
|
+
let _compileScript;
|
|
2240
|
+
async function loadSfcCompiler() {
|
|
2241
|
+
if (!_parse) {
|
|
2242
|
+
const sfc = await import('@vue/compiler-sfc');
|
|
2243
|
+
_parse = sfc.parse;
|
|
2244
|
+
_compileScript = sfc.compileScript;
|
|
2245
|
+
}
|
|
2246
|
+
}
|
|
2247
|
+
function extractPropNamesFromVue(code) {
|
|
2248
|
+
if (!_parse || !_compileScript)
|
|
2249
|
+
return [];
|
|
2250
|
+
let descriptor;
|
|
2251
|
+
try {
|
|
2252
|
+
descriptor = _parse(code).descriptor;
|
|
2253
|
+
} catch {
|
|
2254
|
+
return [];
|
|
2255
|
+
}
|
|
2256
|
+
if (!descriptor.scriptSetup)
|
|
2257
|
+
return [];
|
|
2258
|
+
try {
|
|
2259
|
+
const compiled = _compileScript(descriptor, { id: "prop-extract" });
|
|
2260
|
+
if (!compiled.bindings)
|
|
2261
|
+
return [];
|
|
2262
|
+
return Object.entries(compiled.bindings).filter(([, type]) => type === "props").map(([name]) => name);
|
|
2263
|
+
} catch {
|
|
2264
|
+
return [];
|
|
2265
|
+
}
|
|
2266
|
+
}
|
|
2267
|
+
|
|
2238
2268
|
function isVue(id, opts = {}) {
|
|
2239
2269
|
const { search } = ufo.parseURL(decodeURIComponent(node_url.pathToFileURL(id).href));
|
|
2240
2270
|
if (id.endsWith(".vue") && !search) {
|
|
@@ -4113,7 +4143,7 @@ const module$1 = kit.defineNuxtModule({
|
|
|
4113
4143
|
await onUpgrade(nuxt, options, previousVersion);
|
|
4114
4144
|
},
|
|
4115
4145
|
async setup(config, nuxt) {
|
|
4116
|
-
const _resolver = kit.createResolver((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('shared/nuxt-og-image.
|
|
4146
|
+
const _resolver = kit.createResolver((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('shared/nuxt-og-image.DVJetxwr.cjs', document.baseURI).href)));
|
|
4117
4147
|
const fixSharedPath = (p) => {
|
|
4118
4148
|
if (p.includes("/shared/runtime/"))
|
|
4119
4149
|
return p.replace("/shared/runtime/", "/runtime/");
|
|
@@ -4143,6 +4173,9 @@ const module$1 = kit.defineNuxtModule({
|
|
|
4143
4173
|
logger_js.logger.warn("Nuxt OG Image is enabled but SSR is disabled.\n\nYou should enable SSR (`ssr: true`) or disable the module (`ogImage: { enabled: false }`).");
|
|
4144
4174
|
return;
|
|
4145
4175
|
}
|
|
4176
|
+
if (config.debug && !nuxt.options.dev) {
|
|
4177
|
+
logger_js.logger.warn("`ogImage.debug` is enabled in production. This exposes the `/_og/debug.json` endpoint and should not be enabled in production. Disable it before deploying.");
|
|
4178
|
+
}
|
|
4146
4179
|
const ogImageConfig = config;
|
|
4147
4180
|
for (const key of Object.keys(REMOVED_CONFIG)) {
|
|
4148
4181
|
if (key !== "chromium-node" && key !== "browser-node" && key in ogImageConfig && ogImageConfig[key] !== void 0) {
|
|
@@ -4672,6 +4705,7 @@ ${familyInfo}`);
|
|
|
4672
4705
|
});
|
|
4673
4706
|
}
|
|
4674
4707
|
}
|
|
4708
|
+
await loadSfcCompiler();
|
|
4675
4709
|
nuxt.hook("components:extend", (components) => {
|
|
4676
4710
|
allNuxtComponents = components;
|
|
4677
4711
|
ogImageComponentCtx.components = [];
|
|
@@ -4702,6 +4736,7 @@ ${familyInfo}`);
|
|
|
4702
4736
|
ogImageComponentCtx.detectedRenderers.add(renderer);
|
|
4703
4737
|
const componentFile = fs__namespace.readFileSync(component.filePath, "utf-8");
|
|
4704
4738
|
const credits = componentFile.split("\n").find((line) => line.startsWith(" * @credits"))?.replace("* @credits", "").trim();
|
|
4739
|
+
const propNames = extractPropNamesFromVue(componentFile);
|
|
4705
4740
|
ogImageComponentCtx.components.push({
|
|
4706
4741
|
hash: ohash.hash(componentFile).replaceAll("_", "-"),
|
|
4707
4742
|
pascalName: component.pascalName,
|
|
@@ -4709,7 +4744,8 @@ ${familyInfo}`);
|
|
|
4709
4744
|
path: component.filePath,
|
|
4710
4745
|
category,
|
|
4711
4746
|
credits,
|
|
4712
|
-
renderer
|
|
4747
|
+
renderer,
|
|
4748
|
+
propNames
|
|
4713
4749
|
});
|
|
4714
4750
|
}
|
|
4715
4751
|
});
|
|
@@ -4733,13 +4769,15 @@ ${familyInfo}`);
|
|
|
4733
4769
|
})) {
|
|
4734
4770
|
return;
|
|
4735
4771
|
}
|
|
4772
|
+
const propNames = fs__namespace.statSync(filePath).isFile() ? extractPropNamesFromVue(fs__namespace.readFileSync(filePath, "utf-8")) : [];
|
|
4736
4773
|
ogImageComponentCtx.components.push({
|
|
4737
4774
|
hash: "",
|
|
4738
4775
|
pascalName,
|
|
4739
4776
|
kebabName: pascalName.replace(RE_PASCAL_TO_KEBAB, "$1-$2").toLowerCase(),
|
|
4740
4777
|
path: filePath,
|
|
4741
4778
|
category: "community",
|
|
4742
|
-
renderer
|
|
4779
|
+
renderer,
|
|
4780
|
+
propNames
|
|
4743
4781
|
});
|
|
4744
4782
|
});
|
|
4745
4783
|
}
|
|
@@ -4978,7 +5016,14 @@ export const rootDir = ${JSON.stringify(nuxt.options.rootDir)}`;
|
|
|
4978
5016
|
browser: typeof config.browser === "object" ? {
|
|
4979
5017
|
provider: config.browser.provider,
|
|
4980
5018
|
binding: config.browser.binding
|
|
4981
|
-
} : void 0
|
|
5019
|
+
} : void 0,
|
|
5020
|
+
security: {
|
|
5021
|
+
maxDimension: config.security?.maxDimension ?? 2048,
|
|
5022
|
+
maxDpr: config.security?.maxDpr ?? 2,
|
|
5023
|
+
renderTimeout: config.security?.renderTimeout ?? 15e3,
|
|
5024
|
+
maxQueryParamSize: config.security?.maxQueryParamSize ?? null,
|
|
5025
|
+
restrictRuntimeImagesToOrigin: config.security?.restrictRuntimeImagesToOrigin === true ? [] : config.security?.restrictRuntimeImagesToOrigin || false
|
|
5026
|
+
}
|
|
4982
5027
|
};
|
|
4983
5028
|
if (nuxt.options.dev) {
|
|
4984
5029
|
runtimeConfig.componentDirs = config.componentDirs;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nuxt-og-image",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "6.2.
|
|
4
|
+
"version": "6.2.6",
|
|
5
5
|
"description": "Enlightened OG Image generation for Nuxt.",
|
|
6
6
|
"author": {
|
|
7
7
|
"website": "https://harlanzw.com",
|
|
@@ -108,9 +108,9 @@
|
|
|
108
108
|
"magic-string": "^0.30.21",
|
|
109
109
|
"magicast": "^0.5.2",
|
|
110
110
|
"mocked-exports": "^0.1.1",
|
|
111
|
-
"nuxt-site-config": "^4.0.
|
|
112
|
-
"nuxtseo-layer-devtools": "^0.
|
|
113
|
-
"nuxtseo-shared": "^0.
|
|
111
|
+
"nuxt-site-config": "^4.0.7",
|
|
112
|
+
"nuxtseo-layer-devtools": "^5.0.1",
|
|
113
|
+
"nuxtseo-shared": "^5.0.1",
|
|
114
114
|
"nypm": "^0.6.5",
|
|
115
115
|
"ofetch": "^1.5.1",
|
|
116
116
|
"ohash": "^2.0.11",
|
|
@@ -178,7 +178,7 @@
|
|
|
178
178
|
"typescript": "^6.0.2",
|
|
179
179
|
"unifont": "^0.7.4",
|
|
180
180
|
"unocss": "^66.6.7",
|
|
181
|
-
"vitest": "^4.1.
|
|
181
|
+
"vitest": "^4.1.2",
|
|
182
182
|
"vue-tsc": "^3.2.6",
|
|
183
183
|
"wrangler": "^4.77.0",
|
|
184
184
|
"yoga-wasm-web": "^0.3.3"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{C as e,Ot as t,T as n,Tt as r,U as i,_ as a,at as o,g as s,h as c,jt as l,q as u,v as d,y as f}from"./D2zWjF09.js";import{bt as p,v as m}from"./Co3OAyKc.js";import{a as h,d as g,n as _}from"#entry";function v(e=2e3){let{copy:t,copied:n}=p({legacy:!0,copiedDuring:e});return{copy:t,copied:n}}var y=Object.assign(n({__name:`DevtoolsCopyButton`,props:{text:{}},setup(n){let{copy:s,copied:c}=v();return(l,u)=>{let d=h,f=m;return i(),a(f,{text:r(c)?`Copied!`:`Copy`},{default:o(()=>[e(d,{icon:r(c)?`carbon:checkmark`:`carbon:copy`,"aria-label":r(c)?`Copied`:`Copy to clipboard`,class:t(r(c)?`text-[var(--seo-green)]`:``),onClick:u[0]||=e=>r(s)(n.text)},null,8,[`icon`,`aria-label`,`class`])]),_:1},8,[`text`])}}}),{__name:`DevtoolsCopyButton`}),b=[`innerHTML`],x=Object.assign(n({__name:`OCodeBlock`,props:{code:{},lang:{},lines:{type:Boolean,default:!1},transformRendered:{type:Function}},setup(e){let n=c(()=>{let t=_(e.code,e.lang);return e.transformRendered?e.transformRendered(t.value||``):t.value});return(a,o)=>(i(),f(`pre`,{class:t([`code-block p-5`,e.lines?`code-block-lines`:``]),innerHTML:r(n)},null,10,b))}}),{__name:`OCodeBlock`}),S={class:`devtools-snippet`},C={key:0,class:`devtools-snippet-header`},w={class:`devtools-snippet-label`},T=Object.assign(g(n({__name:`DevtoolsSnippet`,props:{label:{},code:{},lang:{default:`js`}},setup(t){return(n,r)=>{let a=y,o=x;return i(),f(`div`,S,[t.label||n.$slots.header?(i(),f(`div`,C,[u(n.$slots,`header`,{},()=>[s(`code`,w,l(t.label),1)],!0),e(a,{text:t.code},null,8,[`text`])])):d(``,!0),e(o,{code:t.code,lang:t.lang,class:`devtools-snippet-block`},null,8,[`code`,`lang`])])}}}),[[`__scopeId`,`data-v-a6534a8f`]]),{__name:`DevtoolsSnippet`});export{T as t};
|