@tokenoftrust/storefront-runner 3.3.1 → 3.3.3

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.
@@ -98,7 +98,7 @@ export class StaticTenantResolver implements TenantResolver {
98
98
 
99
99
  export const tenantResolver: TenantResolver = new StaticTenantResolver();
100
100
 
101
- const COMPOSED_PLATFORM_FIELDS = ["access", "pathPrefixTenants", "capabilities"] as const;
101
+ const COMPOSED_PLATFORM_FIELDS = ["access", "pathPrefixTenants", "capabilities", "siteType", "features"] as const;
102
102
 
103
103
  /** Same contract as the real registry's withPlatformPolicy — kept in sync by hand. */
104
104
  export function withPlatformPolicy(record: TenantConfig): TenantConfig {
@@ -100,10 +100,7 @@ export function sessionAdmitsHost(
100
100
  return sessionHostCapability(record, hostResource, nowSeconds) !== null;
101
101
  }
102
102
 
103
- /** Parse `DEMO_GATE_MODE` (default "password"). */
104
- export function parseGateMode(raw: string | null | undefined): GateMode {
105
- return (raw ?? "").trim().toLowerCase() === "login" ? "login" : "password";
106
- }
103
+ export { parseGateMode } from "../shared/gateMode.js";
107
104
 
108
105
  /**
109
106
  * Paths that MUST stay reachable without a session, or the visitor could never
@@ -0,0 +1,4 @@
1
+ /** Parse `DEMO_GATE_MODE` (default "password"). Dependency-free so plain-node scripts can load it. */
2
+ export function parseGateMode(raw: string | null | undefined): "password" | "login" {
3
+ return (raw ?? "").trim().toLowerCase() === "login" ? "login" : "password";
4
+ }
@@ -0,0 +1,41 @@
1
+ /**
2
+ * The document's server response time for the evidence panel: the `total` the Worker stamps in
3
+ * `Server-Timing` (`lib/observability/shared/serverTiming.ts`) next to the time this self-fetch
4
+ * waited for the response headers (TTFB as seen from the Worker). Advisory — never gates promotion.
5
+ */
6
+
7
+ export interface ServerResponseTime {
8
+ /** `total;dur` from the document's `Server-Timing`, or null when the header is absent. */
9
+ serverTotalMs: number | null;
10
+ /** Wall time until the response headers arrived. */
11
+ ttfbMs: number;
12
+ /** The isolate was serving its first request (`isolate;desc="cold"`). */
13
+ cold: boolean;
14
+ }
15
+
16
+ /** Pull `total;dur` and the cold marker out of a `Server-Timing` header value. */
17
+ export function parseServerTiming(header: string | null | undefined): Pick<ServerResponseTime, "serverTotalMs" | "cold"> {
18
+ if (!header) return { serverTotalMs: null, cold: false };
19
+ const entries = header.split(",").map((e) => e.trim());
20
+ const total = entries.find((e) => /^total(;|$)/.test(e))?.match(/;\s*dur=([0-9.]+)/);
21
+ return {
22
+ serverTotalMs: total ? Number(total[1]) : null,
23
+ cold: entries.some((e) => /^isolate;\s*desc="cold"$/.test(e)),
24
+ };
25
+ }
26
+
27
+ /** Self-fetch `url` and report its server response time; null when the fetch fails. */
28
+ export async function measureServerResponseTime(
29
+ url: URL,
30
+ now: () => number = () => performance.now(),
31
+ ): Promise<ServerResponseTime | null> {
32
+ try {
33
+ const started = now();
34
+ const res = await fetch(url, { redirect: "manual" });
35
+ const ttfbMs = now() - started;
36
+ await res.body?.cancel();
37
+ return { ...parseServerTiming(res.headers.get("server-timing")), ttfbMs: Math.round(ttfbMs) };
38
+ } catch {
39
+ return null;
40
+ }
41
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tokenoftrust/storefront-runner",
3
- "version": "3.3.1",
3
+ "version": "3.3.3",
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",