nuxt-seo-utils 8.6.0 → 9.0.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 (53) hide show
  1. package/README.md +11 -15
  2. package/dist/cli.mjs +1 -1
  3. package/dist/module.d.mts +55 -3
  4. package/dist/module.d.ts +55 -3
  5. package/dist/module.json +2 -2
  6. package/dist/module.mjs +521 -31
  7. package/dist/runtime/app/composables/polyfills.d.ts +2 -2
  8. package/dist/runtime/app/composables/polyfills.js +2 -2
  9. package/dist/runtime/app/composables/schemaOrg.d.ts +2 -0
  10. package/dist/runtime/app/composables/schemaOrg.js +2 -0
  11. package/dist/runtime/app/composables/useBreadcrumbItems.js +3 -2
  12. package/dist/runtime/app/composables/useFallbackTitle.js +0 -8
  13. package/dist/runtime/app/index.d.ts +5 -0
  14. package/dist/runtime/app/index.js +3 -0
  15. package/dist/runtime/app/logic/applyDefaults.js +1 -2
  16. package/dist/runtime/app/logic/syncDerivedTags.js +25 -15
  17. package/dist/runtime/app/plugins/0.routeRules.d.ts +1 -1
  18. package/dist/runtime/app/plugins/0.routeRules.js +1 -1
  19. package/dist/runtime/app/plugins/1.absoluteImageUrls.server.d.ts +1 -1
  20. package/dist/runtime/app/plugins/1.absoluteImageUrls.server.js +1 -2
  21. package/dist/runtime/app/plugins/colorModeIcons.d.ts +1 -1
  22. package/dist/runtime/app/plugins/colorModeIcons.js +1 -1
  23. package/dist/runtime/app/plugins/defaults.d.ts +1 -1
  24. package/dist/runtime/app/plugins/defaultsWaitI18n.d.ts +1 -1
  25. package/dist/runtime/app/plugins/derivedTags.d.ts +1 -1
  26. package/dist/runtime/app/plugins/derivedTags.js +1 -2
  27. package/dist/runtime/app/plugins/inferSeoMetaPlugin.d.ts +1 -1
  28. package/dist/runtime/app/plugins/inferSeoMetaPlugin.js +2 -16
  29. package/dist/runtime/app/plugins/minifyScripts.server.d.ts +1 -1
  30. package/dist/runtime/app/plugins/minifyScripts.server.js +2 -11
  31. package/dist/runtime/app/plugins/siteConfig.d.ts +1 -1
  32. package/dist/runtime/app/plugins/siteConfig.js +1 -2
  33. package/dist/runtime/app/plugins/titles.d.ts +1 -1
  34. package/dist/runtime/app/plugins/titles.js +1 -2
  35. package/dist/runtime/app/plugins/titlesWaitI18n.d.ts +1 -1
  36. package/dist/runtime/app/plugins/titlesWaitI18n.js +1 -2
  37. package/dist/runtime/server/middleware/redirectCanonical.d.ts +1 -1
  38. package/dist/runtime/server/middleware/redirectCanonical.js +6 -6
  39. package/dist/runtime/server/middleware/redirects.d.ts +2 -0
  40. package/dist/runtime/server/middleware/redirects.js +21 -0
  41. package/dist/runtime/server/middleware/resolveImagesInPagesDir.d.ts +1 -1
  42. package/dist/runtime/server/middleware/resolveImagesInPagesDir.js +5 -6
  43. package/dist/runtime/server/plugins/minifyHtml.js +2 -9
  44. package/dist/runtime/server/routes/__nuxt-seo-utils/debug.d.ts +27 -1
  45. package/dist/runtime/server/routes/__nuxt-seo-utils/debug.js +2 -3
  46. package/dist/runtime/shared/minify.d.ts +0 -6
  47. package/dist/runtime/shared/minify.js +0 -60
  48. package/dist/runtime/shared/redirects.d.ts +40 -0
  49. package/dist/runtime/shared/redirects.js +59 -0
  50. package/dist/runtime/types.d.ts +15 -0
  51. package/dist/types.d.mts +1 -1
  52. package/package.json +42 -37
  53. package/skills/nuxt-seo-utils/SKILL.md +52 -6
@@ -1,8 +1,8 @@
1
1
  import type { ComputedRef } from 'vue';
2
- export declare function useSchemaOrg(): void;
2
+ export declare function useSchemaOrg(_input?: unknown): void;
3
3
  export declare function defineWebSite(): void;
4
4
  export declare function defineWebPage(): void;
