pagegraph 0.11.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/README.md +140 -137
  2. package/dist/audit.d.ts +1 -1
  3. package/dist/audit.js +1 -1
  4. package/dist/build-only/audit.d.ts +1 -0
  5. package/dist/build-only/audit.js +6 -0
  6. package/dist/build-only/audit.js.map +1 -0
  7. package/dist/build-only/config.d.ts +1 -0
  8. package/dist/build-only/config.js +6 -0
  9. package/dist/build-only/config.js.map +1 -0
  10. package/dist/build-only/tanstack-start.d.ts +1 -0
  11. package/dist/build-only/tanstack-start.js +6 -0
  12. package/dist/build-only/tanstack-start.js.map +1 -0
  13. package/dist/build-only/vite.d.ts +1 -0
  14. package/dist/build-only/vite.js +6 -0
  15. package/dist/build-only/vite.js.map +1 -0
  16. package/dist/{checks-nk8ZRRIA.js → checks-uZk5Em9A.js} +3 -141
  17. package/dist/checks-uZk5Em9A.js.map +1 -0
  18. package/dist/cli.js +393 -287
  19. package/dist/cli.js.map +1 -1
  20. package/dist/config.d.ts +7 -66
  21. package/dist/config.js +3 -122
  22. package/dist/config.js.map +1 -1
  23. package/dist/{content-DVL2iyGU.d.ts → content-B1cPtL8b.d.ts} +4 -128
  24. package/dist/{content-CB_kHmJ3.js → content-kcEnQdfi.js} +3 -2
  25. package/dist/{content-CB_kHmJ3.js.map → content-kcEnQdfi.js.map} +1 -1
  26. package/dist/declare-D5o7hwmv.js +9 -0
  27. package/dist/declare-D5o7hwmv.js.map +1 -0
  28. package/dist/declare-DVgdEdOL.d.ts +12127 -0
  29. package/dist/graph-Bcsourlv.js +162 -0
  30. package/dist/graph-Bcsourlv.js.map +1 -0
  31. package/dist/graph-BxCY90vq.d.ts +104 -0
  32. package/dist/graph-CBIY71w6.d.ts +57 -0
  33. package/dist/index.d.ts +37 -73
  34. package/dist/index.js +23 -134
  35. package/dist/index.js.map +1 -1
  36. package/dist/message-DT_CjUdt.js +12 -0
  37. package/dist/message-DT_CjUdt.js.map +1 -0
  38. package/dist/page-heads-6y-CARRQ.js +25 -0
  39. package/dist/page-heads-6y-CARRQ.js.map +1 -0
  40. package/dist/page-heads-DNkjMUEN.d.ts +21 -0
  41. package/dist/projections-D0oOFKiY.js +142 -0
  42. package/dist/projections-D0oOFKiY.js.map +1 -0
  43. package/dist/projections-DeEFe7XT.d.ts +78 -0
  44. package/dist/react.d.ts +26 -12051
  45. package/dist/react.js +12 -3
  46. package/dist/react.js.map +1 -1
  47. package/dist/route-config-35ZEzkNC.js +308 -0
  48. package/dist/route-config-35ZEzkNC.js.map +1 -0
  49. package/dist/route-config-wneg6ktn.d.ts +29 -0
  50. package/dist/tanstack-start/index.d.ts +40 -0
  51. package/dist/tanstack-start/index.js +368 -0
  52. package/dist/tanstack-start/index.js.map +1 -0
  53. package/dist/tanstack-start/server.d.ts +14 -0
  54. package/dist/tanstack-start/server.js +53 -0
  55. package/dist/tanstack-start/server.js.map +1 -0
  56. package/dist/vite-graph-loader-01p1WxEq.js +104 -0
  57. package/dist/vite-graph-loader-01p1WxEq.js.map +1 -0
  58. package/dist/vite-graph-loader-Btgjz5RH.d.ts +56 -0
  59. package/dist/vite.d.ts +2 -28
  60. package/dist/vite.js +1 -307
  61. package/dist/wire-B4RQMc4e.js +26 -0
  62. package/dist/wire-B4RQMc4e.js.map +1 -0
  63. package/package.json +27 -5
  64. package/dist/checks-nk8ZRRIA.js.map +0 -1
  65. package/dist/vite.js.map +0 -1
