urlpurify 2.0.0 → 2.1.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 (62) hide show
  1. package/README.md +1 -1
  2. package/dist/clean.mjs +7 -17
  3. package/dist/defaults.mjs +2 -0
  4. package/dist/index.d.mts +2 -1
  5. package/dist/index.mjs +2 -1
  6. package/dist/node_modules/trousse/dist/urls.mjs +33 -4
  7. package/dist/unwraps/aceml.mjs +2 -4
  8. package/dist/unwraps/adjust.mjs +5 -5
  9. package/dist/unwraps/amazonSes.mjs +3 -5
  10. package/dist/unwraps/anchor.mjs +2 -3
  11. package/dist/unwraps/apptrkr.mjs +3 -3
  12. package/dist/unwraps/archiveToday.mjs +2 -2
  13. package/dist/unwraps/augure.mjs +2 -7
  14. package/dist/unwraps/bing.mjs +2 -2
  15. package/dist/unwraps/bingAds.mjs +5 -7
  16. package/dist/unwraps/bitrix.mjs +3 -2
  17. package/dist/unwraps/ciscoSecureWeb.mjs +4 -7
  18. package/dist/unwraps/cjNetwork.mjs +2 -8
  19. package/dist/unwraps/cse360.mjs +4 -7
  20. package/dist/unwraps/datalifeEngine.mjs +2 -2
  21. package/dist/unwraps/deployer.mjs +2 -2
  22. package/dist/unwraps/digikala.mjs +2 -2
  23. package/dist/unwraps/disqus.mjs +4 -1
  24. package/dist/unwraps/easyMarketing.mjs +2 -2
  25. package/dist/unwraps/facebook.mjs +5 -7
  26. package/dist/unwraps/feedStatistics.mjs +2 -2
  27. package/dist/unwraps/firebaseDynamicLinks.mjs +1 -1
  28. package/dist/unwraps/firstory.mjs +2 -4
  29. package/dist/unwraps/gfnLinkProxy.mjs +2 -2
  30. package/dist/unwraps/godcaster.mjs +3 -3
  31. package/dist/unwraps/govdelivery.d.mts +4 -0
  32. package/dist/unwraps/govdelivery.mjs +12 -0
  33. package/dist/unwraps/impact.mjs +3 -3
  34. package/dist/unwraps/indexHu.mjs +3 -3
  35. package/dist/unwraps/invisionNoExternalLinks.mjs +3 -3
  36. package/dist/unwraps/linksynergy.mjs +3 -3
  37. package/dist/unwraps/logicboard.mjs +3 -3
  38. package/dist/unwraps/mailinblack.mjs +2 -2
  39. package/dist/unwraps/mandrill.mjs +2 -2
  40. package/dist/unwraps/mimecast.mjs +1 -4
  41. package/dist/unwraps/mohtwize.mjs +2 -6
  42. package/dist/unwraps/mozillaOutgoing.mjs +2 -2
  43. package/dist/unwraps/newswire.mjs +2 -2
  44. package/dist/unwraps/postAffiliatePro.mjs +3 -3
  45. package/dist/unwraps/postmark.mjs +2 -2
  46. package/dist/unwraps/prezly.mjs +2 -7
  47. package/dist/unwraps/proofpointV1.mjs +6 -15
  48. package/dist/unwraps/proofpointV2.mjs +12 -2
  49. package/dist/unwraps/qualityClick.mjs +3 -3
  50. package/dist/unwraps/researchgate.mjs +3 -5
  51. package/dist/unwraps/reviveAdserver.mjs +3 -5
  52. package/dist/unwraps/serendipity.mjs +2 -2
  53. package/dist/unwraps/streak.mjs +3 -5
  54. package/dist/unwraps/surly.mjs +2 -8
  55. package/dist/unwraps/webArchive.mjs +2 -2
  56. package/dist/unwraps/xengentr.mjs +2 -2
  57. package/dist/unwraps/yahooJapanAmpViewer.mjs +2 -7
  58. package/dist/unwraps/yahooSearch.mjs +3 -2
  59. package/dist/unwraps/yandexMail.mjs +2 -2
  60. package/dist/unwraps/yourMembership.mjs +3 -3
  61. package/dist/utils.mjs +17 -14
  62. package/package.json +2 -2
@@ -1,4 +1,4 @@
1
- import { isHostOf } from "../node_modules/trousse/dist/urls.mjs";
1
+ import { decodePercent, isHostOf } from "../node_modules/trousse/dist/urls.mjs";
2
2
  import { getParamTarget } from "../utils.mjs";
3
3
  import { getPathTarget } from "../pathTarget.mjs";
4
4
  //#region src/unwraps/firstory.ts
@@ -13,9 +13,7 @@ const unwrapFirstory = (url) => {
13
13
  if (!isHostOf(url, trackHosts)) return;
14
14
  const match = url.pathname.match(trackPrefixRegex);
15
15
  if (!match) return;
16
- try {
17
- return `${decodeURIComponent(url.pathname.slice(match[0].length))}${url.search}${url.hash}`;
18
- } catch {}
16
+ return `${decodePercent(url.pathname.slice(match[0].length))}${url.search}${url.hash}`;
19
17
  };
