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.
Files changed (52) hide show
  1. package/dist/chunks/tw4.cjs +1 -1
  2. package/dist/chunks/tw4.mjs +1 -1
  3. package/dist/chunks/uno.cjs +1 -1
  4. package/dist/chunks/uno.mjs +1 -1
  5. package/dist/devtools/200.html +1 -1
  6. package/dist/devtools/404.html +1 -1
  7. package/dist/devtools/_nuxt/{B9YJLOLG.js → BXPqj_uX.js} +1 -1
  8. package/dist/devtools/_nuxt/Bo4lSgm2.js +3 -0
  9. package/dist/devtools/_nuxt/C9JKABtj.js +1 -0
  10. package/dist/devtools/_nuxt/CHHO6nw6.js +1 -0
  11. package/dist/devtools/_nuxt/DevtoolsSnippet.BaNDy_jv.css +1 -0
  12. package/dist/devtools/_nuxt/Dy0Vu_Hf.js +1 -0
  13. package/dist/devtools/_nuxt/aOrl9V8N.js +4 -0
  14. package/dist/devtools/_nuxt/builds/latest.json +1 -1
  15. package/dist/devtools/_nuxt/builds/meta/116b189e-4f49-45f9-b21c-dfb518abeb03.json +1 -0
  16. package/dist/devtools/_nuxt/entry.DgipzMgL.css +2 -0
  17. package/dist/devtools/_nuxt/iJA-9P1Z.js +2 -0
  18. package/dist/devtools/_nuxt/jJVhk0xb.js +174 -0
  19. package/dist/devtools/_nuxt/pages.DyP4FhjX.css +1 -0
  20. package/dist/devtools/debug/index.html +1 -1
  21. package/dist/devtools/docs/index.html +1 -1
  22. package/dist/devtools/index.html +1 -1
  23. package/dist/devtools/templates/index.html +1 -1
  24. package/dist/module.cjs +1 -1
  25. package/dist/module.d.cts +33 -0
  26. package/dist/module.d.mts +33 -0
  27. package/dist/module.d.ts +33 -0
  28. package/dist/module.json +1 -1
  29. package/dist/module.mjs +1 -1
  30. package/dist/runtime/server/og-image/context.d.ts +1 -1
  31. package/dist/runtime/server/og-image/context.js +41 -5
  32. package/dist/runtime/server/og-image/core/plugins/imageSrc.js +73 -12
  33. package/dist/runtime/server/og-image/takumi/renderer.js +5 -3
  34. package/dist/runtime/server/util/eventHandlers.js +34 -3
  35. package/dist/runtime/shared.d.ts +5 -0
  36. package/dist/runtime/shared.js +10 -0
  37. package/dist/runtime/types.d.ts +9 -0
  38. package/dist/shared/{nuxt-og-image.CvPWboEh.mjs → nuxt-og-image.CA6cPvTd.mjs} +48 -3
  39. package/dist/shared/{nuxt-og-image.Ni0_6XZ0.cjs → nuxt-og-image.DVJetxwr.cjs} +49 -4
  40. package/package.json +5 -5
  41. package/dist/devtools/_nuxt/CGddsLij.js +0 -1
  42. package/dist/devtools/_nuxt/CNPcxXHG.js +0 -173
  43. package/dist/devtools/_nuxt/D84yDWKI.js +0 -1
  44. package/dist/devtools/_nuxt/DLPfJAyQ.js +0 -2
  45. package/dist/devtools/_nuxt/DevtoolsSection.a-2R---I.css +0 -1
  46. package/dist/devtools/_nuxt/DevtoolsSnippet.D9AS35aC.css +0 -1
  47. package/dist/devtools/_nuxt/Dy6LapUo.js +0 -4
  48. package/dist/devtools/_nuxt/Ll4Fy5iv.js +0 -3
  49. package/dist/devtools/_nuxt/builds/meta/05e8381a-ae36-4c96-9530-7973642e8e38.json +0 -1
  50. package/dist/devtools/_nuxt/entry._es5B19-.css +0 -2
  51. package/dist/devtools/_nuxt/pages.CcgChwrv.css +0 -1
  52. 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
- node.props.src = src;
54
- imageBuffer = await $fetch(src, {
55
- responseType: "arrayBuffer"
56
- }).catch(() => {
57
- });
58
- if (imageBuffer) {
59
- const buffer = imageBuffer instanceof ArrayBuffer ? imageBuffer : imageBuffer.buffer;
60
- node.props.src = toBase64Image(buffer);
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
- imageBuffer = await $fetch(decodeHtml(src), {
119
- responseType: "arrayBuffer"
120
- }).catch(() => {
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 dpr = options.takumi?.devicePixelRatio ?? 1;
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
- image = await renderer.createImage(ctx).catch((err) => {
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;
@@ -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;
@@ -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
  }
@@ -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.Ni0_6XZ0.cjs', document.baseURI).href)));
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",
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.6",
112
- "nuxtseo-layer-devtools": "^0.4.5",
113
- "nuxtseo-shared": "^0.8.1",
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.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};