@coldbydefault/next-seo-lite 1.0.0 → 1.0.3
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 +21 -16
- package/dist/index.d.mts +23 -3
- package/dist/index.d.ts +23 -3
- package/dist/index.js +9 -4
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +9 -4
- package/dist/index.mjs.map +1 -1
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -10,10 +10,12 @@ It turns simple props into the full `Metadata` object Next.js expects — includ
|
|
|
10
10
|
## Features
|
|
11
11
|
|
|
12
12
|
- **Title suffixing** — `"Home"` becomes `"Home | MyBrand"` automatically.
|
|
13
|
-
- **
|
|
14
|
-
- **
|
|
13
|
+
- **Configurable separator** — use `" – "` or `" · "` instead of the default `"|"` via `titleSeparator`.
|
|
14
|
+
- **OpenGraph** — fills `og:title`, `og:description`, `og:image`, and `og:locale` in one call.
|
|
15
|
+
- **Twitter Cards** — automatically uses `summary_large_image` when an image is provided, falls back to `summary` otherwise.
|
|
15
16
|
- **Canonical URLs** — combine a `baseUrl` with a page `path` and you're done.
|
|
16
17
|
- **Default fallback image** — set once at the root, used everywhere you don't override it.
|
|
18
|
+
- **`noIndex` support** — mark private pages (`/dashboard`, `/checkout`) with a single flag.
|
|
17
19
|
- **Zero runtime dependencies** — only `next` as a peer dep (for types).
|
|
18
20
|
|
|
19
21
|
---
|
|
@@ -171,25 +173,28 @@ Page-level props always win over the global config.
|
|
|
171
173
|
|
|
172
174
|
### `SEOConfig`
|
|
173
175
|
|
|
174
|
-
| Prop
|
|
175
|
-
|
|
|
176
|
-
| `siteName`
|
|
177
|
-
| `baseUrl`
|
|
178
|
-
| `defaultImage`
|
|
176
|
+
| Prop | Type | Description |
|
|
177
|
+
| ---------------- | -------- | -------------------------------------------------------------------- |
|
|
178
|
+
| `siteName` | `string` | Appended to every title: `"Page \| SiteName"`. |
|
|
179
|
+
| `baseUrl` | `string` | Absolute base URL for canonical links, e.g. `"https://example.com"`. |
|
|
180
|
+
| `defaultImage` | `string` | Fallback OG / Twitter image URL. |
|
|
181
|
+
| `titleSeparator` | `string` | Separator between title and site name. Defaults to `"\|"`. |
|
|
182
|
+
| `locale` | `string` | Default `og:locale`, e.g. `"en_US"`. |
|
|
179
183
|
|
|
180
184
|
---
|
|
181
185
|
|
|
182
186
|
### `SEOProps`
|
|
183
187
|
|
|
184
|
-
| Prop
|
|
185
|
-
|
|
|
186
|
-
| `title`
|
|
187
|
-
| `description`
|
|
188
|
-
| `image`
|
|
189
|
-
| `path`
|
|
190
|
-
| `siteName`
|
|
191
|
-
| `baseUrl`
|
|
192
|
-
| `
|
|
188
|
+
| Prop | Type | Required | Description |
|
|
189
|
+
| ------------- | --------- | -------- | ------------------------------------------------------------------ |
|
|
190
|
+
| `title` | `string` | ✅ | Page title (without suffix). |
|
|
191
|
+
| `description` | `string` | ✅ | Short page description. |
|
|
192
|
+
| `image` | `string` | — | Overrides `defaultImage`. |
|
|
193
|
+
| `path` | `string` | — | Slug appended to `baseUrl` for the canonical URL, e.g. `"/about"`. |
|
|
194
|
+
| `siteName` | `string` | — | Overrides global `siteName`. Pass `""` to suppress the suffix. |
|
|
195
|
+
| `baseUrl` | `string` | — | Overrides global `baseUrl`. |
|
|
196
|
+
| `noIndex` | `boolean` | — | Sets `robots: { index: false, follow: false }` when `true`. |
|
|
197
|
+
| `locale` | `string` | — | Overrides global `locale` for `og:locale`, e.g. `"fr_FR"`. |
|
|
193
198
|
|
|
194
199
|
---
|
|
195
200
|
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { Metadata } from 'next';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* @Author ColdByDefault 2026
|
|
5
|
+
* @MIT License
|
|
6
|
+
*/
|
|
7
|
+
|
|
3
8
|
/**
|
|
4
9
|
* Global defaults applied to every page when you don't override them.
|
|
5
10
|
* Pass this once at the root layout level via `createSEOConfig`.
|
|
@@ -11,6 +16,16 @@ interface SEOConfig {
|
|
|
11
16
|
baseUrl?: string;
|
|
12
17
|
/** Fallback OG/Twitter image URL used when a page omits its own image. */
|
|
13
18
|
defaultImage?: string;
|
|
19
|
+
/**
|
|
20
|
+
* Character(s) placed between the page title and site name.
|
|
21
|
+
* Defaults to `"|"` → `"Home | MyBrand"`.
|
|
22
|
+
*/
|
|
23
|
+
titleSeparator?: string;
|
|
24
|
+
/**
|
|
25
|
+
* Default `og:locale` value, e.g. `"en_US"`.
|
|
26
|
+
* Can be overridden per-page via `SEOProps.locale`.
|
|
27
|
+
*/
|
|
28
|
+
locale?: string;
|
|
14
29
|
}
|
|
15
30
|
/**
|
|
16
31
|
* Per-page SEO props passed to `defineSEO`.
|
|
@@ -21,7 +36,7 @@ interface SEOProps {
|
|
|
21
36
|
/** Short description shown in search results and social previews. */
|
|
22
37
|
description: string;
|
|
23
38
|
/**
|
|
24
|
-
* Absolute
|
|
39
|
+
* Absolute URL for this page's OG/Twitter image.
|
|
25
40
|
* Falls back to `SEOConfig.defaultImage` when omitted.
|
|
26
41
|
*/
|
|
27
42
|
image?: string;
|
|
@@ -40,9 +55,14 @@ interface SEOProps {
|
|
|
40
55
|
*/
|
|
41
56
|
baseUrl?: string;
|
|
42
57
|
/**
|
|
43
|
-
*
|
|
58
|
+
* When `true`, sets `robots: { index: false, follow: false }`.
|
|
59
|
+
* Use for private pages like /dashboard, /checkout, /thank-you.
|
|
44
60
|
*/
|
|
45
|
-
|
|
61
|
+
noIndex?: boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Override `og:locale` for this specific page, e.g. `"fr_FR"`.
|
|
64
|
+
*/
|
|
65
|
+
locale?: string;
|
|
46
66
|
}
|
|
47
67
|
/**
|
|
48
68
|
* Creates a `defineSEO` function pre-loaded with your global defaults.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { Metadata } from 'next';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* @Author ColdByDefault 2026
|
|
5
|
+
* @MIT License
|
|
6
|
+
*/
|
|
7
|
+
|
|
3
8
|
/**
|
|
4
9
|
* Global defaults applied to every page when you don't override them.
|
|
5
10
|
* Pass this once at the root layout level via `createSEOConfig`.
|
|
@@ -11,6 +16,16 @@ interface SEOConfig {
|
|
|
11
16
|
baseUrl?: string;
|
|
12
17
|
/** Fallback OG/Twitter image URL used when a page omits its own image. */
|
|
13
18
|
defaultImage?: string;
|
|
19
|
+
/**
|
|
20
|
+
* Character(s) placed between the page title and site name.
|
|
21
|
+
* Defaults to `"|"` → `"Home | MyBrand"`.
|
|
22
|
+
*/
|
|
23
|
+
titleSeparator?: string;
|
|
24
|
+
/**
|
|
25
|
+
* Default `og:locale` value, e.g. `"en_US"`.
|
|
26
|
+
* Can be overridden per-page via `SEOProps.locale`.
|
|
27
|
+
*/
|
|
28
|
+
locale?: string;
|
|
14
29
|
}
|
|
15
30
|
/**
|
|
16
31
|
* Per-page SEO props passed to `defineSEO`.
|
|
@@ -21,7 +36,7 @@ interface SEOProps {
|
|
|
21
36
|
/** Short description shown in search results and social previews. */
|
|
22
37
|
description: string;
|
|
23
38
|
/**
|
|
24
|
-
* Absolute
|
|
39
|
+
* Absolute URL for this page's OG/Twitter image.
|
|
25
40
|
* Falls back to `SEOConfig.defaultImage` when omitted.
|
|
26
41
|
*/
|
|
27
42
|
image?: string;
|
|
@@ -40,9 +55,14 @@ interface SEOProps {
|
|
|
40
55
|
*/
|
|
41
56
|
baseUrl?: string;
|
|
42
57
|
/**
|
|
43
|
-
*
|
|
58
|
+
* When `true`, sets `robots: { index: false, follow: false }`.
|
|
59
|
+
* Use for private pages like /dashboard, /checkout, /thank-you.
|
|
44
60
|
*/
|
|
45
|
-
|
|
61
|
+
noIndex?: boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Override `og:locale` for this specific page, e.g. `"fr_FR"`.
|
|
64
|
+
*/
|
|
65
|
+
locale?: string;
|
|
46
66
|
}
|
|
47
67
|
/**
|
|
48
68
|
* Creates a `defineSEO` function pre-loaded with your global defaults.
|
package/dist/index.js
CHANGED
|
@@ -35,8 +35,10 @@ function defineSEO(props) {
|
|
|
35
35
|
function buildMetadata(props, config) {
|
|
36
36
|
const siteName = props.siteName !== void 0 ? props.siteName : config.siteName;
|
|
37
37
|
const baseUrl = props.baseUrl ?? config.baseUrl;
|
|
38
|
-
const image = props.image ??
|
|
39
|
-
const
|
|
38
|
+
const image = props.image ?? config.defaultImage;
|
|
39
|
+
const separator = config.titleSeparator ?? "|";
|
|
40
|
+
const locale = props.locale ?? config.locale;
|
|
41
|
+
const fullTitle = siteName !== void 0 && siteName !== "" ? `${props.title} ${separator} ${siteName}` : props.title;
|
|
40
42
|
let canonical;
|
|
41
43
|
if (baseUrl) {
|
|
42
44
|
const base = baseUrl.replace(/\/$/, "");
|
|
@@ -45,20 +47,23 @@ function buildMetadata(props, config) {
|
|
|
45
47
|
canonical = `${base}${slug}`;
|
|
46
48
|
}
|
|
47
49
|
const ogImages = image ? [{ url: image }] : [];
|
|
50
|
+
const twitterCard = image ? "summary_large_image" : "summary";
|
|
48
51
|
const twitterImages = image ? [image] : [];
|
|
49
52
|
const metadata = {
|
|
50
53
|
title: fullTitle,
|
|
51
54
|
description: props.description,
|
|
55
|
+
...props.noIndex && { robots: { index: false, follow: false } },
|
|
52
56
|
openGraph: {
|
|
53
57
|
title: fullTitle,
|
|
54
58
|
description: props.description,
|
|
55
59
|
...ogImages.length > 0 && { images: ogImages },
|
|
56
60
|
type: "website",
|
|
57
61
|
...siteName && { siteName },
|
|
58
|
-
...canonical && { url: canonical }
|
|
62
|
+
...canonical && { url: canonical },
|
|
63
|
+
...locale && { locale }
|
|
59
64
|
},
|
|
60
65
|
twitter: {
|
|
61
|
-
card:
|
|
66
|
+
card: twitterCard,
|
|
62
67
|
title: fullTitle,
|
|
63
68
|
description: props.description,
|
|
64
69
|
...twitterImages.length > 0 && { images: twitterImages }
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\r\n * @Author ColdByDefault 2026\r\n * @MIT License\r\n */\r\n\r\nimport type { Metadata } from \"next\";\r\n\r\n// ---------------------------------------------------------------------------\r\n// Types\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Global defaults applied to every page when you don't override them.\r\n * Pass this once at the root layout level via `createSEOConfig`.\r\n */\r\nexport interface SEOConfig {\r\n /** Your brand / product name, appended to every page title. */\r\n siteName?: string;\r\n /** Absolute base URL used for canonical links, e.g. \"https://example.com\". */\r\n baseUrl?: string;\r\n /** Fallback OG/Twitter image URL used when a page omits its own image. */\r\n defaultImage?: string;\r\n /**\r\n * Character(s) placed between the page title and site name.\r\n * Defaults to `\"|\"` → `\"Home | MyBrand\"`.\r\n */\r\n titleSeparator?: string;\r\n /**\r\n * Default `og:locale` value, e.g. `\"en_US\"`.\r\n * Can be overridden per-page via `SEOProps.locale`.\r\n */\r\n locale?: string;\r\n}\r\n\r\n/**\r\n * Per-page SEO props passed to `defineSEO`.\r\n */\r\nexport interface SEOProps {\r\n /** Page-level title (without the site name suffix). */\r\n title: string;\r\n /** Short description shown in search results and social previews. */\r\n description: string;\r\n /**\r\n * Absolute URL for this page's OG/Twitter image.\r\n * Falls back to `SEOConfig.defaultImage` when omitted.\r\n */\r\n image?: string;\r\n /**\r\n * Slug / path appended to `SEOConfig.baseUrl` to build the canonical URL,\r\n * e.g. \"/about\". Ignored when no `baseUrl` is configured.\r\n */\r\n path?: string;\r\n /**\r\n * Override the global `siteName` for this specific page.\r\n * Set to `\"\"` (empty string) to suppress the suffix entirely.\r\n */\r\n siteName?: string;\r\n /**\r\n * Override the global `baseUrl` for this specific page.\r\n */\r\n baseUrl?: string;\r\n /**\r\n * When `true`, sets `robots: { index: false, follow: false }`.\r\n * Use for private pages like /dashboard, /checkout, /thank-you.\r\n */\r\n noIndex?: boolean;\r\n /**\r\n * Override `og:locale` for this specific page, e.g. `\"fr_FR\"`.\r\n */\r\n locale?: string;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Factory\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Creates a `defineSEO` function pre-loaded with your global defaults.\r\n *\r\n * @example\r\n * // lib/seo.ts\r\n * import { createSEOConfig } from 'next-seo-lite';\r\n *\r\n * export const defineSEO = createSEOConfig({\r\n * siteName: 'MyBrand',\r\n * baseUrl: 'https://mybrand.com',\r\n * defaultImage: 'https://mybrand.com/og-default.png',\r\n * });\r\n */\r\nexport function createSEOConfig(config: SEOConfig = {}) {\r\n return function defineSEO(props: SEOProps): Metadata {\r\n return buildMetadata(props, config);\r\n };\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Standalone helper (zero-config)\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * One-shot helper when you don't need global defaults.\r\n *\r\n * @example\r\n * // app/page.tsx\r\n * import { defineSEO } from 'next-seo-lite';\r\n *\r\n * export const metadata = defineSEO({\r\n * title: 'Home',\r\n * description: 'Welcome to my site.',\r\n * siteName: 'MyBrand',\r\n * });\r\n */\r\nexport function defineSEO(props: SEOProps): Metadata {\r\n return buildMetadata(props, {});\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Core builder\r\n// ---------------------------------------------------------------------------\r\n\r\nfunction buildMetadata(props: SEOProps, config: SEOConfig): Metadata {\r\n // ---- Resolve values (page-level wins over global config) ----------------\r\n const siteName =\r\n props.siteName !== undefined ? props.siteName : config.siteName;\r\n const baseUrl = props.baseUrl ?? config.baseUrl;\r\n const image = props.image ?? config.defaultImage;\r\n const separator = config.titleSeparator ?? \"|\";\r\n const locale = props.locale ?? config.locale;\r\n\r\n // ---- Title --------------------------------------------------------------\r\n const fullTitle =\r\n siteName !== undefined && siteName !== \"\"\r\n ? `${props.title} ${separator} ${siteName}`\r\n : props.title;\r\n\r\n // ---- Canonical URL ------------------------------------------------------\r\n let canonical: string | undefined;\r\n if (baseUrl) {\r\n const base = baseUrl.replace(/\\/$/, \"\");\r\n const normalized = props.path ? props.path.replace(/^\\//, \"\") : \"\";\r\n const slug = normalized ? `/${normalized}` : \"\";\r\n canonical = `${base}${slug}`;\r\n }\r\n\r\n // ---- OG images ----------------------------------------------------------\r\n const ogImages: { url: string }[] = image ? [{ url: image }] : [];\r\n\r\n // ---- Twitter images + card type -----------------------------------------\r\n // Use summary_large_image only when an image is available; fall back to summary.\r\n const twitterCard = image ? \"summary_large_image\" : \"summary\";\r\n const twitterImages: string[] = image ? [image] : [];\r\n\r\n // ---- Assemble Metadata --------------------------------------------------\r\n const metadata: Metadata = {\r\n title: fullTitle,\r\n description: props.description,\r\n ...(props.noIndex && { robots: { index: false, follow: false } }),\r\n openGraph: {\r\n title: fullTitle,\r\n description: props.description,\r\n ...(ogImages.length > 0 && { images: ogImages }),\r\n type: \"website\",\r\n ...(siteName && { siteName }),\r\n ...(canonical && { url: canonical }),\r\n ...(locale && { locale }),\r\n },\r\n twitter: {\r\n card: twitterCard,\r\n title: fullTitle,\r\n description: props.description,\r\n ...(twitterImages.length > 0 && { images: twitterImages }),\r\n },\r\n ...(canonical && {\r\n alternates: {\r\n canonical,\r\n },\r\n }),\r\n };\r\n\r\n return metadata;\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAyFO,SAAS,gBAAgB,SAAoB,CAAC,GAAG;AACtD,SAAO,SAASA,WAAU,OAA2B;AACnD,WAAO,cAAc,OAAO,MAAM;AAAA,EACpC;AACF;AAmBO,SAAS,UAAU,OAA2B;AACnD,SAAO,cAAc,OAAO,CAAC,CAAC;AAChC;AAMA,SAAS,cAAc,OAAiB,QAA6B;AAEnE,QAAM,WACJ,MAAM,aAAa,SAAY,MAAM,WAAW,OAAO;AACzD,QAAM,UAAU,MAAM,WAAW,OAAO;AACxC,QAAM,QAAQ,MAAM,SAAS,OAAO;AACpC,QAAM,YAAY,OAAO,kBAAkB;AAC3C,QAAM,SAAS,MAAM,UAAU,OAAO;AAGtC,QAAM,YACJ,aAAa,UAAa,aAAa,KACnC,GAAG,MAAM,KAAK,IAAI,SAAS,IAAI,QAAQ,KACvC,MAAM;AAGZ,MAAI;AACJ,MAAI,SAAS;AACX,UAAM,OAAO,QAAQ,QAAQ,OAAO,EAAE;AACtC,UAAM,aAAa,MAAM,OAAO,MAAM,KAAK,QAAQ,OAAO,EAAE,IAAI;AAChE,UAAM,OAAO,aAAa,IAAI,UAAU,KAAK;AAC7C,gBAAY,GAAG,IAAI,GAAG,IAAI;AAAA,EAC5B;AAGA,QAAM,WAA8B,QAAQ,CAAC,EAAE,KAAK,MAAM,CAAC,IAAI,CAAC;AAIhE,QAAM,cAAc,QAAQ,wBAAwB;AACpD,QAAM,gBAA0B,QAAQ,CAAC,KAAK,IAAI,CAAC;AAGnD,QAAM,WAAqB;AAAA,IACzB,OAAO;AAAA,IACP,aAAa,MAAM;AAAA,IACnB,GAAI,MAAM,WAAW,EAAE,QAAQ,EAAE,OAAO,OAAO,QAAQ,MAAM,EAAE;AAAA,IAC/D,WAAW;AAAA,MACT,OAAO;AAAA,MACP,aAAa,MAAM;AAAA,MACnB,GAAI,SAAS,SAAS,KAAK,EAAE,QAAQ,SAAS;AAAA,MAC9C,MAAM;AAAA,MACN,GAAI,YAAY,EAAE,SAAS;AAAA,MAC3B,GAAI,aAAa,EAAE,KAAK,UAAU;AAAA,MAClC,GAAI,UAAU,EAAE,OAAO;AAAA,IACzB;AAAA,IACA,SAAS;AAAA,MACP,MAAM;AAAA,MACN,OAAO;AAAA,MACP,aAAa,MAAM;AAAA,MACnB,GAAI,cAAc,SAAS,KAAK,EAAE,QAAQ,cAAc;AAAA,IAC1D;AAAA,IACA,GAAI,aAAa;AAAA,MACf,YAAY;AAAA,QACV;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;","names":["defineSEO"]}
|
package/dist/index.mjs
CHANGED
|
@@ -10,8 +10,10 @@ function defineSEO(props) {
|
|
|
10
10
|
function buildMetadata(props, config) {
|
|
11
11
|
const siteName = props.siteName !== void 0 ? props.siteName : config.siteName;
|
|
12
12
|
const baseUrl = props.baseUrl ?? config.baseUrl;
|
|
13
|
-
const image = props.image ??
|
|
14
|
-
const
|
|
13
|
+
const image = props.image ?? config.defaultImage;
|
|
14
|
+
const separator = config.titleSeparator ?? "|";
|
|
15
|
+
const locale = props.locale ?? config.locale;
|
|
16
|
+
const fullTitle = siteName !== void 0 && siteName !== "" ? `${props.title} ${separator} ${siteName}` : props.title;
|
|
15
17
|
let canonical;
|
|
16
18
|
if (baseUrl) {
|
|
17
19
|
const base = baseUrl.replace(/\/$/, "");
|
|
@@ -20,20 +22,23 @@ function buildMetadata(props, config) {
|
|
|
20
22
|
canonical = `${base}${slug}`;
|
|
21
23
|
}
|
|
22
24
|
const ogImages = image ? [{ url: image }] : [];
|
|
25
|
+
const twitterCard = image ? "summary_large_image" : "summary";
|
|
23
26
|
const twitterImages = image ? [image] : [];
|
|
24
27
|
const metadata = {
|
|
25
28
|
title: fullTitle,
|
|
26
29
|
description: props.description,
|
|
30
|
+
...props.noIndex && { robots: { index: false, follow: false } },
|
|
27
31
|
openGraph: {
|
|
28
32
|
title: fullTitle,
|
|
29
33
|
description: props.description,
|
|
30
34
|
...ogImages.length > 0 && { images: ogImages },
|
|
31
35
|
type: "website",
|
|
32
36
|
...siteName && { siteName },
|
|
33
|
-
...canonical && { url: canonical }
|
|
37
|
+
...canonical && { url: canonical },
|
|
38
|
+
...locale && { locale }
|
|
34
39
|
},
|
|
35
40
|
twitter: {
|
|
36
|
-
card:
|
|
41
|
+
card: twitterCard,
|
|
37
42
|
title: fullTitle,
|
|
38
43
|
description: props.description,
|
|
39
44
|
...twitterImages.length > 0 && { images: twitterImages }
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\r\n * @Author ColdByDefault 2026\r\n * @MIT License\r\n */\r\n\r\nimport type { Metadata } from \"next\";\r\n\r\n// ---------------------------------------------------------------------------\r\n// Types\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Global defaults applied to every page when you don't override them.\r\n * Pass this once at the root layout level via `createSEOConfig`.\r\n */\r\nexport interface SEOConfig {\r\n /** Your brand / product name, appended to every page title. */\r\n siteName?: string;\r\n /** Absolute base URL used for canonical links, e.g. \"https://example.com\". */\r\n baseUrl?: string;\r\n /** Fallback OG/Twitter image URL used when a page omits its own image. */\r\n defaultImage?: string;\r\n /**\r\n * Character(s) placed between the page title and site name.\r\n * Defaults to `\"|\"` → `\"Home | MyBrand\"`.\r\n */\r\n titleSeparator?: string;\r\n /**\r\n * Default `og:locale` value, e.g. `\"en_US\"`.\r\n * Can be overridden per-page via `SEOProps.locale`.\r\n */\r\n locale?: string;\r\n}\r\n\r\n/**\r\n * Per-page SEO props passed to `defineSEO`.\r\n */\r\nexport interface SEOProps {\r\n /** Page-level title (without the site name suffix). */\r\n title: string;\r\n /** Short description shown in search results and social previews. */\r\n description: string;\r\n /**\r\n * Absolute URL for this page's OG/Twitter image.\r\n * Falls back to `SEOConfig.defaultImage` when omitted.\r\n */\r\n image?: string;\r\n /**\r\n * Slug / path appended to `SEOConfig.baseUrl` to build the canonical URL,\r\n * e.g. \"/about\". Ignored when no `baseUrl` is configured.\r\n */\r\n path?: string;\r\n /**\r\n * Override the global `siteName` for this specific page.\r\n * Set to `\"\"` (empty string) to suppress the suffix entirely.\r\n */\r\n siteName?: string;\r\n /**\r\n * Override the global `baseUrl` for this specific page.\r\n */\r\n baseUrl?: string;\r\n /**\r\n * When `true`, sets `robots: { index: false, follow: false }`.\r\n * Use for private pages like /dashboard, /checkout, /thank-you.\r\n */\r\n noIndex?: boolean;\r\n /**\r\n * Override `og:locale` for this specific page, e.g. `\"fr_FR\"`.\r\n */\r\n locale?: string;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Factory\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Creates a `defineSEO` function pre-loaded with your global defaults.\r\n *\r\n * @example\r\n * // lib/seo.ts\r\n * import { createSEOConfig } from 'next-seo-lite';\r\n *\r\n * export const defineSEO = createSEOConfig({\r\n * siteName: 'MyBrand',\r\n * baseUrl: 'https://mybrand.com',\r\n * defaultImage: 'https://mybrand.com/og-default.png',\r\n * });\r\n */\r\nexport function createSEOConfig(config: SEOConfig = {}) {\r\n return function defineSEO(props: SEOProps): Metadata {\r\n return buildMetadata(props, config);\r\n };\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Standalone helper (zero-config)\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * One-shot helper when you don't need global defaults.\r\n *\r\n * @example\r\n * // app/page.tsx\r\n * import { defineSEO } from 'next-seo-lite';\r\n *\r\n * export const metadata = defineSEO({\r\n * title: 'Home',\r\n * description: 'Welcome to my site.',\r\n * siteName: 'MyBrand',\r\n * });\r\n */\r\nexport function defineSEO(props: SEOProps): Metadata {\r\n return buildMetadata(props, {});\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Core builder\r\n// ---------------------------------------------------------------------------\r\n\r\nfunction buildMetadata(props: SEOProps, config: SEOConfig): Metadata {\r\n // ---- Resolve values (page-level wins over global config) ----------------\r\n const siteName =\r\n props.siteName !== undefined ? props.siteName : config.siteName;\r\n const baseUrl = props.baseUrl ?? config.baseUrl;\r\n const image = props.image ?? config.defaultImage;\r\n const separator = config.titleSeparator ?? \"|\";\r\n const locale = props.locale ?? config.locale;\r\n\r\n // ---- Title --------------------------------------------------------------\r\n const fullTitle =\r\n siteName !== undefined && siteName !== \"\"\r\n ? `${props.title} ${separator} ${siteName}`\r\n : props.title;\r\n\r\n // ---- Canonical URL ------------------------------------------------------\r\n let canonical: string | undefined;\r\n if (baseUrl) {\r\n const base = baseUrl.replace(/\\/$/, \"\");\r\n const normalized = props.path ? props.path.replace(/^\\//, \"\") : \"\";\r\n const slug = normalized ? `/${normalized}` : \"\";\r\n canonical = `${base}${slug}`;\r\n }\r\n\r\n // ---- OG images ----------------------------------------------------------\r\n const ogImages: { url: string }[] = image ? [{ url: image }] : [];\r\n\r\n // ---- Twitter images + card type -----------------------------------------\r\n // Use summary_large_image only when an image is available; fall back to summary.\r\n const twitterCard = image ? \"summary_large_image\" : \"summary\";\r\n const twitterImages: string[] = image ? [image] : [];\r\n\r\n // ---- Assemble Metadata --------------------------------------------------\r\n const metadata: Metadata = {\r\n title: fullTitle,\r\n description: props.description,\r\n ...(props.noIndex && { robots: { index: false, follow: false } }),\r\n openGraph: {\r\n title: fullTitle,\r\n description: props.description,\r\n ...(ogImages.length > 0 && { images: ogImages }),\r\n type: \"website\",\r\n ...(siteName && { siteName }),\r\n ...(canonical && { url: canonical }),\r\n ...(locale && { locale }),\r\n },\r\n twitter: {\r\n card: twitterCard,\r\n title: fullTitle,\r\n description: props.description,\r\n ...(twitterImages.length > 0 && { images: twitterImages }),\r\n },\r\n ...(canonical && {\r\n alternates: {\r\n canonical,\r\n },\r\n }),\r\n };\r\n\r\n return metadata;\r\n}\r\n"],"mappings":";AAyFO,SAAS,gBAAgB,SAAoB,CAAC,GAAG;AACtD,SAAO,SAASA,WAAU,OAA2B;AACnD,WAAO,cAAc,OAAO,MAAM;AAAA,EACpC;AACF;AAmBO,SAAS,UAAU,OAA2B;AACnD,SAAO,cAAc,OAAO,CAAC,CAAC;AAChC;AAMA,SAAS,cAAc,OAAiB,QAA6B;AAEnE,QAAM,WACJ,MAAM,aAAa,SAAY,MAAM,WAAW,OAAO;AACzD,QAAM,UAAU,MAAM,WAAW,OAAO;AACxC,QAAM,QAAQ,MAAM,SAAS,OAAO;AACpC,QAAM,YAAY,OAAO,kBAAkB;AAC3C,QAAM,SAAS,MAAM,UAAU,OAAO;AAGtC,QAAM,YACJ,aAAa,UAAa,aAAa,KACnC,GAAG,MAAM,KAAK,IAAI,SAAS,IAAI,QAAQ,KACvC,MAAM;AAGZ,MAAI;AACJ,MAAI,SAAS;AACX,UAAM,OAAO,QAAQ,QAAQ,OAAO,EAAE;AACtC,UAAM,aAAa,MAAM,OAAO,MAAM,KAAK,QAAQ,OAAO,EAAE,IAAI;AAChE,UAAM,OAAO,aAAa,IAAI,UAAU,KAAK;AAC7C,gBAAY,GAAG,IAAI,GAAG,IAAI;AAAA,EAC5B;AAGA,QAAM,WAA8B,QAAQ,CAAC,EAAE,KAAK,MAAM,CAAC,IAAI,CAAC;AAIhE,QAAM,cAAc,QAAQ,wBAAwB;AACpD,QAAM,gBAA0B,QAAQ,CAAC,KAAK,IAAI,CAAC;AAGnD,QAAM,WAAqB;AAAA,IACzB,OAAO;AAAA,IACP,aAAa,MAAM;AAAA,IACnB,GAAI,MAAM,WAAW,EAAE,QAAQ,EAAE,OAAO,OAAO,QAAQ,MAAM,EAAE;AAAA,IAC/D,WAAW;AAAA,MACT,OAAO;AAAA,MACP,aAAa,MAAM;AAAA,MACnB,GAAI,SAAS,SAAS,KAAK,EAAE,QAAQ,SAAS;AAAA,MAC9C,MAAM;AAAA,MACN,GAAI,YAAY,EAAE,SAAS;AAAA,MAC3B,GAAI,aAAa,EAAE,KAAK,UAAU;AAAA,MAClC,GAAI,UAAU,EAAE,OAAO;AAAA,IACzB;AAAA,IACA,SAAS;AAAA,MACP,MAAM;AAAA,MACN,OAAO;AAAA,MACP,aAAa,MAAM;AAAA,MACnB,GAAI,cAAc,SAAS,KAAK,EAAE,QAAQ,cAAc;AAAA,IAC1D;AAAA,IACA,GAAI,aAAa;AAAA,MACf,YAAY;AAAA,QACV;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;","names":["defineSEO"]}
|
package/package.json
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coldbydefault/next-seo-lite",
|
|
3
|
-
"
|
|
4
|
-
"
|
|
3
|
+
"author": "ColdByDefault",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"version": "1.0.3",
|
|
6
|
+
"description": "A zero-dependency SEO helper for Next.js.",
|
|
5
7
|
"repository": {
|
|
6
8
|
"type": "git",
|
|
7
|
-
"url": "https://github.com/coldbydefault/next-seo-lite.git"
|
|
9
|
+
"url": "git+https://github.com/coldbydefault/next-seo-lite.git"
|
|
8
10
|
},
|
|
9
11
|
"main": "dist/index.js",
|
|
10
12
|
"module": "dist/index.mjs",
|
|
@@ -25,8 +27,8 @@
|
|
|
25
27
|
"test": "vitest run",
|
|
26
28
|
"test:watch": "vitest",
|
|
27
29
|
"prepublishOnly": "npm run build",
|
|
28
|
-
"publish:npm": "npm publish --access public
|
|
29
|
-
"publish:github": "npm publish --access public
|
|
30
|
+
"publish:npm": "npm publish --access public --@coldbydefault:registry=https://registry.npmjs.org",
|
|
31
|
+
"publish:github": "npm publish --access public --@coldbydefault:registry=https://npm.pkg.github.com",
|
|
30
32
|
"release": "npm run test && npm run publish:npm && npm run publish:github"
|
|
31
33
|
},
|
|
32
34
|
"keywords": [
|
|
@@ -37,8 +39,6 @@
|
|
|
37
39
|
"twitter-card",
|
|
38
40
|
"canonical"
|
|
39
41
|
],
|
|
40
|
-
"author": "",
|
|
41
|
-
"license": "MIT",
|
|
42
42
|
"peerDependencies": {
|
|
43
43
|
"next": ">=13.0.0"
|
|
44
44
|
},
|