@tokenoftrust/storefront-runner 4.7.6 → 4.7.7

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.
@@ -169,9 +169,18 @@ export async function sitemapIndexResponse(context: APIContext): Promise<Respons
169
169
  return new Response(renderSitemapIndexV1(context.locals.canonicalBase, children), { headers: XML_HEADERS });
170
170
  }
171
171
 
172
+ /**
173
+ * The child path a request names: the last segment of the URL path. Read from the URL, never from
174
+ * `context.params`: a path-routed request (`/<domain>/sitemap-pages-1.xml`) reaches this endpoint
175
+ * through the middleware's rewrite, which leaves the catch-all's params on the context.
176
+ */
177
+ export function sitemapChildPathOf(context: APIContext): string {
178
+ return `/${context.url.pathname.split("/").pop() ?? ""}`;
179
+ }
180
+
172
181
  /** `/sitemap-<group>-<page>.xml`: one child's `<urlset>`, or 404 when the index names no such child. */
173
- export async function sitemapChildResponse(context: APIContext, childPath: string): Promise<Response> {
174
- const named = parseSitemapChildPathV1(childPath);
182
+ export async function sitemapChildResponse(context: APIContext): Promise<Response> {
183
+ const named = parseSitemapChildPathV1(sitemapChildPathOf(context));
175
184
  if (!named) return new Response("Not found", { status: 404, headers: { "content-type": "text/plain; charset=utf-8" } });
176
185
  const children = await tenantSitemapChildren(context.locals);
177
186
  const child = children.find((c) => c.group === named.group && c.page === named.page);
@@ -6,5 +6,5 @@ import type { APIContext } from "astro";
6
6
  import { sitemapChildResponse } from "./_sitemap.js";
7
7
 
8
8
  export function GET(context: APIContext): Promise<Response> {
9
- return sitemapChildResponse(context, `/sitemap-${String(context.params.child ?? "")}.xml`);
9
+ return sitemapChildResponse(context);
10
10
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tokenoftrust/storefront-runner",
3
- "version": "4.7.6",
3
+ "version": "4.7.7",
4
4
  "license": "SEE LICENSE IN LICENSE",
5
5
  "description": "World-shareable storefront runner: multi-tenant renderer on Astro/Cloudflare. No control plane.",
6
6
  "packageManager": "pnpm@11.9.0",
@@ -17,6 +17,7 @@
17
17
  */
18
18
  import { existsSync, mkdirSync, readFileSync, writeFileSync, appendFileSync } from "node:fs";
19
19
  import { dirname, join } from "node:path";
20
+ import { parseSitemapChildPathV1 } from "./sitemap-index.mjs";
20
21
 
21
22
  /** Where `tot clone` puts each mounted space, relative to the root checkout: `spaces/<spaceId>/`. */
22
23
  export const SPACES_DIR = "spaces";
@@ -26,7 +27,9 @@ export const TOPOLOGY_VERSION = 1;
26
27
 
27
28
  /**
28
29
  * Platform-owned paths no space serves (packages/public-runtime PUBLICATION_SPACE_RESERVED_MOUNTS;
29
- * the ownership parity test holds the two equal).
30
+ * the ownership parity test holds the two equal). Child sitemaps (`/sitemap-<group>-<page>.xml`) are
31
+ * platform-owned too, recognized by `parseSitemapChildPathV1` (a byte-identical copy of
32
+ * packages/public-runtime/src/sitemap-index.mjs, pinned by test/sitemap-index-copy.test.mjs).
30
33
  */
31
34
  export const PLATFORM_PATHS = Object.freeze([
32
35
  "/.well-known", "/__evidence", "/__preview", "/_a", "/_astro", "/_style-guide", "/admin", "/api",
@@ -167,7 +170,9 @@ export function owningSpace(topology, urlPath) {
167
170
  const path = normalizeRequestPath(urlPath);
168
171
  if (path === null) return null;
169
172
  const folded = path.toLowerCase();
170
- if (PLATFORM_PATHS.some((reserved) => mountMatchesPath(reserved, folded))) return { space: null, via: "platform" };
173
+ if (PLATFORM_PATHS.some((reserved) => mountMatchesPath(reserved, folded)) || parseSitemapChildPathV1(folded) !== null) {
174
+ return { space: null, via: "platform" };
175
+ }
171
176
  /** @type {{ space: TopologySpace, via: "mount"|"alias", mount: string } | null} */
172
177
  let best = null;
173
178
  for (const space of topology.spaces) {
@@ -44,8 +44,9 @@ export function sitemapChildPathV1(group, page) {
44
44
  export function parseSitemapChildPathV1(path) {
45
45
  if (typeof path !== "string") return null;
46
46
  const match = CHILD_PATH.exec(path);
47
- if (!match || !SITEMAP_GROUPS_V1.includes(match[1])) return null;
48
- return { group: match[1], page: Number(match[2]) };
47
+ const group = match?.[1];
48
+ if (!match || group === undefined || !SITEMAP_GROUPS_V1.includes(group)) return null;
49
+ return { group, page: Number(match[2]) };
49
50
  }
50
51
 
51
52
  /** True for `/sitemap.xml` and for every well-formed child sitemap path. @param {string} path */
@@ -139,7 +140,7 @@ export function isSitemapIndexXmlV1(xml) {
139
140
  */
140
141
  export function sitemapIndexLocsV1(xml) {
141
142
  if (!isSitemapIndexXmlV1(xml)) return [];
142
- return [...xml.matchAll(/<sitemap>\s*<loc>([^<]*)<\/loc>/g)].map((match) => match[1].trim());
143
+ return [...xml.matchAll(/<sitemap>\s*<loc>([^<]*)<\/loc>/g)].map((match) => (match[1] ?? "").trim());
143
144
  }
144
145
 
145
146
  /**