@tokenoftrust/storefront-runner 2.2.119 → 2.2.121
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.
|
@@ -331,6 +331,8 @@ export interface LoginGateInput {
|
|
|
331
331
|
* cockpit, /api) still require a real session.
|
|
332
332
|
*/
|
|
333
333
|
previewTokenValid?: boolean;
|
|
334
|
+
/** A verified, tenant-bound candidate content pin admits public content only. */
|
|
335
|
+
candidatePinValid?: boolean;
|
|
334
336
|
}
|
|
335
337
|
|
|
336
338
|
/**
|
|
@@ -355,10 +357,12 @@ export function evaluateLoginGate(input: LoginGateInput): LoginGateDecision {
|
|
|
355
357
|
// public content only. NEVER for admin/cockpit/api — that guard lives here (not
|
|
356
358
|
// just in middleware) so /admin stays gated even if the flag is set upstream.
|
|
357
359
|
if (input.qaBypass && !isBypassPrivilegedPath(input.pathname)) return { action: "pass" };
|
|
358
|
-
//
|
|
359
|
-
//
|
|
360
|
-
|
|
361
|
-
|
|
360
|
+
// Signed, tenant-bound preview grants admit public content only. Admin,
|
|
361
|
+
// cockpit, and API routes still require a session.
|
|
362
|
+
if (
|
|
363
|
+
(input.previewTokenValid || input.candidatePinValid) &&
|
|
364
|
+
!isBypassPrivilegedPath(input.pathname)
|
|
365
|
+
) {
|
|
362
366
|
return { action: "pass" };
|
|
363
367
|
}
|
|
364
368
|
if (input.hasValidSession) return { action: "pass" };
|
|
@@ -35,6 +35,7 @@ import { resolveAdminTenantMode } from "@/lib/adminTenantEnvelope";
|
|
|
35
35
|
import { gatedHoldingResponse } from "@/lib/auth/gatePage";
|
|
36
36
|
import { readSession, KvSessionStore, SESSION_COOKIE } from "@/lib/auth/session";
|
|
37
37
|
import { runRenderChain } from "./renderChain.js";
|
|
38
|
+
import { resolveCandidateContentPin } from "./candidatePin.js";
|
|
38
39
|
import type { InternalContentGrant } from "@/lib/auth/internalContentAuthority";
|
|
39
40
|
|
|
40
41
|
export interface ControlPlaneInput {
|
|
@@ -63,6 +64,11 @@ export interface ControlPlaneInput {
|
|
|
63
64
|
export async function serveControlPlane(input: ControlPlaneInput): Promise<Response> {
|
|
64
65
|
const { context, next, host, url, tenant, basePath, renderPath, cache, kv } = input;
|
|
65
66
|
const { request, locals } = context;
|
|
67
|
+
// A pinned route rewrite arrives here without the outer preview route's
|
|
68
|
+
// session. Verify its tenant-bound grant before the host login gate runs.
|
|
69
|
+
const candidatePin = input.hostLoginGated
|
|
70
|
+
? await resolveCandidateContentPin(url, tenant.tenant_id)
|
|
71
|
+
: null;
|
|
66
72
|
|
|
67
73
|
// Login-gate enforcement (DEMO_GATE_MODE="login"): runs before the render so a
|
|
68
74
|
// gated page is never served to an unauthenticated viewer. A tenant that
|
|
@@ -170,6 +176,7 @@ export async function serveControlPlane(input: ControlPlaneInput): Promise<Respo
|
|
|
170
176
|
tenantExempt,
|
|
171
177
|
qaBypass,
|
|
172
178
|
previewTokenValid,
|
|
179
|
+
candidatePinValid: !!candidatePin,
|
|
173
180
|
});
|
|
174
181
|
if (decision.action === "redirect") {
|
|
175
182
|
// Admin and the cockpit hard-redirect to sign-in rather than rendering the
|
|
@@ -261,6 +268,7 @@ export async function serveControlPlane(input: ControlPlaneInput): Promise<Respo
|
|
|
261
268
|
publicationRequestPath: input.publicationRequestPath,
|
|
262
269
|
publicationRoute: input.publicationRoute,
|
|
263
270
|
publicationBucket: input.publicationBucket,
|
|
271
|
+
verifiedCandidatePin: candidatePin ?? undefined,
|
|
264
272
|
managedIntegrationDeclarations,
|
|
265
273
|
readTenantConsentSnapshot: () => readSavedConsentSnapshot(tenant.tenant_id),
|
|
266
274
|
// The D1 catalog serving projection, for a tenant that declares
|
|
@@ -14,7 +14,7 @@ import { mergeTheme, themeToCssVars } from "@/themes/schema";
|
|
|
14
14
|
import { createToTClient } from "@/lib/tot/ToTClient";
|
|
15
15
|
import { readEnv, readR2 } from "@/lib/runtimeEnv";
|
|
16
16
|
import { tryServeStaticBundle } from "./staticBundle.js";
|
|
17
|
-
import { resolveCandidateContentPin } from "./candidatePin.js";
|
|
17
|
+
import { resolveCandidateContentPin, type CandidateContentPin } from "./candidatePin.js";
|
|
18
18
|
import { createContentProvider, DevDraftContentProvider } from "@/lib/storyblok/provider";
|
|
19
19
|
import { bindPublicationSpaceContentProviderV1 } from "@/lib/publication/contentProvider.js";
|
|
20
20
|
import { resolvePublicationRuntimeSourceV1 } from "@/lib/publication/runtimeSource.js";
|
|
@@ -144,6 +144,8 @@ export interface RenderChainInput {
|
|
|
144
144
|
readCatalogD1: (() => Promise<Parameters<typeof createToTClient>[1]>) | null;
|
|
145
145
|
/** Exact per-request grant for an F2-selected internal publication space. */
|
|
146
146
|
internalContentGrant?: InternalContentGrant;
|
|
147
|
+
/** Pin already verified for this tenant by the control-plane login gate. */
|
|
148
|
+
verifiedCandidatePin?: CandidateContentPin;
|
|
147
149
|
}
|
|
148
150
|
|
|
149
151
|
/** Materialize-only response header: the tenant's declared origins, comma-separated. */
|
|
@@ -180,7 +182,8 @@ export async function runRenderChain(input: RenderChainInput): Promise<Response>
|
|
|
180
182
|
// pin can only ever name its own version; a mismatched/expired/absent token
|
|
181
183
|
// falls through to the normal channel-resolved read below, same fail-closed
|
|
182
184
|
// posture as the `__preview` token.
|
|
183
|
-
const candidatePin =
|
|
185
|
+
const candidatePin = input.verifiedCandidatePin ??
|
|
186
|
+
await resolveCandidateContentPin(url, tenantRecord.tenant_id);
|
|
184
187
|
// Per-developer AI-edit draft: the signed
|
|
185
188
|
// tot_dev_draft cookie's mere PRESENCE opts the request out of the shared page
|
|
186
189
|
// cache below (a draft view must never be cached publicly); it's verified —
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tokenoftrust/storefront-runner",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.121",
|
|
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",
|