@tokenoftrust/storefront-runner 2.2.77 → 2.2.78
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tokenoftrust/storefront-runner",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.78",
|
|
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",
|
|
@@ -492,7 +492,7 @@ export type ViewerAnalyticsConsentDecision = "granted" | "denied";
|
|
|
492
492
|
export interface ViewerAnalyticsConsentState {
|
|
493
493
|
schemaVersion: 1;
|
|
494
494
|
decision: ViewerAnalyticsConsentDecision;
|
|
495
|
-
source: "tenant-default" | "default-deny" | "stored" | "global-privacy-control";
|
|
495
|
+
source: "tenant-default" | "default-deny" | "stored" | "stored-invalid" | "global-privacy-control";
|
|
496
496
|
canGrant: boolean;
|
|
497
497
|
expiresAt: number | null;
|
|
498
498
|
retentionDays: typeof VIEWER_ANALYTICS_CONSENT_RETENTION_DAYS;
|
|
@@ -596,51 +596,68 @@ export function applyEarlyViewerAnalyticsConsent(
|
|
|
596
596
|
const globalPrivacyControl = win.navigator?.globalPrivacyControl === true;
|
|
597
597
|
|
|
598
598
|
let stored: { decision: ViewerAnalyticsConsentDecision; expiresAt: number } | null = null;
|
|
599
|
+
// A stored record that is present but unreadable may have been a denial, so it denies
|
|
600
|
+
// rather than falling through to a granting tenant default. Only a well-formed record
|
|
601
|
+
// past its retention lapses to the default.
|
|
602
|
+
let storedInvalid = false;
|
|
599
603
|
if (override) {
|
|
600
604
|
stored = { decision: override, expiresAt: now + retentionMs };
|
|
601
605
|
} else {
|
|
606
|
+
let raw: string | null | undefined;
|
|
602
607
|
try {
|
|
603
|
-
|
|
604
|
-
if (raw) {
|
|
605
|
-
const parsed = JSON.parse(raw) as Record<string, unknown>;
|
|
606
|
-
const keys = Object.keys(parsed).sort();
|
|
607
|
-
const decidedAt = parsed["decidedAt"];
|
|
608
|
-
const expiresAt = parsed["expiresAt"];
|
|
609
|
-
const decision = parsed["decision"];
|
|
610
|
-
if (
|
|
611
|
-
keys.join(",") === "decidedAt,decision,environment,expiresAt,schemaVersion,siteSurface,tenantPublicId" &&
|
|
612
|
-
parsed["schemaVersion"] === 1 &&
|
|
613
|
-
parsed["tenantPublicId"] === tenantPublicId &&
|
|
614
|
-
parsed["environment"] === environment &&
|
|
615
|
-
parsed["siteSurface"] === siteSurface &&
|
|
616
|
-
(decision === "granted" || decision === "denied") &&
|
|
617
|
-
typeof decidedAt === "number" &&
|
|
618
|
-
Number.isFinite(decidedAt) &&
|
|
619
|
-
typeof expiresAt === "number" &&
|
|
620
|
-
Number.isFinite(expiresAt) &&
|
|
621
|
-
decidedAt <= now &&
|
|
622
|
-
expiresAt > now &&
|
|
623
|
-
expiresAt - decidedAt === retentionMs
|
|
624
|
-
) {
|
|
625
|
-
stored = { decision, expiresAt };
|
|
626
|
-
}
|
|
627
|
-
}
|
|
608
|
+
raw = win.localStorage?.getItem(scopedStorageKey);
|
|
628
609
|
} catch {
|
|
629
|
-
// Storage denial
|
|
610
|
+
// Storage denial leaves no viewer decision to read.
|
|
611
|
+
}
|
|
612
|
+
if (raw) {
|
|
613
|
+
let parsed: unknown = null;
|
|
614
|
+
try {
|
|
615
|
+
parsed = JSON.parse(raw);
|
|
616
|
+
} catch {
|
|
617
|
+
// Malformed data is handled as an invalid record below.
|
|
618
|
+
}
|
|
619
|
+
const record = typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)
|
|
620
|
+
? parsed as Record<string, unknown>
|
|
621
|
+
: null;
|
|
622
|
+
const decidedAt = record?.["decidedAt"];
|
|
623
|
+
const expiresAt = record?.["expiresAt"];
|
|
624
|
+
const decision = record?.["decision"];
|
|
625
|
+
if (
|
|
626
|
+
record !== null &&
|
|
627
|
+
Object.keys(record).sort().join(",") ===
|
|
628
|
+
"decidedAt,decision,environment,expiresAt,schemaVersion,siteSurface,tenantPublicId" &&
|
|
629
|
+
record["schemaVersion"] === 1 &&
|
|
630
|
+
record["tenantPublicId"] === tenantPublicId &&
|
|
631
|
+
record["environment"] === environment &&
|
|
632
|
+
record["siteSurface"] === siteSurface &&
|
|
633
|
+
(decision === "granted" || decision === "denied") &&
|
|
634
|
+
typeof decidedAt === "number" &&
|
|
635
|
+
Number.isFinite(decidedAt) &&
|
|
636
|
+
typeof expiresAt === "number" &&
|
|
637
|
+
Number.isFinite(expiresAt) &&
|
|
638
|
+
decidedAt <= now &&
|
|
639
|
+
expiresAt - decidedAt === retentionMs
|
|
640
|
+
) {
|
|
641
|
+
if (expiresAt > now) stored = { decision, expiresAt };
|
|
642
|
+
} else {
|
|
643
|
+
storedInvalid = true;
|
|
644
|
+
}
|
|
630
645
|
}
|
|
631
646
|
}
|
|
632
647
|
|
|
633
648
|
const decision: ViewerAnalyticsConsentDecision =
|
|
634
|
-
globalPrivacyControl || !tenantApprovedAnalytics
|
|
649
|
+
globalPrivacyControl || !tenantApprovedAnalytics || (!stored && storedInvalid)
|
|
635
650
|
? "denied"
|
|
636
651
|
: stored?.decision ?? (tenantDefaultAnalytics ? "granted" : "denied");
|
|
637
652
|
const source: ViewerAnalyticsConsentState["source"] = globalPrivacyControl
|
|
638
653
|
? "global-privacy-control"
|
|
639
654
|
: stored
|
|
640
655
|
? "stored"
|
|
641
|
-
:
|
|
642
|
-
? "
|
|
643
|
-
:
|
|
656
|
+
: storedInvalid
|
|
657
|
+
? "stored-invalid"
|
|
658
|
+
: tenantDefaultAnalytics
|
|
659
|
+
? "tenant-default"
|
|
660
|
+
: "default-deny";
|
|
644
661
|
|
|
645
662
|
const eligible = canonicalPurposes.filter(
|
|
646
663
|
(purpose) =>
|