urlpurify 1.0.0

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.
Files changed (162) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +93 -0
  3. package/dist/clean.d.ts +8 -0
  4. package/dist/clean.js +63 -0
  5. package/dist/defaults.d.ts +7 -0
  6. package/dist/defaults.js +30 -0
  7. package/dist/index.d.ts +80 -0
  8. package/dist/index.js +79 -0
  9. package/dist/params.d.ts +4 -0
  10. package/dist/params.js +157 -0
  11. package/dist/types.d.ts +9 -0
  12. package/dist/unwraps/aceml.d.ts +6 -0
  13. package/dist/unwraps/aceml.js +15 -0
  14. package/dist/unwraps/adjust.d.ts +6 -0
  15. package/dist/unwraps/adjust.js +9 -0
  16. package/dist/unwraps/amazonAffiliate.d.ts +6 -0
  17. package/dist/unwraps/amazonAffiliate.js +9 -0
  18. package/dist/unwraps/ampCache.d.ts +6 -0
  19. package/dist/unwraps/ampCache.js +13 -0
  20. package/dist/unwraps/awin.d.ts +6 -0
  21. package/dist/unwraps/awin.js +9 -0
  22. package/dist/unwraps/bing.d.ts +6 -0
  23. package/dist/unwraps/bing.js +14 -0
  24. package/dist/unwraps/cjNetwork.d.ts +6 -0
  25. package/dist/unwraps/cjNetwork.js +17 -0
  26. package/dist/unwraps/digidip.d.ts +6 -0
  27. package/dist/unwraps/digidip.js +8 -0
  28. package/dist/unwraps/disqus.d.ts +6 -0
  29. package/dist/unwraps/disqus.js +8 -0
  30. package/dist/unwraps/douban.d.ts +6 -0
  31. package/dist/unwraps/douban.js +9 -0
  32. package/dist/unwraps/duckduckgo.d.ts +6 -0
  33. package/dist/unwraps/duckduckgo.js +9 -0
  34. package/dist/unwraps/ebayRover.d.ts +6 -0
  35. package/dist/unwraps/ebayRover.js +8 -0
  36. package/dist/unwraps/effiliation.d.ts +6 -0
  37. package/dist/unwraps/effiliation.js +8 -0
  38. package/dist/unwraps/embedly.d.ts +6 -0
  39. package/dist/unwraps/embedly.js +8 -0
  40. package/dist/unwraps/facebook.d.ts +6 -0
  41. package/dist/unwraps/facebook.js +9 -0
  42. package/dist/unwraps/feedsportal.d.ts +6 -0
  43. package/dist/unwraps/feedsportal.js +44 -0
  44. package/dist/unwraps/firebaseDynamicLinks.d.ts +6 -0
  45. package/dist/unwraps/firebaseDynamicLinks.js +8 -0
  46. package/dist/unwraps/flipboard.d.ts +6 -0
  47. package/dist/unwraps/flipboard.js +9 -0
  48. package/dist/unwraps/gateSc.d.ts +6 -0
  49. package/dist/unwraps/gateSc.js +8 -0
  50. package/dist/unwraps/georiot.d.ts +6 -0
  51. package/dist/unwraps/georiot.js +8 -0
  52. package/dist/unwraps/gitee.d.ts +6 -0
  53. package/dist/unwraps/gitee.js +9 -0
  54. package/dist/unwraps/google.d.ts +6 -0
  55. package/dist/unwraps/google.js +8 -0
  56. package/dist/unwraps/googleAmpViewer.d.ts +6 -0
  57. package/dist/unwraps/googleAmpViewer.js +13 -0
  58. package/dist/unwraps/googleNews.d.ts +6 -0
  59. package/dist/unwraps/googleNews.js +8 -0
  60. package/dist/unwraps/googleNewsModern.d.ts +6 -0
  61. package/dist/unwraps/googleNewsModern.js +14 -0
  62. package/dist/unwraps/googleScholar.d.ts +6 -0
  63. package/dist/unwraps/googleScholar.js +8 -0
  64. package/dist/unwraps/googleTranslate.d.ts +6 -0
  65. package/dist/unwraps/googleTranslate.js +8 -0
  66. package/dist/unwraps/hashnode.d.ts +6 -0
  67. package/dist/unwraps/hashnode.js +9 -0
  68. package/dist/unwraps/icptrack.d.ts +6 -0
  69. package/dist/unwraps/icptrack.js +9 -0
  70. package/dist/unwraps/idealoPartner.d.ts +6 -0
  71. package/dist/unwraps/idealoPartner.js +8 -0
  72. package/dist/unwraps/instagram.d.ts +6 -0
  73. package/dist/unwraps/instagram.js +8 -0
  74. package/dist/unwraps/jianshuGo.d.ts +6 -0
  75. package/dist/unwraps/jianshuGo.js +9 -0
  76. package/dist/unwraps/juejin.d.ts +6 -0
  77. package/dist/unwraps/juejin.js +8 -0
  78. package/dist/unwraps/leverAnalytics.d.ts +6 -0
  79. package/dist/unwraps/leverAnalytics.js +8 -0
  80. package/dist/unwraps/linksynergy.d.ts +6 -0
  81. package/dist/unwraps/linksynergy.js +9 -0
  82. package/dist/unwraps/mailchimp.d.ts +6 -0
  83. package/dist/unwraps/mailchimp.js +9 -0
  84. package/dist/unwraps/mailpanion.d.ts +6 -0
  85. package/dist/unwraps/mailpanion.js +8 -0
  86. package/dist/unwraps/mailpgn.d.ts +6 -0
  87. package/dist/unwraps/mailpgn.js +8 -0
  88. package/dist/unwraps/mailtrack.d.ts +6 -0
  89. package/dist/unwraps/mailtrack.js +8 -0
  90. package/dist/unwraps/medium.d.ts +6 -0
  91. package/dist/unwraps/medium.js +9 -0
  92. package/dist/unwraps/mimecast.d.ts +6 -0
  93. package/dist/unwraps/mimecast.js +11 -0
  94. package/dist/unwraps/mozillaOutgoing.d.ts +6 -0
  95. package/dist/unwraps/mozillaOutgoing.js +13 -0
  96. package/dist/unwraps/narrativ.d.ts +6 -0
  97. package/dist/unwraps/narrativ.js +8 -0
  98. package/dist/unwraps/nicoMs.d.ts +6 -0
  99. package/dist/unwraps/nicoMs.js +12 -0
  100. package/dist/unwraps/outlookSafelinks.d.ts +6 -0
  101. package/dist/unwraps/outlookSafelinks.js +8 -0
  102. package/dist/unwraps/partnerAds.d.ts +6 -0
  103. package/dist/unwraps/partnerAds.js +8 -0
  104. package/dist/unwraps/pocket.d.ts +6 -0
  105. package/dist/unwraps/pocket.js +9 -0
  106. package/dist/unwraps/postmark.d.ts +6 -0
  107. package/dist/unwraps/postmark.js +12 -0
  108. package/dist/unwraps/proofpointV1.d.ts +6 -0
  109. package/dist/unwraps/proofpointV1.js +16 -0
  110. package/dist/unwraps/proofpointV2.d.ts +6 -0
  111. package/dist/unwraps/proofpointV2.js +16 -0
  112. package/dist/unwraps/proofpointV3.d.ts +6 -0
  113. package/dist/unwraps/proofpointV3.js +78 -0
  114. package/dist/unwraps/pxf.d.ts +6 -0
  115. package/dist/unwraps/pxf.js +8 -0
  116. package/dist/unwraps/recruitics.d.ts +6 -0
  117. package/dist/unwraps/recruitics.js +8 -0
  118. package/dist/unwraps/redditOut.d.ts +6 -0
  119. package/dist/unwraps/redditOut.js +8 -0
  120. package/dist/unwraps/redirectingat.d.ts +6 -0
  121. package/dist/unwraps/redirectingat.js +8 -0
  122. package/dist/unwraps/segmentfault.d.ts +6 -0
  123. package/dist/unwraps/segmentfault.js +14 -0
  124. package/dist/unwraps/shareasale.d.ts +6 -0
  125. package/dist/unwraps/shareasale.js +9 -0
  126. package/dist/unwraps/sjv.d.ts +6 -0
  127. package/dist/unwraps/sjv.js +8 -0
  128. package/dist/unwraps/skimlinks.d.ts +6 -0
  129. package/dist/unwraps/skimlinks.js +8 -0
  130. package/dist/unwraps/slack.d.ts +6 -0
  131. package/dist/unwraps/slack.js +9 -0
  132. package/dist/unwraps/smartredirect.d.ts +6 -0
  133. package/dist/unwraps/smartredirect.js +8 -0
  134. package/dist/unwraps/sspai.d.ts +6 -0
  135. package/dist/unwraps/sspai.js +9 -0
  136. package/dist/unwraps/steamLinkfilter.d.ts +6 -0
  137. package/dist/unwraps/steamLinkfilter.js +9 -0
  138. package/dist/unwraps/telegramIv.d.ts +6 -0
  139. package/dist/unwraps/telegramIv.js +9 -0
  140. package/dist/unwraps/tradedoubler.d.ts +6 -0
  141. package/dist/unwraps/tradedoubler.js +9 -0
  142. package/dist/unwraps/tumblr.d.ts +6 -0
  143. package/dist/unwraps/tumblr.js +9 -0
  144. package/dist/unwraps/valuecommerce.d.ts +6 -0
  145. package/dist/unwraps/valuecommerce.js +9 -0
  146. package/dist/unwraps/viglink.d.ts +6 -0
  147. package/dist/unwraps/viglink.js +8 -0
  148. package/dist/unwraps/vkAway.d.ts +6 -0
  149. package/dist/unwraps/vkAway.js +9 -0
  150. package/dist/unwraps/webArchive.d.ts +6 -0
  151. package/dist/unwraps/webArchive.js +12 -0
  152. package/dist/unwraps/yahooSearch.d.ts +6 -0
  153. package/dist/unwraps/yahooSearch.js +12 -0
  154. package/dist/unwraps/yandexTurbo.d.ts +6 -0
  155. package/dist/unwraps/yandexTurbo.js +12 -0
  156. package/dist/unwraps/youtube.d.ts +6 -0
  157. package/dist/unwraps/youtube.js +9 -0
  158. package/dist/unwraps/zhihu.d.ts +6 -0
  159. package/dist/unwraps/zhihu.js +8 -0
  160. package/dist/utils.d.ts +11 -0
  161. package/dist/utils.js +50 -0
  162. package/package.json +45 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Maciej Lamberski
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,93 @@
1
+ # urlpurify
2
+
3
+ [![codecov](https://codecov.io/gh/macieklamberski/urlpurify/branch/main/graph/badge.svg)](https://codecov.io/gh/macieklamberski/urlpurify)
4
+ [![npm version](https://img.shields.io/npm/v/urlpurify.svg)](https://www.npmjs.com/package/urlpurify)
5
+ [![license](https://img.shields.io/npm/l/urlpurify.svg)](https://github.com/macieklamberski/urlpurify/blob/main/LICENSE)
6
+
7
+ Unwrap redirect, affiliate, and tracking wrapper URLs and strip tracking parameters. Turn noisy links into clean, direct URLs.
8
+
9
+ URLs collected from feeds, emails, and social platforms rarely point straight at their destination: they pass through search-engine redirects, email security gateways, affiliate networks, and AMP caches, and carry analytics parameters that bloat the link and leak data. urlpurify ships 70+ unwrappers for known wrapper services and a list of 150+ known tracking parameters, plus a composite `cleanUrl()` that applies both. It has zero dependencies and runs in any modern JavaScript runtime, including browsers.
10
+
11
+ ## Installation
12
+
13
+ ```bash
14
+ npm install urlpurify
15
+ ```
16
+
17
+ ## Quick Start
18
+
19
+ ```typescript
20
+ import { cleanUrl } from 'urlpurify'
21
+
22
+ cleanUrl('https://www.google.com/url?q=https%3A%2F%2Fexample.com%2Fpost%3Futm_source%3Dnewsletter')
23
+ // => 'https://example.com/post'
24
+ ```
25
+
26
+ ## API
27
+
28
+ ### `cleanUrl(url, options?)`
29
+
30
+ Unwraps redirect wrappers (repeatedly, since wrappers can nest), then strips tracking parameters. When the input cannot be parsed as a URL or nothing applies, the input string is returned unchanged, so the result is always safe to display.
31
+
32
+ ```typescript
33
+ import { cleanUrl, defaultUnwrappers, unwrapWebArchive } from 'urlpurify'
34
+
35
+ const cleaned = cleanUrl(url, {
36
+ // Unwrappers to apply, first match wins per pass (omit to use defaults).
37
+ unwrappers: [...defaultUnwrappers, unwrapWebArchive],
38
+ // Query parameter names to remove, matched case-insensitively (omit to use defaults).
39
+ trackingParams: ['utm_source', 'utm_medium', 'fbclid'],
40
+ // Maximum number of unwrap passes for nested wrappers. Defaults to 3.
41
+ maxUnwrapDepth: 3,
42
+ })
43
+ ```
44
+
45
+ ### `unwrapUrl(url, unwrappers?)`
46
+
47
+ Applies the unwrappers in order (one pass) and returns the first extracted target, or `undefined` when none match or the input cannot be parsed.
48
+
49
+ ### `stripTrackingParams(url, trackingParams?)`
50
+
51
+ Removes matching query parameters and returns the cleaned URL. The input is returned unchanged when nothing matches or it cannot be parsed.
52
+
53
+ ### `createParamExtractor(config)`
54
+
55
+ Builds an unwrapper for the common case where the target URL sits in a query parameter:
56
+
57
+ ```typescript
58
+ import { cleanUrl, createParamExtractor, defaultUnwrappers } from 'urlpurify'
59
+
60
+ const unwrapExample = createParamExtractor({
61
+ hosts: 'go.example.com', // Also accepts an array of hosts or a regex.
62
+ params: ['target'],
63
+ })
64
+
65
+ cleanUrl(url, { unwrappers: [...defaultUnwrappers, unwrapExample] })
66
+ ```
67
+
68
+ For wrappers that encode the target (base64 path segments, custom escaping), write a plain function of type `UrlUnwrapper`: it receives a `URL` and returns the target string or `undefined`.
69
+
70
+ ### Defaults
71
+
72
+ `defaultTrackingParams` and `defaultUnwrappers` are exported from the package root. `defaultUnwrappers` enables a conservative subset of the catalog (search-engine redirects and social-platform shims); everything else is exported individually for explicit opt-in.
73
+
74
+ ## Unwrappers
75
+
76
+ Enabled by default:
77
+
78
+ | Unwrapper | Description |
79
+ | --- | --- |
80
+ | `unwrapBing` | Bing search-result redirect (www.bing.com/ck/a?u=a1\<base64url\>) |
81
+ | `unwrapFacebookShim` | Facebook link shim (l.facebook.com/l.php?u=\<target\>) |
82
+ | `unwrapGoogle` | Google redirect (google.\<TLD\>/url?url=\<target\> or ?q=\<target\>) |
83
+ | `unwrapGoogleAmpViewer` | Google AMP viewer (www.google.\<TLD\>/amp/s/\<host\>/\<path\>) |
84
+ | `unwrapGoogleNews` | Google News legacy redirect (news.google.\<TLD\>/news/url?url=\<target\>) |
85
+ | `unwrapGoogleNewsModern` | Google News modern article URLs (news.google.com/articles/\<base64\>) |
86
+ | `unwrapGoogleScholar` | Google Scholar search-result redirect (scholar.google.\<TLD\>/scholar_url?url=\<target\>) |
87
+ | `unwrapInstagramShim` | Instagram outbound link shim (l.instagram.com with ?u=\<target\>) |
88
+ | `unwrapRedditOut` | Reddit outbound click tracker (out.reddit.com/?url=\<target\>) |
89
+ | `unwrapVkAway` | VK away redirect (vk.com/away.php?to=\<target\>) |
90
+ | `unwrapYahooSearch` | Yahoo Search redirect (r.search.yahoo.com/.../RU=\<target\>/RK=...) |
91
+ | `unwrapYouTube` | YouTube external redirect (www.youtube.com/redirect?q=\<target\>) |
92
+
93
+ Many more are available for explicit opt-in: email security gateways (Outlook SafeLinks, Proofpoint, Mimecast), affiliate networks (Awin, Skimlinks, Commission Junction), CJK platforms, AMP caches, and others. See [src/unwraps](src/unwraps) for the full catalog, each documented in its source file.
@@ -0,0 +1,8 @@
1
+ import { CleanUrlOptions, UrlUnwrapper } from "./types.js";
2
+
3
+ //#region src/clean.d.ts
4
+ declare const unwrapUrl: (url: string, unwrappers?: Array<UrlUnwrapper>) => string | undefined;
5
+ declare const stripTrackingParams: (url: string, trackingParams?: Array<string>) => string;
6
+ declare const cleanUrl: (url: string, options?: CleanUrlOptions) => string;
7
+ //#endregion
8
+ export { cleanUrl, stripTrackingParams, unwrapUrl };
package/dist/clean.js ADDED
@@ -0,0 +1,63 @@
1
+ import { defaultTrackingParams } from "./params.js";
2
+ import { defaultUnwrappers } from "./defaults.js";
3
+ //#region src/clean.ts
4
+ const trackingParamsCache = /* @__PURE__ */ new WeakMap();
5
+ const getTrackingParamsSet = (params) => {
6
+ let cached = trackingParamsCache.get(params);
7
+ if (!cached) {
8
+ cached = new Set(params.map((param) => param.toLowerCase()));
9
+ trackingParamsCache.set(params, cached);
10
+ }
11
+ return cached;
12
+ };
13
+ const parseUrl = (url) => {
14
+ try {
15
+ return new URL(url);
16
+ } catch {}
17
+ };
18
+ const deleteTrackingParams = (url, trackingParams) => {
19
+ if (!url.search) return false;
20
+ const trackingSet = getTrackingParamsSet(trackingParams);
21
+ const keysToDelete = [];
22
+ for (const key of url.searchParams.keys()) if (trackingSet.has(key.toLowerCase())) keysToDelete.push(key);
23
+ for (const key of keysToDelete) url.searchParams.delete(key);
24
+ return keysToDelete.length > 0;
25
+ };
26
+ const applyUnwrappers = (url, unwrappers) => {
27
+ for (const unwrap of unwrappers) {
28
+ const target = unwrap(url);
29
+ if (target) return target;
30
+ }
31
+ };
32
+ const unwrapUrl = (url, unwrappers = defaultUnwrappers) => {
33
+ const parsed = parseUrl(url);
34
+ if (!parsed) return;
35
+ return applyUnwrappers(parsed, unwrappers);
36
+ };
37
+ const stripTrackingParams = (url, trackingParams = defaultTrackingParams) => {
38
+ const parsed = parseUrl(url);
39
+ if (!parsed) return url;
40
+ if (deleteTrackingParams(parsed, trackingParams)) return parsed.toString();
41
+ return url;
42
+ };
43
+ const cleanUrl = (url, options) => {
44
+ const unwrappers = options?.unwrappers ?? defaultUnwrappers;
45
+ const trackingParams = options?.trackingParams ?? defaultTrackingParams;
46
+ const maxUnwrapDepth = options?.maxUnwrapDepth ?? 3;
47
+ const parsed = parseUrl(url);
48
+ if (!parsed) return url;
49
+ let currentUrl = url;
50
+ let currentParsed = parsed;
51
+ for (let depth = 0; depth < maxUnwrapDepth; depth += 1) {
52
+ const target = applyUnwrappers(currentParsed, unwrappers);
53
+ if (!target) break;
54
+ const targetParsed = parseUrl(target);
55
+ if (!targetParsed) break;
56
+ currentUrl = target;
57
+ currentParsed = targetParsed;
58
+ }
59
+ if (deleteTrackingParams(currentParsed, trackingParams)) return currentParsed.toString();
60
+ return currentUrl;
61
+ };
62
+ //#endregion
63
+ export { cleanUrl, stripTrackingParams, unwrapUrl };
@@ -0,0 +1,7 @@
1
+ import { UrlUnwrapper } from "./types.js";
2
+ import { defaultTrackingParams } from "./params.js";
3
+
4
+ //#region src/defaults.d.ts
5
+ declare const defaultUnwrappers: Array<UrlUnwrapper>;
6
+ //#endregion
7
+ export { defaultUnwrappers };
@@ -0,0 +1,30 @@
1
+ import { unwrapBing } from "./unwraps/bing.js";
2
+ import { unwrapFacebookShim } from "./unwraps/facebook.js";
3
+ import { unwrapGoogle } from "./unwraps/google.js";
4
+ import { unwrapGoogleAmpViewer } from "./unwraps/googleAmpViewer.js";
5
+ import { unwrapGoogleNews } from "./unwraps/googleNews.js";
6
+ import { unwrapGoogleNewsModern } from "./unwraps/googleNewsModern.js";
7
+ import { unwrapGoogleScholar } from "./unwraps/googleScholar.js";
8
+ import { unwrapInstagramShim } from "./unwraps/instagram.js";
9
+ import { unwrapRedditOut } from "./unwraps/redditOut.js";
10
+ import { unwrapVkAway } from "./unwraps/vkAway.js";
11
+ import { unwrapYahooSearch } from "./unwraps/yahooSearch.js";
12
+ import { unwrapYouTube } from "./unwraps/youtube.js";
13
+ import "./params.js";
14
+ //#region src/defaults.ts
15
+ const defaultUnwrappers = [
16
+ unwrapBing,
17
+ unwrapGoogle,
18
+ unwrapGoogleNews,
19
+ unwrapGoogleNewsModern,
20
+ unwrapGoogleScholar,
21
+ unwrapGoogleAmpViewer,
22
+ unwrapYahooSearch,
23
+ unwrapYouTube,
24
+ unwrapFacebookShim,
25
+ unwrapInstagramShim,
26
+ unwrapVkAway,
27
+ unwrapRedditOut
28
+ ];
29
+ //#endregion
30
+ export { defaultUnwrappers };
@@ -0,0 +1,80 @@
1
+ import { CleanUrlOptions, UrlUnwrapper } from "./types.js";
2
+ import { cleanUrl, stripTrackingParams, unwrapUrl } from "./clean.js";
3
+ import { defaultTrackingParams } from "./params.js";
4
+ import { defaultUnwrappers } from "./defaults.js";
5
+ import { unwrapAceml } from "./unwraps/aceml.js";
6
+ import { unwrapAdjust } from "./unwraps/adjust.js";
7
+ import { unwrapAmazonAffiliate } from "./unwraps/amazonAffiliate.js";
8
+ import { unwrapAmpCache } from "./unwraps/ampCache.js";
9
+ import { unwrapAwin } from "./unwraps/awin.js";
10
+ import { unwrapBing } from "./unwraps/bing.js";
11
+ import { unwrapCjNetwork } from "./unwraps/cjNetwork.js";
12
+ import { unwrapDigidip } from "./unwraps/digidip.js";
13
+ import { unwrapDisqus } from "./unwraps/disqus.js";
14
+ import { unwrapDouban } from "./unwraps/douban.js";
15
+ import { unwrapDuckduckgo } from "./unwraps/duckduckgo.js";
16
+ import { unwrapEbayRover } from "./unwraps/ebayRover.js";
17
+ import { unwrapEffiliation } from "./unwraps/effiliation.js";
18
+ import { unwrapEmbedly } from "./unwraps/embedly.js";
19
+ import { unwrapFacebookShim } from "./unwraps/facebook.js";
20
+ import { unwrapFeedsportal } from "./unwraps/feedsportal.js";
21
+ import { unwrapFirebaseDynamicLinks } from "./unwraps/firebaseDynamicLinks.js";
22
+ import { unwrapFlipboard } from "./unwraps/flipboard.js";
23
+ import { unwrapGateSc } from "./unwraps/gateSc.js";
24
+ import { unwrapGeoriot } from "./unwraps/georiot.js";
25
+ import { unwrapGitee } from "./unwraps/gitee.js";
26
+ import { unwrapGoogle } from "./unwraps/google.js";
27
+ import { unwrapGoogleAmpViewer } from "./unwraps/googleAmpViewer.js";
28
+ import { unwrapGoogleNews } from "./unwraps/googleNews.js";
29
+ import { unwrapGoogleNewsModern } from "./unwraps/googleNewsModern.js";
30
+ import { unwrapGoogleScholar } from "./unwraps/googleScholar.js";
31
+ import { unwrapGoogleTranslate } from "./unwraps/googleTranslate.js";
32
+ import { unwrapHashnode } from "./unwraps/hashnode.js";
33
+ import { unwrapIcptrack } from "./unwraps/icptrack.js";
34
+ import { unwrapIdealoPartner } from "./unwraps/idealoPartner.js";
35
+ import { unwrapInstagramShim } from "./unwraps/instagram.js";
36
+ import { unwrapJianshuGo } from "./unwraps/jianshuGo.js";
37
+ import { unwrapJuejin } from "./unwraps/juejin.js";
38
+ import { unwrapLeverAnalytics } from "./unwraps/leverAnalytics.js";
39
+ import { unwrapLinksynergy } from "./unwraps/linksynergy.js";
40
+ import { unwrapMailchimp } from "./unwraps/mailchimp.js";
41
+ import { unwrapMailpanion } from "./unwraps/mailpanion.js";
42
+ import { unwrapMailpgn } from "./unwraps/mailpgn.js";
43
+ import { unwrapMailtrack } from "./unwraps/mailtrack.js";
44
+ import { unwrapMedium } from "./unwraps/medium.js";
45
+ import { unwrapMimecast } from "./unwraps/mimecast.js";
46
+ import { unwrapMozillaOutgoing } from "./unwraps/mozillaOutgoing.js";
47
+ import { unwrapNarrativ } from "./unwraps/narrativ.js";
48
+ import { unwrapNicoMs } from "./unwraps/nicoMs.js";
49
+ import { unwrapOutlookSafelinks } from "./unwraps/outlookSafelinks.js";
50
+ import { unwrapPartnerAds } from "./unwraps/partnerAds.js";
51
+ import { unwrapPocket } from "./unwraps/pocket.js";
52
+ import { unwrapPostmark } from "./unwraps/postmark.js";
53
+ import { unwrapProofpointV1 } from "./unwraps/proofpointV1.js";
54
+ import { unwrapProofpointV2 } from "./unwraps/proofpointV2.js";
55
+ import { unwrapProofpointV3 } from "./unwraps/proofpointV3.js";
56
+ import { unwrapPxf } from "./unwraps/pxf.js";
57
+ import { unwrapRecruitics } from "./unwraps/recruitics.js";
58
+ import { unwrapRedditOut } from "./unwraps/redditOut.js";
59
+ import { unwrapRedirectingat } from "./unwraps/redirectingat.js";
60
+ import { unwrapSegmentfault } from "./unwraps/segmentfault.js";
61
+ import { unwrapShareasale } from "./unwraps/shareasale.js";
62
+ import { unwrapSjv } from "./unwraps/sjv.js";
63
+ import { unwrapSkimlinks } from "./unwraps/skimlinks.js";
64
+ import { unwrapSlack } from "./unwraps/slack.js";
65
+ import { unwrapSmartredirect } from "./unwraps/smartredirect.js";
66
+ import { unwrapSspai } from "./unwraps/sspai.js";
67
+ import { unwrapSteamLinkfilter } from "./unwraps/steamLinkfilter.js";
68
+ import { unwrapTelegramIv } from "./unwraps/telegramIv.js";
69
+ import { unwrapTradedoubler } from "./unwraps/tradedoubler.js";
70
+ import { unwrapTumblr } from "./unwraps/tumblr.js";
71
+ import { unwrapValuecommerce } from "./unwraps/valuecommerce.js";
72
+ import { unwrapViglink } from "./unwraps/viglink.js";
73
+ import { unwrapVkAway } from "./unwraps/vkAway.js";
74
+ import { unwrapWebArchive } from "./unwraps/webArchive.js";
75
+ import { unwrapYahooSearch } from "./unwraps/yahooSearch.js";
76
+ import { unwrapYandexTurbo } from "./unwraps/yandexTurbo.js";
77
+ import { unwrapYouTube } from "./unwraps/youtube.js";
78
+ import { unwrapZhihu } from "./unwraps/zhihu.js";
79
+ import { ParamExtractorConfig, createParamExtractor } from "./utils.js";
80
+ export { type CleanUrlOptions, type ParamExtractorConfig, type UrlUnwrapper, cleanUrl, createParamExtractor, defaultTrackingParams, defaultUnwrappers, stripTrackingParams, unwrapAceml, unwrapAdjust, unwrapAmazonAffiliate, unwrapAmpCache, unwrapAwin, unwrapBing, unwrapCjNetwork, unwrapDigidip, unwrapDisqus, unwrapDouban, unwrapDuckduckgo, unwrapEbayRover, unwrapEffiliation, unwrapEmbedly, unwrapFacebookShim, unwrapFeedsportal, unwrapFirebaseDynamicLinks, unwrapFlipboard, unwrapGateSc, unwrapGeoriot, unwrapGitee, unwrapGoogle, unwrapGoogleAmpViewer, unwrapGoogleNews, unwrapGoogleNewsModern, unwrapGoogleScholar, unwrapGoogleTranslate, unwrapHashnode, unwrapIcptrack, unwrapIdealoPartner, unwrapInstagramShim, unwrapJianshuGo, unwrapJuejin, unwrapLeverAnalytics, unwrapLinksynergy, unwrapMailchimp, unwrapMailpanion, unwrapMailpgn, unwrapMailtrack, unwrapMedium, unwrapMimecast, unwrapMozillaOutgoing, unwrapNarrativ, unwrapNicoMs, unwrapOutlookSafelinks, unwrapPartnerAds, unwrapPocket, unwrapPostmark, unwrapProofpointV1, unwrapProofpointV2, unwrapProofpointV3, unwrapPxf, unwrapRecruitics, unwrapRedditOut, unwrapRedirectingat, unwrapSegmentfault, unwrapShareasale, unwrapSjv, unwrapSkimlinks, unwrapSlack, unwrapSmartredirect, unwrapSspai, unwrapSteamLinkfilter, unwrapTelegramIv, unwrapTradedoubler, unwrapTumblr, unwrapUrl, unwrapValuecommerce, unwrapViglink, unwrapVkAway, unwrapWebArchive, unwrapYahooSearch, unwrapYandexTurbo, unwrapYouTube, unwrapZhihu };
package/dist/index.js ADDED
@@ -0,0 +1,79 @@
1
+ import { createParamExtractor } from "./utils.js";
2
+ import { unwrapBing } from "./unwraps/bing.js";
3
+ import { unwrapFacebookShim } from "./unwraps/facebook.js";
4
+ import { unwrapGoogle } from "./unwraps/google.js";
5
+ import { unwrapGoogleAmpViewer } from "./unwraps/googleAmpViewer.js";
6
+ import { unwrapGoogleNews } from "./unwraps/googleNews.js";
7
+ import { unwrapGoogleNewsModern } from "./unwraps/googleNewsModern.js";
8
+ import { unwrapGoogleScholar } from "./unwraps/googleScholar.js";
9
+ import { unwrapInstagramShim } from "./unwraps/instagram.js";
10
+ import { unwrapRedditOut } from "./unwraps/redditOut.js";
11
+ import { unwrapVkAway } from "./unwraps/vkAway.js";
12
+ import { unwrapYahooSearch } from "./unwraps/yahooSearch.js";
13
+ import { unwrapYouTube } from "./unwraps/youtube.js";
14
+ import { defaultTrackingParams } from "./params.js";
15
+ import { defaultUnwrappers } from "./defaults.js";
16
+ import { cleanUrl, stripTrackingParams, unwrapUrl } from "./clean.js";
17
+ import { unwrapAceml } from "./unwraps/aceml.js";
18
+ import { unwrapAdjust } from "./unwraps/adjust.js";
19
+ import { unwrapAmazonAffiliate } from "./unwraps/amazonAffiliate.js";
20
+ import { unwrapAmpCache } from "./unwraps/ampCache.js";
21
+ import { unwrapAwin } from "./unwraps/awin.js";
22
+ import { unwrapCjNetwork } from "./unwraps/cjNetwork.js";
23
+ import { unwrapDigidip } from "./unwraps/digidip.js";
24
+ import { unwrapDisqus } from "./unwraps/disqus.js";
25
+ import { unwrapDouban } from "./unwraps/douban.js";
26
+ import { unwrapDuckduckgo } from "./unwraps/duckduckgo.js";
27
+ import { unwrapEbayRover } from "./unwraps/ebayRover.js";
28
+ import { unwrapEffiliation } from "./unwraps/effiliation.js";
29
+ import { unwrapEmbedly } from "./unwraps/embedly.js";
30
+ import { unwrapFeedsportal } from "./unwraps/feedsportal.js";
31
+ import { unwrapFirebaseDynamicLinks } from "./unwraps/firebaseDynamicLinks.js";
32
+ import { unwrapFlipboard } from "./unwraps/flipboard.js";
33
+ import { unwrapGateSc } from "./unwraps/gateSc.js";
34
+ import { unwrapGeoriot } from "./unwraps/georiot.js";
35
+ import { unwrapGitee } from "./unwraps/gitee.js";
36
+ import { unwrapGoogleTranslate } from "./unwraps/googleTranslate.js";
37
+ import { unwrapHashnode } from "./unwraps/hashnode.js";
38
+ import { unwrapIcptrack } from "./unwraps/icptrack.js";
39
+ import { unwrapIdealoPartner } from "./unwraps/idealoPartner.js";
40
+ import { unwrapJianshuGo } from "./unwraps/jianshuGo.js";
41
+ import { unwrapJuejin } from "./unwraps/juejin.js";
42
+ import { unwrapLeverAnalytics } from "./unwraps/leverAnalytics.js";
43
+ import { unwrapLinksynergy } from "./unwraps/linksynergy.js";
44
+ import { unwrapMailchimp } from "./unwraps/mailchimp.js";
45
+ import { unwrapMailpanion } from "./unwraps/mailpanion.js";
46
+ import { unwrapMailpgn } from "./unwraps/mailpgn.js";
47
+ import { unwrapMailtrack } from "./unwraps/mailtrack.js";
48
+ import { unwrapMedium } from "./unwraps/medium.js";
49
+ import { unwrapMimecast } from "./unwraps/mimecast.js";
50
+ import { unwrapMozillaOutgoing } from "./unwraps/mozillaOutgoing.js";
51
+ import { unwrapNarrativ } from "./unwraps/narrativ.js";
52
+ import { unwrapNicoMs } from "./unwraps/nicoMs.js";
53
+ import { unwrapOutlookSafelinks } from "./unwraps/outlookSafelinks.js";
54
+ import { unwrapPartnerAds } from "./unwraps/partnerAds.js";
55
+ import { unwrapPocket } from "./unwraps/pocket.js";
56
+ import { unwrapPostmark } from "./unwraps/postmark.js";
57
+ import { unwrapProofpointV1 } from "./unwraps/proofpointV1.js";
58
+ import { unwrapProofpointV2 } from "./unwraps/proofpointV2.js";
59
+ import { unwrapProofpointV3 } from "./unwraps/proofpointV3.js";
60
+ import { unwrapPxf } from "./unwraps/pxf.js";
61
+ import { unwrapRecruitics } from "./unwraps/recruitics.js";
62
+ import { unwrapRedirectingat } from "./unwraps/redirectingat.js";
63
+ import { unwrapSegmentfault } from "./unwraps/segmentfault.js";
64
+ import { unwrapShareasale } from "./unwraps/shareasale.js";
65
+ import { unwrapSjv } from "./unwraps/sjv.js";
66
+ import { unwrapSkimlinks } from "./unwraps/skimlinks.js";
67
+ import { unwrapSlack } from "./unwraps/slack.js";
68
+ import { unwrapSmartredirect } from "./unwraps/smartredirect.js";
69
+ import { unwrapSspai } from "./unwraps/sspai.js";
70
+ import { unwrapSteamLinkfilter } from "./unwraps/steamLinkfilter.js";
71
+ import { unwrapTelegramIv } from "./unwraps/telegramIv.js";
72
+ import { unwrapTradedoubler } from "./unwraps/tradedoubler.js";
73
+ import { unwrapTumblr } from "./unwraps/tumblr.js";
74
+ import { unwrapValuecommerce } from "./unwraps/valuecommerce.js";
75
+ import { unwrapViglink } from "./unwraps/viglink.js";
76
+ import { unwrapWebArchive } from "./unwraps/webArchive.js";
77
+ import { unwrapYandexTurbo } from "./unwraps/yandexTurbo.js";
78
+ import { unwrapZhihu } from "./unwraps/zhihu.js";
79
+ export { cleanUrl, createParamExtractor, defaultTrackingParams, defaultUnwrappers, stripTrackingParams, unwrapAceml, unwrapAdjust, unwrapAmazonAffiliate, unwrapAmpCache, unwrapAwin, unwrapBing, unwrapCjNetwork, unwrapDigidip, unwrapDisqus, unwrapDouban, unwrapDuckduckgo, unwrapEbayRover, unwrapEffiliation, unwrapEmbedly, unwrapFacebookShim, unwrapFeedsportal, unwrapFirebaseDynamicLinks, unwrapFlipboard, unwrapGateSc, unwrapGeoriot, unwrapGitee, unwrapGoogle, unwrapGoogleAmpViewer, unwrapGoogleNews, unwrapGoogleNewsModern, unwrapGoogleScholar, unwrapGoogleTranslate, unwrapHashnode, unwrapIcptrack, unwrapIdealoPartner, unwrapInstagramShim, unwrapJianshuGo, unwrapJuejin, unwrapLeverAnalytics, unwrapLinksynergy, unwrapMailchimp, unwrapMailpanion, unwrapMailpgn, unwrapMailtrack, unwrapMedium, unwrapMimecast, unwrapMozillaOutgoing, unwrapNarrativ, unwrapNicoMs, unwrapOutlookSafelinks, unwrapPartnerAds, unwrapPocket, unwrapPostmark, unwrapProofpointV1, unwrapProofpointV2, unwrapProofpointV3, unwrapPxf, unwrapRecruitics, unwrapRedditOut, unwrapRedirectingat, unwrapSegmentfault, unwrapShareasale, unwrapSjv, unwrapSkimlinks, unwrapSlack, unwrapSmartredirect, unwrapSspai, unwrapSteamLinkfilter, unwrapTelegramIv, unwrapTradedoubler, unwrapTumblr, unwrapUrl, unwrapValuecommerce, unwrapViglink, unwrapVkAway, unwrapWebArchive, unwrapYahooSearch, unwrapYandexTurbo, unwrapYouTube, unwrapZhihu };
@@ -0,0 +1,4 @@
1
+ //#region src/params.d.ts
2
+ declare const defaultTrackingParams: string[];
3
+ //#endregion
4
+ export { defaultTrackingParams };
package/dist/params.js ADDED
@@ -0,0 +1,157 @@
1
+ //#region src/params.ts
2
+ const defaultTrackingParams = [
3
+ "utm_source",
4
+ "utm_medium",
5
+ "utm_campaign",
6
+ "utm_term",
7
+ "utm_content",
8
+ "utm_reader",
9
+ "utm_name",
10
+ "utm_cid",
11
+ "utm_viz_id",
12
+ "gclid",
13
+ "dclid",
14
+ "gbraid",
15
+ "wbraid",
16
+ "gclsrc",
17
+ "gad_source",
18
+ "gad_campaignid",
19
+ "srsltid",
20
+ "fbclid",
21
+ "fb_action_ids",
22
+ "fb_action_types",
23
+ "fb_source",
24
+ "fb_ref",
25
+ "_ga",
26
+ "_gl",
27
+ "_bk",
28
+ "_ke",
29
+ "mc_cid",
30
+ "mc_eid",
31
+ "mc_tc",
32
+ "mkt_tok",
33
+ "msclkid",
34
+ "twclid",
35
+ "ttclid",
36
+ "igshid",
37
+ "mtm_campaign",
38
+ "mtm_cid",
39
+ "mtm_content",
40
+ "mtm_group",
41
+ "mtm_keyword",
42
+ "mtm_medium",
43
+ "mtm_placement",
44
+ "mtm_source",
45
+ "pk_campaign",
46
+ "pk_cid",
47
+ "pk_content",
48
+ "pk_keyword",
49
+ "pk_medium",
50
+ "pk_source",
51
+ "ncid",
52
+ "sr_share",
53
+ "hsa_acc",
54
+ "hsa_ad",
55
+ "hsa_cam",
56
+ "hsa_grp",
57
+ "hsa_kw",
58
+ "hsa_mt",
59
+ "hsa_net",
60
+ "hsa_src",
61
+ "hsa_tgt",
62
+ "hsa_ver",
63
+ "hsCtaTracking",
64
+ "_hsenc",
65
+ "_hsmi",
66
+ "__hstc",
67
+ "__hsfp",
68
+ "__hssc",
69
+ "cid",
70
+ "s_kwcid",
71
+ "sc_cid",
72
+ "ef_id",
73
+ "obOrigUrl",
74
+ "dicbo",
75
+ "yclid",
76
+ "ysclid",
77
+ "_openstat",
78
+ "awinaffid",
79
+ "awinmid",
80
+ "clickref",
81
+ "afftrack",
82
+ "itm_source",
83
+ "itm_medium",
84
+ "itm_campaign",
85
+ "itm_content",
86
+ "itm_channel",
87
+ "itm_audience",
88
+ "int_source",
89
+ "int_medium",
90
+ "int_campaign",
91
+ "int_content",
92
+ "int_placement",
93
+ "int_campaign_type",
94
+ "int_keycode",
95
+ "g2i_source",
96
+ "g2i_medium",
97
+ "g2i_campaign",
98
+ "g2i_or_o",
99
+ "g2i_or_p",
100
+ "doing_wp_cron",
101
+ "preview",
102
+ "preview_id",
103
+ "preview_nonce",
104
+ "replytocom",
105
+ "_",
106
+ "timestamp",
107
+ "ts",
108
+ "cb",
109
+ "cachebuster",
110
+ "nocache",
111
+ "rand",
112
+ "random",
113
+ "sbdcrw",
114
+ "forceByPassCache",
115
+ "sucurianticache",
116
+ "cleancache",
117
+ "rebuildcache",
118
+ "kontrol_health_check_timestamp",
119
+ "action_object_map",
120
+ "action_ref_map",
121
+ "action_type_map",
122
+ "algo_expid",
123
+ "algo_pvid",
124
+ "at_campaign",
125
+ "at_custom1",
126
+ "at_custom2",
127
+ "at_custom3",
128
+ "at_custom4",
129
+ "at_medium",
130
+ "at_preview_index",
131
+ "_bhlid",
132
+ "_branch_match_id",
133
+ "_branch_referrer",
134
+ "__readwiseLocation",
135
+ "campaign_id",
136
+ "click_sum",
137
+ "fref",
138
+ "gs_l",
139
+ "hmb_campaign",
140
+ "hmb_medium",
141
+ "hmb_source",
142
+ "ml_subscriber",
143
+ "ml_subscriber_hash",
144
+ "oly_anon_id",
145
+ "oly_enc_id",
146
+ "rb_clickid",
147
+ "referer",
148
+ "referrer",
149
+ "spm",
150
+ "trk",
151
+ "vero_conv",
152
+ "vero_id",
153
+ "wickedid",
154
+ "xtor"
155
+ ];
156
+ //#endregion
157
+ export { defaultTrackingParams };
@@ -0,0 +1,9 @@
1
+ //#region src/types.d.ts
2
+ type UrlUnwrapper = (url: URL) => string | undefined;
3
+ type CleanUrlOptions = {
4
+ unwrappers?: Array<UrlUnwrapper>;
5
+ trackingParams?: Array<string>;
6
+ maxUnwrapDepth?: number;
7
+ };
8
+ //#endregion
9
+ export { CleanUrlOptions, UrlUnwrapper };
@@ -0,0 +1,6 @@
1
+ import { UrlUnwrapper } from "../types.js";
2
+
3
+ //#region src/unwraps/aceml.d.ts
4
+ declare const unwrapAceml: UrlUnwrapper;
5
+ //#endregion
6
+ export { unwrapAceml };
@@ -0,0 +1,15 @@
1
+ import { createParamExtractor, decodeBase64 } from "../utils.js";
2
+ //#region src/unwraps/aceml.ts
3
+ const baseExtractor = createParamExtractor({
4
+ hosts: /\.acemln[a-d]\.com$/,
5
+ path: "/Prod/link-tracker",
6
+ params: ["redirectUrl"]
7
+ });
8
+ const unwrapAceml = (url) => {
9
+ const raw = baseExtractor(url);
10
+ if (!raw) return;
11
+ const decoded = decodeBase64(raw);
12
+ if (decoded && (decoded.startsWith("http://") || decoded.startsWith("https://"))) return decoded;
13
+ };
14
+ //#endregion
15
+ export { unwrapAceml };
@@ -0,0 +1,6 @@
1
+ import { UrlUnwrapper } from "../types.js";
2
+
3
+ //#region src/unwraps/adjust.d.ts
4
+ declare const unwrapAdjust: UrlUnwrapper;
5
+ //#endregion
6
+ export { unwrapAdjust };
@@ -0,0 +1,9 @@
1
+ //#region src/unwraps/adjust.ts
2
+ const unwrapAdjust = (url) => {
3
+ if (url.hostname !== "app.adjust.com") return;
4
+ const target = url.searchParams.get("redirect");
5
+ if (target?.startsWith("https://") !== true && target?.startsWith("http://") !== true) return;
6
+ return target;
7
+ };
8
+ //#endregion
9
+ export { unwrapAdjust };
@@ -0,0 +1,6 @@
1
+ import { UrlUnwrapper } from "../types.js";
2
+
3
+ //#region src/unwraps/amazonAffiliate.d.ts
4
+ declare const unwrapAmazonAffiliate: UrlUnwrapper;
5
+ //#endregion
6
+ export { unwrapAmazonAffiliate };
@@ -0,0 +1,9 @@
1
+ //#region src/unwraps/amazonAffiliate.ts
2
+ const amazonHostRegex = /\.amazon-adsystem\.com$/;
3
+ const amazonPathRegex = /^\/x\/c\/[^/]+\/(https?:\/\/.+)$/;
4
+ const unwrapAmazonAffiliate = (url) => {
5
+ if (!amazonHostRegex.test(url.hostname)) return;
6
+ return url.pathname.match(amazonPathRegex)?.[1];
7
+ };
8
+ //#endregion
9
+ export { unwrapAmazonAffiliate };
@@ -0,0 +1,6 @@
1
+ import { UrlUnwrapper } from "../types.js";
2
+
3
+ //#region src/unwraps/ampCache.d.ts
4
+ declare const unwrapAmpCache: UrlUnwrapper;
5
+ //#endregion
6
+ export { unwrapAmpCache };
@@ -0,0 +1,13 @@
1
+ import { isHostOf, isSubdomainOf } from "../utils.js";
2
+ //#region src/unwraps/ampCache.ts
3
+ const httpsPathRegex = /^\/c\/s\/(.+)$/;
4
+ const httpPathRegex = /^\/c\/(?!s\/)(.+)$/;
5
+ const unwrapAmpCache = (url) => {
6
+ if (!isHostOf(url, "cdn.ampproject.org") && !isSubdomainOf(url, "cdn.ampproject.org")) return;
7
+ const httpsMatch = url.pathname.match(httpsPathRegex);
8
+ if (httpsMatch) return `https://${httpsMatch[1]}`;
9
+ const httpMatch = url.pathname.match(httpPathRegex);
10
+ if (httpMatch) return `http://${httpMatch[1]}`;
11
+ };
12
+ //#endregion
13
+ export { unwrapAmpCache };
@@ -0,0 +1,6 @@
1
+ import { UrlUnwrapper } from "../types.js";
2
+
3
+ //#region src/unwraps/awin.d.ts
4
+ declare const unwrapAwin: UrlUnwrapper;
5
+ //#endregion
6
+ export { unwrapAwin };