@jdevalk/seo-graph-core 0.1.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +29 -0
  3. package/dist/assemble.d.ts +10 -0
  4. package/dist/assemble.d.ts.map +1 -0
  5. package/dist/assemble.js +12 -0
  6. package/dist/assemble.js.map +1 -0
  7. package/dist/dedupe.d.ts +7 -0
  8. package/dist/dedupe.d.ts.map +1 -0
  9. package/dist/dedupe.js +19 -0
  10. package/dist/dedupe.js.map +1 -0
  11. package/dist/ids.d.ts +47 -0
  12. package/dist/ids.d.ts.map +1 -0
  13. package/dist/ids.js +36 -0
  14. package/dist/ids.js.map +1 -0
  15. package/dist/index.d.ts +25 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +16 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/pieces/article.d.ts +36 -0
  20. package/dist/pieces/article.d.ts.map +1 -0
  21. package/dist/pieces/article.js +33 -0
  22. package/dist/pieces/article.js.map +1 -0
  23. package/dist/pieces/breadcrumb.d.ts +27 -0
  24. package/dist/pieces/breadcrumb.d.ts.map +1 -0
  25. package/dist/pieces/breadcrumb.js +23 -0
  26. package/dist/pieces/breadcrumb.js.map +1 -0
  27. package/dist/pieces/custom.d.ts +12 -0
  28. package/dist/pieces/custom.d.ts.map +1 -0
  29. package/dist/pieces/custom.js +14 -0
  30. package/dist/pieces/custom.js.map +1 -0
  31. package/dist/pieces/image.d.ts +25 -0
  32. package/dist/pieces/image.d.ts.map +1 -0
  33. package/dist/pieces/image.js +24 -0
  34. package/dist/pieces/image.js.map +1 -0
  35. package/dist/pieces/navigation.d.ts +20 -0
  36. package/dist/pieces/navigation.d.ts.map +1 -0
  37. package/dist/pieces/navigation.js +20 -0
  38. package/dist/pieces/navigation.js.map +1 -0
  39. package/dist/pieces/organization.d.ts +33 -0
  40. package/dist/pieces/organization.d.ts.map +1 -0
  41. package/dist/pieces/organization.js +33 -0
  42. package/dist/pieces/organization.js.map +1 -0
  43. package/dist/pieces/person.d.ts +36 -0
  44. package/dist/pieces/person.d.ts.map +1 -0
  45. package/dist/pieces/person.js +13 -0
  46. package/dist/pieces/person.js.map +1 -0
  47. package/dist/pieces/video.d.ts +35 -0
  48. package/dist/pieces/video.d.ts.map +1 -0
  49. package/dist/pieces/video.js +32 -0
  50. package/dist/pieces/video.js.map +1 -0
  51. package/dist/pieces/webpage.d.ts +45 -0
  52. package/dist/pieces/webpage.d.ts.map +1 -0
  53. package/dist/pieces/webpage.js +37 -0
  54. package/dist/pieces/webpage.js.map +1 -0
  55. package/dist/pieces/website.d.ts +22 -0
  56. package/dist/pieces/website.d.ts.map +1 -0
  57. package/dist/pieces/website.js +20 -0
  58. package/dist/pieces/website.js.map +1 -0
  59. package/dist/types.d.ts +30 -0
  60. package/dist/types.d.ts.map +1 -0
  61. package/dist/types.js +2 -0
  62. package/dist/types.js.map +1 -0
  63. package/package.json +51 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Joost de Valk
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # @jdevalk/seo-graph-core
2
+
3
+ Pure schema.org JSON-LD graph builders. Runtime-agnostic core for agent-ready SEO.
4
+
5
+ > **Status:** pre-v1, scaffolding phase. No stable API yet. See the
6
+ > [roadmap](https://github.com/jdevalk/seo-graph#roadmap) in the monorepo root.
7
+
8
+ ## What this is
9
+
10
+ A small, dependency-light library that builds a valid schema.org `@graph` from
11
+ a set of typed inputs. It does one thing: turn structured page data into
12
+ byte-correct JSON-LD that search engines and agents can consume.
13
+
14
+ It does **not** know anything about Astro, Next.js, EmDash, WordPress, or any
15
+ other runtime. Use `@jdevalk/astro-seo-graph` for the Astro integration, or
16
+ consume this directly from your own CMS/framework.
17
+
18
+ ## Why
19
+
20
+ The [agent-ready web](https://joost.blog/tag/agent-ready/) needs every
21
+ publisher to expose a rich, linked knowledge graph for their content. Hand-
22
+ writing JSON-LD is error-prone; writing it once per framework is worse.
23
+ `@jdevalk/seo-graph-core` is the shared core that two real consumers — this
24
+ blog (Astro) and [`@jdevalk/emdash-plugin-seo`](https://www.npmjs.com/package/@jdevalk/emdash-plugin-seo)
25
+ (EmDash CMS) — will both depend on, so the graph they emit stays consistent.
26
+
27
+ ## License
28
+
29
+ MIT © Joost de Valk
@@ -0,0 +1,10 @@
1
+ import type { GraphEntity } from './types.js';
2
+ /**
3
+ * Wrap a list of pieces in a `@context + @graph` envelope. Pieces are
4
+ * deduplicated by `@id` before assembly; first occurrence wins.
5
+ */
6
+ export declare function assembleGraph<T extends GraphEntity>(pieces: readonly T[]): {
7
+ '@context': 'https://schema.org';
8
+ '@graph': T[];
9
+ };
10
+ //# sourceMappingURL=assemble.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assemble.d.ts","sourceRoot":"","sources":["../src/assemble.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAG9C;;;GAGG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,WAAW,EAC/C,MAAM,EAAE,SAAS,CAAC,EAAE,GACrB;IAAE,UAAU,EAAE,oBAAoB,CAAC;IAAC,QAAQ,EAAE,CAAC,EAAE,CAAA;CAAE,CAKrD"}
@@ -0,0 +1,12 @@
1
+ import { deduplicateByGraphId } from './dedupe.js';
2
+ /**
3
+ * Wrap a list of pieces in a `@context + @graph` envelope. Pieces are
4
+ * deduplicated by `@id` before assembly; first occurrence wins.
5
+ */
6
+ export function assembleGraph(pieces) {
7
+ return {
8
+ '@context': 'https://schema.org',
9
+ '@graph': deduplicateByGraphId(pieces),
10
+ };
11
+ }
12
+ //# sourceMappingURL=assemble.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assemble.js","sourceRoot":"","sources":["../src/assemble.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAEnD;;;GAGG;AACH,MAAM,UAAU,aAAa,CACzB,MAAoB;IAEpB,OAAO;QACH,UAAU,EAAE,oBAAoB;QAChC,QAAQ,EAAE,oBAAoB,CAAC,MAAM,CAAC;KACzC,CAAC;AACN,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { GraphEntity } from './types.js';
2
+ /**
3
+ * Deduplicate entities by their `@id`. First occurrence wins. Entities
4
+ * without an `@id` are always kept.
5
+ */
6
+ export declare function deduplicateByGraphId<T extends GraphEntity>(entities: readonly T[]): T[];
7
+ //# sourceMappingURL=dedupe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dedupe.d.ts","sourceRoot":"","sources":["../src/dedupe.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,WAAW,EAAE,QAAQ,EAAE,SAAS,CAAC,EAAE,GAAG,CAAC,EAAE,CAYvF"}
package/dist/dedupe.js ADDED
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Deduplicate entities by their `@id`. First occurrence wins. Entities
3
+ * without an `@id` are always kept.
4
+ */
5
+ export function deduplicateByGraphId(entities) {
6
+ const seen = new Set();
7
+ const result = [];
8
+ for (const entity of entities) {
9
+ const id = entity['@id'];
10
+ if (id !== undefined) {
11
+ if (seen.has(id))
12
+ continue;
13
+ seen.add(id);
14
+ }
15
+ result.push(entity);
16
+ }
17
+ return result;
18
+ }
19
+ //# sourceMappingURL=dedupe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dedupe.js","sourceRoot":"","sources":["../src/dedupe.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAwB,QAAsB;IAC9E,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,MAAM,GAAQ,EAAE,CAAC;IACvB,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE,CAAC;QAC5B,MAAM,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;QACzB,IAAI,EAAE,KAAK,SAAS,EAAE,CAAC;YACnB,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;gBAAE,SAAS;YAC3B,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACjB,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACxB,CAAC;IACD,OAAO,MAAM,CAAC;AAClB,CAAC"}
package/dist/ids.d.ts ADDED
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Factory for stable @id URIs used to cross-reference entities in the graph.
3
+ *
4
+ * Site-wide singletons live at `${siteUrl}/#/schema.org/<Type>` (WebSite,
5
+ * Person, etc). Per-page entities live at `${pageUrl}#<suffix>` (Article,
6
+ * Breadcrumb, PrimaryImage). The `person` id defaults to the site root but
7
+ * can be relocated to e.g. `/about-me/` via `personUrl`.
8
+ */
9
+ export interface IdFactory {
10
+ /** Site-wide Person id. Defaults to `${siteUrl}/#/schema.org/Person`. */
11
+ readonly person: string;
12
+ /** Site-wide Person image id (friendly-named fragment). */
13
+ readonly personImage: string;
14
+ /** Site-wide WebSite id. */
15
+ readonly website: string;
16
+ /** Site-wide SiteNavigationElement id. */
17
+ readonly navigation: string;
18
+ /** Per-org id factory — pass a stable slug. */
19
+ organization(slug: string): string;
20
+ /** Per-country id factory — pass an ISO 3166 alpha-2 code. */
21
+ country(code: string): string;
22
+ /** WebPage id equals the canonical URL itself. */
23
+ webPage(url: string): string;
24
+ /** Breadcrumb id for a given page URL. */
25
+ breadcrumb(url: string): string;
26
+ /** Article id for a given page URL. */
27
+ article(url: string): string;
28
+ /** VideoObject id for a given page URL. */
29
+ videoObject(url: string): string;
30
+ /** Primary ImageObject id for a given page URL. */
31
+ primaryImage(url: string): string;
32
+ }
33
+ export interface MakeIdsOptions {
34
+ /** Canonical site URL, with or without trailing slash. E.g. `https://joost.blog`. */
35
+ siteUrl: string;
36
+ /**
37
+ * URL where the site-wide Person entity lives, with trailing slash.
38
+ * Defaults to `${siteUrl}/`. joost.blog uses `${siteUrl}/about-me/`.
39
+ */
40
+ personUrl?: string;
41
+ }
42
+ /**
43
+ * Build an IdFactory for a given site. The returned factory is stateless —
44
+ * call it as many times as you like, on any piece builder.
45
+ */
46
+ export declare function makeIds(options: MakeIdsOptions): IdFactory;
47
+ //# sourceMappingURL=ids.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ids.d.ts","sourceRoot":"","sources":["../src/ids.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,WAAW,SAAS;IACtB,yEAAyE;IACzE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,2DAA2D;IAC3D,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,4BAA4B;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,0CAA0C;IAC1C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,+CAA+C;IAC/C,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACnC,8DAA8D;IAC9D,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAC9B,kDAAkD;IAClD,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IAC7B,0CAA0C;IAC1C,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IAChC,uCAAuC;IACvC,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IAC7B,2CAA2C;IAC3C,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IACjC,mDAAmD;IACnD,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;CACrC;AAED,MAAM,WAAW,cAAc;IAC3B,qFAAqF;IACrF,OAAO,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAkBD;;;GAGG;AACH,wBAAgB,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,SAAS,CAiB1D"}
package/dist/ids.js ADDED
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Normalize a base URL: strip any trailing slash so we can append `/#...`
3
+ * consistently.
4
+ */
5
+ function stripTrailingSlash(url) {
6
+ return url.replace(/\/+$/, '');
7
+ }
8
+ /**
9
+ * Normalize a person URL: ensure a single trailing slash so the resulting
10
+ * id reads `${personUrl}#/schema.org/Person` with the `/` already present.
11
+ */
12
+ function ensureTrailingSlash(url) {
13
+ return url.endsWith('/') ? url : `${url}/`;
14
+ }
15
+ /**
16
+ * Build an IdFactory for a given site. The returned factory is stateless —
17
+ * call it as many times as you like, on any piece builder.
18
+ */
19
+ export function makeIds(options) {
20
+ const site = stripTrailingSlash(options.siteUrl);
21
+ const person = ensureTrailingSlash(options.personUrl ?? `${site}/`);
22
+ return {
23
+ person: `${person}#/schema.org/Person`,
24
+ personImage: `${site}/#personlogo`,
25
+ website: `${site}/#/schema.org/WebSite`,
26
+ navigation: `${site}/#site-navigation`,
27
+ organization: (slug) => `${site}/#/schema.org/Organization/${slug}`,
28
+ country: (code) => `${site}/#/schema.org/Country/${code.toLowerCase()}`,
29
+ webPage: (url) => url,
30
+ breadcrumb: (url) => `${url}#breadcrumb`,
31
+ article: (url) => `${url}#article`,
32
+ videoObject: (url) => `${url}#video`,
33
+ primaryImage: (url) => `${url}#primaryimage`,
34
+ };
35
+ }
36
+ //# sourceMappingURL=ids.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ids.js","sourceRoot":"","sources":["../src/ids.ts"],"names":[],"mappings":"AA2CA;;;GAGG;AACH,SAAS,kBAAkB,CAAC,GAAW;IACnC,OAAO,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AACnC,CAAC;AAED;;;GAGG;AACH,SAAS,mBAAmB,CAAC,GAAW;IACpC,OAAO,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,CAAC;AAC/C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,OAAO,CAAC,OAAuB;IAC3C,MAAM,IAAI,GAAG,kBAAkB,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACjD,MAAM,MAAM,GAAG,mBAAmB,CAAC,OAAO,CAAC,SAAS,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC;IAEpE,OAAO;QACH,MAAM,EAAE,GAAG,MAAM,qBAAqB;QACtC,WAAW,EAAE,GAAG,IAAI,cAAc;QAClC,OAAO,EAAE,GAAG,IAAI,uBAAuB;QACvC,UAAU,EAAE,GAAG,IAAI,mBAAmB;QACtC,YAAY,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,GAAG,IAAI,8BAA8B,IAAI,EAAE;QAC3E,OAAO,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,GAAG,IAAI,yBAAyB,IAAI,CAAC,WAAW,EAAE,EAAE;QAC/E,OAAO,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,GAAG;QAC7B,UAAU,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,GAAG,GAAG,aAAa;QAChD,OAAO,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,GAAG,GAAG,UAAU;QAC1C,WAAW,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,GAAG,GAAG,QAAQ;QAC5C,YAAY,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,GAAG,GAAG,eAAe;KACvD,CAAC;AACN,CAAC"}
@@ -0,0 +1,25 @@
1
+ export type { GraphEntity, Reference, SchemaGraph } from './types.js';
2
+ export type { IdFactory, MakeIdsOptions } from './ids.js';
3
+ export { makeIds } from './ids.js';
4
+ export { deduplicateByGraphId } from './dedupe.js';
5
+ export { assembleGraph } from './assemble.js';
6
+ export { buildWebSite } from './pieces/website.js';
7
+ export type { WebSiteInput } from './pieces/website.js';
8
+ export { buildPerson } from './pieces/person.js';
9
+ export type { PersonInput } from './pieces/person.js';
10
+ export { buildOrganization } from './pieces/organization.js';
11
+ export type { OrganizationInput } from './pieces/organization.js';
12
+ export { buildSiteNavigationElement } from './pieces/navigation.js';
13
+ export type { NavigationItem, SiteNavigationInput } from './pieces/navigation.js';
14
+ export { buildWebPage } from './pieces/webpage.js';
15
+ export type { WebPageInput, WebPageType } from './pieces/webpage.js';
16
+ export { buildArticle } from './pieces/article.js';
17
+ export type { ArticleInput } from './pieces/article.js';
18
+ export { buildBreadcrumbList } from './pieces/breadcrumb.js';
19
+ export type { BreadcrumbItem, BreadcrumbListInput } from './pieces/breadcrumb.js';
20
+ export { buildImageObject } from './pieces/image.js';
21
+ export type { ImageObjectInput } from './pieces/image.js';
22
+ export { buildVideoObject } from './pieces/video.js';
23
+ export type { VideoObjectInput } from './pieces/video.js';
24
+ export { buildCustomPiece } from './pieces/custom.js';
25
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACtE,YAAY,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC1D,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACnC,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAG9C,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,YAAY,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAExD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,YAAY,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,YAAY,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAElE,OAAO,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AACpE,YAAY,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAElF,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAErE,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,YAAY,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAExD,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAC7D,YAAY,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAElF,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,YAAY,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,YAAY,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,16 @@
1
+ // @jdevalk/seo-graph-core — agent-ready schema.org JSON-LD graph builders.
2
+ export { makeIds } from './ids.js';
3
+ export { deduplicateByGraphId } from './dedupe.js';
4
+ export { assembleGraph } from './assemble.js';
5
+ // Piece builders
6
+ export { buildWebSite } from './pieces/website.js';
7
+ export { buildPerson } from './pieces/person.js';
8
+ export { buildOrganization } from './pieces/organization.js';
9
+ export { buildSiteNavigationElement } from './pieces/navigation.js';
10
+ export { buildWebPage } from './pieces/webpage.js';
11
+ export { buildArticle } from './pieces/article.js';
12
+ export { buildBreadcrumbList } from './pieces/breadcrumb.js';
13
+ export { buildImageObject } from './pieces/image.js';
14
+ export { buildVideoObject } from './pieces/video.js';
15
+ export { buildCustomPiece } from './pieces/custom.js';
16
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAI3E,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACnC,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9C,iBAAiB;AACjB,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGnD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAGjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAG7D,OAAO,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AAGpE,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGnD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGnD,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAG7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAGrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAGrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,36 @@
1
+ import type { IdFactory } from '../ids.js';
2
+ import type { Reference } from '../types.js';
3
+ export interface ArticleInput {
4
+ /** Canonical URL of the article's page. The @id is `${url}#article`. */
5
+ url: string;
6
+ /** Reference to the enclosing WebPage (usually ids.webPage(url)). */
7
+ isPartOf: Reference;
8
+ /** Author reference. May include a `name` alongside the `@id`. */
9
+ author: Reference;
10
+ /** Publisher reference. Usually the same as the author for personal blogs. */
11
+ publisher: Reference;
12
+ headline: string;
13
+ description: string;
14
+ inLanguage?: string;
15
+ datePublished: Date;
16
+ dateModified?: Date;
17
+ /** Reference to the primary ImageObject, if any. */
18
+ image?: Reference;
19
+ /** Top-level category, emitted as `articleSection`. */
20
+ articleSection?: string;
21
+ wordCount?: number;
22
+ /**
23
+ * Full or truncated article body, emitted as `articleBody`. Pass from
24
+ * the aggregator / build step; core doesn't derive it from anything.
25
+ */
26
+ articleBody?: string;
27
+ extra?: Record<string, unknown>;
28
+ }
29
+ /**
30
+ * Build a schema.org Article piece. The caller is responsible for pre-
31
+ * computing the references (author, publisher, isPartOf, image) using the
32
+ * IdFactory, so core doesn't have to know anything about how the site
33
+ * models its Person/Organization/WebPage entities.
34
+ */
35
+ export declare function buildArticle(input: ArticleInput, ids: IdFactory): Record<string, unknown>;
36
+ //# sourceMappingURL=article.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"article.d.ts","sourceRoot":"","sources":["../../src/pieces/article.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,MAAM,WAAW,YAAY;IACzB,wEAAwE;IACxE,GAAG,EAAE,MAAM,CAAC;IACZ,qEAAqE;IACrE,QAAQ,EAAE,SAAS,CAAC;IACpB,kEAAkE;IAClE,MAAM,EAAE,SAAS,CAAC;IAClB,8EAA8E;IAC9E,SAAS,EAAE,SAAS,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,IAAI,CAAC;IACpB,YAAY,CAAC,EAAE,IAAI,CAAC;IACpB,oDAAoD;IACpD,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,uDAAuD;IACvD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,YAAY,EAAE,GAAG,EAAE,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAuBzF"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Build a schema.org Article piece. The caller is responsible for pre-
3
+ * computing the references (author, publisher, isPartOf, image) using the
4
+ * IdFactory, so core doesn't have to know anything about how the site
5
+ * models its Person/Organization/WebPage entities.
6
+ */
7
+ export function buildArticle(input, ids) {
8
+ const piece = {
9
+ '@type': 'Article',
10
+ '@id': ids.article(input.url),
11
+ isPartOf: input.isPartOf,
12
+ author: input.author,
13
+ headline: input.headline,
14
+ mainEntityOfPage: { '@id': ids.webPage(input.url) },
15
+ publisher: input.publisher,
16
+ inLanguage: input.inLanguage ?? 'en-US',
17
+ description: input.description,
18
+ datePublished: input.datePublished.toISOString(),
19
+ };
20
+ if (input.dateModified !== undefined) {
21
+ piece.dateModified = input.dateModified.toISOString();
22
+ }
23
+ if (input.image !== undefined)
24
+ piece.image = input.image;
25
+ if (input.articleSection !== undefined)
26
+ piece.articleSection = input.articleSection;
27
+ if (input.wordCount !== undefined)
28
+ piece.wordCount = input.wordCount;
29
+ if (input.articleBody !== undefined)
30
+ piece.articleBody = input.articleBody;
31
+ return { ...piece, ...input.extra };
32
+ }
33
+ //# sourceMappingURL=article.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"article.js","sourceRoot":"","sources":["../../src/pieces/article.ts"],"names":[],"mappings":"AA8BA;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAAC,KAAmB,EAAE,GAAc;IAC5D,MAAM,KAAK,GAA4B;QACnC,OAAO,EAAE,SAAS;QAClB,KAAK,EAAE,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC;QAC7B,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,gBAAgB,EAAE,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE;QACnD,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,UAAU,EAAE,KAAK,CAAC,UAAU,IAAI,OAAO;QACvC,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,aAAa,EAAE,KAAK,CAAC,aAAa,CAAC,WAAW,EAAE;KACnD,CAAC;IAEF,IAAI,KAAK,CAAC,YAAY,KAAK,SAAS,EAAE,CAAC;QACnC,KAAK,CAAC,YAAY,GAAG,KAAK,CAAC,YAAY,CAAC,WAAW,EAAE,CAAC;IAC1D,CAAC;IACD,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS;QAAE,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;IACzD,IAAI,KAAK,CAAC,cAAc,KAAK,SAAS;QAAE,KAAK,CAAC,cAAc,GAAG,KAAK,CAAC,cAAc,CAAC;IACpF,IAAI,KAAK,CAAC,SAAS,KAAK,SAAS;QAAE,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC,SAAS,CAAC;IACrE,IAAI,KAAK,CAAC,WAAW,KAAK,SAAS;QAAE,KAAK,CAAC,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC;IAE3E,OAAO,EAAE,GAAG,KAAK,EAAE,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC;AACxC,CAAC"}
@@ -0,0 +1,27 @@
1
+ import type { IdFactory } from '../ids.js';
2
+ export interface BreadcrumbItem {
3
+ /** Display name for this crumb, e.g. 'Home', 'Blog', 'Open Source'. */
4
+ name: string;
5
+ /** URL for this crumb. */
6
+ url: string;
7
+ }
8
+ export interface BreadcrumbListInput {
9
+ /**
10
+ * The URL of the page this breadcrumb belongs to. The @id is
11
+ * `${url}#breadcrumb`.
12
+ */
13
+ url: string;
14
+ /** Pre-computed ordered list of crumbs, root first. */
15
+ items: readonly BreadcrumbItem[];
16
+ extra?: Record<string, unknown>;
17
+ }
18
+ /**
19
+ * Build a schema.org BreadcrumbList piece.
20
+ *
21
+ * Breadcrumbs are an input to core, not a derivation. The caller knows
22
+ * its routing conventions; core just wraps the pre-computed items in the
23
+ * right schema.org shape. If you need to derive breadcrumbs from an
24
+ * Astro URL, use `@jdevalk/astro-seo-graph`'s breadcrumb helper instead.
25
+ */
26
+ export declare function buildBreadcrumbList(input: BreadcrumbListInput, ids: IdFactory): Record<string, unknown>;
27
+ //# sourceMappingURL=breadcrumb.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"breadcrumb.d.ts","sourceRoot":"","sources":["../../src/pieces/breadcrumb.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAE3C,MAAM,WAAW,cAAc;IAC3B,uEAAuE;IACvE,IAAI,EAAE,MAAM,CAAC;IACb,0BAA0B;IAC1B,GAAG,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,mBAAmB;IAChC;;;OAGG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ,uDAAuD;IACvD,KAAK,EAAE,SAAS,cAAc,EAAE,CAAC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAC/B,KAAK,EAAE,mBAAmB,EAC1B,GAAG,EAAE,SAAS,GACf,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAazB"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Build a schema.org BreadcrumbList piece.
3
+ *
4
+ * Breadcrumbs are an input to core, not a derivation. The caller knows
5
+ * its routing conventions; core just wraps the pre-computed items in the
6
+ * right schema.org shape. If you need to derive breadcrumbs from an
7
+ * Astro URL, use `@jdevalk/astro-seo-graph`'s breadcrumb helper instead.
8
+ */
9
+ export function buildBreadcrumbList(input, ids) {
10
+ const itemListElement = input.items.map((item, index) => ({
11
+ '@type': 'ListItem',
12
+ position: index + 1,
13
+ name: item.name,
14
+ item: item.url,
15
+ }));
16
+ return {
17
+ '@type': 'BreadcrumbList',
18
+ '@id': ids.breadcrumb(input.url),
19
+ itemListElement,
20
+ ...input.extra,
21
+ };
22
+ }
23
+ //# sourceMappingURL=breadcrumb.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"breadcrumb.js","sourceRoot":"","sources":["../../src/pieces/breadcrumb.ts"],"names":[],"mappings":"AAoBA;;;;;;;GAOG;AACH,MAAM,UAAU,mBAAmB,CAC/B,KAA0B,EAC1B,GAAc;IAEd,MAAM,eAAe,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;QACtD,OAAO,EAAE,UAAU;QACnB,QAAQ,EAAE,KAAK,GAAG,CAAC;QACnB,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,IAAI,EAAE,IAAI,CAAC,GAAG;KACjB,CAAC,CAAC,CAAC;IACJ,OAAO;QACH,OAAO,EAAE,gBAAgB;QACzB,KAAK,EAAE,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC;QAChC,eAAe;QACf,GAAG,KAAK,CAAC,KAAK;KACjB,CAAC;AACN,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Escape hatch: build an arbitrary schema.org piece from a raw object.
3
+ *
4
+ * Use this when the built-in piece builders don't cover what you need —
5
+ * e.g. a Recipe, Event, Product, or a LocalBusiness subtype that needs
6
+ * a specific shape not captured by `buildOrganization`.
7
+ *
8
+ * Note: the built piece is returned as-is. It's the caller's responsibility
9
+ * to supply a valid `@type` and (if cross-referenced) a stable `@id`.
10
+ */
11
+ export declare function buildCustomPiece<T extends Record<string, unknown>>(raw: T): T;
12
+ //# sourceMappingURL=custom.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"custom.d.ts","sourceRoot":"","sources":["../../src/pieces/custom.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,CAE7E"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Escape hatch: build an arbitrary schema.org piece from a raw object.
3
+ *
4
+ * Use this when the built-in piece builders don't cover what you need —
5
+ * e.g. a Recipe, Event, Product, or a LocalBusiness subtype that needs
6
+ * a specific shape not captured by `buildOrganization`.
7
+ *
8
+ * Note: the built piece is returned as-is. It's the caller's responsibility
9
+ * to supply a valid `@type` and (if cross-referenced) a stable `@id`.
10
+ */
11
+ export function buildCustomPiece(raw) {
12
+ return raw;
13
+ }
14
+ //# sourceMappingURL=custom.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"custom.js","sourceRoot":"","sources":["../../src/pieces/custom.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,UAAU,gBAAgB,CAAoC,GAAM;IACtE,OAAO,GAAG,CAAC;AACf,CAAC"}
@@ -0,0 +1,25 @@
1
+ import type { IdFactory } from '../ids.js';
2
+ export interface ImageObjectInput {
3
+ /**
4
+ * Canonical URL of the page this image belongs to. The @id is
5
+ * `${pageUrl}#primaryimage` — to build a site-wide image with a
6
+ * friendly fragment (e.g. the Person logo), use the `id` override.
7
+ */
8
+ pageUrl?: string;
9
+ /** Explicit @id override; takes precedence over `pageUrl`. */
10
+ id?: string;
11
+ /** Public URL of the image file. Used for both `url` and `contentUrl`. */
12
+ url: string;
13
+ width: number;
14
+ height: number;
15
+ inLanguage?: string;
16
+ caption?: string;
17
+ extra?: Record<string, unknown>;
18
+ }
19
+ /**
20
+ * Build a schema.org ImageObject piece. Pass `pageUrl` for a page's
21
+ * primary image (id = `${pageUrl}#primaryimage`), or `id` for a site-
22
+ * wide image like a personal logo.
23
+ */
24
+ export declare function buildImageObject(input: ImageObjectInput, ids: IdFactory): Record<string, unknown>;
25
+ //# sourceMappingURL=image.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image.d.ts","sourceRoot":"","sources":["../../src/pieces/image.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAE3C,MAAM,WAAW,gBAAgB;IAC7B;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,8DAA8D;IAC9D,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,0EAA0E;IAC1E,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC5B,KAAK,EAAE,gBAAgB,EACvB,GAAG,EAAE,SAAS,GACf,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAkBzB"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Build a schema.org ImageObject piece. Pass `pageUrl` for a page's
3
+ * primary image (id = `${pageUrl}#primaryimage`), or `id` for a site-
4
+ * wide image like a personal logo.
5
+ */
6
+ export function buildImageObject(input, ids) {
7
+ const id = input.id ?? (input.pageUrl !== undefined ? ids.primaryImage(input.pageUrl) : undefined);
8
+ if (id === undefined) {
9
+ throw new Error('buildImageObject: either `id` or `pageUrl` is required');
10
+ }
11
+ const piece = {
12
+ '@type': 'ImageObject',
13
+ '@id': id,
14
+ url: input.url,
15
+ contentUrl: input.url,
16
+ width: input.width,
17
+ height: input.height,
18
+ };
19
+ if (input.caption !== undefined)
20
+ piece.caption = input.caption;
21
+ piece.inLanguage = input.inLanguage ?? 'en-US';
22
+ return { ...piece, ...input.extra };
23
+ }
24
+ //# sourceMappingURL=image.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image.js","sourceRoot":"","sources":["../../src/pieces/image.ts"],"names":[],"mappings":"AAoBA;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAC5B,KAAuB,EACvB,GAAc;IAEd,MAAM,EAAE,GAAG,KAAK,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IACnG,IAAI,EAAE,KAAK,SAAS,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CAAC,wDAAwD,CAAC,CAAC;IAC9E,CAAC;IAED,MAAM,KAAK,GAA4B;QACnC,OAAO,EAAE,aAAa;QACtB,KAAK,EAAE,EAAE;QACT,GAAG,EAAE,KAAK,CAAC,GAAG;QACd,UAAU,EAAE,KAAK,CAAC,GAAG;QACrB,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,MAAM,EAAE,KAAK,CAAC,MAAM;KACvB,CAAC;IACF,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS;QAAE,KAAK,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;IAC/D,KAAK,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,IAAI,OAAO,CAAC;IAE/C,OAAO,EAAE,GAAG,KAAK,EAAE,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC;AACxC,CAAC"}
@@ -0,0 +1,20 @@
1
+ import type { IdFactory } from '../ids.js';
2
+ import type { Reference } from '../types.js';
3
+ export interface NavigationItem {
4
+ name: string;
5
+ url: string;
6
+ }
7
+ export interface SiteNavigationInput {
8
+ /** Human-readable nav name, e.g. 'Main navigation'. */
9
+ name: string;
10
+ /** Parent WebSite reference (usually ids.website). */
11
+ isPartOf: Reference;
12
+ items: readonly NavigationItem[];
13
+ extra?: Record<string, unknown>;
14
+ }
15
+ /**
16
+ * Build a schema.org SiteNavigationElement whose `hasPart` is a list of
17
+ * sub-SiteNavigationElement entries (one per nav link).
18
+ */
19
+ export declare function buildSiteNavigationElement(input: SiteNavigationInput, ids: IdFactory): Record<string, unknown>;
20
+ //# sourceMappingURL=navigation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"navigation.d.ts","sourceRoot":"","sources":["../../src/pieces/navigation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,MAAM,WAAW,cAAc;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,mBAAmB;IAChC,uDAAuD;IACvD,IAAI,EAAE,MAAM,CAAC;IACb,sDAAsD;IACtD,QAAQ,EAAE,SAAS,CAAC;IACpB,KAAK,EAAE,SAAS,cAAc,EAAE,CAAC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CACtC,KAAK,EAAE,mBAAmB,EAC1B,GAAG,EAAE,SAAS,GACf,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAczB"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Build a schema.org SiteNavigationElement whose `hasPart` is a list of
3
+ * sub-SiteNavigationElement entries (one per nav link).
4
+ */
5
+ export function buildSiteNavigationElement(input, ids) {
6
+ const hasPart = input.items.map((item) => ({
7
+ '@type': 'SiteNavigationElement',
8
+ name: item.name,
9
+ url: item.url,
10
+ }));
11
+ return {
12
+ '@type': 'SiteNavigationElement',
13
+ '@id': ids.navigation,
14
+ name: input.name,
15
+ isPartOf: input.isPartOf,
16
+ hasPart,
17
+ ...input.extra,
18
+ };
19
+ }
20
+ //# sourceMappingURL=navigation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"navigation.js","sourceRoot":"","sources":["../../src/pieces/navigation.ts"],"names":[],"mappings":"AAiBA;;;GAGG;AACH,MAAM,UAAU,0BAA0B,CACtC,KAA0B,EAC1B,GAAc;IAEd,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACvC,OAAO,EAAE,uBAAuB;QAChC,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,GAAG,EAAE,IAAI,CAAC,GAAG;KAChB,CAAC,CAAC,CAAC;IACJ,OAAO;QACH,OAAO,EAAE,uBAAuB;QAChC,KAAK,EAAE,GAAG,CAAC,UAAU;QACrB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,OAAO;QACP,GAAG,KAAK,CAAC,KAAK;KACjB,CAAC;AACN,CAAC"}
@@ -0,0 +1,33 @@
1
+ import type { IdFactory } from '../ids.js';
2
+ export interface OrganizationInput {
3
+ /** Stable slug used for the @id. */
4
+ slug: string;
5
+ name: string;
6
+ url?: string;
7
+ description?: string;
8
+ /** Logo URL (raw string) or reference to an ImageObject. */
9
+ logo?: string | {
10
+ '@id': string;
11
+ };
12
+ sameAs?: readonly string[];
13
+ /** Escape hatch for schema.org properties specific to a subtype. */
14
+ extra?: Record<string, unknown>;
15
+ }
16
+ /**
17
+ * Build a schema.org Organization piece, or any of its subtypes. Pass the
18
+ * concrete @type as the third argument to set the subtype:
19
+ *
20
+ * ```ts
21
+ * import type { Hotel } from 'schema-dts';
22
+ * const hotel = buildOrganization<Hotel>(
23
+ * { slug: 'la-limonaia', name: 'La Limonaia', extra: { checkinTime: '16:00' } },
24
+ * ids,
25
+ * 'Hotel',
26
+ * );
27
+ * ```
28
+ *
29
+ * The generic type parameter is advisory — it flows schema-dts autocomplete
30
+ * into the `extra` field at call sites when you give it a concrete subtype.
31
+ */
32
+ export declare function buildOrganization(input: OrganizationInput, ids: IdFactory, subtype?: string): Record<string, unknown>;
33
+ //# sourceMappingURL=organization.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"organization.d.ts","sourceRoot":"","sources":["../../src/pieces/organization.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAE3C,MAAM,WAAW,iBAAiB;IAC9B,oCAAoC;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4DAA4D;IAC5D,IAAI,CAAC,EAAE,MAAM,GAAG;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAClC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B,oEAAoE;IACpE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,iBAAiB,CAC7B,KAAK,EAAE,iBAAiB,EACxB,GAAG,EAAE,SAAS,EACd,OAAO,GAAE,MAAuB,GACjC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAWzB"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Build a schema.org Organization piece, or any of its subtypes. Pass the
3
+ * concrete @type as the third argument to set the subtype:
4
+ *
5
+ * ```ts
6
+ * import type { Hotel } from 'schema-dts';
7
+ * const hotel = buildOrganization<Hotel>(
8
+ * { slug: 'la-limonaia', name: 'La Limonaia', extra: { checkinTime: '16:00' } },
9
+ * ids,
10
+ * 'Hotel',
11
+ * );
12
+ * ```
13
+ *
14
+ * The generic type parameter is advisory — it flows schema-dts autocomplete
15
+ * into the `extra` field at call sites when you give it a concrete subtype.
16
+ */
17
+ export function buildOrganization(input, ids, subtype = 'Organization') {
18
+ const piece = {
19
+ '@type': subtype,
20
+ '@id': ids.organization(input.slug),
21
+ name: input.name,
22
+ };
23
+ if (input.url !== undefined)
24
+ piece.url = input.url;
25
+ if (input.description !== undefined)
26
+ piece.description = input.description;
27
+ if (input.logo !== undefined)
28
+ piece.logo = input.logo;
29
+ if (input.sameAs !== undefined)
30
+ piece.sameAs = input.sameAs;
31
+ return { ...piece, ...input.extra };
32
+ }
33
+ //# sourceMappingURL=organization.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"organization.js","sourceRoot":"","sources":["../../src/pieces/organization.ts"],"names":[],"mappings":"AAeA;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,iBAAiB,CAC7B,KAAwB,EACxB,GAAc,EACd,UAAkB,cAAc;IAEhC,MAAM,KAAK,GAA4B;QACnC,OAAO,EAAE,OAAO;QAChB,KAAK,EAAE,GAAG,CAAC,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC;QACnC,IAAI,EAAE,KAAK,CAAC,IAAI;KACnB,CAAC;IACF,IAAI,KAAK,CAAC,GAAG,KAAK,SAAS;QAAE,KAAK,CAAC,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC;IACnD,IAAI,KAAK,CAAC,WAAW,KAAK,SAAS;QAAE,KAAK,CAAC,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC;IAC3E,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS;QAAE,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;IACtD,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS;QAAE,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;IAC5D,OAAO,EAAE,GAAG,KAAK,EAAE,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC;AACxC,CAAC"}
@@ -0,0 +1,36 @@
1
+ import type { IdFactory } from '../ids.js';
2
+ /**
3
+ * Input for a Person piece. All fields except `name` are optional, and
4
+ * any field not explicitly supported here can be passed via `extra`.
5
+ *
6
+ * This intentionally mirrors schema.org's Person vocabulary. We don't
7
+ * re-type every field; the shape is a `Record<string, unknown>` so
8
+ * consumers can pass arbitrary schema.org properties without a version
9
+ * upgrade of this package.
10
+ */
11
+ export interface PersonInput {
12
+ name: string;
13
+ familyName?: string;
14
+ birthDate?: string;
15
+ gender?: string;
16
+ nationality?: {
17
+ '@id': string;
18
+ };
19
+ description?: string;
20
+ jobTitle?: string;
21
+ knowsLanguage?: readonly string[];
22
+ url?: string;
23
+ image?: {
24
+ '@id': string;
25
+ };
26
+ sameAs?: readonly string[];
27
+ worksFor?: ReadonlyArray<Record<string, unknown>>;
28
+ spouse?: Record<string, unknown>;
29
+ children?: ReadonlyArray<Record<string, unknown>>;
30
+ extra?: Record<string, unknown>;
31
+ }
32
+ /**
33
+ * Build a schema.org Person piece using the site-wide Person @id.
34
+ */
35
+ export declare function buildPerson(input: PersonInput, ids: IdFactory): Record<string, unknown>;
36
+ //# sourceMappingURL=person.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"person.d.ts","sourceRoot":"","sources":["../../src/pieces/person.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAE3C;;;;;;;;GAQG;AACH,MAAM,WAAW,WAAW;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAChC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1B,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B,QAAQ,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAClD,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,QAAQ,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAClD,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,EAAE,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAQvF"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Build a schema.org Person piece using the site-wide Person @id.
3
+ */
4
+ export function buildPerson(input, ids) {
5
+ const { extra, ...rest } = input;
6
+ return {
7
+ '@type': 'Person',
8
+ '@id': ids.person,
9
+ ...rest,
10
+ ...extra,
11
+ };
12
+ }
13
+ //# sourceMappingURL=person.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"person.js","sourceRoot":"","sources":["../../src/pieces/person.ts"],"names":[],"mappings":"AA6BA;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,KAAkB,EAAE,GAAc;IAC1D,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI,EAAE,GAAG,KAAK,CAAC;IACjC,OAAO;QACH,OAAO,EAAE,QAAQ;QACjB,KAAK,EAAE,GAAG,CAAC,MAAM;QACjB,GAAG,IAAI;QACP,GAAG,KAAK;KACX,CAAC;AACN,CAAC"}
@@ -0,0 +1,35 @@
1
+ import type { IdFactory } from '../ids.js';
2
+ import type { Reference } from '../types.js';
3
+ export interface VideoObjectInput {
4
+ /**
5
+ * Canonical URL of the page the video lives on. The @id is
6
+ * `${url}#video`.
7
+ */
8
+ url: string;
9
+ name: string;
10
+ description: string;
11
+ /** Reference to the enclosing WebPage (usually ids.webPage(url)). */
12
+ isPartOf: Reference;
13
+ /** YouTube video id — used to derive thumbnailUrl and embedUrl. */
14
+ youtubeId?: string;
15
+ /**
16
+ * Explicit thumbnail URL. If omitted and `youtubeId` is set, defaults
17
+ * to `https://img.youtube.com/vi/{id}/maxresdefault.jpg`.
18
+ */
19
+ thumbnailUrl?: string;
20
+ /**
21
+ * Explicit embed URL. If omitted and `youtubeId` is set, defaults to
22
+ * `https://www.youtube-nocookie.com/embed/{id}`.
23
+ */
24
+ embedUrl?: string;
25
+ uploadDate?: Date;
26
+ /** ISO 8601 duration, e.g. 'PT30M'. */
27
+ duration?: string;
28
+ transcript?: string;
29
+ extra?: Record<string, unknown>;
30
+ }
31
+ /**
32
+ * Build a schema.org VideoObject piece.
33
+ */
34
+ export declare function buildVideoObject(input: VideoObjectInput, ids: IdFactory): Record<string, unknown>;
35
+ //# sourceMappingURL=video.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"video.d.ts","sourceRoot":"","sources":["../../src/pieces/video.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,MAAM,WAAW,gBAAgB;IAC7B;;;OAGG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,qEAAqE;IACrE,QAAQ,EAAE,SAAS,CAAC;IACpB,mEAAmE;IACnE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,IAAI,CAAC;IAClB,uCAAuC;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC5B,KAAK,EAAE,gBAAgB,EACvB,GAAG,EAAE,SAAS,GACf,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CA4BzB"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Build a schema.org VideoObject piece.
3
+ */
4
+ export function buildVideoObject(input, ids) {
5
+ const piece = {
6
+ '@type': 'VideoObject',
7
+ '@id': ids.videoObject(input.url),
8
+ name: input.name,
9
+ description: input.description,
10
+ isPartOf: input.isPartOf,
11
+ };
12
+ const thumbnail = input.thumbnailUrl ??
13
+ (input.youtubeId !== undefined
14
+ ? `https://img.youtube.com/vi/${input.youtubeId}/maxresdefault.jpg`
15
+ : undefined);
16
+ if (thumbnail !== undefined)
17
+ piece.thumbnailUrl = thumbnail;
18
+ const embed = input.embedUrl ??
19
+ (input.youtubeId !== undefined
20
+ ? `https://www.youtube-nocookie.com/embed/${input.youtubeId}`
21
+ : undefined);
22
+ if (embed !== undefined)
23
+ piece.embedUrl = embed;
24
+ if (input.uploadDate !== undefined)
25
+ piece.uploadDate = input.uploadDate.toISOString();
26
+ if (input.duration !== undefined)
27
+ piece.duration = input.duration;
28
+ if (input.transcript !== undefined)
29
+ piece.transcript = input.transcript;
30
+ return { ...piece, ...input.extra };
31
+ }
32
+ //# sourceMappingURL=video.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"video.js","sourceRoot":"","sources":["../../src/pieces/video.ts"],"names":[],"mappings":"AAgCA;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAC5B,KAAuB,EACvB,GAAc;IAEd,MAAM,KAAK,GAA4B;QACnC,OAAO,EAAE,aAAa;QACtB,KAAK,EAAE,GAAG,CAAC,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC;QACjC,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,QAAQ,EAAE,KAAK,CAAC,QAAQ;KAC3B,CAAC;IAEF,MAAM,SAAS,GACX,KAAK,CAAC,YAAY;QAClB,CAAC,KAAK,CAAC,SAAS,KAAK,SAAS;YAC1B,CAAC,CAAC,8BAA8B,KAAK,CAAC,SAAS,oBAAoB;YACnE,CAAC,CAAC,SAAS,CAAC,CAAC;IACrB,IAAI,SAAS,KAAK,SAAS;QAAE,KAAK,CAAC,YAAY,GAAG,SAAS,CAAC;IAE5D,MAAM,KAAK,GACP,KAAK,CAAC,QAAQ;QACd,CAAC,KAAK,CAAC,SAAS,KAAK,SAAS;YAC1B,CAAC,CAAC,0CAA0C,KAAK,CAAC,SAAS,EAAE;YAC7D,CAAC,CAAC,SAAS,CAAC,CAAC;IACrB,IAAI,KAAK,KAAK,SAAS;QAAE,KAAK,CAAC,QAAQ,GAAG,KAAK,CAAC;IAEhD,IAAI,KAAK,CAAC,UAAU,KAAK,SAAS;QAAE,KAAK,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC;IACtF,IAAI,KAAK,CAAC,QAAQ,KAAK,SAAS;QAAE,KAAK,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC;IAClE,IAAI,KAAK,CAAC,UAAU,KAAK,SAAS;QAAE,KAAK,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC;IAExE,OAAO,EAAE,GAAG,KAAK,EAAE,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC;AACxC,CAAC"}
@@ -0,0 +1,45 @@
1
+ import type { IdFactory } from '../ids.js';
2
+ import type { Reference } from '../types.js';
3
+ /**
4
+ * Concrete WebPage subtype. `WebPage` is the default; use `ProfilePage`
5
+ * for /about-me style pages and `CollectionPage` for index/listing pages.
6
+ */
7
+ export type WebPageType = 'WebPage' | 'ProfilePage' | 'CollectionPage';
8
+ export interface WebPageInput {
9
+ /** Canonical URL of the page. The WebPage @id equals this URL. */
10
+ url: string;
11
+ /** Page title (becomes `name`). */
12
+ name: string;
13
+ /** Reference to the site-wide WebSite (usually ids.website). */
14
+ isPartOf: Reference;
15
+ /** Reference to the BreadcrumbList for this page (usually ids.breadcrumb(url)). */
16
+ breadcrumb: Reference;
17
+ inLanguage?: string;
18
+ /** Publish date — emitted as ISO string. */
19
+ datePublished?: Date;
20
+ /** Update date — emitted as ISO string. */
21
+ dateModified?: Date;
22
+ /** Reference to the primary ImageObject, if any. */
23
+ primaryImage?: Reference;
24
+ /**
25
+ * Reference to the entity this page is "about" — used for ProfilePage
26
+ * (the Person) and homepage variants.
27
+ */
28
+ about?: Reference;
29
+ /**
30
+ * Custom potentialAction. If omitted, defaults to a single ReadAction
31
+ * targeting the page URL.
32
+ */
33
+ potentialAction?: ReadonlyArray<Record<string, unknown>>;
34
+ extra?: Record<string, unknown>;
35
+ }
36
+ /**
37
+ * Build a schema.org WebPage (or ProfilePage / CollectionPage) piece.
38
+ *
39
+ * Choose the concrete subtype via the second argument; defaults to
40
+ * `WebPage`. Dispatch (e.g. "blog listing pages use CollectionPage")
41
+ * is a caller concern, not a core concern — core ships the primitives
42
+ * and lets the caller decide.
43
+ */
44
+ export declare function buildWebPage(input: WebPageInput, ids: IdFactory, type?: WebPageType): Record<string, unknown>;
45
+ //# sourceMappingURL=webpage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webpage.d.ts","sourceRoot":"","sources":["../../src/pieces/webpage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C;;;GAGG;AACH,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,aAAa,GAAG,gBAAgB,CAAC;AAEvE,MAAM,WAAW,YAAY;IACzB,kEAAkE;IAClE,GAAG,EAAE,MAAM,CAAC;IACZ,mCAAmC;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,gEAAgE;IAChE,QAAQ,EAAE,SAAS,CAAC;IACpB,mFAAmF;IACnF,UAAU,EAAE,SAAS,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4CAA4C;IAC5C,aAAa,CAAC,EAAE,IAAI,CAAC;IACrB,2CAA2C;IAC3C,YAAY,CAAC,EAAE,IAAI,CAAC;IACpB,oDAAoD;IACpD,YAAY,CAAC,EAAE,SAAS,CAAC;IACzB;;;OAGG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB;;;OAGG;IACH,eAAe,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACzD,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CACxB,KAAK,EAAE,YAAY,EACnB,GAAG,EAAE,SAAS,EACd,IAAI,GAAE,WAAuB,GAC9B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CA8BzB"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Build a schema.org WebPage (or ProfilePage / CollectionPage) piece.
3
+ *
4
+ * Choose the concrete subtype via the second argument; defaults to
5
+ * `WebPage`. Dispatch (e.g. "blog listing pages use CollectionPage")
6
+ * is a caller concern, not a core concern — core ships the primitives
7
+ * and lets the caller decide.
8
+ */
9
+ export function buildWebPage(input, ids, type = 'WebPage') {
10
+ const potentialAction = input.potentialAction ?? [
11
+ { '@type': 'ReadAction', target: [input.url] },
12
+ ];
13
+ const piece = {
14
+ '@type': type,
15
+ '@id': ids.webPage(input.url),
16
+ url: input.url,
17
+ name: input.name,
18
+ isPartOf: input.isPartOf,
19
+ breadcrumb: input.breadcrumb,
20
+ inLanguage: input.inLanguage ?? 'en-US',
21
+ potentialAction,
22
+ };
23
+ if (input.datePublished !== undefined) {
24
+ piece.datePublished = input.datePublished.toISOString();
25
+ }
26
+ if (input.dateModified !== undefined) {
27
+ piece.dateModified = input.dateModified.toISOString();
28
+ }
29
+ if (input.primaryImage !== undefined) {
30
+ piece.primaryImageOfPage = input.primaryImage;
31
+ }
32
+ if (input.about !== undefined) {
33
+ piece.about = input.about;
34
+ }
35
+ return { ...piece, ...input.extra };
36
+ }
37
+ //# sourceMappingURL=webpage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webpage.js","sourceRoot":"","sources":["../../src/pieces/webpage.ts"],"names":[],"mappings":"AAsCA;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CACxB,KAAmB,EACnB,GAAc,EACd,OAAoB,SAAS;IAE7B,MAAM,eAAe,GAA2C,KAAK,CAAC,eAAe,IAAI;QACrF,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE;KACjD,CAAC;IAEF,MAAM,KAAK,GAA4B;QACnC,OAAO,EAAE,IAAI;QACb,KAAK,EAAE,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC;QAC7B,GAAG,EAAE,KAAK,CAAC,GAAG;QACd,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,UAAU,EAAE,KAAK,CAAC,UAAU,IAAI,OAAO;QACvC,eAAe;KAClB,CAAC;IAEF,IAAI,KAAK,CAAC,aAAa,KAAK,SAAS,EAAE,CAAC;QACpC,KAAK,CAAC,aAAa,GAAG,KAAK,CAAC,aAAa,CAAC,WAAW,EAAE,CAAC;IAC5D,CAAC;IACD,IAAI,KAAK,CAAC,YAAY,KAAK,SAAS,EAAE,CAAC;QACnC,KAAK,CAAC,YAAY,GAAG,KAAK,CAAC,YAAY,CAAC,WAAW,EAAE,CAAC;IAC1D,CAAC;IACD,IAAI,KAAK,CAAC,YAAY,KAAK,SAAS,EAAE,CAAC;QACnC,KAAK,CAAC,kBAAkB,GAAG,KAAK,CAAC,YAAY,CAAC;IAClD,CAAC;IACD,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QAC5B,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;IAC9B,CAAC;IAED,OAAO,EAAE,GAAG,KAAK,EAAE,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC;AACxC,CAAC"}
@@ -0,0 +1,22 @@
1
+ import type { IdFactory } from '../ids.js';
2
+ import type { Reference } from '../types.js';
3
+ export interface WebSiteInput {
4
+ /** Site URL, typically with trailing slash. */
5
+ url: string;
6
+ name: string;
7
+ description?: string;
8
+ /** Publisher entity — usually the site-wide Person or Organization. */
9
+ publisher: Reference;
10
+ /** Default content language, e.g. 'en-US'. */
11
+ inLanguage?: string;
12
+ /** Optional navigation reference (e.g. ids.navigation). */
13
+ hasPart?: Reference;
14
+ /** Escape hatch for extra schema.org properties. */
15
+ extra?: Record<string, unknown>;
16
+ }
17
+ /**
18
+ * Build a schema.org WebSite piece. This is the site-wide singleton;
19
+ * every page's WebPage should reference it via `isPartOf`.
20
+ */
21
+ export declare function buildWebSite(input: WebSiteInput, ids: IdFactory): Record<string, unknown>;
22
+ //# sourceMappingURL=website.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"website.d.ts","sourceRoot":"","sources":["../../src/pieces/website.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,MAAM,WAAW,YAAY;IACzB,+CAA+C;IAC/C,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uEAAuE;IACvE,SAAS,EAAE,SAAS,CAAC;IACrB,8CAA8C;IAC9C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,2DAA2D;IAC3D,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,oDAAoD;IACpD,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,YAAY,EAAE,GAAG,EAAE,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAYzF"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Build a schema.org WebSite piece. This is the site-wide singleton;
3
+ * every page's WebPage should reference it via `isPartOf`.
4
+ */
5
+ export function buildWebSite(input, ids) {
6
+ const piece = {
7
+ '@type': 'WebSite',
8
+ '@id': ids.website,
9
+ url: input.url,
10
+ name: input.name,
11
+ };
12
+ if (input.description !== undefined)
13
+ piece.description = input.description;
14
+ piece.publisher = input.publisher;
15
+ piece.inLanguage = input.inLanguage ?? 'en-US';
16
+ if (input.hasPart !== undefined)
17
+ piece.hasPart = input.hasPart;
18
+ return { ...piece, ...input.extra };
19
+ }
20
+ //# sourceMappingURL=website.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"website.js","sourceRoot":"","sources":["../../src/pieces/website.ts"],"names":[],"mappings":"AAkBA;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,KAAmB,EAAE,GAAc;IAC5D,MAAM,KAAK,GAA4B;QACnC,OAAO,EAAE,SAAS;QAClB,KAAK,EAAE,GAAG,CAAC,OAAO;QAClB,GAAG,EAAE,KAAK,CAAC,GAAG;QACd,IAAI,EAAE,KAAK,CAAC,IAAI;KACnB,CAAC;IACF,IAAI,KAAK,CAAC,WAAW,KAAK,SAAS;QAAE,KAAK,CAAC,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC;IAC3E,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC,SAAS,CAAC;IAClC,KAAK,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,IAAI,OAAO,CAAC;IAC/C,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS;QAAE,KAAK,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;IAC/D,OAAO,EAAE,GAAG,KAAK,EAAE,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC;AACxC,CAAC"}
@@ -0,0 +1,30 @@
1
+ import type { Thing, WithContext } from 'schema-dts';
2
+ /**
3
+ * A reference to another entity in the @graph, by its @id.
4
+ *
5
+ * Most schema.org entities link to each other via `{ '@id': string }`.
6
+ * Some consumers (notably joost.blog's Article.author) include the `name`
7
+ * alongside the id, which is redundant but valid schema.org. The optional
8
+ * `name` field lets callers opt into that pattern.
9
+ */
10
+ export interface Reference {
11
+ '@id': string;
12
+ name?: string;
13
+ }
14
+ /**
15
+ * The assembled @graph produced by `assembleGraph`.
16
+ */
17
+ export type SchemaGraph<T extends Thing = Thing> = WithContext<Thing> & {
18
+ '@context': 'https://schema.org';
19
+ '@graph': T[];
20
+ };
21
+ /**
22
+ * A single entity in the graph, as returned by a piece builder.
23
+ * All entities should carry an `@id` so they can be cross-referenced.
24
+ */
25
+ export interface GraphEntity {
26
+ '@type': string | readonly string[];
27
+ '@id'?: string;
28
+ [key: string]: unknown;
29
+ }
30
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAErD;;;;;;;GAOG;AACH,MAAM,WAAW,SAAS;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,KAAK,GAAG,KAAK,IAAI,WAAW,CAAC,KAAK,CAAC,GAAG;IACpE,UAAU,EAAE,oBAAoB,CAAC;IACjC,QAAQ,EAAE,CAAC,EAAE,CAAC;CACjB,CAAC;AAEF;;;GAGG;AACH,MAAM,WAAW,WAAW;IACxB,OAAO,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAAC;IACpC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CAC1B"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@jdevalk/seo-graph-core",
3
+ "version": "0.1.0-alpha.0",
4
+ "description": "Pure schema.org JSON-LD graph builders. Runtime-agnostic core for agent-ready SEO.",
5
+ "keywords": [
6
+ "schema.org",
7
+ "json-ld",
8
+ "seo",
9
+ "agent-ready",
10
+ "structured-data"
11
+ ],
12
+ "author": "Joost de Valk <joost@joost.blog>",
13
+ "license": "MIT",
14
+ "type": "module",
15
+ "main": "./dist/index.js",
16
+ "types": "./dist/index.d.ts",
17
+ "exports": {
18
+ ".": {
19
+ "types": "./dist/index.d.ts",
20
+ "import": "./dist/index.js"
21
+ }
22
+ },
23
+ "files": [
24
+ "dist",
25
+ "README.md",
26
+ "LICENSE"
27
+ ],
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "git+https://github.com/jdevalk/seo-graph.git",
31
+ "directory": "packages/seo-graph-core"
32
+ },
33
+ "bugs": "https://github.com/jdevalk/seo-graph/issues",
34
+ "homepage": "https://github.com/jdevalk/seo-graph/tree/main/packages/seo-graph-core#readme",
35
+ "publishConfig": {
36
+ "access": "public"
37
+ },
38
+ "dependencies": {
39
+ "schema-dts": "^2.0.0"
40
+ },
41
+ "devDependencies": {
42
+ "@types/node": "^22.0.0",
43
+ "typescript": "^5.6.0",
44
+ "vitest": "^2.0.0"
45
+ },
46
+ "scripts": {
47
+ "build": "tsc -p tsconfig.build.json",
48
+ "typecheck": "tsc -p tsconfig.json",
49
+ "test": "vitest run"
50
+ }
51
+ }