@@ -0,0 +1,162 @@
1
+ import { t as applyTitleTemplate } from "./declare-D5o7hwmv.js";
2
+ //#region src/core/graph.ts
3
+ /** Kind for instances whose collection route carries no declaration to inherit. */
4
+ const FALLBACK_KIND = "page";
5
+ /**
6
+ * Join a child's local path onto its parent's computed full path with the same
7
+ * semantics as TanStack's route init (relative segments, index "/" inherits the
8
+ * parent, pathless/group routes are transparent), then normalize trailing slashes.
9
+ */
10
+ function joinPath(parent, seg) {
11
+ if (seg === void 0) return parent;
12
+ if (seg === "/") return parent;
13
+ const trimmed = seg.replace(/^\/+/, "").replace(/\/+$/, "");
14
+ return `${parent === "/" ? "" : parent}/${trimmed}`.replace(/\/{2,}/g, "/");
15
+ }
16
+ /** A route's declared head as graph data: templated title, description, and plain FAQs. */
17
+ function declaredHead(seo) {
18
+ if (seo.head === void 0) return void 0;
19
+ return {
20
+ title: applyTitleTemplate(seo.titleTemplate, seo.head.title),
21
+ description: seo.head.description,
22
+ faqs: seo.head.faqs?.map(({ question, answer }) => ({
23
+ question,
24
+ answer
25
+ }))
26
+ };
27
+ }
28
+ /** Merge a route's declaration into an existing same-path node (deeper route wins). */
29
+ function mergeSeo(base, override) {
30
+ return {
31
+ kind: override.kind,
32
+ crumb: override.crumb ?? base.crumb,
33
+ sitemap: override.sitemap ?? base.sitemap,
34
+ robots: override.robots ?? base.robots,
35
+ related: override.related ?? base.related,
36
+ link: override.link ?? base.link,
37
+ redirectTo: override.redirectTo ?? base.redirectTo,
38
+ modifiedAt: override.modifiedAt ?? base.modifiedAt,
39
+ head: override.head ?? base.head,
40
+ titleTemplate: override.titleTemplate ?? base.titleTemplate
41
+ };
42
+ }
43
+ /**
44
+ * Walk the route tree building structural nodes and crumb-parent edges. `crumbStack`
45
+ * holds the paths of crumb-declaring ancestors so each crumb node links to its nearest
46
+ * crumb ancestor down the real route-parent chain (matching render-time breadcrumbs).
47
+ */
48
+ function walkRoutes(route, parentPath, isRoot, nodes, edges, crumbStack) {
49
+ const path = isRoot ? "/" : joinPath(parentPath, route.options.path);
50
+ const seo = route.options.staticData?.seo;
51
+ if (seo) {
52
+ const existing = nodes.get(path);
53
+ if (existing) {
54
+ existing.policy = mergeSeo(existing.policy, seo);
55
+ existing.kind = existing.policy.kind;
56
+ existing.head = declaredHead(seo) ?? existing.head;
57
+ } else nodes.set(path, {
58
+ path,
59
+ kind: seo.kind,
60
+ source: "route",
61
+ policy: { ...seo },
62
+ head: declaredHead(seo)
63
+ });
64
+ const nearestCrumbAncestor = crumbStack[crumbStack.length - 1];
65
+ if (seo.crumb !== void 0 && nearestCrumbAncestor !== void 0) edges.push({
66
+ from: path,
67
+ to: nearestCrumbAncestor,
68
+ type: "crumb-parent"
69
+ });
70
+ }
71
+ const pushedCrumb = seo?.crumb !== void 0;
72
+ if (pushedCrumb) crumbStack.push(path);
73
+ for (const child of route.children ?? []) walkRoutes(child, path, false, nodes, edges, crumbStack);
74
+ if (pushedCrumb) crumbStack.pop();
75
+ }
76
+ /**
77
+ * Add one collection's instance nodes, inheriting kind + sitemap policy from the
78
+ * collection route's declaration, then append the edges it declares. A path already
79
+ * owned by another node is a collision: the first owner keeps the path and the
80
+ * conflict is reported (the `path-owner-collision` check turns it into a violation).
81
+ */
82
+ function addCollection(nodes, edges, collisions, collection) {
83
+ const collectionNode = nodes.get(collection.route);
84
+ const kind = collectionNode?.kind ?? FALLBACK_KIND;
85
+ const sitemap = collectionNode?.policy.sitemap;
86
+ const titleTemplate = collectionNode?.policy.titleTemplate;
87
+ /**
88
+ * Paths this collection lost to an earlier owner. Their instances never enter
89
+ * the graph, so any edge declared out of them would dangle — and the dead-edge
90
+ * check only validates an edge's `to`, so nothing downstream would catch it.
91
+ */
92
+ const rejected = /* @__PURE__ */ new Set();
93
+ for (const instance of collection.instances) {
94
+ const existing = nodes.get(instance.path);
95
+ if (existing) {
96
+ collisions.push({
97
+ path: instance.path,
98
+ sources: [existing.source, collection.source]
99
+ });
100
+ rejected.add(instance.path);
101
+ continue;
102
+ }
103
+ nodes.set(instance.path, {
104
+ path: instance.path,
105
+ kind,
106
+ source: collection.source,
107
+ policy: {
108
+ kind,
109
+ sitemap
110
+ },
111
+ head: {
112
+ title: applyTitleTemplate(titleTemplate, instance.title),
113
+ description: instance.description
114
+ },
115
+ instance: {
116
+ title: instance.title,
117
+ description: instance.description,
118
+ publishedAt: instance.publishedAt,
119
+ modifiedAt: instance.modifiedAt
120
+ }
121
+ });
122
+ }
123
+ for (const edge of collection.edges ?? []) {
124
+ if (rejected.has(edge.from)) continue;
125
+ edges.push(edge);
126
+ }
127
+ }
128
+ /**
129
+ * Build the SEO graph from route declarations and content collections.
130
+ *
131
+ * Synchronous: the caller materializes its collections before calling, so there is
132
+ * no async work here. Callers own the origin.
133
+ */
134
+ function buildSeoGraph(input) {
135
+ const nodes = /* @__PURE__ */ new Map();
136
+ const edges = [];
137
+ const collisions = [];
138
+ walkRoutes(input.routeTree, "/", true, nodes, edges, []);
139
+ for (const collection of input.collections ?? []) addCollection(nodes, edges, collisions, collection);
140
+ for (const node of nodes.values()) {
141
+ if (node.source !== "route") continue;
142
+ for (const to of node.policy.related ?? []) edges.push({
143
+ from: node.path,
144
+ to,
145
+ type: "related"
146
+ });
147
+ if (node.policy.redirectTo !== void 0) edges.push({
148
+ from: node.path,
149
+ to: node.policy.redirectTo,
150
+ type: "redirect"
151
+ });
152
+ }
153
+ return {
154
+ nodes,
155
+ edges,
156
+ collisions
157
+ };
158
+ }
159
+ //#endregion
160
+ export { buildSeoGraph as t };
161
+
162
+ //# sourceMappingURL=graph-Bcsourlv.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph-Bcsourlv.js","names":[],"sources":["../src/core/graph.ts"],"sourcesContent":["/**\n * SEO graph — the derived model that projections (sitemap, robots), the CLI, and\n * the check engine all read from. Built from route declarations (`staticData.seo`)\n * plus consumer-supplied content collections. This module is pure: no React, no\n * env, no knowledge of where instances come from. Origins and env-derived values\n * are injected by the callers of the projections, never read here.\n *\n * A node is one of:\n * - a structural route (`source: \"route\"`), keyed by its normalized full path,\n * merging a layout route's declaration (crumb) with its index child's (kind,\n * sitemap policy) when both resolve to the same URL;\n * - a content instance (`source` = the collection's label), keyed by the page URL\n * and carrying page-level metadata.\n *\n * Edges: `crumb-parent` (breadcrumb ancestry), `related` (deliberate cross-links),\n * `collection-member` (membership in a curated set), and `redirect` (route aliases).\n * The route walk emits crumb/related/redirect edges from declarations; a collection\n * may declare any additional edges its instances need.\n */\n\nimport type { AnyRoute } from \"@tanstack/react-router\";\n\nimport { applyTitleTemplate, type PublicPath, type RouteSeo, type SeoKind } from \"./declare\";\n\n/**\n * Where a node came from: `\"route\"` for a structural route declaration, or the\n * `source` label of the collection that produced the instance (e.g. \"blog\").\n */\nexport type SeoSource = string;\n\nexport interface SeoNode {\n /** Canonical path, no origin (e.g. \"/pricing\", \"/blog/my-post\"). */\n path: string;\n kind: SeoKind;\n source: SeoSource;\n /** Route-declared policy, or synthesized (kind + inherited sitemap) for instances. */\n policy: RouteSeo;\n /**\n * The head the page ships: a static route's declared `head`, or an instance's\n * title (through its route's `titleTemplate`) and description. Absent when the\n * route computes its head at request time and no collection supplies it.\n */\n head?: SeoNodeHead | undefined;\n instance?:\n | {\n title: string;\n description?: string | undefined;\n publishedAt?: string | undefined;\n modifiedAt?: string | undefined;\n }\n | undefined;\n}\n\n/**\n * A node's head as graph data: the full title, description, and FAQ text. An\n * instance without a description still carries its title.\n */\nexport interface SeoNodeHead {\n readonly title: string;\n readonly description?: string | undefined;\n readonly faqs?: ReadonlyArray<{ readonly question: string; readonly answer: string }> | undefined;\n}\n\nexport type SeoEdgeType = \"crumb-parent\" | \"related\" | \"redirect\" | \"collection-member\";\n\nexport interface SeoEdge {\n from: string;\n to: string;\n type: SeoEdgeType;\n}\n\nexport interface SeoGraph {\n nodes: Map<string, SeoNode>;\n edges: Array<SeoEdge>;\n /** Exact-path ownership conflicts encountered while assembling graph sources. */\n collisions?: ReadonlyArray<{ path: string; sources: ReadonlyArray<SeoSource> }> | undefined;\n}\n\n/** One concrete page produced by a collection. */\nexport interface SeoInstance {\n /** Canonical path of the page (e.g. \"/blog/my-post\"). */\n readonly path: string;\n readonly title: string;\n readonly description?: string | undefined;\n readonly publishedAt?: string | undefined;\n readonly modifiedAt?: string | undefined;\n}\n\nexport interface SeoCollection {\n /**\n * The param route these instances render through (e.g. \"/blog/$slug\"). Instances\n * inherit this route's declared policy (kind + sitemap) — the graph reads it from\n * the structural node, so declarations stay the single source of truth.\n */\n readonly route: PublicPath;\n /** The `source` stamped on every node this collection produces (e.g. \"blog\"). */\n readonly source: SeoSource;\n readonly instances: ReadonlyArray<SeoInstance>;\n /** Edges the collection declares between its instances and the rest of the graph. */\n readonly edges?: ReadonlyArray<SeoEdge> | undefined;\n}\n\n/**\n * The structural route shape the graph walks: a TanStack route tree has it\n * before `init()`, and an adapter can build it from parsed route files.\n */\nexport interface SeoRouteNode {\n readonly options: {\n readonly path?: string | undefined;\n readonly staticData?: { readonly seo?: RouteSeo | undefined } | undefined;\n };\n readonly children?: ReadonlyArray<SeoRouteNode> | undefined;\n}\n\nexport interface BuildSeoGraphInput {\n readonly routeTree: AnyRoute | SeoRouteNode;\n readonly collections?: ReadonlyArray<SeoCollection> | undefined;\n}\n\n/** Kind for instances whose collection route carries no declaration to inherit. */\nconst FALLBACK_KIND: SeoKind = \"page\";\n\n\n/**\n * Join a child's local path onto its parent's computed full path with the same\n * semantics as TanStack's route init (relative segments, index \"/\" inherits the\n * parent, pathless/group routes are transparent), then normalize trailing slashes.\n */\nfunction joinPath(parent: string, seg: string | undefined): string {\n if (seg === undefined) return parent; // pathless layout / route group\n if (seg === \"/\") return parent; // index route resolves to its parent's URL\n const trimmed = seg.replace(/^\\/+/, \"\").replace(/\\/+$/, \"\");\n const joined = `${parent === \"/\" ? \"\" : parent}/${trimmed}`;\n return joined.replace(/\\/{2,}/g, \"/\");\n}\n\n/** A route's declared head as graph data: templated title, description, and plain FAQs. */\nfunction declaredHead(seo: RouteSeo): SeoNodeHead | undefined {\n if (seo.head === undefined) return undefined;\n return {\n title: applyTitleTemplate(seo.titleTemplate, seo.head.title),\n description: seo.head.description,\n faqs: seo.head.faqs?.map(({ question, answer }) => ({ question, answer })),\n };\n}\n\n/** Merge a route's declaration into an existing same-path node (deeper route wins). */\nfunction mergeSeo(base: RouteSeo, override: RouteSeo): RouteSeo {\n return {\n kind: override.kind,\n crumb: override.crumb ?? base.crumb,\n sitemap: override.sitemap ?? base.sitemap,\n robots: override.robots ?? base.robots,\n related: override.related ?? base.related,\n link: override.link ?? base.link,\n redirectTo: override.redirectTo ?? base.redirectTo,\n modifiedAt: override.modifiedAt ?? base.modifiedAt,\n head: override.head ?? base.head,\n titleTemplate: override.titleTemplate ?? base.titleTemplate,\n };\n}\n\n/**\n * Walk the route tree building structural nodes and crumb-parent edges. `crumbStack`\n * holds the paths of crumb-declaring ancestors so each crumb node links to its nearest\n * crumb ancestor down the real route-parent chain (matching render-time breadcrumbs).\n */\nfunction walkRoutes(\n route: SeoRouteNode,\n parentPath: string,\n isRoot: boolean,\n nodes: Map<string, SeoNode>,\n edges: Array<SeoEdge>,\n crumbStack: Array<string>,\n): void {\n const path = isRoot ? \"/\" : joinPath(parentPath, route.options.path);\n const seo = route.options.staticData?.seo;\n\n if (seo) {\n const existing = nodes.get(path);\n if (existing) {\n existing.policy = mergeSeo(existing.policy, seo);\n existing.kind = existing.policy.kind;\n // A head renders with its own route's template, never one merged from a layout.\n existing.head = declaredHead(seo) ?? existing.head;\n } else {\n nodes.set(path, { path, kind: seo.kind, source: \"route\", policy: { ...seo }, head: declaredHead(seo) });\n }\n\n const nearestCrumbAncestor = crumbStack[crumbStack.length - 1];\n if (seo.crumb !== undefined && nearestCrumbAncestor !== undefined) {\n edges.push({ from: path, to: nearestCrumbAncestor, type: \"crumb-parent\" });\n }\n }\n\n const pushedCrumb = seo?.crumb !== undefined;\n if (pushedCrumb) crumbStack.push(path);\n for (const child of route.children ?? []) {\n walkRoutes(child, path, false, nodes, edges, crumbStack);\n }\n if (pushedCrumb) crumbStack.pop();\n}\n\n/**\n * Add one collection's instance nodes, inheriting kind + sitemap policy from the\n * collection route's declaration, then append the edges it declares. A path already\n * owned by another node is a collision: the first owner keeps the path and the\n * conflict is reported (the `path-owner-collision` check turns it into a violation).\n */\nfunction addCollection(\n nodes: Map<string, SeoNode>,\n edges: Array<SeoEdge>,\n collisions: Array<{ path: string; sources: ReadonlyArray<SeoSource> }>,\n collection: SeoCollection,\n): void {\n const collectionNode = nodes.get(collection.route);\n const kind = collectionNode?.kind ?? FALLBACK_KIND;\n const sitemap = collectionNode?.policy.sitemap;\n const titleTemplate = collectionNode?.policy.titleTemplate;\n\n /**\n * Paths this collection lost to an earlier owner. Their instances never enter\n * the graph, so any edge declared out of them would dangle — and the dead-edge\n * check only validates an edge's `to`, so nothing downstream would catch it.\n */\n const rejected = new Set<string>();\n\n for (const instance of collection.instances) {\n const existing = nodes.get(instance.path);\n if (existing) {\n collisions.push({ path: instance.path, sources: [existing.source, collection.source] });\n rejected.add(instance.path);\n continue;\n }\n nodes.set(instance.path, {\n path: instance.path,\n kind,\n source: collection.source,\n policy: { kind, sitemap },\n head: { title: applyTitleTemplate(titleTemplate, instance.title), description: instance.description },\n instance: {\n title: instance.title,\n description: instance.description,\n publishedAt: instance.publishedAt,\n modifiedAt: instance.modifiedAt,\n },\n });\n }\n\n for (const edge of collection.edges ?? []) {\n if (rejected.has(edge.from)) continue;\n edges.push(edge);\n }\n}\n\n/**\n * Build the SEO graph from route declarations and content collections.\n *\n * Synchronous: the caller materializes its collections before calling, so there is\n * no async work here. Callers own the origin.\n */\nexport function buildSeoGraph(input: BuildSeoGraphInput): SeoGraph {\n const nodes = new Map<string, SeoNode>();\n const edges: Array<SeoEdge> = [];\n const collisions: Array<{ path: string; sources: ReadonlyArray<SeoSource> }> = [];\n\n walkRoutes(input.routeTree as unknown as SeoRouteNode, \"/\", true, nodes, edges, []);\n\n for (const collection of input.collections ?? []) {\n addCollection(nodes, edges, collisions, collection);\n }\n\n for (const node of nodes.values()) {\n if (node.source !== \"route\") continue;\n for (const to of node.policy.related ?? []) {\n edges.push({ from: node.path, to, type: \"related\" });\n }\n if (node.policy.redirectTo !== undefined) {\n edges.push({ from: node.path, to: node.policy.redirectTo, type: \"redirect\" });\n }\n }\n\n return { nodes, edges, collisions };\n}\n"],"mappings":"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"}
@@ -0,0 +1,104 @@
1
+ import { i as RouteSeo, n as PublicPath, o as SeoKind } from "./declare-DVgdEdOL.js";
2
+ import { AnyRoute } from "@tanstack/react-router";
3
+ //#region src/core/graph.d.ts
4
+ /**
5
+ * Where a node came from: `"route"` for a structural route declaration, or the
6
+ * `source` label of the collection that produced the instance (e.g. "blog").
7
+ */
8
+ type SeoSource = string;
9
+ interface SeoNode {
10
+ /** Canonical path, no origin (e.g. "/pricing", "/blog/my-post"). */
11
+ path: string;
12
+ kind: SeoKind;
13
+ source: SeoSource;
14
+ /** Route-declared policy, or synthesized (kind + inherited sitemap) for instances. */
15
+ policy: RouteSeo;
16
+ /**
17
+ * The head the page ships: a static route's declared `head`, or an instance's
18
+ * title (through its route's `titleTemplate`) and description. Absent when the
19
+ * route computes its head at request time and no collection supplies it.
20
+ */
21
+ head?: SeoNodeHead | undefined;
22
+ instance?: {
23
+ title: string;
24
+ description?: string | undefined;
25
+ publishedAt?: string | undefined;
26
+ modifiedAt?: string | undefined;
27
+ } | undefined;
28
+ }
29
+ /**
30
+ * A node's head as graph data: the full title, description, and FAQ text. An
31
+ * instance without a description still carries its title.
32
+ */
33
+ interface SeoNodeHead {
34
+ readonly title: string;
35
+ readonly description?: string | undefined;
36
+ readonly faqs?: ReadonlyArray<{
37
+ readonly question: string;
38
+ readonly answer: string;
39
+ }> | undefined;
40
+ }
41
+ type SeoEdgeType = "crumb-parent" | "related" | "redirect" | "collection-member";
42
+ interface SeoEdge {
43
+ from: string;
44
+ to: string;
45
+ type: SeoEdgeType;
46
+ }
47
+ interface SeoGraph {
48
+ nodes: Map<string, SeoNode>;
49
+ edges: Array<SeoEdge>;
50
+ /** Exact-path ownership conflicts encountered while assembling graph sources. */
51
+ collisions?: ReadonlyArray<{
52
+ path: string;
53
+ sources: ReadonlyArray<SeoSource>;
54
+ }> | undefined;
55
+ }
56
+ /** One concrete page produced by a collection. */
57
+ interface SeoInstance {
58
+ /** Canonical path of the page (e.g. "/blog/my-post"). */
59
+ readonly path: string;
60
+ readonly title: string;
61
+ readonly description?: string | undefined;
62
+ readonly publishedAt?: string | undefined;
63
+ readonly modifiedAt?: string | undefined;
64
+ }
65
+ interface SeoCollection {
66
+ /**
67
+ * The param route these instances render through (e.g. "/blog/$slug"). Instances
68
+ * inherit this route's declared policy (kind + sitemap) — the graph reads it from
69
+ * the structural node, so declarations stay the single source of truth.
70
+ */
71
+ readonly route: PublicPath;
72
+ /** The `source` stamped on every node this collection produces (e.g. "blog"). */
73
+ readonly source: SeoSource;
74
+ readonly instances: ReadonlyArray<SeoInstance>;
75
+ /** Edges the collection declares between its instances and the rest of the graph. */
76
+ readonly edges?: ReadonlyArray<SeoEdge> | undefined;
77
+ }
78
+ /**
79
+ * The structural route shape the graph walks: a TanStack route tree has it
80
+ * before `init()`, and an adapter can build it from parsed route files.
81
+ */
82
+ interface SeoRouteNode {
83
+ readonly options: {
84
+ readonly path?: string | undefined;
85
+ readonly staticData?: {
86
+ readonly seo?: RouteSeo | undefined;
87
+ } | undefined;
88
+ };
89
+ readonly children?: ReadonlyArray<SeoRouteNode> | undefined;
90
+ }
91
+ interface BuildSeoGraphInput {
92
+ readonly routeTree: AnyRoute | SeoRouteNode;
93
+ readonly collections?: ReadonlyArray<SeoCollection> | undefined;
94
+ }
95
+ /**
96
+ * Build the SEO graph from route declarations and content collections.
97
+ *
98
+ * Synchronous: the caller materializes its collections before calling, so there is
99
+ * no async work here. Callers own the origin.
100
+ */
101
+ declare function buildSeoGraph(input: BuildSeoGraphInput): SeoGraph;
102
+ //#endregion
103
+ export { SeoGraph as a, SeoNodeHead as c, buildSeoGraph as d, SeoEdgeType as i, SeoRouteNode as l, SeoCollection as n, SeoInstance as o, SeoEdge as r, SeoNode as s, BuildSeoGraphInput as t, SeoSource as u };
104
+ //# sourceMappingURL=graph-BxCY90vq.d.ts.map
@@ -0,0 +1,57 @@
1
+ import { a as SeoGraph } from "./graph-BxCY90vq.js";
2
+ import { r as RobotsConfig } from "./projections-DeEFe7XT.js";
3
+ import { t as SeoRouteConfigOptions } from "./route-config-wneg6ktn.js";
4
+ import "@tanstack/router-generator";
5
+ //#region src/tanstack-start/graph.d.ts
6
+ /** The robots.txt policy a build serves; `origin` and indexability come from {@link SiteRuntime}. */
7
+ type RobotsPolicy = Pick<RobotsConfig, "disallow" | "contentSignal" | "directives">;
8
+ /** The graph and the site runtime one evaluation produces. */
9
+ interface AppGraph {
10
+ readonly graph: SeoGraph;
11
+ readonly site: SiteRuntime;
12
+ }
13
+ /** Site identity and robots policy, baked into the runtime module per build. */
14
+ interface SiteRuntime {
15
+ readonly origin: string;
16
+ readonly indexable: boolean;
17
+ readonly robots: RobotsPolicy;
18
+ }
19
+ interface PagegraphOptions {
20
+ /** This build's canonical origin, no trailing slash, e.g. `https://example.com`. */
21
+ readonly origin: string;
22
+ /**
23
+ * Whether this build's host may be indexed. A non-indexable build serves a
24
+ * disallow-all robots.txt with no Sitemap line. Defaults to `true`.
25
+ */
26
+ readonly indexable?: boolean | undefined;
27
+ readonly robots?: {
28
+ /** Path prefixes disallowed on an indexable host, beyond the route-config exclusions. */
29
+ readonly disallow?: ReadonlyArray<string> | undefined;
30
+ /** `Content-Signal` value for an indexable host, e.g. `"search=yes, ai-input=yes, ai-train=yes"`. */
31
+ readonly contentSignal?: string | undefined;
32
+ /** Extra lines in the `User-agent: *` group on an indexable host. */
33
+ readonly directives?: ReadonlyArray<string> | undefined;
34
+ } | undefined;
35
+ /**
36
+ * Root-relative module whose `collections` export is a `SeoCollection[]`, or a
37
+ * function returning one (sync or async). It runs in the app's Vite pipeline,
38
+ * so content virtual modules (Fumadocs, MDX) and path aliases resolve.
39
+ */
40
+ readonly collections?: string | undefined;
41
+ /**
42
+ * Route files (globs relative to the routes directory) never evaluated for the
43
+ * graph: app surfaces that declare `staticData` but import server-runtime-only
44
+ * modules. Their paths stay out of the graph.
45
+ */
46
+ readonly exclude?: ReadonlyArray<string> | undefined;
47
+ /** Relative to the Vite root. Defaults to `src/routes`. */
48
+ readonly routesDirectory?: string | undefined;
49
+ /**
50
+ * Generate the route-config module and enforce per-group SEO coverage (the
51
+ * `seoRouteConfig` gate). Its robots exclusions join `robots.disallow`.
52
+ */
53
+ readonly routeConfig?: Omit<SeoRouteConfigOptions, "routesDirectory"> | undefined;
54
+ }
55
+ //#endregion
56
+ export { SiteRuntime as i, PagegraphOptions as n, RobotsPolicy as r, AppGraph as t };
57
+ //# sourceMappingURL=graph-CBIY71w6.d.ts.map
package/dist/index.d.ts CHANGED
@@ -1,79 +1,43 @@
1
- import { $ as PublicPath, A as RenderedEdgeFailure, B as FreshnessEntry, C as Anchor, D as RENDERED_EDGE_ARTIFACT_SCHEMA_VERSION, E as LinkGraphDiff, F as decodeRenderedEdgeArtifact, G as SeoCollection, H as FreshnessReport, I as diffLinkGraph, J as SeoGraph, K as SeoEdge, L as extractAnchors, M as RenderedPage, N as SimpleEdge, O as RenderedEdgeArtifact, P as buildRenderedGraph, Q as buildSeoGraph, R as normalizePath, S as hasStructuralViolations, T as LinkEdge, U as freshnessReport, V as FreshnessPolicy, W as BuildSeoGraphInput, X as SeoNode, Y as SeoInstance, Z as SeoSource, _ as Violation, a as Heading, b as checkGraph, c as RenderedDocument, d as checkRenderedContent, et as Register, f as extractPageContent, g as Severity, h as CoverageRule, i as ContentRuleName, j as RenderedGraph, k as RenderedEdgeArtifactCrawl, l as WordCountRule, m as CheckGraphOptions, n as ContentFinding, nt as SeoKind, o as JsonLdNode, p as renderedCheckTargets, q as SeoEdgeType, r as ContentPolicy, rt as SitemapPolicy, s as PageContent, t as ContentCheckOptions, tt as RouteSeo, u as checkPageContent, v as checkCoverage, w as AnchorRegion, x as checkRenderedCoverage, y as checkFreshness, z as renderedGraphFromEdges } from "./content-DVL2iyGU.js";
1
+ import { a as SeoFaq, c as SitemapPolicy, i as RouteSeo, l as applyTitleTemplate, n as PublicPath, o as SeoKind, r as Register, s as SeoPageHead, t as JsonLdDocument } from "./declare-DVgdEdOL.js";
2
+ import { a as SeoGraph, c as SeoNodeHead, d as buildSeoGraph, i as SeoEdgeType, l as SeoRouteNode, n as SeoCollection, o as SeoInstance, r as SeoEdge, s as SeoNode, t as BuildSeoGraphInput, u as SeoSource } from "./graph-BxCY90vq.js";
3
+ import { A as RenderedEdgeFailure, B as FreshnessEntry, C as Anchor, D as RENDERED_EDGE_ARTIFACT_SCHEMA_VERSION, E as LinkGraphDiff, F as decodeRenderedEdgeArtifact, H as FreshnessReport, I as diffLinkGraph, L as extractAnchors, M as RenderedPage, N as SimpleEdge, O as RenderedEdgeArtifact, P as buildRenderedGraph, R as normalizePath, S as hasStructuralViolations, T as LinkEdge, U as freshnessReport, V as FreshnessPolicy, _ as Violation, a as Heading, b as checkGraph, c as RenderedDocument, d as checkRenderedContent, f as extractPageContent, g as Severity, h as CoverageRule, i as ContentRuleName, j as RenderedGraph, k as RenderedEdgeArtifactCrawl, l as WordCountRule, m as CheckGraphOptions, n as ContentFinding, o as JsonLdNode, p as renderedCheckTargets, r as ContentPolicy, s as PageContent, t as ContentCheckOptions, u as checkPageContent, v as checkCoverage, w as AnchorRegion, x as checkRenderedCoverage, y as checkFreshness, z as renderedGraphFromEdges } from "./content-B1cPtL8b.js";
4
+ import { a as inspectNode, c as renderRobots, i as contentSignal, l as renderSitemap, n as ProjectionConfig, o as isSitemapEligible, r as RobotsConfig, s as lastModified, t as NodeReport } from "./projections-DeEFe7XT.js";
5
+ import { i as selectPageHeadNodes, n as PageHeadsOptions, r as pageHeads, t as PageHead } from "./page-heads-DNkjMUEN.js";
2
6
  import { AnyRouter } from "@tanstack/react-router";
