@jdevalk/seo-graph-core 0.6.1 → 0.7.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/AGENTS.md CHANGED
@@ -24,6 +24,38 @@ Two packages:
24
24
 
25
25
  ---
26
26
 
27
+ ## Contents
28
+
29
+ **Schema core** — concepts and builders for the JSON-LD graph:
30
+
31
+ - [Architecture](#architecture)
32
+ - [Installation](#installation)
33
+ - [The @id system](#the-id-system)
34
+ - [Piece builders reference](#piece-builders-reference)
35
+
36
+ **Recipes and patterns** — how to model real sites:
37
+
38
+ - [Site type recipes](#site-type-recipes)
39
+ - [Trust and credibility signals](#trust-and-credibility-signals)
40
+ - [Choosing the right Article subtype](#choosing-the-right-article-subtype)
41
+ - [Actions: telling agents what they can do](#actions-telling-agents-what-they-can-do)
42
+ - [Multi-type entities](#multi-type-entities)
43
+ - [Rich Organization patterns](#rich-organization-patterns)
44
+ - [Rich Person patterns](#rich-person-patterns)
45
+ - [Reference implementations](#reference-implementations)
46
+
47
+ **Astro integration** — runtime component and build-time checks:
48
+
49
+ - [Astro integration guide](#astro-integration-guide) — the `<Seo>` component, hreflang, schema endpoints
50
+ - [Build-time integration](#build-time-integration) — `seoGraph()` hook, H1 validation, metadata uniqueness, IndexNow, `llms.txt`
51
+ - [Complete integration example](#complete-integration-example)
52
+ - [Advanced patterns](#advanced-patterns)
53
+ - [Common mistakes](#common-mistakes)
54
+ - [Validating your output](#validating-your-output)
55
+ - [Repository structure](#repository-structure)
56
+
57
+ ---
58
+
27
59
  ## Architecture
28
60
 
29
61
  ```
@@ -2484,10 +2516,89 @@ export const GET = createSchemaMap({
2484
2516
  **Schema map entry options:**
2485
2517
  | Field | Type | Default | Purpose |
2486
2518
  |---|---|---|---|
2487
- | `path` | `string` | — | Relative path to schema endpoint |
2488
- | `lastModified` | `Date` | — | Last modification date |
2489
- | `changeFreq` | Sitemap frequency string | `'daily'` | Update frequency hint |
2490
- | `priority` | `number` | `0.8` | Priority hint (0.0-1.0) |
2519
+ | `path` | `string` | — | Path of the schema endpoint. Leading slash optional. |
2520
+ | `lastModified` | `Date` | — | Last-modified date. Rendered as `YYYY-MM-DD`. |
2521
+
2522
+ **`createSchemaMap` options:**
2523
+ | Option | Type | Default | Purpose |
2524
+ |---|---|---|---|
2525
+ | `siteUrl` | `string` | — | Canonical origin. Trailing slash stripped. |
2526
+ | `entries` | `SchemaMapEntry[]` | — | One entry per schema endpoint. |
2527
+ | `cacheControl` | `string \| null` | `'max-age=300'` | Cache-Control header. `null` to omit. |
2528
+
2529
+ `<changefreq>` and `<priority>` are deliberately not emitted —
2530
+ Google and other major crawlers ignore them, and fabricating defaults
2531
+ is worse than omitting.
2532
+
2533
+ ### API catalog (RFC 9727)
2534
+
2535
+ Serve a standards-compliant API catalog at `/.well-known/api-catalog`
2536
+ ([RFC 9727](https://www.rfc-editor.org/rfc/rfc9727)) so agent crawlers
2537
+ can discover the site's APIs in one fetch:
2538
+
2539
+ ```ts
2540
+ // src/pages/.well-known/api-catalog.ts
2541
+ import { createApiCatalog } from '@jdevalk/astro-seo-graph';
2542
+
2543
+ export const GET = createApiCatalog({
2544
+ siteUrl: 'https://example.com',
2545
+ schemaEndpoints: [
2546
+ { path: '/schema/post.json', schemaType: 'BlogPosting', serviceDoc: '/seo-graph/' },
2547
+ { path: '/schema/page.json', schemaType: 'WebPage', serviceDoc: '/seo-graph/' },
2548
+ ],
2549
+ schemaMap: { path: '/schemamap.xml', serviceDoc: '/seo-graph/' },
2550
+ additional: [
2551
+ { anchor: '/ask', serviceDoc: '/ask-docs/', type: 'https://schema.org/SearchAction' },
2552
+ ],
2553
+ });
2554
+ ```
2555
+
2556
+ Output is `application/linkset+json` ([RFC 9264](https://www.rfc-editor.org/rfc/rfc9264)).
2557
+ `schemaEndpoints` get auto-typed as `https://schema.org/<schemaType>`;
2558
+ `schemaMap` is emitted without a `type` (no standard one exists);
2559
+ `additional` accepts free-form `anchor`/`serviceDoc`/`type` (each
2560
+ either `string` or `string[]`). Relative paths are absolutized against
2561
+ `siteUrl`; absolute URLs pass through unchanged.
2562
+
2563
+ The package also exports a `CATALOG_PATH` constant
2564
+ (`'/.well-known/api-catalog'`) so callers can reference the canonical
2565
+ location without duplicating the string.
2566
+
2567
+ **Options:**
2568
+ | Option | Type | Default | Purpose |
2569
+ |---|---|---|---|
2570
+ | `siteUrl` | `string` | — | Canonical origin. Trailing slash stripped. |
2571
+ | `schemaEndpoints` | `ApiCatalogSchemaEndpointEntry[]` | — | Schema.org JSON endpoints with `path` + `schemaType`. |
2572
+ | `schemaMap` | `ApiCatalogSchemaMapEntry` | — | Path of the `createSchemaMap` route. |
2573
+ | `additional` | `ApiCatalogEntry[]` | — | Site-specific APIs not covered by the package factories. |
2574
+ | `cacheControl` | `string \| null` | `'max-age=300'` | Cache-Control header. `null` to omit. |
2575
+ | `contentType` | `string` | `'application/linkset+json'` | Override only with reason. |
2576
+ | `indent` | `number` | `2` | JSON indentation. `0` for compact. |
2577
+
2578
+ ### Last-modified dates from git
2579
+
2580
+ `gitLastmod` reads the committer date of the most recent git commit
2581
+ that touched a file, with configurable `excludeCommits` (skip bulk
2582
+ imports / reformats / renames) and `depth` (how many commits to
2583
+ inspect). Use it to feed `dateModified` on JSON-LD pieces or
2584
+ `<lastmod>` in sitemaps without trusting filesystem `mtime` (which
2585
+ gets rewritten on every CI checkout):
2586
+
2587
+ ```ts
2588
+ import { gitLastmod } from '@jdevalk/astro-seo-graph';
2589
+
2590
+ const last = gitLastmod(`src/content/blog/${entry.id}/index.md`, {
2591
+ excludeCommits: ['52130a9', '989dc47'],
2592
+ depth: 20,
2593
+ });
2594
+ ```
2595
+
2596
+ Returns `null` when the file has no git history, git isn't on the
2597
+ PATH, or every commit in the inspected window is excluded — fall back
2598
+ to `publishDate` in that case. `excludeCommits` matches on the first 7
2599
+ characters of the SHA, so short hashes from `git log --oneline` work
2600
+ directly. Build-time only — shells out to the `git` binary via
2601
+ `execFileSync`.
2491
2602
 
2492
2603
  ### The `aggregate` function
2493
2604
 
@@ -2544,18 +2655,24 @@ const blog = defineCollection({
2544
2655
  }
2545
2656
  ```
2546
2657
 
2547
- ### `buildAstroSeoProps`
2658
+ ### `buildSeoContext`
2548
2659
 
2549
- Pure-TS function that powers `<Seo>` internally. Use when you want to feed a
2550
- different head component:
2660
+ Pure-TS function that powers `<Seo>` internally. Returns a flat,
2661
+ render-ready normalization of `SeoProps` (resolved title, canonical, OG
2662
+ fields, hreflang entries, robots directives, twitter overrides). Use when
2663
+ you want to render the head yourself:
2551
2664
 
2552
2665
  ```ts
2553
- import { buildAstroSeoProps } from '@jdevalk/astro-seo-graph';
2666
+ import { buildSeoContext } from '@jdevalk/astro-seo-graph';
2554
2667
 
2555
- const astroSeoProps = buildAstroSeoProps(mySeoProps, Astro.url.href);
2556
- // Pass to astro-seo's <SEO> or any custom head component
2668
+ const ctx = buildSeoContext(mySeoProps, Astro.url.href);
2669
+ // ctx.title, ctx.canonical, ctx.og.*, ctx.twitter, ctx.hreflangs, ...
2557
2670
  ```
2558
2671
 
2672
+ The companion constant `ROBOTS_EXTRAS` exposes the
2673
+ `max-snippet:-1, max-image-preview:large, max-video-preview:-1`
2674
+ directives that `<Seo>` always appends to the robots tag.
2675
+
2559
2676
  ### `buildAlternateLinks`
2560
2677
 
2561
2678
  Pure helper for hreflang link generation. No Astro runtime needed — safe
@@ -2576,6 +2693,246 @@ const links = buildAlternateLinks({
2576
2693
 
2577
2694
  ---
2578
2695
 
2696
+ ## Build-time integration
2697
+
2698
+ `@jdevalk/astro-seo-graph/integration` exports a default `seoGraph()`
2699
+ function that returns an Astro integration. It hooks `astro:build:done`
2700
+ to run cross-page SEO checks and optional post-build actions against the
2701
+ static HTML output. SSR pages aren't on disk at build time, so they're
2702
+ not checked.
2703
+
2704
+ ```js
2705
+ // astro.config.mjs
2706
+ import { defineConfig } from 'astro/config';
2707
+ import seoGraph from '@jdevalk/astro-seo-graph/integration';
2708
+
2709
+ export default defineConfig({
2710
+ site: 'https://example.com',
2711
+ integrations: [
2712
+ seoGraph({
2713
+ // All options below are optional; listed with defaults.
2714
+ validateH1: true,
2715
+ validateUniqueMetadata: true,
2716
+ validateImageAlt: true,
2717
+ validateMetadataLength: true, // or { title: { max: 60 }, ... }
2718
+ validateInternalLinks: true, // or { skip: (href) => href.startsWith('/api/') }
2719
+ // indexNow: { ... },
2720
+ // llmsTxt: { ... },
2721
+ }),
2722
+ ],
2723
+ });
2724
+ ```
2725
+
2726
+ ### Options
2727
+
2728
+ | Option | Default | Purpose |
2729
+ | ------------------------ | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
2730
+ | `validateH1` | `true` | Warn when a page has zero or >1 `<h1>` elements. |
2731
+ | `validateUniqueMetadata` | `true` | Warn when two pages share the same `<title>` or meta description. |
2732
+ | `validateImageAlt` | `true` | Warn when a page has `<img>` tags missing an `alt` attribute. |
2733
+ | `validateMetadataLength` | `true` | Warn when `<title>` or description length falls outside SERP-friendly bounds (title 30–65, description 70–200 by default; overridable per-field). |
2734
+ | `validateInternalLinks` | `true` | Warn on trailing-slash mismatches and links to pages not in the build. Accepts `{ skip }` to exclude SSR-only routes. |
2735
+ | `indexNow` | — | Submit built URLs to IndexNow. Omit to disable. |
2736
+ | `llmsTxt` | — | Generate `llms.txt` at the root of the build output. Omit to disable. |
2737
+
2738
+ ### H1 and metadata validation
2739
+
2740
+ `validateH1` flags pages with missing or duplicate `<h1>` elements — the
2741
+ most common on-page SEO/accessibility miss. `validateUniqueMetadata`
2742
+ flags `<title>` or `<meta name="description">` values that repeat across
2743
+ pages; duplicates hurt Google's ability to pick a canonical result and
2744
+ can only be spotted across the whole corpus. `validateImageAlt` flags
2745
+ `<img>` tags missing an `alt` attribute. WCAG-sanctioned decorative
2746
+ markers are respected: `alt=""` (the canonical pattern) and
2747
+ `role="presentation"`/`role="none"` (removes the image from the
2748
+ accessibility tree) are not flagged. Only a tag with neither triggers a
2749
+ warning.
2750
+
2751
+ `validateMetadataLength` flags `<title>` and `<meta name="description">`
2752
+ values outside the configured bounds. Pass `true` for the defaults
2753
+ (title 30–65, description 70–200) or an object to override per-field:
2754
+
2755
+ ```ts
2756
+ validateMetadataLength: {
2757
+ title: { min: 40, max: 60 },
2758
+ description: { max: 160 },
2759
+ },
2760
+ ```
2761
+
2762
+ `validateInternalLinks` scans `<a href>` values across every built page
2763
+ and flags two classes of issue: trailing-slash mismatches (e.g. linking
2764
+ to `/about-me` when the built page is `/about-me/` — "works" via
2765
+ redirect but wastes a round-trip on every click) and true 404s (links
2766
+ to paths not in the build). Only same-origin (via `config.site`) and
2767
+ root-relative links are checked; external URLs, `mailto:`, `tel:`, and
2768
+ fragment-only links are skipped.
2769
+
2770
+ Explicit redirects are honored by default: sources in
2771
+ `public/_redirects` (Netlify / Cloudflare Pages format) and literal
2772
+ keys in Astro's `redirects` config are treated as valid link targets.
2773
+ Dynamic rules (`*`, `:splat`, `[slug]` params) are skipped — use
2774
+ `skip` for those cases. Set `honorRedirects: false` to opt out (useful
2775
+ when auditing for redirect hops).
2776
+
2777
+ Pass `{ skip: (href) => boolean }` to exclude SSR-only routes or paths
2778
+ handled at the host/CDN layer.
2779
+
2780
+ The extractors, helpers, and the length resolver are exported for reuse:
2781
+
2782
+ ```ts
2783
+ import {
2784
+ classifyInternalLink,
2785
+ collectAstroRedirectSources,
2786
+ countH1s,
2787
+ DEFAULT_METADATA_LENGTH_BOUNDS,
2788
+ extractAnchorHrefs,
2789
+ extractTitle,
2790
+ extractMetaDescription,
2791
+ findImagesWithoutAlt,
2792
+ htmlFileToPath,
2793
+ parseNetlifyRedirects,
2794
+ resolveMetadataLengthBounds,
2795
+ } from '@jdevalk/astro-seo-graph/integration';
2796
+ ```
2797
+
2798
+ ### IndexNow submission
2799
+
2800
+ ```js
2801
+ seoGraph({
2802
+ indexNow: {
2803
+ key: process.env.INDEXNOW_KEY!, // 8–128 chars from [A-Za-z0-9-]
2804
+ host: 'example.com',
2805
+ siteUrl: 'https://example.com',
2806
+ // keyLocation?: defaults to https://<host>/<key>.txt
2807
+ // endpoint?: defaults to api.indexnow.org
2808
+ // filter?: (url) => boolean — composed on top of the built-in
2809
+ // /404 exclusion. Example skipping paginated archives:
2810
+ // filter: (url) => !/^\/blog\/\d+\/$/.test(new URL(url).pathname),
2811
+ },
2812
+ });
2813
+ ```
2814
+
2815
+ Only URLs on `host` are submitted. `index.html` paths are rewritten to
2816
+ their trailing-slash form. `/404` (and `/404/`) are always excluded —
2817
+ search engines don't need to be notified about the 404 page and
2818
+ submitting it wastes daily IndexNow quota.
2819
+
2820
+ **Deploy the key file first.** IndexNow verifies ownership by fetching
2821
+ `https://<host>/<key>.txt` on every submission. Submissions sent before
2822
+ the key is reachable in production get rejected (HTTP 403) and the key
2823
+ is treated as invalid — you'll have to rotate it. Serve the key via
2824
+ `createIndexNowKeyRoute` (see below), deploy, confirm the `.txt` loads
2825
+ over HTTPS, _then_ enable `indexNow` in the integration.
2826
+
2827
+ ```ts
2828
+ // src/pages/[your-key-here].txt.ts
2829
+ import { createIndexNowKeyRoute } from '@jdevalk/astro-seo-graph';
2830
+
2831
+ export const GET = createIndexNowKeyRoute({ key: 'your-key-here' });
2832
+ ```
2833
+
2834
+ The filename (minus `.txt.ts`) must equal the key.
2835
+
2836
+ #### Gating submission to the production branch
2837
+
2838
+ Preview and feature-branch deploys share the same IndexNow key as
2839
+ production but shouldn't notify search engines — submitting preview
2840
+ URLs wastes daily quota and can get the key flagged invalid (the host
2841
+ hasn't served those URLs yet).
2842
+
2843
+ `indexNowOnBranch(branch, options, productionBranch?)` passes the
2844
+ options through unchanged when `branch` matches `productionBranch`
2845
+ (default `"main"`) and returns `undefined` otherwise, so `seoGraph()`
2846
+ skips submission entirely on non-production deploys.
2847
+
2848
+ > **`import.meta.env` is not available in `astro.config.mjs`.** Astro
2849
+ > only exposes `import.meta.env` inside components and pages processed
2850
+ > by the Vite pipeline. Config files run in Node.js before Vite
2851
+ > starts, so you must read branch variables via `process.env` instead.
2852
+
2853
+ ```js
2854
+ import { defineConfig } from 'astro/config';
2855
+ import seoGraph, { indexNowOnBranch } from '@jdevalk/astro-seo-graph/integration';
2856
+
2857
+ export default defineConfig({
2858
+ integrations: [
2859
+ seoGraph({
2860
+ indexNow: indexNowOnBranch(process.env.CF_PAGES_BRANCH ?? '', {
2861
+ key: process.env.INDEXNOW_KEY,
2862
+ host: 'example.com',
2863
+ siteUrl: 'https://example.com',
2864
+ }),
2865
+ }),
2866
+ ],
2867
+ });
2868
+ ```
2869
+
2870
+ Platform branch variables:
2871
+
2872
+ - Cloudflare Pages: `process.env.CF_PAGES_BRANCH`
2873
+ - Vercel: `process.env.VERCEL_GIT_COMMIT_REF`
2874
+ - Netlify: `process.env.BRANCH`
2875
+
2876
+ Pass a third argument to use a branch name other than `"main"`:
2877
+
2878
+ ```js
2879
+ indexNowOnBranch(process.env.CF_PAGES_BRANCH ?? '', options, 'production');
2880
+ ```
2881
+
2882
+ ### llms.txt generation
2883
+
2884
+ Generates an [`llms.txt`](https://llmstxt.org) file — a markdown summary
2885
+ of the site that LLMs can use as a concise entry point.
2886
+
2887
+ ```js
2888
+ seoGraph({
2889
+ llmsTxt: {
2890
+ title: 'Example Site',
2891
+ siteUrl: 'https://example.com',
2892
+ summary: 'A demo site about X, Y, and Z.',
2893
+ // details?: extra paragraphs between summary and sections
2894
+ // sections?: user-supplied sections (skips auto-collection)
2895
+ // filter?: (url) => boolean — drop URLs from auto-section
2896
+ // autoSectionName?: defaults to 'Pages'
2897
+ // outputPath?: defaults to 'llms.txt'
2898
+ },
2899
+ });
2900
+ ```
2901
+
2902
+ By default, one "Pages" section is auto-generated from every built HTML
2903
+ file's `<title>` + meta description. Supply `sections` to take full
2904
+ control of the structure:
2905
+
2906
+ ```js
2907
+ llmsTxt: {
2908
+ title: 'Example Site',
2909
+ siteUrl: 'https://example.com',
2910
+ sections: [
2911
+ {
2912
+ name: 'Docs',
2913
+ links: [
2914
+ { url: 'https://example.com/docs/intro/', title: 'Intro', description: 'Start here' },
2915
+ ],
2916
+ },
2917
+ { name: 'Blog', links: [/* ... */] },
2918
+ ],
2919
+ }
2920
+ ```
2921
+
2922
+ The renderer is also exported for non-Astro contexts:
2923
+
2924
+ ```ts
2925
+ import { renderLlmsTxt } from '@jdevalk/astro-seo-graph';
2926
+
2927
+ const markdown = renderLlmsTxt({
2928
+ title: 'Example',
2929
+ summary: 'A demo site.',
2930
+ sections: [{ name: 'Pages', links: [{ url: 'https://x/', title: 'Home' }] }],
2931
+ });
2932
+ ```
2933
+
2934
+ ---
2935
+
2579
2936
  ## Complete integration example
2580
2937
 
2581
2938
  Here's how joost.blog wires everything together. Use this as a reference
@@ -3095,7 +3452,8 @@ seo-graph/
3095
3452
  │ ├── alternates.ts # buildAlternateLinks
3096
3453
  │ ├── content.ts # seoSchema, imageSchema
3097
3454
  │ └── components/
3098
- └── seo-props.ts # buildAstroSeoProps
3455
+ ├── seo-props.ts # SeoProps interface
3456
+ │ └── seo-context.ts # buildSeoContext
3099
3457
  ├── AGENTS.md # This file
3100
3458
  ├── README.md # Project overview
3101
3459
  └── pnpm-workspace.yaml
package/README.md CHANGED
@@ -35,19 +35,26 @@ npm install @jdevalk/seo-graph-core
35
35
  | `assembleGraph(pieces)` | Wraps pieces in a `{ @context, @graph }` envelope with first-wins deduplication by `@id`. |
36
36
  | `deduplicateByGraphId(entities)` | The dedup engine on its own, in case you need custom assembly. |
37
37
 
38
+ Pass `{ warnOnDanglingReferences: true }` to `assembleGraph` to emit a
39
+ console warning when any `{ '@id': '...' }` reference doesn't resolve to
40
+ an entity in the graph — a cheap sanity check to catch typos and
41
+ missing pieces during development.
42
+
38
43
  ### IndexNow
39
44
 
40
- | API | Purpose |
41
- | ---------------------------- | ----------------------------------------------------------------------------- |
42
- | `submitToIndexNow` | POST URLs to the IndexNow aggregator. Filters by host, dedupes, chunks at 10k. |
43
- | `generateIndexNowKey` | Generate a random hex key (Web Crypto). |
44
- | `validateIndexNowKey` | Verify a key is 8–128 hex chars. |
45
- | `getIndexNowKeyFileContent` | Body to serve at `/<key>.txt` for host verification. |
45
+ | API | Purpose |
46
+ | --------------------------- | ------------------------------------------------------------------------------ |
47
+ | `submitToIndexNow` | POST URLs to the IndexNow aggregator. Filters by host, dedupes, chunks at 10k. |
48
+ | `generateIndexNowKey` | Generate a random hex key (Web Crypto). |
49
+ | `validateIndexNowKey` | Verify a key is 8–128 chars from `[A-Za-z0-9-]` (IndexNow spec allow-list). |
50
+ | `getIndexNowKeyFileContent` | Body to serve at `/<key>.txt` for host verification. |
46
51
 
47
52
  ### Piece builders
48
53
 
49
- All builders take an input object and the `IdFactory`, and return a plain
50
- object with `@type` and `@id`. Builders for CreativeWork subtypes (`WebSite`,
54
+ The dedicated builders take an input object and the `IdFactory`, and return a
55
+ plain object with `@type` and `@id`. `buildPiece` is the exception: it takes
56
+ only the input object — pass `@id` and `@type` inline in that object. Builders
57
+ for CreativeWork subtypes (`WebSite`,
51
58
  `WebPage`, `Article`) share a common set of optional fields via
52
59
  `CreativeWorkFields`: `description`, `inLanguage`, `datePublished`,
53
60
  `dateModified`, `about`, `copyrightHolder`, `copyrightYear`,
@@ -1 +1 @@
1
- {"version":3,"file":"assemble.js","sourceRoot":"","sources":["../src/assemble.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAcnD;;;GAGG;AACH,SAAS,iBAAiB,CAAC,KAAc,EAAE,IAAiB;IACxD,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO;IAE/E,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACvB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACvB,iBAAiB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAClC,CAAC;QACD,OAAO;IACX,CAAC;IAED,MAAM,GAAG,GAAG,KAAgC,CAAC;IAE7C,iEAAiE;IACjE,IAAI,OAAO,GAAG,CAAC,KAAK,CAAC,KAAK,QAAQ,IAAI,GAAG,CAAC,OAAO,CAAC,KAAK,SAAS,EAAE,CAAC;QAC/D,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;QACrB,OAAO;IACX,CAAC;IAED,kDAAkD;IAClD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;QACnC,iBAAiB,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACjC,CAAC;AACL,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,aAAa,CACzB,MAAoB,EACpB,OAA8B;IAE9B,MAAM,KAAK,GAAG,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAE3C,IAAI,OAAO,EAAE,wBAAwB,EAAE,CAAC;QACpC,MAAM,SAAS,GAAG,IAAI,GAAG,EAAU,CAAC;QACpC,KAAK,MAAM,MAAM,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,OAAO,MAAM,CAAC,KAAK,CAAC,KAAK,QAAQ,EAAE,CAAC;gBACpC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;YACjC,CAAC;QACL,CAAC;QAED,oEAAoE;QACpE,MAAM,IAAI,GAAG,IAAI,GAAG,EAAkB,CAAC;QACvC,KAAK,MAAM,MAAM,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;YAC3C,MAAM,SAAS,GAAG,IAAI,GAAG,EAAU,CAAC;YACpC,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC9C,IAAI,GAAG,KAAK,KAAK;oBAAE,SAAS;gBAC5B,iBAAiB,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;YACtC,CAAC;YACD,KAAK,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;gBAC1B,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;oBAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;YAClD,CAAC;QACL,CAAC;QAED,KAAK,MAAM,CAAC,GAAG,EAAE,UAAU,CAAC,IAAI,IAAI,EAAE,CAAC;YACnC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;gBACtB,OAAO,CAAC,IAAI,CACR,qCAAqC,UAAU,eAAe,GAAG,6CAA6C,CACjH,CAAC;YACN,CAAC;QACL,CAAC;IACL,CAAC;IAED,OAAO;QACH,UAAU,EAAE,oBAAoB;QAChC,QAAQ,EAAE,KAAK;KAClB,CAAC;AACN,CAAC"}
1
+ {"version":3,"file":"assemble.js","sourceRoot":"","sources":["../src/assemble.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAcnD;;;GAGG;AACH,SAAS,iBAAiB,CAAC,KAAc,EAAE,IAAiB;IACxD,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO;IAE/E,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACvB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACvB,iBAAiB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAClC,CAAC;QACD,OAAO;IACX,CAAC;IAED,MAAM,GAAG,GAAG,KAAgC,CAAC;IAE7C,iEAAiE;IACjE,IAAI,OAAO,GAAG,CAAC,KAAK,CAAC,KAAK,QAAQ,IAAI,GAAG,CAAC,OAAO,CAAC,KAAK,SAAS,EAAE,CAAC;QAC/D,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;QACrB,OAAO;IACX,CAAC;IAED,kDAAkD;IAClD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;QACnC,iBAAiB,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACjC,CAAC;AACL,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,aAAa,CACzB,MAAoB,EACpB,OAA8B;IAE9B,MAAM,KAAK,GAAG,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAE3C,IAAI,OAAO,EAAE,wBAAwB,EAAE,CAAC;QACpC,MAAM,SAAS,GAAG,IAAI,GAAG,EAAU,CAAC;QACpC,KAAK,MAAM,MAAM,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,OAAO,MAAM,CAAC,KAAK,CAAC,KAAK,QAAQ,EAAE,CAAC;gBACpC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;YACjC,CAAC;QACL,CAAC;QAED,oEAAoE;QACpE,MAAM,IAAI,GAAG,IAAI,GAAG,EAAkB,CAAC;QACvC,KAAK,MAAM,MAAM,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;YAC3C,MAAM,SAAS,GAAG,IAAI,GAAG,EAAU,CAAC;YACpC,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC9C,IAAI,GAAG,KAAK,KAAK;oBAAE,SAAS;gBAC5B,iBAAiB,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;YACtC,CAAC;YACD,KAAK,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;gBAC1B,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;oBAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;YAClD,CAAC;QACL,CAAC;QAED,KAAK,MAAM,CAAC,GAAG,EAAE,UAAU,CAAC,IAAI,IAAI,EAAE,CAAC;YACnC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;gBACtB,OAAO,CAAC,IAAI,CACR,qCAAqC,UAAU,eAAe,GAAG,6CAA6C,CACjH,CAAC;YACN,CAAC;QACL,CAAC;IACL,CAAC;IAED,OAAO;QACH,UAAU,EAAE,oBAAoB;QAChC,QAAQ,EAAE,KAAK;KAClB,CAAC;AACN,CAAC","sourcesContent":["import type { GraphEntity } from './types.js';\nimport { deduplicateByGraphId } from './dedupe.js';\n\nexport interface AssembleGraphOptions {\n /**\n * When `true`, logs a warning for every `{ '@id': '...' }` reference\n * in the graph that doesn't resolve to an entity with a matching\n * `@id`. Helps catch broken links in the graph (e.g. a WebSite\n * referencing a Person that was never included).\n *\n * Defaults to `false`.\n */\n warnOnDanglingReferences?: boolean;\n}\n\n/**\n * Walk a value recursively and collect every `{ '@id': string }` reference\n * that is NOT a top-level entity (i.e. doesn't have `@type`).\n */\nfunction collectReferences(value: unknown, refs: Set<string>): void {\n if (value === null || value === undefined || typeof value !== 'object') return;\n\n if (Array.isArray(value)) {\n for (const item of value) {\n collectReferences(item, refs);\n }\n return;\n }\n\n const obj = value as Record<string, unknown>;\n\n // An object with @id but no @type is a reference, not an entity.\n if (typeof obj['@id'] === 'string' && obj['@type'] === undefined) {\n refs.add(obj['@id']);\n return;\n }\n\n // Recurse into values of entities/nested objects.\n for (const val of Object.values(obj)) {\n collectReferences(val, refs);\n }\n}\n\n/**\n * Wrap a list of pieces in a `@context + @graph` envelope. Pieces are\n * deduplicated by `@id` before assembly; first occurrence wins.\n *\n * When `warnOnDanglingReferences` is enabled, logs warnings for any\n * `{ '@id': '...' }` reference that doesn't resolve to an entity in\n * the graph.\n */\nexport function assembleGraph<T extends GraphEntity>(\n pieces: readonly T[],\n options?: AssembleGraphOptions,\n): { '@context': 'https://schema.org'; '@graph': T[] } {\n const graph = deduplicateByGraphId(pieces);\n\n if (options?.warnOnDanglingReferences) {\n const entityIds = new Set<string>();\n for (const entity of graph) {\n if (typeof entity['@id'] === 'string') {\n entityIds.add(entity['@id']);\n }\n }\n\n // Map from referenced @id → @type of the entity that references it.\n const refs = new Map<string, string>();\n for (const entity of graph) {\n const sourceType = String(entity['@type']);\n const collected = new Set<string>();\n for (const [key, val] of Object.entries(entity)) {\n if (key === '@id') continue;\n collectReferences(val, collected);\n }\n for (const ref of collected) {\n if (!refs.has(ref)) refs.set(ref, sourceType);\n }\n }\n\n for (const [ref, sourceType] of refs) {\n if (!entityIds.has(ref)) {\n console.warn(\n `[seo-graph] Dangling reference in ${sourceType}: { \"@id\": \"${ref}\" } does not match any entity in the graph.`,\n );\n }\n }\n }\n\n return {\n '@context': 'https://schema.org',\n '@graph': graph,\n };\n}\n"]}
@@ -1 +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"}
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","sourcesContent":["import type { GraphEntity } from './types.js';\n\n/**\n * Deduplicate entities by their `@id`. First occurrence wins. Entities\n * without an `@id` are always kept.\n */\nexport function deduplicateByGraphId<T extends GraphEntity>(entities: readonly T[]): T[] {\n const seen = new Set<string>();\n const result: T[] = [];\n for (const entity of entities) {\n const id = entity['@id'];\n if (id !== undefined) {\n if (seen.has(id)) continue;\n seen.add(id);\n }\n result.push(entity);\n }\n return result;\n}\n"]}
package/dist/ids.js.map CHANGED
@@ -1 +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"}
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","sourcesContent":["/**\n * Factory for stable @id URIs used to cross-reference entities in the graph.\n *\n * Site-wide singletons live at `${siteUrl}/#/schema.org/<Type>` (WebSite,\n * Person, etc). Per-page entities live at `${pageUrl}#<suffix>` (Article,\n * Breadcrumb, PrimaryImage). The `person` id defaults to the site root but\n * can be relocated to e.g. `/about-me/` via `personUrl`.\n */\nexport interface IdFactory {\n /** Site-wide Person id. Defaults to `${siteUrl}/#/schema.org/Person`. */\n readonly person: string;\n /** Site-wide Person image id (friendly-named fragment). */\n readonly personImage: string;\n /** Site-wide WebSite id. */\n readonly website: string;\n /** Site-wide SiteNavigationElement id. */\n readonly navigation: string;\n /** Per-org id factory — pass a stable slug. */\n organization(slug: string): string;\n /** Per-country id factory — pass an ISO 3166 alpha-2 code. */\n country(code: string): string;\n /** WebPage id equals the canonical URL itself. */\n webPage(url: string): string;\n /** Breadcrumb id for a given page URL. */\n breadcrumb(url: string): string;\n /** Article id for a given page URL. */\n article(url: string): string;\n /** VideoObject id for a given page URL. */\n videoObject(url: string): string;\n /** Primary ImageObject id for a given page URL. */\n primaryImage(url: string): string;\n}\n\nexport interface MakeIdsOptions {\n /** Canonical site URL, with or without trailing slash. E.g. `https://joost.blog`. */\n siteUrl: string;\n /**\n * URL where the site-wide Person entity lives, with trailing slash.\n * Defaults to `${siteUrl}/`. joost.blog uses `${siteUrl}/about-me/`.\n */\n personUrl?: string;\n}\n\n/**\n * Normalize a base URL: strip any trailing slash so we can append `/#...`\n * consistently.\n */\nfunction stripTrailingSlash(url: string): string {\n return url.replace(/\\/+$/, '');\n}\n\n/**\n * Normalize a person URL: ensure a single trailing slash so the resulting\n * id reads `${personUrl}#/schema.org/Person` with the `/` already present.\n */\nfunction ensureTrailingSlash(url: string): string {\n return url.endsWith('/') ? url : `${url}/`;\n}\n\n/**\n * Build an IdFactory for a given site. The returned factory is stateless —\n * call it as many times as you like, on any piece builder.\n */\nexport function makeIds(options: MakeIdsOptions): IdFactory {\n const site = stripTrailingSlash(options.siteUrl);\n const person = ensureTrailingSlash(options.personUrl ?? `${site}/`);\n\n return {\n person: `${person}#/schema.org/Person`,\n personImage: `${site}/#personlogo`,\n website: `${site}/#/schema.org/WebSite`,\n navigation: `${site}/#site-navigation`,\n organization: (slug: string) => `${site}/#/schema.org/Organization/${slug}`,\n country: (code: string) => `${site}/#/schema.org/Country/${code.toLowerCase()}`,\n webPage: (url: string) => url,\n breadcrumb: (url: string) => `${url}#breadcrumb`,\n article: (url: string) => `${url}#article`,\n videoObject: (url: string) => `${url}#video`,\n primaryImage: (url: string) => `${url}#primaryimage`,\n };\n}\n"]}
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAG3E,OAAO,EAAE,uBAAuB,EAAE,yBAAyB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAEpG,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACnC,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAG9C,iBAAiB;AACjB,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGnD,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,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEhD,oBAAoB;AACpB,OAAO,EACH,gBAAgB,EAChB,mBAAmB,EACnB,mBAAmB,EACnB,yBAAyB,EACzB,yBAAyB,EACzB,6BAA6B,GAChC,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAG3E,OAAO,EAAE,uBAAuB,EAAE,yBAAyB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAEpG,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACnC,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAG9C,iBAAiB;AACjB,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGnD,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,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEhD,oBAAoB;AACpB,OAAO,EACH,gBAAgB,EAChB,mBAAmB,EACnB,mBAAmB,EACnB,yBAAyB,EACzB,yBAAyB,EACzB,6BAA6B,GAChC,MAAM,eAAe,CAAC","sourcesContent":["// @jdevalk/seo-graph-core — agent-ready schema.org JSON-LD graph builders.\n\nexport type { GraphEntity, Reference, SchemaGraph, CreativeWorkFields } from './types.js';\nexport { applyCreativeWorkFields, spreadRemainingProperties, CREATIVE_WORK_KEYS } from './types.js';\nexport type { IdFactory, MakeIdsOptions } from './ids.js';\nexport { makeIds } from './ids.js';\nexport { deduplicateByGraphId } from './dedupe.js';\nexport { assembleGraph } from './assemble.js';\nexport type { AssembleGraphOptions } from './assemble.js';\n\n// Piece builders\nexport { buildWebSite } from './pieces/website.js';\nexport type { WebSiteInput } from './pieces/website.js';\n\nexport { buildSiteNavigationElement } from './pieces/navigation.js';\nexport type { NavigationItem, SiteNavigationInput } from './pieces/navigation.js';\n\nexport { buildWebPage } from './pieces/webpage.js';\nexport type { WebPageInput, WebPageType } from './pieces/webpage.js';\n\nexport { buildArticle } from './pieces/article.js';\nexport type { ArticleInput, ArticleType } from './pieces/article.js';\n\nexport { buildBreadcrumbList } from './pieces/breadcrumb.js';\nexport type { BreadcrumbItem, BreadcrumbListInput } from './pieces/breadcrumb.js';\n\nexport { buildImageObject } from './pieces/image.js';\nexport type { ImageObjectInput } from './pieces/image.js';\n\nexport { buildVideoObject } from './pieces/video.js';\nexport type { VideoObjectInput } from './pieces/video.js';\n\nexport { buildPiece } from './pieces/custom.js';\n\n// IndexNow protocol\nexport {\n submitToIndexNow,\n validateIndexNowKey,\n generateIndexNowKey,\n getIndexNowKeyFileContent,\n DEFAULT_INDEXNOW_ENDPOINT,\n INDEXNOW_MAX_URLS_PER_REQUEST,\n} from './indexnow.js';\nexport type { SubmitToIndexNowOptions, IndexNowSubmitResult } from './indexnow.js';\n"]}
@@ -5,7 +5,7 @@ export declare const INDEXNOW_MAX_URLS_PER_REQUEST = 10000;
5
5
  export interface SubmitToIndexNowOptions {
6
6
  /** Bare host, e.g. `example.com`. No scheme, no trailing slash. */
7
7
  host: string;
8
- /** 8–128 hex-character key. Must match the key file served on the host. */
8
+ /** 8–128 character key from `[A-Za-z0-9-]`. Must match the key file served on the host. */
9
9
  key: string;
10
10
  /**
11
11
  * Optional absolute URL where the key file is hosted. Defaults to
@@ -36,7 +36,7 @@ export interface IndexNowSubmitResult {
36
36
  * per chunk; a single-chunk submission returns a one-element array.
37
37
  */
38
38
  export declare function submitToIndexNow(options: SubmitToIndexNowOptions): Promise<IndexNowSubmitResult[]>;
39
- /** Returns true when `key` is 8–128 hexadecimal characters. */
39
+ /** Returns true when `key` is 8–128 characters drawn from `[A-Za-z0-9-]`. */
40
40
  export declare function validateIndexNowKey(key: string): boolean;
41
41
  /**
42
42
  * Generate a cryptographically random IndexNow key of `length` hex
@@ -1 +1 @@
1
- {"version":3,"file":"indexnow.d.ts","sourceRoot":"","sources":["../src/indexnow.ts"],"names":[],"mappings":"AAIA,2EAA2E;AAC3E,eAAO,MAAM,yBAAyB,sCAAsC,CAAC;AAE7E,2DAA2D;AAC3D,eAAO,MAAM,6BAA6B,QAAS,CAAC;AAOpD,MAAM,WAAW,uBAAuB;IACpC,mEAAmE;IACnE,IAAI,EAAE,MAAM,CAAC;IACb,2EAA2E;IAC3E,GAAG,EAAE,MAAM,CAAC;IACZ;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oEAAoE;IACpE,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gEAAgE;IAChE,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACxB;AAED,MAAM,WAAW,oBAAoB;IACjC,yEAAyE;IACzE,MAAM,EAAE,MAAM,CAAC;IACf,wDAAwD;IACxD,EAAE,EAAE,OAAO,CAAC;IACZ,sEAAsE;IACtE,OAAO,EAAE,MAAM,CAAC;IAChB,+DAA+D;IAC/D,SAAS,EAAE,MAAM,CAAC;CACrB;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,CAClC,OAAO,EAAE,uBAAuB,GACjC,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAgDjC;AA0BD,+DAA+D;AAC/D,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAIxD;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,SAAK,GAAG,MAAM,CAWvD;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAO7D"}
1
+ {"version":3,"file":"indexnow.d.ts","sourceRoot":"","sources":["../src/indexnow.ts"],"names":[],"mappings":"AAIA,2EAA2E;AAC3E,eAAO,MAAM,yBAAyB,sCAAsC,CAAC;AAE7E,2DAA2D;AAC3D,eAAO,MAAM,6BAA6B,QAAS,CAAC;AAapD,MAAM,WAAW,uBAAuB;IACpC,mEAAmE;IACnE,IAAI,EAAE,MAAM,CAAC;IACb,2FAA2F;IAC3F,GAAG,EAAE,MAAM,CAAC;IACZ;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oEAAoE;IACpE,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gEAAgE;IAChE,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACxB;AAED,MAAM,WAAW,oBAAoB;IACjC,yEAAyE;IACzE,MAAM,EAAE,MAAM,CAAC;IACf,wDAAwD;IACxD,EAAE,EAAE,OAAO,CAAC;IACZ,sEAAsE;IACtE,OAAO,EAAE,MAAM,CAAC;IAChB,+DAA+D;IAC/D,SAAS,EAAE,MAAM,CAAC;CACrB;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,CAClC,OAAO,EAAE,uBAAuB,GACjC,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAgDjC;AA0BD,6EAA6E;AAC7E,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAIxD;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,SAAK,GAAG,MAAM,CAWvD;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAO7D"}
package/dist/indexnow.js CHANGED
@@ -8,7 +8,13 @@ export const INDEXNOW_MAX_URLS_PER_REQUEST = 10_000;
8
8
  /** Key length constraints per the spec. */
9
9
  const MIN_KEY_LENGTH = 8;
10
10
  const MAX_KEY_LENGTH = 128;
11
- const HEX_KEY_RE = /^[a-f0-9]+$/i;
11
+ // Per the IndexNow spec the key may contain [A-Za-z0-9-]. The wording at
12
+ // indexnow.org calls these "hexadecimal characters" but the explicit
13
+ // allow-list is the broader set, and Bing / Yandex both issue and accept
14
+ // non-hex keys (Yandex's own docs use a mixed-case example).
15
+ // Refs: https://www.indexnow.org/documentation
16
+ // https://yandex.com/support/webmaster/en/indexnow/key
17
+ const KEY_RE = /^[A-Za-z0-9-]+$/;
12
18
  /**
13
19
  * Submit URLs to IndexNow. Filters out URLs not on `host`, deduplicates,
14
20
  * and chunks at {@link INDEXNOW_MAX_URLS_PER_REQUEST}. Returns one result
@@ -17,7 +23,7 @@ const HEX_KEY_RE = /^[a-f0-9]+$/i;
17
23
  export async function submitToIndexNow(options) {
18
24
  const { host, key, urls } = options;
19
25
  if (!validateIndexNowKey(key)) {
20
- throw new Error(`IndexNow key must be ${MIN_KEY_LENGTH}–${MAX_KEY_LENGTH} hex characters.`);
26
+ throw new Error(`IndexNow key must be ${MIN_KEY_LENGTH}–${MAX_KEY_LENGTH} characters from [A-Za-z0-9-].`);
21
27
  }
22
28
  if (!host || host.includes('/') || host.includes(':')) {
23
29
  throw new Error(`IndexNow host must be a bare host (got: ${host}).`);
@@ -86,13 +92,13 @@ function filterUrlsForHost(urls, host) {
86
92
  }
87
93
  return out;
88
94
  }
89
- /** Returns true when `key` is 8–128 hexadecimal characters. */
95
+ /** Returns true when `key` is 8–128 characters drawn from `[A-Za-z0-9-]`. */
90
96
  export function validateIndexNowKey(key) {
91
97
  if (typeof key !== 'string')
92
98
  return false;
93
99
  if (key.length < MIN_KEY_LENGTH || key.length > MAX_KEY_LENGTH)
94
100
  return false;
95
- return HEX_KEY_RE.test(key);
101
+ return KEY_RE.test(key);
96
102
  }
97
103
  /**
98
104
  * Generate a cryptographically random IndexNow key of `length` hex
@@ -117,7 +123,7 @@ export function generateIndexNowKey(length = 32) {
117
123
  */
118
124
  export function getIndexNowKeyFileContent(key) {
119
125
  if (!validateIndexNowKey(key)) {
120
- throw new Error(`IndexNow key must be ${MIN_KEY_LENGTH}–${MAX_KEY_LENGTH} hex characters.`);
126
+ throw new Error(`IndexNow key must be ${MIN_KEY_LENGTH}–${MAX_KEY_LENGTH} characters from [A-Za-z0-9-].`);
121
127
  }
122
128
  return key;
123
129
  }
@@ -1 +1 @@
1
- {"version":3,"file":"indexnow.js","sourceRoot":"","sources":["../src/indexnow.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"indexnow.js","sourceRoot":"","sources":["../src/indexnow.ts"],"names":[],"mappings":"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","sourcesContent":["// IndexNow protocol support. Submits URLs to participating search engines\n// (Bing, Yandex, Seznam, Naver, Yep) through the neutral aggregator\n// endpoint at api.indexnow.org. Spec: https://www.indexnow.org/documentation\n\n/** Default aggregator endpoint. Fans out to every participating engine. */\nexport const DEFAULT_INDEXNOW_ENDPOINT = 'https://api.indexnow.org/IndexNow';\n\n/** IndexNow accepts up to 10,000 URLs per bulk request. */\nexport const INDEXNOW_MAX_URLS_PER_REQUEST = 10_000;\n\n/** Key length constraints per the spec. */\nconst MIN_KEY_LENGTH = 8;\nconst MAX_KEY_LENGTH = 128;\n// Per the IndexNow spec the key may contain [A-Za-z0-9-]. The wording at\n// indexnow.org calls these \"hexadecimal characters\" but the explicit\n// allow-list is the broader set, and Bing / Yandex both issue and accept\n// non-hex keys (Yandex's own docs use a mixed-case example).\n// Refs: https://www.indexnow.org/documentation\n// https://yandex.com/support/webmaster/en/indexnow/key\nconst KEY_RE = /^[A-Za-z0-9-]+$/;\n\nexport interface SubmitToIndexNowOptions {\n /** Bare host, e.g. `example.com`. No scheme, no trailing slash. */\n host: string;\n /** 8–128 character key from `[A-Za-z0-9-]`. Must match the key file served on the host. */\n key: string;\n /**\n * Optional absolute URL where the key file is hosted. Defaults to\n * `https://<host>/<key>.txt`. Supply this when the key file lives at\n * a non-default path.\n */\n keyLocation?: string;\n /** URLs to submit. Must all be on `host`. Empty list is a no-op. */\n urls: readonly string[];\n /** Override the endpoint. Defaults to {@link DEFAULT_INDEXNOW_ENDPOINT}. */\n endpoint?: string;\n /** Injectable fetch for testing. Defaults to global `fetch`. */\n fetch?: typeof fetch;\n}\n\nexport interface IndexNowSubmitResult {\n /** HTTP status from the IndexNow server. `0` when the request failed. */\n status: number;\n /** Whether the submission was accepted (200 or 202). */\n ok: boolean;\n /** Response body text if any, or error message on network failure. */\n message: string;\n /** Number of URLs actually submitted after filtering/dedup. */\n submitted: number;\n}\n\n/**\n * Submit URLs to IndexNow. Filters out URLs not on `host`, deduplicates,\n * and chunks at {@link INDEXNOW_MAX_URLS_PER_REQUEST}. Returns one result\n * per chunk; a single-chunk submission returns a one-element array.\n */\nexport async function submitToIndexNow(\n options: SubmitToIndexNowOptions,\n): Promise<IndexNowSubmitResult[]> {\n const { host, key, urls } = options;\n if (!validateIndexNowKey(key)) {\n throw new Error(\n `IndexNow key must be ${MIN_KEY_LENGTH}–${MAX_KEY_LENGTH} characters from [A-Za-z0-9-].`,\n );\n }\n if (!host || host.includes('/') || host.includes(':')) {\n throw new Error(`IndexNow host must be a bare host (got: ${host}).`);\n }\n\n const filtered = filterUrlsForHost(urls, host);\n if (filtered.length === 0) return [];\n\n const endpoint = options.endpoint ?? DEFAULT_INDEXNOW_ENDPOINT;\n const keyLocation = options.keyLocation ?? `https://${host}/${key}.txt`;\n const doFetch = options.fetch ?? fetch;\n\n const results: IndexNowSubmitResult[] = [];\n for (let i = 0; i < filtered.length; i += INDEXNOW_MAX_URLS_PER_REQUEST) {\n const chunk = filtered.slice(i, i + INDEXNOW_MAX_URLS_PER_REQUEST);\n const body = JSON.stringify({ host, key, keyLocation, urlList: chunk });\n try {\n const res = await doFetch(endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json; charset=utf-8',\n Accept: 'application/json',\n },\n body,\n });\n const text = await res.text().catch(() => '');\n results.push({\n status: res.status,\n ok: res.status === 200 || res.status === 202,\n message: text,\n submitted: chunk.length,\n });\n } catch (err) {\n results.push({\n status: 0,\n ok: false,\n message: err instanceof Error ? err.message : String(err),\n submitted: chunk.length,\n });\n }\n }\n return results;\n}\n\n/**\n * Keep only URLs whose hostname matches `host` (case-insensitive) and\n * deduplicate while preserving first-seen order.\n */\nfunction filterUrlsForHost(urls: readonly string[], host: string): string[] {\n const lowerHost = host.toLowerCase();\n const seen = new Set<string>();\n const out: string[] = [];\n for (const raw of urls) {\n let parsed: URL;\n try {\n parsed = new URL(raw);\n } catch {\n continue;\n }\n if (parsed.hostname.toLowerCase() !== lowerHost) continue;\n const normalized = parsed.toString();\n if (seen.has(normalized)) continue;\n seen.add(normalized);\n out.push(normalized);\n }\n return out;\n}\n\n/** Returns true when `key` is 8–128 characters drawn from `[A-Za-z0-9-]`. */\nexport function validateIndexNowKey(key: string): boolean {\n if (typeof key !== 'string') return false;\n if (key.length < MIN_KEY_LENGTH || key.length > MAX_KEY_LENGTH) return false;\n return KEY_RE.test(key);\n}\n\n/**\n * Generate a cryptographically random IndexNow key of `length` hex\n * characters. Default 32. Uses Web Crypto, available in Node 20+,\n * browsers, and edge/worker runtimes.\n */\nexport function generateIndexNowKey(length = 32): string {\n if (length < MIN_KEY_LENGTH || length > MAX_KEY_LENGTH || length % 2 !== 0) {\n throw new Error(\n `IndexNow key length must be an even number between ${MIN_KEY_LENGTH} and ${MAX_KEY_LENGTH}.`,\n );\n }\n const bytes = new Uint8Array(length / 2);\n crypto.getRandomValues(bytes);\n let hex = '';\n for (const b of bytes) hex += b.toString(16).padStart(2, '0');\n return hex;\n}\n\n/**\n * Plain-text body to serve at `https://<host>/<key>.txt`. IndexNow\n * verifies ownership by fetching this file and comparing to the\n * submitted key.\n */\nexport function getIndexNowKeyFileContent(key: string): string {\n if (!validateIndexNowKey(key)) {\n throw new Error(\n `IndexNow key must be ${MIN_KEY_LENGTH}–${MAX_KEY_LENGTH} characters from [A-Za-z0-9-].`,\n );\n }\n return key;\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  import type { ArticleLeaf } from 'schema-dts';
2
2
  import type { IdFactory } from '../ids.js';
3
- import type { Reference, CreativeWorkFields } from '../types.js';
3
+ import type { Reference, CreativeWorkFields, GraphEntity } from '../types.js';
4
4
  /**
5
5
  * Concrete Article subtype. `Article` is the default; use `BlogPosting`
6
6
  * for blog posts, `NewsArticle` for journalism, `TechArticle` for
@@ -11,8 +11,13 @@ export type ArticleType = 'Article' | 'BlogPosting' | 'NewsArticle' | 'TechArtic
11
11
  interface ArticleCoreFields extends CreativeWorkFields {
12
12
  /** Canonical URL of the article's page. The @id is `${url}#article`. */
13
13
  url: string;
14
- /** Reference to the enclosing WebPage (usually ids.webPage(url)). */
15
- isPartOf: Reference;
14
+ /**
15
+ * Reference to the enclosing entity, usually the WebPage
16
+ * (`ids.webPage(url)`). Pass an array to link the Article to more than
17
+ * one parent — e.g. both its WebPage and a Blog
18
+ * (`[{ '@id': ids.webPage(url) }, { '@id': blogId }]`).
19
+ */
20
+ isPartOf: Reference | Reference[];
16
21
  /** Author reference. May include a `name` alongside the `@id`. */
17
22
  author: Reference;
18
23
  /** Publisher reference. Usually the same as the author for personal blogs. */
@@ -33,6 +38,6 @@ export type ArticleInput = ArticleCoreFields & Omit<Partial<ArticleLeaf>, keyof
33
38
  /**
34
39
  * Build a schema.org Article piece.
35
40
  */
36
- export declare function buildArticle(input: ArticleInput, ids: IdFactory, type?: ArticleType): Record<string, unknown>;
41
+ export declare function buildArticle(input: ArticleInput, ids: IdFactory, type?: ArticleType): GraphEntity;
37
42
  export {};
38
43
  //# sourceMappingURL=article.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"article.d.ts","sourceRoot":"","sources":["../../src/pieces/article.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAOjE;;;;;GAKG;AACH,MAAM,MAAM,WAAW,GACjB,SAAS,GACT,aAAa,GACb,aAAa,GACb,aAAa,GACb,kBAAkB,GAClB,QAAQ,CAAC;AAEf,UAAU,iBAAkB,SAAQ,kBAAkB;IAClD,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,sEAAsE;IACtE,WAAW,EAAE,MAAM,CAAC;IACpB,6FAA6F;IAC7F,aAAa,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,WAAW,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,MAAM,YAAY,GAAG,iBAAiB,GACxC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,MAAM,iBAAiB,GAAG,OAAO,CAAC,CAAC;AAelE;;GAEG;AACH,wBAAgB,YAAY,CACxB,KAAK,EAAE,YAAY,EACnB,GAAG,EAAE,SAAS,EACd,IAAI,GAAE,WAAuB,GAC9B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAmBzB"}
1
+ {"version":3,"file":"article.d.ts","sourceRoot":"","sources":["../../src/pieces/article.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAO9E;;;;;GAKG;AACH,MAAM,MAAM,WAAW,GACjB,SAAS,GACT,aAAa,GACb,aAAa,GACb,aAAa,GACb,kBAAkB,GAClB,QAAQ,CAAC;AAEf,UAAU,iBAAkB,SAAQ,kBAAkB;IAClD,wEAAwE;IACxE,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;OAKG;IACH,QAAQ,EAAE,SAAS,GAAG,SAAS,EAAE,CAAC;IAClC,kEAAkE;IAClE,MAAM,EAAE,SAAS,CAAC;IAClB,8EAA8E;IAC9E,SAAS,EAAE,SAAS,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,sEAAsE;IACtE,WAAW,EAAE,MAAM,CAAC;IACpB,6FAA6F;IAC7F,aAAa,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,WAAW,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,MAAM,YAAY,GAAG,iBAAiB,GACxC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,MAAM,iBAAiB,GAAG,OAAO,CAAC,CAAC;AAelE;;GAEG;AACH,wBAAgB,YAAY,CACxB,KAAK,EAAE,YAAY,EACnB,GAAG,EAAE,SAAS,EACd,IAAI,GAAE,WAAuB,GAC9B,WAAW,CAmBb"}
@@ -1 +1 @@
1
- {"version":3,"file":"article.js","sourceRoot":"","sources":["../../src/pieces/article.ts"],"names":[],"mappings":"AAIA,OAAO,EACH,uBAAuB,EACvB,yBAAyB,EACzB,kBAAkB,GACrB,MAAM,aAAa,CAAC;AAyCrB,MAAM,YAAY,GAAG,IAAI,GAAG,CAAS;IACjC,GAAG,kBAAkB;IACrB,KAAK;IACL,UAAU;IACV,QAAQ;IACR,WAAW;IACX,UAAU;IACV,OAAO;IACP,gBAAgB;IAChB,WAAW;IACX,aAAa;CAChB,CAAC,CAAC;AAEH;;GAEG;AACH,MAAM,UAAU,YAAY,CACxB,KAAmB,EACnB,GAAc,EACd,OAAoB,SAAS;IAE7B,MAAM,KAAK,GAA4B;QACnC,OAAO,EAAE,IAAI;QACb,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;KAC7B,CAAC;IAEF,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS;QAAE,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;IACzD,uBAAuB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IACtC,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;IAC3E,yBAAyB,CAAC,KAAK,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC;IAEtD,OAAO,KAAK,CAAC;AACjB,CAAC"}
1
+ {"version":3,"file":"article.js","sourceRoot":"","sources":["../../src/pieces/article.ts"],"names":[],"mappings":"AAIA,OAAO,EACH,uBAAuB,EACvB,yBAAyB,EACzB,kBAAkB,GACrB,MAAM,aAAa,CAAC;AA8CrB,MAAM,YAAY,GAAG,IAAI,GAAG,CAAS;IACjC,GAAG,kBAAkB;IACrB,KAAK;IACL,UAAU;IACV,QAAQ;IACR,WAAW;IACX,UAAU;IACV,OAAO;IACP,gBAAgB;IAChB,WAAW;IACX,aAAa;CAChB,CAAC,CAAC;AAEH;;GAEG;AACH,MAAM,UAAU,YAAY,CACxB,KAAmB,EACnB,GAAc,EACd,OAAoB,SAAS;IAE7B,MAAM,KAAK,GAAgB;QACvB,OAAO,EAAE,IAAI;QACb,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;KAC7B,CAAC;IAEF,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS;QAAE,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;IACzD,uBAAuB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IACtC,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;IAC3E,yBAAyB,CAAC,KAAK,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC;IAEtD,OAAO,KAAK,CAAC;AACjB,CAAC","sourcesContent":["import type { ArticleLeaf } from 'schema-dts';\n\nimport type { IdFactory } from '../ids.js';\nimport type { Reference, CreativeWorkFields, GraphEntity } from '../types.js';\nimport {\n applyCreativeWorkFields,\n spreadRemainingProperties,\n CREATIVE_WORK_KEYS,\n} from '../types.js';\n\n/**\n * Concrete Article subtype. `Article` is the default; use `BlogPosting`\n * for blog posts, `NewsArticle` for journalism, `TechArticle` for\n * technical docs, `ScholarlyArticle` for academic papers, or `Report`\n * for data/research reports.\n */\nexport type ArticleType =\n | 'Article'\n | 'BlogPosting'\n | 'NewsArticle'\n | 'TechArticle'\n | 'ScholarlyArticle'\n | 'Report';\n\ninterface ArticleCoreFields extends CreativeWorkFields {\n /** Canonical URL of the article's page. The @id is `${url}#article`. */\n url: string;\n /**\n * Reference to the enclosing entity, usually the WebPage\n * (`ids.webPage(url)`). Pass an array to link the Article to more than\n * one parent — e.g. both its WebPage and a Blog\n * (`[{ '@id': ids.webPage(url) }, { '@id': blogId }]`).\n */\n isPartOf: Reference | Reference[];\n /** Author reference. May include a `name` alongside the `@id`. */\n author: Reference;\n /** Publisher reference. Usually the same as the author for personal blogs. */\n publisher: Reference;\n headline: string;\n /** Required for articles — overrides the optional inherited field. */\n description: string;\n /** Required for articles — overrides the optional inherited field. Emitted as ISO string. */\n datePublished: Date;\n /** Reference to the primary ImageObject, if any. */\n image?: Reference;\n /** Top-level category, emitted as `articleSection`. */\n articleSection?: string;\n wordCount?: number;\n articleBody?: string;\n}\n\nexport type ArticleInput = ArticleCoreFields &\n Omit<Partial<ArticleLeaf>, keyof ArticleCoreFields | '@type'>;\n\nconst HANDLED_KEYS = new Set<string>([\n ...CREATIVE_WORK_KEYS,\n 'url',\n 'isPartOf',\n 'author',\n 'publisher',\n 'headline',\n 'image',\n 'articleSection',\n 'wordCount',\n 'articleBody',\n]);\n\n/**\n * Build a schema.org Article piece.\n */\nexport function buildArticle(\n input: ArticleInput,\n ids: IdFactory,\n type: ArticleType = 'Article',\n): GraphEntity {\n const piece: GraphEntity = {\n '@type': type,\n '@id': ids.article(input.url),\n isPartOf: input.isPartOf,\n author: input.author,\n headline: input.headline,\n mainEntityOfPage: { '@id': ids.webPage(input.url) },\n publisher: input.publisher,\n };\n\n if (input.image !== undefined) piece.image = input.image;\n applyCreativeWorkFields(piece, input);\n if (input.articleSection !== undefined) piece.articleSection = input.articleSection;\n if (input.wordCount !== undefined) piece.wordCount = input.wordCount;\n if (input.articleBody !== undefined) piece.articleBody = input.articleBody;\n spreadRemainingProperties(piece, input, HANDLED_KEYS);\n\n return piece;\n}\n"]}
@@ -1,5 +1,6 @@
1
1
  import type { BreadcrumbListLeaf } from 'schema-dts';
2
2
  import type { IdFactory } from '../ids.js';
3
+ import type { GraphEntity } from '../types.js';
3
4
  export interface BreadcrumbItem {
4
5
  /** Display name for this crumb, e.g. 'Home', 'Blog', 'Open Source'. */
5
6
  name: string;
@@ -18,6 +19,6 @@ export type BreadcrumbListInput = BreadcrumbListCoreFields & Omit<Partial<Breadc
18
19
  /**
19
20
  * Build a schema.org BreadcrumbList piece.
20
21
  */
21
- export declare function buildBreadcrumbList(input: BreadcrumbListInput, ids: IdFactory): Record<string, unknown>;
22
+ export declare function buildBreadcrumbList(input: BreadcrumbListInput, ids: IdFactory): GraphEntity;
22
23
  export {};
23
24
  //# sourceMappingURL=breadcrumb.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"breadcrumb.d.ts","sourceRoot":"","sources":["../../src/pieces/breadcrumb.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAErD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAG3C,MAAM,WAAW,cAAc;IAC3B,uEAAuE;IACvE,IAAI,EAAE,MAAM,CAAC;IACb,0BAA0B;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,0FAA0F;IAC1F,EAAE,CAAC,EAAE,MAAM,CAAC;CACf;AAED,UAAU,wBAAwB;IAC9B,sDAAsD;IACtD,GAAG,EAAE,MAAM,CAAC;IACZ,uDAAuD;IACvD,KAAK,EAAE,SAAS,cAAc,EAAE,CAAC;CACpC;AAED,MAAM,MAAM,mBAAmB,GAAG,wBAAwB,GACtD,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAAC,EAAE,MAAM,wBAAwB,GAAG,OAAO,CAAC,CAAC;AAIhF;;GAEG;AACH,wBAAgB,mBAAmB,CAC/B,KAAK,EAAE,mBAAmB,EAC1B,GAAG,EAAE,SAAS,GACf,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAsBzB"}
1
+ {"version":3,"file":"breadcrumb.d.ts","sourceRoot":"","sources":["../../src/pieces/breadcrumb.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAErD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG/C,MAAM,WAAW,cAAc;IAC3B,uEAAuE;IACvE,IAAI,EAAE,MAAM,CAAC;IACb,0BAA0B;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,0FAA0F;IAC1F,EAAE,CAAC,EAAE,MAAM,CAAC;CACf;AAED,UAAU,wBAAwB;IAC9B,sDAAsD;IACtD,GAAG,EAAE,MAAM,CAAC;IACZ,uDAAuD;IACvD,KAAK,EAAE,SAAS,cAAc,EAAE,CAAC;CACpC;AAED,MAAM,MAAM,mBAAmB,GAAG,wBAAwB,GACtD,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAAC,EAAE,MAAM,wBAAwB,GAAG,OAAO,CAAC,CAAC;AAIhF;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,mBAAmB,EAAE,GAAG,EAAE,SAAS,GAAG,WAAW,CAsB3F"}
@@ -1 +1 @@
1
- {"version":3,"file":"breadcrumb.js","sourceRoot":"","sources":["../../src/pieces/breadcrumb.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AAqBxD,MAAM,YAAY,GAAG,IAAI,GAAG,CAAS,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC;AAEvD;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAC/B,KAA0B,EAC1B,GAAc;IAEd,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;IACzC,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,EAAE;YACT,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,EAAE;YACpB,CAAC,CAAC,KAAK,KAAK,SAAS;gBACnB,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE;gBAClC,CAAC,CAAC,IAAI,CAAC,GAAG;KACnB,CAAC,CAAC,CAAC;IAEJ,MAAM,KAAK,GAA4B;QACnC,OAAO,EAAE,gBAAgB;QACzB,KAAK,EAAE,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC;QAChC,eAAe;KAClB,CAAC;IAEF,yBAAyB,CAAC,KAAK,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC;IAEtD,OAAO,KAAK,CAAC;AACjB,CAAC"}
1
+ {"version":3,"file":"breadcrumb.js","sourceRoot":"","sources":["../../src/pieces/breadcrumb.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AAqBxD,MAAM,YAAY,GAAG,IAAI,GAAG,CAAS,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC;AAEvD;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAA0B,EAAE,GAAc;IAC1E,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;IACzC,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,EAAE;YACT,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,EAAE;YACpB,CAAC,CAAC,KAAK,KAAK,SAAS;gBACnB,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE;gBAClC,CAAC,CAAC,IAAI,CAAC,GAAG;KACnB,CAAC,CAAC,CAAC;IAEJ,MAAM,KAAK,GAAgB;QACvB,OAAO,EAAE,gBAAgB;QACzB,KAAK,EAAE,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC;QAChC,eAAe;KAClB,CAAC;IAEF,yBAAyB,CAAC,KAAK,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC;IAEtD,OAAO,KAAK,CAAC;AACjB,CAAC","sourcesContent":["import type { BreadcrumbListLeaf } from 'schema-dts';\n\nimport type { IdFactory } from '../ids.js';\nimport type { GraphEntity } from '../types.js';\nimport { spreadRemainingProperties } from '../types.js';\n\nexport interface BreadcrumbItem {\n /** Display name for this crumb, e.g. 'Home', 'Blog', 'Open Source'. */\n name: string;\n /** URL for this crumb. */\n url: string;\n /** Optional @id override. When set, the `item` value uses this @id instead of the URL. */\n id?: string;\n}\n\ninterface BreadcrumbListCoreFields {\n /** The URL of the page this breadcrumb belongs to. */\n url: string;\n /** Pre-computed ordered list of crumbs, root first. */\n items: readonly BreadcrumbItem[];\n}\n\nexport type BreadcrumbListInput = BreadcrumbListCoreFields &\n Omit<Partial<BreadcrumbListLeaf>, keyof BreadcrumbListCoreFields | '@type'>;\n\nconst HANDLED_KEYS = new Set<string>(['url', 'items']);\n\n/**\n * Build a schema.org BreadcrumbList piece.\n */\nexport function buildBreadcrumbList(input: BreadcrumbListInput, ids: IdFactory): GraphEntity {\n const lastIndex = input.items.length - 1;\n const itemListElement = input.items.map((item, index) => ({\n '@type': 'ListItem',\n position: index + 1,\n name: item.name,\n item: item.id\n ? { '@id': item.id }\n : index === lastIndex\n ? { '@id': ids.webPage(item.url) }\n : item.url,\n }));\n\n const piece: GraphEntity = {\n '@type': 'BreadcrumbList',\n '@id': ids.breadcrumb(input.url),\n itemListElement,\n };\n\n spreadRemainingProperties(piece, input, HANDLED_KEYS);\n\n return piece;\n}\n"]}
@@ -1,4 +1,5 @@
1
1
  import type { Thing } from 'schema-dts';
2
+ import type { GraphEntity } from '../types.js';
2
3
  /**
3
4
  * Build an arbitrary schema.org piece from a raw object.
4
5
  *
@@ -25,9 +26,9 @@ export declare function buildPiece<T extends Thing, TType extends string = strin
25
26
  }>> & {
26
27
  '@type': TType;
27
28
  '@id'?: string;
28
- }): Record<string, unknown>;
29
+ }): GraphEntity;
29
30
  export declare function buildPiece(raw: Record<string, unknown> & {
30
31
  '@type': string | readonly string[];
31
32
  '@id'?: string;
32
- }): Record<string, unknown>;
33
+ }): GraphEntity;
33
34
  //# sourceMappingURL=custom.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"custom.d.ts","sourceRoot":"","sources":["../../src/pieces/custom.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAExC;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,KAAK,EAAE,KAAK,SAAS,MAAM,GAAG,MAAM,EACrE,GAAG,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,EAAE;IAAE,OAAO,EAAE,KAAK,CAAA;CAAE,CAAC,CAAC,GAAG;IAC3C,OAAO,EAAE,KAAK,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB,GACF,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAC3B,wBAAgB,UAAU,CACtB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IAC3B,OAAO,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAAC;IACpC,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB,GACF,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC"}
1
+ {"version":3,"file":"custom.d.ts","sourceRoot":"","sources":["../../src/pieces/custom.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAExC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,KAAK,EAAE,KAAK,SAAS,MAAM,GAAG,MAAM,EACrE,GAAG,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,EAAE;IAAE,OAAO,EAAE,KAAK,CAAA;CAAE,CAAC,CAAC,GAAG;IAC3C,OAAO,EAAE,KAAK,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB,GACF,WAAW,CAAC;AACf,wBAAgB,UAAU,CACtB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IAC3B,OAAO,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAAC;IACpC,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB,GACF,WAAW,CAAC"}
@@ -1,4 +1,6 @@
1
1
  export function buildPiece(raw) {
2
+ // The public overloads both require `@type` on `raw`, so the result
3
+ // always satisfies GraphEntity; the implementation signature is wider.
2
4
  return raw;
3
5
  }
4
6
  //# sourceMappingURL=custom.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"custom.js","sourceRoot":"","sources":["../../src/pieces/custom.ts"],"names":[],"mappings":"AAmCA,MAAM,UAAU,UAAU,CAAC,GAA4B;IACnD,OAAO,GAAG,CAAC;AACf,CAAC"}
1
+ {"version":3,"file":"custom.js","sourceRoot":"","sources":["../../src/pieces/custom.ts"],"names":[],"mappings":"AAqCA,MAAM,UAAU,UAAU,CAAC,GAA4B;IACnD,oEAAoE;IACpE,uEAAuE;IACvE,OAAO,GAAkB,CAAC;AAC9B,CAAC","sourcesContent":["import type { Thing } from 'schema-dts';\n\nimport type { GraphEntity } from '../types.js';\n\n/**\n * Build an arbitrary schema.org piece from a raw object.\n *\n * Pass a `schema-dts` type as the generic parameter to get autocomplete.\n * The `@type` value in your input narrows the union to the matching leaf\n * type, so `buildPiece<Product>` with `'@type': 'Product'` gives you\n * full ProductLeaf autocomplete — no need to import Leaf types.\n *\n * ```ts\n * import type { Product } from 'schema-dts';\n * buildPiece<Product>({\n * '@type': 'Product',\n * '@id': `${url}#product`,\n * name: 'Running Shoe',\n * color: 'Black', // ← autocomplete from schema-dts\n * sku: 'ABC123', // ← autocomplete from schema-dts\n * });\n * ```\n *\n * Without a generic, the input is untyped — any properties are accepted.\n */\nexport function buildPiece<T extends Thing, TType extends string = string>(\n raw: Partial<Extract<T, { '@type': TType }>> & {\n '@type': TType;\n '@id'?: string;\n },\n): GraphEntity;\nexport function buildPiece(\n raw: Record<string, unknown> & {\n '@type': string | readonly string[];\n '@id'?: string;\n },\n): GraphEntity;\nexport function buildPiece(raw: Record<string, unknown>): GraphEntity {\n // The public overloads both require `@type` on `raw`, so the result\n // always satisfies GraphEntity; the implementation signature is wider.\n return raw as GraphEntity;\n}\n"]}
@@ -1,5 +1,6 @@
1
1
  import type { ImageObjectLeaf } from 'schema-dts';
2
2
  import type { IdFactory } from '../ids.js';
3
+ import type { GraphEntity } from '../types.js';
3
4
  interface ImageObjectCoreFields {
4
5
  pageUrl?: string;
5
6
  id?: string;
@@ -16,6 +17,6 @@ export type ImageObjectInput = ImageObjectCoreFields & Omit<Partial<ImageObjectL
16
17
  * primary image (id = `${pageUrl}#primaryimage`), or `id` for a site-
17
18
  * wide image like a personal logo.
18
19
  */
19
- export declare function buildImageObject(input: ImageObjectInput, ids: IdFactory): Record<string, unknown>;
20
+ export declare function buildImageObject(input: ImageObjectInput, ids: IdFactory): GraphEntity;
20
21
  export {};
21
22
  //# sourceMappingURL=image.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"image.d.ts","sourceRoot":"","sources":["../../src/pieces/image.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAG3C,UAAU,qBAAqB;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,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;CACpB;AAED,MAAM,MAAM,gBAAgB,GAAG,qBAAqB,GAChD,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,EAAE,MAAM,qBAAqB,GAAG,OAAO,CAAC,CAAC;AAY1E;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,gBAAgB,EAAE,GAAG,EAAE,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAoBjG"}
1
+ {"version":3,"file":"image.d.ts","sourceRoot":"","sources":["../../src/pieces/image.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG/C,UAAU,qBAAqB;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,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;CACpB;AAED,MAAM,MAAM,gBAAgB,GAAG,qBAAqB,GAChD,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,EAAE,MAAM,qBAAqB,GAAG,OAAO,CAAC,CAAC;AAY1E;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,gBAAgB,EAAE,GAAG,EAAE,SAAS,GAAG,WAAW,CAoBrF"}
@@ -1 +1 @@
1
- {"version":3,"file":"image.js","sourceRoot":"","sources":["../../src/pieces/image.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AAgBxD,MAAM,YAAY,GAAG,IAAI,GAAG,CAAS;IACjC,SAAS;IACT,IAAI;IACJ,KAAK;IACL,OAAO;IACP,QAAQ;IACR,YAAY;IACZ,SAAS;CACZ,CAAC,CAAC;AAEH;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAuB,EAAE,GAAc;IACpE,MAAM,UAAU,GACZ,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;IAC5F,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,wDAAwD,CAAC,CAAC;IAC9E,CAAC;IAED,MAAM,KAAK,GAA4B;QACnC,OAAO,EAAE,aAAa;QACtB,KAAK,EAAE,UAAU;QACjB,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,IAAI,KAAK,CAAC,UAAU,KAAK,SAAS;QAAE,KAAK,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC;IACxE,yBAAyB,CAAC,KAAK,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC;IAEtD,OAAO,KAAK,CAAC;AACjB,CAAC"}
1
+ {"version":3,"file":"image.js","sourceRoot":"","sources":["../../src/pieces/image.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AAgBxD,MAAM,YAAY,GAAG,IAAI,GAAG,CAAS;IACjC,SAAS;IACT,IAAI;IACJ,KAAK;IACL,OAAO;IACP,QAAQ;IACR,YAAY;IACZ,SAAS;CACZ,CAAC,CAAC;AAEH;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAuB,EAAE,GAAc;IACpE,MAAM,UAAU,GACZ,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;IAC5F,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,wDAAwD,CAAC,CAAC;IAC9E,CAAC;IAED,MAAM,KAAK,GAAgB;QACvB,OAAO,EAAE,aAAa;QACtB,KAAK,EAAE,UAAU;QACjB,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,IAAI,KAAK,CAAC,UAAU,KAAK,SAAS;QAAE,KAAK,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC;IACxE,yBAAyB,CAAC,KAAK,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC;IAEtD,OAAO,KAAK,CAAC;AACjB,CAAC","sourcesContent":["import type { ImageObjectLeaf } from 'schema-dts';\n\nimport type { IdFactory } from '../ids.js';\nimport type { GraphEntity } from '../types.js';\nimport { spreadRemainingProperties } from '../types.js';\n\ninterface ImageObjectCoreFields {\n pageUrl?: string;\n id?: string;\n /** Public URL of the image file. Used for both `url` and `contentUrl`. */\n url: string;\n width: number;\n height: number;\n inLanguage?: string;\n caption?: string;\n}\n\nexport type ImageObjectInput = ImageObjectCoreFields &\n Omit<Partial<ImageObjectLeaf>, keyof ImageObjectCoreFields | '@type'>;\n\nconst HANDLED_KEYS = new Set<string>([\n 'pageUrl',\n 'id',\n 'url',\n 'width',\n 'height',\n 'inLanguage',\n 'caption',\n]);\n\n/**\n * Build a schema.org ImageObject piece. Pass `pageUrl` for a page's\n * primary image (id = `${pageUrl}#primaryimage`), or `id` for a site-\n * wide image like a personal logo.\n */\nexport function buildImageObject(input: ImageObjectInput, ids: IdFactory): GraphEntity {\n const resolvedId =\n input.id ?? (input.pageUrl !== undefined ? ids.primaryImage(input.pageUrl) : undefined);\n if (resolvedId === undefined) {\n throw new Error('buildImageObject: either `id` or `pageUrl` is required');\n }\n\n const piece: GraphEntity = {\n '@type': 'ImageObject',\n '@id': resolvedId,\n url: input.url,\n contentUrl: input.url,\n width: input.width,\n height: input.height,\n };\n if (input.caption !== undefined) piece.caption = input.caption;\n if (input.inLanguage !== undefined) piece.inLanguage = input.inLanguage;\n spreadRemainingProperties(piece, input, HANDLED_KEYS);\n\n return piece;\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  import type { SiteNavigationElementLeaf } from 'schema-dts';
2
2
  import type { IdFactory } from '../ids.js';
3
- import type { Reference } from '../types.js';
3
+ import type { Reference, GraphEntity } from '../types.js';
4
4
  export interface NavigationItem {
5
5
  name: string;
6
6
  url: string;
@@ -15,6 +15,6 @@ export type SiteNavigationInput = SiteNavigationCoreFields & Omit<Partial<SiteNa
15
15
  * Build a schema.org SiteNavigationElement whose `hasPart` is a list of
16
16
  * sub-SiteNavigationElement entries (one per nav link).
17
17
  */
18
- export declare function buildSiteNavigationElement(input: SiteNavigationInput, ids: IdFactory): Record<string, unknown>;
18
+ export declare function buildSiteNavigationElement(input: SiteNavigationInput, ids: IdFactory): GraphEntity;
19
19
  export {};
20
20
  //# sourceMappingURL=navigation.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"navigation.d.ts","sourceRoot":"","sources":["../../src/pieces/navigation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAC;AAE5D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAG7C,MAAM,WAAW,cAAc;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACf;AAED,UAAU,wBAAwB;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,SAAS,CAAC;IACpB,KAAK,EAAE,SAAS,cAAc,EAAE,CAAC;CACpC;AAED,MAAM,MAAM,mBAAmB,GAAG,wBAAwB,GACtD,IAAI,CAAC,OAAO,CAAC,yBAAyB,CAAC,EAAE,MAAM,wBAAwB,GAAG,OAAO,CAAC,CAAC;AAIvF;;;GAGG;AACH,wBAAgB,0BAA0B,CACtC,KAAK,EAAE,mBAAmB,EAC1B,GAAG,EAAE,SAAS,GACf,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAkBzB"}
1
+ {"version":3,"file":"navigation.d.ts","sourceRoot":"","sources":["../../src/pieces/navigation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAC;AAE5D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG1D,MAAM,WAAW,cAAc;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACf;AAED,UAAU,wBAAwB;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,SAAS,CAAC;IACpB,KAAK,EAAE,SAAS,cAAc,EAAE,CAAC;CACpC;AAED,MAAM,MAAM,mBAAmB,GAAG,wBAAwB,GACtD,IAAI,CAAC,OAAO,CAAC,yBAAyB,CAAC,EAAE,MAAM,wBAAwB,GAAG,OAAO,CAAC,CAAC;AAIvF;;;GAGG;AACH,wBAAgB,0BAA0B,CACtC,KAAK,EAAE,mBAAmB,EAC1B,GAAG,EAAE,SAAS,GACf,WAAW,CAkBb"}
@@ -1 +1 @@
1
- {"version":3,"file":"navigation.js","sourceRoot":"","sources":["../../src/pieces/navigation.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AAgBxD,MAAM,YAAY,GAAG,IAAI,GAAG,CAAS,CAAC,MAAM,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;AAEpE;;;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;IAEJ,MAAM,KAAK,GAA4B;QACnC,OAAO,EAAE,uBAAuB;QAChC,KAAK,EAAE,GAAG,CAAC,UAAU;QACrB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,OAAO;KACV,CAAC;IAEF,yBAAyB,CAAC,KAAK,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC;IAEtD,OAAO,KAAK,CAAC;AACjB,CAAC"}
1
+ {"version":3,"file":"navigation.js","sourceRoot":"","sources":["../../src/pieces/navigation.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AAgBxD,MAAM,YAAY,GAAG,IAAI,GAAG,CAAS,CAAC,MAAM,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;AAEpE;;;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;IAEJ,MAAM,KAAK,GAAgB;QACvB,OAAO,EAAE,uBAAuB;QAChC,KAAK,EAAE,GAAG,CAAC,UAAU;QACrB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,OAAO;KACV,CAAC;IAEF,yBAAyB,CAAC,KAAK,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC;IAEtD,OAAO,KAAK,CAAC;AACjB,CAAC","sourcesContent":["import type { SiteNavigationElementLeaf } from 'schema-dts';\n\nimport type { IdFactory } from '../ids.js';\nimport type { Reference, GraphEntity } from '../types.js';\nimport { spreadRemainingProperties } from '../types.js';\n\nexport interface NavigationItem {\n name: string;\n url: string;\n}\n\ninterface SiteNavigationCoreFields {\n name: string;\n isPartOf: Reference;\n items: readonly NavigationItem[];\n}\n\nexport type SiteNavigationInput = SiteNavigationCoreFields &\n Omit<Partial<SiteNavigationElementLeaf>, keyof SiteNavigationCoreFields | '@type'>;\n\nconst HANDLED_KEYS = new Set<string>(['name', 'isPartOf', 'items']);\n\n/**\n * Build a schema.org SiteNavigationElement whose `hasPart` is a list of\n * sub-SiteNavigationElement entries (one per nav link).\n */\nexport function buildSiteNavigationElement(\n input: SiteNavigationInput,\n ids: IdFactory,\n): GraphEntity {\n const hasPart = input.items.map((item) => ({\n '@type': 'SiteNavigationElement',\n name: item.name,\n url: item.url,\n }));\n\n const piece: GraphEntity = {\n '@type': 'SiteNavigationElement',\n '@id': ids.navigation,\n name: input.name,\n isPartOf: input.isPartOf,\n hasPart,\n };\n\n spreadRemainingProperties(piece, input, HANDLED_KEYS);\n\n return piece;\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  import type { VideoObjectLeaf } from 'schema-dts';
2
2
  import type { IdFactory } from '../ids.js';
3
- import type { Reference } from '../types.js';
3
+ import type { Reference, GraphEntity } from '../types.js';
4
4
  interface VideoObjectCoreFields {
5
5
  url: string;
6
6
  name: string;
@@ -17,6 +17,6 @@ export type VideoObjectInput = VideoObjectCoreFields & Omit<Partial<VideoObjectL
17
17
  /**
18
18
  * Build a schema.org VideoObject piece.
19
19
  */
20
- export declare function buildVideoObject(input: VideoObjectInput, ids: IdFactory): Record<string, unknown>;
20
+ export declare function buildVideoObject(input: VideoObjectInput, ids: IdFactory): GraphEntity;
21
21
  export {};
22
22
  //# sourceMappingURL=video.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"video.d.ts","sourceRoot":"","sources":["../../src/pieces/video.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAG7C,UAAU,qBAAqB;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,IAAI,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,MAAM,gBAAgB,GAAG,qBAAqB,GAChD,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,EAAE,MAAM,qBAAqB,GAAG,OAAO,CAAC,CAAC;AAe1E;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,gBAAgB,EAAE,GAAG,EAAE,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CA6BjG"}
1
+ {"version":3,"file":"video.d.ts","sourceRoot":"","sources":["../../src/pieces/video.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG1D,UAAU,qBAAqB;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,IAAI,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,MAAM,gBAAgB,GAAG,qBAAqB,GAChD,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,EAAE,MAAM,qBAAqB,GAAG,OAAO,CAAC,CAAC;AAe1E;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,gBAAgB,EAAE,GAAG,EAAE,SAAS,GAAG,WAAW,CA6BrF"}
@@ -1 +1 @@
1
- {"version":3,"file":"video.js","sourceRoot":"","sources":["../../src/pieces/video.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AAkBxD,MAAM,YAAY,GAAG,IAAI,GAAG,CAAS;IACjC,KAAK;IACL,MAAM;IACN,aAAa;IACb,UAAU;IACV,WAAW;IACX,cAAc;IACd,UAAU;IACV,YAAY;IACZ,UAAU;IACV,YAAY;CACf,CAAC,CAAC;AAEH;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAuB,EAAE,GAAc;IACpE,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;IACxE,yBAAyB,CAAC,KAAK,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC;IAEtD,OAAO,KAAK,CAAC;AACjB,CAAC"}
1
+ {"version":3,"file":"video.js","sourceRoot":"","sources":["../../src/pieces/video.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AAkBxD,MAAM,YAAY,GAAG,IAAI,GAAG,CAAS;IACjC,KAAK;IACL,MAAM;IACN,aAAa;IACb,UAAU;IACV,WAAW;IACX,cAAc;IACd,UAAU;IACV,YAAY;IACZ,UAAU;IACV,YAAY;CACf,CAAC,CAAC;AAEH;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAuB,EAAE,GAAc;IACpE,MAAM,KAAK,GAAgB;QACvB,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;IACxE,yBAAyB,CAAC,KAAK,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC;IAEtD,OAAO,KAAK,CAAC;AACjB,CAAC","sourcesContent":["import type { VideoObjectLeaf } from 'schema-dts';\n\nimport type { IdFactory } from '../ids.js';\nimport type { Reference, GraphEntity } from '../types.js';\nimport { spreadRemainingProperties } from '../types.js';\n\ninterface VideoObjectCoreFields {\n url: string;\n name: string;\n description: string;\n isPartOf: Reference;\n youtubeId?: string;\n thumbnailUrl?: string;\n embedUrl?: string;\n uploadDate?: Date;\n duration?: string;\n transcript?: string;\n}\n\nexport type VideoObjectInput = VideoObjectCoreFields &\n Omit<Partial<VideoObjectLeaf>, keyof VideoObjectCoreFields | '@type'>;\n\nconst HANDLED_KEYS = new Set<string>([\n 'url',\n 'name',\n 'description',\n 'isPartOf',\n 'youtubeId',\n 'thumbnailUrl',\n 'embedUrl',\n 'uploadDate',\n 'duration',\n 'transcript',\n]);\n\n/**\n * Build a schema.org VideoObject piece.\n */\nexport function buildVideoObject(input: VideoObjectInput, ids: IdFactory): GraphEntity {\n const piece: GraphEntity = {\n '@type': 'VideoObject',\n '@id': ids.videoObject(input.url),\n name: input.name,\n description: input.description,\n isPartOf: input.isPartOf,\n };\n\n const thumbnail =\n input.thumbnailUrl ??\n (input.youtubeId !== undefined\n ? `https://img.youtube.com/vi/${input.youtubeId}/maxresdefault.jpg`\n : undefined);\n if (thumbnail !== undefined) piece.thumbnailUrl = thumbnail;\n\n const embed =\n input.embedUrl ??\n (input.youtubeId !== undefined\n ? `https://www.youtube-nocookie.com/embed/${input.youtubeId}`\n : undefined);\n if (embed !== undefined) piece.embedUrl = embed;\n\n if (input.uploadDate !== undefined) piece.uploadDate = input.uploadDate.toISOString();\n if (input.duration !== undefined) piece.duration = input.duration;\n if (input.transcript !== undefined) piece.transcript = input.transcript;\n spreadRemainingProperties(piece, input, HANDLED_KEYS);\n\n return piece;\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  import type { WebPageLeaf } from 'schema-dts';
2
2
  import type { IdFactory } from '../ids.js';
3
- import type { Reference, CreativeWorkFields } from '../types.js';
3
+ import type { Reference, CreativeWorkFields, GraphEntity } from '../types.js';
4
4
  /**
5
5
  * Concrete WebPage subtype. `WebPage` is the default; use `ProfilePage`
6
6
  * for /about-me style pages and `CollectionPage` for index/listing pages.
@@ -27,6 +27,6 @@ export type WebPageInput = WebPageCoreFields & Omit<Partial<WebPageLeaf>, keyof
27
27
  /**
28
28
  * Build a schema.org WebPage (or ProfilePage / CollectionPage) piece.
29
29
  */
30
- export declare function buildWebPage(input: WebPageInput, ids: IdFactory, type?: WebPageType): Record<string, unknown>;
30
+ export declare function buildWebPage(input: WebPageInput, ids: IdFactory, type?: WebPageType): GraphEntity;
31
31
  export {};
32
32
  //# sourceMappingURL=webpage.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"webpage.d.ts","sourceRoot":"","sources":["../../src/pieces/webpage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAOjE;;;GAGG;AACH,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,aAAa,GAAG,gBAAgB,CAAC;AAEvE,UAAU,iBAAkB,SAAQ,kBAAkB;IAClD,kEAAkE;IAClE,GAAG,EAAE,MAAM,CAAC;IACZ,mCAAmC;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,gEAAgE;IAChE,QAAQ,EAAE,SAAS,CAAC;IACpB,qDAAqD;IACrD,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB,oDAAoD;IACpD,YAAY,CAAC,EAAE,SAAS,CAAC;IACzB;;;OAGG;IACH,eAAe,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CAC5D;AAED,MAAM,MAAM,YAAY,GAAG,iBAAiB,GACxC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,MAAM,iBAAiB,GAAG,OAAO,CAAC,CAAC;AAYlE;;GAEG;AACH,wBAAgB,YAAY,CACxB,KAAK,EAAE,YAAY,EACnB,GAAG,EAAE,SAAS,EACd,IAAI,GAAE,WAAuB,GAC9B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAoBzB"}
1
+ {"version":3,"file":"webpage.d.ts","sourceRoot":"","sources":["../../src/pieces/webpage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAO9E;;;GAGG;AACH,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,aAAa,GAAG,gBAAgB,CAAC;AAEvE,UAAU,iBAAkB,SAAQ,kBAAkB;IAClD,kEAAkE;IAClE,GAAG,EAAE,MAAM,CAAC;IACZ,mCAAmC;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,gEAAgE;IAChE,QAAQ,EAAE,SAAS,CAAC;IACpB,qDAAqD;IACrD,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB,oDAAoD;IACpD,YAAY,CAAC,EAAE,SAAS,CAAC;IACzB;;;OAGG;IACH,eAAe,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CAC5D;AAED,MAAM,MAAM,YAAY,GAAG,iBAAiB,GACxC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,MAAM,iBAAiB,GAAG,OAAO,CAAC,CAAC;AAYlE;;GAEG;AACH,wBAAgB,YAAY,CACxB,KAAK,EAAE,YAAY,EACnB,GAAG,EAAE,SAAS,EACd,IAAI,GAAE,WAAuB,GAC9B,WAAW,CAoBb"}
@@ -1 +1 @@
1
- {"version":3,"file":"webpage.js","sourceRoot":"","sources":["../../src/pieces/webpage.ts"],"names":[],"mappings":"AAIA,OAAO,EACH,uBAAuB,EACvB,yBAAyB,EACzB,kBAAkB,GACrB,MAAM,aAAa,CAAC;AA6BrB,MAAM,YAAY,GAAG,IAAI,GAAG,CAAS;IACjC,GAAG,kBAAkB;IACrB,KAAK;IACL,MAAM;IACN,UAAU;IACV,YAAY;IACZ,cAAc;IACd,iBAAiB;CACpB,CAAC,CAAC;AAEH;;GAEG;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,eAAe;KAClB,CAAC;IAEF,IAAI,KAAK,CAAC,UAAU,KAAK,SAAS;QAAE,KAAK,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC;IACxE,IAAI,KAAK,CAAC,YAAY,KAAK,SAAS;QAAE,KAAK,CAAC,kBAAkB,GAAG,KAAK,CAAC,YAAY,CAAC;IACpF,uBAAuB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IACtC,yBAAyB,CAAC,KAAK,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC;IAEtD,OAAO,KAAK,CAAC;AACjB,CAAC"}
1
+ {"version":3,"file":"webpage.js","sourceRoot":"","sources":["../../src/pieces/webpage.ts"],"names":[],"mappings":"AAIA,OAAO,EACH,uBAAuB,EACvB,yBAAyB,EACzB,kBAAkB,GACrB,MAAM,aAAa,CAAC;AA6BrB,MAAM,YAAY,GAAG,IAAI,GAAG,CAAS;IACjC,GAAG,kBAAkB;IACrB,KAAK;IACL,MAAM;IACN,UAAU;IACV,YAAY;IACZ,cAAc;IACd,iBAAiB;CACpB,CAAC,CAAC;AAEH;;GAEG;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,GAAgB;QACvB,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,eAAe;KAClB,CAAC;IAEF,IAAI,KAAK,CAAC,UAAU,KAAK,SAAS;QAAE,KAAK,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC;IACxE,IAAI,KAAK,CAAC,YAAY,KAAK,SAAS;QAAE,KAAK,CAAC,kBAAkB,GAAG,KAAK,CAAC,YAAY,CAAC;IACpF,uBAAuB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IACtC,yBAAyB,CAAC,KAAK,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC;IAEtD,OAAO,KAAK,CAAC;AACjB,CAAC","sourcesContent":["import type { WebPageLeaf } from 'schema-dts';\n\nimport type { IdFactory } from '../ids.js';\nimport type { Reference, CreativeWorkFields, GraphEntity } from '../types.js';\nimport {\n applyCreativeWorkFields,\n spreadRemainingProperties,\n CREATIVE_WORK_KEYS,\n} from '../types.js';\n\n/**\n * Concrete WebPage subtype. `WebPage` is the default; use `ProfilePage`\n * for /about-me style pages and `CollectionPage` for index/listing pages.\n */\nexport type WebPageType = 'WebPage' | 'ProfilePage' | 'CollectionPage';\n\ninterface WebPageCoreFields extends CreativeWorkFields {\n /** Canonical URL of the page. The WebPage @id equals this URL. */\n url: string;\n /** Page title (becomes `name`). */\n name: string;\n /** Reference to the site-wide WebSite (usually ids.website). */\n isPartOf: Reference;\n /** Reference to the BreadcrumbList for this page. */\n breadcrumb?: Reference;\n /** Reference to the primary ImageObject, if any. */\n primaryImage?: Reference;\n /**\n * Custom potentialAction. If omitted, defaults to a single ReadAction\n * targeting the page URL.\n */\n potentialAction?: ReadonlyArray<Record<string, unknown>>;\n}\n\nexport type WebPageInput = WebPageCoreFields &\n Omit<Partial<WebPageLeaf>, keyof WebPageCoreFields | '@type'>;\n\nconst HANDLED_KEYS = new Set<string>([\n ...CREATIVE_WORK_KEYS,\n 'url',\n 'name',\n 'isPartOf',\n 'breadcrumb',\n 'primaryImage',\n 'potentialAction',\n]);\n\n/**\n * Build a schema.org WebPage (or ProfilePage / CollectionPage) piece.\n */\nexport function buildWebPage(\n input: WebPageInput,\n ids: IdFactory,\n type: WebPageType = 'WebPage',\n): GraphEntity {\n const potentialAction: ReadonlyArray<Record<string, unknown>> = input.potentialAction ?? [\n { '@type': 'ReadAction', target: [input.url] },\n ];\n\n const piece: GraphEntity = {\n '@type': type,\n '@id': ids.webPage(input.url),\n url: input.url,\n name: input.name,\n isPartOf: input.isPartOf,\n potentialAction,\n };\n\n if (input.breadcrumb !== undefined) piece.breadcrumb = input.breadcrumb;\n if (input.primaryImage !== undefined) piece.primaryImageOfPage = input.primaryImage;\n applyCreativeWorkFields(piece, input);\n spreadRemainingProperties(piece, input, HANDLED_KEYS);\n\n return piece;\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  import type { WebSiteLeaf } from 'schema-dts';
2
2
  import type { IdFactory } from '../ids.js';
3
- import type { Reference, CreativeWorkFields } from '../types.js';
3
+ import type { Reference, CreativeWorkFields, GraphEntity } from '../types.js';
4
4
  interface WebSiteCoreFields extends CreativeWorkFields {
5
5
  /** Site URL, typically with trailing slash. */
6
6
  url: string;
@@ -15,6 +15,6 @@ export type WebSiteInput = WebSiteCoreFields & Omit<Partial<WebSiteLeaf>, keyof
15
15
  * Build a schema.org WebSite piece. This is the site-wide singleton;
16
16
  * every page's WebPage should reference it via `isPartOf`.
17
17
  */
18
- export declare function buildWebSite(input: WebSiteInput, ids: IdFactory): Record<string, unknown>;
18
+ export declare function buildWebSite(input: WebSiteInput, ids: IdFactory): GraphEntity;
19
19
  export {};
20
20
  //# sourceMappingURL=website.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"website.d.ts","sourceRoot":"","sources":["../../src/pieces/website.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAOjE,UAAU,iBAAkB,SAAQ,kBAAkB;IAClD,+CAA+C;IAC/C,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,uEAAuE;IACvE,SAAS,EAAE,SAAS,CAAC;IACrB,2DAA2D;IAC3D,OAAO,CAAC,EAAE,SAAS,CAAC;CACvB;AAED,MAAM,MAAM,YAAY,GAAG,iBAAiB,GACxC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,MAAM,iBAAiB,GAAG,OAAO,CAAC,CAAC;AAUlE;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,YAAY,EAAE,GAAG,EAAE,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAczF"}
1
+ {"version":3,"file":"website.d.ts","sourceRoot":"","sources":["../../src/pieces/website.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAO9E,UAAU,iBAAkB,SAAQ,kBAAkB;IAClD,+CAA+C;IAC/C,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,uEAAuE;IACvE,SAAS,EAAE,SAAS,CAAC;IACrB,2DAA2D;IAC3D,OAAO,CAAC,EAAE,SAAS,CAAC;CACvB;AAED,MAAM,MAAM,YAAY,GAAG,iBAAiB,GACxC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,MAAM,iBAAiB,GAAG,OAAO,CAAC,CAAC;AAUlE;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,YAAY,EAAE,GAAG,EAAE,SAAS,GAAG,WAAW,CAc7E"}
@@ -1 +1 @@
1
- {"version":3,"file":"website.js","sourceRoot":"","sources":["../../src/pieces/website.ts"],"names":[],"mappings":"AAIA,OAAO,EACH,uBAAuB,EACvB,yBAAyB,EACzB,kBAAkB,GACrB,MAAM,aAAa,CAAC;AAerB,MAAM,YAAY,GAAG,IAAI,GAAG,CAAS;IACjC,GAAG,kBAAkB;IACrB,KAAK;IACL,MAAM;IACN,WAAW;IACX,SAAS;CACZ,CAAC,CAAC;AAEH;;;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;QAChB,SAAS,EAAE,KAAK,CAAC,SAAS;KAC7B,CAAC;IAEF,uBAAuB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IACtC,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS;QAAE,KAAK,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;IAC/D,yBAAyB,CAAC,KAAK,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC;IAEtD,OAAO,KAAK,CAAC;AACjB,CAAC"}
1
+ {"version":3,"file":"website.js","sourceRoot":"","sources":["../../src/pieces/website.ts"],"names":[],"mappings":"AAIA,OAAO,EACH,uBAAuB,EACvB,yBAAyB,EACzB,kBAAkB,GACrB,MAAM,aAAa,CAAC;AAerB,MAAM,YAAY,GAAG,IAAI,GAAG,CAAS;IACjC,GAAG,kBAAkB;IACrB,KAAK;IACL,MAAM;IACN,WAAW;IACX,SAAS;CACZ,CAAC,CAAC;AAEH;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,KAAmB,EAAE,GAAc;IAC5D,MAAM,KAAK,GAAgB;QACvB,OAAO,EAAE,SAAS;QAClB,KAAK,EAAE,GAAG,CAAC,OAAO;QAClB,GAAG,EAAE,KAAK,CAAC,GAAG;QACd,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,SAAS,EAAE,KAAK,CAAC,SAAS;KAC7B,CAAC;IAEF,uBAAuB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IACtC,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS;QAAE,KAAK,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;IAC/D,yBAAyB,CAAC,KAAK,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC;IAEtD,OAAO,KAAK,CAAC;AACjB,CAAC","sourcesContent":["import type { WebSiteLeaf } from 'schema-dts';\n\nimport type { IdFactory } from '../ids.js';\nimport type { Reference, CreativeWorkFields, GraphEntity } from '../types.js';\nimport {\n applyCreativeWorkFields,\n spreadRemainingProperties,\n CREATIVE_WORK_KEYS,\n} from '../types.js';\n\ninterface WebSiteCoreFields extends CreativeWorkFields {\n /** Site URL, typically with trailing slash. */\n url: string;\n name: string;\n /** Publisher entity — usually the site-wide Person or Organization. */\n publisher: Reference;\n /** Optional navigation reference (e.g. ids.navigation). */\n hasPart?: Reference;\n}\n\nexport type WebSiteInput = WebSiteCoreFields &\n Omit<Partial<WebSiteLeaf>, keyof WebSiteCoreFields | '@type'>;\n\nconst HANDLED_KEYS = new Set<string>([\n ...CREATIVE_WORK_KEYS,\n 'url',\n 'name',\n 'publisher',\n 'hasPart',\n]);\n\n/**\n * Build a schema.org WebSite piece. This is the site-wide singleton;\n * every page's WebPage should reference it via `isPartOf`.\n */\nexport function buildWebSite(input: WebSiteInput, ids: IdFactory): GraphEntity {\n const piece: GraphEntity = {\n '@type': 'WebSite',\n '@id': ids.website,\n url: input.url,\n name: input.name,\n publisher: input.publisher,\n };\n\n applyCreativeWorkFields(piece, input);\n if (input.hasPart !== undefined) piece.hasPart = input.hasPart;\n spreadRemainingProperties(piece, input, HANDLED_KEYS);\n\n return piece;\n}\n"]}
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AA6DA;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CACnC,KAA8B,EAC9B,KAAyB;IAEzB,IAAI,KAAK,CAAC,WAAW,KAAK,SAAS;QAAE,KAAK,CAAC,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC;IAC3E,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS;QAAE,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;IACzD,IAAI,KAAK,CAAC,UAAU,KAAK,SAAS;QAAE,KAAK,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC;IACxE,IAAI,KAAK,CAAC,aAAa,KAAK,SAAS;QAAE,KAAK,CAAC,aAAa,GAAG,KAAK,CAAC,aAAa,CAAC,WAAW,EAAE,CAAC;IAC/F,IAAI,KAAK,CAAC,YAAY,KAAK,SAAS;QAAE,KAAK,CAAC,YAAY,GAAG,KAAK,CAAC,YAAY,CAAC,WAAW,EAAE,CAAC;IAC5F,IAAI,KAAK,CAAC,eAAe,KAAK,SAAS;QAAE,KAAK,CAAC,eAAe,GAAG,KAAK,CAAC,eAAe,CAAC;IACvF,IAAI,KAAK,CAAC,aAAa,KAAK,SAAS;QAAE,KAAK,CAAC,aAAa,GAAG,KAAK,CAAC,aAAa,CAAC;IACjF,IAAI,KAAK,CAAC,eAAe,KAAK,SAAS;QAAE,KAAK,CAAC,eAAe,GAAG,KAAK,CAAC,eAAe,CAAC;IACvF,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS;QAAE,KAAK,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;IAC/D,IAAI,KAAK,CAAC,mBAAmB,KAAK,SAAS;QACvC,KAAK,CAAC,mBAAmB,GAAG,KAAK,CAAC,mBAAmB,CAAC;AAC9D,CAAC;AAED,mDAAmD;AACnD,MAAM,CAAC,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAAS;IAC9C,aAAa;IACb,OAAO;IACP,YAAY;IACZ,eAAe;IACf,cAAc;IACd,iBAAiB;IACjB,eAAe;IACf,iBAAiB;IACjB,SAAS;IACT,qBAAqB;CACxB,CAAC,CAAC;AAEH;;;GAGG;AACH,MAAM,UAAU,yBAAyB,CACrC,KAA8B,EAC9B,KAAa,EACb,WAAgC;IAEhC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAC/C,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YAC/C,KAAK,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QACvB,CAAC;IACL,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AA6DA;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CACnC,KAA8B,EAC9B,KAAyB;IAEzB,IAAI,KAAK,CAAC,WAAW,KAAK,SAAS;QAAE,KAAK,CAAC,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC;IAC3E,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS;QAAE,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;IACzD,IAAI,KAAK,CAAC,UAAU,KAAK,SAAS;QAAE,KAAK,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC;IACxE,IAAI,KAAK,CAAC,aAAa,KAAK,SAAS;QAAE,KAAK,CAAC,aAAa,GAAG,KAAK,CAAC,aAAa,CAAC,WAAW,EAAE,CAAC;IAC/F,IAAI,KAAK,CAAC,YAAY,KAAK,SAAS;QAAE,KAAK,CAAC,YAAY,GAAG,KAAK,CAAC,YAAY,CAAC,WAAW,EAAE,CAAC;IAC5F,IAAI,KAAK,CAAC,eAAe,KAAK,SAAS;QAAE,KAAK,CAAC,eAAe,GAAG,KAAK,CAAC,eAAe,CAAC;IACvF,IAAI,KAAK,CAAC,aAAa,KAAK,SAAS;QAAE,KAAK,CAAC,aAAa,GAAG,KAAK,CAAC,aAAa,CAAC;IACjF,IAAI,KAAK,CAAC,eAAe,KAAK,SAAS;QAAE,KAAK,CAAC,eAAe,GAAG,KAAK,CAAC,eAAe,CAAC;IACvF,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS;QAAE,KAAK,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;IAC/D,IAAI,KAAK,CAAC,mBAAmB,KAAK,SAAS;QACvC,KAAK,CAAC,mBAAmB,GAAG,KAAK,CAAC,mBAAmB,CAAC;AAC9D,CAAC;AAED,mDAAmD;AACnD,MAAM,CAAC,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAAS;IAC9C,aAAa;IACb,OAAO;IACP,YAAY;IACZ,eAAe;IACf,cAAc;IACd,iBAAiB;IACjB,eAAe;IACf,iBAAiB;IACjB,SAAS;IACT,qBAAqB;CACxB,CAAC,CAAC;AAEH;;;GAGG;AACH,MAAM,UAAU,yBAAyB,CACrC,KAA8B,EAC9B,KAAa,EACb,WAAgC;IAEhC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAC/C,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YAC/C,KAAK,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QACvB,CAAC;IACL,CAAC;AACL,CAAC","sourcesContent":["import type { Thing, WithContext } from 'schema-dts';\n\n/**\n * A reference to another entity in the @graph, by its @id.\n *\n * Most schema.org entities link to each other via `{ '@id': string }`.\n * Some consumers (notably joost.blog's Article.author) include the `name`\n * alongside the id, which is redundant but valid schema.org. The optional\n * `name` field lets callers opt into that pattern.\n */\nexport interface Reference {\n '@id': string;\n name?: string;\n}\n\n/**\n * The assembled @graph produced by `assembleGraph`.\n */\nexport type SchemaGraph<T extends Thing = Thing> = WithContext<Thing> & {\n '@context': 'https://schema.org';\n '@graph': T[];\n};\n\n/**\n * A single entity in the graph, as returned by a piece builder.\n * All entities should carry an `@id` so they can be cross-referenced.\n */\nexport interface GraphEntity {\n '@type': string | readonly string[];\n '@id'?: string;\n [key: string]: unknown;\n}\n\n/**\n * Optional schema.org CreativeWork properties shared across WebSite,\n * WebPage, and Article builders. Extend your input interface from this\n * to inherit the fields.\n */\nexport interface CreativeWorkFields {\n /** Short description / summary of this entity. */\n description?: string;\n /** What this entity is about — e.g. a Person, Organization, or other entity. */\n about?: Reference;\n /** Content language, e.g. 'en-US'. */\n inLanguage?: string;\n /** Publish date — emitted as ISO string. */\n datePublished?: Date;\n /** Update date — emitted as ISO string. */\n dateModified?: Date;\n /** Who holds the copyright — typically a Person or Organization reference. */\n copyrightHolder?: Reference;\n /** Year copyright was first asserted. */\n copyrightYear?: number;\n /** Human-readable copyright text, e.g. '© 2026 Jane Doe. All rights reserved.' */\n copyrightNotice?: string;\n /** License URL or CreativeWork reference (e.g. a Creative Commons URL). */\n license?: string;\n /** Whether the content is free to access. */\n isAccessibleForFree?: boolean;\n}\n\n/**\n * Apply shared CreativeWork fields to a piece under construction.\n * Call from any builder whose input extends `CreativeWorkFields`.\n */\nexport function applyCreativeWorkFields(\n piece: Record<string, unknown>,\n input: CreativeWorkFields,\n): void {\n if (input.description !== undefined) piece.description = input.description;\n if (input.about !== undefined) piece.about = input.about;\n if (input.inLanguage !== undefined) piece.inLanguage = input.inLanguage;\n if (input.datePublished !== undefined) piece.datePublished = input.datePublished.toISOString();\n if (input.dateModified !== undefined) piece.dateModified = input.dateModified.toISOString();\n if (input.copyrightHolder !== undefined) piece.copyrightHolder = input.copyrightHolder;\n if (input.copyrightYear !== undefined) piece.copyrightYear = input.copyrightYear;\n if (input.copyrightNotice !== undefined) piece.copyrightNotice = input.copyrightNotice;\n if (input.license !== undefined) piece.license = input.license;\n if (input.isAccessibleForFree !== undefined)\n piece.isAccessibleForFree = input.isAccessibleForFree;\n}\n\n/** Keys that `applyCreativeWorkFields` handles. */\nexport const CREATIVE_WORK_KEYS = new Set<string>([\n 'description',\n 'about',\n 'inLanguage',\n 'datePublished',\n 'dateModified',\n 'copyrightHolder',\n 'copyrightYear',\n 'copyrightNotice',\n 'license',\n 'isAccessibleForFree',\n]);\n\n/**\n * Spread all properties from `input` into `piece`, skipping keys that\n * the builder handles specially. Call after all explicit field handling.\n */\nexport function spreadRemainingProperties(\n piece: Record<string, unknown>,\n input: object,\n handledKeys: ReadonlySet<string>,\n): void {\n for (const [key, value] of Object.entries(input)) {\n if (!handledKeys.has(key) && value !== undefined) {\n piece[key] = value;\n }\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jdevalk/seo-graph-core",
3
- "version": "0.6.1",
3
+ "version": "0.7.0",
4
4
  "description": "Pure schema.org JSON-LD graph builders. Runtime-agnostic core for agent-ready SEO.",
5
5
  "keywords": [
6
6
  "schema.org",
@@ -40,9 +40,9 @@
40
40
  "schema-dts": "^2.0.0"
41
41
  },
42
42
  "devDependencies": {
43
- "@types/node": "^22.0.0",
44
- "typescript": "^5.6.0",
45
- "vitest": "^2.0.0"
43
+ "@types/node": "^25.9.3",
44
+ "typescript": "^6.0.3",
45
+ "vitest": "^4.1.9"
46
46
  },
47
47
  "scripts": {
48
48
  "build": "tsc -p tsconfig.build.json && cp ../../AGENTS.md .",