@jdevalk/astro-seo-graph 0.2.4 → 0.3.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.
package/README.md CHANGED
@@ -2,30 +2,25 @@
2
2
 
3
3
  Astro integration for [`@jdevalk/seo-graph-core`](../seo-graph-core). Ships a
4
4
  `<Seo>` component, route factories for agent-ready schema endpoints, a
5
- content-collection aggregator, and Zod helpers for content schemas.
6
-
7
- > **Status:** `0.1.0` (pre-1.0). The API works and has two real consumers
8
- > in production (joost.blog and limonaia.house), but a few known warts in
9
- > the core will be smoothed out in `0.2.x` without breaking changes. See
10
- > `@jdevalk/seo-graph-core`'s README for the full list.
11
-
12
- ## What's in v0.1
13
-
14
- | API | Purpose |
15
- | ------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
16
- | **`<Seo>`** (`./Seo.astro`) | Single head component covering `<title>`, meta description, canonical, Open Graph, Twitter card, hreflang alternates, and optional JSON-LD `@graph`. Wraps [`astro-seo`](https://github.com/jonasmerlin/astro-seo) for the meta tags. |
17
- | **`createSchemaEndpoint`** | Factory returning an Astro `APIRoute` handler that serves a corpus-wide JSON-LD `@graph` for a content collection. |
18
- | **`createSchemaMap`** | Factory returning an `APIRoute` handler that emits a sitemap-style XML listing of your site's schema endpoints — the discovery point for agent crawlers. |
19
- | **`aggregate`** | Shared engine behind the endpoint factories. Walks a list of entries, runs a caller-supplied mapper, deduplicates by `@id`. |
20
- | **`seoSchema`, `imageSchema`** | Zod schemas for the `seo` and `image` fields on content collections. Import them into `src/content.config.ts`. |
21
- | **`buildAstroSeoProps`** | Pure-TS logic that powers `<Seo>` — exported for users who want to feed a different head component. |
22
- | **`buildAlternateLinks`** | Pure helper that turns a `{ hreflang, href }` entry list into normalized `<link rel="alternate">` tags plus an `x-default`. Used internally by `<Seo>`'s `alternates` prop, and exported for non-Astro callers (e.g. CMS plugins feeding their own metadata pipelines). |
23
-
24
- ## Not in `0.1.x` (coming in `0.2.x`)
25
-
26
- - **`createOgRenderer`** — a themeable `satori` + `sharp` wrapper for generating
27
- Open Graph images at build time. Pulled out of `0.1` to keep the dep tree
28
- free of native binaries. Keep using your own `og-image.ts` for now.
5
+ content-collection aggregator, breadcrumb helpers, and Zod helpers for content
6
+ schemas.
7
+
8
+ For detailed usage including all builder signatures, site-type recipes, and
9
+ schema.org best practices see [AGENTS.md](../../AGENTS.md) in the repository
10
+ root.
11
+
12
+ ## What you get
13
+
14
+ | API | Purpose |
15
+ |---|---|
16
+ | **`<Seo>`** (`./Seo.astro`) | Single head component covering `<title>`, meta description, canonical, Open Graph, Twitter card, hreflang alternates, and optional JSON-LD `@graph`. Wraps [`astro-seo`](https://github.com/jonasmerlin/astro-seo) for the meta tags. |
17
+ | **`createSchemaEndpoint`** | Factory returning an Astro `APIRoute` handler that serves a corpus-wide JSON-LD `@graph` for a content collection. |
18
+ | **`createSchemaMap`** | Factory returning an `APIRoute` handler that emits a sitemap-style XML listing of your site's schema endpoints — the discovery point for agent crawlers. |
19
+ | **`aggregate`** | Shared engine behind the endpoint factories. Walks a list of entries, runs a caller-supplied mapper, deduplicates by `@id`. |
20
+ | **`seoSchema`, `imageSchema`** | Zod schemas for the `seo` and `image` fields on content collections. Import them into `src/content.config.ts`. |
21
+ | **`buildAstroSeoProps`** | Pure-TS logic that powers `<Seo>` — exported for users who want to feed a different head component. |
22
+ | **`buildAlternateLinks`** | Pure helper that turns a `{ hreflang, href }` entry list into normalized `<link rel="alternate">` tags plus an `x-default`. Used internally by `<Seo>`'s `alternates` prop, and exported for non-Astro callers (e.g. CMS plugins feeding their own metadata pipelines). |
23
+ | **`breadcrumbsFromUrl`** | Derives a breadcrumb trail from an Astro URL. Splits path segments, supports custom display names and segment skipping. Returns `BreadcrumbItem[]` ready to pass to `buildBreadcrumbList`. |
29
24
 
30
25
  ## Installation
31
26
 
@@ -78,6 +73,41 @@ const graph = buildSchemaGraph({
78
73
  </html>
79
74
  ```
80
75
 
76
+ ## Breadcrumbs from URL
77
+
78
+ Derive a breadcrumb trail from an Astro page URL instead of computing it
79
+ manually:
80
+
81
+ ```ts
82
+ import { breadcrumbsFromUrl } from '@jdevalk/astro-seo-graph';
83
+ import { buildBreadcrumbList, makeIds } from '@jdevalk/seo-graph-core';
84
+
85
+ const ids = makeIds({ siteUrl: 'https://example.com' });
86
+ const url = 'https://example.com/blog/open-source/my-post/';
87
+
88
+ const items = breadcrumbsFromUrl({
89
+ url: Astro.url, // or any URL / string
90
+ siteUrl: 'https://example.com',
91
+ pageName: 'My Post', // display name for the current page
92
+ // homeName: 'Home', // optional, defaults to 'Home'
93
+ // names: { blog: 'Articles' }, // optional, custom segment names
94
+ // skip: ['category'], // optional, segments to omit
95
+ });
96
+
97
+ const breadcrumb = buildBreadcrumbList({ url, items }, ids);
98
+ // items === [
99
+ // { name: 'Home', url: 'https://example.com/' },
100
+ // { name: 'Blog', url: 'https://example.com/blog/' },
101
+ // { name: 'Open Source', url: 'https://example.com/blog/open-source/' },
102
+ // { name: 'My Post', url: 'https://example.com/blog/open-source/my-post/' },
103
+ // ]
104
+ ```
105
+
106
+ Segments without a `names` entry are title-cased from their slug
107
+ (`open-source` → `Open Source`). Sites with a base path
108
+ (e.g. `https://example.com/docs`) are supported — pass the base path as part
109
+ of `siteUrl`.
110
+
81
111
  ## hreflang alternates
82
112
 
83
113
  For multilingual sites, pass an `alternates` prop with one entry per locale.
@@ -181,6 +211,7 @@ export const GET = createSchemaEndpoint({
181
211
  datePublished: post.data.publishDate,
182
212
  },
183
213
  ids,
214
+ 'BlogPosting',
184
215
  ),
185
216
  ];
186
217
  },
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Breadcrumb derivation helper for Astro pages.
3
+ *
4
+ * Pure function: no DOM, no fetch, no Astro runtime. Takes a page URL
5
+ * (typically `Astro.url`) and derives an ordered breadcrumb trail from
6
+ * its path segments. The returned `BreadcrumbItem[]` array is passed
7
+ * straight to `buildBreadcrumbList` from `@jdevalk/seo-graph-core`.
8
+ *
9
+ * Callers control display names via the `names` map and can omit
10
+ * segments via `skip`. Segments without a mapped name are title-cased
11
+ * from their slug (e.g. `open-source` → `Open Source`).
12
+ */
13
+ import type { BreadcrumbItem } from '@jdevalk/seo-graph-core';
14
+ export interface BreadcrumbsFromUrlInput {
15
+ /**
16
+ * The full page URL. Typically `Astro.url` inside a layout, or any
17
+ * absolute URL string.
18
+ */
19
+ url: URL | string;
20
+ /**
21
+ * Site origin with optional base path, e.g. `'https://example.com'`
22
+ * or `'https://example.com/docs'`. Used to construct absolute URLs
23
+ * for each crumb. Must not end with a slash.
24
+ */
25
+ siteUrl: string;
26
+ /** Display name for the current (last) page. */
27
+ pageName: string;
28
+ /**
29
+ * Display name for the root crumb. Defaults to `'Home'`.
30
+ */
31
+ homeName?: string;
32
+ /**
33
+ * Map of path segments to display names. Keys are individual slug
34
+ * segments (e.g. `'blog'`, `'open-source'`). Segments not in this
35
+ * map are title-cased from their slug.
36
+ */
37
+ names?: Readonly<Record<string, string>>;
38
+ /**
39
+ * Segments to exclude from the breadcrumb trail. The pages they
40
+ * point to are still valid URLs — they just won't appear as crumbs.
41
+ * For example, `['category']` skips a `/blog/category/` crumb while
42
+ * still including `/blog/category/open-source/`.
43
+ */
44
+ skip?: readonly string[];
45
+ }
46
+ /**
47
+ * Derive a breadcrumb trail from a page URL.
48
+ *
49
+ * Always includes a root ("Home") crumb and the current page as the
50
+ * last crumb. Intermediate crumbs are derived from path segments
51
+ * between root and the page, skipping any segments listed in `skip`.
52
+ *
53
+ * @returns Ordered `BreadcrumbItem[]`, root first. Pass directly to
54
+ * `buildBreadcrumbList`'s `items` field.
55
+ */
56
+ export declare function breadcrumbsFromUrl(input: BreadcrumbsFromUrlInput): BreadcrumbItem[];
57
+ //# sourceMappingURL=breadcrumbs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"breadcrumbs.d.ts","sourceRoot":"","sources":["../src/breadcrumbs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAE9D,MAAM,WAAW,uBAAuB;IACpC;;;OAGG;IACH,GAAG,EAAE,GAAG,GAAG,MAAM,CAAC;IAElB;;;;OAIG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB,gDAAgD;IAChD,QAAQ,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;;OAIG;IACH,KAAK,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAEzC;;;;;OAKG;IACH,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC5B;AAqBD;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,uBAAuB,GAAG,cAAc,EAAE,CAkCnF"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Breadcrumb derivation helper for Astro pages.
3
+ *
4
+ * Pure function: no DOM, no fetch, no Astro runtime. Takes a page URL
5
+ * (typically `Astro.url`) and derives an ordered breadcrumb trail from
6
+ * its path segments. The returned `BreadcrumbItem[]` array is passed
7
+ * straight to `buildBreadcrumbList` from `@jdevalk/seo-graph-core`.
8
+ *
9
+ * Callers control display names via the `names` map and can omit
10
+ * segments via `skip`. Segments without a mapped name are title-cased
11
+ * from their slug (e.g. `open-source` → `Open Source`).
12
+ */
13
+ /**
14
+ * Title-case a URL slug: split on hyphens, capitalize each word.
15
+ *
16
+ * `'open-source'` → `'Open Source'`
17
+ */
18
+ function titleCaseSlug(slug) {
19
+ return slug
20
+ .split('-')
21
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
22
+ .join(' ');
23
+ }
24
+ /**
25
+ * Ensure `url` ends with exactly one trailing slash.
26
+ */
27
+ function trailingSlash(url) {
28
+ return url.endsWith('/') ? url : url + '/';
29
+ }
30
+ /**
31
+ * Derive a breadcrumb trail from a page URL.
32
+ *
33
+ * Always includes a root ("Home") crumb and the current page as the
34
+ * last crumb. Intermediate crumbs are derived from path segments
35
+ * between root and the page, skipping any segments listed in `skip`.
36
+ *
37
+ * @returns Ordered `BreadcrumbItem[]`, root first. Pass directly to
38
+ * `buildBreadcrumbList`'s `items` field.
39
+ */
40
+ export function breadcrumbsFromUrl(input) {
41
+ const { pageName, homeName = 'Home', names = {}, skip = [] } = input;
42
+ const normalizedSiteUrl = trailingSlash(input.siteUrl);
43
+ const pageUrl = typeof input.url === 'string' ? new URL(input.url) : input.url;
44
+ const pageHref = trailingSlash(pageUrl.href);
45
+ // Derive the path relative to the site origin.
46
+ const siteOrigin = new URL(normalizedSiteUrl);
47
+ const relativePath = pageUrl.pathname.slice(siteOrigin.pathname.length);
48
+ const segments = relativePath.split('/').filter(Boolean);
49
+ // When the page is the site root, there is only one crumb.
50
+ if (segments.length === 0) {
51
+ return [{ name: pageName, url: pageHref }];
52
+ }
53
+ const skipSet = new Set(skip);
54
+ const items = [{ name: homeName, url: normalizedSiteUrl }];
55
+ // Build intermediate crumbs (everything except the last segment,
56
+ // which is the current page).
57
+ let accumulated = siteOrigin.pathname;
58
+ for (const segment of segments.slice(0, -1)) {
59
+ accumulated = trailingSlash(accumulated + segment);
60
+ if (skipSet.has(segment))
61
+ continue;
62
+ const name = names[segment] ?? titleCaseSlug(segment);
63
+ items.push({ name, url: siteOrigin.origin + accumulated });
64
+ }
65
+ // Current page is always the last crumb.
66
+ items.push({ name: pageName, url: pageHref });
67
+ return items;
68
+ }
69
+ //# sourceMappingURL=breadcrumbs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"breadcrumbs.js","sourceRoot":"","sources":["../src/breadcrumbs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AA0CH;;;;GAIG;AACH,SAAS,aAAa,CAAC,IAAY;IAC/B,OAAO,IAAI;SACN,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;SAC3D,IAAI,CAAC,GAAG,CAAC,CAAC;AACnB,CAAC;AAED;;GAEG;AACH,SAAS,aAAa,CAAC,GAAW;IAC9B,OAAO,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,CAAC;AAC/C,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAA8B;IAC7D,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,MAAM,EAAE,KAAK,GAAG,EAAE,EAAE,IAAI,GAAG,EAAE,EAAE,GAAG,KAAK,CAAC;IAErE,MAAM,iBAAiB,GAAG,aAAa,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACvD,MAAM,OAAO,GAAG,OAAO,KAAK,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC;IAC/E,MAAM,QAAQ,GAAG,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAE7C,+CAA+C;IAC/C,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,iBAAiB,CAAC,CAAC;IAC9C,MAAM,YAAY,GAAG,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACxE,MAAM,QAAQ,GAAG,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAEzD,2DAA2D;IAC3D,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC/C,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC;IAC9B,MAAM,KAAK,GAAqB,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,iBAAiB,EAAE,CAAC,CAAC;IAE7E,iEAAiE;IACjE,8BAA8B;IAC9B,IAAI,WAAW,GAAG,UAAU,CAAC,QAAQ,CAAC;IACtC,KAAK,MAAM,OAAO,IAAI,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1C,WAAW,GAAG,aAAa,CAAC,WAAW,GAAG,OAAO,CAAC,CAAC;QACnD,IAAI,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC;YAAE,SAAS;QACnC,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,aAAa,CAAC,OAAO,CAAC,CAAC;QACtD,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,UAAU,CAAC,MAAM,GAAG,WAAW,EAAE,CAAC,CAAC;IAC/D,CAAC;IAED,yCAAyC;IACzC,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC;IAE9C,OAAO,KAAK,CAAC;AACjB,CAAC"}
package/dist/index.d.ts CHANGED
@@ -7,4 +7,6 @@ export { buildAstroSeoProps } from './components/seo-props.js';
7
7
  export type { SeoProps, AstroSeoProps } from './components/seo-props.js';
8
8
  export { buildAlternateLinks } from './alternates.js';
9
9
  export type { AlternateLink, BuildAlternateLinksInput } from './alternates.js';
10
+ export { breadcrumbsFromUrl } from './breadcrumbs.js';
11
+ export type { BreadcrumbsFromUrlInput } from './breadcrumbs.js';
10
12
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,YAAY,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAE1E,OAAO,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACpE,YAAY,EAAE,qBAAqB,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE3F,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAE9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAEzE,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtD,YAAY,EAAE,aAAa,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,YAAY,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAE1E,OAAO,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACpE,YAAY,EAAE,qBAAqB,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE3F,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAE9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAEzE,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtD,YAAY,EAAE,aAAa,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;AAE/E,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,YAAY,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC"}
package/dist/index.js CHANGED
@@ -8,4 +8,5 @@ export { createSchemaEndpoint, createSchemaMap } from './routes.js';
8
8
  export { seoSchema, imageSchema } from './content-helpers.js';
9
9
  export { buildAstroSeoProps } from './components/seo-props.js';
10
10
  export { buildAlternateLinks } from './alternates.js';
11
+ export { breadcrumbsFromUrl } from './breadcrumbs.js';
11
12
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,EAAE;AACF,wEAAwE;AACxE,8EAA8E;AAC9E,sDAAsD;AAEtD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAG5C,OAAO,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAGpE,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAE9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAG/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,EAAE;AACF,wEAAwE;AACxE,8EAA8E;AAC9E,sDAAsD;AAEtD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAG5C,OAAO,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAGpE,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAE9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAG/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAGtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jdevalk/astro-seo-graph",
3
- "version": "0.2.4",
3
+ "version": "0.3.0",
4
4
  "description": "Astro integration for @jdevalk/seo-graph-core. Seo component, route factories, content-collection aggregator, Zod content helpers.",
5
5
  "keywords": [
6
6
  "astro",
@@ -46,7 +46,7 @@
46
46
  "astro-seo": "^1.1.0",
47
47
  "schema-dts": "^2.0.0",
48
48
  "zod": "^3.24.0",
49
- "@jdevalk/seo-graph-core": "0.3.0"
49
+ "@jdevalk/seo-graph-core": "0.4.0"
50
50
  },
51
51
  "devDependencies": {
52
52
  "@types/node": "^22.0.0",