3
- //#region src/core/projections.d.ts
4
- interface ProjectionConfig {
5
- origin: string;
6
- indexable: boolean;
7
+ //#region src/core/collections.d.ts
8
+ /** What a page contributes: its instance metadata plus the paths it links to deliberately. */
9
+ interface ContentEntry extends Omit<SeoInstance, "path"> {
10
+ /** Defaults to the page's `url`. */
11
+ readonly path?: string | undefined;
12
+ /** Deliberate cross-links, emitted as `related` edges from this page. */
13
+ readonly related?: ReadonlyArray<string> | undefined;
7
14
  }
8
- interface RobotsConfig extends ProjectionConfig {
9
- /** Path prefixes to disallow on an indexable host (e.g. the app-only groups). */
10
- disallow: ReadonlyArray<string>;
11
- /**
12
- * Origin-wide Content-Signal preferences
13
- * (https://contentsignals.org/), emitted as `Content-Signal: <value>` under
14
- * `User-agent: *` on an indexable host. Omit for none. The plugin never
15
- * invents a default — pass the policy you want, e.g.
16
- * `"search=yes, ai-input=yes, ai-train=yes"`.
17
- */
18
- contentSignal?: string | undefined;
19
- /**
20
- * Extra full lines in the indexable `User-agent: *` group, after
21
- * Content-Signal (if any) and before Allow/Disallow. Use for directives the
22
- * plugin does not model, or to compose {@link contentSignal} yourself.
23
- */
24
- directives?: ReadonlyArray<string> | undefined;
25
- /**
26
- * Last-mile override: receives the rendered robots.txt and returns the file
27
- * to emit. Runs for indexable and preview hosts. Use when you need to wrap
28
- * or replace the default body rather than add group lines.
29
- */
30
- transform?: ((robots: string) => string) | undefined;
15
+ interface ContentCollectionOptions<Page> {
16
+ /** The param route these pages render through, e.g. `/blog/$slug`. */
17
+ readonly route: PublicPath;
18
+ /** The `source` label stamped on every node, e.g. `"blog"`. */
19
+ readonly source: SeoSource;
20
+ readonly pages: ReadonlyArray<Page>;
21
+ /** Map one page to its entry; decode frontmatter here. */
22
+ readonly entry: (page: Page) => ContentEntry;
23
+ /** Edges beyond `related` (crumb parents, collection membership). */
24
+ readonly edges?: ReadonlyArray<SeoEdge> | undefined;
31
25
  }
32
- interface NodeReport {
33
- node: SeoNode;
34
- inSitemap: boolean;
35
- incoming: Array<SeoEdge>;
36
- outgoing: Array<SeoEdge>;
26
+ declare function contentCollection<Page extends {
27
+ readonly url: string;
28
+ }>(options: ContentCollectionOptions<Page>): SeoCollection;
29
+ //#endregion
30
+ //#region src/core/wire.d.ts
31
+ interface SeoGraphJson {
32
+ readonly nodes: ReadonlyArray<SeoNode>;
33
+ readonly edges: ReadonlyArray<SeoEdge>;
34
+ readonly collisions?: ReadonlyArray<{
35
+ readonly path: string;
36
+ readonly sources: ReadonlyArray<SeoSource>;
37
+ }> | undefined;
37
38
  }
38
- /**
39
- * A node belongs in the sitemap when it declares a positive sitemap policy, is not
40
- * a redirect, is not robots-noindexed, and is not a param template (a route whose
41
- * path still contains a `$` segment — those exist only so their instances inherit).
42
- */
43
- declare function isSitemapEligible(node: SeoNode): boolean;
44
- /**
45
- * The date a node's content last changed, as declared: an instance's
46
- * `modifiedAt`, else its `publishedAt`; a route's own `modifiedAt`. A node with
47
- * no date (a docs page without frontmatter dates, an undated route) returns
48
- * undefined, and the sitemap omits its `<lastmod>`.
49
- */
50
- declare function lastModified(node: SeoNode): string | undefined;
51
- /**
52
- * Render sitemap.xml from the graph. Each entry's `<lastmod>` is its
53
- * {@link lastModified} date: frontmatter for content instances, the declared
54
- * `modifiedAt` for routes. Route entries are sorted by path, then instances follow in collection order.
55
- * `indexable` is intentionally unused — the sitemap body is host-independent;
56
- * robots.txt is what gates crawling.
57
- */
58
- declare function renderSitemap(graph: SeoGraph, cfg: ProjectionConfig): string;
59
- /** Format a Content-Signal robots.txt directive from the preference list. */
60
- declare function contentSignal(value: string): string;
61
- /**
62
- * Render robots.txt. A non-indexable host (previews) gets a disallow-all
63
- * with no Sitemap line; an indexable host disallows exactly the prefixes the caller
64
- * passes. Pages that declare `robots: noindex` are intentionally NOT added as
65
- * Disallow entries — a Disallow would stop crawlers reaching the page to read its
66
- * `noindex, follow` meta, so the graph's per-node robots policy never feeds this
67
- * list. `graph` is unused — kept for signature parity with the other projections,
68
- * which callers load the graph once for and pass to each.
69
- *
70
- * Origin-wide group directives (`contentSignal`, `directives`) are indexable-host
71
- * only. {@link RobotsConfig.transform} always runs last so a consumer can override
72
- * the whole file.
73
- */
74
- declare function renderRobots(_graph: SeoGraph, cfg: RobotsConfig): string;
75
- /** Inspect a single node: its declaration, sitemap eligibility, and edges. */
76
- declare function inspectNode(graph: SeoGraph, path: string): NodeReport | undefined;
39
+ declare function graphToJson(graph: SeoGraph): SeoGraphJson;
40
+ declare function graphFromJson(json: SeoGraphJson): SeoGraph;
77
41
  //#endregion
78
42
  //#region src/core/link-candidates.d.ts
79
43
  /** One proposed contextual link, in the direction the link would be authored. */
@@ -192,5 +156,5 @@ declare const hasBlockingIssues: (report: LiveHeadReport) => boolean;
192
156
  */
193
157
  declare function resolveRouteLink(router: AnyRouter, path: string): RouteSeo["link"];
194
158
  //#endregion
195
- export { type Anchor, type AnchorRegion, type BuildSeoGraphInput, type CheckGraphOptions, type ContentCheckOptions, type ContentFinding, type ContentPolicy, type ContentRuleName, type CoverageRule, type FreshnessEntry, type FreshnessPolicy, type FreshnessReport, type Heading, type JsonLdNode, type JsonLdReport, type LinkCandidateOptions, type LinkCandidatePair, type LinkCandidateResult, type LinkClusterSummary, type LinkEdge, type LinkGraphDiff, type LiveHeadReport, type NodeReport, type PageContent, type ProjectionConfig, type PublicPath, RENDERED_EDGE_ARTIFACT_SCHEMA_VERSION, type Register, type RenderedDocument, type RenderedEdgeArtifact, type RenderedEdgeArtifactCrawl, type RenderedEdgeFailure, type RenderedGraph, type RenderedPage, type RobotsConfig, type RouteSeo, type SeoCollection, type SeoEdge, type SeoEdgeType, type SeoGraph, type SeoInstance, type SeoKind, type SeoNode, type SeoSource, type Severity, type SimpleEdge, type SitemapPolicy, type Violation, type WordCountRule, buildRenderedGraph, buildSeoGraph, candidateSourceText, checkCoverage, checkFreshness, checkGraph, checkPageContent, checkRenderedContent, checkRenderedCoverage, contentSignal, decodeRenderedEdgeArtifact, decodeRenderedEdges, diffLinkGraph, extractAnchors, extractPageContent, freshnessReport, generateLinkCandidates, hasBlockingIssues, hasStructuralViolations, inspectHtml, inspectNode, isSitemapEligible, lastModified, matchesClusterFilter, normalizePath, renderRobots, renderSitemap, renderedCheckTargets, renderedGraphFromEdges, resolveRouteLink, undirectedEdgeKey };
159
+ export { type Anchor, type AnchorRegion, type BuildSeoGraphInput, type CheckGraphOptions, type ContentCheckOptions, type ContentCollectionOptions, type ContentEntry, type ContentFinding, type ContentPolicy, type ContentRuleName, type CoverageRule, type FreshnessEntry, type FreshnessPolicy, type FreshnessReport, type Heading, type JsonLdDocument, type JsonLdNode, type JsonLdReport, type LinkCandidateOptions, type LinkCandidatePair, type LinkCandidateResult, type LinkClusterSummary, type LinkEdge, type LinkGraphDiff, type LiveHeadReport, type NodeReport, type PageContent, type PageHead, type PageHeadsOptions, type ProjectionConfig, type PublicPath, RENDERED_EDGE_ARTIFACT_SCHEMA_VERSION, type Register, type RenderedDocument, type RenderedEdgeArtifact, type RenderedEdgeArtifactCrawl, type RenderedEdgeFailure, type RenderedGraph, type RenderedPage, type RobotsConfig, type RouteSeo, type SeoCollection, type SeoEdge, type SeoEdgeType, type SeoFaq, type SeoGraph, type SeoGraphJson, type SeoInstance, type SeoKind, type SeoNode, type SeoNodeHead, type SeoPageHead, type SeoRouteNode, type SeoSource, type Severity, type SimpleEdge, type SitemapPolicy, type Violation, type WordCountRule, applyTitleTemplate, buildRenderedGraph, buildSeoGraph, candidateSourceText, checkCoverage, checkFreshness, checkGraph, checkPageContent, checkRenderedContent, checkRenderedCoverage, contentCollection, contentSignal, decodeRenderedEdgeArtifact, decodeRenderedEdges, diffLinkGraph, extractAnchors, extractPageContent, freshnessReport, generateLinkCandidates, graphFromJson, graphToJson, hasBlockingIssues, hasStructuralViolations, inspectHtml, inspectNode, isSitemapEligible, lastModified, matchesClusterFilter, normalizePath, pageHeads, renderRobots, renderSitemap, renderedCheckTargets, renderedGraphFromEdges, resolveRouteLink, selectPageHeadNodes, undirectedEdgeKey };
196
160
  //# sourceMappingURL=index.d.ts.map