@ingram-tech/nk-seo 0.5.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -27,7 +27,9 @@ components live at `@ingram-tech/nk-seo/components`.
27
27
  bun add @ingram-tech/nk-seo
28
28
  ```
29
29
 
30
- `next` and `react` are optional peers (only the components need them).
30
+ `next` and `react` are optional peers the package root is runtime-free of
31
+ both; the `/components` and `/og` entries need them (`/og` uses `next/og` and
32
+ the React JSX runtime).
31
33
 
32
34
  ## Structured data
33
35
 
@@ -184,14 +186,22 @@ each `opengraph-image.tsx` and asserts a valid PNG comes out.
184
186
  ## Hreflang & canonical
185
187
 
186
188
  Render in `<head>` from the root layout. By default it reads the `x-pathname`
187
- request header — set it in middleware:
189
+ request header — set it on the **forwarded request** in middleware (setting it
190
+ on the response does nothing: `headers()` in a server component reads incoming
191
+ request headers):
188
192
 
189
193
  ```ts
190
194
  // middleware.ts
191
- const res = NextResponse.next();
192
- res.headers.set("x-pathname", req.nextUrl.pathname);
195
+ const requestHeaders = new Headers(req.headers);
196
+ requestHeaders.set("x-pathname", req.nextUrl.pathname);
197
+ return NextResponse.next({ request: { headers: requestHeaders } });
193
198
  ```
194
199
 
200
+ Copying `req.headers` first also overwrites any client-spoofed `x-pathname`.
201
+ Note that reading the header (`headers()`) opts the page into dynamic
202
+ rendering — pass `pathname` explicitly (e.g. from route params) on pages that
203
+ must stay static.
204
+
195
205
  ```tsx
196
206
  import { HreflangLinks } from "@ingram-tech/nk-seo/components";
197
207
 
@@ -218,6 +228,11 @@ Two rules of the road:
218
228
 
219
229
  - **One canonical per page.** If your pages already set `alternates.canonical`
220
230
  (e.g. via `createMetadata`), render `<HreflangLinks canonical={false} />`.
231
+ - **The canonical must self-reference.** A localized variant that
232
+ canonicalizes to a different URL makes Google discard the whole hreflang
233
+ cluster. The prefix strategy auto-detects the current locale from the
234
+ (possibly `/fr/…`-prefixed) pathname; the query strategy can't see the query
235
+ string server-side, so pass `currentLocale` from your locale negotiation.
221
236
  - Building metadata instead of rendering links? The pure `hreflangAlternates`
222
237
  (package root) returns the same `{ canonical, links }` for use in
223
238
  `generateMetadata`.
@@ -19,6 +19,14 @@ export interface HreflangConfig {
19
19
  param?: string;
20
20
  /** Default (unprefixed) locale for the `"prefix"` strategy. */
21
21
  defaultLocale?: string;
22
+ /**
23
+ * Locale of the page being rendered. Determines the self-referencing
24
+ * canonical: a localized variant that canonicalizes to another URL makes
25
+ * Google discard the entire hreflang cluster. For the `"prefix"` strategy it
26
+ * is auto-detected from the pathname; for `"query"` the server can't see the
27
+ * query string, so pass it (e.g. from your locale negotiation).
28
+ */
29
+ currentLocale?: string;
22
30
  /** Optional locale → hreflang tag map, e.g. `{ en: "en-BE", fr: "fr-BE" }`. */
23
31
  hrefLangTags?: Record<string, string>;
24
32
  }
