@tokenoftrust/storefront-runner 2.1.1 → 2.1.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.
|
@@ -273,6 +273,24 @@ export function isBypassPrivilegedPath(pathname: string): boolean {
|
|
|
273
273
|
return false;
|
|
274
274
|
}
|
|
275
275
|
|
|
276
|
+
/**
|
|
277
|
+
* Control surfaces a withheld visitor is sent straight to sign-in for, instead of the
|
|
278
|
+
* "Coming soon" holding page: admin and the cockpit (with its `/dev` alias), in both the
|
|
279
|
+
* bare and the tenant-prefixed form. The holding page's audience is a public browser of
|
|
280
|
+
* a gated STOREFRONT; a developer or merchant heading for a control surface needs the
|
|
281
|
+
* sign-in prompt, not an ambiguous 200 that reads as "this store isn't ready." `/api/`
|
|
282
|
+
* is excluded — API callers need a status, not a redirect.
|
|
283
|
+
*/
|
|
284
|
+
export function isSignInRedirectPath(pathname: string): boolean {
|
|
285
|
+
// Bare `/api/...` would otherwise read as tenant `api` + `/dev`.
|
|
286
|
+
if (pathname === "/api" || pathname.startsWith("/api/")) return false;
|
|
287
|
+
if (isAdminPath(pathname)) return true;
|
|
288
|
+
if (pathname === "/cockpit" || pathname.startsWith("/cockpit/")) return true;
|
|
289
|
+
if (/^\/[^/]+\/cockpit(?:\/|$)/.test(pathname)) return true;
|
|
290
|
+
if (pathname === "/dev" || pathname.startsWith("/dev/")) return true;
|
|
291
|
+
return /^\/[^/]+\/dev(?:\/|$)/.test(pathname);
|
|
292
|
+
}
|
|
293
|
+
|
|
276
294
|
export type LoginGateDecision =
|
|
277
295
|
| { action: "pass" }
|
|
278
296
|
| { action: "redirect"; location: string };
|
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
evaluateLoginGate,
|
|
26
26
|
isAuthPath,
|
|
27
27
|
isAdminPath,
|
|
28
|
+
isSignInRedirectPath,
|
|
28
29
|
sessionAdmitsHost,
|
|
29
30
|
sessionHostCapability,
|
|
30
31
|
type GateMode,
|
|
@@ -171,15 +172,16 @@ export async function serveControlPlane(input: ControlPlaneInput): Promise<Respo
|
|
|
171
172
|
previewTokenValid,
|
|
172
173
|
});
|
|
173
174
|
if (decision.action === "redirect") {
|
|
174
|
-
//
|
|
175
|
-
//
|
|
176
|
-
//
|
|
175
|
+
// Admin and the cockpit hard-redirect to sign-in rather than rendering the
|
|
176
|
+
// merchant-facing "Coming soon" holding page: an unauthenticated visitor to a
|
|
177
|
+
// control surface must land on the sign-in prompt, never an ambiguous 200 that
|
|
177
178
|
// reads as "this store isn't ready." The holding page's whole audience is a
|
|
178
|
-
// public browser of a gated STOREFRONT; it is the wrong signal for /admin
|
|
179
|
-
// gate already decided to withhold — this only changes
|
|
180
|
-
// page); it never weakens the gate. `decision.location`
|
|
181
|
-
// `?next=` so the
|
|
182
|
-
|
|
179
|
+
// public browser of a gated STOREFRONT; it is the wrong signal for /admin and
|
|
180
|
+
// `/<tenant>/cockpit`. The gate already decided to withhold — this only changes
|
|
181
|
+
// HOW (303 vs holding page); it never weakens the gate. `decision.location`
|
|
182
|
+
// already carries `?next=` so the visitor returns to exactly where they were
|
|
183
|
+
// headed.
|
|
184
|
+
if (isSignInRedirectPath(url.pathname)) {
|
|
183
185
|
return context.redirect(decision.location, 303);
|
|
184
186
|
}
|
|
185
187
|
// Withhold content but offer sign-in (carrying the intended destination).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tokenoftrust/storefront-runner",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.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",
|