@iterant/site-runtime 3.11.0 → 3.11.1

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.
@@ -50,7 +50,7 @@ runtime and says so.
50
50
 
51
51
  <!-- generated: available libraries -->
52
52
 
53
- _Generated from package.json by scripts/generate-kit-table.mjs. Runtime 3.11.0._
53
+ _Generated from package.json by scripts/generate-kit-table.mjs. Runtime 3.11.1._
54
54
 
55
55
  **Toolchain** (this package owns the version; do NOT declare these):
56
56
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iterant/site-runtime",
3
- "version": "3.11.0",
3
+ "version": "3.11.1",
4
4
  "type": "module",
5
5
  "description": "The platform layer every Iterant brand site runs on: content grammar, collection schemas, SEO head and JSON-LD, layout core, Astro config preset, dev integrations and the verify gates.",
6
6
  "scripts": {
@@ -33,11 +33,15 @@ function resolvePagesDir({ pagesDir, root }: SitemapPathsOptions): string {
33
33
 
34
34
  /**
35
35
  * Every advertised page entry's route (neither draft nor noindex), home
36
- * excluded (@astrojs/sitemap already emits the site root). Returns `{ paths, pagesDir }` so a caller can report
36
+ * excluded (@astrojs/sitemap already emits the site root), beside `deny`: the
37
+ * routes of the entries that are NOT advertised. The integration crawls the
38
+ * prerendered pages itself and would list those a second way, so the caller
39
+ * drops them through its filter. Returns `pagesDir` so a caller can report
37
40
  * WHERE it looked when the answer is empty.
38
41
  */
39
42
  export function getSitemapPaths(options: SitemapPathsOptions = {}): {
40
43
  paths: string[];
44
+ deny: string[];
41
45
  entryCount: number;
42
46
  pagesDir: string;
43
47
  } {
@@ -46,22 +50,24 @@ export function getSitemapPaths(options: SitemapPathsOptions = {}): {
46
50
  try {
47
51
  entries = readdirSync(pagesDir, { recursive: true }) as string[];
48
52
  } catch {
49
- return { paths: [], pagesDir, entryCount: 0 }; // no page entries yet
53
+ return { paths: [], deny: [], pagesDir, entryCount: 0 }; // no page entries yet
50
54
  }
51
55
  const jsonEntries = entries.filter((entry) => entry.endsWith(".json"));
52
56
  const entryCount = jsonEntries.length;
53
- const paths = jsonEntries
54
- .filter((rel) => /\.json$/i.test(rel))
55
- .map((rel) => {
56
- try {
57
- const data = JSON.parse(readFileSync(join(pagesDir, rel), "utf8"));
58
- if (typeof data.route !== "string") return null;
59
- if (!isAdvertised(data, { includeDrafts: false })) return null;
60
- return data.route as string;
61
- } catch {
62
- return null; // malformed entry; the build will surface the schema error
57
+ const paths: string[] = [];
58
+ const deny: string[] = [];
59
+ for (const rel of jsonEntries) {
60
+ try {
61
+ const data = JSON.parse(readFileSync(join(pagesDir, rel), "utf8"));
62
+ if (typeof data.route !== "string") continue;
63
+ if (!isAdvertised(data, { includeDrafts: false })) {
64
+ deny.push(data.route as string);
65
+ } else if (data.route !== "/") {
66
+ paths.push(data.route as string);
63
67
  }
64
- })
65
- .filter((path): path is string => path !== null && path !== "/");
66
- return { paths, pagesDir, entryCount };
68
+ } catch {
69
+ // malformed entry; the build will surface the schema error
70
+ }
71
+ }
72
+ return { paths, deny, pagesDir, entryCount };
67
73
  }
@@ -14,11 +14,16 @@ const PLACEHOLDER = "https://starter.invalid";
14
14
  // names them here.
15
15
  const PLATFORM_DENY = new Set(["/under-construction"]);
16
16
 
17
- /** Whether a sitemap URL may be listed: everything but the platform's own routes. */
18
- export function sitemapPageAllowed(url: string): boolean {
17
+ /** Whether a sitemap URL may be listed: neither a platform route nor a denied
18
+ * entry route (a draft or a noindex page), whichever way the integration
19
+ * found it. */
20
+ export function sitemapPageAllowed(
21
+ url: string,
22
+ deny: ReadonlySet<string> = new Set(),
23
+ ): boolean {
19
24
  try {
20
25
  const pathname = new URL(url).pathname.replace(/\/+$/, "") || "/";
21
- return !PLATFORM_DENY.has(pathname);
26
+ return !PLATFORM_DENY.has(pathname) && !deny.has(pathname);
22
27
  } catch {
23
28
  return true;
24
29
  }
@@ -41,6 +46,9 @@ export function sitemapWithCustomPages(
41
46
  // This integration is ordered ahead of @astrojs/sitemap, so the array is
42
47
  // populated before anything reads it.
43
48
  const customPages: string[] = [...(sitemapOptions.customPages ?? [])];
49
+ // Filled beside customPages: the entry routes the integration must not list
50
+ // from its own crawl of prerendered pages.
51
+ const denied = new Set<string>();
44
52
 
45
53
  return [
46
54
  {
@@ -49,6 +57,7 @@ export function sitemapWithCustomPages(
49
57
  "astro:config:setup": ({ config, logger }) => {
50
58
  const {
51
59
  paths,
60
+ deny,
52
61
  pagesDir: searched,
53
62
  entryCount,
54
63
  } = getSitemapPaths({
@@ -68,6 +77,9 @@ export function sitemapWithCustomPages(
68
77
  `page entries in ${searched} are all drafts or the site root; the sitemap lists no SSR routes yet`,
69
78
  );
70
79
  }
80
+ for (const path of deny) {
81
+ denied.add(path.replace(/\/+$/, "") || "/");
82
+ }
71
83
  for (const path of paths) {
72
84
  customPages.push(
73
85
  `${PLACEHOLDER}${path.startsWith("/") ? path : `/${path}`}`,
@@ -85,7 +97,8 @@ export function sitemapWithCustomPages(
85
97
  ...sitemapOptions,
86
98
  customPages,
87
99
  filter: (page) =>
88
- sitemapPageAllowed(page) && (userFilter ? userFilter(page) : true),
100
+ sitemapPageAllowed(page, denied) &&
101
+ (userFilter ? userFilter(page) : true),
89
102
  serialize(item) {
90
103
  if (resolvedSite && item.url.startsWith(PLACEHOLDER)) {
91
104
  item.url = resolvedSite + item.url.slice(PLACEHOLDER.length);