nuxt-og-image 6.1.2 → 6.2.0

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 (116) hide show
  1. package/README.md +4 -1
  2. package/dist/chunks/tw4.cjs +4 -3
  3. package/dist/chunks/tw4.mjs +4 -3
  4. package/dist/chunks/uno.cjs +4 -3
  5. package/dist/chunks/uno.mjs +4 -3
  6. package/dist/content.cjs +14 -15
  7. package/dist/content.d.cts +9 -29
  8. package/dist/content.d.mts +9 -29
  9. package/dist/content.d.ts +9 -29
  10. package/dist/content.mjs +13 -15
  11. package/dist/devtools/200.html +1 -0
  12. package/dist/devtools/404.html +1 -0
  13. package/dist/devtools/_fonts/4ppnHhMi-pBsWSPo7mY0avYxlDoAg1N3PTzCwXLZ5rA-d9oibkGnTd1JL3tc_xnaVgBLYmOB8kjrK2cvZaqwj9s.woff2 +0 -0
  14. package/dist/devtools/_fonts/4qBuU9MRVUlPZNPSF7Xom_sK8RBEnfYu-9VXFrdq8A8-8TDwLE1HAj1sQn7XxVWtM_7sIaPM-DTdO3Pf8U2DF1U.woff2 +0 -0
  15. package/dist/devtools/_fonts/6dYsbWUd_BpKJ7mdDihgOcya1gHXLpJBuMYXux3WMjE-q3fYNS8YbW5n7ZeXI2vSNgkRWW5VDPKAl51SNTjG2qk.woff2 +0 -0
  16. package/dist/devtools/_fonts/Lr-hqqZZsYmCt0ITUlr1CUrWim9fsKvoDFZliMxgNHY-iTa_Yt_PzhOY9TX7ZXdSlEPim6iRt92xhECwaxWxd5w.woff2 +0 -0
  17. package/dist/devtools/_fonts/OknHvWI6KtYn1JQBzX7eSpNDBQ8520F9TvSUJYkVf6A-xeZn9253svK_8Q2LD0XEruY_MnEsuCRO5LenPoggC0Y.woff2 +0 -0
  18. package/dist/devtools/_fonts/PV2hrQG6wq5BlIPDjdL1IcOflycaghyt5MHzlBqZtlo-lb_WexLz3VZqfTN0oi554iBH5tT2j2UFEV-XErCAS3E.woff2 +0 -0
  19. package/dist/devtools/_fonts/UA7OtwYHwGN_HjcVGTdmiQxUit7FlqkCwxVUWSeXVnQ-B4OXCFOL_tWrYODpQTc07aMaj0c2cewTOmBRWR9tD-A.woff2 +0 -0
  20. package/dist/devtools/_fonts/VE4cDVCv5MxbFM7ZLoLCGbIpNd71zhp7MDI9lmN5Y7I-xZyDYCUVrd6LV8eVGF3Um3UZjBFuUtDGtvdyTBBRYBo.woff2 +0 -0
  21. package/dist/devtools/_fonts/fVoGbnMbBFd5L9BBp9fUPavUSkZ_EmsQNSyadkT-108-U4T0khaeLQSIhtt9eVvaCEKJjtWJ4ioRJOf8hvqkWY0.woff2 +0 -0
  22. package/dist/devtools/_fonts/lQAxeCEs1R0Lw-H9XRU1RlOARQN8J6npRsPjyEDMe5s-_DUSLEkO3tKTuun_gSnDLoQPVEnpOnyqZMOw0ByZ6PA.woff2 +0 -0
  23. package/dist/devtools/_fonts/lntlqNHKLV2n82yTwMde70QqOjcfLE2XJ5oKZ3vRPWc-z6TxpIZQdWXztWLr9_OFWqt_WJJoeGtuK_-XQMZGQwE.woff2 +0 -0
  24. package/dist/devtools/_fonts/qxAYvKsXWeYv731eb-h5TRurcdIP_W44mpNdX-HABAk-zUDeMEFlNtNbrwvT9JxLEBg0TphGy70O6RfIoIX_ZwU.woff2 +0 -0
  25. package/dist/devtools/_nuxt/B78iZWPg.js +1 -0
  26. package/dist/{client/_nuxt/D1lfPgTt.js → devtools/_nuxt/BGlUVBvU.js} +1 -1
  27. package/dist/devtools/_nuxt/BL4rmk_W.js +3 -0
  28. package/dist/devtools/_nuxt/BXH6Xx3v.js +3860 -0
  29. package/dist/devtools/_nuxt/CIJ7xJ8b.js +1 -0
  30. package/dist/devtools/_nuxt/CSSHjAxs.js +1 -0
  31. package/dist/{client/_nuxt/Cktc5--N.js → devtools/_nuxt/CsKs7wwl.js} +1 -1
  32. package/dist/{client/_nuxt/Vmj2QZYx.js → devtools/_nuxt/CstUYNOH.js} +1 -1
  33. package/dist/devtools/_nuxt/CxnX_MvN.js +173 -0
  34. package/dist/devtools/_nuxt/CzeCuK1q.js +1 -0
  35. package/dist/devtools/_nuxt/D7bfXIZ-.js +6 -0
  36. package/dist/devtools/_nuxt/DCmYAnXe.js +2 -0
  37. package/dist/devtools/_nuxt/DevtoolsSection.Bxijw5im.css +1 -0
  38. package/dist/devtools/_nuxt/DevtoolsSnippet.CbB_PUej.css +1 -0
  39. package/dist/{client/_nuxt/Dk-IKZND.js → devtools/_nuxt/DmM2Yt1_.js} +1 -1
  40. package/dist/devtools/_nuxt/builds/latest.json +1 -0
  41. package/dist/devtools/_nuxt/builds/meta/22b67a5a-b859-4a85-ad96-a4de4f79168b.json +1 -0
  42. package/dist/devtools/_nuxt/entry.CYlLP9qU.css +2 -0
  43. package/dist/devtools/_nuxt/error-404.BGfO7-QM.css +1 -0
  44. package/dist/devtools/_nuxt/error-500.CIongMTI.css +1 -0
  45. package/dist/{client/_nuxt/CwCh3_ha.js → devtools/_nuxt/o_f3Li2p.js} +1 -1
  46. package/dist/devtools/_nuxt/pages.BAzvGALH.css +1 -0
  47. package/dist/{client/_nuxt/templates.DAFgwCzd.css → devtools/_nuxt/templates.C7e57cTp.css} +1 -1
  48. package/dist/devtools/_nuxt/u4npBYiO.js +3 -0
  49. package/dist/devtools/_nuxt/ws2lPK1y.js +1 -0
  50. package/dist/{client/_nuxt/OW9R-PIP.js → devtools/_nuxt/ynN9sMNI.js} +1 -1
  51. package/dist/devtools/debug/index.html +1 -0
  52. package/dist/devtools/docs/index.html +1 -0
  53. package/dist/devtools/index.html +1 -0
  54. package/dist/devtools/templates/index.html +1 -0
  55. package/dist/module.cjs +4 -3
  56. package/dist/module.json +1 -1
  57. package/dist/module.mjs +4 -3
  58. package/dist/runtime/server/og-image/bindings/font-assets/cloudflare.js +8 -5
  59. package/dist/runtime/server/og-image/browser/screenshot.js +3 -3
  60. package/dist/runtime/server/og-image/context.js +2 -2
  61. package/dist/runtime/server/og-image/core/plugins/imageSrc.js +4 -4
  62. package/dist/runtime/server/og-image/fonts.d.ts +5 -10
  63. package/dist/runtime/server/og-image/fonts.js +15 -6
  64. package/dist/runtime/server/og-image/satori/renderer.js +1 -1
  65. package/dist/runtime/server/og-image/takumi/renderer.js +2 -2
  66. package/dist/runtime/server/util/kit.d.ts +1 -1
  67. package/dist/runtime/server/util/kit.js +2 -5
  68. package/dist/runtime/shared/urlEncoding.d.ts +7 -0
  69. package/dist/runtime/shared/urlEncoding.js +13 -1
  70. package/dist/runtime/shared.d.ts +1 -1
  71. package/dist/runtime/shared.js +1 -1
  72. package/dist/shared/{nuxt-og-image.DuUfHPCI.mjs → nuxt-og-image.Bd7Znc-u.mjs} +82 -158
  73. package/dist/shared/{nuxt-og-image.DFZD-Kf4.cjs → nuxt-og-image.CBzKFXjI.cjs} +86 -162
  74. package/package.json +16 -14
  75. package/dist/client/200.html +0 -1
  76. package/dist/client/404.html +0 -1
  77. package/dist/client/_fonts/0xp3SbCWC1OhX7q1-uF6kilMZFm-alJNkUtkLTPCy_A-tN9KwPUWhhXvtqh74sU9FIkI4W6hsbm85r0X24hjOfM.woff2 +0 -0
  78. package/dist/client/_fonts/4HA9tc4y8BVQeLXvLn3JgQqilAj1xrAnUSprQGHIPSw-ZPswEL_UDOYaxTLQDUySPjoOHDxhD83pD19HMfKfK9s.woff2 +0 -0
  79. package/dist/client/_fonts/Bmul3LaKlc7BUKqJHE_UmEoF40Sg_2ga52yJjwyDcKs-TnYmYl1DNYkiWMu0Vx49DakCPBuiCCj9zoLIuQjUdKY.woff2 +0 -0
  80. package/dist/client/_fonts/DfgmjWGpWte3Q3a54Nevr_BYmMM5YEJXRI1CdI2VwO0-ox5RadQfCyVTmKl_hubTaIJjtRw9oaQz2GDBeZR6l1M.woff2 +0 -0
  81. package/dist/client/_fonts/LK8hREFNeTe-EIzvbfgusJBg3CJ7Q7NFgYIiGb2LZ8-qiyWl0ATLJjOsRPZC_7a8mTMFxEMKEv6JTK_kHtMzbM.woff2 +0 -0
  82. package/dist/client/_fonts/Lc_5lWuBuZcZ166p1-s-mnGkMJwIYJE_QDCkws8iCkI-r45Qbm2hCykrfOZ0kowz__uTTTUOPDN9hz34QcRNTY4.woff2 +0 -0
  83. package/dist/client/_fonts/UBlOS9e0BmJuiF5yVs0YcJrFWaa-iN8zx9TP_lmKs8c-iH3Naewt5UjJ0AQ38QZs4lkEo4zdjMIVkLs4y7EiwIE.woff2 +0 -0
  84. package/dist/client/_fonts/gRxGIWazSFZVyzU0s62U9IArK3RJLkOoUmXx0C8Npsw-kMFNQG6iwjw2nvqS3ut9jMSVn__HlJ28slvxjE4hYfc.woff2 +0 -0
  85. package/dist/client/_fonts/hIKtJJBMNYGPUppSYZpyuF6c24cKhBkhsgaCTgzYgqw-jRJyBPlfGDXClyrgfO6GK_Pfs1RmTsB-wWX6MOgpsRA.woff2 +0 -0
  86. package/dist/client/_fonts/iEvApgDRmzKzNqOYocBTrmcHZmuGAJloawKDP1S0nyE-T3oc_9We24QGwfw5naik4cM0g7VxylWVaQwKm4dy3cw.woff2 +0 -0
  87. package/dist/client/_fonts/kokcBTWRechd97ZdVUpUxrOFbsRt8whO21yA1vQ6iJ8-O7CCbVvFgg_MFLTdyFF9FMeMvIoEmxJLubqVDYTUoWY.woff2 +0 -0
  88. package/dist/client/_fonts/oFzdhjQtZFydTZ757bmiVFXgReR2bBSYm_CjQ7B1Jjs-F6oFbDhOWKYJbgrlC93wkLkPlIV7mzgvqwqEDxQMeHA.woff2 +0 -0
  89. package/dist/client/_nuxt/BKAklG_t.js +0 -1
  90. package/dist/client/_nuxt/C8-_X1H0.js +0 -1
  91. package/dist/client/_nuxt/CZ3ilSZL.js +0 -3860
  92. package/dist/client/_nuxt/CZT7uv4X.js +0 -1
  93. package/dist/client/_nuxt/CfKtH86J.js +0 -3
  94. package/dist/client/_nuxt/CoV50A8g.js +0 -6
  95. package/dist/client/_nuxt/DHgFLo6c.js +0 -2
  96. package/dist/client/_nuxt/JeQLwE-R.js +0 -1
  97. package/dist/client/_nuxt/OSectionBlock.BVHnMsIr.css +0 -1
  98. package/dist/client/_nuxt/W-5Wci_Y.js +0 -1
  99. package/dist/client/_nuxt/builds/latest.json +0 -1
  100. package/dist/client/_nuxt/builds/meta/1e1bd3b0-a510-4582-8d5c-6be1220c8d28.json +0 -1
  101. package/dist/client/_nuxt/entry.CjxjoX5J.css +0 -2
  102. package/dist/client/_nuxt/error-404.DFn4r7cG.css +0 -1
  103. package/dist/client/_nuxt/error-500.DDG-bAQG.css +0 -1
  104. package/dist/client/_nuxt/pages.CVzrVadZ.css +0 -1
  105. package/dist/client/_nuxt/uVtaRSp0.js +0 -174
  106. package/dist/client/debug/index.html +0 -1
  107. package/dist/client/docs/index.html +0 -1
  108. package/dist/client/index.html +0 -1
  109. package/dist/client/templates/index.html +0 -1
  110. /package/dist/{client/_nuxt/CM-t-6ZT.js → devtools/_nuxt/C5jzcy9i.js} +0 -0
  111. /package/dist/{client/_nuxt/HWyD49jH.js → devtools/_nuxt/CCTv7mmB.js} +0 -0
  112. /package/dist/{client/_nuxt/DMFL1JmN.js → devtools/_nuxt/CnH6h21e.js} +0 -0
  113. /package/dist/{client/_nuxt/BsRKQH5X.js → devtools/_nuxt/CuJezOxb.js} +0 -0
  114. /package/dist/{client/_nuxt/CDaXKRRu.js → devtools/_nuxt/E8AZ6HoH.js} +0 -0
  115. /package/dist/{client → devtools}/_nuxt/IFrameLoader.HTWy4e5S.css +0 -0
  116. /package/dist/{client/_nuxt/PONEy9N-.js → devtools/_nuxt/O5eLyffU.js} +0 -0