@@ -1 +1 @@
1
- {"version":3,"file":"alternates.d.ts","sourceRoot":"","sources":["../src/alternates.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC9B,yDAAyD;IACzD,OAAO,EAAE,MAAM,CAAC;IAChB,+DAA+D;IAC/D,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC9B,mEAAmE;IACnE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+DAA+D;IAC/D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,+EAA+E;IAC/E,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACtC;AAED,MAAM,WAAW,YAAY;IAC5B,gEAAgE;IAChE,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,kBAAkB;IAClC,oDAAoD;IACpD,SAAS,EAAE,MAAM,CAAC;IAClB,wEAAwE;IACxE,KAAK,EAAE,YAAY,EAAE,CAAC;CACtB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CACjC,MAAM,EAAE,cAAc,EACtB,QAAQ,EAAE,MAAM,GACd,kBAAkB,CAyBpB"}
1
+ {"version":3,"file":"alternates.d.ts","sourceRoot":"","sources":["../src/alternates.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC9B,yDAAyD;IACzD,OAAO,EAAE,MAAM,CAAC;IAChB,+DAA+D;IAC/D,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC9B,mEAAmE;IACnE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+DAA+D;IAC/D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,+EAA+E;IAC/E,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACtC;AAED,MAAM,WAAW,YAAY;IAC5B,gEAAgE;IAChE,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,kBAAkB;IAClC,oDAAoD;IACpD,SAAS,EAAE,MAAM,CAAC;IAClB,wEAAwE;IACxE,KAAK,EAAE,YAAY,EAAE,CAAC;CACtB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CACjC,MAAM,EAAE,cAAc,EACtB,QAAQ,EAAE,MAAM,GACd,kBAAkB,CA2DpB"}
@@ -5,17 +5,46 @@ import { absoluteUrl } from "./url.js";
5
5
  */
6
6
  export function hreflangAlternates(config, pathname) {
7
7
  const { strategy = "query", param = "hl", defaultLocale, hrefLangTags } = config;
8
- const canonical = absoluteUrl(pathname, config.baseUrl);
8
+ if (strategy === "prefix" && !defaultLocale) {
9
+ // Without it every locale gets a prefix while canonical/x-default point
10
+ // at a bare path that is no locale's URL — a silent SEO bug.
11
+ throw new Error("hreflangAlternates: `defaultLocale` is required for the prefix strategy.");
12
+ }
13
+ // Prefix strategy: accept both the bare and the locale-prefixed form of the
14
+ // path (middleware's `x-pathname` carries the latter on a real localized
15
+ // route — blindly prepending would emit /fr/fr/about) and detect the
16
+ // current locale from it.
17
+ let basePath = pathname;
18
+ let currentLocale = config.currentLocale;
19
+ if (strategy === "prefix") {
20
+ for (const locale of config.locales) {
21
+ if (pathname === `/${locale}` || pathname.startsWith(`/${locale}/`)) {
22
+ basePath = pathname.slice(locale.length + 1) || "/";
23
+ currentLocale ??= locale;
24
+ break;
25
+ }
26
+ }
27
+ currentLocale ??= defaultLocale;
28
+ }
29
+ /** The default-locale URL — the bare path; also serves as x-default. */
30
+ const defaultUrl = absoluteUrl(basePath, config.baseUrl);
9
31
  const hrefFor = (locale) => {
10
32
  if (strategy === "prefix") {
11
- if (defaultLocale && locale === defaultLocale) {
12
- return canonical;
13
- }
14
- const clean = pathname === "/" ? "" : pathname;
33
+ if (locale === defaultLocale)
34
+ return defaultUrl;
35
+ const clean = basePath === "/" ? "" : basePath;
15
36
  return absoluteUrl(`/${locale}${clean}`, config.baseUrl);
16
37
  }
17
- return `${canonical}?${param}=${locale}`;
38
+ return `${defaultUrl}${defaultUrl.includes("?") ? "&" : "?"}${param}=${locale}`;
18
39
  };
40
+ // Self-referencing canonical: the current variant's own URL. Canonicalizing
41
+ // a localized variant to the bare path makes Google treat the variants as
42
+ // duplicates and ignore the hreflang annotations entirely.
43
+ const canonical = currentLocale &&
44
+ currentLocale !== defaultLocale &&
45
+ config.locales.includes(currentLocale)
46
+ ? hrefFor(currentLocale)
47
+ : defaultUrl;
19
48
  return {
20
49
  canonical,
21
50
  links: [
@@ -23,7 +52,7 @@ export function hreflangAlternates(config, pathname) {
23
52
  hrefLang: hrefLangTags?.[locale] ?? locale,
24
53
  href: hrefFor(locale),
25
54
  })),
26
- { hrefLang: "x-default", href: canonical },
55
+ { hrefLang: "x-default", href: defaultUrl },
27
56
  ],
28
57
  };
29
58
  }
