@tokenoftrust/storefront-runner 2.2.126 → 2.3.1
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/package.json +3 -1
- package/apps/storefront/public/shared/commerce-chrome.css +57 -15
- package/apps/storefront/public/shared/commerce-marketing.css +7 -7
- package/apps/storefront/src/components/Badge.astro +1 -1
- package/apps/storefront/src/components/Breadcrumbs.astro +8 -3
- package/apps/storefront/src/components/Section.astro +4 -1
- package/apps/storefront/src/components/Seo.astro +7 -5
- package/apps/storefront/src/components/blog/BlogIndexView.astro +22 -13
- package/apps/storefront/src/components/blog/ShareRow.astro +43 -0
- package/apps/storefront/src/components/chrome/AnnouncementBar.astro +1 -1
- package/apps/storefront/src/components/chrome/NavDropdown.astro +7 -7
- package/apps/storefront/src/components/chrome/SiteFooter.astro +17 -0
- package/apps/storefront/src/components/chrome/SiteHeader.astro +5 -5
- package/apps/storefront/src/components/commerce/TagFilterCloud.astro +1 -1
- package/apps/storefront/src/components/compliance/NicotineWarning.astro +12 -22
- package/apps/storefront/src/components/compliance/PactActNotice.astro +9 -10
- package/apps/storefront/src/components/content/ProseSections.astro +2 -2
- package/apps/storefront/src/components/home/Hero.astro +34 -12
- package/apps/storefront/src/components/islands/IsolatedAgeGate.tsx +39 -5
- package/apps/storefront/src/components/islands/VariantSelector.tsx +3 -3
- package/apps/storefront/src/components/marketing/CardGrid.astro +1 -1
- package/apps/storefront/src/components/marketing/CodeSample.astro +1 -1
- package/apps/storefront/src/components/marketing/CtaBand.astro +1 -1
- package/apps/storefront/src/components/marketing/Faq.astro +1 -1
- package/apps/storefront/src/components/marketing/Integrations.astro +1 -1
- package/apps/storefront/src/components/marketing/MarketingCtas.astro +1 -1
- package/apps/storefront/src/components/marketing/MarketingHero.astro +1 -1
- package/apps/storefront/src/components/marketing/ProofStrip.astro +1 -1
- package/apps/storefront/src/components/marketing/SplitCompare.astro +1 -1
- package/apps/storefront/src/components/marketing/Steps.astro +1 -1
- package/apps/storefront/src/components/marketing/Testimonials.astro +2 -2
- package/apps/storefront/src/components/marketing/TrustBar.astro +1 -1
- package/apps/storefront/src/components/membership/TierComparisonTable.astro +1 -1
- package/apps/storefront/src/components/plp/ActiveFilters.astro +1 -1
- package/apps/storefront/src/components/plp/FacetSidebar.astro +4 -4
- package/apps/storefront/src/components/plp/Pagination.astro +1 -1
- package/apps/storefront/src/components/plp/SortSelect.astro +1 -1
- package/apps/storefront/src/components/style-guide/StyleGuideNav.astro +18 -3
- package/apps/storefront/src/components/the-build/TheBuildIndexView.astro +9 -5
- package/apps/storefront/src/config/devTenantSeed.ts +23 -34
- package/apps/storefront/src/config/resolver.ts +0 -38
- package/apps/storefront/src/layouts/Layout.astro +8 -1
- package/apps/storefront/src/lib/assets/preview-version-cookie.ts +52 -5
- package/apps/storefront/src/lib/blog/pagination.ts +20 -10
- package/apps/storefront/src/lib/blog/presentation.ts +94 -0
- package/apps/storefront/src/lib/blog/rss.ts +1 -1
- package/apps/storefront/src/lib/blog/types.ts +24 -7
- package/apps/storefront/src/lib/breadcrumbs.ts +25 -0
- package/apps/storefront/src/lib/checkoutCommerce.ts +26 -3
- package/apps/storefront/src/lib/chrome/model.ts +4 -0
- package/apps/storefront/src/lib/cloudflare-workers.d.ts +53 -0
- package/apps/storefront/src/lib/compliance/rawComplianceNotices.ts +38 -18
- package/apps/storefront/src/lib/dashboard/delegateGate.ts +28 -0
- package/apps/storefront/src/lib/homeVisualParity.ts +8 -5
- package/apps/storefront/src/lib/jsonld.ts +5 -5
- package/apps/storefront/src/lib/pinnedRouteRewriteBoundary.ts +20 -2
- package/apps/storefront/src/lib/rawChrome.ts +74 -12
- package/apps/storefront/src/lib/runtimeEnv.ts +1 -1
- package/apps/storefront/src/lib/seo/documentTitle.ts +19 -0
- package/apps/storefront/src/lib/shared/addToRelease.ts +32 -0
- package/apps/storefront/src/lib/storyblok/content-model.ts +3 -0
- package/apps/storefront/src/lib/styleGuideThemes.ts +20 -22
- package/apps/storefront/src/pages/[...slug].astro +13 -8
- package/apps/storefront/src/pages/blog/[slug].astro +56 -24
- package/apps/storefront/src/pages/blog/author/[author].astro +17 -9
- package/apps/storefront/src/pages/blog/category/[category].astro +18 -10
- package/apps/storefront/src/pages/blog/index.astro +2 -0
- package/apps/storefront/src/pages/blog/page/[n].astro +2 -0
- package/apps/storefront/src/pages/blog/tag/[tag].astro +18 -10
- package/apps/storefront/src/pages/collections/[handle].astro +5 -4
- package/apps/storefront/src/pages/collections/index.astro +4 -3
- package/apps/storefront/src/pages/index.astro +34 -27
- package/apps/storefront/src/pages/products/[handle].astro +5 -4
- package/apps/storefront/src/pages/saved.astro +4 -3
- package/apps/storefront/src/pages/search.astro +4 -3
- package/apps/storefront/src/pages/style-guide/[tenant]/[theme].astro +129 -118
- package/apps/storefront/src/pages/style-guide/[tenant]/chrome/[theme].astro +19 -15
- package/apps/storefront/src/pages/style-guide/[tenant]/guide/[theme].astro +23 -27
- package/apps/storefront/src/pages/style-guide/[tenant]/index.astro +7 -14
- package/apps/storefront/src/pages/style-guide/index.astro +6 -5
- package/apps/storefront/src/pages/tenants/[id]/[...path].ts +32 -7
- package/apps/storefront/src/pages/the-build/[slug].astro +44 -20
- package/apps/storefront/src/pages/the-build/index.astro +2 -0
- package/apps/storefront/src/pages/the-build/page/[n].astro +2 -0
- package/apps/storefront/src/styles/admin.css +47 -0
- package/apps/storefront/src/styles/global.css +104 -56
- package/apps/storefront/src/themes/derivedTokens.ts +34 -0
- package/apps/storefront/src/themes/schema.ts +6 -0
- package/apps/storefront/test/pipeline/harness.ts +164 -0
- package/apps/storefront/test/pipeline/intake-worker.mjs +14 -0
- package/apps/storefront/test/pipeline/pipeline-host.ts +77 -0
- package/apps/storefront/test/pipeline/synthetic-job.ts +156 -0
- package/apps/storefront/vitest.workers.config.cts +67 -0
- package/docs/widget-library-guide.md +1496 -0
- package/package.json +1 -1
- package/packages/cli/src/declared-config.mjs +400 -5
- package/packages/public-runtime/package.json +1 -0
- package/packages/public-runtime/src/checkout.ts +13 -0
- package/packages/public-runtime/src/chrome.ts +93 -2
- package/packages/public-runtime/src/compliance-coherence.d.mts +17 -0
- package/packages/public-runtime/src/compliance-coherence.mjs +84 -0
- package/packages/public-runtime/src/declared-tenant-config.d.mts +1 -1
- package/packages/public-runtime/src/declared-tenant-config.mjs +6 -2
- package/packages/public-runtime/src/extension-contract-values.d.mts +4 -1
- package/packages/public-runtime/src/extension-contract-values.mjs +14 -1
- package/packages/public-runtime/src/extension-contract.ts +2 -0
- package/packages/public-runtime/src/tenant.ts +48 -4
- package/pnpm-lock.runner.yaml +469 -0
- package/scripts/tenant/validate.mjs +27 -1
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compliance COHERENCE: what a regulated tenant's declared `compliance` block must hold
|
|
3
|
+
* together before its preview can pass the `age_gate`, `excise` and `jurisdiction`
|
|
4
|
+
* evidence checks. Every rule here reads declared config only, so it is checkable from
|
|
5
|
+
* a checkout with no platform state:
|
|
6
|
+
*
|
|
7
|
+
* - the hosted reconcile grades these checks with it
|
|
8
|
+
* (packages/private-controlplane/src/evidence-producer.ts);
|
|
9
|
+
* - `tot validate` reports the same failures locally, from the CLI's own copy
|
|
10
|
+
* (packages/cli/src/declared-config.mjs), pinned to this one by
|
|
11
|
+
* packages/cli/test/declared-config-parity.test.mjs.
|
|
12
|
+
*
|
|
13
|
+
* Each failure names the exact `compliance.*` field that resolves it, in both the
|
|
14
|
+
* detail and the hint, so the first failure a developer sees is actionable.
|
|
15
|
+
*
|
|
16
|
+
* Plain JS on purpose (same reason as declared-tenant-config.mjs): plain-`node`
|
|
17
|
+
* tooling and the CLI's parity test read it alongside the TypeScript runtime.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/** The evidence checks this module grades, in report order. */
|
|
21
|
+
export const COHERENCE_CHECK_IDS = Object.freeze(["age_gate", "excise", "jurisdiction"]);
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* True when the declared compliance block marks the tenant regulated (an age minimum
|
|
25
|
+
* or the FDA nicotine warning).
|
|
26
|
+
*
|
|
27
|
+
* @param {Record<string, unknown> | null | undefined} compliance
|
|
28
|
+
*/
|
|
29
|
+
export function isRegulatedCompliance(compliance) {
|
|
30
|
+
const minAge = compliance?.minAge;
|
|
31
|
+
return (typeof minAge === "number" && minAge > 0) || !!compliance?.nicotineWarning;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* True when the declared block renders a shipping/jurisdiction notice: the platform's
|
|
36
|
+
* fixed-wording PACT Act notice (`pactAct: true`) or the tenant's own restriction
|
|
37
|
+
* text (`shippingRestriction`). Both render in the site footer.
|
|
38
|
+
*
|
|
39
|
+
* @param {Record<string, unknown> | null | undefined} compliance
|
|
40
|
+
*/
|
|
41
|
+
export function declaresJurisdictionNotice(compliance) {
|
|
42
|
+
const text = compliance?.shippingRestriction;
|
|
43
|
+
return compliance?.pactAct === true || (typeof text === "string" && text.trim().length > 0);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Every coherence failure in a declared compliance block, keyed by evidence check id.
|
|
48
|
+
* An unregulated block has none. An absent key means that check is coherent.
|
|
49
|
+
*
|
|
50
|
+
* @param {Record<string, unknown> | null | undefined} compliance
|
|
51
|
+
* @returns {Partial<Record<"age_gate" | "excise" | "jurisdiction", { field: string, detail: string, hint: string }>>}
|
|
52
|
+
*/
|
|
53
|
+
export function complianceCoherenceFailures(compliance) {
|
|
54
|
+
/** @type {Partial<Record<"age_gate" | "excise" | "jurisdiction", { field: string, detail: string, hint: string }>>} */
|
|
55
|
+
const out = {};
|
|
56
|
+
if (!isRegulatedCompliance(compliance)) return out;
|
|
57
|
+
const minAge = typeof compliance?.minAge === "number" ? compliance.minAge : null;
|
|
58
|
+
if (minAge == null || minAge < 18) {
|
|
59
|
+
out.age_gate = {
|
|
60
|
+
field: "compliance.minAge",
|
|
61
|
+
detail: "Age-restricted/nicotine products require `compliance.minAge` (18 or higher) — none is set.",
|
|
62
|
+
hint: "Set `compliance.minAge` (18+) in .tot/config.json.",
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
if (compliance?.nicotineWarning && (minAge == null || minAge < 21)) {
|
|
66
|
+
out.excise = {
|
|
67
|
+
field: "compliance.minAge",
|
|
68
|
+
detail: "Nicotine products (`compliance.nicotineWarning`) require `compliance.minAge` of 21 or higher.",
|
|
69
|
+
hint: "Set `compliance.minAge` to 21 in .tot/config.json (nicotine requires 21+, not just 18+).",
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
if (!declaresJurisdictionNotice(compliance)) {
|
|
73
|
+
out.jurisdiction = {
|
|
74
|
+
field: "compliance.pactAct",
|
|
75
|
+
detail:
|
|
76
|
+
"Regulated products require a shipping/jurisdiction notice: set `compliance.pactAct: true` " +
|
|
77
|
+
"or `compliance.shippingRestriction` — neither is set.",
|
|
78
|
+
hint:
|
|
79
|
+
"Set `compliance.pactAct: true` for the platform's PACT Act notice, or " +
|
|
80
|
+
"`compliance.shippingRestriction` to your own restriction text, in .tot/config.json.",
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
return out;
|
|
84
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** Types for the dependency-free declared-tenant-config module (declared-tenant-config.mjs). */
|
|
2
2
|
import type { TenantConfig } from "./tenant.js";
|
|
3
3
|
|
|
4
|
-
export type DeclaredTenantConfigField = "siteType" | "compliance" | "capabilities" | "features" | "embeds";
|
|
4
|
+
export type DeclaredTenantConfigField = "displayName" | "siteType" | "compliance" | "capabilities" | "features" | "embeds";
|
|
5
5
|
export type DeclaredTenantConfig = Partial<Pick<TenantConfig, DeclaredTenantConfigField>>;
|
|
6
6
|
|
|
7
7
|
export const DECLARED_TENANT_CONFIG_FIELDS: readonly DeclaredTenantConfigField[];
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
|
|
20
20
|
/** `.tot/config.json` keys that become TenantConfig fields. */
|
|
21
21
|
export const DECLARED_TENANT_CONFIG_FIELDS = Object.freeze([
|
|
22
|
+
"displayName",
|
|
22
23
|
"siteType",
|
|
23
24
|
"compliance",
|
|
24
25
|
"capabilities",
|
|
@@ -87,7 +88,10 @@ export function declaredTenantConfig(config) {
|
|
|
87
88
|
/** @type {Record<string, unknown>} */
|
|
88
89
|
const out = {};
|
|
89
90
|
if (!isPlainObject(config)) return out;
|
|
90
|
-
const { siteType, compliance, capabilities, features, embeds } = /** @type {Record<string, unknown>} */ (config);
|
|
91
|
+
const { displayName, siteType, compliance, capabilities, features, embeds } = /** @type {Record<string, unknown>} */ (config);
|
|
92
|
+
// The store's name as visitors read it: the `<title>` suffix, og:site_name,
|
|
93
|
+
// Organization JSON-LD, breadcrumbs, the default blog heading, the copyright line.
|
|
94
|
+
if (typeof displayName === "string" && displayName.trim()) out.displayName = displayName.trim();
|
|
91
95
|
if (typeof siteType === "string" && SITE_TYPES.has(siteType)) out.siteType = siteType;
|
|
92
96
|
if (isPlainObject(compliance)) out.compliance = compliance;
|
|
93
97
|
if (isPlainObject(capabilities)) out.capabilities = capabilities;
|
|
@@ -102,7 +106,7 @@ export function isEmptyDeclaredTenantConfig(declared) {
|
|
|
102
106
|
}
|
|
103
107
|
|
|
104
108
|
/**
|
|
105
|
-
* Overlay a declaration onto a resolved tenant. `siteType`
|
|
109
|
+
* Overlay a declaration onto a resolved tenant. `displayName` and `siteType` are replaced; the object
|
|
106
110
|
* fields merge key by key, and `embeds` (catalog slugs) is unioned, so a declaration
|
|
107
111
|
* adds to — and can set individual keys of — what the platform record already
|
|
108
112
|
* carries, but never erases what it omits.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const BLOCK_PALETTE_CURRENT_CONTRACT: "block-palette@
|
|
1
|
+
export declare const BLOCK_PALETTE_CURRENT_CONTRACT: "block-palette@7";
|
|
2
2
|
export declare const BLOCK_PALETTE_SUPPORTED_CONTRACTS: readonly [
|
|
3
3
|
"block-palette@1",
|
|
4
4
|
"block-palette@2",
|
|
@@ -6,6 +6,7 @@ export declare const BLOCK_PALETTE_SUPPORTED_CONTRACTS: readonly [
|
|
|
6
6
|
"block-palette@4",
|
|
7
7
|
"block-palette@5",
|
|
8
8
|
"block-palette@6",
|
|
9
|
+
"block-palette@7",
|
|
9
10
|
];
|
|
10
11
|
export declare const FEATURED_PRODUCT_PRESENTATIONS: readonly ["grid", "carousel"];
|
|
11
12
|
export declare const PROMO_TILE_PRESENTATIONS: readonly [
|
|
@@ -14,6 +15,8 @@ export declare const PROMO_TILE_PRESENTATIONS: readonly [
|
|
|
14
15
|
"editorial-cards",
|
|
15
16
|
"logo-strip",
|
|
16
17
|
];
|
|
18
|
+
export declare const THEME_HEADING_LEVELS: readonly ["hero", "h1", "h2", "h3"];
|
|
19
|
+
export declare function isThemeCssSize(value: unknown): value is string;
|
|
17
20
|
export declare function isSafeRehostedAssetPath(value: unknown): value is string;
|
|
18
21
|
export declare function isSafeRehostedAssetPathForTenant(value: unknown, tenantId: unknown): value is string;
|
|
19
22
|
export declare function isSafeStorefrontHref(value: unknown): value is string;
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* runtime and repository Node tooling. The separately published CLI mirrors
|
|
6
6
|
* these values and pins that mirror with a parity test.
|
|
7
7
|
*/
|
|
8
|
-
export const BLOCK_PALETTE_CURRENT_CONTRACT = "block-palette@
|
|
8
|
+
export const BLOCK_PALETTE_CURRENT_CONTRACT = "block-palette@7";
|
|
9
9
|
|
|
10
10
|
export const BLOCK_PALETTE_SUPPORTED_CONTRACTS = Object.freeze([
|
|
11
11
|
"block-palette@1",
|
|
@@ -13,6 +13,7 @@ export const BLOCK_PALETTE_SUPPORTED_CONTRACTS = Object.freeze([
|
|
|
13
13
|
"block-palette@3",
|
|
14
14
|
"block-palette@4",
|
|
15
15
|
"block-palette@5",
|
|
16
|
+
"block-palette@6",
|
|
16
17
|
BLOCK_PALETTE_CURRENT_CONTRACT,
|
|
17
18
|
]);
|
|
18
19
|
|
|
@@ -25,6 +26,18 @@ export const PROMO_TILE_PRESENTATIONS = Object.freeze([
|
|
|
25
26
|
"logo-strip",
|
|
26
27
|
]);
|
|
27
28
|
|
|
29
|
+
/** Heading levels a theme may size (theme.json `type.headings`). */
|
|
30
|
+
export const THEME_HEADING_LEVELS = Object.freeze(["hero", "h1", "h2", "h3"]);
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* A heading size a theme may emit: a CSS length or a math function over lengths
|
|
34
|
+
* ("28px", "1.75rem", "clamp(1.5rem, 4vw, 2rem)"). The character set cannot close
|
|
35
|
+
* the declaration or the injected `<style>` block.
|
|
36
|
+
*/
|
|
37
|
+
export function isThemeCssSize(value) {
|
|
38
|
+
return typeof value === "string" && value.length <= 120 && /^[0-9a-z.%(),+\-*/ ]*[0-9a-z%)]$/i.test(value.trim());
|
|
39
|
+
}
|
|
40
|
+
|
|
28
41
|
/** True only for static assets materialized into a governed serving namespace. */
|
|
29
42
|
export function isSafeRehostedAssetPath(value) {
|
|
30
43
|
if (typeof value !== "string" || !value.startsWith("/")) return false;
|
|
@@ -16,9 +16,11 @@ export {
|
|
|
16
16
|
BLOCK_PALETTE_SUPPORTED_CONTRACTS,
|
|
17
17
|
FEATURED_PRODUCT_PRESENTATIONS,
|
|
18
18
|
PROMO_TILE_PRESENTATIONS,
|
|
19
|
+
THEME_HEADING_LEVELS,
|
|
19
20
|
isSafeRehostedAssetPath,
|
|
20
21
|
isSafeRehostedAssetPathForTenant,
|
|
21
22
|
isSafeStorefrontHref,
|
|
23
|
+
isThemeCssSize,
|
|
22
24
|
} from "./extension-contract-values.mjs";
|
|
23
25
|
|
|
24
26
|
export type PromoTilePresentation =
|
|
@@ -61,9 +61,12 @@ export interface ThemeColorTokens {
|
|
|
61
61
|
error?: string;
|
|
62
62
|
/** Informational state (notices, help). */
|
|
63
63
|
info?: string;
|
|
64
|
-
/** Accent tuned for SMALL text/links on light surfaces (AA). Default:
|
|
65
|
-
*
|
|
64
|
+
/** Accent tuned for SMALL text/links on light surfaces (AA). Default:
|
|
65
|
+
* `accent` with its lightness capped; set to hand-tune contrast. */
|
|
66
66
|
"accent-ink"?: string;
|
|
67
|
+
/** Readable text/icon color ON an `accent` fill. Default: black or white,
|
|
68
|
+
* whichever the accent's lightness favours; set to hand-tune contrast. */
|
|
69
|
+
"accent-contrast"?: string;
|
|
67
70
|
/** Hover/active shade of `primary`. Default: a derived darken of `primary`. */
|
|
68
71
|
"primary-hover"?: string;
|
|
69
72
|
/** Hover/active shade of `accent`. Default: a derived darken of `accent`. */
|
|
@@ -98,6 +101,9 @@ export interface ThemeColorTokens {
|
|
|
98
101
|
/** Trust / reassurance accent — guarantee callouts, security and compliance
|
|
99
102
|
* badges, proof strips. Default: `success`. */
|
|
100
103
|
trust?: string;
|
|
104
|
+
/** Home hero eyebrow text. Default: `muted` on a light hero, a translucent
|
|
105
|
+
* `primary-contrast` on a bold hero. */
|
|
106
|
+
"hero-eyebrow"?: string;
|
|
101
107
|
}
|
|
102
108
|
|
|
103
109
|
export interface ThemeFontFamily {
|
|
@@ -112,8 +118,24 @@ export interface ThemeTypeTokens {
|
|
|
112
118
|
/** Type scale ratio, e.g. 1.25 (major third). */
|
|
113
119
|
scale: number;
|
|
114
120
|
tracking?: string;
|
|
121
|
+
/**
|
|
122
|
+
* Fixed heading sizes (any CSS length: "28px", "1.75rem", "clamp(…)"). Each
|
|
123
|
+
* replaces the fluid display-scale size for its level: `hero` sizes the home
|
|
124
|
+
* hero headline; `h1`–`h3` size every other heading of that level (page and
|
|
125
|
+
* listing titles, block titles, rich-text headings). Unset levels keep the
|
|
126
|
+
* fluid scale derived from `scale`.
|
|
127
|
+
*/
|
|
128
|
+
headings?: ThemeHeadingSizes;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export interface ThemeHeadingSizes {
|
|
132
|
+
hero?: string;
|
|
133
|
+
h1?: string;
|
|
134
|
+
h2?: string;
|
|
135
|
+
h3?: string;
|
|
115
136
|
}
|
|
116
137
|
|
|
138
|
+
|
|
117
139
|
export interface ThemeSpaceTokens {
|
|
118
140
|
/** Base spacing unit in px. */
|
|
119
141
|
base: number;
|
|
@@ -259,6 +281,24 @@ export interface ExciseTaxConfig {
|
|
|
259
281
|
*/
|
|
260
282
|
export type ComplianceRuleProfile = "vape-nicotine-us";
|
|
261
283
|
|
|
284
|
+
/**
|
|
285
|
+
* The FDA nicotine warning's presentation: a validated `preset` ("dark" by default,
|
|
286
|
+
* "light"), optionally adjusted by `style`. Any `style` that leaves the preset is a
|
|
287
|
+
* custom presentation the owner approves before it goes live. Validated and resolved
|
|
288
|
+
* by packages/cli/src/declared-config.mjs; the wording is never configurable.
|
|
289
|
+
*/
|
|
290
|
+
export interface NicotineWarningDeclaration {
|
|
291
|
+
preset?: string;
|
|
292
|
+
style?: {
|
|
293
|
+
background?: string;
|
|
294
|
+
text?: string;
|
|
295
|
+
border?: string;
|
|
296
|
+
textTransform?: "uppercase" | "none";
|
|
297
|
+
fontWeight?: number;
|
|
298
|
+
fontSizePx?: number;
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
|
|
262
302
|
export interface ComplianceConfig {
|
|
263
303
|
/**
|
|
264
304
|
* The reviewed rule PROFILE whose ruleset the enforcement gate evaluates for
|
|
@@ -272,8 +312,12 @@ export interface ComplianceConfig {
|
|
|
272
312
|
ruleProfile?: ComplianceRuleProfile;
|
|
273
313
|
/** Minimum age to enter. Drives the soft affirmation gate (e.g. 21). */
|
|
274
314
|
minAge?: number;
|
|
275
|
-
/**
|
|
276
|
-
|
|
315
|
+
/**
|
|
316
|
+
* Render the FDA nicotine warning sitewide + reinforced on PDP. `true` renders the
|
|
317
|
+
* default preset; an object picks a validated preset and, optionally, a custom style
|
|
318
|
+
* the owner reviews at go-live (packages/cli/src/declared-config.mjs).
|
|
319
|
+
*/
|
|
320
|
+
nicotineWarning?: boolean | NicotineWarningDeclaration;
|
|
277
321
|
/** Short PACT-Act / no-ship-states / adult-signature notice (plain text). */
|
|
278
322
|
shippingRestriction?: string;
|
|
279
323
|
/**
|