@@ -7,7 +7,7 @@ import { useNitroApp } from "nitropack/runtime";
7
7
  import { hash } from "ohash";
8
8
  import { parseURL, withoutLeadingSlash, withoutTrailingSlash, withQuery } from "ufo";
9
9
  import { normalizeKey } from "unstorage";
10
- import { decodeOgImageParams, separateProps } from "../../shared.js";
10
+ import { decodeOgImageParams, extractEncodedSegment, separateProps } from "../../shared.js";
11
11
  import { autoEjectCommunityTemplate } from "../util/auto-eject.js";
12
12
  import { createNitroRouteRuleMatcher } from "../util/kit.js";
13
13
  import { normaliseOptions } from "../util/options.js";
@@ -41,7 +41,7 @@ export async function resolveContext(e) {
41
41
  if (!extension || !path.includes(".") || extension.includes("/") || !["png", "jpeg", "jpg", "webp", "svg", "html", "json"].includes(extension)) {
42
42
  extension = "png";
43
43
  }
44
- const encodedSegment = path.split("/").pop().replace(new RegExp(`\\.${extension}$`), "");
44
+ const encodedSegment = extractEncodedSegment(path, extension);
45
45
  const hashMatch = encodedSegment.match(RE_HASH_MODE);
46
46
  let urlOptions = {};
47
47
  if (hashMatch) {
@@ -1,4 +1,4 @@
1
- import { useNitroOrigin } from "#site-config/server/composables/useNitroOrigin";
1
+ import { getNitroOrigin } from "#site-config/server/composables/getNitroOrigin";
2
2
  import { useStorage } from "nitropack/runtime";
3
3
  import { withBase, withoutLeadingSlash } from "ufo";
4
4
  import { toBase64Image } from "../../../../shared.js";
@@ -38,7 +38,7 @@ export default defineTransformer([
38
38
  });
39
39
  if (!imageBuffer && !import.meta.prerender) {
40
40
  imageBuffer = await e.$fetch(src, {
41
- baseURL: useNitroOrigin(e),
41
+ baseURL: getNitroOrigin(e),
42
42
  responseType: "arrayBuffer"
43
43
  }).catch(() => {
44
44
  });
@@ -83,7 +83,7 @@ export default defineTransformer([
83
83
  const buffer = imageBuffer instanceof ArrayBuffer ? imageBuffer : imageBuffer.buffer;
84
84
  node.props.src = toBase64Image(buffer);
85
85
  } else {
86
- node.props.src = `${withBase(src, `${useNitroOrigin(e)}`)}?${Date.now()}`;
86
+ node.props.src = `${withBase(src, `${getNitroOrigin(e)}`)}?${Date.now()}`;
87
87
  }
88
88
  }
89
89
  }
@@ -108,7 +108,7 @@ export default defineTransformer([
108
108
  });
109
109
  if (!imageBuffer && !import.meta.prerender) {
110
110
  imageBuffer = await e.$fetch(src, {
111
- baseURL: useNitroOrigin(e),
111
+ baseURL: getNitroOrigin(e),
112
112
  responseType: "arrayBuffer"
113
113
  }).catch(() => {
114
114
  });
@@ -1,19 +1,14 @@
1
1
  import type { H3Event } from 'h3';
2
2
  import type { OgImageRenderEventContext, RuntimeFontConfig } from '../../types.js';
3
3
  export { codepointsIntersectRanges, extractCodepoints, parseUnicodeRange } from './unicode-range.js';
4
+ type FontFormat = 'ttf' | 'otf' | 'woff' | 'woff2';
4
5
  export interface LoadFontsOptions {
5
6
  /**
6
- * Whether the renderer supports WOFF2.
7
- * When false, WOFF2 fonts will use satoriSrc (converted TTF) if available,
8
- * otherwise they will be skipped.
7
+ * Font formats the renderer can parse.
8
+ * Satori: ttf, otf, woff
9
+ * Takumi: ttf, woff2
9
10
  */
10
- supportsWoff2: boolean;
11
- /**
12
- * Prefer static (satoriSrc) fonts over WOFF2 when available.
13
- * Used by Takumi to avoid WOFF2 subset decompression bugs while still
14
- * falling through to WOFF2 when no static alternative exists.
15
- */
16
- preferStatic?: boolean;
11
+ supportedFormats: Set<FontFormat>;
17
12
  /** Component pascalName — filters fonts to only what this component needs */
18
13
  component?: string;
19
14
  /** When set, ensures this font family is included even if not in requirements */
@@ -6,6 +6,15 @@ import { logger } from "../../logger.js";
6
6
  import { fontArrayCache, fontCache } from "./cache/lru.js";
7
7
  import { codepointsIntersectRanges, parseUnicodeRange } from "./unicode-range.js";
8
8
  export { codepointsIntersectRanges, extractCodepoints, parseUnicodeRange } from "./unicode-range.js";
9
+ function fontFormat(src) {
10
+ if (src.endsWith(".woff2"))
11
+ return "woff2";
12
+ if (src.endsWith(".woff"))
13
+ return "woff";
14
+ if (src.endsWith(".otf"))
15
+ return "otf";
16
+ return "ttf";
17
+ }
9
18
  async function loadFont(event, font, src) {
10
19
  const cacheKey = `${font.family}-${font.weight}-${font.style}-${src}`;
11
20
  const cached = fontCache.get(cacheKey);
@@ -107,16 +116,16 @@ export async function loadAllFonts(event, options) {
107
116
  const results = await Promise.all(
108
117
  fonts.map(async (f) => {
109
118
  let src = f.src;
110
- const isWoff2 = f.src.endsWith(".woff2");
111
- if (isWoff2 && (options.preferStatic || !options.supportsWoff2)) {
112
- if (f.satoriSrc) {
119
+ const srcFormat = fontFormat(f.src);
120
+ if (!options.supportedFormats.has(srcFormat)) {
121
+ if (f.satoriSrc && options.supportedFormats.has(fontFormat(f.satoriSrc))) {
113
122
  src = f.satoriSrc;
114
- } else if (!options.supportsWoff2) {
123
+ } else {
115
124
  return null;
116
125
  }
117
126
  }
118
127
  let data = await loadFont(event, f, src);
119
- if (!data && src !== f.src && options.supportsWoff2) {
128
+ if (!data && src !== f.src && options.supportedFormats.has(srcFormat)) {
120
129
  data = await loadFont(event, f, f.src);
121
130
  if (data)
122
131
  src = f.src;
@@ -137,7 +146,7 @@ export async function loadAllFonts(event, options) {
137
146
  return cachedArray;
138
147
  fontArrayCache.set(fingerprint, loaded);
139
148
  const isCommunity = options.component && map[options.component]?.category === "community";
140
- if (!options.supportsWoff2 && loaded.length === 0 && fonts.length > 0 && !isCommunity) {
149
+ if (!options.supportedFormats.has("woff2") && loaded.length === 0 && fonts.length > 0 && !isCommunity) {
141
150
  const variableFamilies = [...new Set(fonts.map((f) => f.family))];
142
151
  const warnKey = `variable-fonts-${variableFamilies.join(",")}`;
143
152
  if (!_warnedFontKeys.has(warnKey)) {
@@ -33,7 +33,7 @@ export async function createSvg(event) {
33
33
  const codepoints = extractCodepoints(vnodes);
34
34
  const hasCustomFonts = Array.isArray(options.fonts) && options.fonts.length > 0;
35
35
  const fonts = await loadFontsForRenderer(event, {
36
- supportsWoff2: false,
36
+ supportedFormats: /* @__PURE__ */ new Set(["ttf", "otf", "woff"]),
37
37
  component: options.component,
38
38
  fontFamilyOverride: fontFamilyOverride || defaultFont,
39
39
  codepoints,
@@ -71,7 +71,7 @@ async function createImage(event, format) {
71
71
  const { fontFamilyOverride, defaultFont } = getDefaultFontFamily(options);
72
72
  const nodes = await createTakumiNodes(event);
73
73
  const codepoints = extractCodepoints(nodes);
74
- const fonts = await loadFontsForRenderer(event, { supportsWoff2: true, preferStatic: true, component: options.component, fontFamilyOverride: fontFamilyOverride || defaultFont, codepoints });
74
+ const fonts = await loadFontsForRenderer(event, { supportedFormats: /* @__PURE__ */ new Set(["ttf", "woff2"]), component: options.component, fontFamilyOverride: fontFamilyOverride || defaultFont, codepoints });
75
75
  await event._nitro.hooks.callHook("nuxt-og-image:takumi:nodes", nodes, event);
76
76
  const state = await getTakumiState(event);
77
77
  await loadFontsIntoRenderer(state, fonts);
@@ -129,7 +129,7 @@ const TakumiRenderer = {
129
129
  async debug(e) {
130
130
  const [vnodes, fonts] = await Promise.all([
131
131
  createTakumiNodes(e),
132
- loadFontsForRenderer(e, { supportsWoff2: true, preferStatic: true, component: e.options.component })
132
+ loadFontsForRenderer(e, { supportedFormats: /* @__PURE__ */ new Set(["ttf", "woff2"]), component: e.options.component })
133
133
  ]);
134
134
  return {
135
135
  vnodes,
@@ -1,6 +1,6 @@
1
1
  import type { H3Event } from 'h3';
2
2
  import type { NitroRouteRules } from 'nitropack';
3
3
  import type { NuxtIslandResponse } from 'nuxt/app';
4
+ export { withoutQuery } from 'nuxtseo-shared/utils';
4
5
  export declare function fetchIsland(e: H3Event, component: string, props: Record<string, any>): Promise<NuxtIslandResponse>;
5
- export declare function withoutQuery(path: string): string | undefined;
6
6
  export declare function createNitroRouteRuleMatcher(): ((path: string) => NitroRouteRules);
@@ -3,6 +3,7 @@ import { useRuntimeConfig } from "nitropack/runtime";
3
3
  import { hash } from "ohash";
4
4
  import { createRouter as createRadixRouter, toRouteMatcher } from "radix3";
5
5
  import { withoutBase, withoutTrailingSlash } from "ufo";
6
+ export { withoutQuery } from "nuxtseo-shared/utils";
6
7
  export function fetchIsland(e, component, props) {
7
8
  const hashId = hash([component, props]).replaceAll("_", "-");
8
9
  return e.$fetch(`/__nuxt_island/${component}_${hashId}.json`, {
@@ -11,9 +12,6 @@ export function fetchIsland(e, component, props) {
11
12
  }
12
13
  });
13
14
  }
14
- export function withoutQuery(path) {
15
- return path.split("?")[0];
16
- }
17
15
  export function createNitroRouteRuleMatcher() {
18
16
  const { nitro, app } = useRuntimeConfig();
19
17
  const _routeRulesMatcher = toRouteMatcher(
@@ -25,8 +23,7 @@ export function createNitroRouteRuleMatcher() {
25
23
  );
26
24
  return (path) => {
27
25
  return defu({}, ..._routeRulesMatcher.matchAll(
28
- // radix3 does not support trailing slashes
29
- withoutBase(withoutTrailingSlash(withoutQuery(path)), app.baseURL)
26
+ withoutBase(withoutTrailingSlash(path.split("?")[0]), app.baseURL)
30
27
  ).reverse());
31
28
  };
32
29
  }
@@ -62,3 +62,10 @@ export declare function parseOgImageUrl(url: string): {
62
62
  isStatic: boolean;
63
63
  hash?: string;
64
64
  };
65
+ /**
66
+ * Extract the encoded segment from the full path, handling the case where
67
+ * %2F in prop values has been decoded to / by intermediaries (#522).
68
+ * Uses the full catch-all match after /_og/d/ (or /_og/s/) instead of
69
+ * only the last path segment.
70
+ */
71
+ export declare function extractEncodedSegment(path: string, extension: string): string;
@@ -10,6 +10,7 @@ const RE_PERCENT20 = /%20/g;
10
10
  const RE_PLUS = /\+/g;
11
11
  const RE_SINGLE_UNDERSCORE = /(?<!_)_(?!_)/;
12
12
  const RE_OG_PATH_PREFIX = /^\/_og\/[ds]\//;
13
+ const RE_OG_ROUTE_PREFIX = /\/_og\/[ds]\//;
13
14
  const RE_FILE_EXTENSION_WITH_CAPTURE = /\.(\w+)$/;
14
15
  const RE_FILE_EXTENSION = /\.\w+$/;
15
16
  const RE_HASH_SEGMENT = /^o_([a-z0-9]+)$/i;
@@ -144,7 +145,11 @@ export function encodeOgImageParams(options, defaults) {
144
145
  } else {
145
146
  const escaped = str.startsWith("~") ? `~${str}` : str;
146
147
  const encoded = encodeURIComponent(escaped.replace(RE_UNDERSCORE, "__")).replace(RE_PERCENT20, "+");
147
- parts.push(`${alias}_${encoded}`);
148
+ if (encoded.includes("%")) {
149
+ parts.push(`${alias}_~${b64Encode(str)}`);
150
+ } else {
151
+ parts.push(`${alias}_${encoded}`);
152
+ }
148
153
  }
149
154
  }
150
155
  }
@@ -255,3 +260,10 @@ export function parseOgImageUrl(url) {
255
260
  isStatic
256
261
  };
257
262
  }
263
+ export function extractEncodedSegment(path, extension) {
264
+ const match = path.match(RE_OG_ROUTE_PREFIX);
265
+ if (match?.index != null) {
266
+ return path.slice(match.index + match[0].length).replace(new RegExp(`\\.${extension}$`), "");
267
+ }
268
+ return path.split("/").pop().replace(new RegExp(`\\.${extension}$`), "");
269
+ }
@@ -1,7 +1,7 @@
1
1
  import type { ResolvableMeta } from '@unhead/vue';
2
2
  import type { OgImageOptions, OgImagePrebuilt } from './types.js';
3
3
  export { extractSocialPreviewTags, toBase64Image } from './pure.js';
4
- export { buildOgImageUrl, decodeOgImageParams, encodeOgImageParams, hashOgImageOptions, parseOgImageUrl } from './shared/urlEncoding.js';
4
+ export { buildOgImageUrl, decodeOgImageParams, encodeOgImageParams, extractEncodedSegment, hashOgImageOptions, parseOgImageUrl } from './shared/urlEncoding.js';
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;
@@ -1,7 +1,7 @@
1
1
  import { defu } from "defu";
2
2
  import { toValue } from "vue";
3
3
  export { extractSocialPreviewTags, toBase64Image } from "./pure.js";
4
- export { buildOgImageUrl, decodeOgImageParams, encodeOgImageParams, hashOgImageOptions, parseOgImageUrl } from "./shared/urlEncoding.js";
4
+ export { buildOgImageUrl, decodeOgImageParams, encodeOgImageParams, extractEncodedSegment, hashOgImageOptions, parseOgImageUrl } from "./shared/urlEncoding.js";
5
5
  const RE_KEBAB_CASE = /-([a-z])/g;
6
6
  export function generateMeta(url, resolvedOptions) {
7
7
  const key = resolvedOptions.key || "og";