@@ -61,6 +61,12 @@ function collectCampaignParams(source?: URLSearchParams): Record<string, string>
6161 return collected
6262}
6363
64+ /** Shared empty-guard for the two `with*` builders below. */
65+ function collectNonEmptyCampaignParams ( ) : Record < string , string > | null {
66+ const collected = collectCampaignParams ( )
67+ return Object . keys ( collected ) . length === 0 ? null : collected
68+ }
69+
6470/**
6571 * Appends the current URL's campaign params to an internal path, preserving
6672 * partner attribution across a plain navigation. Used by the `'/download'`
@@ -69,10 +75,28 @@ function collectCampaignParams(source?: URLSearchParams): Record<string, string>
6975 * with the utm params stripped, silently losing the whole funnel attribution.
7076 */
7177function withCampaignParams ( path : string ) : string {
72- const collected = collectCampaignParams ( )
73- if ( Object . keys ( collected ) . length === 0 ) return path
78+ const collected = collectNonEmptyCampaignParams ( )
79+ if ( ! collected ) return path
7480 const params = new URLSearchParams ( collected )
7581 return `${ path } ${ path . includes ( '?' ) ? '&' : '?' } ${ params . toString ( ) } `
7682}
7783
78- export { collectCampaignParams , withCampaignParams }
84+ /**
85+ * Overlays the visitor's incoming campaign params (if any) onto a base URL's
86+ * own query string, overriding same-named params the base URL already
87+ * carries. For URLs that ship a baked-in default attribution (e.g. the Play
88+ * Store listing's own "QR code" campaign tag), this lets a live incoming
89+ * campaign win instead of being silently discarded at the store handoff.
90+ * Falls back to the base URL untouched when no campaign params are present.
91+ */
92+ function withCampaignParamsOverlay ( baseUrl : string ) : string {
93+ const collected = collectNonEmptyCampaignParams ( )
94+ if ( ! collected ) return baseUrl
95+ const url = new URL ( baseUrl )
96+ for ( const [ key , value ] of Object . entries ( collected ) ) {
97+ url . searchParams . set ( key , value )
98+ }
99+ return url . toString ( )
100+ }
101+
102+ export { collectCampaignParams , withCampaignParams , withCampaignParamsOverlay }
0 commit comments