diff --git a/.cspell.jsonc b/.cspell.jsonc index 0ba6ee6..e9ab136 100644 --- a/.cspell.jsonc +++ b/.cspell.jsonc @@ -2,8 +2,8 @@ { "allowCompoundWords": true, "dictionaries": [ - "!bash","!cpp","!csharp","dictionary-src-sh","!en-gb","!go","html", - "!latex","node","!php","!python","typescript" + "!bash","!cpp","!csharp","dictionary-custom","dictionary-src-sh","!en-gb","!go","html", + "javascript","!latex","node","!php","!python","typescript" ], "dictionaryDefinitions": [ { @@ -17,13 +17,6 @@ "ignoreRegExpList": [ "entities","mdanchors","regexes","urlencoded","webhosts" ], - "languageSettings": [ - { - "dictionaries": ["dictionary-custom"], - "languageId": "javascript,typescript,markdown", - "locale": "*" - } - ], "patterns": [ { "name": "entities", diff --git a/.cspell/dictionary-custom.txt b/.cspell/dictionary-custom.txt index 8b5ef9b..f45e924 100644 --- a/.cspell/dictionary-custom.txt +++ b/.cspell/dictionary-custom.txt @@ -1,12 +1,18 @@ Blogsy +Bronto Codacy +cyclonedx +delighter Ghostery +Klaviyo +Listrak Matomo Octocat -Textastic -cyclonedx -delighter +Omeda smushing +Temu +Textastic uglifyjs unskim utmstrip +Vero diff --git a/README.md b/README.md index f5f45f2..3970dd3 100644 --- a/README.md +++ b/README.md @@ -81,11 +81,12 @@ ad or tracking blockers. If the current URL contains a parameter in the form of `url=...` this bookmarklet will parse the `url` parameter and navigate to that URL. -+ __[UtmStrip] v2.1.0__: Strips off the UTM query string elements of the ++ __[UtmStrip] v2.2.0__: Strips off the UTM query string elements of the current URL to remove common "urchin" tracking information from youtube, etc. Also removes Google `/amp/` suffix from URL path. Asks to copy the new URL -to the clipboard. Finally, replaces history & reloads the page. _NOTE:_ This -bookmarklet also works with Safari and Firefox on macOS. +to the clipboard. Finally, replaces history & reloads the page. Now works to +remove host-specific trackers for common online retailers and Google Search. +_NOTE:_ This bookmarklet also works with Safari and Firefox on macOS. + __[unskim] v2.0.1__: Bypass redirect and affiliate link wrappers by detecting common URL parameters (like `url=`, `destination=`, `redirect=`, @@ -127,7 +128,7 @@ followed link into a bookmark for JavaScript bookmarklet. + __Mobile Safari setup link__ -- [Setup OpenInTextastic] v1.1.2 + __Mobile Safari setup link__ -- [Setup OpenInWorkingCopy] v1.6.2 + __Mobile Safari setup link__ -- [Setup OpenURLParam] v1.2.0 -+ __Mobile Safari setup link__ -- [Setup UtmStrip] v2.1.0 ++ __Mobile Safari setup link__ -- [Setup UtmStrip] v2.2.0 + __Mobile Safari setup link__ -- [Setup unskim] v2.0.1 + __Mobile Safari setup link__ -- [Setup x-man] v1.3.1 @@ -225,8 +226,9 @@ using a URL protocol scheme. that URL. + __UtmStrip__ - Strips off the UTM query string elements of the current URL. Based on [safari-utm-stripper Bookmarklet][kiding-gist 589242021df49eb17be3]. - NOTE: UtmStrip now borrows heavily from patterns provided by [Firefox - Extension Neat URL][Neat URL] + NOTE: UtmStrip borrowed heavily from [Firefox Extension Neat URL][Neat URL] + patterns, and now does much more. There are many site-specific tracking + elements removed and Google Search URLs are decluttered, too. + __x-man__ - Uses the current selection in the browser to create and open a link that uses the `x-man-page://` URL scheme supported by Safari and Terminal.app. There doesn't seem to be any official documentation for this @@ -236,6 +238,10 @@ using a URL protocol scheme. ## Version Notes +4.1.1 Major update to UtmStrip with 26 new universal exact-match static keys, + 4 new universal prefixes, 57 new host-specific keys/prefixes across 7 new + hosts, and host-specific tracking & decluttering for Google Search. + 4.1.0 Revise 11 bookmarklets- streamline simple ones, modernize KillStickyHeaders and OpenURLParam. Update scripts/build-bookmarklets.js to compact bookmarklets that don't use vars. @@ -347,7 +353,7 @@ repos I had; doesn't build yet [OpenInTextastic]: javascript:if(%2FiP(ad%7Chone)%2F.test(navigator.userAgent))location.href=location.href.replace(%2F%5Ehttps%3F%2F%2C'textastic')%3Bvoid'1.1.2' "OpenInTextastic" [OpenInWorkingCopy]: javascript:if(%2FiP(ad%7Chone)%2F.test(navigator.userAgent)%26%26('bitbucket.org'===location.host%7C%7C'github.com'===location.host))location.href=%60working-copy:%2F%2Fshow%3Fremote=%24%7BencodeURIComponent(location.href.split('%2F').slice(0%2C5).join('%2F'))%7D.git%60%3Bvoid'1.6.2' "OpenInWorkingCopy" [OpenURLParam]: javascript:'use%20strict'%3B(()=%3E%7Bconst%20t=new%20URL(document.location.href)%3Bif(11%3Et.search.length)return%3Bconst%20e=new%20URLSearchParams(t.search)%2Cn=%5B'url'%2C'destination'%2C'redirect'%2C'target'%2C'goto'%2C'u'%2C'dest'%2C'link'%2C'out'%5D.filter(t=%3Ee.has(t)).map(t=%3E%7Bconst%20n=e.get(t)%3Breturn%20n%3FdecodeURIComponent(n):''%7D).find(t=%3Et.match(%2F%5Ehttps:%2F))%3Bn%26%26window.location.replace(new%20URL(n))%7D)()%3Bvoid'1.2.0' "OpenURLParam" -[UtmStrip]: javascript:'use%20strict'%3B(()=%3E%7Bconst%20e=location.pathname%2Ci=location.search%3Bif(3%3Ei.length%26%26!e.includes('%2Famp'))return%3Blet%20c=e%2Ct=i%3Bconst%20a=location.hostname%2Cn=(e%2Ci)=%3Ee.replace(i%2C'%241')%3Bif(a.includes('aliexpress.')%26%26(t=n(t%2C%2F(%5B%3F%26%5D)aff%5F(platform%7Ctrace%5Fkey)=%5B%5E%26%5D%2B%2Fgi)%2Ct=n(t%2C%2F(%5B%3F%26%5D)algo%5F%5Bep%5Dvid=%5B%5E%26%5D%2B%2Fg)%2Ct=n(t%2C%2F(%5B%3F%26%5D)(btsid%7Cws%5Fab%5Ftest)=%5B%5E%26%5D%2B%2Fg)%2Ct=n(t%2C%2F(%5B%3F%26%5D)s%5Bcp%5Dm=%5B%5E%26%5D%2B%2Fg))%2C%2F(%7C%5C.)amazon%5C.com%24%2F.test(a)%26%26(t=n(t%2C%2F(%5B%3F%26%5D)(%5Fencoding%7Cie%7ClinkCode%7ClinkId%7Cpf%7Cpsc%7Cref%5F%7Ctag)=%5B%5E%26%5D%2B%2Fgi)%2Ct=n(t%2C%2F(%5B%3F%26%5D)p%5Bdf%5D%5Frd%5F.%2A%3F=%5B%5E%26%5D%2B%2Fgi)%2Ct=n(t%2C%2F(%5B%3F%26%5D)(content-id%7Ccrid%7Ccv%5Fct%5Fcx%7Clanguage%7Cqid%7Csprefix%7Csr%7Cth)=%5B%5E%26%5D%2B%2Fg)%2Ct=n(t%2C%2F(%5B%3F%26%5D)asc(%5Fcampaign%7C%5Frefurl%7C%5Fsource%7Csubtag)=%5B%5E%26%5D%2B%2Fg)%2Ct=n(t%2C%2F(%5B%3F%26%5D)dib(%5Ftag)%3F=%5B%5E%26%5D%2B%2Fg))%2Ct.includes('fb%5F')%26%26(t=n(t%2C%2F(%5B%3F%26%5D)fb%5F(action%5Fids%7Caction%5Ftypes%7Cref%7Csource)=%5B%5E%26%5D%2B%2Fgi)%2Ct=n(t%2C%2F(%5B%3F%26%5D)(fbclid%7Chrc%7Crefsrc)=%5B%5E%26%5D%2B%2Fgi))%2Ct.includes('action%5F')%26%26(t=n(t%2C%2F(%5B%3F%26%5D)action%5F(object%7Cref%7Ctype)%5Fmap=%5B%5E%26%5D%2B%2Fgi))%2Ct=n(t%2C%2F(%5B%3F%26%5D)(assetType%7CelqTrack%7Cmkt%5Ftok%7CoriginalReferer%7Creferrer%7Cterminal%5Fid%7Ctrk%7CtrkCampaign%7CtrkInfo)=%5B%5E%26%5D%2B%2Fgi)%2Ct.toLowerCase().includes('id=')%26%26(t=n(t%2C%2F(%5B%3F%26%5D)(an%7Casset%7Ccampaign%7Ce%7Cgcl%7Crecipient%7Csite)id=%5B%5E%26%5D%2B%2Fgi))%2C(t.includes('ga%5F')%7C%7Ct.includes('utm%5F'))%26%26(t=n(t%2C%2F(%5B%3F%26%5D)(ga%7Cutm)%5F(campaign%7Ccid%7Ccontent%7Cdesign%7Cmedium%7Cname%7Cplace%7Cpubreferrer%7Creader%7Csource%7Cswu%7Cterm%7Cuserid%7Cviz%5Fid)=%5B%5E%26%5D%2B%2Fgi)%2Ct=n(t%2C%2F(%5B%3F%26%5D)gcl(id%7Csrc)=%5B%5E%26%5D%2B%2Fgi))%2C(%2F(m%7Cwww)%5C.youtube%5C.com%24%2F.test(a)%7C%7C'youtu.be'===a%7C%7C'www.youtube-nocookie.com'===a)%26%26(t=n(t%2C%2F(%5B%3F%26%5D)(ac%7Cannotation%5Fid%7Capp%7Cfeature%7Cgclid%7Ckw%7Csrc%5Fvid)=%5B%5E%26%5D%2B%2Fgi))%2C%2F%5B%3F%26%5D%5Fhs(enc%7Cmi)=%2F.test(t)%26%26(t=n(t%2C%2F(%5B%3F%26%5D)%5Fhs(enc%7Cmi)=%5B%5E%26%5D%2B%2Fgi))%2Ct.includes('hmb%5F')%26%26(t=n(t%2C%2F(%5B%3F%26%5D)hmb%5F(campaign%7Cmedium%7Csource)=%5B%5E%26%5D%2B%2Fgi))%2Ct.includes('cm%5F')%26%26(t=n(t%2C%2F(%5B%3F%26%5D)cm%5F(mmc%7Cmmca%5Cd%2B%7Cre%7Csp)=%5B%5E%26%5D%2B%2Fgi)%2Ct=n(t%2C%2F(%5B%3F%26%5D)manual%5Fcm%5Fmmc=%5B%5E%26%5D%2B%2Fgi))%2C%2F%5B%3F%26%5Dmc%5F%5Bce%5Did=%2F.test(t)%26%26(t=n(t%2C%2F(%5B%3F%26%5D)mc%5F%5Bce%5Did=%5B%5E%26%5D%2B%2Fgi))%2C%2F%5B%3F%26%5D(iesrc%7Cmkt%5Ftok)=%2F.test(t)%26%26(t=n(t%2C%2F(%5B%3F%26%5D)(iesrc%7Cmkt%5Ftok)=%5B%5E%26%5D%2B%2Fgi))%2Ct.includes('pk%5F')%26%26(t=n(t%2C%2F(%5B%3F%26%5D)pk%5F(campaign%7Ccontent%7Ckwd%7Cmedium%7Csource)=%5B%5E%26%5D%2B%2Fgi))%2Ct=t.replace(%2F%26%26%2B%2Fg%2C'%26').replace(%2F%26%24%2F%2C'')%2Ct='%3F'===t%5B0%5D%3Ft.replace(%2F%5E%5C%3F%26%2F%2C'%3F'):'%3F'%2Bt%2Ct=3%3Et.length%3F'':t%2Cc=c.replace(%2F%5C%2Famp%5C%2F%3F%24%2F%2C'')%2C(i!==t%7C%7Ce!==c)%26%26confirm('Update%20history%20and%20copy%20cleaned%20URL%20to%20clipboard%3F'))%7Bconst%20e=%60%24%7Blocation.protocol%7D%2F%2F%24%7Blocation.host%7D%24%7Bc%7D%24%7Bt%7D%24%7Blocation.hash%7D%60%3Bnavigator.clipboard.writeText(e)%2Chistory.replaceState(null%2C''%2Ce)%3Bconst%20i=window.open(e%2C'%5Fself'%2C'noreferrer')%3Bi%26%26(i.opener=null)%7D%7D)()%3Bvoid'2.1.0' "UtmStrip" +[UtmStrip]: javascript:'use%20strict'%3B(()=%3E%7Bconst%20t=location.pathname%2Ce=location.search%3Bif(3%3Ee.length%26%26!t.includes('%2Famp'))return%3Bconst%20i=location.hostname%2Cs=new%20URLSearchParams(e)%2Ca=%5B'assetType'%2C'elqTrack'%2C'mkt%5Ftok'%2C'originalReferer'%2C'referrer'%2C'terminal%5Fid'%2C'trk'%2C'trkCampaign'%2C'trkInfo'%2C'anid'%2C'assetid'%2C'campaignid'%2C'eid'%2C'gclid'%2C'recipientid'%2C'siteid'%2C'sib%5Fcuid'%2C'sib%5Fsid'%2C'%5Fbta%5Ftid'%2C'%5Fbta%5Fc'%2C'%5F%5Fs'%2C'fbclid'%2C'hrc'%2C'igsh'%2C'igshid'%2C'refsrc'%2C'%5Fgl'%2C'gclsrc'%2C'srsltid'%2C'%5Fhsenc'%2C'%5Fhsmi'%2C'%5F%5Fhsfp'%2C'%5F%5Fhssc'%2C'%5F%5Fhstc'%2C'cm%5Fmmc'%2C'cm%5Fre'%2C'cm%5Fsp'%2C'manual%5Fcm%5Fmmc'%2C'%5Fke'%2C'%5Fkx'%2C'trk%5Fcontact'%2C'trk%5Fmsg'%2C'trk%5Fmodule'%2C'trk%5Fsid'%2C'mc%5Fcid'%2C'mc%5Feid'%2C'iesrc'%2C'msclkid'%2C'dclid'%2C'twclid'%2C'ttclid'%2C'oly%5Fenc%5Fid'%2C'oly%5Fanon%5Fid'%2C'epik'%2C'vero%5Fid'%5D%2C%5F=%5B'fb%5F'%2C'action%5F'%2C'ga%5F'%2C'utm%5F'%2C'hmb%5F'%2C'hsa%5F'%2C'mtm%5F'%2C'pk%5F'%2C'oly%5F'%2C'stm%5F'%5D%3B%2F%5C.aliexpress%5C.%5Ba-z%5D%7B2%2C3%7D%24%2F.test(i)%3F(a.push('algo%5Fevid'%2C'algo%5Fpvid'%2C'btsid'%2C'spm'%2C'scm'%2C'ws%5Fab%5Ftest')%2C%5F.push('aff%5F')):%2F(%7C%5C.)amazon%5C.com%24%2F.test(i)%3Fa.push('%5Fencoding'%2C'asc%5Fcampaign'%2C'asc%5Frefurl'%2C'asc%5Fsource'%2C'ascsubtag'%2C'content-id'%2C'crid'%2C'cv%5Fct%5Fcx'%2C'dib%5Ftag'%2C'dib'%2C'ie'%2C'language'%2C'linkCode'%2C'linkId'%2C'pd%5Frd%5Fi'%2C'pd%5Frd%5Fr'%2C'pd%5Frd%5Fw'%2C'pd%5Frd%5Fwg'%2C'pf%5Frd%5Fi'%2C'pf%5Frd%5Fm'%2C'pf%5Frd%5Fp'%2C'pf%5Frd%5Fr'%2C'pf%5Frd%5Fs'%2C'pf%5Frd%5Ft'%2C'pf'%2C'psc'%2C'qid'%2C'ref%5F'%2C'sprefix'%2C'sr'%2C'tag'%2C'th'):i.endsWith('.ebay.com')%7C%7C%2F%5C.ebay%5C.co%5C.%5Ba-z%5D%7B2%7D%24%2F.test(i)%3Fa.push('mkevt'%2C'mkcid'%2C'mkrid'%2C'campid'%2C'toolid'%2C'customid'%2C'norover'%2C'itm'%2C'amdata'):%2F(%5E%7C%5C.)google%5C.(com%7C%5Ba-z%5D%7B2%7D%7Ccom%3F%5C.%5Ba-z%5D%7B2%7D)%24%2F.test(i)%26%26t.startsWith('%2Fsearch')%3Fa.push('aqs'%2C'ei'%2C'gs%5Flp'%2C'gs%5Fssp'%2C'iflsig'%2C'sca%5Fesv'%2C'ved'%2C'oq'%2C'sa'%2C'uact'%2C'rlz'%2C'sxsrf'%2C'bih'%2C'biw'%2C'client'%2C'prmd'%2C'sclient'%2C'source'%2C'sourceid'%2C'ie'%2C'oe'):i.endsWith('.linkedin.com')%3Fa.push('li%5Ffat%5Fid'%2C'licu'%2C'lipi'%2C'midSig'%2C'midToken'%2C'refId'):i.endsWith('.target.com')%3Fa.push('afid'%2C'clkid'%2C'lnm'%2C'preselect'%2C'tref'):i.endsWith('.temu.com')%3F(a.push('%5Fbg%5Ffs'%2C'%5Fp%5Fjump%5Fid'%2C'%5Fp%5Frfs'%2C'refer%5Fpage%5Fid'%2C'refer%5Fpage%5Fname'%2C'refer%5Fpage%5Fsn')%2C%5F.push('%5Fx%5F')):i.endsWith('.tiktok.com')%7C%7C'tiktok.com'===i%3Fa.push('%5Fd'%2C'%5Fr'%2C'%5Ft'%2C'is%5Ffrom%5Fwebapp'%2C'preview%5Fpb'%2C'share%5Fapp%5Fname'%2C'share%5Fitem%5Fid'%2C'tt4d%5Ft'%2C'timestamp'%2C'u%5Fcode'%2C'user%5Fid'):%2F%5C.(twitter%7Cx)%5C.com%24%2F.test(i)%7C%7C%2F%5E(twitter%7Cx)%5C.com%24%2F.test(i)%3Fa.push('cn'%2C'ref%5Fsrc'%2C'ref%5Furl'%2C's'%2C't'):i.endsWith('.walmart.com')%3Fa.push('adsredirect'%2C'affiliates%5Fad%5Fid'%2C'athcpid'%2C'athpgid'%2C'athcgid'%2C'athmtid'%2C'athstid'%2C'athznid'%2C'athiession'%2C'athancid'%2C'athposb'%2C'athena'%2C'campaign%5Fid'%2C'wmlspartner'):(%2F(m%7Cwww)%5C.youtube%5C.com%24%2F.test(i)%7C%7C'youtu.be'===i%7C%7C'www.youtube-nocookie.com'===i)%26%26a.push('ac'%2C'annotation%5Fid'%2C'app'%2C'feature'%2C'gclid'%2C'kw'%2C'src%5Fvid')%3Bconst%20c=new%20Set(a.map(t=%3Et.toLowerCase()))%2Cr=t=%3E%7Bconst%20e=t.toLowerCase()%3Breturn%20c.has(e)%7C%7C%5F.some(t=%3Ee.startsWith(t))%7C%7C%2F%5Ecm%5Fmmca%5Cd%2B%24%2Fi.test(t)%7D%3Bfor(const%20t%20of%5B...s.keys()%5D)r(t)%26%26s.delete(t)%3Blet%20d=s.toString()%3Bd=d%3F'%3F'%2Bd:''%3Bconst%20o=t.replace(%2F%5C%2Famp%5C%2F%3F%24%2F%2C'')%3Bif((e!==d%7C%7Ct!==o)%26%26confirm('Update%20history%20and%20copy%20cleaned%20URL%20to%20clipboard%3F'))%7Bconst%20t=%60%24%7Blocation.protocol%7D%2F%2F%24%7Blocation.host%7D%24%7Bo%7D%24%7Bd%7D%24%7Blocation.hash%7D%60%3Bnavigator.clipboard.writeText(t)%2Chistory.replaceState(null%2C''%2Ct)%3Bconst%20e=window.open(t%2C'%5Fself'%2C'noreferrer')%3Be%26%26(e.opener=null)%7D%7D)()%3Bvoid'2.2.0' "UtmStrip" [unskim]: javascript:'use%20strict'%3B(()=%3E%7Blet%20e=new%20URL(document.location.href)%3Bif('safari-resource:%2FErrorPage.html'===e.href)%7Bconst%20t=document.querySelector('p.error-message')%3F.textContent%3F.match(%2FSafari%20can't%20open%20the%20page%20%22(https%3F:%5B%5E%22%5D%2B)%22%2F)%3F.%5B1%5D%3Bt%26%26(e=new%20URL(t))%7Dif(''===e.search)return%3Bconst%20t=new%20URLSearchParams(e.search)%2Cr=%5B'url'%2C'destination'%2C'redirect'%2C'target'%2C'goto'%2C'u'%2C'dest'%2C'link'%2C'out'%5D.filter(e=%3Et.has(e)).map(e=%3E%7Bconst%20r=t.get(e)%3Breturn%20r%3FdecodeURIComponent(r):''%7D).find(e=%3Ee.match(%2F%5Ehttps%3F:%2F))%3Br%26%26window.location.replace(new%20URL(r))%7D)()%3Bvoid'2.0.1' "unskim" [x-man]: javascript:'use%20strict'%3B(()=%3E%7Bconst%20i=navigator.userAgent%2Cn=i.includes('Chrome%2F')%7C%7Ci.includes('Firefox%2F')%7C%7Ci.includes('Brave%2F')%7C%7Ci.includes('Edg%2F')%2Co=i.includes('Safari%2F')%2Ct=!n%26%26!o%2Ca=navigator.platform.startsWith('Mac')%26%26o%26%26!n%26%26!t%26%26!navigator.maxTouchPoints%26%262%3Enavigator.maxTouchPoints%2Ce=window.getSelection()%3Bif(!e)return%3Bconst%20l=e.toString().split('%5Cn')%5B0%5D.trim()%3Blet%20r='x-man-page:%2F%2F'%3Bconst%20c=l.match(%2F%5E(.%2A%3F)%5C((%5Cd)%5C)%24%2F)%3Bif(r%2B=c%3F'1'===c%5B2%5D%3Fc%5B1%5D:%60%24%7Bc%5B2%5D%7D%2F%24%7Bc%5B1%5D%7D%60:l%2Cl)%7Bif(confirm(%60Link%20for%20%22%24%7Bl%7D%22%20is:%20%24%7Br%7D%5Cn%5CnCopy%20to%20clipboard%3F%60))%7Blet%20i=''%3Bif(navigator.clipboard%3Fnavigator.clipboard.writeText(r):(i=%60Unable%20to%20copy%20%22%24%7Br%7D%22%20to%20clipboard.%60%2Cr='')%2Ca%26%26''!==r)%7Blet%20n=null%3Btry%7Bn=window.open(r)%2Cn%26%26(n.opener=null)%7Dcatch(n)%7Bi=%60Popup%20window%20blocked.%20Clipboard%20contains%20%22%24%7Br%7D%22%60%7Dfinally%7Bwindow.focus()%2Cnull!==n%26%26setTimeout(()=%3E%7Bn%26%26n.close()%7D%2C3333)%7D%7Delse''!==r%26%26(i=%60Unable%20to%20open%20new%20link%20with%20Terminal.%20Clipboard%20contains%20%22%24%7Br%7D%22%60)%3B''!==i%26%26alert(i)%7De.empty()%7D%7D)()%3Bvoid'1.3.1' "x-man" @@ -366,7 +372,7 @@ repos I had; doesn't build yet [Setup OpenInTextastic]: https://mobilemind.github.io/OpenInlets/x/#javascript:if(%2FiP(ad%7Chone)%2F.test(navigator.userAgent))location.href=location.href.replace(%2F%5Ehttps%3F%2F%2C'textastic')%3Bvoid'1.1.2' "Setup OpenInTextastic" [Setup OpenInWorkingCopy]: https://mobilemind.github.io/OpenInlets/x/#javascript:if(%2FiP(ad%7Chone)%2F.test(navigator.userAgent)%26%26('bitbucket.org'===location.host%7C%7C'github.com'===location.host))location.href=%60working-copy:%2F%2Fshow%3Fremote=%24%7BencodeURIComponent(location.href.split('%2F').slice(0%2C5).join('%2F'))%7D.git%60%3Bvoid'1.6.2' "Setup OpenInWorkingCopy" [Setup OpenURLParam]: https://mobilemind.github.io/OpenInlets/x/#javascript:'use%20strict'%3B(()=%3E%7Bconst%20t=new%20URL(document.location.href)%3Bif(11%3Et.search.length)return%3Bconst%20e=new%20URLSearchParams(t.search)%2Cn=%5B'url'%2C'destination'%2C'redirect'%2C'target'%2C'goto'%2C'u'%2C'dest'%2C'link'%2C'out'%5D.filter(t=%3Ee.has(t)).map(t=%3E%7Bconst%20n=e.get(t)%3Breturn%20n%3FdecodeURIComponent(n):''%7D).find(t=%3Et.match(%2F%5Ehttps:%2F))%3Bn%26%26window.location.replace(new%20URL(n))%7D)()%3Bvoid'1.2.0' "Setup OpenURLParam" -[Setup UtmStrip]: https://mobilemind.github.io/OpenInlets/x/#javascript:'use%20strict'%3B(()=%3E%7Bconst%20e=location.pathname%2Ci=location.search%3Bif(3%3Ei.length%26%26!e.includes('%2Famp'))return%3Blet%20c=e%2Ct=i%3Bconst%20a=location.hostname%2Cn=(e%2Ci)=%3Ee.replace(i%2C'%241')%3Bif(a.includes('aliexpress.')%26%26(t=n(t%2C%2F(%5B%3F%26%5D)aff%5F(platform%7Ctrace%5Fkey)=%5B%5E%26%5D%2B%2Fgi)%2Ct=n(t%2C%2F(%5B%3F%26%5D)algo%5F%5Bep%5Dvid=%5B%5E%26%5D%2B%2Fg)%2Ct=n(t%2C%2F(%5B%3F%26%5D)(btsid%7Cws%5Fab%5Ftest)=%5B%5E%26%5D%2B%2Fg)%2Ct=n(t%2C%2F(%5B%3F%26%5D)s%5Bcp%5Dm=%5B%5E%26%5D%2B%2Fg))%2C%2F(%7C%5C.)amazon%5C.com%24%2F.test(a)%26%26(t=n(t%2C%2F(%5B%3F%26%5D)(%5Fencoding%7Cie%7ClinkCode%7ClinkId%7Cpf%7Cpsc%7Cref%5F%7Ctag)=%5B%5E%26%5D%2B%2Fgi)%2Ct=n(t%2C%2F(%5B%3F%26%5D)p%5Bdf%5D%5Frd%5F.%2A%3F=%5B%5E%26%5D%2B%2Fgi)%2Ct=n(t%2C%2F(%5B%3F%26%5D)(content-id%7Ccrid%7Ccv%5Fct%5Fcx%7Clanguage%7Cqid%7Csprefix%7Csr%7Cth)=%5B%5E%26%5D%2B%2Fg)%2Ct=n(t%2C%2F(%5B%3F%26%5D)asc(%5Fcampaign%7C%5Frefurl%7C%5Fsource%7Csubtag)=%5B%5E%26%5D%2B%2Fg)%2Ct=n(t%2C%2F(%5B%3F%26%5D)dib(%5Ftag)%3F=%5B%5E%26%5D%2B%2Fg))%2Ct.includes('fb%5F')%26%26(t=n(t%2C%2F(%5B%3F%26%5D)fb%5F(action%5Fids%7Caction%5Ftypes%7Cref%7Csource)=%5B%5E%26%5D%2B%2Fgi)%2Ct=n(t%2C%2F(%5B%3F%26%5D)(fbclid%7Chrc%7Crefsrc)=%5B%5E%26%5D%2B%2Fgi))%2Ct.includes('action%5F')%26%26(t=n(t%2C%2F(%5B%3F%26%5D)action%5F(object%7Cref%7Ctype)%5Fmap=%5B%5E%26%5D%2B%2Fgi))%2Ct=n(t%2C%2F(%5B%3F%26%5D)(assetType%7CelqTrack%7Cmkt%5Ftok%7CoriginalReferer%7Creferrer%7Cterminal%5Fid%7Ctrk%7CtrkCampaign%7CtrkInfo)=%5B%5E%26%5D%2B%2Fgi)%2Ct.toLowerCase().includes('id=')%26%26(t=n(t%2C%2F(%5B%3F%26%5D)(an%7Casset%7Ccampaign%7Ce%7Cgcl%7Crecipient%7Csite)id=%5B%5E%26%5D%2B%2Fgi))%2C(t.includes('ga%5F')%7C%7Ct.includes('utm%5F'))%26%26(t=n(t%2C%2F(%5B%3F%26%5D)(ga%7Cutm)%5F(campaign%7Ccid%7Ccontent%7Cdesign%7Cmedium%7Cname%7Cplace%7Cpubreferrer%7Creader%7Csource%7Cswu%7Cterm%7Cuserid%7Cviz%5Fid)=%5B%5E%26%5D%2B%2Fgi)%2Ct=n(t%2C%2F(%5B%3F%26%5D)gcl(id%7Csrc)=%5B%5E%26%5D%2B%2Fgi))%2C(%2F(m%7Cwww)%5C.youtube%5C.com%24%2F.test(a)%7C%7C'youtu.be'===a%7C%7C'www.youtube-nocookie.com'===a)%26%26(t=n(t%2C%2F(%5B%3F%26%5D)(ac%7Cannotation%5Fid%7Capp%7Cfeature%7Cgclid%7Ckw%7Csrc%5Fvid)=%5B%5E%26%5D%2B%2Fgi))%2C%2F%5B%3F%26%5D%5Fhs(enc%7Cmi)=%2F.test(t)%26%26(t=n(t%2C%2F(%5B%3F%26%5D)%5Fhs(enc%7Cmi)=%5B%5E%26%5D%2B%2Fgi))%2Ct.includes('hmb%5F')%26%26(t=n(t%2C%2F(%5B%3F%26%5D)hmb%5F(campaign%7Cmedium%7Csource)=%5B%5E%26%5D%2B%2Fgi))%2Ct.includes('cm%5F')%26%26(t=n(t%2C%2F(%5B%3F%26%5D)cm%5F(mmc%7Cmmca%5Cd%2B%7Cre%7Csp)=%5B%5E%26%5D%2B%2Fgi)%2Ct=n(t%2C%2F(%5B%3F%26%5D)manual%5Fcm%5Fmmc=%5B%5E%26%5D%2B%2Fgi))%2C%2F%5B%3F%26%5Dmc%5F%5Bce%5Did=%2F.test(t)%26%26(t=n(t%2C%2F(%5B%3F%26%5D)mc%5F%5Bce%5Did=%5B%5E%26%5D%2B%2Fgi))%2C%2F%5B%3F%26%5D(iesrc%7Cmkt%5Ftok)=%2F.test(t)%26%26(t=n(t%2C%2F(%5B%3F%26%5D)(iesrc%7Cmkt%5Ftok)=%5B%5E%26%5D%2B%2Fgi))%2Ct.includes('pk%5F')%26%26(t=n(t%2C%2F(%5B%3F%26%5D)pk%5F(campaign%7Ccontent%7Ckwd%7Cmedium%7Csource)=%5B%5E%26%5D%2B%2Fgi))%2Ct=t.replace(%2F%26%26%2B%2Fg%2C'%26').replace(%2F%26%24%2F%2C'')%2Ct='%3F'===t%5B0%5D%3Ft.replace(%2F%5E%5C%3F%26%2F%2C'%3F'):'%3F'%2Bt%2Ct=3%3Et.length%3F'':t%2Cc=c.replace(%2F%5C%2Famp%5C%2F%3F%24%2F%2C'')%2C(i!==t%7C%7Ce!==c)%26%26confirm('Update%20history%20and%20copy%20cleaned%20URL%20to%20clipboard%3F'))%7Bconst%20e=%60%24%7Blocation.protocol%7D%2F%2F%24%7Blocation.host%7D%24%7Bc%7D%24%7Bt%7D%24%7Blocation.hash%7D%60%3Bnavigator.clipboard.writeText(e)%2Chistory.replaceState(null%2C''%2Ce)%3Bconst%20i=window.open(e%2C'%5Fself'%2C'noreferrer')%3Bi%26%26(i.opener=null)%7D%7D)()%3Bvoid'2.1.0' "Setup UtmStrip" +[Setup UtmStrip]: https://mobilemind.github.io/OpenInlets/x/#javascript:'use%20strict'%3B(()=%3E%7Bconst%20t=location.pathname%2Ce=location.search%3Bif(3%3Ee.length%26%26!t.includes('%2Famp'))return%3Bconst%20i=location.hostname%2Cs=new%20URLSearchParams(e)%2Ca=%5B'assetType'%2C'elqTrack'%2C'mkt%5Ftok'%2C'originalReferer'%2C'referrer'%2C'terminal%5Fid'%2C'trk'%2C'trkCampaign'%2C'trkInfo'%2C'anid'%2C'assetid'%2C'campaignid'%2C'eid'%2C'gclid'%2C'recipientid'%2C'siteid'%2C'sib%5Fcuid'%2C'sib%5Fsid'%2C'%5Fbta%5Ftid'%2C'%5Fbta%5Fc'%2C'%5F%5Fs'%2C'fbclid'%2C'hrc'%2C'igsh'%2C'igshid'%2C'refsrc'%2C'%5Fgl'%2C'gclsrc'%2C'srsltid'%2C'%5Fhsenc'%2C'%5Fhsmi'%2C'%5F%5Fhsfp'%2C'%5F%5Fhssc'%2C'%5F%5Fhstc'%2C'cm%5Fmmc'%2C'cm%5Fre'%2C'cm%5Fsp'%2C'manual%5Fcm%5Fmmc'%2C'%5Fke'%2C'%5Fkx'%2C'trk%5Fcontact'%2C'trk%5Fmsg'%2C'trk%5Fmodule'%2C'trk%5Fsid'%2C'mc%5Fcid'%2C'mc%5Feid'%2C'iesrc'%2C'msclkid'%2C'dclid'%2C'twclid'%2C'ttclid'%2C'oly%5Fenc%5Fid'%2C'oly%5Fanon%5Fid'%2C'epik'%2C'vero%5Fid'%5D%2C%5F=%5B'fb%5F'%2C'action%5F'%2C'ga%5F'%2C'utm%5F'%2C'hmb%5F'%2C'hsa%5F'%2C'mtm%5F'%2C'pk%5F'%2C'oly%5F'%2C'stm%5F'%5D%3B%2F%5C.aliexpress%5C.%5Ba-z%5D%7B2%2C3%7D%24%2F.test(i)%3F(a.push('algo%5Fevid'%2C'algo%5Fpvid'%2C'btsid'%2C'spm'%2C'scm'%2C'ws%5Fab%5Ftest')%2C%5F.push('aff%5F')):%2F(%7C%5C.)amazon%5C.com%24%2F.test(i)%3Fa.push('%5Fencoding'%2C'asc%5Fcampaign'%2C'asc%5Frefurl'%2C'asc%5Fsource'%2C'ascsubtag'%2C'content-id'%2C'crid'%2C'cv%5Fct%5Fcx'%2C'dib%5Ftag'%2C'dib'%2C'ie'%2C'language'%2C'linkCode'%2C'linkId'%2C'pd%5Frd%5Fi'%2C'pd%5Frd%5Fr'%2C'pd%5Frd%5Fw'%2C'pd%5Frd%5Fwg'%2C'pf%5Frd%5Fi'%2C'pf%5Frd%5Fm'%2C'pf%5Frd%5Fp'%2C'pf%5Frd%5Fr'%2C'pf%5Frd%5Fs'%2C'pf%5Frd%5Ft'%2C'pf'%2C'psc'%2C'qid'%2C'ref%5F'%2C'sprefix'%2C'sr'%2C'tag'%2C'th'):i.endsWith('.ebay.com')%7C%7C%2F%5C.ebay%5C.co%5C.%5Ba-z%5D%7B2%7D%24%2F.test(i)%3Fa.push('mkevt'%2C'mkcid'%2C'mkrid'%2C'campid'%2C'toolid'%2C'customid'%2C'norover'%2C'itm'%2C'amdata'):%2F(%5E%7C%5C.)google%5C.(com%7C%5Ba-z%5D%7B2%7D%7Ccom%3F%5C.%5Ba-z%5D%7B2%7D)%24%2F.test(i)%26%26t.startsWith('%2Fsearch')%3Fa.push('aqs'%2C'ei'%2C'gs%5Flp'%2C'gs%5Fssp'%2C'iflsig'%2C'sca%5Fesv'%2C'ved'%2C'oq'%2C'sa'%2C'uact'%2C'rlz'%2C'sxsrf'%2C'bih'%2C'biw'%2C'client'%2C'prmd'%2C'sclient'%2C'source'%2C'sourceid'%2C'ie'%2C'oe'):i.endsWith('.linkedin.com')%3Fa.push('li%5Ffat%5Fid'%2C'licu'%2C'lipi'%2C'midSig'%2C'midToken'%2C'refId'):i.endsWith('.target.com')%3Fa.push('afid'%2C'clkid'%2C'lnm'%2C'preselect'%2C'tref'):i.endsWith('.temu.com')%3F(a.push('%5Fbg%5Ffs'%2C'%5Fp%5Fjump%5Fid'%2C'%5Fp%5Frfs'%2C'refer%5Fpage%5Fid'%2C'refer%5Fpage%5Fname'%2C'refer%5Fpage%5Fsn')%2C%5F.push('%5Fx%5F')):i.endsWith('.tiktok.com')%7C%7C'tiktok.com'===i%3Fa.push('%5Fd'%2C'%5Fr'%2C'%5Ft'%2C'is%5Ffrom%5Fwebapp'%2C'preview%5Fpb'%2C'share%5Fapp%5Fname'%2C'share%5Fitem%5Fid'%2C'tt4d%5Ft'%2C'timestamp'%2C'u%5Fcode'%2C'user%5Fid'):%2F%5C.(twitter%7Cx)%5C.com%24%2F.test(i)%7C%7C%2F%5E(twitter%7Cx)%5C.com%24%2F.test(i)%3Fa.push('cn'%2C'ref%5Fsrc'%2C'ref%5Furl'%2C's'%2C't'):i.endsWith('.walmart.com')%3Fa.push('adsredirect'%2C'affiliates%5Fad%5Fid'%2C'athcpid'%2C'athpgid'%2C'athcgid'%2C'athmtid'%2C'athstid'%2C'athznid'%2C'athiession'%2C'athancid'%2C'athposb'%2C'athena'%2C'campaign%5Fid'%2C'wmlspartner'):(%2F(m%7Cwww)%5C.youtube%5C.com%24%2F.test(i)%7C%7C'youtu.be'===i%7C%7C'www.youtube-nocookie.com'===i)%26%26a.push('ac'%2C'annotation%5Fid'%2C'app'%2C'feature'%2C'gclid'%2C'kw'%2C'src%5Fvid')%3Bconst%20c=new%20Set(a.map(t=%3Et.toLowerCase()))%2Cr=t=%3E%7Bconst%20e=t.toLowerCase()%3Breturn%20c.has(e)%7C%7C%5F.some(t=%3Ee.startsWith(t))%7C%7C%2F%5Ecm%5Fmmca%5Cd%2B%24%2Fi.test(t)%7D%3Bfor(const%20t%20of%5B...s.keys()%5D)r(t)%26%26s.delete(t)%3Blet%20d=s.toString()%3Bd=d%3F'%3F'%2Bd:''%3Bconst%20o=t.replace(%2F%5C%2Famp%5C%2F%3F%24%2F%2C'')%3Bif((e!==d%7C%7Ct!==o)%26%26confirm('Update%20history%20and%20copy%20cleaned%20URL%20to%20clipboard%3F'))%7Bconst%20t=%60%24%7Blocation.protocol%7D%2F%2F%24%7Blocation.host%7D%24%7Bo%7D%24%7Bd%7D%24%7Blocation.hash%7D%60%3Bnavigator.clipboard.writeText(t)%2Chistory.replaceState(null%2C''%2Ct)%3Bconst%20e=window.open(t%2C'%5Fself'%2C'noreferrer')%3Be%26%26(e.opener=null)%7D%7D)()%3Bvoid'2.2.0' "Setup UtmStrip" [Setup unskim]: https://mobilemind.github.io/OpenInlets/x/#javascript:'use%20strict'%3B(()=%3E%7Blet%20e=new%20URL(document.location.href)%3Bif('safari-resource:%2FErrorPage.html'===e.href)%7Bconst%20t=document.querySelector('p.error-message')%3F.textContent%3F.match(%2FSafari%20can't%20open%20the%20page%20%22(https%3F:%5B%5E%22%5D%2B)%22%2F)%3F.%5B1%5D%3Bt%26%26(e=new%20URL(t))%7Dif(''===e.search)return%3Bconst%20t=new%20URLSearchParams(e.search)%2Cr=%5B'url'%2C'destination'%2C'redirect'%2C'target'%2C'goto'%2C'u'%2C'dest'%2C'link'%2C'out'%5D.filter(e=%3Et.has(e)).map(e=%3E%7Bconst%20r=t.get(e)%3Breturn%20r%3FdecodeURIComponent(r):''%7D).find(e=%3Ee.match(%2F%5Ehttps%3F:%2F))%3Br%26%26window.location.replace(new%20URL(r))%7D)()%3Bvoid'2.0.1' "Setup unskim" [Setup x-man]: https://mobilemind.github.io/OpenInlets/x/#javascript:'use%20strict'%3B(()=%3E%7Bconst%20i=navigator.userAgent%2Cn=i.includes('Chrome%2F')%7C%7Ci.includes('Firefox%2F')%7C%7Ci.includes('Brave%2F')%7C%7Ci.includes('Edg%2F')%2Co=i.includes('Safari%2F')%2Ct=!n%26%26!o%2Ca=navigator.platform.startsWith('Mac')%26%26o%26%26!n%26%26!t%26%26!navigator.maxTouchPoints%26%262%3Enavigator.maxTouchPoints%2Ce=window.getSelection()%3Bif(!e)return%3Bconst%20l=e.toString().split('%5Cn')%5B0%5D.trim()%3Blet%20r='x-man-page:%2F%2F'%3Bconst%20c=l.match(%2F%5E(.%2A%3F)%5C((%5Cd)%5C)%24%2F)%3Bif(r%2B=c%3F'1'===c%5B2%5D%3Fc%5B1%5D:%60%24%7Bc%5B2%5D%7D%2F%24%7Bc%5B1%5D%7D%60:l%2Cl)%7Bif(confirm(%60Link%20for%20%22%24%7Bl%7D%22%20is:%20%24%7Br%7D%5Cn%5CnCopy%20to%20clipboard%3F%60))%7Blet%20i=''%3Bif(navigator.clipboard%3Fnavigator.clipboard.writeText(r):(i=%60Unable%20to%20copy%20%22%24%7Br%7D%22%20to%20clipboard.%60%2Cr='')%2Ca%26%26''!==r)%7Blet%20n=null%3Btry%7Bn=window.open(r)%2Cn%26%26(n.opener=null)%7Dcatch(n)%7Bi=%60Popup%20window%20blocked.%20Clipboard%20contains%20%22%24%7Br%7D%22%60%7Dfinally%7Bwindow.focus()%2Cnull!==n%26%26setTimeout(()=%3E%7Bn%26%26n.close()%7D%2C3333)%7D%7Delse''!==r%26%26(i=%60Unable%20to%20open%20new%20link%20with%20Terminal.%20Clipboard%20contains%20%22%24%7Br%7D%22%60)%3B''!==i%26%26alert(i)%7De.empty()%7D%7D)()%3Bvoid'1.3.1' "Setup x-man" diff --git a/SECURITY.md b/SECURITY.md index 527b805..31a5a8c 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -64,8 +64,8 @@ npm version patch # or minor, or major git push --follow-tags # Or manually create and push a signed tag -git tag -s 4.1.0 -m "Release version 4.1.0" -git push origin 4.1.0 +git tag -s 4.1.1 -m "Release version 4.1.1" +git push origin 4.1.1 ``` ## Release Verification @@ -76,10 +76,10 @@ All releases should be signed with GPG/SSH signatures for verification: ```bash # Verify the signature on a release tag -git verify-tag 4.1.0 +git verify-tag 4.1.1 # Show tag details with signature -git tag -v 4.1.0 +git tag -v 4.1.1 ``` ### Verifying Signed Commits diff --git a/bookmarklets.json b/bookmarklets.json index b582370..4b06a98 100644 --- a/bookmarklets.json +++ b/bookmarklets.json @@ -63,7 +63,7 @@ { "name": "UtmStrip", "file": "utmstrip.bookmarklet", - "version": "2.1.0" + "version": "2.2.0" }, { "name": "deLighter", diff --git a/dist/utmstrip.bookmarklet b/dist/utmstrip.bookmarklet index 454a5fc..02b2a94 100644 --- a/dist/utmstrip.bookmarklet +++ b/dist/utmstrip.bookmarklet @@ -1 +1 @@ -javascript:'use%20strict'%3B(()=%3E%7Bconst%20e=location.pathname%2Ci=location.search%3Bif(3%3Ei.length%26%26!e.includes('%2Famp'))return%3Blet%20c=e%2Ct=i%3Bconst%20a=location.hostname%2Cn=(e%2Ci)=%3Ee.replace(i%2C'%241')%3Bif(a.includes('aliexpress.')%26%26(t=n(t%2C%2F(%5B%3F%26%5D)aff%5F(platform%7Ctrace%5Fkey)=%5B%5E%26%5D%2B%2Fgi)%2Ct=n(t%2C%2F(%5B%3F%26%5D)algo%5F%5Bep%5Dvid=%5B%5E%26%5D%2B%2Fg)%2Ct=n(t%2C%2F(%5B%3F%26%5D)(btsid%7Cws%5Fab%5Ftest)=%5B%5E%26%5D%2B%2Fg)%2Ct=n(t%2C%2F(%5B%3F%26%5D)s%5Bcp%5Dm=%5B%5E%26%5D%2B%2Fg))%2C%2F(%7C%5C.)amazon%5C.com%24%2F.test(a)%26%26(t=n(t%2C%2F(%5B%3F%26%5D)(%5Fencoding%7Cie%7ClinkCode%7ClinkId%7Cpf%7Cpsc%7Cref%5F%7Ctag)=%5B%5E%26%5D%2B%2Fgi)%2Ct=n(t%2C%2F(%5B%3F%26%5D)p%5Bdf%5D%5Frd%5F.%2A%3F=%5B%5E%26%5D%2B%2Fgi)%2Ct=n(t%2C%2F(%5B%3F%26%5D)(content-id%7Ccrid%7Ccv%5Fct%5Fcx%7Clanguage%7Cqid%7Csprefix%7Csr%7Cth)=%5B%5E%26%5D%2B%2Fg)%2Ct=n(t%2C%2F(%5B%3F%26%5D)asc(%5Fcampaign%7C%5Frefurl%7C%5Fsource%7Csubtag)=%5B%5E%26%5D%2B%2Fg)%2Ct=n(t%2C%2F(%5B%3F%26%5D)dib(%5Ftag)%3F=%5B%5E%26%5D%2B%2Fg))%2Ct.includes('fb%5F')%26%26(t=n(t%2C%2F(%5B%3F%26%5D)fb%5F(action%5Fids%7Caction%5Ftypes%7Cref%7Csource)=%5B%5E%26%5D%2B%2Fgi)%2Ct=n(t%2C%2F(%5B%3F%26%5D)(fbclid%7Chrc%7Crefsrc)=%5B%5E%26%5D%2B%2Fgi))%2Ct.includes('action%5F')%26%26(t=n(t%2C%2F(%5B%3F%26%5D)action%5F(object%7Cref%7Ctype)%5Fmap=%5B%5E%26%5D%2B%2Fgi))%2Ct=n(t%2C%2F(%5B%3F%26%5D)(assetType%7CelqTrack%7Cmkt%5Ftok%7CoriginalReferer%7Creferrer%7Cterminal%5Fid%7Ctrk%7CtrkCampaign%7CtrkInfo)=%5B%5E%26%5D%2B%2Fgi)%2Ct.toLowerCase().includes('id=')%26%26(t=n(t%2C%2F(%5B%3F%26%5D)(an%7Casset%7Ccampaign%7Ce%7Cgcl%7Crecipient%7Csite)id=%5B%5E%26%5D%2B%2Fgi))%2C(t.includes('ga%5F')%7C%7Ct.includes('utm%5F'))%26%26(t=n(t%2C%2F(%5B%3F%26%5D)(ga%7Cutm)%5F(campaign%7Ccid%7Ccontent%7Cdesign%7Cmedium%7Cname%7Cplace%7Cpubreferrer%7Creader%7Csource%7Cswu%7Cterm%7Cuserid%7Cviz%5Fid)=%5B%5E%26%5D%2B%2Fgi)%2Ct=n(t%2C%2F(%5B%3F%26%5D)gcl(id%7Csrc)=%5B%5E%26%5D%2B%2Fgi))%2C(%2F(m%7Cwww)%5C.youtube%5C.com%24%2F.test(a)%7C%7C'youtu.be'===a%7C%7C'www.youtube-nocookie.com'===a)%26%26(t=n(t%2C%2F(%5B%3F%26%5D)(ac%7Cannotation%5Fid%7Capp%7Cfeature%7Cgclid%7Ckw%7Csrc%5Fvid)=%5B%5E%26%5D%2B%2Fgi))%2C%2F%5B%3F%26%5D%5Fhs(enc%7Cmi)=%2F.test(t)%26%26(t=n(t%2C%2F(%5B%3F%26%5D)%5Fhs(enc%7Cmi)=%5B%5E%26%5D%2B%2Fgi))%2Ct.includes('hmb%5F')%26%26(t=n(t%2C%2F(%5B%3F%26%5D)hmb%5F(campaign%7Cmedium%7Csource)=%5B%5E%26%5D%2B%2Fgi))%2Ct.includes('cm%5F')%26%26(t=n(t%2C%2F(%5B%3F%26%5D)cm%5F(mmc%7Cmmca%5Cd%2B%7Cre%7Csp)=%5B%5E%26%5D%2B%2Fgi)%2Ct=n(t%2C%2F(%5B%3F%26%5D)manual%5Fcm%5Fmmc=%5B%5E%26%5D%2B%2Fgi))%2C%2F%5B%3F%26%5Dmc%5F%5Bce%5Did=%2F.test(t)%26%26(t=n(t%2C%2F(%5B%3F%26%5D)mc%5F%5Bce%5Did=%5B%5E%26%5D%2B%2Fgi))%2C%2F%5B%3F%26%5D(iesrc%7Cmkt%5Ftok)=%2F.test(t)%26%26(t=n(t%2C%2F(%5B%3F%26%5D)(iesrc%7Cmkt%5Ftok)=%5B%5E%26%5D%2B%2Fgi))%2Ct.includes('pk%5F')%26%26(t=n(t%2C%2F(%5B%3F%26%5D)pk%5F(campaign%7Ccontent%7Ckwd%7Cmedium%7Csource)=%5B%5E%26%5D%2B%2Fgi))%2Ct=t.replace(%2F%26%26%2B%2Fg%2C'%26').replace(%2F%26%24%2F%2C'')%2Ct='%3F'===t%5B0%5D%3Ft.replace(%2F%5E%5C%3F%26%2F%2C'%3F'):'%3F'%2Bt%2Ct=3%3Et.length%3F'':t%2Cc=c.replace(%2F%5C%2Famp%5C%2F%3F%24%2F%2C'')%2C(i!==t%7C%7Ce!==c)%26%26confirm('Update%20history%20and%20copy%20cleaned%20URL%20to%20clipboard%3F'))%7Bconst%20e=%60%24%7Blocation.protocol%7D%2F%2F%24%7Blocation.host%7D%24%7Bc%7D%24%7Bt%7D%24%7Blocation.hash%7D%60%3Bnavigator.clipboard.writeText(e)%2Chistory.replaceState(null%2C''%2Ce)%3Bconst%20i=window.open(e%2C'%5Fself'%2C'noreferrer')%3Bi%26%26(i.opener=null)%7D%7D)()%3Bvoid'2.1.0' \ No newline at end of file +javascript:'use%20strict'%3B(()=%3E%7Bconst%20t=location.pathname%2Ce=location.search%3Bif(3%3Ee.length%26%26!t.includes('%2Famp'))return%3Bconst%20i=location.hostname%2Cs=new%20URLSearchParams(e)%2Ca=%5B'assetType'%2C'elqTrack'%2C'mkt%5Ftok'%2C'originalReferer'%2C'referrer'%2C'terminal%5Fid'%2C'trk'%2C'trkCampaign'%2C'trkInfo'%2C'anid'%2C'assetid'%2C'campaignid'%2C'eid'%2C'gclid'%2C'recipientid'%2C'siteid'%2C'sib%5Fcuid'%2C'sib%5Fsid'%2C'%5Fbta%5Ftid'%2C'%5Fbta%5Fc'%2C'%5F%5Fs'%2C'fbclid'%2C'hrc'%2C'igsh'%2C'igshid'%2C'refsrc'%2C'%5Fgl'%2C'gclsrc'%2C'srsltid'%2C'%5Fhsenc'%2C'%5Fhsmi'%2C'%5F%5Fhsfp'%2C'%5F%5Fhssc'%2C'%5F%5Fhstc'%2C'cm%5Fmmc'%2C'cm%5Fre'%2C'cm%5Fsp'%2C'manual%5Fcm%5Fmmc'%2C'%5Fke'%2C'%5Fkx'%2C'trk%5Fcontact'%2C'trk%5Fmsg'%2C'trk%5Fmodule'%2C'trk%5Fsid'%2C'mc%5Fcid'%2C'mc%5Feid'%2C'iesrc'%2C'msclkid'%2C'dclid'%2C'twclid'%2C'ttclid'%2C'oly%5Fenc%5Fid'%2C'oly%5Fanon%5Fid'%2C'epik'%2C'vero%5Fid'%5D%2C%5F=%5B'fb%5F'%2C'action%5F'%2C'ga%5F'%2C'utm%5F'%2C'hmb%5F'%2C'hsa%5F'%2C'mtm%5F'%2C'pk%5F'%2C'oly%5F'%2C'stm%5F'%5D%3B%2F%5C.aliexpress%5C.%5Ba-z%5D%7B2%2C3%7D%24%2F.test(i)%3F(a.push('algo%5Fevid'%2C'algo%5Fpvid'%2C'btsid'%2C'spm'%2C'scm'%2C'ws%5Fab%5Ftest')%2C%5F.push('aff%5F')):%2F(%7C%5C.)amazon%5C.com%24%2F.test(i)%3Fa.push('%5Fencoding'%2C'asc%5Fcampaign'%2C'asc%5Frefurl'%2C'asc%5Fsource'%2C'ascsubtag'%2C'content-id'%2C'crid'%2C'cv%5Fct%5Fcx'%2C'dib%5Ftag'%2C'dib'%2C'ie'%2C'language'%2C'linkCode'%2C'linkId'%2C'pd%5Frd%5Fi'%2C'pd%5Frd%5Fr'%2C'pd%5Frd%5Fw'%2C'pd%5Frd%5Fwg'%2C'pf%5Frd%5Fi'%2C'pf%5Frd%5Fm'%2C'pf%5Frd%5Fp'%2C'pf%5Frd%5Fr'%2C'pf%5Frd%5Fs'%2C'pf%5Frd%5Ft'%2C'pf'%2C'psc'%2C'qid'%2C'ref%5F'%2C'sprefix'%2C'sr'%2C'tag'%2C'th'):i.endsWith('.ebay.com')%7C%7C%2F%5C.ebay%5C.co%5C.%5Ba-z%5D%7B2%7D%24%2F.test(i)%3Fa.push('mkevt'%2C'mkcid'%2C'mkrid'%2C'campid'%2C'toolid'%2C'customid'%2C'norover'%2C'itm'%2C'amdata'):%2F(%5E%7C%5C.)google%5C.(com%7C%5Ba-z%5D%7B2%7D%7Ccom%3F%5C.%5Ba-z%5D%7B2%7D)%24%2F.test(i)%26%26t.startsWith('%2Fsearch')%3Fa.push('aqs'%2C'ei'%2C'gs%5Flp'%2C'gs%5Fssp'%2C'iflsig'%2C'sca%5Fesv'%2C'ved'%2C'oq'%2C'sa'%2C'uact'%2C'rlz'%2C'sxsrf'%2C'bih'%2C'biw'%2C'client'%2C'prmd'%2C'sclient'%2C'source'%2C'sourceid'%2C'ie'%2C'oe'):i.endsWith('.linkedin.com')%3Fa.push('li%5Ffat%5Fid'%2C'licu'%2C'lipi'%2C'midSig'%2C'midToken'%2C'refId'):i.endsWith('.target.com')%3Fa.push('afid'%2C'clkid'%2C'lnm'%2C'preselect'%2C'tref'):i.endsWith('.temu.com')%3F(a.push('%5Fbg%5Ffs'%2C'%5Fp%5Fjump%5Fid'%2C'%5Fp%5Frfs'%2C'refer%5Fpage%5Fid'%2C'refer%5Fpage%5Fname'%2C'refer%5Fpage%5Fsn')%2C%5F.push('%5Fx%5F')):i.endsWith('.tiktok.com')%7C%7C'tiktok.com'===i%3Fa.push('%5Fd'%2C'%5Fr'%2C'%5Ft'%2C'is%5Ffrom%5Fwebapp'%2C'preview%5Fpb'%2C'share%5Fapp%5Fname'%2C'share%5Fitem%5Fid'%2C'tt4d%5Ft'%2C'timestamp'%2C'u%5Fcode'%2C'user%5Fid'):%2F%5C.(twitter%7Cx)%5C.com%24%2F.test(i)%7C%7C%2F%5E(twitter%7Cx)%5C.com%24%2F.test(i)%3Fa.push('cn'%2C'ref%5Fsrc'%2C'ref%5Furl'%2C's'%2C't'):i.endsWith('.walmart.com')%3Fa.push('adsredirect'%2C'affiliates%5Fad%5Fid'%2C'athcpid'%2C'athpgid'%2C'athcgid'%2C'athmtid'%2C'athstid'%2C'athznid'%2C'athiession'%2C'athancid'%2C'athposb'%2C'athena'%2C'campaign%5Fid'%2C'wmlspartner'):(%2F(m%7Cwww)%5C.youtube%5C.com%24%2F.test(i)%7C%7C'youtu.be'===i%7C%7C'www.youtube-nocookie.com'===i)%26%26a.push('ac'%2C'annotation%5Fid'%2C'app'%2C'feature'%2C'gclid'%2C'kw'%2C'src%5Fvid')%3Bconst%20c=new%20Set(a.map(t=%3Et.toLowerCase()))%2Cr=t=%3E%7Bconst%20e=t.toLowerCase()%3Breturn%20c.has(e)%7C%7C%5F.some(t=%3Ee.startsWith(t))%7C%7C%2F%5Ecm%5Fmmca%5Cd%2B%24%2Fi.test(t)%7D%3Bfor(const%20t%20of%5B...s.keys()%5D)r(t)%26%26s.delete(t)%3Blet%20d=s.toString()%3Bd=d%3F'%3F'%2Bd:''%3Bconst%20o=t.replace(%2F%5C%2Famp%5C%2F%3F%24%2F%2C'')%3Bif((e!==d%7C%7Ct!==o)%26%26confirm('Update%20history%20and%20copy%20cleaned%20URL%20to%20clipboard%3F'))%7Bconst%20t=%60%24%7Blocation.protocol%7D%2F%2F%24%7Blocation.host%7D%24%7Bo%7D%24%7Bd%7D%24%7Blocation.hash%7D%60%3Bnavigator.clipboard.writeText(t)%2Chistory.replaceState(null%2C''%2Ct)%3Bconst%20e=window.open(t%2C'%5Fself'%2C'noreferrer')%3Be%26%26(e.opener=null)%7D%7D)()%3Bvoid'2.2.0' \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index b8620a9..f22cb41 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "OpenInlets", - "version": "4.1.0", + "version": "4.1.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "OpenInlets", - "version": "4.1.0", + "version": "4.1.1", "license": "MIT", "devDependencies": { "@eslint/js": "9.39.2", diff --git a/package.json b/package.json index 7b281e6..1f09acb 100644 --- a/package.json +++ b/package.json @@ -59,5 +59,5 @@ "test": "npm run build && npm run verify-build", "verify-build": "node scripts/verify-build.js" }, - "version": "4.1.0" + "version": "4.1.1" } diff --git a/scripts/test-utmstrip.js b/scripts/test-utmstrip.js new file mode 100644 index 0000000..b054ae0 --- /dev/null +++ b/scripts/test-utmstrip.js @@ -0,0 +1,223 @@ +#!/usr/bin/env node +/* eslint no-plusplus: 0 */ +// cSpell:words Bronto Klaviyo Listrak Omeda +/* cSpell: ignore afid amdata anid ascsubtag assetid athancid athcgid athcpid athiession athmtid athpgid athposb athstid athznid btsid campaignid campid clkid crid customid dclid epik evid fbclid gclid gclsrc hsenc hsfp hsmi hssc hstc iesrc iflsig igsh igshid licu lipi mkcid mkevt mkrid mmca msclkid prmd pvid recipientid sclient siteid sourceid sprefix srsltid sxsrf ttclid twclid uact wmlspartner youtu */ +/** + * Test utmstrip.ts logic against test URL corpus + * Run: node scripts/test-utmstrip.js + */ +const testData = require('../tests/utmstrip-test-urls.json'); + +// Replicate the shouldDelete logic from utmstrip.ts +const universalExact = [ + // Generic tracking + 'assetType', 'elqTrack', 'mkt_tok', 'originalReferer', 'referrer', + 'terminal_id', 'trk', 'trkCampaign', 'trkInfo', + // *id suffix params + 'anid', 'assetid', 'campaignid', 'eid', 'gclid', 'recipientid', 'siteid', + // Brevo/Sendinblue + 'sib_cuid', 'sib_sid', + // Bronto (Oracle) + '_bta_c', '_bta_tid', + // Drip + '__s', + // Facebook/Instagram + 'fbclid', 'hrc', 'igsh', 'igshid', 'refsrc', + // Google Analytics + '_gl', 'gclsrc', 'srsltid', + // HubSpot + '_hsenc', '_hsmi', '__hsfp', '__hssc', '__hstc', + // IBM (non-numeric only) + 'cm_mmc', 'cm_re', 'cm_sp', 'manual_cm_mmc', + // Klaviyo + '_ke', '_kx', + // Listrak + 'trk_contact', 'trk_module', 'trk_msg', 'trk_sid', + // MailChimp + 'mc_cid', 'mc_eid', + // Marketo + 'iesrc', + // Microsoft & ad platform click IDs + 'dclid', 'msclkid', 'ttclid', 'twclid', + // Omeda + 'oly_anon_id', 'oly_enc_id', + // Pinterest + 'epik', + // Vero + 'vero_id' +]; + +const universalPrefixes = [ + // Facebook: fb_action_ids, fb_action_types, fb_ref, fb_source & action_* + 'action_', 'fb_', + // Google Analytics + 'ga_', 'utm_', + // HubSpot + 'hmb_', 'hsa_', + // Matomo + 'mtm_', 'pk_', + // Sailthru email + 'stm_', + // Omeda + 'oly_' +]; + +const aliexpressExact = ['algo_evid', 'algo_pvid', 'btsid', 'scm', 'spm', 'ws_ab_test']; +const aliexpressPrefixes = ['aff_']; + +const amazonExact = [ + '_encoding', 'asc_campaign', 'asc_refurl', 'asc_source', 'ascsubtag', + 'content-id', 'crid', 'cv_ct_cx', 'dib_tag', 'dib', 'ie', 'language', + 'linkCode', 'linkId', 'pd_rd_i', 'pd_rd_r', 'pd_rd_w', 'pd_rd_wg', 'pf_rd_i', + 'pf_rd_m', 'pf_rd_p', 'pf_rd_r', 'pf_rd_s', 'pf_rd_t', 'pf', 'psc', 'qid', + 'ref_', 'sprefix', 'sr', 'tag', 'th' +]; + +const youtubeExact = ['ac', 'annotation_id', 'app', 'feature', 'gclid', 'kw', 'src_vid']; + +// Host-specific: eBay +const ebayExact = [ + 'amdata', 'campid', 'customid', 'itm', 'mkcid', 'mkevt', 'mkrid', 'norover', 'toolid' +]; + +// Host-specific: LinkedIn +const linkedinExact = ['li_fat_id', 'licu', 'lipi', 'midSig', 'midToken', 'refId']; + +// Host-specific: Google Search (only on /search path) +const googleSearchExact = [ + // Session/tracking identifiers + 'ei', 'ved', 'iflsig', 'sca_esv', 'aqs', 'gs_lp', 'gs_ssp', + // Query tracking + 'oq', 'sa', 'uact', + // Distribution/client tracking + 'rlz', 'sxsrf', + // Browser/client info (clutter) + 'bih', 'biw', 'client', 'prmd', 'sclient', 'source', 'sourceid', + // Encoding params (clutter) + 'ie', 'oe' +]; + +// Host-specific: Target +const targetExact = ['afid', 'clkid', 'lnm', 'tref', 'preselect']; + +// Host-specific: Temu +const temuExact = [ + '_bg_fs', '_p_jump_id', '_p_rfs', 'refer_page_id', 'refer_page_name', 'refer_page_sn' +]; +const temuPrefixes = ['_x_']; + +// Host-specific: TikTok +const tiktokExact = [ + '_d', '_r', '_t', 'is_from_webapp', 'preview_pb', 'share_app_name', 'share_item_id', + 'timestamp', 'tt4d_t', 'u_code', 'user_id', +]; + +// Host-specific: Twitter/X +const twitterExact = ['cn', 'ref_src', 'ref_url', 's', 't']; + +// Host-specific: Walmart +const walmartExact = [ + 'adsredirect', 'affiliates_ad_id', 'athancid', 'athcgid', 'athcpid', + 'athena', 'athiession', 'athmtid', 'athpgid', 'athposb', 'athstid', + 'athznid', 'campaign_id', 'wmlspartner' +]; + + +function stripUrl(inputUrl) { + const url = new URL(inputUrl); + const locSearch = url.search; + const locPath = url.pathname; + + // Early exit if nothing to strip + if (locSearch.length < 3 && !locPath.includes('/amp')) { + return inputUrl; + } + + const params = new URLSearchParams(locSearch); + const host = url.hostname; + + // Build combined param lists based on host + const exactParams = [...universalExact]; + const prefixParams = [...universalPrefixes]; + + if ((/\.aliexpress\.[a-z]{2,3}$/).test(host)) { + exactParams.push(...aliexpressExact); + prefixParams.push(...aliexpressPrefixes); + } else if ((/(|\.)amazon\.com$/).test(host)) { + exactParams.push(...amazonExact); + } else if (host.endsWith('.ebay.com') || (/\.ebay\.co\.[a-z]{2}$/).test(host)) { + exactParams.push(...ebayExact); + } else if ((/(^|\.)google\.(com|[a-z]{2}|com?\.[a-z]{2})$/).test(host) && locPath.startsWith('/search')) { + exactParams.push(...googleSearchExact); + } else if (host.endsWith('.linkedin.com')) { + exactParams.push(...linkedinExact); + } else if (host.endsWith('.target.com')) { + exactParams.push(...targetExact); + } else if (host.endsWith('.temu.com')) { + exactParams.push(...temuExact); + prefixParams.push(...temuPrefixes); + } else if (host.endsWith('.tiktok.com') || host === 'tiktok.com') { + exactParams.push(...tiktokExact); + } else if ((/\.(twitter|x)\.com$/).test(host) || (/^(twitter|x)\.com$/).test(host)) { + exactParams.push(...twitterExact); + } else if (host.endsWith('.walmart.com')) { + exactParams.push(...walmartExact); + } else if ((/(m|www)\.youtube\.com$/).test(host) || + host === 'youtu.be' || host === 'www.youtube-nocookie.com') { + exactParams.push(...youtubeExact); + } + + // Convert to lowercase Set for O(1) lookup + const exactSet = new Set(exactParams.map(p => p.toLowerCase())); + + const shouldDelete = (key) => { + const k = key.toLowerCase(); + if (exactSet.has(k)) { + return true; + } else if (prefixParams.some(p => k.startsWith(p))) { + return true; + } else if (/^cm_mmca\d+$/i.test(key)) { + return true; + } + return false; + }; + + for (const key of [...params.keys()]) { + if (shouldDelete(key)) { + params.delete(key); + } + } + + let searchStr = params.toString(); + searchStr = searchStr ? `?${searchStr}` : ''; + + const pathStr = url.pathname.replace(/\/amp\/?$/, ''); + + return `${url.protocol}//${url.host}${pathStr}${searchStr}${url.hash}`; +} + +// Run tests +let passed = 0; +let failed = 0; + +console.log('Testing UTMStrip refactored logic...\n'); + +for (const test of testData.testCases) { + const result = stripUrl(test.input); + const ok = result === test.expected; + + if (ok) { + passed++; + console.log(`✓ ${test.name}`); + } else { + failed++; + console.log(`✗ ${test.name}`); + console.log(` Input: ${test.input}`); + console.log(` Expected: ${test.expected}`); + console.log(` Got: ${result}`); + console.log(` Note: ${test.note}`); + } +} + +console.log(`\n${passed} passed, ${failed} failed out of ${testData.testCases.length} tests`); +process.exit(failed > 0 ? 1 : 0); diff --git a/src/utmstrip.ts b/src/utmstrip.ts index 96216d7..abad76f 100644 --- a/src/utmstrip.ts +++ b/src/utmstrip.ts @@ -1,5 +1,5 @@ -/* eslint max-statements: ["error", 65] */ -/* cSpell:ignore hsenc, hsmi, iesrc, Matomo, youtu */ +/* eslint max-statements: ["error", 55] */ +/* cSpell: ignore afid amdata anid ascsubtag assetid athancid athcgid athcpid athiession athmtid athpgid athposb athstid athznid btsid campaignid campid clkid crid customid dclid epik evid fbclid gclid gclsrc hsenc hsfp hsmi hssc hstc iesrc iflsig igsh igshid licu lipi mkcid mkevt mkrid mmca msclkid prmd pvid recipientid sclient siteid sourceid sprefix srsltid sxsrf ttclid twclid uact wmlspartner youtu */ (() => { const locPath: string = location.pathname, locSearch: string = location.search; @@ -7,78 +7,180 @@ if (locSearch.length < 3 && !locPath.includes('/amp')) { return; } - let pathStr: string = locPath, - searchStr: string = locSearch; - const hostStr: string = location.hostname, - strip = (s: string, p: RegExp): string => s.replace(p, '$1'); - // AliExpress trackers - if (hostStr.includes('aliexpress.')) { - searchStr = strip(searchStr, /([?&])aff_(platform|trace_key)=[^&]+/ig); - searchStr = strip(searchStr, /([?&])algo_[ep]vid=[^&]+/g); - searchStr = strip(searchStr, /([?&])(btsid|ws_ab_test)=[^&]+/g); - searchStr = strip(searchStr, /([?&])s[cp]m=[^&]+/g); + const host: string = location.hostname; + const params = new URLSearchParams(locSearch); + + // Universal exact-match params to strip (all hosts) + const universalExact: string[] = [ + // Generic tracking + 'assetType', 'elqTrack', 'mkt_tok', 'originalReferer', 'referrer', + 'terminal_id', 'trk', 'trkCampaign', 'trkInfo', + // *id suffix params + 'anid', 'assetid', 'campaignid', 'eid', 'gclid', 'recipientid', 'siteid', + // Brevo/Sendinblue + 'sib_cuid', 'sib_sid', + // Bronto (Oracle) + '_bta_tid', '_bta_c', + // Drip + '__s', + // Facebook/Instagram + 'fbclid', 'hrc', 'igsh', 'igshid', 'refsrc', + // Google Analytics + '_gl', 'gclsrc', 'srsltid', + // HubSpot + '_hsenc', '_hsmi', '__hsfp', '__hssc', '__hstc', + // IBM (non-numeric only) + 'cm_mmc', 'cm_re', 'cm_sp', 'manual_cm_mmc', + // Klaviyo + '_ke', '_kx', + // Listrak + 'trk_contact', 'trk_msg', 'trk_module', 'trk_sid', + // MailChimp + 'mc_cid', 'mc_eid', + // Marketo + 'iesrc', + // Microsoft & ad platform click IDs + 'msclkid', 'dclid', 'twclid', 'ttclid', + // Omeda + 'oly_enc_id', 'oly_anon_id', + // Pinterest + 'epik', + // Vero + 'vero_id' + ]; + + // Universal prefix params to strip + const universalPrefixes: string[] = [ + // Facebook: fb_action_ids, fb_action_types, fb_ref, fb_source & action_* + 'fb_', 'action_', + // Google Analytics + 'ga_', 'utm_', + // HubSpot + 'hmb_', 'hsa_', + // Matomo + 'mtm_','pk_', + // Omeda + 'oly_', + // Sailthru email + 'stm_' + ]; + + // Host-specific rules + const aliexpressExact: string[] = ['algo_evid', 'algo_pvid', 'btsid', 'spm', 'scm', 'ws_ab_test']; + const aliexpressPrefixes: string[] = ['aff_']; + + const amazonExact: string[] = [ + '_encoding', 'asc_campaign', 'asc_refurl', 'asc_source', 'ascsubtag', 'content-id', 'crid', + 'cv_ct_cx', 'dib_tag', 'dib', 'ie', 'language', 'linkCode', 'linkId', 'pd_rd_i', 'pd_rd_r', + 'pd_rd_w', 'pd_rd_wg', 'pf_rd_i', 'pf_rd_m', 'pf_rd_p', 'pf_rd_r', 'pf_rd_s', 'pf_rd_t', + 'pf', 'psc', 'qid', 'ref_', 'sprefix', 'sr', 'tag', 'th' + ]; + + const youtubeExact: string[] = ['ac', 'annotation_id', 'app', 'feature', 'gclid', 'kw', 'src_vid']; + + // Host-specific: Walmart + const walmartExact: string[] = [ + 'adsredirect', 'affiliates_ad_id', 'athcpid', 'athpgid', 'athcgid', 'athmtid', 'athstid', + 'athznid', 'athiession', 'athancid', 'athposb', 'athena', 'campaign_id', 'wmlspartner' + ]; + + // Host-specific: Target + const targetExact: string[] = ['afid', 'clkid', 'lnm', 'preselect', 'tref']; + + // Host-specific: Temu + const temuExact: string[] = [ + '_bg_fs', '_p_jump_id', '_p_rfs', 'refer_page_id', 'refer_page_name', 'refer_page_sn' + ]; + const temuPrefixes: string[] = ['_x_']; + + // Host-specific: eBay + const ebayExact: string[] = [ + 'mkevt', 'mkcid', 'mkrid', 'campid', 'toolid', 'customid', + 'norover', 'itm', 'amdata' + ]; + + // Host-specific: Twitter/X + const twitterExact: string[] = ['cn', 'ref_src', 'ref_url', 's', 't']; + + // Host-specific: LinkedIn + const linkedinExact: string[] = ['li_fat_id', 'licu', 'lipi', 'midSig', 'midToken', 'refId']; + + // Host-specific: Google Search (only on /search path) + const googleSearchExact: string[] = [ + // Session/tracking identifiers + 'aqs', 'ei', 'gs_lp', 'gs_ssp', 'iflsig', 'sca_esv', 'ved', + // Query tracking + 'oq', 'sa', 'uact', + // Distribution/client tracking + 'rlz', 'sxsrf', + // Browser/client info (clutter) + 'bih', 'biw', 'client', 'prmd', 'sclient', 'source', 'sourceid', + // Encoding params (clutter) + 'ie', 'oe' + ]; + + // Host-specific: TikTok + const tiktokExact: string[] = [ + '_d', '_r', '_t', 'is_from_webapp', 'preview_pb', 'share_app_name', + 'share_item_id', 'tt4d_t', 'timestamp', 'u_code', 'user_id' + ]; + + // Build combined param lists based on host + const exactParams: string[] = [...universalExact]; + const prefixParams: string[] = [...universalPrefixes]; + + // Host-specific additions + if ((/\.aliexpress\.[a-z]{2,3}$/).test(host)) { + exactParams.push(...aliexpressExact); + prefixParams.push(...aliexpressPrefixes); + } else if ((/(|\.)amazon\.com$/).test(host)) { + exactParams.push(...amazonExact); + } else if (host.endsWith('.ebay.com') || (/\.ebay\.co\.[a-z]{2}$/).test(host)) { + exactParams.push(...ebayExact); + } else if ((/(^|\.)google\.(com|[a-z]{2}|com?\.[a-z]{2})$/).test(host) && locPath.startsWith('/search')) { + exactParams.push(...googleSearchExact); + } else if (host.endsWith('.linkedin.com')) { + exactParams.push(...linkedinExact); + } else if (host.endsWith('.target.com')) { + exactParams.push(...targetExact); + } else if (host.endsWith('.temu.com')) { + exactParams.push(...temuExact); + prefixParams.push(...temuPrefixes); + } else if (host.endsWith('.tiktok.com') || host === 'tiktok.com') { + exactParams.push(...tiktokExact); + } else if ((/\.(twitter|x)\.com$/).test(host) || (/^(twitter|x)\.com$/).test(host)) { + exactParams.push(...twitterExact); + } else if (host.endsWith('.walmart.com')) { + exactParams.push(...walmartExact); + } else if ((/(m|www)\.youtube\.com$/).test(host) || + host === 'youtu.be' || host === 'www.youtube-nocookie.com') { + exactParams.push(...youtubeExact); } - // Amazon referrals - if ((/(|\.)amazon\.com$/).test(hostStr)) { - searchStr = strip(searchStr, /([?&])(_encoding|ie|linkCode|linkId|pf|psc|ref_|tag)=[^&]+/ig); - searchStr = strip(searchStr, /([?&])p[df]_rd_.*?=[^&]+/ig); - searchStr = strip(searchStr, /([?&])(content-id|crid|cv_ct_cx|language|qid|sprefix|sr|th)=[^&]+/g); - searchStr = strip(searchStr, /([?&])asc(_campaign|_refurl|_source|subtag)=[^&]+/g); - searchStr = strip(searchStr, /([?&])dib(_tag)?=[^&]+/g); - } - // Facebook - if (searchStr.includes('fb_')) { - searchStr = strip(searchStr, /([?&])fb_(action_ids|action_types|ref|source)=[^&]+/ig); - searchStr = strip(searchStr, /([?&])(fbclid|hrc|refsrc)=[^&]+/ig); - } - if (searchStr.includes('action_')) { - searchStr = strip(searchStr, /([?&])action_(object|ref|type)_map=[^&]+/ig); - } - // generic/general - searchStr = strip(searchStr, /([?&])(assetType|elqTrack|mkt_tok|originalReferer|referrer|terminal_id|trk|trkCampaign|trkInfo)=[^&]+/ig); - if (searchStr.toLowerCase().includes('id=')) { - searchStr = strip(searchStr, /([?&])(an|asset|campaign|e|gcl|recipient|site)id=[^&]+/ig); - } - // Google Analytics - if (searchStr.includes('ga_') || searchStr.includes('utm_')) { - searchStr = strip(searchStr, /([?&])(ga|utm)_(campaign|cid|content|design|medium|name|place|pubreferrer|reader|source|swu|term|userid|viz_id)=[^&]+/ig); - searchStr = strip(searchStr, /([?&])gcl(id|src)=[^&]+/ig); - } - // Google YouTube (handles youtube.com, youtu.be, etc.) - if ((/(m|www)\.youtube\.com$/).test(hostStr) || hostStr === 'youtu.be' || hostStr === 'www.youtube-nocookie.com') { - searchStr = strip(searchStr, /([?&])(ac|annotation_id|app|feature|gclid|kw|src_vid)=[^&]+/ig); - } - // HubSpot - if (/[?&]_hs(enc|mi)=/.test(searchStr)) { - searchStr = strip(searchStr, /([?&])_hs(enc|mi)=[^&]+/ig); - } - if (searchStr.includes('hmb_')) { - searchStr = strip(searchStr, /([?&])hmb_(campaign|medium|source)=[^&]+/ig); - } - // IBM Digital Analytics (Coremetrics) - if (searchStr.includes('cm_')) { - searchStr = strip(searchStr, /([?&])cm_(mmc|mmca\d+|re|sp)=[^&]+/ig); - searchStr = strip(searchStr, /([?&])manual_cm_mmc=[^&]+/ig); - } - // MailChimp - if (/[?&]mc_[ce]id=/.test(searchStr)) { - searchStr = strip(searchStr, /([?&])mc_[ce]id=[^&]+/ig); - } - // Marketo - if (/[?&](iesrc|mkt_tok)=/.test(searchStr)) { - searchStr = strip(searchStr, /([?&])(iesrc|mkt_tok)=[^&]+/ig); - } - // Matomo - if (searchStr.includes('pk_')) { - searchStr = strip(searchStr, /([?&])pk_(campaign|content|kwd|medium|source)=[^&]+/ig); + + // Convert to lowercase Set for O(1) lookup + const exactSet: Set = new Set(exactParams.map(p => p.toLowerCase())); + + // Check if param should be deleted + const shouldDelete = (key: string): boolean => { + const k: string = key.toLowerCase(); + return (exactSet.has(k) || prefixParams.some(p => k.startsWith(p)) || (/^cm_mmca\d+$/i.test(key))); + }; + + // Iterate and delete matching params + for (const key of [...params.keys()]) { + if (shouldDelete(key)) { + params.delete(key); + } } - // clean-up: reduce run of '&', remove trailing '&', fix leading '?' - searchStr = searchStr.replace(/&&+/g, '&').replace(/&$/, ''); - searchStr = searchStr[0] === '?' ? searchStr.replace(/^\?&/, '?') : `?${searchStr}`; - searchStr = searchStr.length < 3 ? '' : searchStr; - // clean-up '/amp/' in pathname - pathStr = pathStr.replace(/\/amp\/?$/, ''); - // if changed replace location with stripped version + + // Reconstruct search string + let searchStr: string = params.toString(); + searchStr = searchStr ? `?${searchStr}` : ''; + + // Clean up '/amp/' in pathname + const pathStr: string = locPath.replace(/\/amp\/?$/, ''); + + // If changed, replace location with stripped version if (locSearch !== searchStr || locPath !== pathStr) { if (confirm('Update history and copy cleaned URL to clipboard?')) { const newURL: string = `${location.protocol}//${location.host}${pathStr}${searchStr}${location.hash}`; diff --git a/tests/utmstrip-test-urls.json b/tests/utmstrip-test-urls.json new file mode 100644 index 0000000..abc0c4f --- /dev/null +++ b/tests/utmstrip-test-urls.json @@ -0,0 +1,455 @@ +{ + "description": "Test URLs for utmstrip.ts refactor validation", + "version": "1.0.0", + "testCases": [ + { + "name": "Amazon - user provided example", + "category": "amazon", + "input": "https://www.amazon.com/s?k=5+mm+lead+holder+and+refills&crid=13ICN6SZ22528&sprefix=5+mm+lead+holder+and+refills%2Caps%2C182&ref=nb_sb_noss", + "expected": "https://www.amazon.com/s?k=5+mm+lead+holder+and+refills&ref=nb_sb_noss", + "note": "crid and sprefix should be stripped, k and ref preserved" + }, + { + "name": "Amazon - pd_rd parameters", + "category": "amazon", + "input": "https://www.amazon.com/dp/B08N5WRWNW?pd_rd_i=B08N5WRWNW&pd_rd_r=abc123&pd_rd_w=xyz&pd_rd_wg=456", + "expected": "https://www.amazon.com/dp/B08N5WRWNW", + "note": "All pd_rd_* params should be stripped" + }, + { + "name": "Amazon - pf_rd parameters", + "category": "amazon", + "input": "https://www.amazon.com/dp/B08N5WRWNW?pf_rd_i=desktop&pf_rd_m=ATVPDKIKX0DER&pf_rd_p=abc&pf_rd_r=xyz&pf_rd_s=slot&pf_rd_t=type", + "expected": "https://www.amazon.com/dp/B08N5WRWNW", + "note": "All pf_rd_* params should be stripped" + }, + { + "name": "Amazon - mixed tracking params", + "category": "amazon", + "input": "https://www.amazon.com/dp/B08N5WRWNW?_encoding=UTF8&ie=UTF8&linkCode=ll1&linkId=abc123&pf=1&psc=1&ref_=nav_logo&tag=mytag-20", + "expected": "https://www.amazon.com/dp/B08N5WRWNW", + "note": "All Amazon tracking params should be stripped" + }, + { + "name": "Amazon - content and search params", + "category": "amazon", + "input": "https://www.amazon.com/s?k=laptop&content-id=123&cv_ct_cx=laptop&language=en_US&qid=1234567890&sr=8-1&th=1", + "expected": "https://www.amazon.com/s?k=laptop", + "note": "content-id, cv_ct_cx, language, qid, sr, th should be stripped" + }, + { + "name": "Amazon - asc and dib params", + "category": "amazon", + "input": "https://www.amazon.com/dp/B08N5WRWNW?asc_campaign=test&asc_refurl=http://example.com&asc_source=web&ascsubtag=abc&dib=eyJ2IjoiMSJ9&dib_tag=se", + "expected": "https://www.amazon.com/dp/B08N5WRWNW", + "note": "asc_* and dib* params should be stripped" + }, + { + "name": "AliExpress - aff params", + "category": "aliexpress", + "input": "https://www.aliexpress.com/item/123.html?aff_platform=link&aff_trace_key=abc123&algo_evid=xyz&algo_pvid=456", + "expected": "https://www.aliexpress.com/item/123.html", + "note": "aff_* and algo_* params should be stripped" + }, + { + "name": "AliExpress - spm/scm and other params", + "category": "aliexpress", + "input": "https://www.aliexpress.com/item/123.html?spm=a2g0o&scm=1007.123&btsid=abc&ws_ab_test=searchweb0_0", + "expected": "https://www.aliexpress.com/item/123.html", + "note": "spm, scm, btsid, ws_ab_test should be stripped" + }, + { + "name": "Facebook - fb_ params", + "category": "facebook", + "input": "https://example.com/page?fb_action_ids=123&fb_action_types=og.likes&fb_ref=default&fb_source=timeline", + "expected": "https://example.com/page", + "note": "All fb_* params should be stripped" + }, + { + "name": "Facebook - fbclid and related", + "category": "facebook", + "input": "https://example.com/page?fbclid=IwAR3abc123&hrc=1&refsrc=deprecated", + "expected": "https://example.com/page", + "note": "fbclid, hrc, refsrc should be stripped" + }, + { + "name": "Facebook - action_*_map params", + "category": "facebook", + "input": "https://example.com/page?action_object_map={}&action_ref_map=[]&action_type_map={}", + "expected": "https://example.com/page", + "note": "action_*_map params should be stripped" + }, + { + "name": "Google Analytics - utm params", + "category": "google-analytics", + "input": "https://example.com/page?utm_source=google&utm_medium=cpc&utm_campaign=spring&utm_term=shoes&utm_content=ad1", + "expected": "https://example.com/page", + "note": "All utm_* params should be stripped" + }, + { + "name": "Google Analytics - ga params", + "category": "google-analytics", + "input": "https://example.com/page?ga_source=test&ga_medium=email&ga_campaign=newsletter", + "expected": "https://example.com/page", + "note": "All ga_* params should be stripped" + }, + { + "name": "Google Analytics - gcl params", + "category": "google-analytics", + "input": "https://example.com/page?gclid=CjwKCAjw&gclsrc=aw.ds", + "expected": "https://example.com/page", + "note": "gclid and gclsrc should be stripped" + }, + { + "name": "YouTube - tracking params", + "category": "youtube", + "input": "https://www.youtube.com/watch?v=dQw4w9WgXcQ&ac=1&annotation_id=abc&app=desktop&feature=youtu.be&gclid=xyz&kw=test&src_vid=abc", + "expected": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", + "note": "YouTube tracking params stripped, v param preserved" + }, + { + "name": "YouTube mobile", + "category": "youtube", + "input": "https://m.youtube.com/watch?v=dQw4w9WgXcQ&feature=share&app=mobile", + "expected": "https://m.youtube.com/watch?v=dQw4w9WgXcQ", + "note": "Mobile YouTube tracking params stripped" + }, + { + "name": "YouTube short URL", + "category": "youtube", + "input": "https://youtu.be/dQw4w9WgXcQ?feature=share", + "expected": "https://youtu.be/dQw4w9WgXcQ", + "note": "youtu.be tracking params stripped" + }, + { + "name": "HubSpot - _hs params", + "category": "hubspot", + "input": "https://example.com/page?_hsenc=p2ANqtz-abc&_hsmi=123456789", + "expected": "https://example.com/page", + "note": "_hsenc and _hsmi should be stripped" + }, + { + "name": "HubSpot - hmb params", + "category": "hubspot", + "input": "https://example.com/page?hmb_campaign=test&hmb_medium=email&hmb_source=newsletter", + "expected": "https://example.com/page", + "note": "All hmb_* params should be stripped" + }, + { + "name": "MailChimp - mc params", + "category": "mailchimp", + "input": "https://example.com/page?mc_cid=abc123&mc_eid=def456", + "expected": "https://example.com/page", + "note": "mc_cid and mc_eid should be stripped" + }, + { + "name": "Marketo - iesrc and mkt_tok", + "category": "marketo", + "input": "https://example.com/page?iesrc=ctr&mkt_tok=abc123", + "expected": "https://example.com/page", + "note": "iesrc and mkt_tok should be stripped" + }, + { + "name": "Matomo - pk params", + "category": "matomo", + "input": "https://example.com/page?pk_campaign=test&pk_content=abc&pk_kwd=keyword&pk_medium=email&pk_source=newsletter", + "expected": "https://example.com/page", + "note": "All pk_* params should be stripped" + }, + { + "name": "Generic - *id suffix params", + "category": "generic", + "input": "https://example.com/page?anid=123&assetid=456&campaignid=789&eid=abc&gclid=xyz&recipientid=user1&siteid=site1", + "expected": "https://example.com/page", + "note": "All *id suffix params should be stripped" + }, + { + "name": "Generic - misc tracking params", + "category": "generic", + "input": "https://example.com/page?assetType=pdf&elqTrack=true&originalReferer=google&referrer=facebook&terminal_id=123&trk=public_post&trkCampaign=spring&trkInfo=abc", + "expected": "https://example.com/page", + "note": "Various generic tracking params should be stripped" + }, + { + "name": "AMP path cleanup", + "category": "amp", + "input": "https://example.com/article/amp/", + "expected": "https://example.com/article", + "note": "/amp/ should be removed from path" + }, + { + "name": "AMP path with params", + "category": "amp", + "input": "https://example.com/article/amp?utm_source=google", + "expected": "https://example.com/article", + "note": "/amp and utm params should be removed" + }, + { + "name": "Mixed - multiple tracking systems", + "category": "mixed", + "input": "https://example.com/page?utm_source=google&fbclid=abc&gclid=xyz&mc_cid=123&_hsenc=456", + "expected": "https://example.com/page", + "note": "Multiple tracking systems in one URL" + }, + { + "name": "Preserve legitimate params", + "category": "preserve", + "input": "https://example.com/search?q=test&page=2&sort=price&filter=active", + "expected": "https://example.com/search?q=test&page=2&sort=price&filter=active", + "note": "Non-tracking params should be preserved" + }, + { + "name": "Preserve with tracking mixed in", + "category": "preserve", + "input": "https://example.com/search?q=test&utm_source=google&page=2&fbclid=abc", + "expected": "https://example.com/search?q=test&page=2", + "note": "Legitimate params preserved, tracking stripped" + }, + { + "name": "No params - early exit", + "category": "edge-case", + "input": "https://example.com/page", + "expected": "https://example.com/page", + "note": "No query string should trigger early exit" + }, + { + "name": "Short params - early exit", + "category": "edge-case", + "input": "https://example.com/page?a", + "expected": "https://example.com/page?a", + "note": "Very short query string should trigger early exit" + }, + { + "name": "Hash preserved", + "category": "edge-case", + "input": "https://example.com/page?utm_source=google#section1", + "expected": "https://example.com/page#section1", + "note": "Hash fragment should be preserved" + }, + { + "name": "Encoded characters in params", + "category": "edge-case", + "input": "https://www.amazon.com/s?k=test%20product&sprefix=test%20product%2Caps%2C100", + "expected": "https://www.amazon.com/s?k=test+product", + "note": "URL-encoded characters normalized by URLSearchParams (%20 becomes +)" + }, + { + "name": "Ad platform click IDs", + "category": "ad-platforms", + "input": "https://example.com/page?msclkid=abc&dclid=def&twclid=ghi&ttclid=jkl", + "expected": "https://example.com/page", + "note": "Microsoft, DoubleClick, Twitter, TikTok click IDs should be stripped" + }, + { + "name": "Instagram share tracking", + "category": "instagram", + "input": "https://example.com/page?igsh=abc123&igshid=def456", + "expected": "https://example.com/page", + "note": "Instagram share params should be stripped" + }, + { + "name": "Google _gl and srsltid", + "category": "google-analytics", + "input": "https://example.com/page?_gl=abc&srsltid=def", + "expected": "https://example.com/page", + "note": "Google cross-domain linker and search result ID should be stripped" + }, + { + "name": "HubSpot cookies params", + "category": "hubspot", + "input": "https://example.com/page?__hsfp=abc&__hssc=def&__hstc=ghi", + "expected": "https://example.com/page", + "note": "HubSpot cookie params should be stripped" + }, + { + "name": "HubSpot Ads params", + "category": "hubspot", + "input": "https://example.com/page?hsa_cam=abc&hsa_grp=def&hsa_mt=ghi&hsa_src=jkl", + "expected": "https://example.com/page", + "note": "HubSpot Ads params (hsa_*) should be stripped" + }, + { + "name": "Klaviyo params", + "category": "klaviyo", + "input": "https://example.com/page?_kx=abc&_ke=def", + "expected": "https://example.com/page", + "note": "Klaviyo tracking params should be stripped" + }, + { + "name": "Brevo/Sendinblue params", + "category": "brevo", + "input": "https://example.com/page?sib_cuid=abc&sib_sid=def", + "expected": "https://example.com/page", + "note": "Brevo/Sendinblue params should be stripped" + }, + { + "name": "Drip params", + "category": "drip", + "input": "https://example.com/page?__s=abc123", + "expected": "https://example.com/page", + "note": "Drip __s param should be stripped" + }, + { + "name": "Bronto params", + "category": "bronto", + "input": "https://example.com/page?_bta_tid=abc&_bta_c=def", + "expected": "https://example.com/page", + "note": "Bronto (Oracle) params should be stripped" + }, + { + "name": "Listrak params", + "category": "listrak", + "input": "https://example.com/page?trk_contact=abc&trk_msg=def&trk_module=ghi&trk_sid=jkl", + "expected": "https://example.com/page", + "note": "Listrak params should be stripped" + }, + { + "name": "Pinterest epik", + "category": "pinterest", + "input": "https://example.com/page?epik=abc123", + "expected": "https://example.com/page", + "note": "Pinterest epik param should be stripped" + }, + { + "name": "Vero params", + "category": "vero", + "input": "https://example.com/page?vero_id=abc123", + "expected": "https://example.com/page", + "note": "Vero vero_id param should be stripped" + }, + { + "name": "Omeda params", + "category": "omeda", + "input": "https://example.com/page?oly_enc_id=abc&oly_anon_id=def&oly_campaign=ghi", + "expected": "https://example.com/page", + "note": "Omeda params (exact and oly_* prefix) should be stripped" + }, + { + "name": "Matomo mtm prefix", + "category": "matomo", + "input": "https://example.com/page?mtm_campaign=test&mtm_content=abc&mtm_kwd=keyword", + "expected": "https://example.com/page", + "note": "Matomo mtm_* params should be stripped" + }, + { + "name": "Sailthru stm prefix", + "category": "sailthru", + "input": "https://example.com/page?stm_campaign=test&stm_source=email&stm_medium=abc", + "expected": "https://example.com/page", + "note": "Sailthru stm_* params should be stripped" + }, + { + "name": "Walmart tracking params", + "category": "walmart", + "input": "https://www.walmart.com/ip/12345?athcpid=abc&wmlspartner=test&affiliates_ad_id=xyz", + "expected": "https://www.walmart.com/ip/12345", + "note": "Walmart tracking params should be stripped" + }, + { + "name": "Target tracking params", + "category": "target", + "input": "https://www.target.com/p/item?afid=123&clkid=456&lnm=xyz&tref=abc&preselect=1", + "expected": "https://www.target.com/p/item", + "note": "Target tracking params should be stripped" + }, + { + "name": "Temu tracking params", + "category": "temu", + "input": "https://www.temu.com/product?_bg_fs=1&_p_jump_id=abc&_x_ads_channel=def&_x_ads_account=ghi", + "expected": "https://www.temu.com/product", + "note": "Temu tracking params (exact and _x_* prefix) should be stripped" + }, + { + "name": "eBay tracking params", + "category": "ebay", + "input": "https://www.ebay.com/itm/12345?mkevt=1&mkcid=1&mkrid=abc&campid=def&toolid=ghi&amdata=xyz", + "expected": "https://www.ebay.com/itm/12345", + "note": "eBay tracking params should be stripped" + }, + { + "name": "Twitter/X tracking params", + "category": "twitter", + "input": "https://twitter.com/user/status/12345?t=abc&s=20&ref_src=twsrc&ref_url=https://example.com", + "expected": "https://twitter.com/user/status/12345", + "note": "Twitter/X tracking params should be stripped" + }, + { + "name": "X.com tracking params", + "category": "twitter", + "input": "https://x.com/user/status/12345?t=abc&s=20&cn=share", + "expected": "https://x.com/user/status/12345", + "note": "X.com tracking params should be stripped" + }, + { + "name": "LinkedIn tracking params", + "category": "linkedin", + "input": "https://www.linkedin.com/posts/user?li_fat_id=abc&lipi=def&licu=ghi&midToken=jkl", + "expected": "https://www.linkedin.com/posts/user", + "note": "LinkedIn tracking params should be stripped" + }, + { + "name": "Google Search - tracking params stripped, query preserved", + "category": "google-search", + "input": "https://www.google.com/search?q=test+query&ei=abc123&ved=xyz789&sca_esv=def456&aqs=chrome.0.0&gs_lp=Egxnd3M&oq=test", + "expected": "https://www.google.com/search?q=test+query", + "note": "Google Search tracking params stripped, q param preserved" + }, + { + "name": "Google Search - functional params preserved", + "category": "google-search", + "input": "https://www.google.com/search?q=test&hl=en&safe=active&tbs=qdr:w&tbm=isch&ei=abc&ved=def", + "expected": "https://www.google.com/search?q=test&hl=en&safe=active&tbs=qdr%3Aw&tbm=isch", + "note": "Functional params (hl, safe, tbs, tbm) preserved, tracking stripped" + }, + { + "name": "Google Search - client/browser clutter stripped", + "category": "google-search", + "input": "https://www.google.com/search?q=test&client=safari&bih=800&biw=1200&sclient=gws-wiz&source=hp&sourceid=chrome&ie=UTF-8&oe=UTF-8", + "expected": "https://www.google.com/search?q=test", + "note": "Browser/client info params stripped as clutter" + }, + { + "name": "Google Search - country domain (google.co.uk)", + "category": "google-search", + "input": "https://www.google.co.uk/search?q=british+search&ei=abc&ved=def&rlz=1C1CHBD&sxsrf=xyz", + "expected": "https://www.google.co.uk/search?q=british+search", + "note": "Google country domain tracking params stripped" + }, + { + "name": "Google Search - pagination preserved", + "category": "google-search", + "input": "https://www.google.com/search?q=paginated&start=20&num=10&ei=abc&ved=def&sa=N", + "expected": "https://www.google.com/search?q=paginated&start=20&num=10", + "note": "Pagination params (start, num) preserved, tracking stripped" + }, + { + "name": "Google non-search path - no stripping", + "category": "google-search", + "input": "https://docs.google.com/document/d/abc123?ei=tracking&ved=param", + "expected": "https://docs.google.com/document/d/abc123?ei=tracking&ved=param", + "note": "Google Docs (non-search) should NOT have params stripped" + }, + { + "name": "TikTok tracking params", + "category": "tiktok", + "input": "https://www.tiktok.com/@user/video/123?_t=abc&_r=def&share_item_id=xyz&is_from_webapp=1", + "expected": "https://www.tiktok.com/@user/video/123", + "note": "TikTok tracking params should be stripped" + }, + { + "name": "Mixed new universal params", + "category": "mixed", + "input": "https://example.com/page?msclkid=abc&igsh=def&_kx=ghi&epik=jkl&vero_id=mno", + "expected": "https://example.com/page", + "note": "Multiple new universal tracking params in one URL" + } + ], + "excludedFromScope": [ + { + "name": "IBM Coremetrics - cm_mmca numeric", + "category": "ibm-excluded", + "input": "https://example.com/page?cm_mmc=test&cm_mmca1=abc&cm_mmca2=def&cm_mmca99=xyz", + "note": "cm_mmca\\d+ pattern excluded from refactor scope - will still use regex in original" + } + ] +}