@tokenoftrust/storefront-runner 4.11.1 → 4.11.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.
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"preview": "wrangler dev",
|
|
15
15
|
"typecheck": "astro check && tsc --noEmit",
|
|
16
16
|
"astro": "astro",
|
|
17
|
-
"test": "NODE_OPTIONS=--experimental-sqlite
|
|
17
|
+
"test": "NODE_OPTIONS=--experimental-sqlite tot-gate vitest run --exclude src/lib/integrations/apps/v84CleanCloneReplay.test.ts --exclude src/lib/integrations/apps/v84NonportableRouteDogfood.test.ts --exclude src/lib/integrations/apps/v84CloneLifecycleEvidence.test.ts && NODE_OPTIONS=--experimental-sqlite tot-gate vitest run src/lib/integrations/apps/v84CleanCloneReplay.test.ts src/lib/integrations/apps/v84NonportableRouteDogfood.test.ts src/lib/integrations/apps/v84CloneLifecycleEvidence.test.ts --fileParallelism=false && pnpm run test:pipeline && pnpm run test:pipeline-faults",
|
|
18
18
|
"depcruise": "depcruise src --config .runner-dependency-cruiser.cjs"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tokenoftrust/storefront-runner",
|
|
3
|
-
"version": "4.11.
|
|
3
|
+
"version": "4.11.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",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"scripts": {
|
|
48
48
|
"typecheck": "tsc --noEmit",
|
|
49
49
|
"build": "tsc",
|
|
50
|
-
"test": "
|
|
50
|
+
"test": "tot-gate vitest run",
|
|
51
51
|
"test:watch": "vitest",
|
|
52
52
|
"generate:managed-analytics-schemas": "node --experimental-strip-types scripts/generate-managed-analytics-api-v1-schemas.mjs"
|
|
53
53
|
},
|
|
@@ -55,6 +55,8 @@ export interface ContactSalesActionSourceOptions {
|
|
|
55
55
|
now?: () => number;
|
|
56
56
|
navigate?: (href: string) => void;
|
|
57
57
|
schedule?: (callback: () => void, delayMs: number) => void;
|
|
58
|
+
/** Current document URL. Same-document targets are not cancelled. */
|
|
59
|
+
pageUrl?: string | (() => string);
|
|
58
60
|
}
|
|
59
61
|
|
|
60
62
|
function deferredNavigationHref(node: ContactSalesActionElement, event: ContactSalesClickEvent): string | undefined {
|
|
@@ -68,10 +70,37 @@ function deferredNavigationHref(node: ContactSalesActionElement, event: ContactS
|
|
|
68
70
|
return node.href;
|
|
69
71
|
}
|
|
70
72
|
|
|
73
|
+
function currentPageUrl(pageUrl: ContactSalesActionSourceOptions["pageUrl"]): string | undefined {
|
|
74
|
+
if (typeof pageUrl === "function") {
|
|
75
|
+
const value = pageUrl();
|
|
76
|
+
return typeof value === "string" && value ? value : undefined;
|
|
77
|
+
}
|
|
78
|
+
return typeof pageUrl === "string" && pageUrl ? pageUrl : undefined;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** True when href stays on this document and only the fragment can change. */
|
|
82
|
+
function isSameDocumentNavigation(href: string, pageUrl: string | undefined): boolean {
|
|
83
|
+
if (pageUrl) {
|
|
84
|
+
try {
|
|
85
|
+
const current = new URL(pageUrl);
|
|
86
|
+
const target = new URL(href, pageUrl);
|
|
87
|
+
return current.origin === target.origin
|
|
88
|
+
&& current.pathname === target.pathname
|
|
89
|
+
&& current.search === target.search;
|
|
90
|
+
} catch {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return href.startsWith("#");
|
|
95
|
+
}
|
|
96
|
+
|
|
71
97
|
/**
|
|
72
98
|
* Bind the fixed reviewed DOM identities to a typed source for the managed-analytics
|
|
73
99
|
* bridge. A keyboard activation of an anchor/button produces its native `click`, so
|
|
74
100
|
* it follows this same semantic path without a separate key listener.
|
|
101
|
+
*
|
|
102
|
+
* A same-document target is recorded and then left to the browser. Cancelling it and
|
|
103
|
+
* assigning the href updates the hash without scrolling.
|
|
75
104
|
*/
|
|
76
105
|
export function createContactSalesActionSource(
|
|
77
106
|
options: ContactSalesActionSourceOptions,
|
|
@@ -98,7 +127,9 @@ export function createContactSalesActionSource(
|
|
|
98
127
|
bound.add(node);
|
|
99
128
|
const emit = (event: ContactSalesClickEvent = {}): void => {
|
|
100
129
|
const navigationHref = options.navigate ? deferredNavigationHref(node, event) : undefined;
|
|
101
|
-
|
|
130
|
+
const deferNavigation = typeof navigationHref === "string"
|
|
131
|
+
&& !isSameDocumentNavigation(navigationHref, currentPageUrl(options.pageUrl));
|
|
132
|
+
if (deferNavigation) event.preventDefault?.();
|
|
102
133
|
sequence += 1;
|
|
103
134
|
const at = now();
|
|
104
135
|
const activation: PlatformManagedActionActivation = {
|
|
@@ -113,7 +144,7 @@ export function createContactSalesActionSource(
|
|
|
113
144
|
listener(activation);
|
|
114
145
|
// A full-document navigation destroys the isolated GA4 iframe. Give its
|
|
115
146
|
// MessagePort one bounded turn to receive the reviewed action first.
|
|
116
|
-
if (navigationHref) {
|
|
147
|
+
if (deferNavigation && navigationHref) {
|
|
117
148
|
schedule(() => { if (live) options.navigate?.(navigationHref); }, CONTACT_SALES_NAVIGATION_DEFER_MS);
|
|
118
149
|
}
|
|
119
150
|
};
|
|
@@ -584,6 +584,7 @@ function createDocumentLifecycle(
|
|
|
584
584
|
if (typeof win.location.assign === "function") win.location.assign(href);
|
|
585
585
|
else win.location.href = href;
|
|
586
586
|
},
|
|
587
|
+
pageUrl: () => win.location.href,
|
|
587
588
|
}),
|
|
588
589
|
}),
|
|
589
590
|
pageView: () => documentPageView(win, descriptor, options.now ?? Date.now),
|