5
- export declare function defineBreadcrumb(): void;
5
+ export declare function defineBreadcrumb(_input?: unknown): void;
6
6
  export declare function useI18n(): {
7
7
  t: (_: string, fallback: string, _options: any) => string;
8
8
  te: (_: string) => boolean;
@@ -1,12 +1,12 @@
1
1
  import { computed, toValue } from "vue";
2
2
  import { useSiteConfig } from "#site-config/app/composables/useSiteConfig";
3
- export function useSchemaOrg() {
3
+ export function useSchemaOrg(_input) {
4
4
  }
5
5
  export function defineWebSite() {
6
6
  }
7
7
  export function defineWebPage() {
8
8
  }
9
- export function defineBreadcrumb() {
9
+ export function defineBreadcrumb(_input) {
10
10
  }
11
11
  export function useI18n() {
12
12
  const siteConfig = useSiteConfig({
@@ -0,0 +1,2 @@
1
+ export { useSchemaOrg } from '#schema-org/app/composables/useSchemaOrg';
2
+ export { defineBreadcrumb } from '@unhead/schema-org/vue';
@@ -0,0 +1,2 @@
1
+ export { useSchemaOrg } from "#schema-org/app/composables/useSchemaOrg";
2
+ export { defineBreadcrumb } from "@unhead/schema-org/vue";
@@ -14,11 +14,12 @@ import {
14
14
  toValue,
15
15
  watch
16
16
  } from "vue";
17
- import { defineBreadcrumb, useI18n, useSchemaOrg } from "#imports";
17
+ import { defineBreadcrumb, useSchemaOrg } from "#seo-utils-schema";
18
18
  import { useSiteConfig } from "#site-config/app/composables/useSiteConfig";
19
19
  import { createSitePathResolver } from "#site-config/app/composables/utils";
20
20
  import { pathBreadcrumbSegments, resolveBreadcrumbRoot } from "../../shared/breadcrumbs.js";
21
21
  import { normaliseCanonicalUrl } from "../../shared/canonicalUrl.js";
22
+ import { useI18n as useI18nPolyfill } from "./polyfills.js";
22
23
  function withoutQuery(path) {
23
24
  return path.split("?")[0] || "";
24
25
  }
@@ -78,7 +79,7 @@ export function useBreadcrumbItems(_options = {}) {
78
79
  }
79
80
  const route = useRoute();
80
81
  const router = useRouter();
81
- const i18n = useI18n();
82
+ const i18n = nuxtApp.$i18n || useI18nPolyfill();
82
83
  const siteResolver = createSitePathResolver({
83
84
  canonical: true,
84
85
  absolute: true
@@ -2,7 +2,6 @@ import { useError, useNuxtApp, useRoute } from "nuxt/app";
2
2
  import { titleCase } from "scule";
3
3
  import { withoutTrailingSlash } from "ufo";
4
4
  import { computed } from "vue";
5
- import { useI18n } from "#imports";
6
5
  export function useFallbackTitle() {
7
6
  const route = useRoute();
8
7
  const err = useError();
@@ -11,13 +10,6 @@ export function useFallbackTitle() {
11
10
  i18n = useNuxtApp().$i18n;
12
11
  } catch {
13
12
  }
14
- if (!i18n) {
15
- try {
16
- i18n = useI18n();
17
- } catch {
18
- console.warn("[nuxt-seo-utils] useFallbackTitle: could not resolve the i18n instance. Titles will not be resolved from i18n messages.");
19
- }
20
- }
21
13
  return computed(() => {
22
14
  if (err.value?.statusCode && [404, 500].includes(err.value.statusCode)) {
23
15
  return `${err.value.statusCode} - ${err.value.message}`;
@@ -0,0 +1,5 @@
1
+ export type { BreadcrumbItemProps, BreadcrumbProps, ResolvedBreadcrumbProps } from './composables/useBreadcrumbItems.js';
2
+ export { useBreadcrumbItems } from './composables/useBreadcrumbItems.js';
3
+ export { useFallbackTitle } from './composables/useFallbackTitle.js';
4
+ export type { ShareLinks, ShareLinksOptions, ShareLinkUtmParams, SharePlatform } from './composables/useShareLinks.js';
5
+ export { useShareLinks } from './composables/useShareLinks.js';
@@ -0,0 +1,3 @@
1
+ export { useBreadcrumbItems } from "./composables/useBreadcrumbItems.js";
2
+ export { useFallbackTitle } from "./composables/useFallbackTitle.js";
3
+ export { useShareLinks } from "./composables/useShareLinks.js";
@@ -1,6 +1,5 @@
1
- import { injectHead, useHead, useSeoMeta } from "@unhead/vue";
2
1
  import { TemplateParamsPlugin } from "@unhead/vue/plugins";
3
- import { useError, useRoute, useRuntimeConfig } from "nuxt/app";
2
+ import { injectHead, useError, useHead, useRoute, useRuntimeConfig, useSeoMeta } from "nuxt/app";
4
3
  import { computed, toValue } from "vue";
5
4
  import { useSiteConfig } from "#site-config/app/composables/useSiteConfig";
6
5
  import { createSitePathResolver } from "#site-config/app/composables/utils";
@@ -20,24 +20,34 @@ export function ogImageEntryIds(entryTags) {
20
20
  return ids;
21
21
  }
22
22
  export function syncDerivedTags(tags, entriesWithOgImage) {
23
- const winningOgImageEntries = new Set(tags.filter(isOgImage).map(entryOf));
24
- const canonicalHref = tags.find((tag) => tag.tag === "link" && tag.props.rel === "canonical")?.props.href;
23
+ const winningOgImageEntries = /* @__PURE__ */ new Set();
24
+ let canonicalTag;
25
+ for (const tag of tags) {
26
+ if (isOgImage(tag))
27
+ winningOgImageEntries.add(entryOf(tag));
28
+ if (!canonicalTag && tag.tag === "link" && tag.props.rel === "canonical")
29
+ canonicalTag = tag;
30
+ }
31
+ const canonicalHref = canonicalTag?.props.href;
25
32
  const lostOgImage = (tag) => {
26
33
  const entry = entryOf(tag);
27
34
  return entry !== void 0 && entriesWithOgImage.has(entry) && !winningOgImageEntries.has(entry);
28
35
  };
29
- return tags.flatMap((tag) => {
30
- if (tag.tag !== "meta")
31
- return [tag];
32
- if (metaKey(tag)?.startsWith("og:image:") && lostOgImage(tag))
33
- return [];
34
- if (tag.key?.startsWith(TWITTER_IMAGE_FALLBACK_KEY) && lostOgImage(tag))
35
- return [];
36
- if (tag.key === OG_URL_KEY) {
37
- if (typeof canonicalHref !== "string" || !canonicalHref)
38
- return [];
39
- return [{ ...tag, props: { ...tag.props, content: canonicalHref } }];
36
+ const result = [];
37
+ for (const tag of tags) {
38
+ if (tag.tag === "meta") {
39
+ if (metaKey(tag)?.startsWith("og:image:") && lostOgImage(tag))
40
+ continue;
41
+ if (tag.key?.startsWith(TWITTER_IMAGE_FALLBACK_KEY) && lostOgImage(tag))
42
+ continue;
43
+ if (tag.key === OG_URL_KEY) {
44
+ if (typeof canonicalHref !== "string" || !canonicalHref)
45
+ continue;
46
+ result.push({ ...tag, props: { ...tag.props, content: canonicalHref } });
47
+ continue;
48
+ }
40
49
  }
41
- return [tag];
42
- });
50
+ result.push(tag);
51
+ }
52
+ return result;
43
53
  }
@@ -1,2 +1,2 @@
1
- declare const _default: import("#app").Plugin<Record<string, unknown>> & import("#app").ObjectPlugin<Record<string, unknown>>;
1
+ declare const _default: import("nuxt/app").Plugin<Record<string, unknown>> & import("nuxt/app").ObjectPlugin<Record<string, unknown>>;
2
2
  export default _default;
@@ -1,4 +1,4 @@
1
- import { defineNuxtPlugin, useHead, useRequestEvent, useSeoMeta, useState } from "#imports";
1
+ import { defineNuxtPlugin, useHead, useRequestEvent, useSeoMeta, useState } from "nuxt/app";
2
2
  function parseRouteRuleState(context) {
3
3
  const rules = context._nitro?.routeRules;
4
4
  return {
@@ -1,2 +1,2 @@
1
- declare const _default: import("#app").Plugin<Record<string, unknown>> & import("#app").ObjectPlugin<Record<string, unknown>>;
1
+ declare const _default: import("nuxt/app").Plugin<Record<string, unknown>> & import("nuxt/app").ObjectPlugin<Record<string, unknown>>;
2
2
  export default _default;
@@ -1,5 +1,4 @@
1
- import { injectHead } from "@unhead/vue";
2
- import { defineNuxtPlugin } from "nuxt/app";
1
+ import { defineNuxtPlugin, injectHead } from "nuxt/app";
3
2
  import { unref } from "vue";
4
3
  import { createSitePathResolver } from "#site-config/app/composables/utils";
5
4
  export default defineNuxtPlugin({
@@ -1,2 +1,2 @@
1
- declare const _default: import("#app").Plugin<Record<string, unknown>> & import("#app").ObjectPlugin<Record<string, unknown>>;
1
+ declare const _default: import("nuxt/app").Plugin<Record<string, unknown>> & import("nuxt/app").ObjectPlugin<Record<string, unknown>>;
2
2
  export default _default;
@@ -1,4 +1,4 @@
1
- import { defineNuxtPlugin, useHead, useNuxtApp, useRuntimeConfig } from "#imports";
1
+ import { defineNuxtPlugin, useHead, useNuxtApp, useRuntimeConfig } from "nuxt/app";
2
2
  import { selectColorModeIconLinks } from "../logic/colorModeIcons.js";
3
3
  export default defineNuxtPlugin({
4
4
  name: "nuxt-seo-utils:color-mode-icons",
@@ -1,2 +1,2 @@
1
- declare const _default: import("#app").Plugin<Record<string, unknown>> & import("#app").ObjectPlugin<Record<string, unknown>>;
1
+ declare const _default: import("nuxt/app").Plugin<Record<string, unknown>> & import("nuxt/app").ObjectPlugin<Record<string, unknown>>;
2
2
  export default _default;
@@ -1,2 +1,2 @@
1
- declare const _default: import("#app").Plugin<Record<string, unknown>> & import("#app").ObjectPlugin<Record<string, unknown>>;
1
+ declare const _default: import("nuxt/app").Plugin<Record<string, unknown>> & import("nuxt/app").ObjectPlugin<Record<string, unknown>>;
2
2
  export default _default;
@@ -1,2 +1,2 @@
1
- declare const _default: import("#app").Plugin<Record<string, unknown>> & import("#app").ObjectPlugin<Record<string, unknown>>;
1
+ declare const _default: import("nuxt/app").Plugin<Record<string, unknown>> & import("nuxt/app").ObjectPlugin<Record<string, unknown>>;
2
2
  export default _default;
@@ -1,5 +1,4 @@
1
- import { injectHead } from "@unhead/vue";
2
- import { defineNuxtPlugin } from "nuxt/app";
1
+ import { defineNuxtPlugin, injectHead } from "nuxt/app";
3
2
  import { ogImageEntryIds, syncDerivedTags } from "../logic/syncDerivedTags.js";
4
3
  export default defineNuxtPlugin({
5
4
  name: "nuxt-seo:derived-tags",
@@ -1,2 +1,2 @@
1
- declare const _default: import("#app").Plugin<Record<string, unknown>> & import("#app").ObjectPlugin<Record<string, unknown>>;
1
+ declare const _default: import("nuxt/app").Plugin<Record<string, unknown>> & import("nuxt/app").ObjectPlugin<Record<string, unknown>>;
2
2
  export default _default;
@@ -1,7 +1,5 @@
1
- import { injectHead } from "@unhead/vue";
2
1
  import { InferSeoMetaPlugin, TemplateParamsPlugin } from "@unhead/vue/plugins";
3
- import { defineNuxtPlugin, useRuntimeConfig } from "nuxt/app";
4
- const disabledTwitterCard = "x-nuxt-seo-utils-disabled-twitter-card";
2
+ import { defineNuxtPlugin, injectHead, useRuntimeConfig } from "nuxt/app";
5
3
  export default defineNuxtPlugin(() => {
6
4
  const head = injectHead();
7
5
  if (!head)
@@ -9,19 +7,7 @@ export default defineNuxtPlugin(() => {
9
7
  const { automaticTwitterTags } = useRuntimeConfig().public["seo-utils"];
10
8
  head.use(TemplateParamsPlugin);
11
9
  if (automaticTwitterTags === false) {
12
- head.use(InferSeoMetaPlugin({ twitterCard: disabledTwitterCard }));
13
- head.use({
14
- key: "nuxt-seo-utils:twitter-card-suppression",
15
- hooks: {
16
- "tags:beforeResolve": ({ tags }) => {
17
- for (let i = tags.length - 1; i >= 0; i--) {
18
- const tag = tags[i];
19
- if (tag.tag === "meta" && tag.props.name === "twitter:card" && tag.props.content === disabledTwitterCard)
20
- tags.splice(i, 1);
21
- }
22
- }
23
- }
24
- });
10
+ head.use(InferSeoMetaPlugin({ twitterCard: false }));
25
11
  } else {
26
12
  head.use(InferSeoMetaPlugin());
27
13
  }
@@ -1,2 +1,2 @@
1
- declare const _default: import("#app").Plugin<Record<string, unknown>> & import("#app").ObjectPlugin<Record<string, unknown>>;
1
+ declare const _default: import("nuxt/app").Plugin<Record<string, unknown>> & import("nuxt/app").ObjectPlugin<Record<string, unknown>>;
2
2
  export default _default;
@@ -1,6 +1,5 @@
1
- import { injectHead } from "@unhead/vue";
2
- import { defineNuxtPlugin } from "nuxt/app";
3
- import { JSON_TYPES, minifyCSS, minifyJS, minifyJSON, SKIP_JS_TYPES } from "../../shared/minify.js";
1
+ import { defineNuxtPlugin, injectHead } from "nuxt/app";
2
+ import { JSON_TYPES, minifyCSS, minifyJSON } from "../../shared/minify.js";
4
3
  export default defineNuxtPlugin({
5
4
  enforce: "post",
6
5
  setup() {
@@ -26,14 +25,6 @@ export default defineNuxtPlugin({
26
25
  }
27
26
  continue;
28
27
  }
29
- if (type && SKIP_JS_TYPES.has(type))
30
- continue;
31
- try {
32
- const minified = minifyJS(content);
33
- if (minified.length < content.length)
34
- tag.innerHTML = minified;
35
- } catch {
36
- }
37
28
  } else if (tag.tag === "style") {
38
29
  try {
39
30
  const minified = minifyCSS(content);
@@ -1,2 +1,2 @@
1
- declare const _default: import("#app").Plugin<Record<string, unknown>> & import("#app").ObjectPlugin<Record<string, unknown>>;
1
+ declare const _default: import("nuxt/app").Plugin<Record<string, unknown>> & import("nuxt/app").ObjectPlugin<Record<string, unknown>>;
2
2
  export default _default;
@@ -1,5 +1,4 @@
1
- import { injectHead } from "@unhead/vue";
2
- import { defineNuxtPlugin, useRuntimeConfig } from "nuxt/app";
1
+ import { defineNuxtPlugin, injectHead, useRuntimeConfig } from "nuxt/app";
3
2
  import { useSiteConfig } from "#site-config/app/composables/useSiteConfig";
4
3
  export default defineNuxtPlugin(() => {
5
4
  const head = injectHead();
@@ -1,2 +1,2 @@
1
- declare const _default: import("#app").Plugin<Record<string, unknown>> & import("#app").ObjectPlugin<Record<string, unknown>>;
1
+ declare const _default: import("nuxt/app").Plugin<Record<string, unknown>> & import("nuxt/app").ObjectPlugin<Record<string, unknown>>;
2
2
  export default _default;
@@ -1,5 +1,4 @@
1
- import { useHead } from "@unhead/vue";
2
- import { defineNuxtPlugin } from "nuxt/app";
1
+ import { defineNuxtPlugin, useHead } from "nuxt/app";
3
2
  import { useFallbackTitle } from "../composables/useFallbackTitle.js";
4
3
  export default defineNuxtPlugin({
5
4
  name: "nuxt-seo:fallback-titles",
@@ -1,2 +1,2 @@
1
- declare const _default: import("#app").Plugin<Record<string, unknown>> & import("#app").ObjectPlugin<Record<string, unknown>>;
1
+ declare const _default: import("nuxt/app").Plugin<Record<string, unknown>> & import("nuxt/app").ObjectPlugin<Record<string, unknown>>;
2
2
  export default _default;
@@ -1,5 +1,4 @@
1
- import { useHead } from "@unhead/vue";
2
- import { defineNuxtPlugin } from "nuxt/app";
1
+ import { defineNuxtPlugin, useHead } from "nuxt/app";
3
2
  import { useFallbackTitle } from "../composables/useFallbackTitle.js";
4
3
  export default defineNuxtPlugin({
5
4
  name: "nuxt-seo:fallback-titles",
@@ -1,2 +1,2 @@
1
- declare const _default: any;
1
+ declare const _default: import("nuxt/server").EventHandler<string | undefined>;
2
2
  export default _default;
@@ -1,11 +1,11 @@
1
+ import { defineEventHandler, getRequestHost, sendRedirect } from "nuxt/server";
1
2
  import { joinURL } from "ufo";
2
- import { defineEventHandler, getRequestHost, sendRedirect, setHeader } from "#nuxtseo/h3";
3
3
  import { getSiteConfig } from "#site-config/server/composables/getSiteConfig";
4
4
  export default defineEventHandler((e) => {
5
5
  if (import.meta.prerender) {
6
6
  return;
7
7
  }
8
- const path = e.path;
8
+ const path = e.url.pathname;
9
9
  if (path.startsWith("/_nuxt") || path.startsWith("/api")) {
10
10
  return;
11
11
  }
@@ -16,13 +16,13 @@ export default defineEventHandler((e) => {
16
16
  if (!siteConfig.url || siteConfig.env !== "production") {
17
17
  return;
18
18
  }
19
- const siteConfigHostName = new URL(e.path, siteConfig.url).host;
19
+ const siteConfigHostName = new URL(e.url.pathname, siteConfig.url).host;
20
20
  const host = getRequestHost(e, { xForwardedHost: true });
21
- if (e.headers.get("x-nuxt-seo-redirected") || host.includes("http") || host.replace("https://", "").includes(":")) {
21
+ if (e.req.headers.get("x-nuxt-seo-redirected") || host.includes("http") || host.replace("https://", "").includes(":")) {
22
22
  return;
23
23
  }
24
24
  if (host.split(":")[0] !== siteConfigHostName.split(":")[0]) {
25
- setHeader(e, "x-nuxt-seo-redirected", "true");
26
- return sendRedirect(e, joinURL(siteConfig.url, e.path), 301);
25
+ e.res.headers.set("x-nuxt-seo-redirected", "true");
26
+ return sendRedirect(e, joinURL(siteConfig.url, e.url.pathname + e.url.search), 301);
27
27
  }
28
28
  });
@@ -0,0 +1,2 @@
1
+ declare const _default: import("nuxt/server").EventHandler<string | undefined>;
2
+ export default _default;
@@ -0,0 +1,21 @@
1
+ import { createError, defineEventHandler, sendRedirect, useRuntimeConfig } from "nuxt/server";
2
+ import { decodePath, joinURL, withoutBase } from "ufo";
3
+ import { appendSearch, createRedirectMatcher, isAbsoluteUrl, REDIRECT_CACHE_CONTROL, resolveTarget } from "../../shared/redirects.js";
4
+ let match;
5
+ export default defineEventHandler((e) => {
6
+ const config = useRuntimeConfig();
7
+ match ||= createRedirectMatcher(config["seo-utils-redirects"]);
8
+ const baseURL = config.app.baseURL;
9
+ const path = decodePath(withoutBase(e.url.pathname, baseURL));
10
+ const rule = match(path);
11
+ if (!rule)
12
+ return;
13
+ if (rule._tag === "Gone") {
14
+ throw createError({ status: rule.statusCode, statusText: rule.statusCode === 410 ? "Gone" : "Not Found" });
15
+ }
16
+ const target = resolveTarget(rule, path);
17
+ const location = isAbsoluteUrl(target) ? target : joinURL(baseURL, target);
18
+ if (!e.res.headers.has("cache-control"))
19
+ e.res.headers.set("cache-control", REDIRECT_CACHE_CONTROL);
20
+ return sendRedirect(e, appendSearch(location, e.url.search), rule.statusCode);
21
+ });
@@ -1,2 +1,2 @@
1
- declare const _default: any;
1
+ declare const _default: import("nuxt/server").EventHandler<Promise<NonSharedBuffer | undefined>>;
2
2
  export default _default;
@@ -1,16 +1,15 @@
1
1
  import fs from "node:fs";
2
- import { parseURL } from "ufo";
3
- import { defineEventHandler, setHeader } from "#nuxtseo/h3";
2
+ import { defineEventHandler } from "nuxt/server";
4
3
  import { fileMapping } from "#seo-utils-virtual/pageDirImages";
5
4
  export default defineEventHandler(async (e) => {
6
- const path = parseURL(e.path).pathname;
5
+ const path = e.url.pathname;
7
6
  if (fileMapping[path]) {
8
7
  if (path.endsWith(".svg"))
9
- setHeader(e, "Content-Type", "image/svg+xml");
8
+ e.res.headers.set("Content-Type", "image/svg+xml");
10
9
  else if (path.endsWith(".png"))
11
- setHeader(e, "Content-Type", "image/png");
10
+ e.res.headers.set("Content-Type", "image/png");
12
11
  else if (path.endsWith(".jpg") || path.endsWith(".jpeg"))
13
- setHeader(e, "Content-Type", "image/jpeg");
12
+ e.res.headers.set("Content-Type", "image/jpeg");
14
13
  return fs.readFileSync(fileMapping[path]);
15
14
  }
16
15
  });
@@ -1,5 +1,5 @@
1
1
  import { defineNitroPlugin } from "#nuxtseo/nitro";
2
- import { JSON_TYPES, minifyCSS, minifyJS, minifyJSON, SKIP_JS_TYPES } from "../../shared/minify.js";
2
+ import { JSON_TYPES, minifyCSS, minifyJSON } from "../../shared/minify.js";
3
3
  const INLINE_SCRIPT_RE = /<script(?![^>]+\bsrc\b)([^>]*)>([\s\S]*?)<\/script\s*>/gi;
4
4
  const INLINE_STYLE_RE = /<style([^>]*)>([\s\S]*?)<\/style\s*>/gi;
5
5
  const TYPE_ATTR_RE = /\btype\s*=\s*["']([^"']*)["']/i;
@@ -16,14 +16,7 @@ function minifyChunk(chunk) {
16
16
  return full;
17
17
  }
18
18
  }
19
- if (type && SKIP_JS_TYPES.has(type))
20
- return full;
21
- try {
22
- const m = minifyJS(content);
23
- return m.length < content.length ? `<script${attrs}>${m}<\/script>` : full;
24
- } catch {
25
- return full;
26
- }
19
+ return full;
27
20
  });
28
21
  out = out.replace(INLINE_STYLE_RE, (full, attrs, content) => {
29
22
  if (!content)
@@ -1,2 +1,28 @@
1
- declare const _default: any;
1
+ declare const _default: import("nuxt/server").EventHandler<{
2
+ runtimeConfig: {
3
+ canonicalQueryWhitelist: string[];
4
+ canonicalLowercase: boolean;
5
+ automaticTwitterTags: boolean;
6
+ tagPriority: import("@unhead/vue").UseHeadOptions["tagPriority"];
7
+ separator?: string;
8
+ titleSeparator?: string;
9
+ colorModeIcons?: import("../../../types.js").ColorModeIconLinks;
10
+ version: {};
11
+ appBaseURL: string;
12
+ };
13
+ siteConfig: {
14
+ url: string;
15
+ name: any;
16
+ description: any;
17
+ env: any;
18
+ indexable: any;
19
+ trailingSlash: any;
20
+ titleSeparator: any;
21
+ defaultLocale: any;
22
+ currentLocale: any;
23
+ twitter: any;
24
+ };
25
+ headConfig: {};
26
+ path: string | string[];
27
+ }>;
2
28
  export default _default;
@@ -1,9 +1,8 @@
1
- import { defineEventHandler, getQuery } from "#nuxtseo/h3";
2
- import { useRuntimeConfig } from "#nuxtseo/nitro";
1
+ import { defineEventHandler, getQuery, useRuntimeConfig } from "nuxt/server";
3
2
  import { getSiteConfig } from "#site-config/server/composables";
4
3
  export default defineEventHandler((e) => {
5
4
  const siteConfig = getSiteConfig(e);
6
- const runtimeConfig = useRuntimeConfig(e);
5
+ const runtimeConfig = useRuntimeConfig();
7
6
  const seoUtils = runtimeConfig.public?.["seo-utils"] || {};
8
7
  const headConfig = runtimeConfig["seo-utils-head"] || { link: [], meta: [] };
9
8
  const query = getQuery(e);
@@ -1,10 +1,4 @@
1
1
  export declare const JSON_TYPES: Set<string>;
2
- export declare const SKIP_JS_TYPES: Set<string>;
3
- /**
4
- * Lightweight JS minifier in pure JS (no native deps).
5
- * Strips comments and collapses whitespace while preserving string literals.
6
- */
7
- export declare function minifyJS(code: string): string;
8
2
  /**
9
3
  * Lightweight CSS minifier in pure JS (no native deps).
10
4
  * Strips comments and collapses whitespace while preserving string literals.
@@ -1,62 +1,5 @@
1
1
  export const JSON_TYPES = /* @__PURE__ */ new Set(["application/json", "application/ld+json"]);
2
- export const SKIP_JS_TYPES = /* @__PURE__ */ new Set(["application/json", "application/ld+json", "speculationrules", "importmap"]);
3
- const JS_MINIFY_CANDIDATE_RE = /[\s/]/;
4
2
  const CSS_MINIFY_CANDIDATE_RE = /[\s/]|;\}|0\.\d/;
5
- export function minifyJS(code) {
6
- if (!JS_MINIFY_CANDIDATE_RE.test(code))
7
- return code;
8
- let result = "";
9
- let last = "";
10
- let i = 0;
11
- const len = code.length;
12
- const append = (value) => {
13
- result += value;
14
- last = value;
15
- };
16
- while (i < len) {
17
- const ch = code[i];
18
- if (ch === "'" || ch === '"' || ch === "`") {
19
- const quote = ch;
20
- append(ch);
21
- i++;
22
- while (i < len && code[i] !== quote) {
23
- if (code[i] === "\\") {
24
- append(code[i++]);
25
- }
26
- append(code[i++]);
27
- }
28
- if (i < len)
29
- append(code[i++]);
30
- } else if (ch === "/" && code[i + 1] === "/") {
31
- i += 2;
32
- while (i < len && code[i] !== "\n")
33
- i++;
34
- } else if (ch === "/" && code[i + 1] === "*") {
35
- i += 2;
36
- while (i < len && !(code[i] === "*" && code[i + 1] === "/"))
37
- i++;
38
- i += 2;
39
- } else if (ch === " " || ch === " " || ch === "\n" || ch === "\r") {
40
- let hasNewline = false;
41
- while (i < len && (code[i] === " " || code[i] === " " || code[i] === "\n" || code[i] === "\r")) {
42
- if (code[i] === "\n")
43
- hasNewline = true;
44
- i++;
45
- }
46
- const next = code[i];
47
- if (hasNewline && last && next && last !== "{" && last !== "}" && last !== ";" && next !== "}" && next !== ";")
48
- append("\n");
49
- else if (last && next && isIdentChar(last) && isIdentChar(next))
50
- append(" ");
51
- else if (last && next && (last === "+" && next === "+" || last === "-" && next === "-"))
52
- append(" ");
53
- } else {
54
- append(ch);
55
- i++;
56
- }
57
- }
58
- return result.trim();
59
- }
60
3
  export function minifyCSS(code) {
61
4
  if (!CSS_MINIFY_CANDIDATE_RE.test(code))
62
5
  return code;
@@ -132,9 +75,6 @@ export function minifyCSS(code) {
132
75
  }
133
76
  return result.trim();
134
77
  }
135
- function isIdentChar(ch) {
136
- return ch >= "a" && ch <= "z" || ch >= "A" && ch <= "Z" || ch >= "0" && ch <= "9" || ch === "_" || ch === "$";
137
- }
138
78
  function isCSSBasePunctuation(ch) {
139
79
  return ch === "{" || ch === "}" || ch === ";" || ch === ":" || ch === ",";
140
80
  }
@@ -0,0 +1,40 @@
1
+ /** How an entry key matches request paths. `/old/**` matches `/old` and every path below it. */
2
+ export type SourcePattern = {
3
+ _tag: 'Exact';
4
+ path: string;
5
+ } | {
6
+ _tag: 'Prefix';
7
+ prefix: string;
8
+ };
9
+ /** The part of an entry the server needs to answer a request. */
10
+ export type RedirectRule = {
11
+ _tag: 'Moved';
12
+ pattern: SourcePattern;
13
+ to: string;
14
+ statusCode: 301 | 308;
15
+ } | {
16
+ _tag: 'Gone';
17
+ pattern: SourcePattern;
18
+ statusCode: 410 | 404;
19
+ };
20
+ export type MovedRule = Extract<RedirectRule, {
21
+ _tag: 'Moved';
22
+ }>;
23
+ /** Without a max-age, Chromium caches a 301 or 308 forever, so a later fix or removal never reaches returning visitors. */
24
+ export declare const REDIRECT_CACHE_CONTROL = "public, max-age=3600";
25
+ export declare function normalizePath(path: string): string;
26
+ export declare function isAbsoluteUrl(to: string): boolean;
27
+ /** Parse an entry key into a pattern, or return why the key is invalid. */
28
+ export declare function parseSourcePattern(source: string): SourcePattern | string;
29
+ export declare function matchesSource(pattern: SourcePattern, path: string): boolean;
30
+ /**
31
+ * Index entries for lookup. An exact entry wins, then the longest matching prefix.
32
+ * The path must not include `app.baseURL`, the query string, or the hash.
33
+ */
34
+ export declare function createRedirectMatcher<T extends {
35
+ pattern: SourcePattern;
36
+ }>(entries: readonly T[]): (path: string) => T | undefined;
37
+ /** The target for a request path. A target ending in `/**` gets the path below the source prefix. */
38
+ export declare function resolveTarget(rule: MovedRule, path: string): string;
39
+ /** Keep the request query string. A query on the target comes first. */
40
+ export declare function appendSearch(target: string, search: string): string;