@duckduckgo/autoconsent 9.0.0 → 9.2.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.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,27 @@
1
+ # v9.2.0 (Thu Jan 25 2024)
2
+
3
+ #### 🚀 Enhancement
4
+
5
+ - Handle popup right after first popup detected (#326) [#327](https://github.com/duckduckgo/autoconsent/pull/327) ([@seia-soto](https://github.com/seia-soto))
6
+
7
+ #### Authors: 1
8
+
9
+ - HoJeong Go ([@seia-soto](https://github.com/seia-soto))
10
+
11
+ ---
12
+
13
+ # v9.1.0 (Thu Jan 11 2024)
14
+
15
+ #### 🚀 Enhancement
16
+
17
+ - Add a rule for lightbox CMP [#329](https://github.com/duckduckgo/autoconsent/pull/329) ([@seia-soto](https://github.com/seia-soto))
18
+
19
+ #### Authors: 1
20
+
21
+ - HoJeong Go ([@seia-soto](https://github.com/seia-soto))
22
+
23
+ ---
24
+
1
25
  # v9.0.0 (Thu Jan 11 2024)
2
26
 
3
27
  #### 💥 Breaking Change
@@ -1989,9 +1989,23 @@
1989
1989
  return false;
1990
1990
  }
1991
1991
  this.updateState({ lifecycle: "cmpDetected" });
1992
- let foundPopups = await this.detectPopups(foundCmps.filter((r) => !r.isCosmetic));
1992
+ const staticCmps = [];
1993
+ const cosmeticCmps = [];
1994
+ for (const cmp of foundCmps) {
1995
+ if (cmp.isCosmetic) {
1996
+ cosmeticCmps.push(cmp);
1997
+ } else {
1998
+ staticCmps.push(cmp);
1999
+ }
2000
+ }
2001
+ let result = false;
2002
+ let foundPopups = await this.detectPopups(staticCmps, async (cmp) => {
2003
+ result = await this.handlePopup(cmp);
2004
+ });
1993
2005
  if (foundPopups.length === 0) {
1994
- foundPopups = await this.detectPopups(foundCmps.filter((r) => r.isCosmetic));
2006
+ foundPopups = await this.detectPopups(cosmeticCmps, async (cmp) => {
2007
+ result = await this.handlePopup(cmp);
2008
+ });
1995
2009
  }
1996
2010
  if (foundPopups.length === 0) {
1997
2011
  logsConfig.lifecycle && console.log("no popup found");
@@ -2000,10 +2014,6 @@
2000
2014
  }
2001
2015
  return false;
2002
2016
  }
2003
- this.updateState({ lifecycle: "openPopupDetected" });
2004
- if (this.config.enablePrehide && !this.state.prehideOn) {
2005
- this.prehideElements();
2006
- }
2007
2017
  if (foundPopups.length > 1) {
2008
2018
  const errorDetails = {
2009
2019
  msg: `Found multiple CMPs, check the detection rules.`,
@@ -2015,15 +2025,7 @@
2015
2025
  details: errorDetails
2016
2026
  });
2017
2027
  }
2018
- this.foundCmp = foundPopups[0];
2019
- if (this.config.autoAction === "optOut") {
2020
- return await this.doOptOut();
2021
- } else if (this.config.autoAction === "optIn") {
2022
- return await this.doOptIn();
2023
- } else {
2024
- logsConfig.lifecycle && console.log("waiting for opt-out signal...", location.href);
2025
- return true;
2026
- }
2028
+ return result;
2027
2029
  }
2028
2030
  async findCmp(retries) {
2029
2031
  const logsConfig = this.config.logs;
@@ -2054,25 +2056,51 @@
2054
2056
  }
2055
2057
  return foundCMPs;
2056
2058
  }
2057
- async detectPopups(cmps) {
2058
- const logsConfig = this.config.logs;
2059
- const result = [];
2060
- const popupLookups = cmps.map((cmp) => this.waitForPopup(cmp).then((isOpen) => {
2061
- if (isOpen) {
2062
- this.updateState({ detectedPopups: this.state.detectedPopups.concat([cmp.name]) });
2063
- this.sendContentMessage({
2064
- type: "popupFound",
2065
- cmp: cmp.name,
2066
- url: location.href
2067
- });
2068
- result.push(cmp);
2059
+ async detectPopup(cmp) {
2060
+ const isOpen = await this.waitForPopup(cmp);
2061
+ if (isOpen) {
2062
+ this.updateState({ detectedPopups: this.state.detectedPopups.concat([cmp.name]) });
2063
+ this.sendContentMessage({
2064
+ type: "popupFound",
2065
+ cmp: cmp.name,
2066
+ url: location.href
2067
+ });
2068
+ }
2069
+ return cmp;
2070
+ }
2071
+ async detectPopups(cmps, onFirstPopupAppears) {
2072
+ const tasks = cmps.map(
2073
+ (cmp) => this.detectPopup(cmp).catch((error) => {
2074
+ this.config.logs.errors && console.warn(`error waiting for a popup for ${cmp.name}`, error);
2075
+ throw error;
2076
+ })
2077
+ );
2078
+ await Promise.any(tasks).then((cmp) => {
2079
+ onFirstPopupAppears(cmp);
2080
+ }).catch(() => null);
2081
+ const results = await Promise.allSettled(tasks);
2082
+ const popups = [];
2083
+ for (const result of results) {
2084
+ if (result.status === "fulfilled") {
2085
+ popups.push(result.value);
2069
2086
  }
2070
- }).catch((e) => {
2071
- logsConfig.errors && console.warn(`error waiting for a popup for ${cmp.name}`, e);
2072
- return null;
2073
- }));
2074
- await Promise.all(popupLookups);
2075
- return result;
2087
+ }
2088
+ return popups;
2089
+ }
2090
+ async handlePopup(cmp) {
2091
+ this.updateState({ lifecycle: "openPopupDetected" });
2092
+ if (this.config.enablePrehide && !this.state.prehideOn) {
2093
+ this.prehideElements();
2094
+ }
2095
+ this.foundCmp = cmp;
2096
+ if (this.config.autoAction === "optOut") {
2097
+ return await this.doOptOut();
2098
+ } else if (this.config.autoAction === "optIn") {
2099
+ return await this.doOptIn();
2100
+ } else {
2101
+ this.config.logs.lifecycle && console.log("waiting for opt-out signal...", location.href);
2102
+ return true;
2103
+ }
2076
2104
  }
2077
2105
  async doOptOut() {
2078
2106
  const logsConfig = this.config.logs;
@@ -2929,6 +2929,32 @@
2929
2929
  }
2930
2930
  ]
2931
2931
  },
2932
+ {
2933
+ "name": "lightbox",
2934
+ "prehideSelectors": [
2935
+ ".darken-layer.open,.lightbox.lightbox--cookie-consent"
2936
+ ],
2937
+ "detectCmp": [
2938
+ {
2939
+ "exists": "body.cookie-consent-is-active div.lightbox--cookie-consent > div.lightbox__content > div.cookie-consent[data-jsb]"
2940
+ }
2941
+ ],
2942
+ "detectPopup": [
2943
+ {
2944
+ "visible": "body.cookie-consent-is-active div.lightbox--cookie-consent > div.lightbox__content > div.cookie-consent[data-jsb]"
2945
+ }
2946
+ ],
2947
+ "optOut": [
2948
+ {
2949
+ "click": ".cookie-consent__footer > button[type='submit']:not([data-button='selectAll'])"
2950
+ }
2951
+ ],
2952
+ "optIn": [
2953
+ {
2954
+ "click": ".cookie-consent__footer > button[type='submit'][data-button='selectAll']"
2955
+ }
2956
+ ]
2957
+ },
2932
2958
  {
2933
2959
  "name": "linkedin.com",
2934
2960
  "prehideSelectors": [
@@ -1989,9 +1989,23 @@
1989
1989
  return false;
1990
1990
  }
1991
1991
  this.updateState({ lifecycle: "cmpDetected" });
1992
- let foundPopups = await this.detectPopups(foundCmps.filter((r) => !r.isCosmetic));
1992
+ const staticCmps = [];
1993
+ const cosmeticCmps = [];
1994
+ for (const cmp of foundCmps) {
1995
+ if (cmp.isCosmetic) {
1996
+ cosmeticCmps.push(cmp);
1997
+ } else {
1998
+ staticCmps.push(cmp);
1999
+ }
2000
+ }
2001
+ let result = false;
2002
+ let foundPopups = await this.detectPopups(staticCmps, async (cmp) => {
2003
+ result = await this.handlePopup(cmp);
2004
+ });
1993
2005
  if (foundPopups.length === 0) {
1994
- foundPopups = await this.detectPopups(foundCmps.filter((r) => r.isCosmetic));
2006
+ foundPopups = await this.detectPopups(cosmeticCmps, async (cmp) => {
2007
+ result = await this.handlePopup(cmp);
2008
+ });
1995
2009
  }
1996
2010
  if (foundPopups.length === 0) {
1997
2011
  logsConfig.lifecycle && console.log("no popup found");
@@ -2000,10 +2014,6 @@
2000
2014
  }
2001
2015
  return false;
2002
2016
  }
2003
- this.updateState({ lifecycle: "openPopupDetected" });
2004
- if (this.config.enablePrehide && !this.state.prehideOn) {
2005
- this.prehideElements();
2006
- }
2007
2017
  if (foundPopups.length > 1) {
2008
2018
  const errorDetails = {
2009
2019
  msg: `Found multiple CMPs, check the detection rules.`,
@@ -2015,15 +2025,7 @@
2015
2025
  details: errorDetails
2016
2026
  });
2017
2027
  }
