@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 node ../../scripts/vitest-run.mjs 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 node ../../scripts/vitest-run.mjs 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",
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.1",
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": "node ../../scripts/vitest-run.mjs run",
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
- if (navigationHref) event.preventDefault?.();
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),