20
18
  //#endregion
21
19
  export { unwrapFirstory };
@@ -1,10 +1,10 @@
1
1
  import { isHttpUrl } from "../node_modules/trousse/dist/urls.mjs";
2
- import { decodeBase64 } from "../utils.mjs";
2
+ import { decodeBase64, getParamValues } from "../utils.mjs";
3
3
  //#region src/unwraps/gfnLinkProxy.ts
4
4
  const pathRegex = /^(?:\/[^/]+)?\/redirect\/?$/;
5
5
  const unwrapGfnLinkProxy = (url) => {
6
6
  if (!pathRegex.test(url.pathname)) return;
7
- const raw = url.searchParams.get("to");
7
+ const raw = getParamValues(url, "to").at(0);
8
8
  if (!raw) return;
9
9
  const decoded = decodeBase64(raw);
10
10
  if (decoded && isHttpUrl(decoded)) return decoded;
@@ -1,5 +1,5 @@
1
- import { isHostOf } from "../node_modules/trousse/dist/urls.mjs";
2
- import { createParamExtractor, percentDecode } from "../utils.mjs";
1
+ import { decodePercent, isHostOf } from "../node_modules/trousse/dist/urls.mjs";
2
+ import { createParamExtractor } from "../utils.mjs";
3
3
  //#region src/unwraps/godcaster.ts
4
4
  const episodePrefixRegex = /^\/act\/e\/\d+\/\d+\/\d+\//;
5
5
  const encodedSchemeRegex = /^https?%(?:25)?3A/i;
@@ -14,7 +14,7 @@ const unwrapGodcaster = (url) => {
14
14
  const match = url.pathname.match(episodePrefixRegex);
15
15
  if (!match) return;
16
16
  let target = url.pathname.slice(match[0].length);
17
- while (encodedSchemeRegex.test(target)) target = percentDecode(target);
17
+ while (encodedSchemeRegex.test(target)) target = decodePercent(target);
18
18
  return `${target}${url.hash}`;
19
19
  };
20
20
  //#endregion
@@ -0,0 +1,4 @@
1
+ import { UrlUnwrapper } from "../types.mjs";
2
+ //#region src/unwraps/govdelivery.d.ts
3
+ export declare const unwrapGovdelivery: UrlUnwrapper;
4
+ //#endregion
@@ -0,0 +1,12 @@
1
+ import { isHostOf, isHttpUrl } from "../node_modules/trousse/dist/urls.mjs";
2
+ //#region src/unwraps/govdelivery.ts
3
+ const clickQueryRegex = /^\?type=click&enid=[^&]+&&&\d+&&&(.+)$/;
4
+ const unwrapGovdelivery = (url) => {
5
+ if (!isHostOf(url, "links.govdelivery.com") || url.pathname !== "/track") return;
6
+ const match = clickQueryRegex.exec(url.search);
7
+ if (!match?.[1]) return;
8
+ const target = `${match[1]}${url.hash}`;
9
+ if (isHttpUrl(target)) return target;
10
+ };
11
+ //#endregion
12
+ export { unwrapGovdelivery };
@@ -1,5 +1,5 @@
1
- import { isHttpUrl } from "../node_modules/trousse/dist/urls.mjs";
2
- import { getParamValues, percentDecode } from "../utils.mjs";
1
+ import { decodePercent, isHttpUrl } from "../node_modules/trousse/dist/urls.mjs";
2
+ import { getParamValues } from "../utils.mjs";
3
3
  //#region src/unwraps/impact.ts
4
4
  const pathRegex = /^\/c\/\d+\/\d+\/\d+$/;
5
5
  const sjvHostRegex = /\.sjv\.io$/;
@@ -12,7 +12,7 @@ const unwrapImpact = (url) => {
12
12
  const isPxfPath = pxfHostRegex.test(url.hostname) && pxfPathRegex.test(url.pathname);
13
13
  if (!pathRegex.test(url.pathname) && !isSjvPath && !isPxfPath) return;
14
14
  let target = getParamValues(url, "u").at(0);
15
- if (target && encodedSchemeRegex.test(target)) target = percentDecode(target);
15
+ if (target && encodedSchemeRegex.test(target)) target = decodePercent(target);
16
16
  if (target && isHttpUrl(target)) return target;
17
17
  };
18
18
  //#endregion
@@ -1,5 +1,5 @@
1
- import { isHostOf } from "../node_modules/trousse/dist/urls.mjs";
2
- import { createParamExtractor, percentDecode } from "../utils.mjs";
1
+ import { decodePercent, isHostOf } from "../node_modules/trousse/dist/urls.mjs";
2
+ import { createParamExtractor } from "../utils.mjs";
3
3
  //#region src/unwraps/indexHu.ts
4
4
  const sectionParamRegex = /^index_[a-z]+_cikklink$/;
5
5
  const encodedSchemeRegex = /^https?%3A/i;
@@ -17,7 +17,7 @@ const unwrapSectionCounter = (url) => {
17
17
  for (const [key, value] of url.searchParams) {
18
18
  if (!sectionParamRegex.test(key) || !value) continue;
19
19
  if (!encodedSchemeRegex.test(value)) return value;
20
- return percentDecode(value);
20
+ return decodePercent(value);
21
21
  }
22
22
  };
23
23
  const unwrapIndexHu = (url) => {
@@ -1,12 +1,12 @@
1
- import { isHttpUrl } from "../node_modules/trousse/dist/urls.mjs";
2
- import { getParamValues, percentDecode } from "../utils.mjs";
1
+ import { decodePercent, isHttpUrl } from "../node_modules/trousse/dist/urls.mjs";
2
+ import { getParamValues } from "../utils.mjs";
3
3
  //#region src/unwraps/invisionNoExternalLinks.ts
4
4
  const pathRegex = /^(?:\/[^/]+)?\/redirect\/$/;
5
5
  const encodedSchemeRegex = /^https?%3A/i;
6
6
  const unwrapInvisionNoExternalLinks = (url) => {
7
7
  if (!pathRegex.test(url.pathname)) return;
8
8
  let target = getParamValues(url, "to").at(0);
9
- if (target && encodedSchemeRegex.test(target)) target = percentDecode(target);
9
+ if (target && encodedSchemeRegex.test(target)) target = decodePercent(target);
10
10
  if (!target || !isHttpUrl(target)) return;
11
11
  return target;
12
12
  };
@@ -1,5 +1,5 @@
1
- import { isHostOf, isHttpUrl } from "../node_modules/trousse/dist/urls.mjs";
2
- import { getParamValues, percentDecode } from "../utils.mjs";
1
+ import { decodePercent, isHostOf, isHttpUrl } from "../node_modules/trousse/dist/urls.mjs";
2
+ import { getParamValues } from "../utils.mjs";
3
3
  //#region src/unwraps/linksynergy.ts
4
4
  const linksynergyHosts = [
5
5
  "click.linksynergy.com",
@@ -19,7 +19,7 @@ const unwrapLinksynergy = (url) => {
19
19
  const target = getParamValues(url, param).at(0);
20
20
  if (!target) return;
21
21
  if (isHttpUrl(target)) return target;
22
- const decoded = percentDecode(target);
22
+ const decoded = decodePercent(target);
23
23
  if (isHttpUrl(decoded)) return decoded;
24
24
  };
25
25
  //#endregion
@@ -1,12 +1,12 @@
1
- import { isHttpUrl } from "../node_modules/trousse/dist/urls.mjs";
2
- import { getParamValues, percentDecode } from "../utils.mjs";
1
+ import { decodePercent, isHttpUrl } from "../node_modules/trousse/dist/urls.mjs";
2
+ import { getParamValues } from "../utils.mjs";
3
3
  //#region src/unwraps/logicboard.ts
4
4
  const pathRegex = /^(?:\/[^/]+){0,2}\/away\.php$/;
5
5
  const encodedSchemeRegex = /^https?%3A/i;
6
6
  const unwrapLogicboard = (url) => {
7
7
  if (!pathRegex.test(url.pathname)) return;
8
8
  let target = getParamValues(url, "s").at(0);
9
- if (target && encodedSchemeRegex.test(target)) target = percentDecode(target);
9
+ if (target && encodedSchemeRegex.test(target)) target = decodePercent(target);
10
10
  if (!target || !isHttpUrl(target)) return;
11
11
  return target;
12
12
  };
@@ -1,9 +1,9 @@
1
1
  import { isHttpUrl } from "../node_modules/trousse/dist/urls.mjs";
2
- import { decodeBase64Url } from "../utils.mjs";
2
+ import { decodeBase64Url, getParamValues } from "../utils.mjs";
3
3
  //#region src/unwraps/mailinblack.ts
4
4
  const unwrapMailinblack = (url) => {
5
5
  if (url.pathname !== "/securelink/") return;
6
- const key = url.searchParams.get("key");
6
+ const key = getParamValues(url, "key").at(0);
7
7
  if (!key) return;
8
8
  const json = decodeBase64Url(key);
9
9
  if (!json) return;
@@ -1,5 +1,5 @@
1
1
  import { isHostOf, isHttpUrl } from "../node_modules/trousse/dist/urls.mjs";
2
- import { createParamExtractor, decodeBase64Url } from "../utils.mjs";
2
+ import { createParamExtractor, decodeBase64Url, getParamValues } from "../utils.mjs";
3
3
  //#region src/unwraps/mandrill.ts
4
4
  const hosts = ["go.mnsvc.com", "mandrillapp.com"];
5
5
  const clickPathRegex = /^\/track\/click\/\d+\/[^/]+$/;
@@ -18,7 +18,7 @@ const unwrapMandrill = (url) => {
18
18
  const target = extractClickPhp(url);
19
19
  if (target) return target;
20
20
  if (!isHostOf(url, hosts) || !clickPathRegex.test(url.pathname)) return;
21
- const payload = url.searchParams.get("p");
21
+ const payload = getParamValues(url, "p").at(0);
22
22
  if (!payload) return;
23
23
  return decodePayload(payload);
24
24
  };
@@ -5,10 +5,7 @@ const mimecastProtectHostRegex = /^url\.(?:au|ca|de|jer|uk|us|usb|za)\.m\.mimeca
5
5
  const mimecastPathRegex = /^\/s\/[^/]+$/;
6
6
  const unwrapMimecast = (url) => {
7
7
  if (!(mimecastHostRegex.test(url.hostname) || mimecastProtectHostRegex.test(url.hostname)) || !mimecastPathRegex.test(url.pathname)) return;
8
- const targetUrl = getParamTarget(url, "url");
9
- if (targetUrl) return targetUrl;
10
- const targetDomain = url.searchParams.get("domain");
11
- if (targetDomain) return `https://${targetDomain}`;
8
+ return getParamTarget(url, "url");
12
9
  };
13
10
  //#endregion
14
11
  export { unwrapMimecast };
@@ -1,4 +1,4 @@
1
- import { isHostOf } from "../node_modules/trousse/dist/urls.mjs";
1
+ import { decodePercent, isHostOf } from "../node_modules/trousse/dist/urls.mjs";
2
2
  //#region src/unwraps/mohtwize.ts
3
3
  const carrierPrefix = "?fileURL=/";
4
4
  const schemeRegex = /^https?:/i;
@@ -7,11 +7,7 @@ const unwrapMohtwize = (url) => {
7
7
  if (!isHostOf(url, "stats.mohtwize.net") || url.pathname !== "/redirect.mp3") return;
8
8
  if (!url.search.startsWith(carrierPrefix)) return;
9
9
  let target = `${url.search.slice(10)}${url.hash}`;
10
- if (encodedSchemeRegex.test(target)) try {
11
- target = decodeURIComponent(target);
12
- } catch {
13
- return;
14
- }
10
+ if (encodedSchemeRegex.test(target)) target = decodePercent(target);
15
11
  if (!target) return;
16
12
  if (schemeRegex.test(target)) return target;
17
13
  return `https://${target}`;
@@ -1,4 +1,4 @@
1
- import { decodeSegment, isHostOf } from "../node_modules/trousse/dist/urls.mjs";
1
+ import { decodePercent, isHostOf } from "../node_modules/trousse/dist/urls.mjs";
2
2
  //#region src/unwraps/mozillaOutgoing.ts
3
3
  const pathRegex = /^\/v1\/[0-9a-f]{64}\/(.+)$/;
4
4
  const mozillaOutgoingHosts = [
@@ -10,7 +10,7 @@ const unwrapMozillaOutgoing = (url) => {
10
10
  if (!isHostOf(url, mozillaOutgoingHosts)) return;
11
11
  const match = url.pathname.match(pathRegex);
12
12
  if (!match) return;
13
- return decodeSegment(match[1]);
13
+ return decodePercent(match[1]);
14
14
  };
15
15
  //#endregion
16
16
  export { unwrapMozillaOutgoing };
@@ -1,6 +1,6 @@
1
1
  import { isAnyOf } from "../node_modules/trousse/dist/matching.mjs";
2
2
  import { isHttpUrl } from "../node_modules/trousse/dist/urls.mjs";
3
- import { decodeBase64Url } from "../utils.mjs";
3
+ import { decodeBase64Url, getParamValues } from "../utils.mjs";
4
4
  //#region src/unwraps/newswire.ts
5
5
  const hosts = [
6
6
  "stats.newswire.com",
@@ -9,7 +9,7 @@ const hosts = [
9
9
  ];
10
10
  const unwrapNewswire = (url) => {
11
11
  if (!isAnyOf(url.hostname, hosts) || url.pathname !== "/x/html") return;
12
- const value = url.searchParams.get("final");
12
+ const value = getParamValues(url, "final").at(0);
13
13
  if (!value) return;
14
14
  const decoded = decodeBase64Url(value);
15
15
  if (!decoded || !isHttpUrl(decoded)) return;
@@ -1,12 +1,12 @@
1
- import { isHttpUrl } from "../node_modules/trousse/dist/urls.mjs";
2
- import { getParamValues, percentDecode } from "../utils.mjs";
1
+ import { decodePercent, isHttpUrl } from "../node_modules/trousse/dist/urls.mjs";
2
+ import { getParamValues } from "../utils.mjs";
3
3
  //#region src/unwraps/postAffiliatePro.ts
4
4
  const pathRegex = /^\/(?:[^/]+\/)*scripts\/click\.php$/;
5
5
  const encodedSchemeRegex = /^https?%3A/i;
6
6
  const unwrapPostAffiliatePro = (url) => {
7
7
  if (!pathRegex.test(url.pathname)) return;
8
8
  let target = getParamValues(url, "desturl").at(0);
9
- if (target && encodedSchemeRegex.test(target)) target = percentDecode(target);
9
+ if (target && encodedSchemeRegex.test(target)) target = decodePercent(target);
10
10
  if (target && isHttpUrl(target)) return target;
11
11
  };
12
12
  //#endregion
@@ -1,11 +1,11 @@
1
- import { decodeSegment, isHostOf } from "../node_modules/trousse/dist/urls.mjs";
1
+ import { decodePercent, isHostOf } from "../node_modules/trousse/dist/urls.mjs";
2
2
  //#region src/unwraps/postmark.ts
3
3
  const postmarkPathRegex = /^\/[23][mt]?(s?)\/([^/]+)\//;
4
4
  const unwrapPostmark = (url) => {
5
5
  if (!isHostOf(url, ["click.pstmrk.it", "track.pstmrk.it"])) return;
6
6
  const match = url.pathname.match(postmarkPathRegex);
7
7
  if (!match) return;
8
- const target = decodeSegment(match[2]);
8
+ const target = decodePercent(match[2]);
9
9
  if (!target) return;
10
10
  return `${match[1] ? "https" : "http"}://${target}`;
11
11
  };
@@ -1,16 +1,11 @@
1
- import { isHostOf, isHttpUrl } from "../node_modules/trousse/dist/urls.mjs";
1
+ import { decodePercent, isHostOf, isHttpUrl } from "../node_modules/trousse/dist/urls.mjs";
2
2
  //#region src/unwraps/prezly.ts
3
3
  const pathRegex = /^\/c\/[0-9a-f-]{36}\/[0-9a-f]{8}\/([^/]+)$/;
4
4
  const unwrapPrezly = (url) => {
5
5
  if (!isHostOf(url, "prezlymail.com")) return;
6
6
  const match = pathRegex.exec(url.pathname);
7
7
  if (!match?.[1]) return;
8
- let target;
9
- try {
10
- target = decodeURIComponent(match[1]);
11
- } catch {
12
- return;
13
- }
8
+ const target = decodePercent(match[1]);
14
9
  if (isHttpUrl(target)) return target;
15
10
  };
16
11
  //#endregion
@@ -1,18 +1,9 @@
1
- import { decodeSegment } from "../node_modules/trousse/dist/urls.mjs";
2
1
  import { createParamExtractor } from "../utils.mjs";
3
2
  //#region src/unwraps/proofpointV1.ts
4
- const createProofpointUnwrapper = (path) => {
5
- const baseExtractor = createParamExtractor({
6
- hosts: "urldefense.proofpoint.com",
7
- path,
8
- params: ["u"]
9
- });
10
- return (url) => {
11
- const raw = baseExtractor(url);
12
- if (!raw) return;
13
- return decodeSegment(raw.replace(/-/g, "%").replace(/_/g, "/"));
14
- };
15
- };
16
- const unwrapProofpointV1 = createProofpointUnwrapper("/v1/url");
3
+ const unwrapProofpointV1 = createParamExtractor({
4
+ hosts: "urldefense.proofpoint.com",
5
+ path: "/v1/url",
6
+ params: ["u"]
7
+ });
17
8
  //#endregion
18
- export { createProofpointUnwrapper, unwrapProofpointV1 };
9
+ export { unwrapProofpointV1 };
@@ -1,5 +1,15 @@
1
- import { createProofpointUnwrapper } from "./proofpointV1.mjs";
1
+ import { decodePercent } from "../node_modules/trousse/dist/urls.mjs";
2
+ import { createParamExtractor } from "../utils.mjs";
2
3
  //#region src/unwraps/proofpointV2.ts
3
- const unwrapProofpointV2 = createProofpointUnwrapper("/v2/url");
4
+ const extractTarget = createParamExtractor({
5
+ hosts: "urldefense.proofpoint.com",
6
+ path: "/v2/url",
7
+ params: ["u"]
8
+ });
9
+ const unwrapProofpointV2 = (url) => {
10
+ const raw = extractTarget(url);
11
+ if (!raw) return;
12
+ return decodePercent(raw.replace(/-/g, "%").replace(/_/g, "/"));
13
+ };
4
14
  //#endregion
5
15
  export { unwrapProofpointV2 };
@@ -1,12 +1,12 @@
1
- import { isHttpUrl } from "../node_modules/trousse/dist/urls.mjs";
2
- import { getParamValues, percentDecode } from "../utils.mjs";
1
+ import { decodePercent, isHttpUrl } from "../node_modules/trousse/dist/urls.mjs";
2
+ import { getParamValues } from "../utils.mjs";
3
3
  //#region src/unwraps/qualityClick.ts
4
4
  const encodedSchemeRegex = /^https?%3A/i;
5
5
  const unwrapQualityClick = (url) => {
6
6
  if (url.pathname !== "/go.cgi") return;
7
7
  if (!url.searchParams.has("pid") || !url.searchParams.has("wmid")) return;
8
8
  let target = getParamValues(url, "target").at(0);
9
- if (target && encodedSchemeRegex.test(target)) target = percentDecode(target);
9
+ if (target && encodedSchemeRegex.test(target)) target = decodePercent(target);
10
10
  if (target && isHttpUrl(target)) return target;
11
11
  };
12
12
  //#endregion
@@ -1,4 +1,4 @@
1
- import { isHostOf, isHttpUrl } from "../node_modules/trousse/dist/urls.mjs";
1
+ import { decodePercent, isHostOf, isHttpUrl } from "../node_modules/trousse/dist/urls.mjs";
2
2
  import { createParamExtractor } from "../utils.mjs";
3
3
  //#region src/unwraps/researchgate.ts
4
4
  const derefPathRegex = /^\/deref\/(.+)$/;
@@ -14,10 +14,8 @@ const unwrapResearchgate = (url) => {
14
14
  const match = derefPathRegex.exec(url.pathname);
15
15
  if (!match?.[1]) return;
16
16
  if (isHttpUrl(match[1])) return `${match[1]}${url.search}${url.hash}`;
17
- try {
18
- const target = decodeURIComponent(match[1]);
19
- if (isHttpUrl(target)) return target;
20
- } catch {}
17
+ const target = decodePercent(match[1]);
18
+ if (isHttpUrl(target)) return target;
21
19
  };
22
20
  //#endregion
23
21
  export { unwrapResearchgate };
@@ -1,4 +1,4 @@
1
- import { isHttpUrl } from "../node_modules/trousse/dist/urls.mjs";
1
+ import { decodePercent, isHttpUrl } from "../node_modules/trousse/dist/urls.mjs";
2
2
  import { getParamTarget } from "../utils.mjs";
3
3
  //#region src/unwraps/reviveAdserver.ts
4
4
  const clickPathRegex = /^(?:\/[^/]+)*\/c[kl]\.php$/;
@@ -14,10 +14,8 @@ const unwrapReviveAdserver = (url) => {
14
14
  index = url.search.indexOf(marker);
15
15
  }
16
16
  if (index === -1) return;
17
- try {
18
- const target = decodeURIComponent(url.search.slice(index + marker.length));
19
- if (isHttpUrl(target)) return target;
20
- } catch {}
17
+ const target = decodePercent(url.search.slice(index + marker.length));
18
+ if (isHttpUrl(target)) return target;
21
19
  return;
22
20
  }
23
21
  if (!legacyClickPathRegex.test(url.pathname) || !url.searchParams.has("bannerid")) return;
@@ -1,10 +1,10 @@
1
1
  import { isHttpUrl } from "../node_modules/trousse/dist/urls.mjs";
2
- import { decodeBase64 } from "../utils.mjs";
2
+ import { decodeBase64, getParamValues } from "../utils.mjs";
3
3
  //#region src/unwraps/serendipity.ts
4
4
  const pathRegex = /^(?:\/[^/]+)?\/exit\.php$/;
5
5
  const unwrapSerendipity = (url) => {
6
6
  if (!pathRegex.test(url.pathname) || !url.searchParams.has("entry_id")) return;
7
- const raw = url.searchParams.get("url");
7
+ const raw = getParamValues(url, "url").at(0);
8
8
  if (!raw) return;
9
9
  const decoded = decodeBase64(raw);
10
10
  if (decoded && isHttpUrl(decoded)) return decoded;
@@ -1,4 +1,4 @@
1
- import { isHostOrSubdomainOf, isHttpUrl } from "../node_modules/trousse/dist/urls.mjs";
1
+ import { decodePercent, isHostOrSubdomainOf, isHttpUrl } from "../node_modules/trousse/dist/urls.mjs";
2
2
  //#region src/unwraps/streak.ts
3
3
  const domains = ["streaklinks.com", "streak-link.com"];
4
4
  const pathRegex = /^\/[\w-]{24}\/([^/]+)$/;
@@ -6,10 +6,8 @@ const unwrapStreak = (url) => {
6
6
  if (!isHostOrSubdomainOf(url, domains)) return;
7
7
  const match = pathRegex.exec(url.pathname);
8
8
  if (!match?.[1]) return;
9
- try {
10
- const target = decodeURIComponent(match[1]);
11
- if (isHttpUrl(target)) return target;
12
- } catch {}
9
+ const target = decodePercent(match[1]);
10
+ if (isHttpUrl(target)) return target;
13
11
  };
14
12
  //#endregion
15
13
  export { unwrapStreak };
@@ -1,4 +1,4 @@
1
- import { isHostOf, isHttpUrl } from "../node_modules/trousse/dist/urls.mjs";
1
+ import { decodePercent, isHostOf, isHttpUrl } from "../node_modules/trousse/dist/urls.mjs";
2
2
  //#region src/unwraps/surly.ts
3
3
  const pathRegex = /^\/o\/([^/].*?)(?:\/AA\d{6})?$/;
4
4
  const schemeRegex = /^https?:\/\//i;
@@ -6,13 +6,7 @@ const unwrapSurly = (url) => {
6
6
  if (!isHostOf(url, ["sur.ly", "www.sur.ly"])) return;
7
7
  const match = pathRegex.exec(url.pathname);
8
8
  if (!match?.[1]) return;
9
- let path;
10
- try {
11
- path = decodeURIComponent(match[1]);
12
- } catch {
13
- return;
14
- }
15
- const target = `https://${path.replace(schemeRegex, "")}`;
9
+ const target = `https://${decodePercent(match[1]).replace(schemeRegex, "")}`;
16
10
  if (isHttpUrl(target)) return target;
17
11
  };
18
12
  //#endregion
@@ -1,4 +1,4 @@
1
- import { decodeSegment, isHostOf, isHttpUrl } from "../node_modules/trousse/dist/urls.mjs";
1
+ import { decodePercent, isHostOf, isHttpUrl } from "../node_modules/trousse/dist/urls.mjs";
2
2
  //#region src/unwraps/webArchive.ts
3
3
  const hosts = [
4
4
  "web.archive.org",
@@ -30,7 +30,7 @@ const unwrapWebArchive = (url) => {
30
30
  if (isHostOf(url, "wayback.archive-it.org")) match = url.pathname.match(archiveItPathRegex);
31
31
  if (isHostOf(url, "scholar.archive.org")) match = url.pathname.match(scholarPathRegex);
32
32
  if (!match) return;
33
- let target = decodeSegment(match[1]);
33
+ let target = decodePercent(match[1]);
34
34
  if (target && !schemeRegex.test(target) && schemelessRegex.test(target)) target = `http://${target}`;
35
35
  if (!target || !isHttpUrl(target)) return;
36
36
  return `${target}${url.search}${url.hash}`;
@@ -1,9 +1,9 @@
1
1
  import { isHttpUrl } from "../node_modules/trousse/dist/urls.mjs";
2
- import { decodeBase64 } from "../utils.mjs";
2
+ import { decodeBase64, getParamValues } from "../utils.mjs";
3
3
  //#region src/unwraps/xengentr.ts
4
4
  const unwrapXengentr = (url) => {
5
5
  if (url.pathname !== "/yonlendirme") return;
6
- const raw = url.searchParams.get("to");
6
+ const raw = getParamValues(url, "to").at(0);
7
7
  if (!raw) return;
8
8
  const decoded = decodeBase64(raw);
9
9
  if (decoded && isHttpUrl(decoded)) return decoded;
@@ -1,4 +1,4 @@
1
- import { isHostOf, isHttpUrl } from "../node_modules/trousse/dist/urls.mjs";
1
+ import { decodePercent, isHostOf, isHttpUrl } from "../node_modules/trousse/dist/urls.mjs";
2
2
  //#region src/unwraps/yahooJapanAmpViewer.ts
3
3
  const httpsPathRegex = /^\/amp\/s\/(.+)$/;
4
4
  const httpPathRegex = /^\/amp\/(?!s\/)(.+)$/;
@@ -7,12 +7,7 @@ const unwrapYahooJapanAmpViewer = (url) => {
7
7
  const httpsMatch = httpsPathRegex.exec(url.pathname);
8
8
  const match = httpsMatch ?? httpPathRegex.exec(url.pathname);
9
9
  if (!match?.[1]) return;
10
- let path;
11
- try {
12
- path = decodeURIComponent(match[1]);
13
- } catch {
14
- return;
15
- }
10
+ const path = decodePercent(match[1]);
16
11
  const target = `${httpsMatch ? "https" : "http"}://${path}${url.search}`;
17
12
  if (isHttpUrl(target)) return target;
18
13
  };
@@ -1,4 +1,5 @@
1
- import { decodeSegment, isHostOf } from "../node_modules/trousse/dist/urls.mjs";
1
+ import { decodePercent, isHostOf } from "../node_modules/trousse/dist/urls.mjs";
2
+ import { decodeEncodedScheme } from "../utils.mjs";
2
3
  //#region src/unwraps/yahooSearch.ts
3
4
  const hosts = [
4
5
  "r.search.yahoo.com",
@@ -10,7 +11,7 @@ const unencodedTargetRegex = /^(?:\/[^/]+)*\/RU=(https?:\/\/.+?)\/RK=/;
10
11
  const unwrapYahooSearch = (url) => {
11
12
  if (!isHostOf(url, hosts)) return;
12
13
  const match = url.pathname.match(yahooPathRegex);
13
- if (match) return decodeSegment(match[1]);
14
+ if (match) return decodeEncodedScheme(decodePercent(match[1]));
14
15
  const unencodedMatch = url.pathname.match(unencodedTargetRegex);
15
16
  if (unencodedMatch) return unencodedMatch[1];
16
17
  };
@@ -1,10 +1,10 @@
1
1
  import { isHttpUrl } from "../node_modules/trousse/dist/urls.mjs";
2
- import { decodeBase64Url } from "../utils.mjs";
2
+ import { decodeBase64Url, getParamValues } from "../utils.mjs";
3
3
  //#region src/unwraps/yandexMail.ts
4
4
  const hostRegex = /^mail\.yandex\.(?:com\.tr|[a-z]{2,3})$/;
5
5
  const unwrapYandexMail = (url) => {
6
6
  if (!hostRegex.test(url.hostname) || url.pathname !== "/re.jsx") return;
7
- const value = url.searchParams.get("l");
7
+ const value = getParamValues(url, "l").at(0);
8
8
  if (!value) return;
9
9
  const decoded = decodeBase64Url(value);
10
10
  if (!decoded || !isHttpUrl(decoded)) return;
@@ -1,12 +1,12 @@
1
- import { isHttpUrl } from "../node_modules/trousse/dist/urls.mjs";
2
- import { getParamValues, percentDecode } from "../utils.mjs";
1
+ import { decodePercent, isHttpUrl } from "../node_modules/trousse/dist/urls.mjs";
2
+ import { getParamValues } from "../utils.mjs";
3
3
  //#region src/unwraps/yourMembership.ts
4
4
  const ymlinkRegex = /^\d+$/;
5
5
  const encodedSchemeRegex = /^https?%3A/i;
6
6
  const unwrapYourMembership = (url) => {
7
7
  if (url.pathname !== "/link.asp" || !ymlinkRegex.test(url.searchParams.get("ymlink") ?? "")) return;
8
8
  let target = getParamValues(url, "finalurl").at(0);
9
- if (target && encodedSchemeRegex.test(target)) target = percentDecode(target);
9
+ if (target && encodedSchemeRegex.test(target)) target = decodePercent(target);
10
10
  if (target && isHttpUrl(target)) return target;
11
11
  };
12
12
  //#endregion
package/dist/utils.mjs CHANGED
@@ -1,14 +1,10 @@
1
1
  import { isAnyOf } from "./node_modules/trousse/dist/matching.mjs";
2
- import { isHostOf, isHostOrSubdomainOf } from "./node_modules/trousse/dist/urls.mjs";
2
+ import { decodePercent, isHostOf, isHostOrSubdomainOf } from "./node_modules/trousse/dist/urls.mjs";
3
3
  //#region src/utils.ts
4
- const percentDecode = (value) => {
5
- const escaped = value.replaceAll("+", "%2B").replaceAll("&", "%26");
6
- return new URLSearchParams(`value=${escaped}`).get("value") ?? "";
7
- };
8
4
  const encodedSchemeRegex = /^https?%3A/i;
9
5
  const decodeEncodedScheme = (value) => {
10
6
  if (!encodedSchemeRegex.test(value)) return value;
11
- return percentDecode(value);
7
+ return decodePercent(value);
12
8
  };
13
9
  const unencodedTargetRegex = /^https?:\/\//i;
14
10
  const getParamValues = (url, name) => {
@@ -16,12 +12,13 @@ const getParamValues = (url, name) => {
16
12
  for (const pair of url.search.slice(1).split("&")) {
17
13
  const entry = new URLSearchParams(`&${pair}`).entries().next().value;
18
14
  if (!entry || entry[0] !== name) continue;
19
- const raw = pair.slice(pair.indexOf("=") + 1);
15
+ const separator = pair.indexOf("=");
16
+ const raw = separator === -1 ? "" : pair.slice(separator + 1);
20
17
  if (!unencodedTargetRegex.test(raw)) {
21
- values.push(entry[1]);
18
+ values.push(decodePercent(raw.replaceAll("+", " ")));
22
19
  continue;
23
20
  }
24
- values.push(percentDecode(raw));
21
+ values.push(decodePercent(raw));
25
22
  }
26
23
  return values;
27
24
  };
@@ -50,13 +47,19 @@ const decodeBase64Binary = (value) => {
50
47
  return atob(value);
51
48
  } catch {}
52
49
  };
53
- const utf8Decoder = new TextDecoder();
54
50
  const decodeBase64 = (value) => {
55
51
  const binary = decodeBase64Binary(value);
56
52
  if (binary === void 0) return;
57
- const bytes = new Uint8Array(binary.length);
58
- for (let index = 0; index < binary.length; index++) bytes[index] = binary.charCodeAt(index);
59
- return utf8Decoder.decode(bytes);
53
+ let encoded = "";
54
+ for (let index = 0; index < binary.length; index++) {
55
+ const byte = binary.charCodeAt(index);
56
+ if (byte < 128 && binary[index] !== "%") {
57
+ encoded += binary[index];
58
+ continue;
59
+ }
60
+ encoded += `%${byte.toString(16).toUpperCase().padStart(2, "0")}`;
61
+ }
62
+ return decodePercent(encoded);
60
63
  };
61
64
  const toBase64 = (base64Url) => {
62
65
  return base64Url.replace(/-/g, "+").replace(/_/g, "/");
@@ -72,4 +75,4 @@ const getUtf8ByteLength = (value) => {
72
75
  return utf8Encoder.encode(value).length;
73
76
  };
74
77
  //#endregion
75
- export { createParamExtractor, decodeBase64, decodeBase64Binary, decodeBase64Url, decodeBase64UrlBinary, getParamTarget, getParamValues, getUtf8ByteLength, percentDecode };
78
+ export { createParamExtractor, decodeBase64, decodeBase64Binary, decodeBase64Url, decodeBase64UrlBinary, decodeEncodedScheme, getParamTarget, getParamValues, getUtf8ByteLength };
package/package.json CHANGED
@@ -42,8 +42,8 @@
42
42
  "devDependencies": {
43
43
  "@types/bun": "^1.4.2",
44
44
  "kvalita": "^1.24.3",
45
- "trousse": "^2.10.1",
45
+ "trousse": "^2.15.0",
46
46
  "tsdown": "^0.23.0"
47
47
  },
48
- "version": "2.0.0"
48
+ "version": "2.1.0"
49
49
  }