2018
- this.foundCmp = foundPopups[0];
2019
- if (this.config.autoAction === "optOut") {
2020
- return await this.doOptOut();
2021
- } else if (this.config.autoAction === "optIn") {
2022
- return await this.doOptIn();
2023
- } else {
2024
- logsConfig.lifecycle && console.log("waiting for opt-out signal...", location.href);
2025
- return true;
2026
- }
2028
+ return result;
2027
2029
  }
2028
2030
  async findCmp(retries) {
2029
2031
  const logsConfig = this.config.logs;
@@ -2054,25 +2056,51 @@
2054
2056
  }
2055
2057
  return foundCMPs;
2056
2058
  }
2057
- async detectPopups(cmps) {
2058
- const logsConfig = this.config.logs;
2059
- const result = [];
2060
- const popupLookups = cmps.map((cmp) => this.waitForPopup(cmp).then((isOpen) => {
2061
- if (isOpen) {
2062
- this.updateState({ detectedPopups: this.state.detectedPopups.concat([cmp.name]) });
2063
- this.sendContentMessage({
2064
- type: "popupFound",
2065
- cmp: cmp.name,
2066
- url: location.href
2067
- });
2068
- result.push(cmp);
2059
+ async detectPopup(cmp) {
2060
+ const isOpen = await this.waitForPopup(cmp);
2061
+ if (isOpen) {
2062
+ this.updateState({ detectedPopups: this.state.detectedPopups.concat([cmp.name]) });
2063
+ this.sendContentMessage({
2064
+ type: "popupFound",
2065
+ cmp: cmp.name,
2066
+ url: location.href
2067
+ });
2068
+ }
2069
+ return cmp;
2070
+ }
2071
+ async detectPopups(cmps, onFirstPopupAppears) {
2072
+ const tasks = cmps.map(
2073
+ (cmp) => this.detectPopup(cmp).catch((error) => {
2074
+ this.config.logs.errors && console.warn(`error waiting for a popup for ${cmp.name}`, error);
2075
+ throw error;
2076
+ })
2077
+ );
2078
+ await Promise.any(tasks).then((cmp) => {
2079
+ onFirstPopupAppears(cmp);
2080
+ }).catch(() => null);
2081
+ const results = await Promise.allSettled(tasks);
2082
+ const popups = [];
2083
+ for (const result of results) {
2084
+ if (result.status === "fulfilled") {
2085
+ popups.push(result.value);
2069
2086
  }
2070
- }).catch((e) => {
2071
- logsConfig.errors && console.warn(`error waiting for a popup for ${cmp.name}`, e);
2072
- return null;
2073
- }));
2074
- await Promise.all(popupLookups);
2075
- return result;
2087
+ }
2088
+ return popups;
2089
+ }
2090
+ async handlePopup(cmp) {
2091
+ this.updateState({ lifecycle: "openPopupDetected" });
2092
+ if (this.config.enablePrehide && !this.state.prehideOn) {
2093
+ this.prehideElements();
2094
+ }
2095
+ this.foundCmp = cmp;
2096
+ if (this.config.autoAction === "optOut") {
2097
+ return await this.doOptOut();
2098
+ } else if (this.config.autoAction === "optIn") {
2099
+ return await this.doOptIn();
2100
+ } else {
2101
+ this.config.logs.lifecycle && console.log("waiting for opt-out signal...", location.href);
2102
+ return true;
2103
+ }
2076
2104
  }
2077
2105
  async doOptOut() {
2078
2106
  const logsConfig = this.config.logs;
@@ -2929,6 +2929,32 @@
2929
2929
  }
2930
2930
  ]
2931
2931
  },
