@thenewdynamic/astro-seo 0.1.1 → 0.1.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 CHANGED
@@ -23,6 +23,7 @@ npm install @thenewdynamic/astro-seo
23
23
  import tndSeo from '@thenewdynamic/astro-seo'
24
24
 
25
25
  export default defineConfig({
26
+ site: 'https://example.com',
26
27
  integrations: [tndSeo()]
27
28
  })
28
29
  ```
@@ -32,7 +33,17 @@ export default defineConfig({
32
33
  import type { SeoUserConfig } from '@thenewdynamic/astro-seo'
33
34
 
34
35
  export default {
35
- site: new URL('https://example.com'),
36
+ defaults: {
37
+ image: '/og-image.png', // Required — default OG image
38
+ title: 'My Site',
39
+ description: 'A brief site description',
40
+ },
41
+ // Optional — customize image resolution (e.g., Sanity)
42
+ resolveImage: (image) => `https://cdn.example.com/${image.src}`,
43
+ // Optional — override SEO fields per content type
44
+ transformEntry: (entry) => ({ /* ... */ }),
45
+ // Optional — detect production mode (defaults to import.meta.env.PROD)
46
+ isProd: () => process.env.NODE_ENV === 'production',
36
47
  } satisfies SeoUserConfig
37
48
  ```
38
49
 
@@ -1,3 +1,3 @@
1
1
  import type { SeoUserConfig, SeoEntry, SeoData } from '../types.js';
2
- export declare const makeGetData: (config: SeoUserConfig) => (entry: SeoEntry) => SeoData;
2
+ export declare const makeGetData: (config?: SeoUserConfig) => (entry: SeoEntry) => SeoData;
3
3
  //# sourceMappingURL=getData.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"getData.d.ts","sourceRoot":"","sources":["../../src/core/getData.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAGnE,eAAO,MAAM,WAAW,GAAI,QAAQ,aAAa,MAAM,OAAO,QAAQ,KAAG,OAkIxE,CAAA"}
1
+ {"version":3,"file":"getData.d.ts","sourceRoot":"","sources":["../../src/core/getData.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAGnE,eAAO,MAAM,WAAW,GAAI,SAAQ,aAAkB,MAAM,OAAO,QAAQ,KAAG,OAoI7E,CAAA"}
@@ -1,21 +1,24 @@
1
1
  import { escapeString, makeAbsUrl, isHome, getExcerpt } from '../utils.js';
2
- export const makeGetData = (config) => (entry) => {
3
- const { site, resolveImage, transformEntry } = config;
4
- const { url: baseURL } = site;
5
- const absUrl = makeAbsUrl(baseURL);
6
- const { title: siteTitle, description: siteDescription, image: siteImage, seo: { twitterHandle: siteTwitterHandle } = {}, prod, } = site;
7
- let { title = 'Missing', type = 'website', _type, _updatedAt, time_start, time_end, venue, date, url, description, descriptionText, locale = 'en_US', image, authors = [], bodyText, translation, twitterCard = 'summary_large_image', twitterHandle = siteTwitterHandle, twitterCreatorHandle = siteTwitterHandle, } = entry;
2
+ export const makeGetData = (config = {}) => (entry) => {
3
+ const { resolveImage, transformEntry, isProd } = config;
4
+ const urlInput = config.defaults?.url;
5
+ const baseURL = typeof urlInput === 'string' ? urlInput : urlInput?.toString?.();
6
+ const absUrl = baseURL ? makeAbsUrl(baseURL) : undefined;
7
+ const { title: defaultsTitle, description: defaultsDescription, image: defaultsImage, seo: { twitterHandle: defaultsTwitterHandle } = {}, } = config.defaults ?? {};
8
+ let { title = 'Website', type = 'website', _type, _updatedAt, time_start, time_end, venue, date, url, description, descriptionText, locale = 'en_US', image, authors = [], bodyText, translation, twitterCard = 'summary_large_image', twitterHandle = defaultsTwitterHandle, twitterCreatorHandle = defaultsTwitterHandle, } = entry;
8
9
  const seo = entry.seo || {};
9
10
  const { title: seoTitle, description: seoDescription, image: seoImage, canonical: seoCanonical, private: seoPrivate = false, } = seo;
10
11
  type = _type === 'post' ? 'article' : 'website';
11
- url = url ? absUrl(url) || undefined : undefined;
12
- const isPrivate = seoPrivate || !(prod?.() ?? true);
12
+ url = url && absUrl ? absUrl(url) || undefined : undefined;
13
+ const isPrivate = seoPrivate || !(isProd?.() ?? true);
13
14
  const canonical = seoCanonical || url;
15
+ // Title: seo > entry > defaults > "Website"
14
16
  title = seoTitle
15
17
  ? seoTitle
16
- : title
18
+ : title !== 'Website'
17
19
  ? escapeString(title)
18
- : siteTitle ?? 'Missing';
20
+ : defaultsTitle || 'Website';
21
+ // Description: seo > entry text > defaults > ""
19
22
  description = seoDescription
20
23
  ? seoDescription
21
24
  : descriptionText
@@ -24,17 +27,17 @@ export const makeGetData = (config) => (entry) => {
24
27
  ? escapeString(description)
25
28
  : bodyText
26
29
  ? getExcerpt(bodyText, 300)
27
- : siteDescription;
30
+ : defaultsDescription || '';
28
31
  let ogTitle = title;
29
- if (siteTitle && !isHome(entry)) {
30
- title = `${title} | ${siteTitle}`;
32
+ if (defaultsTitle && !isHome(entry)) {
33
+ title = `${title} | ${defaultsTitle}`;
31
34
  }
32
35
  else if (isHome(entry)) {
33
- title = site.title;
34
- ogTitle = site.title;
36
+ title = defaultsTitle || title;
37
+ ogTitle = title;
35
38
  }
36
- const resolvedSiteImage = siteImage;
37
- image = seoImage || image || resolvedSiteImage;
39
+ const resolvedDefaultsImage = defaultsImage;
40
+ image = seoImage || image || resolvedDefaultsImage;
38
41
  let imageAlt = '';
39
42
  if (image && typeof image !== 'string') {
40
43
  const img = image;
@@ -43,7 +46,7 @@ export const makeGetData = (config) => (entry) => {
43
46
  ? resolveImage(img, { width: 1000 })
44
47
  : (img.src ?? img.url ?? '');
45
48
  }
46
- else if (image && typeof image === 'string') {
49
+ else if (image && typeof image === 'string' && baseURL) {
47
50
  image = baseURL + image;
48
51
  }
49
52
  const languageAlternates = translation
@@ -56,7 +59,7 @@ export const makeGetData = (config) => (entry) => {
56
59
  publishedTime: date,
57
60
  modifiedTime: _updatedAt,
58
61
  authors: authors?.length
59
- ? authors.map((a) => ({ name: a.title ?? a.name ?? '', url: a.url ? absUrl(a.url) : false }))
62
+ ? authors.map((a) => ({ name: a.title ?? a.name ?? '', url: a.url && absUrl ? absUrl(a.url) : false }))
60
63
  : [],
61
64
  description,
62
65
  canonical,
@@ -71,7 +74,7 @@ export const makeGetData = (config) => (entry) => {
71
74
  locale: locale,
72
75
  localeAlternate,
73
76
  languageAlternates,
74
- siteTitle: siteTitle ?? '',
77
+ siteTitle: defaultsTitle || '',
75
78
  twitterCard: twitterCard,
76
79
  twitterHandle: twitterHandle,
77
80
  twitterCreatorHandle: twitterCreatorHandle,
@@ -1 +1 @@
1
- {"version":3,"file":"getData.js","sourceRoot":"","sources":["../../src/core/getData.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"getData.js","sourceRoot":"","sources":["../../src/core/getData.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAK1D,eAAO,MAAM,cAAc,GAAI,QAAQ,aAAa,KAAG,QAKtD,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAK1D,eAAO,MAAM,cAAc,GAAI,QAAQ,aAAa,KAAG,QAUtD,CAAA"}
@@ -2,6 +2,9 @@ import { makeGetData } from './getData.js';
2
2
  import { makeGetMetasData } from './getMetasData.js';
3
3
  import { makeGetStructuredData } from './getStructuredData.js';
4
4
  export const createSeoUtils = (config) => {
5
+ if (!config?.defaults?.image) {
6
+ throw new Error('@thenewdynamic/astro-seo: `defaults.image` is required. Set a default OG image in your `seo.config.ts` (e.g., `image: "/og-image.png"` or a Sanity image object).');
7
+ }
5
8
  const getData = makeGetData(config);
6
9
  const getMetasData = makeGetMetasData(getData);
7
10
  const getStructuredData = makeGetStructuredData(getData);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AACpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAA;AAE9D,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,MAAqB,EAAY,EAAE;IAChE,MAAM,OAAO,GAAG,WAAW,CAAC,MAAM,CAAC,CAAA;IACnC,MAAM,YAAY,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAA;IAC9C,MAAM,iBAAiB,GAAG,qBAAqB,CAAC,OAAO,CAAC,CAAA;IACxD,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,CAAA;AACrD,CAAC,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AACpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAA;AAE9D,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,MAAqB,EAAY,EAAE;IAChE,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CACb,mKAAmK,CACpK,CAAA;IACH,CAAC;IACD,MAAM,OAAO,GAAG,WAAW,CAAC,MAAM,CAAC,CAAA;IACnC,MAAM,YAAY,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAA;IAC9C,MAAM,iBAAiB,GAAG,qBAAqB,CAAC,OAAO,CAAC,CAAA;IACxD,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,CAAA;AACrD,CAAC,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,OAAO,CAAA;AAE7C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAc/C,MAAM,CAAC,OAAO,UAAU,MAAM,CAAC,OAAO,GAAE,aAAkB,GAAG,gBAAgB,CAmC5E;AAED,YAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAC3F,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,OAAO,CAAA;AAE7C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAc/C,MAAM,CAAC,OAAO,UAAU,MAAM,CAAC,OAAO,GAAE,aAAkB,GAAG,gBAAgB,CA2C5E;AAED,YAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAC3F,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA"}
package/dist/index.js CHANGED
@@ -13,10 +13,12 @@ declare module 'virtual:tnd/seo' {
13
13
  export default function tndSeo(options = {}) {
14
14
  let configFilePath;
15
15
  let coreModulePath;
16
+ let astroSite;
16
17
  return {
17
18
  name: '@thenewdynamic/astro-seo',
18
19
  hooks: {
19
20
  'astro:config:setup': ({ config, updateConfig }) => {
21
+ astroSite = config.site?.toString();
20
22
  const root = fileURLToPath(config.root);
21
23
  const userConfigPath = options.configPath ?? './seo.config';
22
24
  configFilePath = resolve(root, userConfigPath);
@@ -33,7 +35,13 @@ export default function tndSeo(options = {}) {
33
35
  return [
34
36
  `import userConfig from '${configFilePath}'`,
35
37
  `import { createSeoUtils } from '${coreModulePath}'`,
36
- `export const { getData, getMetasData, getStructuredData } = createSeoUtils(userConfig)`,
38
+ `const astroSite = ${astroSite ? `'${astroSite}'` : 'undefined'}`,
39
+ `const defaultIsProd = () => import.meta.env.PROD`,
40
+ `const config = userConfig || {}`,
41
+ `config.defaults = config.defaults || {}`,
42
+ `if (astroSite && !config.defaults.url) config.defaults.url = astroSite`,
43
+ `if (!config.isProd) config.isProd = defaultIsProd`,
44
+ `export const { getData, getMetasData, getStructuredData } = createSeoUtils(config)`,
37
45
  ].join('\n');
38
46
  },
39
47
  };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAKnC,MAAM,iBAAiB,GAAG,iBAAiB,CAAA;AAC3C,MAAM,WAAW,GAAG,IAAI,GAAG,iBAAiB,CAAA;AAE5C,MAAM,oBAAoB,GAAG;;;;;;;CAO5B,CAAA;AAED,MAAM,CAAC,OAAO,UAAU,MAAM,CAAC,UAAyB,EAAE;IACxD,IAAI,cAAsB,CAAA;IAC1B,IAAI,cAAsB,CAAA;IAE1B,OAAO;QACL,IAAI,EAAE,0BAA0B;QAChC,KAAK,EAAE;YACL,oBAAoB,EAAE,CAAC,EAAE,MAAM,EAAE,YAAY,EAAE,EAAE,EAAE;gBACjD,MAAM,IAAI,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;gBACvC,MAAM,cAAc,GAAG,OAAO,CAAC,UAAU,IAAI,cAAc,CAAA;gBAC3D,cAAc,GAAG,OAAO,CAAC,IAAI,EAAE,cAAc,CAAC,CAAA;gBAC9C,cAAc,GAAG,aAAa,CAAC,IAAI,GAAG,CAAC,iBAAiB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;gBAE3E,MAAM,MAAM,GAAW;oBACrB,IAAI,EAAE,qBAAqB;oBAC3B,SAAS,CAAC,EAAE;wBACV,IAAI,EAAE,KAAK,iBAAiB;4BAAE,OAAO,WAAW,CAAA;oBAClD,CAAC;oBACD,IAAI,CAAC,EAAE;wBACL,IAAI,EAAE,KAAK,WAAW;4BAAE,OAAM;wBAC9B,OAAO;4BACL,2BAA2B,cAAc,GAAG;4BAC5C,mCAAmC,cAAc,GAAG;4BACpD,wFAAwF;yBACzF,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;oBACd,CAAC;iBACF,CAAA;gBAED,YAAY,CAAC,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,CAAA;YAC/C,CAAC;YACD,mBAAmB,EAAE,CAAC,EAAE,WAAW,EAAE,EAAE,EAAE;gBACvC,WAAW,CAAC,EAAE,QAAQ,EAAE,sBAAsB,EAAE,OAAO,EAAE,oBAAoB,EAAE,CAAC,CAAA;YAClF,CAAC;SACF;KACF,CAAA;AACH,CAAC;AAGD,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAKnC,MAAM,iBAAiB,GAAG,iBAAiB,CAAA;AAC3C,MAAM,WAAW,GAAG,IAAI,GAAG,iBAAiB,CAAA;AAE5C,MAAM,oBAAoB,GAAG;;;;;;;CAO5B,CAAA;AAED,MAAM,CAAC,OAAO,UAAU,MAAM,CAAC,UAAyB,EAAE;IACxD,IAAI,cAAsB,CAAA;IAC1B,IAAI,cAAsB,CAAA;IAC1B,IAAI,SAA6B,CAAA;IAEjC,OAAO;QACL,IAAI,EAAE,0BAA0B;QAChC,KAAK,EAAE;YACL,oBAAoB,EAAE,CAAC,EAAE,MAAM,EAAE,YAAY,EAAE,EAAE,EAAE;gBACjD,SAAS,GAAG,MAAM,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAA;gBACnC,MAAM,IAAI,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;gBACvC,MAAM,cAAc,GAAG,OAAO,CAAC,UAAU,IAAI,cAAc,CAAA;gBAC3D,cAAc,GAAG,OAAO,CAAC,IAAI,EAAE,cAAc,CAAC,CAAA;gBAC9C,cAAc,GAAG,aAAa,CAAC,IAAI,GAAG,CAAC,iBAAiB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;gBAE3E,MAAM,MAAM,GAAW;oBACrB,IAAI,EAAE,qBAAqB;oBAC3B,SAAS,CAAC,EAAE;wBACV,IAAI,EAAE,KAAK,iBAAiB;4BAAE,OAAO,WAAW,CAAA;oBAClD,CAAC;oBACD,IAAI,CAAC,EAAE;wBACL,IAAI,EAAE,KAAK,WAAW;4BAAE,OAAM;wBAC9B,OAAO;4BACL,2BAA2B,cAAc,GAAG;4BAC5C,mCAAmC,cAAc,GAAG;4BACpD,qBAAqB,SAAS,CAAC,CAAC,CAAC,IAAI,SAAS,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE;4BACjE,kDAAkD;4BAClD,iCAAiC;4BACjC,yCAAyC;4BACzC,wEAAwE;4BACxE,mDAAmD;4BACnD,oFAAoF;yBACrF,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;oBACd,CAAC;iBACF,CAAA;gBAED,YAAY,CAAC,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,CAAA;YAC/C,CAAC;YACD,mBAAmB,EAAE,CAAC,EAAE,WAAW,EAAE,EAAE,EAAE;gBACvC,WAAW,CAAC,EAAE,QAAQ,EAAE,sBAAsB,EAAE,OAAO,EAAE,oBAAoB,EAAE,CAAC,CAAA;YAClF,CAAC;SACF;KACF,CAAA;AACH,CAAC;AAGD,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA"}
package/dist/types.d.ts CHANGED
@@ -1,13 +1,12 @@
1
- export interface SiteConfig {
2
- url: string;
3
- title: string;
1
+ export interface DefaultsConfig {
2
+ url?: string;
3
+ image: string | Record<string, unknown>;
4
+ title?: string;
4
5
  description?: string;
5
- image?: string | Record<string, unknown>;
6
6
  seo?: {
7
7
  title?: string;
8
8
  twitterHandle?: string;
9
9
  };
10
- prod?: () => boolean;
11
10
  }
12
11
  export interface ImageOptions {
13
12
  width?: number;
@@ -85,9 +84,10 @@ export interface SeoData {
85
84
  timeEnd?: string;
86
85
  }
87
86
  export interface SeoUserConfig {
88
- site: SiteConfig;
87
+ defaults?: DefaultsConfig;
89
88
  resolveImage?: (image: Record<string, unknown>, opts?: ImageOptions) => string;
90
89
  transformEntry?: (entry: SeoEntry) => Partial<SeoData>;
90
+ isProd?: () => boolean;
91
91
  }
92
92
  export interface SeoUtils {
93
93
  getData: (entry: SeoEntry) => SeoData;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thenewdynamic/astro-seo",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "type": "module",
5
5
  "description": "Astro integration for SEO meta tags and structured data",
6
6
  "author": "The New Dynamic",
@@ -41,11 +41,13 @@
41
41
  },
42
42
  "scripts": {
43
43
  "build": "tsc",
44
+ "dev": "tsc --watch",
44
45
  "prepublishOnly": "npm run build"
45
46
  },
46
47
  "devDependencies": {
47
48
  "@types/node": "^20.0.0",
48
49
  "astro": "^4.14.0",
50
+ "esbuild": "^0.28.0",
49
51
  "typescript": "^5.0.0"
50
52
  },
51
53
  "peerDependencies": {
@@ -1,21 +1,21 @@
1
1
  import type { SeoUserConfig, SeoEntry, SeoData } from '../types.js'
2
2
  import { escapeString, makeAbsUrl, isHome, getExcerpt } from '../utils.js'
3
3
 
4
- export const makeGetData = (config: SeoUserConfig) => (entry: SeoEntry): SeoData => {
5
- const { site, resolveImage, transformEntry } = config
6
- const { url: baseURL } = site
7
- const absUrl = makeAbsUrl(baseURL)
4
+ export const makeGetData = (config: SeoUserConfig = {}) => (entry: SeoEntry): SeoData => {
5
+ const { resolveImage, transformEntry, isProd } = config
6
+ const urlInput = config.defaults?.url
7
+ const baseURL = typeof urlInput === 'string' ? urlInput : (urlInput as any)?.toString?.()
8
+ const absUrl = baseURL ? makeAbsUrl(baseURL) : undefined
8
9
 
9
10
  const {
10
- title: siteTitle,
11
- description: siteDescription,
12
- image: siteImage,
13
- seo: { twitterHandle: siteTwitterHandle } = {},
14
- prod,
15
- } = site
11
+ title: defaultsTitle,
12
+ description: defaultsDescription,
13
+ image: defaultsImage,
14
+ seo: { twitterHandle: defaultsTwitterHandle } = {},
15
+ } = config.defaults ?? {}
16
16
 
17
17
  let {
18
- title = 'Missing',
18
+ title = 'Website',
19
19
  type = 'website',
20
20
  _type,
21
21
  _updatedAt,
@@ -32,8 +32,8 @@ export const makeGetData = (config: SeoUserConfig) => (entry: SeoEntry): SeoData
32
32
  bodyText,
33
33
  translation,
34
34
  twitterCard = 'summary_large_image',
35
- twitterHandle = siteTwitterHandle,
36
- twitterCreatorHandle = siteTwitterHandle,
35
+ twitterHandle = defaultsTwitterHandle,
36
+ twitterCreatorHandle = defaultsTwitterHandle,
37
37
  } = entry
38
38
 
39
39
  const seo = entry.seo || {}
@@ -46,17 +46,19 @@ export const makeGetData = (config: SeoUserConfig) => (entry: SeoEntry): SeoData
46
46
  } = seo
47
47
 
48
48
  type = _type === 'post' ? 'article' : 'website'
49
- url = url ? absUrl(url) || undefined : undefined
49
+ url = url && absUrl ? absUrl(url) || undefined : undefined
50
50
 
51
- const isPrivate = seoPrivate || !(prod?.() ?? true)
51
+ const isPrivate = seoPrivate || !(isProd?.() ?? true)
52
52
  const canonical = seoCanonical || url
53
53
 
54
+ // Title: seo > entry > defaults > "Website"
54
55
  title = seoTitle
55
56
  ? seoTitle
56
- : title
57
+ : title !== 'Website'
57
58
  ? escapeString(title as string)
58
- : siteTitle ?? 'Missing'
59
+ : defaultsTitle || 'Website'
59
60
 
61
+ // Description: seo > entry text > defaults > ""
60
62
  description = seoDescription
61
63
  ? seoDescription
62
64
  : descriptionText
@@ -65,19 +67,19 @@ export const makeGetData = (config: SeoUserConfig) => (entry: SeoEntry): SeoData
65
67
  ? escapeString(description)
66
68
  : bodyText
67
69
  ? getExcerpt(bodyText, 300)
68
- : siteDescription
70
+ : defaultsDescription || ''
69
71
 
70
72
  let ogTitle = title
71
73
 
72
- if (siteTitle && !isHome(entry)) {
73
- title = `${title} | ${siteTitle}`
74
+ if (defaultsTitle && !isHome(entry)) {
75
+ title = `${title} | ${defaultsTitle}`
74
76
  } else if (isHome(entry)) {
75
- title = site.title
76
- ogTitle = site.title
77
+ title = defaultsTitle || title
78
+ ogTitle = title
77
79
  }
78
80
 
79
- const resolvedSiteImage = siteImage
80
- image = seoImage || image || resolvedSiteImage
81
+ const resolvedDefaultsImage = defaultsImage
82
+ image = seoImage || image || resolvedDefaultsImage
81
83
 
82
84
  let imageAlt = ''
83
85
 
@@ -87,7 +89,7 @@ export const makeGetData = (config: SeoUserConfig) => (entry: SeoEntry): SeoData
87
89
  image = resolveImage
88
90
  ? resolveImage(img, { width: 1000 })
89
91
  : (img.src ?? img.url ?? '') as string
90
- } else if (image && typeof image === 'string') {
92
+ } else if (image && typeof image === 'string' && baseURL) {
91
93
  image = baseURL + image
92
94
  }
93
95
 
@@ -102,7 +104,7 @@ export const makeGetData = (config: SeoUserConfig) => (entry: SeoEntry): SeoData
102
104
  publishedTime: date,
103
105
  modifiedTime: _updatedAt,
104
106
  authors: authors?.length
105
- ? authors.map((a) => ({ name: a.title ?? a.name ?? '', url: a.url ? absUrl(a.url) : false }))
107
+ ? authors.map((a) => ({ name: a.title ?? a.name ?? '', url: a.url && absUrl ? absUrl(a.url) : false }))
106
108
  : [],
107
109
  description,
108
110
  canonical,
@@ -117,7 +119,7 @@ export const makeGetData = (config: SeoUserConfig) => (entry: SeoEntry): SeoData
117
119
  locale: locale as string,
118
120
  localeAlternate,
119
121
  languageAlternates,
120
- siteTitle: siteTitle ?? '',
122
+ siteTitle: defaultsTitle || '',
121
123
  twitterCard: twitterCard as string,
122
124
  twitterHandle: twitterHandle as string | undefined,
123
125
  twitterCreatorHandle: twitterCreatorHandle as string | undefined,
package/src/core/index.ts CHANGED
@@ -4,6 +4,11 @@ import { makeGetMetasData } from './getMetasData.js'
4
4
  import { makeGetStructuredData } from './getStructuredData.js'
5
5
 
6
6
  export const createSeoUtils = (config: SeoUserConfig): SeoUtils => {
7
+ if (!config?.defaults?.image) {
8
+ throw new Error(
9
+ '@thenewdynamic/astro-seo: `defaults.image` is required. Set a default OG image in your `seo.config.ts` (e.g., `image: "/og-image.png"` or a Sanity image object).'
10
+ )
11
+ }
7
12
  const getData = makeGetData(config)
8
13
  const getMetasData = makeGetMetasData(getData)
9
14
  const getStructuredData = makeGetStructuredData(getData)
package/src/index.ts CHANGED
@@ -19,11 +19,13 @@ declare module 'virtual:tnd/seo' {
19
19
  export default function tndSeo(options: TndSeoOptions = {}): AstroIntegration {
20
20
  let configFilePath: string
21
21
  let coreModulePath: string
22
+ let astroSite: string | undefined
22
23
 
23
24
  return {
24
25
  name: '@thenewdynamic/astro-seo',
25
26
  hooks: {
26
27
  'astro:config:setup': ({ config, updateConfig }) => {
28
+ astroSite = config.site?.toString()
27
29
  const root = fileURLToPath(config.root)
28
30
  const userConfigPath = options.configPath ?? './seo.config'
29
31
  configFilePath = resolve(root, userConfigPath)
@@ -39,7 +41,13 @@ export default function tndSeo(options: TndSeoOptions = {}): AstroIntegration {
39
41
  return [
40
42
  `import userConfig from '${configFilePath}'`,
41
43
  `import { createSeoUtils } from '${coreModulePath}'`,
42
- `export const { getData, getMetasData, getStructuredData } = createSeoUtils(userConfig)`,
44
+ `const astroSite = ${astroSite ? `'${astroSite}'` : 'undefined'}`,
45
+ `const defaultIsProd = () => import.meta.env.PROD`,
46
+ `const config = userConfig || {}`,
47
+ `config.defaults = config.defaults || {}`,
48
+ `if (astroSite && !config.defaults.url) config.defaults.url = astroSite`,
49
+ `if (!config.isProd) config.isProd = defaultIsProd`,
50
+ `export const { getData, getMetasData, getStructuredData } = createSeoUtils(config)`,
43
51
  ].join('\n')
44
52
  },
45
53
  }
package/src/types.ts CHANGED
@@ -1,13 +1,12 @@
1
- export interface SiteConfig {
2
- url: string
3
- title: string
1
+ export interface DefaultsConfig {
2
+ url?: string
3
+ image: string | Record<string, unknown>
4
+ title?: string
4
5
  description?: string
5
- image?: string | Record<string, unknown>
6
6
  seo?: {
7
7
  title?: string
8
8
  twitterHandle?: string
9
9
  }
10
- prod?: () => boolean
11
10
  }
12
11
 
13
12
  export interface ImageOptions {
@@ -76,9 +75,10 @@ export interface SeoData {
76
75
  }
77
76
 
78
77
  export interface SeoUserConfig {
79
- site: SiteConfig
78
+ defaults?: DefaultsConfig
80
79
  resolveImage?: (image: Record<string, unknown>, opts?: ImageOptions) => string
81
80
  transformEntry?: (entry: SeoEntry) => Partial<SeoData>
81
+ isProd?: () => boolean
82
82
  }
83
83
 
84
84
  export interface SeoUtils {