@duckduckgo/autoconsent 9.1.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.
@@ -1994,9 +1994,23 @@
1994
1994
  return false;
1995
1995
  }
1996
1996
  this.updateState({ lifecycle: "cmpDetected" });
1997
- let foundPopups = await this.detectPopups(foundCmps.filter((r) => !r.isCosmetic));
1997
+ const staticCmps = [];
1998
+ const cosmeticCmps = [];
1999
+ for (const cmp of foundCmps) {
2000
+ if (cmp.isCosmetic) {
2001
+ cosmeticCmps.push(cmp);
2002
+ } else {
2003
+ staticCmps.push(cmp);
2004
+ }
2005
+ }
2006
+ let result = false;
2007
+ let foundPopups = await this.detectPopups(staticCmps, async (cmp) => {
2008
+ result = await this.handlePopup(cmp);
2009
+ });
1998
2010
  if (foundPopups.length === 0) {
1999
- foundPopups = await this.detectPopups(foundCmps.filter((r) => r.isCosmetic));
2011
+ foundPopups = await this.detectPopups(cosmeticCmps, async (cmp) => {
2012
+ result = await this.handlePopup(cmp);
2013
+ });
2000
2014
  }
2001
2015
  if (foundPopups.length === 0) {
2002
2016
  logsConfig.lifecycle && console.log("no popup found");
@@ -2005,10 +2019,6 @@
2005
2019
  }
2006
2020
  return false;
2007
2021
  }
2008
- this.updateState({ lifecycle: "openPopupDetected" });
2009
- if (this.config.enablePrehide && !this.state.prehideOn) {
2010
- this.prehideElements();
2011
- }
2012
2022
  if (foundPopups.length > 1) {
2013
2023
  const errorDetails = {
2014
2024
  msg: `Found multiple CMPs, check the detection rules.`,
@@ -2020,15 +2030,7 @@
2020
2030
  details: errorDetails
2021
2031
  });
2022
2032
  }
2023
- this.foundCmp = foundPopups[0];
2024
- if (this.config.autoAction === "optOut") {
2025
- return await this.doOptOut();
2026
- } else if (this.config.autoAction === "optIn") {
2027
- return await this.doOptIn();
2028
- } else {
2029
- logsConfig.lifecycle && console.log("waiting for opt-out signal...", location.href);
2030
- return true;
2031
- }
2033
+ return result;
2032
2034
  }
2033
2035
  async findCmp(retries) {
2034
2036
  const logsConfig = this.config.logs;
@@ -2059,25 +2061,51 @@
2059
2061
  }
2060
2062
  return foundCMPs;
2061
2063
  }
