@tokenoftrust/storefront-runner 2.3.0 → 2.3.2
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.
- package/apps/storefront/src/config/devTenantSeed.ts +5 -2
- package/apps/storefront/src/lib/checkoutCommerce.ts +26 -3
- package/apps/storefront/src/lib/dashboard/delegateGate.ts +1 -1
- package/apps/storefront/src/lib/shared/capability.ts +12 -0
- package/package.json +1 -1
- package/packages/public-runtime/src/checkout.ts +13 -0
- package/apps/storefront/src/lib/shared/addToRelease.ts +0 -32
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
* tenancy-resolver-fence — the concrete registry stays behind the config boundary.
|
|
27
27
|
*/
|
|
28
28
|
import type { DeepPartial, TenantConfig, ThemeTokens } from "@tot/public-runtime";
|
|
29
|
+
import { SHARED_DEMO_CHECKOUT } from "@tot/public-runtime";
|
|
29
30
|
import { rootPublicationSpaceConfig } from "./publicationSpaceConfig";
|
|
30
31
|
import { loadTenantAnalyticsDeclarations } from "@/lib/integration/tenantAnalyticsDeclarations";
|
|
31
32
|
|
|
@@ -94,12 +95,14 @@ export function synthesizeDevTenant(
|
|
|
94
95
|
...(euUkVisitors ? { euUkVisitors } : {}),
|
|
95
96
|
};
|
|
96
97
|
// Cart wires to the shared ToT demo checkout store (test mode, no secret), the
|
|
97
|
-
// same as the bundled demo tenants
|
|
98
|
+
// same as the bundled demo tenants — and the SAME constant the hosted QA/test
|
|
99
|
+
// tier's demo-checkout fallback reuses (checkoutCommerce.ts), so both surfaces
|
|
100
|
+
// stay wired to one definition. A marketing tenant never resolves it (the
|
|
98
101
|
// render chain gates on features.catalog); a commerce one gets its cart
|
|
99
102
|
// affordance and /cart on localhost whether or not it has catalog files yet.
|
|
100
103
|
return {
|
|
101
104
|
...base,
|
|
102
|
-
commerce: { checkout:
|
|
105
|
+
commerce: { checkout: SHARED_DEMO_CHECKOUT },
|
|
103
106
|
};
|
|
104
107
|
}
|
|
105
108
|
|
|
@@ -11,19 +11,31 @@
|
|
|
11
11
|
* - `FOXY_CART_SECRET` is the cart-validation secret used only in `signed`
|
|
12
12
|
* mode; the `unsigned-demo` mode never reads it (validation is OFF), which
|
|
13
13
|
* is what lets a developer run the whole cart locally with zero secrets.
|
|
14
|
+
*
|
|
15
|
+
* `COMMERCE_DEMO_CHECKOUT_TIER` gates a FALLBACK for a commerce tenant that has
|
|
16
|
+
* no `commerce.checkout` of its own (e.g. a staff-provisioned store —
|
|
17
|
+
* buildStaffTenantConfig projects a minimal record with none). Declared-tier
|
|
18
|
+
* config, not a tenant check: "test" reuses the exact SHARED_DEMO_CHECKOUT the
|
|
19
|
+
* local dev loop wires (synthesizeDevTenant), so a staff-provisioned store's
|
|
20
|
+
* cart renders on hosted QA preview the same as it does under `tot dev`. Any
|
|
21
|
+
* other value — including unset, the PRODUCTION default — fails CLOSED to no
|
|
22
|
+
* cart: an unpaid production store's preview IS its public site, so a demo
|
|
23
|
+
* checkout must never appear there. A tenant's own declared checkout always
|
|
24
|
+
* wins; this only fills in when `commerce.checkout` is absent.
|
|
14
25
|
*/
|
|
15
26
|
import type { TenantConfig, ResolvedManagedCheckout } from "@tot/public-runtime";
|
|
16
|
-
import { resolveManagedCheckout } from "@tot/public-runtime";
|
|
27
|
+
import { resolveManagedCheckout, SHARED_DEMO_CHECKOUT } from "@tot/public-runtime";
|
|
17
28
|
import { readEnv } from "@/lib/runtimeEnv";
|
|
18
29
|
|
|
19
30
|
/**
|
|
20
31
|
* Resolve the effective checkout facts for a tenant, or null when the tenant has
|
|
21
|
-
* no store configured
|
|
32
|
+
* no store configured (its own, or the QA/test-tier demo fallback). Applies the
|
|
33
|
+
* checkout env overrides.
|
|
22
34
|
*/
|
|
23
35
|
export async function resolveTenantCommerce(
|
|
24
36
|
tenant: TenantConfig,
|
|
25
37
|
): Promise<ResolvedManagedCheckout | null> {
|
|
26
|
-
const checkout = tenant.commerce?.checkout;
|
|
38
|
+
const checkout = tenant.commerce?.checkout ?? (await demoCheckoutFallback());
|
|
27
39
|
if (!checkout) return null;
|
|
28
40
|
// Per-environment overrides so the SAME tenant can point at different stores /
|
|
29
41
|
// checkout hosts by env: FOXY_STORE_SUBDOMAIN picks the checkout store;
|
|
@@ -38,6 +50,17 @@ export async function resolveTenantCommerce(
|
|
|
38
50
|
return resolveManagedCheckout({ ...checkout, storeSubDomain, storeDomain });
|
|
39
51
|
}
|
|
40
52
|
|
|
53
|
+
/**
|
|
54
|
+
* The QA/test-tier-only demo-checkout fallback, or undefined when this
|
|
55
|
+
* environment hasn't declared itself eligible. Fails closed: only the literal
|
|
56
|
+
* value "test" enables it, so an unset var (today's only production-shaped
|
|
57
|
+
* state — there is no `[env.production]` block yet) never does.
|
|
58
|
+
*/
|
|
59
|
+
async function demoCheckoutFallback() {
|
|
60
|
+
const tier = await readEnv("COMMERCE_DEMO_CHECKOUT_TIER");
|
|
61
|
+
return tier === "test" ? SHARED_DEMO_CHECKOUT : undefined;
|
|
62
|
+
}
|
|
63
|
+
|
|
41
64
|
/**
|
|
42
65
|
* The cart-validation secret for signed mode. Returns undefined in
|
|
43
66
|
* `unsigned-demo` mode (never needed) or when unset. A signed-mode tenant with
|
|
@@ -36,7 +36,7 @@ export type DelegateSection = { mode: "unpaid"; role: null; explanation: string
|
|
|
36
36
|
/**
|
|
37
37
|
* Resolve the whole delegate section. Before a store is paid there is no live
|
|
38
38
|
* site and preview-access developers can already add changes to the release
|
|
39
|
-
* (`
|
|
39
|
+
* (the `merge-to-preview` admission class, lib/pipeline/admission.ts), so delegation has nothing to grant: every viewer, the
|
|
40
40
|
* owner included, gets {@link UNPAID_DELEGATION_NOTE}. A paid store resolves
|
|
41
41
|
* {@link resolveDelegateGate} unchanged.
|
|
42
42
|
*/
|
|
@@ -16,6 +16,18 @@
|
|
|
16
16
|
/** Access level the acting operator holds. */
|
|
17
17
|
export type Capability = "preview-access" | "ship-on-behalf";
|
|
18
18
|
|
|
19
|
+
const CAPABILITIES: readonly Capability[] = ["preview-access", "ship-on-behalf"];
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* The console operator's capability from env + request. Pure decision over the two inputs;
|
|
23
|
+
* fail-closed to `preview-access`. Only call AFTER the operator Bearer has been authenticated (so
|
|
24
|
+
* the header is trusted).
|
|
25
|
+
*/
|
|
26
|
+
export function decideCapability(configured: string | undefined, requested: string | null): Capability {
|
|
27
|
+
const raw = (configured ?? requested ?? "").trim();
|
|
28
|
+
return CAPABILITIES.includes(raw as Capability) ? (raw as Capability) : "preview-access";
|
|
29
|
+
}
|
|
30
|
+
|
|
19
31
|
/** Complete tenant-role vocabulary emitted by verified identity assertions. */
|
|
20
32
|
export const TENANT_ROLES = ["owner", "admin", "member"] as const;
|
|
21
33
|
export type TenantRole = (typeof TENANT_ROLES)[number];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tokenoftrust/storefront-runner",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.2",
|
|
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",
|
|
@@ -59,6 +59,19 @@ export interface ManagedCheckoutConfig {
|
|
|
59
59
|
cartDrawerCss?: string;
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
+
/**
|
|
63
|
+
* The ONE shared ToT-owned demo checkout store (test mode, cart validation
|
|
64
|
+
* OFF, no secret). The local dev loop (`synthesizeDevTenant`) wires every
|
|
65
|
+
* local commerce checkout to this exact config; the hosted QA/test tier's
|
|
66
|
+
* demo-checkout fallback (`resolveTenantCommerce`) reuses this same constant
|
|
67
|
+
* rather than a second copy of the literal, so "the same as `tot dev`" stays
|
|
68
|
+
* true by construction instead of by two authors agreeing.
|
|
69
|
+
*/
|
|
70
|
+
export const SHARED_DEMO_CHECKOUT: ManagedCheckoutConfig = {
|
|
71
|
+
storeSubDomain: "tot-preview",
|
|
72
|
+
mode: "unsigned-demo",
|
|
73
|
+
};
|
|
74
|
+
|
|
62
75
|
/** Resolved, request-scoped commerce facts stashed on `Astro.locals`. */
|
|
63
76
|
export interface ResolvedManagedCheckout extends ManagedCheckoutConfig {
|
|
64
77
|
/** `https://<storeDomain>` — the loader + cart origin (for CSP + links). */
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Who may Add to release — integrate an accepted change into the store's
|
|
3
|
-
* `preview` release. Pure; shared by the integrate/resolve admission, the
|
|
4
|
-
* Publish console, and the Team page so all three answer one question.
|
|
5
|
-
*/
|
|
6
|
-
import { storefrontModeAllowsGoLive } from "@tot/public-runtime";
|
|
7
|
-
import { isOwnerCapability, type Capability } from "./capability";
|
|
8
|
-
|
|
9
|
-
/** Pure inputs to the Add-to-release decision. */
|
|
10
|
-
export interface AddToReleaseInput {
|
|
11
|
-
/** The viewer's standing over THIS tenant (owner/admin/member), if any. */
|
|
12
|
-
capability: string | null | undefined;
|
|
13
|
-
/** The viewer's live ship grant over this tenant. */
|
|
14
|
-
shipGrant: Capability;
|
|
15
|
-
/** True only when the viewer's access is bound to THIS tenant. */
|
|
16
|
-
tenantScoped: boolean;
|
|
17
|
-
/** The tenant's storefront mode — `"enabled"` means the store is paid. */
|
|
18
|
-
storefrontMode: string | null | undefined;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* May this viewer add an accepted change to the store's `preview` release?
|
|
23
|
-
*
|
|
24
|
-
* Owner/admin standing or a ship-on-behalf grant always may. Before a store is
|
|
25
|
-
* paid there is no live site, so preview IS the site: a developer whose access is
|
|
26
|
-
* scoped to this tenant may add without a ship-on-behalf grant. Once the store is
|
|
27
|
-
* paid, the preview/live split and ship-on-behalf delegation apply.
|
|
28
|
-
*/
|
|
29
|
-
export function canAddToRelease(input: AddToReleaseInput): boolean {
|
|
30
|
-
if (isOwnerCapability(input.capability) || input.shipGrant === "ship-on-behalf") return true;
|
|
31
|
-
return input.tenantScoped && !storefrontModeAllowsGoLive(input.storefrontMode);
|
|
32
|
-
}
|