2932
+ {
2933
+ "name": "lightbox",
2934
+ "prehideSelectors": [
2935
+ ".darken-layer.open,.lightbox.lightbox--cookie-consent"
2936
+ ],
2937
+ "detectCmp": [
2938
+ {
2939
+ "exists": "body.cookie-consent-is-active div.lightbox--cookie-consent > div.lightbox__content > div.cookie-consent[data-jsb]"
2940
+ }
2941
+ ],
2942
+ "detectPopup": [
2943
+ {
2944
+ "visible": "body.cookie-consent-is-active div.lightbox--cookie-consent > div.lightbox__content > div.cookie-consent[data-jsb]"
2945
+ }
2946
+ ],
2947
+ "optOut": [
2948
+ {
2949
+ "click": ".cookie-consent__footer > button[type='submit']:not([data-button='selectAll'])"
2950
+ }
2951
+ ],
2952
+ "optIn": [
2953
+ {
2954
+ "click": ".cookie-consent__footer > button[type='submit'][data-button='selectAll']"
2955
+ }
2956
+ ]
2957
+ },
2932
2958
  {
2933
2959
  "name": "linkedin.com",
2934
2960
  "prehideSelectors": [
@@ -2012,9 +2012,23 @@ var AutoConsent = class {
2012
2012
  return false;
2013
2013
  }
2014
2014
  this.updateState({ lifecycle: "cmpDetected" });
2015
- let foundPopups = await this.detectPopups(foundCmps.filter((r) => !r.isCosmetic));
2015
+ const staticCmps = [];
2016
+ const cosmeticCmps = [];
2017
+ for (const cmp of foundCmps) {
2018
+ if (cmp.isCosmetic) {
2019
+ cosmeticCmps.push(cmp);
2020
+ } else {
2021
+ staticCmps.push(cmp);
2022
+ }
2023
+ }
2024
+ let result = false;
2025
+ let foundPopups = await this.detectPopups(staticCmps, async (cmp) => {
2026
+ result = await this.handlePopup(cmp);
2027
+ });
2016
2028
  if (foundPopups.length === 0) {
2017
- foundPopups = await this.detectPopups(foundCmps.filter((r) => r.isCosmetic));
2029
+ foundPopups = await this.detectPopups(cosmeticCmps, async (cmp) => {
2030
+ result = await this.handlePopup(cmp);
2031
+ });
2018
2032
  }
2019
2033
  if (foundPopups.length === 0) {
2020
2034
  logsConfig.lifecycle && console.log("no popup found");
@@ -2023,10 +2037,6 @@ var AutoConsent = class {
2023
2037
  }
2024
2038
  return false;
2025
2039
  }
2026
- this.updateState({ lifecycle: "openPopupDetected" });
2027
- if (this.config.enablePrehide && !this.state.prehideOn) {
2028
- this.prehideElements();
2029
- }
2030
2040
  if (foundPopups.length > 1) {
2031
2041
  const errorDetails = {
2032
2042
  msg: `Found multiple CMPs, check the detection rules.`,
@@ -2038,15 +2048,7 @@ var AutoConsent = class {
2038
2048
  details: errorDetails
2039
2049
  });
2040
2050
  }
2041
- this.foundCmp = foundPopups[0];
2042
- if (this.config.autoAction === "optOut") {
2043
- return await this.doOptOut();
2044
- } else if (this.config.autoAction === "optIn") {
2045
- return await this.doOptIn();
2046
- } else {
2047
- logsConfig.lifecycle && console.log("waiting for opt-out signal...", location.href);
2048
- return true;
2049
- }
2051
+ return result;
2050
2052
  }
2051
2053
  async findCmp(retries) {
2052
2054
  const logsConfig = this.config.logs;
@@ -2077,25 +2079,51 @@ var AutoConsent = class {
2077
2079
  }
2078
2080
  return foundCMPs;
2079
2081
  }
2080
- async detectPopups(cmps) {
2081
- const logsConfig = this.config.logs;
2082
- const result = [];
2083
- const popupLookups = cmps.map((cmp) => this.waitForPopup(cmp).then((isOpen) => {
2084
- if (isOpen) {
2085
- this.updateState({ detectedPopups: this.state.detectedPopups.concat([cmp.name]) });
2086
- this.sendContentMessage({
2087
- type: "popupFound",
2088
- cmp: cmp.name,
2089
- url: location.href
2090
- });
2091
- result.push(cmp);
2082
+ async detectPopup(cmp) {
2083
+ const isOpen = await this.waitForPopup(cmp);
2084
+ if (isOpen) {
2085
+ this.updateState({ detectedPopups: this.state.detectedPopups.concat([cmp.name]) });
2086
+ this.sendContentMessage({
2087
+ type: "popupFound",
2088
+ cmp: cmp.name,
2089
+ url: location.href
2090
+ });
2091
+ }
2092
+ return cmp;
2093
+ }
2094
+ async detectPopups(cmps, onFirstPopupAppears) {
2095
+ const tasks = cmps.map(
2096
+ (cmp) => this.detectPopup(cmp).catch((error) => {
2097
+ this.config.logs.errors && console.warn(`error waiting for a popup for ${cmp.name}`, error);
2098
+ throw error;
2099
+ })
2100
+ );
2101
+ await Promise.any(tasks).then((cmp) => {
2102
+ onFirstPopupAppears(cmp);
2103
+ }).catch(() => null);
2104
+ const results = await Promise.allSettled(tasks);
2105
+ const popups = [];
2106
+ for (const result of results) {
2107
+ if (result.status === "fulfilled") {
2108
+ popups.push(result.value);
2092
2109
  }
2093
- }).catch((e) => {
2094
- logsConfig.errors && console.warn(`error waiting for a popup for ${cmp.name}`, e);
2095
- return null;
2096
- }));
2097
- await Promise.all(popupLookups);
2098
- return result;
2110
+ }
2111
+ return popups;
2112
+ }
2113
+ async handlePopup(cmp) {
2114
+ this.updateState({ lifecycle: "openPopupDetected" });
2115
+ if (this.config.enablePrehide && !this.state.prehideOn) {
2116
+ this.prehideElements();
2117
+ }
2118
+ this.foundCmp = cmp;
2119
+ if (this.config.autoAction === "optOut") {
2120
+ return await this.doOptOut();
2121
+ } else if (this.config.autoAction === "optIn") {
2122
+ return await this.doOptIn();
2123
+ } else {
2124
+ this.config.logs.lifecycle && console.log("waiting for opt-out signal...", location.href);
2125
+ return true;
2126
+ }
2099
2127
  }
2100
2128
  async doOptOut() {
2101
2129
  const logsConfig = this.config.logs;
@@ -1987,9 +1987,23 @@ var AutoConsent = class {
1987
1987
  return false;
1988
1988
  }
1989
1989
  this.updateState({ lifecycle: "cmpDetected" });
1990
- let foundPopups = await this.detectPopups(foundCmps.filter((r) => !r.isCosmetic));
1990
+ const staticCmps = [];
1991
+ const cosmeticCmps = [];
1992
+ for (const cmp of foundCmps) {
1993
+ if (cmp.isCosmetic) {
1994
+ cosmeticCmps.push(cmp);
1995
+ } else {
1996
+ staticCmps.push(cmp);
1997
+ }
1998
+ }
1999
+ let result = false;
2000
+ let foundPopups = await this.detectPopups(staticCmps, async (cmp) => {
2001
+ result = await this.handlePopup(cmp);
2002
+ });
1991
2003
  if (foundPopups.length === 0) {
1992
- foundPopups = await this.detectPopups(foundCmps.filter((r) => r.isCosmetic));
2004
+ foundPopups = await this.detectPopups(cosmeticCmps, async (cmp) => {
2005
+ result = await this.handlePopup(cmp);
2006
+ });
1993
2007
  }
1994
2008
  if (foundPopups.length === 0) {
1995
2009
  logsConfig.lifecycle && console.log("no popup found");
@@ -1998,10 +2012,6 @@ var AutoConsent = class {
1998
2012
  }
1999
2013
  return false;
2000
2014
  }
2001
- this.updateState({ lifecycle: "openPopupDetected" });
2002
- if (this.config.enablePrehide && !this.state.prehideOn) {
2003
- this.prehideElements();
2004
- }
2005
2015
  if (foundPopups.length > 1) {
2006
2016
  const errorDetails = {
2007
2017
  msg: `Found multiple CMPs, check the detection rules.`,
@@ -2013,15 +2023,7 @@ var AutoConsent = class {
2013
2023
  details: errorDetails
2014
2024
  });
2015
2025
  }
2016
- this.foundCmp = foundPopups[0];
2017
- if (this.config.autoAction === "optOut") {
2018
- return await this.doOptOut();
2019
- } else if (this.config.autoAction === "optIn") {
2020
- return await this.doOptIn();
2021
- } else {
2022
- logsConfig.lifecycle && console.log("waiting for opt-out signal...", location.href);
2023
- return true;
2024
- }
2026
+ return result;
2025
2027
  }
2026
2028
  async findCmp(retries) {
2027
2029
  const logsConfig = this.config.logs;
@@ -2052,25 +2054,51 @@ var AutoConsent = class {
2052
2054
  }
2053
2055
  return foundCMPs;
2054
2056
  }
2055
- async detectPopups(cmps) {
2056
- const logsConfig = this.config.logs;
2057
- const result = [];
2058
- const popupLookups = cmps.map((cmp) => this.waitForPopup(cmp).then((isOpen) => {
2059
- if (isOpen) {
2060
- this.updateState({ detectedPopups: this.state.detectedPopups.concat([cmp.name]) });
2061
- this.sendContentMessage({
2062
- type: "popupFound",
2063
- cmp: cmp.name,
2064
- url: location.href
2065
- });
2066
- result.push(cmp);
2057
+ async detectPopup(cmp) {
2058
+ const isOpen = await this.waitForPopup(cmp);
2059
+ if (isOpen) {
2060
+ this.updateState({ detectedPopups: this.state.detectedPopups.concat([cmp.name]) });
2061
+ this.sendContentMessage({
2062
+ type: "popupFound",
2063
+ cmp: cmp.name,
2064
+ url: location.href
2065
+ });
2066
+ }
2067
+ return cmp;
2068
+ }
2069
+ async detectPopups(cmps, onFirstPopupAppears) {
2070
+ const tasks = cmps.map(
2071
+ (cmp) => this.detectPopup(cmp).catch((error) => {
2072
+ this.config.logs.errors && console.warn(`error waiting for a popup for ${cmp.name}`, error);
2073
+ throw error;
2074
+ })
2075
+ );
2076
+ await Promise.any(tasks).then((cmp) => {
2077
+ onFirstPopupAppears(cmp);
2078
+ }).catch(() => null);
2079
+ const results = await Promise.allSettled(tasks);
2080
+ const popups = [];
2081
+ for (const result of results) {
2082
+ if (result.status === "fulfilled") {
2083
+ popups.push(result.value);
2067
2084
  }
2068
- }).catch((e) => {
2069
- logsConfig.errors && console.warn(`error waiting for a popup for ${cmp.name}`, e);
2070
- return null;
2071
- }));
2072
- await Promise.all(popupLookups);
2073
- return result;
2085
+ }
2086
+ return popups;
2087
+ }
2088
+ async handlePopup(cmp) {
2089
+ this.updateState({ lifecycle: "openPopupDetected" });
2090
+ if (this.config.enablePrehide && !this.state.prehideOn) {
2091
+ this.prehideElements();
2092
+ }
2093
+ this.foundCmp = cmp;
2094
+ if (this.config.autoAction === "optOut") {
2095
+ return await this.doOptOut();
2096
+ } else if (this.config.autoAction === "optIn") {
2097
+ return await this.doOptIn();
2098
+ } else {
2099
+ this.config.logs.lifecycle && console.log("waiting for opt-out signal...", location.href);
2100
+ return true;
2101
+ }
2074
2102
  }
2075
2103
  async doOptOut() {
2076
2104
  const logsConfig = this.config.logs;