2062
- async detectPopups(cmps) {
2063
- const logsConfig = this.config.logs;
2064
- const result = [];
2065
- const popupLookups = cmps.map((cmp) => this.waitForPopup(cmp).then((isOpen) => {
2066
- if (isOpen) {
2067
- this.updateState({ detectedPopups: this.state.detectedPopups.concat([cmp.name]) });
2068
- this.sendContentMessage({
2069
- type: "popupFound",
2070
- cmp: cmp.name,
2071
- url: location.href
2072
- });
2073
- result.push(cmp);
2064
+ async detectPopup(cmp) {
2065
+ const isOpen = await this.waitForPopup(cmp);
2066
+ if (isOpen) {
2067
+ this.updateState({ detectedPopups: this.state.detectedPopups.concat([cmp.name]) });
2068
+ this.sendContentMessage({
2069
+ type: "popupFound",
2070
+ cmp: cmp.name,
2071
+ url: location.href
2072
+ });
2073
+ }
2074
+ return cmp;
2075
+ }
2076
+ async detectPopups(cmps, onFirstPopupAppears) {
2077
+ const tasks = cmps.map(
2078
+ (cmp) => this.detectPopup(cmp).catch((error) => {
2079
+ this.config.logs.errors && console.warn(`error waiting for a popup for ${cmp.name}`, error);
2080
+ throw error;
2081
+ })
2082
+ );
2083
+ await Promise.any(tasks).then((cmp) => {
2084
+ onFirstPopupAppears(cmp);
2085
+ }).catch(() => null);
2086
+ const results = await Promise.allSettled(tasks);
2087
+ const popups = [];
2088
+ for (const result of results) {
2089
+ if (result.status === "fulfilled") {
2090
+ popups.push(result.value);
2074
2091
  }
2075
- }).catch((e) => {
2076
- logsConfig.errors && console.warn(`error waiting for a popup for ${cmp.name}`, e);
2077
- return null;
2078
- }));
2079
- await Promise.all(popupLookups);
2080
- return result;
2092
+ }
2093
+ return popups;
2094
+ }
2095
+ async handlePopup(cmp) {
2096
+ this.updateState({ lifecycle: "openPopupDetected" });
2097
+ if (this.config.enablePrehide && !this.state.prehideOn) {
2098
+ this.prehideElements();
2099
+ }
2100
+ this.foundCmp = cmp;
2101
+ if (this.config.autoAction === "optOut") {
2102
+ return await this.doOptOut();
2103
+ } else if (this.config.autoAction === "optIn") {
2104
+ return await this.doOptIn();
2105
+ } else {
2106
+ this.config.logs.lifecycle && console.log("waiting for opt-out signal...", location.href);
2107
+ return true;
2108
+ }
2081
2109
  }
2082
2110
  async doOptOut() {
2083
2111
  const logsConfig = this.config.logs;
package/lib/web.ts CHANGED
@@ -149,9 +149,22 @@ export default class AutoConsent {
149
149
  this.updateState({ lifecycle: 'cmpDetected' });
150
150
 
151
151
  // we resort to cosmetic rules only if no non-cosmetic rules are found
152
- let foundPopups = await this.detectPopups(foundCmps.filter(r => !r.isCosmetic))
152
+ const staticCmps: AutoCMP[] = []
153
+ const cosmeticCmps: AutoCMP[] = []
154
+
155
+ for (const cmp of foundCmps) {
156
+ if (cmp.isCosmetic) {
157
+ cosmeticCmps.push(cmp)
158
+ } else {
159
+ staticCmps.push(cmp)
160
+ }
161
+ }
162
+
163
+ let result = false
164
+
165
+ let foundPopups = await this.detectPopups(staticCmps, async cmp => { result = await this.handlePopup(cmp) })
153
166
  if (foundPopups.length === 0) {
154
- foundPopups = await this.detectPopups(foundCmps.filter(r => r.isCosmetic))
167
+ foundPopups = await this.detectPopups(cosmeticCmps, async cmp => { result = await this.handlePopup(cmp) })
155
168
  }
156
169
 
157
170
  if (foundPopups.length === 0) {
@@ -162,11 +175,6 @@ export default class AutoConsent {
162
175
  return false;
163
176
  }
164
177
 
165
- this.updateState({ lifecycle: 'openPopupDetected' });
166
- if (this.config.enablePrehide && !this.state.prehideOn) { // prehide might have timeouted by this time, apply it again
167
- this.prehideElements();
168
- }
169
-
170
178
  if (foundPopups.length > 1) {
171
179
  const errorDetails = {
172
180
  msg: `Found multiple CMPs, check the detection rules.`,
@@ -179,16 +187,7 @@ export default class AutoConsent {
179
187
  });
180
188
  }
181
189
 
182
- this.foundCmp = foundPopups[0];
183
-
184
- if (this.config.autoAction === 'optOut') {
185
- return await this.doOptOut();
186
- } else if (this.config.autoAction === 'optIn') {
187
- return await this.doOptIn();
188
- } else {
189
- logsConfig.lifecycle && console.log("waiting for opt-out signal...", location.href);
190
- return true;
191
- }
190
+ return result
192
191
  }
193
192
 
194
193
  async findCmp(retries: number): Promise<AutoCMP[]> {
@@ -224,25 +223,66 @@ export default class AutoConsent {
224
223
  return foundCMPs;
225
224
  }
226
225
 
227
- async detectPopups(cmps: AutoCMP[]): Promise<AutoCMP[]> {
228
- const logsConfig = this.config.logs;
229
- const result: AutoCMP[] = [];
230
- const popupLookups = cmps.map((cmp) => this.waitForPopup(cmp).then((isOpen) => {
231
- if (isOpen) {
232
- this.updateState({ detectedPopups: this.state.detectedPopups.concat([cmp.name]) });
233
- this.sendContentMessage({
234
- type: 'popupFound',
235
- cmp: cmp.name,
236
- url: location.href,
237
- }); // notify the browser
238
- result.push(cmp);
226
+ async detectPopup(cmp: AutoCMP): Promise<AutoCMP> {
227
+ const isOpen = await this.waitForPopup(cmp);
228
+
229
+ if (isOpen) {
230
+ this.updateState({ detectedPopups: this.state.detectedPopups.concat([cmp.name]) });
231
+ this.sendContentMessage({
232
+ type: 'popupFound',
233
+ cmp: cmp.name,
234
+ url: location.href,
235
+ }); // notify the browser
236
+ }
237
+
238
+ return cmp
239
+ }
240
+
241
+ async detectPopups(cmps: AutoCMP[], onFirstPopupAppears: (cmp: AutoCMP) => Promise<unknown>) {
242
+ const tasks = cmps.map(
243
+ cmp => this.detectPopup(cmp)
244
+ // Handle errors immediately and propagate the error to next handler: Promise.allSettled
245
+ .catch(error => {
246
+ this.config.logs.errors && console.warn(`error waiting for a popup for ${cmp.name}`, error)
247
+
248
+ throw error
249
+ })
250
+ )
251
+
252
+ await Promise.any(tasks)
253
+ .then(cmp => {
254
+ onFirstPopupAppears(cmp)
255
+ })
256
+ .catch(() => null)
257
+
258
+ const results = await Promise.allSettled(tasks)
259
+ const popups: AutoCMP[] = []
260
+
261
+ for (const result of results) {
262
+ if (result.status === 'fulfilled') {
263
+ popups.push(result.value)
239
264
  }
240
- }).catch((e) => {
241
- logsConfig.errors && console.warn(`error waiting for a popup for ${cmp.name}`, e);
242
- return null
243
- }));
244
- await Promise.all(popupLookups);
245
- return result;
265
+ }
266
+
267
+ return popups
268
+ }
269
+
270
+ async handlePopup(cmp: AutoCMP): Promise<boolean> {
271
+ this.updateState({ lifecycle: 'openPopupDetected' });
272
+ if (this.config.enablePrehide && !this.state.prehideOn) { // prehide might have timeouted by this time, apply it again
273
+ this.prehideElements();
274
+ }
275
+
276
+ this.foundCmp = cmp;
277
+
278
+ if (this.config.autoAction === 'optOut') {
279
+ return await this.doOptOut();
280
+ } else if (this.config.autoAction === 'optIn') {
281
+ return await this.doOptIn();
282
+ } else {
283
+ this.config.logs.lifecycle && console.log("waiting for opt-out signal...", location.href);
284
+ return true;
285
+ }
246
286
  }
247
287
 
248
288
  async doOptOut(): Promise<boolean> {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@duckduckgo/autoconsent",
3
- "version": "9.1.0",
3
+ "version": "9.2.0",
4
4
  "description": "",
5
5
  "main": "dist/autoconsent.cjs.js",
6
6
  "module": "dist/autoconsent.esm.js",