@@ -1 +1 @@
1
- {"version":3,"file":"alternates.js","sourceRoot":"","sources":["../src/alternates.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAwCvC;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CACjC,MAAsB,EACtB,QAAgB;IAEhB,MAAM,EAAE,QAAQ,GAAG,OAAO,EAAE,KAAK,GAAG,IAAI,EAAE,aAAa,EAAE,YAAY,EAAE,GAAG,MAAM,CAAC;IACjF,MAAM,SAAS,GAAG,WAAW,CAAC,QAAQ,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IAExD,MAAM,OAAO,GAAG,CAAC,MAAc,EAAU,EAAE;QAC1C,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAC3B,IAAI,aAAa,IAAI,MAAM,KAAK,aAAa,EAAE,CAAC;gBAC/C,OAAO,SAAS,CAAC;YAClB,CAAC;YACD,MAAM,KAAK,GAAG,QAAQ,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC;YAC/C,OAAO,WAAW,CAAC,IAAI,MAAM,GAAG,KAAK,EAAE,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;QAC1D,CAAC;QACD,OAAO,GAAG,SAAS,IAAI,KAAK,IAAI,MAAM,EAAE,CAAC;IAC1C,CAAC,CAAC;IAEF,OAAO;QACN,SAAS;QACT,KAAK,EAAE;YACN,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;gBAClC,QAAQ,EAAE,YAAY,EAAE,CAAC,MAAM,CAAC,IAAI,MAAM;gBAC1C,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC;aACrB,CAAC,CAAC;YACH,EAAE,QAAQ,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,EAAE;SAC1C;KACD,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"alternates.js","sourceRoot":"","sources":["../src/alternates.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAgDvC;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CACjC,MAAsB,EACtB,QAAgB;IAEhB,MAAM,EAAE,QAAQ,GAAG,OAAO,EAAE,KAAK,GAAG,IAAI,EAAE,aAAa,EAAE,YAAY,EAAE,GAAG,MAAM,CAAC;IACjF,IAAI,QAAQ,KAAK,QAAQ,IAAI,CAAC,aAAa,EAAE,CAAC;QAC7C,wEAAwE;QACxE,6DAA6D;QAC7D,MAAM,IAAI,KAAK,CACd,0EAA0E,CAC1E,CAAC;IACH,CAAC;IAED,4EAA4E;IAC5E,yEAAyE;IACzE,qEAAqE;IACrE,0BAA0B;IAC1B,IAAI,QAAQ,GAAG,QAAQ,CAAC;IACxB,IAAI,aAAa,GAAG,MAAM,CAAC,aAAa,CAAC;IACzC,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC3B,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YACrC,IAAI,QAAQ,KAAK,IAAI,MAAM,EAAE,IAAI,QAAQ,CAAC,UAAU,CAAC,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;gBACrE,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,GAAG,CAAC;gBACpD,aAAa,KAAK,MAAM,CAAC;gBACzB,MAAM;YACP,CAAC;QACF,CAAC;QACD,aAAa,KAAK,aAAa,CAAC;IACjC,CAAC;IAED,wEAAwE;IACxE,MAAM,UAAU,GAAG,WAAW,CAAC,QAAQ,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IAEzD,MAAM,OAAO,GAAG,CAAC,MAAc,EAAU,EAAE;QAC1C,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAC3B,IAAI,MAAM,KAAK,aAAa;gBAAE,OAAO,UAAU,CAAC;YAChD,MAAM,KAAK,GAAG,QAAQ,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC;YAC/C,OAAO,WAAW,CAAC,IAAI,MAAM,GAAG,KAAK,EAAE,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;QAC1D,CAAC;QACD,OAAO,GAAG,UAAU,GAAG,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,KAAK,IAAI,MAAM,EAAE,CAAC;IACjF,CAAC,CAAC;IAEF,4EAA4E;IAC5E,0EAA0E;IAC1E,2DAA2D;IAC3D,MAAM,SAAS,GACd,aAAa;QACb,aAAa,KAAK,aAAa;QAC/B,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC;QACrC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC;QACxB,CAAC,CAAC,UAAU,CAAC;IAEf,OAAO;QACN,SAAS;QACT,KAAK,EAAE;YACN,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;gBAClC,QAAQ,EAAE,YAAY,EAAE,CAAC,MAAM,CAAC,IAAI,MAAM;gBAC1C,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC;aACrB,CAAC,CAAC;YACH,EAAE,QAAQ,EAAE,WAAW,EAAE,IAAI,EAAE,UAAU,EAAE;SAC3C;KACD,CAAC;AACH,CAAC"}
@@ -1,9 +1,19 @@
1
1
  import { type HreflangConfig } from "./alternates.js";
2
2
  export interface HreflangLinksProps extends HreflangConfig {
3
3
  /**
4
- * Path being rendered. Defaults to the `x-pathname` request header (set it in
5
- * middleware: `headers.set("x-pathname", req.nextUrl.pathname)`). Pass
6
- * explicitly if you don't use that header (e.g. from route params).
4
+ * Path being rendered. Defaults to the `x-pathname` REQUEST header it must
5
+ * be set on the forwarded request in middleware (a response header is
6
+ * invisible to `headers()`):
7
+ *
8
+ * ```ts
9
+ * const requestHeaders = new Headers(req.headers);
10
+ * requestHeaders.set("x-pathname", req.nextUrl.pathname);
11
+ * return NextResponse.next({ request: { headers: requestHeaders } });
12
+ * ```
13
+ *
14
+ * Pass explicitly if you don't use that header (e.g. from route params) —
15
+ * also the only way to keep the page statically renderable, since reading
16
+ * `headers()` opts the page into dynamic rendering.
7
17
  */
8
18
  pathname?: string;
9
19
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"hreflang.d.ts","sourceRoot":"","sources":["../src/hreflang.tsx"],"names":[],"mappings":"AACA,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAE1E,MAAM,WAAW,kBAAmB,SAAQ,cAAc;IACzD;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;;;GAQG;AACH,wBAAsB,aAAa,CAAC,EACnC,QAAQ,EACR,SAAgB,EAChB,GAAG,MAAM,EACT,EAAE,kBAAkB,wCAwBpB"}
1
+ {"version":3,"file":"hreflang.d.ts","sourceRoot":"","sources":["../src/hreflang.tsx"],"names":[],"mappings":"AACA,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAE1E,MAAM,WAAW,kBAAmB,SAAQ,cAAc;IACzD;;;;;;;;;;;;;;OAcG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;;;GAQG;AACH,wBAAsB,aAAa,CAAC,EACnC,QAAQ,EACR,SAAgB,EAChB,GAAG,MAAM,EACT,EAAE,kBAAkB,wCA4BpB"}
package/dist/hreflang.js CHANGED
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { headers } from "next/headers";
3
3
  import { hreflangAlternates } from "./alternates.js";
4
4
  /**
@@ -14,10 +14,12 @@ export async function HreflangLinks({ pathname, canonical = true, ...config }) {
14
14
  const path = pathname ?? (await headers()).get("x-pathname");
15
15
  if (!path) {
16
16
  throw new Error("HreflangLinks: no `pathname` prop and no `x-pathname` request header. " +
17
- 'Set the header in middleware (`res.headers.set("x-pathname", req.nextUrl.pathname)`) ' +
18
- "or pass `pathname` explicitly.");
17
+ "Set it on the forwarded REQUEST in middleware " +
18
+ '`const h = new Headers(req.headers); h.set("x-pathname", req.nextUrl.pathname); ' +
19
+ "return NextResponse.next({ request: { headers: h } });` — " +
20
+ "(a response header is invisible to `headers()`), or pass `pathname` explicitly.");
19
21
  }
20
22
  const { canonical: canonicalUrl, links } = hreflangAlternates(config, path);
21
- return (_jsxs(_Fragment, { children: [canonical ? _jsx("link", { rel: "canonical", href: canonicalUrl }) : null, links.map((link) => (_jsx("link", { rel: "alternate", hrefLang: link.hrefLang, href: link.href }, link.hrefLang)))] }));
23
+ return (_jsxs(_Fragment, { children: [canonical ? _jsx("link", { rel: "canonical", href: canonicalUrl }) : null, links.map((link) => (_jsx("link", { rel: "alternate", hrefLang: link.hrefLang, href: link.href }, `${link.hrefLang} ${link.href}`)))] }));
22
24
  }
23
25
  //# sourceMappingURL=hreflang.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"hreflang.js","sourceRoot":"","sources":["../src/hreflang.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,kBAAkB,EAAuB,MAAM,iBAAiB,CAAC;AAiB1E;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,EACnC,QAAQ,EACR,SAAS,GAAG,IAAI,EAChB,GAAG,MAAM,EACW;IACpB,MAAM,IAAI,GAAG,QAAQ,IAAI,CAAC,MAAM,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IAC7D,IAAI,CAAC,IAAI,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CACd,wEAAwE;YACvE,uFAAuF;YACvF,gCAAgC,CACjC,CAAC;IACH,CAAC;IACD,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,KAAK,EAAE,GAAG,kBAAkB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAE5E,OAAO,CACN,8BACE,SAAS,CAAC,CAAC,CAAC,eAAM,GAAG,EAAC,WAAW,EAAC,IAAI,EAAE,YAAY,GAAI,CAAC,CAAC,CAAC,IAAI,EAC/D,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CACpB,eAEC,GAAG,EAAC,WAAW,EACf,QAAQ,EAAE,IAAI,CAAC,QAAQ,EACvB,IAAI,EAAE,IAAI,CAAC,IAAI,IAHV,IAAI,CAAC,QAAQ,CAIjB,CACF,CAAC,IACA,CACH,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"hreflang.js","sourceRoot":"","sources":["../src/hreflang.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,kBAAkB,EAAuB,MAAM,iBAAiB,CAAC;AA2B1E;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,EACnC,QAAQ,EACR,SAAS,GAAG,IAAI,EAChB,GAAG,MAAM,EACW;IACpB,MAAM,IAAI,GAAG,QAAQ,IAAI,CAAC,MAAM,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IAC7D,IAAI,CAAC,IAAI,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CACd,wEAAwE;YACvE,kDAAkD;YAClD,kFAAkF;YAClF,4DAA4D;YAC5D,iFAAiF,CAClF,CAAC;IACH,CAAC;IACD,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,KAAK,EAAE,GAAG,kBAAkB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAE5E,OAAO,CACN,8BACE,SAAS,CAAC,CAAC,CAAC,eAAM,GAAG,EAAC,WAAW,EAAC,IAAI,EAAE,YAAY,GAAI,CAAC,CAAC,CAAC,IAAI,EAC/D,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CACpB,eAIC,GAAG,EAAC,WAAW,EACf,QAAQ,EAAE,IAAI,CAAC,QAAQ,EACvB,IAAI,EAAE,IAAI,CAAC,IAAI,IAHV,GAAG,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,IAAI,EAAE,CAInC,CACF,CAAC,IACA,CACH,CAAC;AACH,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"json-ld.d.ts","sourceRoot":"","sources":["../src/json-ld.tsx"],"names":[],"mappings":"AAUA,eAAO,MAAM,eAAe,GAAI,MAAM,MAAM,GAAG,MAAM,EAAE,KAAG,MAMtD,CAAC;AAEL;;;;;;;GAOG;AACH,wBAAgB,MAAM,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;CAAE,+BAQ3D"}
1
+ {"version":3,"file":"json-ld.d.ts","sourceRoot":"","sources":["../src/json-ld.tsx"],"names":[],"mappings":"AAUA,eAAO,MAAM,eAAe,SAAU,MAAM,GAAG,MAAM,EAAE,KAAG,MAMtD,CAAC;AAEL;;;;;;;GAOG;AACH,wBAAgB,MAAM,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;CAAE,+BAQ3D"}
@@ -71,7 +71,7 @@ export interface RootMetadataInput {
71
71
  */
72
72
  export declare function createMetadata(site: MetadataSiteConfig): {
73
73
  (input: PageMetadataInput): Metadata;
74
- root(input?: RootMetadataInput): Metadata;
74
+ root: (input?: RootMetadataInput) => Metadata;
75
75
  };
76
76
  export type PageMetadata = ReturnType<typeof createMetadata>;
77
77
  //# sourceMappingURL=metadata.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"metadata.d.ts","sourceRoot":"","sources":["../src/metadata.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,MAAM,CAAC;AAGrC;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAClC,wDAAwD;IACxD,OAAO,EAAE,MAAM,CAAC;IAChB,4BAA4B;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,0DAA0D;IAC1D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,sCAAsC;IACtC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oCAAoC;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uCAAuC;IACvC,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,6DAA6D;AAC7D,MAAM,WAAW,iBAAiB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,sFAAsF;IACtF,IAAI,EAAE,MAAM,CAAC;IACb,oEAAoE;IACpE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;IAC7B,QAAQ,CAAC,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAC;IAChC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,gEAAgE;IAChE,SAAS,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IACxD,8DAA8D;IAC9D,OAAO,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;CACpD;AAED,mEAAmE;AACnE,MAAM,WAAW,iBAAiB;IACjC,2EAA2E;IAC3E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4EAA4E;IAC5E,SAAS,CAAC,EAAE,QAAQ,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,kBAAkB;YAGzB,iBAAiB,GAAG,QAAQ;iBA6CR,iBAAiB,GAAQ,QAAQ;EAalF;AAED,MAAM,MAAM,YAAY,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC"}
1
+ {"version":3,"file":"metadata.d.ts","sourceRoot":"","sources":["../src/metadata.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,MAAM,CAAC;AAGrC;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAClC,wDAAwD;IACxD,OAAO,EAAE,MAAM,CAAC;IAChB,4BAA4B;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,0DAA0D;IAC1D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,sCAAsC;IACtC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oCAAoC;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uCAAuC;IACvC,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,6DAA6D;AAC7D,MAAM,WAAW,iBAAiB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,sFAAsF;IACtF,IAAI,EAAE,MAAM,CAAC;IACb,oEAAoE;IACpE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;IAC7B,QAAQ,CAAC,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAC;IAChC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,gEAAgE;IAChE,SAAS,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IACxD,8DAA8D;IAC9D,OAAO,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;CACpD;AAED,mEAAmE;AACnE,MAAM,WAAW,iBAAiB;IACjC,2EAA2E;IAC3E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4EAA4E;IAC5E,SAAS,CAAC,EAAE,QAAQ,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,kBAAkB;YAGzB,iBAAiB,GAAG,QAAQ;mBA+CR,iBAAiB,KAAQ,QAAQ;EAalF;AAED,MAAM,MAAM,YAAY,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC"}
package/dist/metadata.js CHANGED
@@ -33,7 +33,9 @@ export function createMetadata(site) {
33
33
  description: input.description,
34
34
  ...(input.keywords ? { keywords: input.keywords } : {}),
35
35
  alternates: { canonical: url },
36
- ...(input.noIndex ? { robots: { index: false, follow: false } } : {}),
36
+ // noindex but follow: keep link equity flowing through the page. Use a
37
+ // full robots override in the page's own metadata for nofollow too.
38
+ ...(input.noIndex ? { robots: { index: false, follow: true } } : {}),
37
39
  openGraph: {
38
40
  title: input.title,
39
41
  description: input.description,
@@ -1 +1 @@
1
- {"version":3,"file":"metadata.js","sourceRoot":"","sources":["../src/metadata.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"metadata.js","sourceRoot":"","sources":["../src/metadata.ts"],"names":[],"mappings":"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"}
package/dist/routes.d.ts CHANGED
@@ -63,7 +63,11 @@ export interface RobotsConfig {
63
63
  * from `VERCEL_ENV === "production"` (and/or a host check).
64
64
  */
65
65
  isProduction: boolean;
66
- /** Prod-only disallow list (private routes, APIs, auth flows). */
66
+ /**
67
+ * Prod-only disallow list (private routes, APIs, auth flows). Entries that
68
+ * would block `/_next` are rejected: crawlers must reach the JS/CSS under it
69
+ * to render pages, so disallowing it silently harms indexing.
70
+ */
67
71
  disallow?: string[];
68
72
  /** Prod allow rule. Default "/". */
69
73
  allow?: string | string[];
@@ -1 +1 @@
1
- {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,MAAM,CAAC;AAG1C;;;;;;;;GAQG;AAEH,KAAK,eAAe,GAAG,WAAW,CAAC,aAAa,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC;AAErF,kEAAkE;AAClE,MAAM,MAAM,gBAAgB,GAAG,WAAW,CACzC,WAAW,CAAC,aAAa,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,WAAW,CAAC,CACrE,CAAC;AAEF,kEAAkE;AAClE,MAAM,WAAW,YAAY;IAC5B,+DAA+D;IAC/D,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,0FAA0F;IAC1F,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,SAAS,CAAC,EAAE,gBAAgB,CAAC;CAC7B;AAED,MAAM,WAAW,aAAa;IAC7B,wDAAwD;IACxD,OAAO,EAAE,MAAM,CAAC;IAChB,4EAA4E;IAC5E,MAAM,EAAE,KAAK,CAAC,MAAM,GAAG,YAAY,CAAC,CAAC;IACrC,kDAAkD;IAClD,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,qDAAqD;IACrD,sBAAsB,CAAC,EAAE,eAAe,CAAC;IACzC,yEAAyE;IACzE,eAAe,CAAC,EAAE,MAAM,CAAC;CACzB;AAeD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,GAAG,aAAa,CAAC,OAAO,CA6B1E;AAED,MAAM,WAAW,YAAY;IAC5B,wDAAwD;IACxD,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;OAKG;IACH,YAAY,EAAE,OAAO,CAAC;IACtB,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,oCAAoC;IACpC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC1B,kFAAkF;IAClF,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,aAAa,CAAC,MAAM,CAcvE"}
1
+ {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,MAAM,CAAC;AAG1C;;;;;;;;GAQG;AAEH,KAAK,eAAe,GAAG,WAAW,CAAC,aAAa,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC;AAErF,kEAAkE;AAClE,MAAM,MAAM,gBAAgB,GAAG,WAAW,CACzC,WAAW,CAAC,aAAa,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,WAAW,CAAC,CACrE,CAAC;AAEF,kEAAkE;AAClE,MAAM,WAAW,YAAY;IAC5B,+DAA+D;IAC/D,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,0FAA0F;IAC1F,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,SAAS,CAAC,EAAE,gBAAgB,CAAC;CAC7B;AAED,MAAM,WAAW,aAAa;IAC7B,wDAAwD;IACxD,OAAO,EAAE,MAAM,CAAC;IAChB,4EAA4E;IAC5E,MAAM,EAAE,KAAK,CAAC,MAAM,GAAG,YAAY,CAAC,CAAC;IACrC,kDAAkD;IAClD,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,qDAAqD;IACrD,sBAAsB,CAAC,EAAE,eAAe,CAAC;IACzC,yEAAyE;IACzE,eAAe,CAAC,EAAE,MAAM,CAAC;CACzB;AAeD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,GAAG,aAAa,CAAC,OAAO,CA6B1E;AAED,MAAM,WAAW,YAAY;IAC5B,wDAAwD;IACxD,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;OAKG;IACH,YAAY,EAAE,OAAO,CAAC;IACtB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,oCAAoC;IACpC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC1B,kFAAkF;IAClF,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,aAAa,CAAC,MAAM,CAwBvE"}
package/dist/routes.js CHANGED
@@ -65,6 +65,12 @@ export function createRobots(config) {
65
65
  if (!config.isProduction) {
66
66
  return { rules: { userAgent: "*", disallow: "/" } };
67
67
  }
68
+ const nextAsset = config.disallow?.find((path) => path.trim().replace(/^\//, "").startsWith("_next"));
69
+ if (nextAsset !== undefined) {
70
+ throw new Error(`createRobots: refusing to disallow "${nextAsset}". Blocking /_next stops ` +
71
+ "crawlers from fetching the JS/CSS they need to render your pages, which " +
72
+ "hurts indexing. Next.js does not block it by default and neither should you.");
73
+ }
68
74
  const sitemapPath = config.sitemapPath === undefined ? "/sitemap.xml" : config.sitemapPath;
69
75
  return {
70
76
  rules: {
@@ -1 +1 @@
1
- {"version":3,"file":"routes.js","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"routes.js","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"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"}
package/dist/url.d.ts CHANGED
@@ -3,6 +3,12 @@
3
3
  * pass through untouched. The one URL-resolution rule for the whole package —
4
4
  * every entry (builders, metadata, routes, hreflang) resolves through here so
5
5
  * they can't drift (e.g. trailing-slash `baseUrl` producing `//` paths).
6
+ *
7
+ * Throws when the input escapes the site origin. A protocol-relative path
8
+ * (`//evil.com/x` — which a request to `https://site//evil.com/x` puts into
9
+ * `req.nextUrl.pathname` and thus into `x-pathname`) or a scheme'd value
10
+ * (`javascript:…`) would otherwise flow straight into a canonical/hreflang
11
+ * link, an SEO-hijack primitive once cached. Loud beats poisoned.
6
12
  */
7
13
  export declare const absoluteUrl: (path: string, baseUrl: string) => string;
8
14
  //# sourceMappingURL=url.d.ts.map
package/dist/url.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"url.d.ts","sourceRoot":"","sources":["../src/url.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,eAAO,MAAM,WAAW,GAAI,MAAM,MAAM,EAAE,SAAS,MAAM,KAAG,MACS,CAAC"}
1
+ {"version":3,"file":"url.d.ts","sourceRoot":"","sources":["../src/url.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,WAAW,SAAU,MAAM,WAAW,MAAM,KAAG,MAU3D,CAAC"}
package/dist/url.js CHANGED
@@ -3,6 +3,21 @@
3
3
  * pass through untouched. The one URL-resolution rule for the whole package —
4
4
  * every entry (builders, metadata, routes, hreflang) resolves through here so
5
5
  * they can't drift (e.g. trailing-slash `baseUrl` producing `//` paths).
6
+ *
7
+ * Throws when the input escapes the site origin. A protocol-relative path
8
+ * (`//evil.com/x` — which a request to `https://site//evil.com/x` puts into
9
+ * `req.nextUrl.pathname` and thus into `x-pathname`) or a scheme'd value
10
+ * (`javascript:…`) would otherwise flow straight into a canonical/hreflang
11
+ * link, an SEO-hijack primitive once cached. Loud beats poisoned.
6
12
  */
7
- export const absoluteUrl = (path, baseUrl) => /^https?:\/\//.test(path) ? path : new URL(path, baseUrl).toString();
13
+ export const absoluteUrl = (path, baseUrl) => {
14
+ if (/^https?:\/\//.test(path))
15
+ return path;
16
+ const base = new URL(baseUrl);
17
+ const resolved = new URL(path, base);
18
+ if (resolved.origin !== base.origin) {
19
+ throw new Error(`@ingram-tech/nk-seo: "${path}" resolves outside the site origin ${base.origin}`);
20
+ }
21
+ return resolved.toString();
22
+ };
8
23
  //# sourceMappingURL=url.js.map
package/dist/url.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"url.js","sourceRoot":"","sources":["../src/url.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,IAAY,EAAE,OAAe,EAAU,EAAE,CACpE,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAC"}
1
+ {"version":3,"file":"url.js","sourceRoot":"","sources":["../src/url.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,IAAY,EAAE,OAAe,EAAU,EAAE;IACpE,IAAI,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAC3C,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;IAC9B,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACrC,IAAI,QAAQ,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC;QACrC,MAAM,IAAI,KAAK,CACd,yBAAyB,IAAI,sCAAsC,IAAI,CAAC,MAAM,EAAE,CAChF,CAAC;IACH,CAAC;IACD,OAAO,QAAQ,CAAC,QAAQ,EAAE,CAAC;AAC5B,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ingram-tech/nk-seo",
3
- "version": "0.5.0",
3
+ "version": "0.6.1",
4
4
  "description": "SEO primitives for Next.js sites: typed schema.org JSON-LD builders, a <JsonLd> tag, a Metadata factory (canonical + OG + Twitter), and configurable hreflang alternates.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -36,13 +36,13 @@
36
36
  "test": "vitest run"
37
37
  },
38
38
  "devDependencies": {
39
- "@ingram-tech/nk-dev": "0.2.4",
40
- "@types/node": "^26.0.1",
39
+ "@ingram-tech/nk-dev": "0.5.0",
40
+ "@types/node": "^26.1.1",
41
41
  "@types/react": "^19.2.17",
42
- "next": "^16.0.0",
42
+ "next": "^16.2.10",
43
43
  "react": "^19.2.7",
44
- "typescript": "^6.0.3",
45
- "vitest": "^4.1.9"
44
+ "typescript": "^7.0.2",
45
+ "vitest": "^4.1.10"
46
46
  },
47
47
  "peerDependencies": {
48
48
  "next": ">=14.0.0",