@tokenoftrust/storefront-runner 2.4.20 → 2.4.21

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.
@@ -25,7 +25,10 @@ import {
25
25
  type PublicationSpaceManifestV1,
26
26
  type RouteTierIndexV1,
27
27
  type TenantConfig,
28
+ PUBLICATION_DISCOVERY_ENTRY_KINDS_V1,
29
+ type PublicationDiscoveryEntryKindV1,
28
30
  } from "@tot/public-runtime";
31
+ import { rawPageCanonicalUrl } from "../rawMarketingHtml.js";
29
32
 
30
33
  export type DiscoverySurfaceV1 = "sitemap" | "feeds" | "publicSearch" | "llms";
31
34
 
@@ -34,6 +37,8 @@ export interface MountedDiscoveryEntryV1 {
34
37
  spaceId: string;
35
38
  /** Tenant-relative canonical route (no trailing slash). */
36
39
  canonicalPath: string;
40
+ /** The renderer that serves it; {@link mountedDiscoveryUrlV1} builds its URL from this. */
41
+ kind: PublicationDiscoveryEntryKindV1;
37
42
  title: string;
38
43
  summary: string;
39
44
  searchText: string;
@@ -88,8 +93,9 @@ function boundedString(value: unknown, allowEmpty = true): value is string {
88
93
  function parseEntry(value: unknown): MountedDiscoveryEntryV1 | null {
89
94
  if (!value || typeof value !== "object" || Array.isArray(value)) return null;
90
95
  const raw = value as Record<string, unknown>;
91
- if (!exactKeys(raw, ["spaceId", "canonicalPath", "title", "summary", "searchText", "surfaces"],
92
- ["publishedAt", "updatedAt"])) return null;
96
+ if (!exactKeys(raw, ["spaceId", "canonicalPath", "kind", "title", "summary", "searchText", "surfaces"],
97
+ ["publishedAt", "updatedAt"]) ||
98
+ !(PUBLICATION_DISCOVERY_ENTRY_KINDS_V1 as readonly unknown[]).includes(raw.kind)) return null;
93
99
  const surfaces = raw.surfaces;
94
100
  if (!surfaces || typeof surfaces !== "object" || Array.isArray(surfaces) ||
95
101
  !exactKeys(surfaces, SURFACES) ||
@@ -102,6 +108,7 @@ function parseEntry(value: unknown): MountedDiscoveryEntryV1 | null {
102
108
  return {
103
109
  spaceId: raw.spaceId,
104
110
  canonicalPath: raw.canonicalPath,
111
+ kind: raw.kind as PublicationDiscoveryEntryKindV1,
105
112
  title: raw.title,
106
113
  summary: raw.summary,
107
114
  searchText: raw.searchText,
@@ -180,6 +187,17 @@ export async function readMountedPublicationDiscoveryV1(input: {
180
187
  left.canonicalPath < right.canonicalPath ? -1 : left.canonicalPath > right.canonicalPath ? 1 : 0);
181
188
  }
182
189
 
190
+ /**
191
+ * The absolute URL every discovery surface lists for a mounted entry: the canonical the page
192
+ * itself declares. A raw-HTML page's comes from {@link rawPageCanonicalUrl}, the constructor its
193
+ * renderer (`pages/[...slug].astro`) calls, so the sitemap and the page cannot disagree.
194
+ */
195
+ export function mountedDiscoveryUrlV1(canonicalBase: string, entry: Pick<MountedDiscoveryEntryV1,
196
+ "canonicalPath" | "kind">): string {
197
+ if (entry.kind === "raw-html") return rawPageCanonicalUrl(canonicalBase, entry.canonicalPath.slice(1));
198
+ return `${canonicalBase.replace(/\/$/, "")}${entry.canonicalPath}`;
199
+ }
200
+
183
201
  /** An RFC 3339 instant for a feed, or undefined when the value is not a date. */
184
202
  export function feedInstantV1(value: string | undefined): string | undefined {
185
203
  if (!value) return undefined;
@@ -11,6 +11,7 @@ import { readKv } from "@/lib/runtimeEnv.js";
11
11
  import {
12
12
  declaresMountedSpacesV1,
13
13
  feedInstantV1,
14
+ mountedDiscoveryUrlV1,
14
15
  readMountedPublicationDiscoveryV1,
15
16
  rootOwnsDiscoveryPathV1,
16
17
  } from "@/lib/publication/mountedDiscovery.js";
@@ -53,7 +54,7 @@ export async function GET(context: APIContext): Promise<Response> {
53
54
  const mounted = await readMountedPublicationDiscoveryV1({ tenant, store: await readKv("TENANT_CACHE"), index });
54
55
  for (const entry of mounted) {
55
56
  if (!entry.surfaces.feeds) continue;
56
- items.push(item(`${base}${entry.canonicalPath}`, entry.title, entry.summary, entry.searchText,
57
+ items.push(item(mountedDiscoveryUrlV1(canonicalBase, entry), entry.title, entry.summary, entry.searchText,
57
58
  entry.publishedAt, entry.updatedAt));
58
59
  }
59
60
  }
@@ -16,6 +16,7 @@ import { compileRouteTierIndexV1 } from "@tot/public-runtime";
16
16
  import { readKv } from "@/lib/runtimeEnv.js";
17
17
  import {
18
18
  declaresMountedSpacesV1,
19
+ mountedDiscoveryUrlV1,
19
20
  readMountedPublicationDiscoveryV1,
20
21
  rootOwnsDiscoveryPathV1,
21
22
  } from "@/lib/publication/mountedDiscovery.js";
@@ -119,7 +120,7 @@ export async function GET(context: APIContext): Promise<Response> {
119
120
  lines.push("## More content");
120
121
  for (const entry of mounted) {
121
122
  const desc = oneLine(entry.summary);
122
- lines.push(`- [${oneLine(entry.title, 200) ?? entry.title}](${base}${entry.canonicalPath})${desc ? `: ${desc}` : ""}`);
123
+ lines.push(`- [${oneLine(entry.title, 200) ?? entry.title}](${mountedDiscoveryUrlV1(canonicalBase, entry)})${desc ? `: ${desc}` : ""}`);
123
124
  }
124
125
  lines.push("");
125
126
  }
@@ -9,6 +9,7 @@ import { compileRouteTierIndexV1 } from "@tot/public-runtime";
9
9
  import { readKv } from "@/lib/runtimeEnv.js";
10
10
  import {
11
11
  declaresMountedSpacesV1,
12
+ mountedDiscoveryUrlV1,
12
13
  readMountedPublicationDiscoveryV1,
13
14
  rootOwnsDiscoveryPathV1,
14
15
  } from "@/lib/publication/mountedDiscovery.js";
@@ -35,7 +36,7 @@ export async function GET(context: APIContext): Promise<Response> {
35
36
  const mounted = await readMountedPublicationDiscoveryV1({ tenant, store: await readKv("TENANT_CACHE"), index });
36
37
  for (const entry of mounted) {
37
38
  if (!entry.surfaces.publicSearch) continue;
38
- entries.push({ canonicalPath: entry.canonicalPath, canonicalUrl: `${base}${entry.canonicalPath}`,
39
+ entries.push({ canonicalPath: entry.canonicalPath, canonicalUrl: mountedDiscoveryUrlV1(canonicalBase, entry),
39
40
  title: entry.title, summary: entry.summary, searchText: entry.searchText });
40
41
  }
41
42
  }
@@ -20,6 +20,7 @@ import { compileRouteTierIndexV1 } from "@tot/public-runtime";
20
20
  import { readKv } from "@/lib/runtimeEnv.js";
21
21
  import {
22
22
  declaresMountedSpacesV1,
23
+ mountedDiscoveryUrlV1,
23
24
  readMountedPublicationDiscoveryV1,
24
25
  rootOwnsDiscoveryPathV1,
25
26
  } from "@/lib/publication/mountedDiscovery.js";
@@ -137,7 +138,7 @@ export async function GET(context: APIContext): Promise<Response> {
137
138
  const mounted = await readMountedPublicationDiscoveryV1({ tenant, store: await readKv("TENANT_CACHE"), index });
138
139
  for (const entry of mounted) {
139
140
  if (!entry.surfaces.sitemap) continue;
140
- const loc = `${base}${entry.canonicalPath}`;
141
+ const loc = mountedDiscoveryUrlV1(canonicalBase, entry);
141
142
  if (listed.has(loc)) continue;
142
143
  listed.add(loc);
143
144
  const lastmod = entry.updatedAt ?? entry.publishedAt;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tokenoftrust/storefront-runner",
3
- "version": "2.4.20",
3
+ "version": "2.4.21",
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",
@@ -27,6 +27,15 @@ export const PUBLICATION_MOUNT_ENTRY_VERSION = 1 as const;
27
27
  export const PUBLICATION_SPACE_PATH_CASE_POLICY = "sensitive" as const;
28
28
  export const PUBLICATION_SPACE_UNICODE_POLICY = "nfc" as const;
29
29
 
30
+ /**
31
+ * Which renderer serves a discovery entry's route, so every discovery surface lists the canonical
32
+ * that page declares: `raw-html` pages (a mounted space's home and its pages-html) carry the
33
+ * raw-page trailing slash; `page`, `post` and `archive` routes are listed as they are.
34
+ */
35
+ export type PublicationDiscoveryEntryKindV1 = "raw-html" | "page" | "post" | "archive";
36
+ export const PUBLICATION_DISCOVERY_ENTRY_KINDS_V1: readonly PublicationDiscoveryEntryKindV1[] =
37
+ ["raw-html", "page", "post", "archive"];
38
+
30
39
  /** Static public-discovery outputs generated from exact live publication versions. */
31
40
  export const PUBLICATION_DISCOVERY_OUTPUT_PATHS_V1 = [
32
41
  "/feed.json",