@browserless.io/browserless 2.36.0 → 2.37.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 (369) hide show
  1. package/CHANGELOG.md +16 -2
  2. package/build/browsers/index.d.ts +1 -0
  3. package/build/browsers/index.js +3 -2
  4. package/build/http.d.ts +3 -2
  5. package/build/http.js +3 -2
  6. package/build/routes/chrome/tests/kill-sessions.spec.js +0 -11
  7. package/build/routes/chrome/ws/function-connect.d.ts +7 -0
  8. package/build/routes/chrome/ws/function-connect.js +6 -0
  9. package/build/routes/chrome/ws/function-connect.query.json +120 -0
  10. package/build/routes/chromium/ws/function-connect.d.ts +1 -0
  11. package/build/routes/chromium/ws/function-connect.js +1 -0
  12. package/build/routes/chromium/ws/function-connect.query.json +120 -0
  13. package/build/routes/edge/ws/function-connect.d.ts +7 -0
  14. package/build/routes/edge/ws/function-connect.js +6 -0
  15. package/build/routes/edge/ws/function-connect.query.json +120 -0
  16. package/build/sdk-utils.js +1 -1
  17. package/build/shared/function-connect.ws.d.ts +15 -0
  18. package/build/shared/function-connect.ws.js +13 -0
  19. package/build/shared/utils/function/handler.js +6 -4
  20. package/build/types.d.ts +6 -0
  21. package/build/types.js +3 -0
  22. package/extensions/ublocklite/_locales/ar/messages.json +60 -24
  23. package/extensions/ublocklite/_locales/az/messages.json +36 -0
  24. package/extensions/ublocklite/_locales/be/messages.json +36 -0
  25. package/extensions/ublocklite/_locales/bg/messages.json +36 -0
  26. package/extensions/ublocklite/_locales/bn/messages.json +36 -0
  27. package/extensions/ublocklite/_locales/br_FR/messages.json +36 -0
  28. package/extensions/ublocklite/_locales/bs/messages.json +36 -0
  29. package/extensions/ublocklite/_locales/ca/messages.json +36 -0
  30. package/extensions/ublocklite/_locales/cs/messages.json +36 -0
  31. package/extensions/ublocklite/_locales/cv/messages.json +36 -0
  32. package/extensions/ublocklite/_locales/cy/messages.json +40 -4
  33. package/extensions/ublocklite/_locales/da/messages.json +39 -3
  34. package/extensions/ublocklite/_locales/de/messages.json +36 -0
  35. package/extensions/ublocklite/_locales/el/messages.json +36 -0
  36. package/extensions/ublocklite/_locales/en/messages.json +36 -0
  37. package/extensions/ublocklite/_locales/en_GB/messages.json +36 -0
  38. package/extensions/ublocklite/_locales/eo/messages.json +36 -0
  39. package/extensions/ublocklite/_locales/es/messages.json +36 -0
  40. package/extensions/ublocklite/_locales/et/messages.json +36 -0
  41. package/extensions/ublocklite/_locales/eu/messages.json +36 -0
  42. package/extensions/ublocklite/_locales/fa/messages.json +36 -0
  43. package/extensions/ublocklite/_locales/fi/messages.json +37 -1
  44. package/extensions/ublocklite/_locales/fil/messages.json +36 -0
  45. package/extensions/ublocklite/_locales/fr/messages.json +36 -0
  46. package/extensions/ublocklite/_locales/fy/messages.json +37 -1
  47. package/extensions/ublocklite/_locales/gl/messages.json +37 -1
  48. package/extensions/ublocklite/_locales/gu/messages.json +36 -0
  49. package/extensions/ublocklite/_locales/he/messages.json +36 -0
  50. package/extensions/ublocklite/_locales/hi/messages.json +36 -0
  51. package/extensions/ublocklite/_locales/hr/messages.json +36 -0
  52. package/extensions/ublocklite/_locales/hu/messages.json +36 -0
  53. package/extensions/ublocklite/_locales/hy/messages.json +36 -0
  54. package/extensions/ublocklite/_locales/id/messages.json +36 -0
  55. package/extensions/ublocklite/_locales/it/messages.json +36 -0
  56. package/extensions/ublocklite/_locales/ja/messages.json +36 -0
  57. package/extensions/ublocklite/_locales/ka/messages.json +36 -0
  58. package/extensions/ublocklite/_locales/kk/messages.json +36 -0
  59. package/extensions/ublocklite/_locales/kn/messages.json +36 -0
  60. package/extensions/ublocklite/_locales/ko/messages.json +36 -0
  61. package/extensions/ublocklite/_locales/lt/messages.json +36 -0
  62. package/extensions/ublocklite/_locales/lv/messages.json +36 -0
  63. package/extensions/ublocklite/_locales/mk/messages.json +36 -0
  64. package/extensions/ublocklite/_locales/ml/messages.json +36 -0
  65. package/extensions/ublocklite/_locales/mr/messages.json +36 -0
  66. package/extensions/ublocklite/_locales/ms/messages.json +36 -0
  67. package/extensions/ublocklite/_locales/nb/messages.json +53 -17
  68. package/extensions/ublocklite/_locales/nl/messages.json +36 -0
  69. package/extensions/ublocklite/_locales/oc/messages.json +36 -0
  70. package/extensions/ublocklite/_locales/pa/messages.json +36 -0
  71. package/extensions/ublocklite/_locales/pl/messages.json +36 -0
  72. package/extensions/ublocklite/_locales/pt_BR/messages.json +36 -0
  73. package/extensions/ublocklite/_locales/pt_PT/messages.json +36 -0
  74. package/extensions/ublocklite/_locales/ro/messages.json +36 -0
  75. package/extensions/ublocklite/_locales/ru/messages.json +36 -0
  76. package/extensions/ublocklite/_locales/si/messages.json +36 -0
  77. package/extensions/ublocklite/_locales/sk/messages.json +36 -0
  78. package/extensions/ublocklite/_locales/sl/messages.json +36 -0
  79. package/extensions/ublocklite/_locales/so/messages.json +36 -0
  80. package/extensions/ublocklite/_locales/sq/messages.json +36 -0
  81. package/extensions/ublocklite/_locales/sr/messages.json +36 -0
  82. package/extensions/ublocklite/_locales/sv/messages.json +36 -0
  83. package/extensions/ublocklite/_locales/sw/messages.json +36 -0
  84. package/extensions/ublocklite/_locales/ta/messages.json +36 -0
  85. package/extensions/ublocklite/_locales/te/messages.json +36 -0
  86. package/extensions/ublocklite/_locales/th/messages.json +36 -0
  87. package/extensions/ublocklite/_locales/tr/messages.json +36 -0
  88. package/extensions/ublocklite/_locales/uk/messages.json +36 -0
  89. package/extensions/ublocklite/_locales/ur/messages.json +36 -0
  90. package/extensions/ublocklite/_locales/vi/messages.json +36 -0
  91. package/extensions/ublocklite/_locales/zh_CN/messages.json +36 -0
  92. package/extensions/ublocklite/_locales/zh_TW/messages.json +36 -0
  93. package/extensions/ublocklite/css/dashboard-common.css +0 -1
  94. package/extensions/ublocklite/css/dashboard.css +8 -0
  95. package/extensions/ublocklite/css/settings.css +101 -1
  96. package/extensions/ublocklite/css/unpicker-ui.css +1 -0
  97. package/extensions/ublocklite/dashboard.html +48 -11
  98. package/extensions/ublocklite/js/background.js +49 -35
  99. package/extensions/ublocklite/js/backup-restore.js +153 -0
  100. package/extensions/ublocklite/js/config.js +2 -0
  101. package/extensions/ublocklite/js/dashboard.js +19 -0
  102. package/extensions/ublocklite/js/develop.js +2 -11
  103. package/extensions/ublocklite/js/dom.js +10 -0
  104. package/extensions/ublocklite/js/filter-lists.js +5 -5
  105. package/extensions/ublocklite/js/filter-manager-ui.js +486 -0
  106. package/extensions/ublocklite/js/filter-manager.js +85 -53
  107. package/extensions/ublocklite/js/mode-manager.js +8 -1
  108. package/extensions/ublocklite/js/picker-ui.js +2 -2
  109. package/extensions/ublocklite/js/popup.js +20 -20
  110. package/extensions/ublocklite/js/ro-dnr-editor.js +9 -5
  111. package/extensions/ublocklite/js/ruleset-manager.js +13 -8
  112. package/extensions/ublocklite/js/scripting/unpicker.js +3 -3
  113. package/extensions/ublocklite/js/settings.js +51 -0
  114. package/extensions/ublocklite/js/static-filtering-parser.js +4 -4
  115. package/extensions/ublocklite/js/unpicker-ui.js +5 -5
  116. package/extensions/ublocklite/js/utils.js +14 -0
  117. package/extensions/ublocklite/manifest.json +2 -2
  118. package/extensions/ublocklite/rulesets/generic-details.json +2 -3
  119. package/extensions/ublocklite/rulesets/main/adguard-mobile.json +3 -2
  120. package/extensions/ublocklite/rulesets/main/adguard-spyware-url.json +5 -4
  121. package/extensions/ublocklite/rulesets/main/annoyances-cookies.json +12 -4
  122. package/extensions/ublocklite/rulesets/main/annoyances-notifications.json +3 -1
  123. package/extensions/ublocklite/rulesets/main/annoyances-others.json +4 -3
  124. package/extensions/ublocklite/rulesets/main/annoyances-overlays.json +4 -3
  125. package/extensions/ublocklite/rulesets/main/annoyances-widgets.json +4 -2
  126. package/extensions/ublocklite/rulesets/main/block-lan.json +3 -1
  127. package/extensions/ublocklite/rulesets/main/chn-0.json +25 -16
  128. package/extensions/ublocklite/rulesets/main/deu-0.json +2 -9
  129. package/extensions/ublocklite/rulesets/main/easylist.json +26 -65
  130. package/extensions/ublocklite/rulesets/main/easyprivacy.json +94 -21
  131. package/extensions/ublocklite/rulesets/main/fin-0.json +2 -1
  132. package/extensions/ublocklite/rulesets/main/fra-0.json +1 -1
  133. package/extensions/ublocklite/rulesets/main/hun-0.json +3 -2
  134. package/extensions/ublocklite/rulesets/main/idn-0.json +22 -8
  135. package/extensions/ublocklite/rulesets/main/ind-0.json +62 -43
  136. package/extensions/ublocklite/rulesets/main/irn-0.json +5 -4
  137. package/extensions/ublocklite/rulesets/main/isr-0.json +2 -3
  138. package/extensions/ublocklite/rulesets/main/ita-0.json +9 -2
  139. package/extensions/ublocklite/rulesets/main/jpn-1.json +49 -31
  140. package/extensions/ublocklite/rulesets/main/kor-1.json +6 -3
  141. package/extensions/ublocklite/rulesets/main/nld-0.json +4 -1
  142. package/extensions/ublocklite/rulesets/main/pgl.json +30 -6
  143. package/extensions/ublocklite/rulesets/main/pol-0.json +1 -1
  144. package/extensions/ublocklite/rulesets/main/rou-1.json +4 -2
  145. package/extensions/ublocklite/rulesets/main/rus-0.json +18 -11
  146. package/extensions/ublocklite/rulesets/main/rus-1.json +3 -3
  147. package/extensions/ublocklite/rulesets/main/spa-1.json +6 -5
  148. package/extensions/ublocklite/rulesets/main/stevenblack-hosts.json +10500 -90447
  149. package/extensions/ublocklite/rulesets/main/swe-1.json +36 -27
  150. package/extensions/ublocklite/rulesets/main/tur-0.json +10 -7
  151. package/extensions/ublocklite/rulesets/main/ublock-badware.json +37 -13
  152. package/extensions/ublocklite/rulesets/main/ublock-filters.json +61 -34
  153. package/extensions/ublocklite/rulesets/main/ubol-tests.json +28 -0
  154. package/extensions/ublocklite/rulesets/main/ukr-0.json +1 -1
  155. package/extensions/ublocklite/rulesets/main/urlhaus-full.json +1575 -584
  156. package/extensions/ublocklite/rulesets/main/vie-1.json +40 -44
  157. package/extensions/ublocklite/rulesets/regex/chn-0.json +2 -2
  158. package/extensions/ublocklite/rulesets/regex/easylist.json +1 -1
  159. package/extensions/ublocklite/rulesets/regex/jpn-1.json +1 -2
  160. package/extensions/ublocklite/rulesets/regex/swe-1.json +0 -1
  161. package/extensions/ublocklite/rulesets/regex/ublock-badware.json +9 -3
  162. package/extensions/ublocklite/rulesets/regex/ublock-filters.json +22 -16
  163. package/extensions/ublocklite/rulesets/ruleset-details.json +206 -206
  164. package/extensions/ublocklite/rulesets/scripting/generic/annoyances-cookies.js +3 -3
  165. package/extensions/ublocklite/rulesets/scripting/generic/annoyances-notifications.js +1 -1
  166. package/extensions/ublocklite/rulesets/scripting/generic/annoyances-others.js +3 -3
  167. package/extensions/ublocklite/rulesets/scripting/generic/annoyances-social.js +3 -3
  168. package/extensions/ublocklite/rulesets/scripting/generic/chn-0.js +2 -2
  169. package/extensions/ublocklite/rulesets/scripting/generic/easylist.js +3 -3
  170. package/extensions/ublocklite/rulesets/scripting/generic/jpn-1.js +1 -1
  171. package/extensions/ublocklite/rulesets/scripting/generic/rus-1.js +2 -2
  172. package/extensions/ublocklite/rulesets/scripting/generic/swe-1.js +1 -1
  173. package/extensions/ublocklite/rulesets/scripting/generic/ublock-filters.js +3 -3
  174. package/extensions/ublocklite/rulesets/scripting/generichigh/easylist.css +2 -1
  175. package/extensions/ublocklite/rulesets/scripting/generichigh/idn-0.css +3 -0
  176. package/extensions/ublocklite/rulesets/scripting/generichigh/jpn-1.css +1 -0
  177. package/extensions/ublocklite/rulesets/scripting/generichigh/ublock-filters.css +9 -1
  178. package/extensions/ublocklite/rulesets/scripting/procedural/adguard-mobile.js +3 -3
  179. package/extensions/ublocklite/rulesets/scripting/procedural/annoyances-cookies.js +3 -3
  180. package/extensions/ublocklite/rulesets/scripting/procedural/annoyances-overlays.js +3 -3
  181. package/extensions/ublocklite/rulesets/scripting/procedural/annoyances-social.js +3 -3
  182. package/extensions/ublocklite/rulesets/scripting/procedural/chn-0.js +1 -1
  183. package/extensions/ublocklite/rulesets/scripting/procedural/deu-0.js +3 -3
  184. package/extensions/ublocklite/rulesets/scripting/procedural/easylist.js +3 -3
  185. package/extensions/ublocklite/rulesets/scripting/procedural/fin-0.js +3 -3
  186. package/extensions/ublocklite/rulesets/scripting/procedural/ind-0.js +3 -3
  187. package/extensions/ublocklite/rulesets/scripting/procedural/irn-0.js +3 -3
  188. package/extensions/ublocklite/rulesets/scripting/procedural/jpn-1.js +3 -3
  189. package/extensions/ublocklite/rulesets/scripting/procedural/kor-1.js +3 -3
  190. package/extensions/ublocklite/rulesets/scripting/procedural/ltu-0.js +1 -1
  191. package/extensions/ublocklite/rulesets/scripting/procedural/rou-1.js +3 -3
  192. package/extensions/ublocklite/rulesets/scripting/procedural/rus-0.js +3 -3
  193. package/extensions/ublocklite/rulesets/scripting/procedural/rus-1.js +1 -1
  194. package/extensions/ublocklite/rulesets/scripting/procedural/swe-1.js +3 -3
  195. package/extensions/ublocklite/rulesets/scripting/procedural/tur-0.js +3 -3
  196. package/extensions/ublocklite/rulesets/scripting/procedural/ublock-filters.js +3 -3
  197. package/extensions/ublocklite/rulesets/scripting/procedural/vie-1.js +3 -3
  198. package/extensions/ublocklite/rulesets/scripting/scriptlet/adguard-mobile.abort-current-script.js +2 -2
  199. package/extensions/ublocklite/rulesets/scripting/scriptlet/adguard-mobile.adjust-setTimeout.js +332 -0
  200. package/extensions/ublocklite/rulesets/scripting/scriptlet/adguard-mobile.json-prune-fetch-response.js +588 -0
  201. package/extensions/ublocklite/rulesets/scripting/scriptlet/adguard-mobile.json-prune-xhr-response.js +597 -0
  202. package/extensions/ublocklite/rulesets/scripting/scriptlet/adguard-mobile.remove-cookie.js +376 -0
  203. package/extensions/ublocklite/rulesets/scripting/scriptlet/adguard-mobile.set-constant.js +2 -2
  204. package/extensions/ublocklite/rulesets/scripting/scriptlet/adguard-mobile.set-cookie-reload.js +1 -1
  205. package/extensions/ublocklite/rulesets/scripting/scriptlet/adguard-mobile.xml-prune.js +443 -0
  206. package/extensions/ublocklite/rulesets/scripting/scriptlet/annoyances-cookies.prevent-requestAnimationFrame.js +1 -1
  207. package/extensions/ublocklite/rulesets/scripting/scriptlet/annoyances-cookies.set-cookie-reload.js +2 -2
  208. package/extensions/ublocklite/rulesets/scripting/scriptlet/annoyances-cookies.set-cookie.js +2 -2
  209. package/extensions/ublocklite/rulesets/scripting/scriptlet/annoyances-cookies.set-local-storage-item.js +2 -2
  210. package/extensions/ublocklite/rulesets/scripting/scriptlet/annoyances-cookies.trusted-click-element.js +88 -77
  211. package/extensions/ublocklite/rulesets/scripting/scriptlet/annoyances-cookies.trusted-set-cookie-reload.js +2 -2
  212. package/extensions/ublocklite/rulesets/scripting/scriptlet/annoyances-cookies.trusted-set-cookie.js +2 -2
  213. package/extensions/ublocklite/rulesets/scripting/scriptlet/annoyances-cookies.trusted-set-local-storage-item.js +2 -2
  214. package/extensions/ublocklite/rulesets/scripting/scriptlet/annoyances-others.set-local-storage-item.js +2 -2
  215. package/extensions/ublocklite/rulesets/scripting/scriptlet/annoyances-others.set-session-storage-item.js +2 -2
  216. package/extensions/ublocklite/rulesets/scripting/scriptlet/annoyances-overlays.abort-current-script.js +2 -2
  217. package/extensions/ublocklite/rulesets/scripting/scriptlet/annoyances-overlays.prevent-setTimeout.js +2 -2
  218. package/extensions/ublocklite/rulesets/scripting/scriptlet/annoyances-overlays.set-constant.js +1 -1
  219. package/extensions/ublocklite/rulesets/scripting/scriptlet/annoyances-overlays.trusted-click-element.js +88 -77
  220. package/extensions/ublocklite/rulesets/scripting/scriptlet/annoyances-overlays.trusted-set-local-storage-item.js +2 -2
  221. package/extensions/ublocklite/rulesets/scripting/scriptlet/chn-0.addEventListener-defuser.js +1 -1
  222. package/extensions/ublocklite/rulesets/scripting/scriptlet/easyprivacy.set-constant.js +1 -1
  223. package/extensions/ublocklite/rulesets/scripting/scriptlet/fin-0.spoof-css.js +422 -0
  224. package/extensions/ublocklite/rulesets/scripting/scriptlet/idn-0.prevent-window-open.js +2 -2
  225. package/extensions/ublocklite/rulesets/scripting/scriptlet/irn-0.href-sanitizer.js +2 -2
  226. package/extensions/ublocklite/rulesets/scripting/scriptlet/jpn-1.abort-current-script.js +1 -1
  227. package/extensions/ublocklite/rulesets/scripting/scriptlet/jpn-1.addEventListener-defuser.js +1 -1
  228. package/extensions/ublocklite/rulesets/scripting/scriptlet/jpn-1.href-sanitizer.js +2 -2
  229. package/extensions/ublocklite/rulesets/scripting/scriptlet/jpn-1.json-prune.js +2 -2
  230. package/extensions/ublocklite/rulesets/scripting/scriptlet/jpn-1.prevent-fetch.js +2 -2
  231. package/extensions/ublocklite/rulesets/scripting/scriptlet/kor-1.abort-current-script.js +2 -2
  232. package/extensions/ublocklite/rulesets/scripting/scriptlet/kor-1.json-prune-xhr-response.js +2 -2
  233. package/extensions/ublocklite/rulesets/scripting/scriptlet/kor-1.prevent-fetch.js +2 -2
  234. package/extensions/ublocklite/rulesets/scripting/scriptlet/kor-1.prevent-window-open.js +471 -0
  235. package/extensions/ublocklite/rulesets/scripting/scriptlet/kor-1.prevent-xhr.js +2 -2
  236. package/extensions/ublocklite/rulesets/scripting/scriptlet/kor-1.remove-cookie.js +376 -0
  237. package/extensions/ublocklite/rulesets/scripting/scriptlet/rus-0.abort-on-property-read.js +1 -1
  238. package/extensions/ublocklite/rulesets/scripting/scriptlet/rus-0.abort-on-property-write.js +1 -1
  239. package/extensions/ublocklite/rulesets/scripting/scriptlet/rus-0.addEventListener-defuser.js +3 -3
  240. package/extensions/ublocklite/rulesets/scripting/scriptlet/rus-0.close-window.js +3 -3
  241. package/extensions/ublocklite/rulesets/scripting/scriptlet/rus-0.href-sanitizer.js +1 -1
  242. package/extensions/ublocklite/rulesets/scripting/scriptlet/rus-0.json-prune-fetch-response.js +2 -2
  243. package/extensions/ublocklite/rulesets/scripting/scriptlet/rus-0.prevent-setTimeout.js +2 -2
  244. package/extensions/ublocklite/rulesets/scripting/scriptlet/rus-0.remove-node-text.js +1 -1
  245. package/extensions/ublocklite/rulesets/scripting/scriptlet/rus-0.set-attr.js +1 -1
  246. package/extensions/ublocklite/rulesets/scripting/scriptlet/rus-0.set-constant.js +3 -3
  247. package/extensions/ublocklite/rulesets/scripting/scriptlet/rus-1.json-prune-xhr-response.js +597 -0
  248. package/extensions/ublocklite/rulesets/scripting/scriptlet/rus-1.set-constant.js +1 -1
  249. package/extensions/ublocklite/rulesets/scripting/scriptlet/spa-1.abort-current-script.js +2 -2
  250. package/extensions/ublocklite/rulesets/scripting/scriptlet/spa-1.json-prune.js +2 -2
  251. package/extensions/ublocklite/rulesets/scripting/scriptlet/spa-1.noeval-if.js +2 -2
  252. package/extensions/ublocklite/rulesets/scripting/scriptlet/spa-1.prevent-fetch.js +2 -2
  253. package/extensions/ublocklite/rulesets/scripting/scriptlet/spa-1.prevent-window-open.js +1 -1
  254. package/extensions/ublocklite/rulesets/scripting/scriptlet/spa-1.set-constant.js +2 -2
  255. package/extensions/ublocklite/rulesets/scripting/scriptlet/swe-1.href-sanitizer.js +1 -1
  256. package/extensions/ublocklite/rulesets/scripting/scriptlet/swe-1.prevent-setTimeout.js +2 -2
  257. package/extensions/ublocklite/rulesets/scripting/scriptlet/tur-0.abort-on-property-read.js +1 -1
  258. package/extensions/ublocklite/rulesets/scripting/scriptlet/tur-0.addEventListener-defuser.js +2 -2
  259. package/extensions/ublocklite/rulesets/scripting/scriptlet/tur-0.prevent-setTimeout.js +2 -2
  260. package/extensions/ublocklite/rulesets/scripting/scriptlet/tur-0.prevent-window-open.js +1 -1
  261. package/extensions/ublocklite/rulesets/scripting/scriptlet/tur-0.remove-attr.js +2 -2
  262. package/extensions/ublocklite/rulesets/scripting/scriptlet/tur-0.set-constant.js +2 -2
  263. package/extensions/ublocklite/rulesets/scripting/scriptlet/tur-0.set-local-storage-item.js +2 -2
  264. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.abort-current-script.js +3 -3
  265. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.abort-on-property-read.js +3 -3
  266. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.abort-on-property-write.js +2 -2
  267. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.abort-on-stack-trace.js +2 -2
  268. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.addEventListener-defuser.js +2 -2
  269. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.adjust-setInterval.js +1 -1
  270. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.adjust-setTimeout.js +1 -1
  271. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.href-sanitizer.js +2 -2
  272. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.json-edit.js +2 -2
  273. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.json-prune-fetch-response.js +2 -2
  274. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.json-prune-xhr-response.js +1 -1
  275. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.json-prune.js +2 -2
  276. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.jsonl-edit-xhr-response.js +2 -2
  277. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.noeval-if.js +1 -1
  278. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.prevent-fetch.js +2 -2
  279. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.prevent-requestAnimationFrame.js +3 -3
  280. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.prevent-setInterval.js +3 -3
  281. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.prevent-setTimeout.js +3 -3
  282. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.prevent-window-open.js +2 -2
  283. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.prevent-xhr.js +3 -3
  284. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.remove-cookie.js +2 -2
  285. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.remove-node-text.js +3 -3
  286. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.set-attr.js +2 -2
  287. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.set-constant.js +3 -3
  288. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.set-local-storage-item.js +2 -2
  289. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.set-session-storage-item.js +1 -1
  290. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.spoof-css.js +2 -2
  291. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.trusted-click-element.js +86 -75
  292. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.trusted-create-html.js +2 -2
  293. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.trusted-json-edit-fetch-response.js +2 -2
  294. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.trusted-json-edit.js +851 -0
  295. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.trusted-replace-argument.js +2 -2
  296. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.trusted-replace-node-text.js +3 -3
  297. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.trusted-replace-outbound-text.js +2 -2
  298. package/extensions/ublocklite/rulesets/scripting/scriptlet/ublock-filters.trusted-suppress-native-method.js +2 -2
  299. package/extensions/ublocklite/rulesets/scripting/scriptlet/vie-1.abort-current-script.js +2 -2
  300. package/extensions/ublocklite/rulesets/scripting/scriptlet/vie-1.abort-on-property-read.js +2 -2
  301. package/extensions/ublocklite/rulesets/scripting/specific/adguard-mobile.js +3 -3
  302. package/extensions/ublocklite/rulesets/scripting/specific/annoyances-cookies.js +3 -3
  303. package/extensions/ublocklite/rulesets/scripting/specific/annoyances-notifications.js +3 -3
  304. package/extensions/ublocklite/rulesets/scripting/specific/annoyances-others.js +3 -3
  305. package/extensions/ublocklite/rulesets/scripting/specific/annoyances-overlays.js +3 -3
  306. package/extensions/ublocklite/rulesets/scripting/specific/annoyances-social.js +3 -3
  307. package/extensions/ublocklite/rulesets/scripting/specific/chn-0.js +3 -3
  308. package/extensions/ublocklite/rulesets/scripting/specific/deu-0.js +3 -3
  309. package/extensions/ublocklite/rulesets/scripting/specific/easylist.js +3 -3
  310. package/extensions/ublocklite/rulesets/scripting/specific/fin-0.js +3 -3
  311. package/extensions/ublocklite/rulesets/scripting/specific/fra-0.js +3 -3
  312. package/extensions/ublocklite/rulesets/scripting/specific/idn-0.js +3 -3
  313. package/extensions/ublocklite/rulesets/scripting/specific/ind-0.js +3 -3
  314. package/extensions/ublocklite/rulesets/scripting/specific/irn-0.js +3 -3
  315. package/extensions/ublocklite/rulesets/scripting/specific/isr-0.js +3 -3
  316. package/extensions/ublocklite/rulesets/scripting/specific/ita-0.js +3 -3
  317. package/extensions/ublocklite/rulesets/scripting/specific/jpn-1.js +3 -3
  318. package/extensions/ublocklite/rulesets/scripting/specific/kor-1.js +3 -3
  319. package/extensions/ublocklite/rulesets/scripting/specific/ltu-0.js +3 -3
  320. package/extensions/ublocklite/rulesets/scripting/specific/nld-0.js +3 -3
  321. package/extensions/ublocklite/rulesets/scripting/specific/rou-1.js +3 -3
  322. package/extensions/ublocklite/rulesets/scripting/specific/rus-0.js +3 -3
  323. package/extensions/ublocklite/rulesets/scripting/specific/rus-1.js +3 -3
  324. package/extensions/ublocklite/rulesets/scripting/specific/spa-1.js +3 -3
  325. package/extensions/ublocklite/rulesets/scripting/specific/swe-1.js +3 -3
  326. package/extensions/ublocklite/rulesets/scripting/specific/tur-0.js +3 -3
  327. package/extensions/ublocklite/rulesets/scripting/specific/ublock-badware.js +1 -1
  328. package/extensions/ublocklite/rulesets/scripting/specific/ublock-filters.js +3 -3
  329. package/extensions/ublocklite/rulesets/scripting/specific/ukr-0.js +3 -3
  330. package/extensions/ublocklite/rulesets/scripting/specific/vie-1.js +3 -3
  331. package/extensions/ublocklite/rulesets/scriptlet-details.json +227 -126
  332. package/extensions/ublocklite/rulesets/strictblock/adguard-mobile.json +1 -0
  333. package/extensions/ublocklite/rulesets/strictblock/annoyances-others.json +1 -0
  334. package/extensions/ublocklite/rulesets/strictblock/chn-0.json +222 -1
  335. package/extensions/ublocklite/rulesets/strictblock/easylist.json +1 -1
  336. package/extensions/ublocklite/rulesets/strictblock/easyprivacy.json +62 -2
  337. package/extensions/ublocklite/rulesets/strictblock/idn-0.json +2 -0
  338. package/extensions/ublocklite/rulesets/strictblock/irn-0.json +4 -1
  339. package/extensions/ublocklite/rulesets/strictblock/isr-0.json +1 -0
  340. package/extensions/ublocklite/rulesets/strictblock/ita-0.json +1 -0
  341. package/extensions/ublocklite/rulesets/strictblock/jpn-1.json +203 -186
  342. package/extensions/ublocklite/rulesets/strictblock/pgl.json +30 -6
  343. package/extensions/ublocklite/rulesets/strictblock/pol-0.json +2 -0
  344. package/extensions/ublocklite/rulesets/strictblock/rou-1.json +1 -0
  345. package/extensions/ublocklite/rulesets/strictblock/stevenblack-hosts.json +10500 -90447
  346. package/extensions/ublocklite/rulesets/strictblock/swe-1.json +0 -3
  347. package/extensions/ublocklite/rulesets/strictblock/ublock-badware.json +655 -650
  348. package/extensions/ublocklite/rulesets/strictblock/ublock-filters.json +1 -1
  349. package/extensions/ublocklite/rulesets/strictblock/ukr-0.json +1 -0
  350. package/extensions/ublocklite/rulesets/strictblock/urlhaus-full.json +1575 -584
  351. package/extensions/ublocklite/rulesets/strictblock/vie-1.json +0 -3
  352. package/extensions/ublocklite/rulesets/urlskip/ublock-filters.json +31 -1
  353. package/extensions/ublocklite/ublock.zip +0 -0
  354. package/extensions/ublocklite/web_accessible_resources/google-ima.js +14 -7
  355. package/package.json +7 -7
  356. package/src/browsers/index.ts +5 -4
  357. package/src/http.ts +3 -2
  358. package/src/routes/chrome/tests/kill-sessions.spec.ts +0 -10
  359. package/src/routes/chrome/ws/function-connect.ts +12 -0
  360. package/src/routes/chromium/ws/function-connect.ts +1 -0
  361. package/src/routes/edge/ws/function-connect.ts +12 -0
  362. package/src/sdk-utils.ts +1 -1
  363. package/src/shared/function-connect.ws.ts +38 -0
  364. package/src/shared/utils/function/handler.ts +11 -6
  365. package/src/types.ts +4 -0
  366. package/static/docs/swagger.json +104 -2
  367. package/static/docs/swagger.min.json +103 -1
  368. package/static/function/client.js +14 -20
  369. package/static/function/index.html +14 -20
@@ -0,0 +1,486 @@
1
+ /*******************************************************************************
2
+
3
+ uBlock Origin Lite - a comprehensive, MV3-compliant content blocker
4
+ Copyright (C) 2025-present Raymond Hill
5
+
6
+ This program is free software: you can redistribute it and/or modify
7
+ it under the terms of the GNU General Public License as published by
8
+ the Free Software Foundation, either version 3 of the License, or
9
+ (at your option) any later version.
10
+
11
+ This program is distributed in the hope that it will be useful,
12
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ GNU General Public License for more details.
15
+
16
+ You should have received a copy of the GNU General Public License
17
+ along with this program. If not, see {http://www.gnu.org/licenses/}.
18
+
19
+ Home: https://github.com/gorhill/uBlock
20
+ */
21
+
22
+ import { browser, sendMessage } from './ext.js';
23
+ import { dom, qs$, qsa$ } from './dom.js';
24
+ import { nodeFromTemplate } from './dashboard.js';
25
+ import punycode from './punycode.js';
26
+
27
+ /******************************************************************************/
28
+
29
+ const dataContainer = qs$('section[data-pane="filters"] .hostnames');
30
+
31
+ /******************************************************************************/
32
+
33
+ function isValidHostname(hostname) {
34
+ try {
35
+ const url = new URL(`https://${hostname}/`);
36
+ return url.hostname === hostname;
37
+ } catch {
38
+ }
39
+ return false;
40
+ }
41
+
42
+ /******************************************************************************/
43
+
44
+ function toPrettySelector(selector) {
45
+ if ( selector.startsWith('{') === false ) { return selector; }
46
+ try {
47
+ return JSON.parse(selector).raw;
48
+ } catch {
49
+ }
50
+ return selector;
51
+ }
52
+
53
+ /******************************************************************************/
54
+
55
+ function hostnameFromNode(node) {
56
+ const li = node.closest('li.hostname');
57
+ if ( li === null ) { return; }
58
+ const span = qs$(li, '.hostname[data-pretty]');
59
+ if ( span === null ) { return; }
60
+ return span.dataset.ugly || undefined;
61
+ }
62
+
63
+ function selectorFromNode(node) {
64
+ const li = node.closest('li.selector');
65
+ if ( li === null ) { return; }
66
+ const span = qs$(li, '.selector[data-pretty]');
67
+ if ( span === null ) { return; }
68
+ return span.dataset.ugly || undefined;
69
+ }
70
+
71
+ function selectorsFromNode(node, all = false) {
72
+ const li = node.closest('li.hostname');
73
+ if ( li === null ) { return []; }
74
+ const qsel = all
75
+ ? 'li.selector [contenteditable]'
76
+ : 'li.selector:not(.removed) [contenteditable]';
77
+ return Array.from(qsa$(li, qsel)).map(a => a.dataset.ugly);
78
+ }
79
+
80
+ /******************************************************************************/
81
+
82
+ async function removeSelectorsFromHostname(node) {
83
+ const hostnameNode = node.closest('li.hostname');
84
+ if ( hostnameNode === null ) { return; }
85
+ const hostname = hostnameFromNode(hostnameNode);
86
+ if ( hostname === undefined ) { return; }
87
+ const selectors = Array.from(
88
+ qsa$(hostnameNode, 'li.selector.removed [contenteditable]')
89
+ ).map(a => a.dataset.ugly);
90
+ if ( selectors.length === 0 ) { return; }
91
+ dom.cl.add(dom.body, 'busy');
92
+ updateContentEditability();
93
+ await sendMessage({ what: 'removeCustomFilters', hostname, selectors });
94
+ await debounceRenderCustomFilters();
95
+ dom.cl.remove(dom.body, 'busy');
96
+ updateContentEditability();
97
+ }
98
+
99
+ async function unremoveSelectorsFromHostname(node) {
100
+ const hostnameNode = node.closest('li.hostname');
101
+ if ( hostnameNode === null ) { return; }
102
+ const hostname = hostnameFromNode(hostnameNode);
103
+ if ( hostname === undefined ) { return; }
104
+ const selectors = Array.from(
105
+ qsa$(hostnameNode, 'li.selector:not(.removed) [contenteditable]')
106
+ ).map(a => a.dataset.ugly);
107
+ if ( selectors.length === 0 ) { return; }
108
+ dom.cl.add(dom.body, 'busy');
109
+ updateContentEditability();
110
+ await sendMessage({ what: 'addCustomFilters', hostname, selectors });
111
+ await debounceRenderCustomFilters();
112
+ dom.cl.remove(dom.body, 'busy');
113
+ updateContentEditability();
114
+ }
115
+
116
+ /******************************************************************************/
117
+
118
+ function dataFromDOM() {
119
+ const data = new Map();
120
+ for ( const hostnameNode of qsa$('li.hostname') ) {
121
+ const hostname = hostnameFromNode(hostnameNode);
122
+ const selectors = [];
123
+ for ( const selectorNode of qsa$(hostnameNode, 'li.selector') ) {
124
+ selectors.push(selectorFromNode(selectorNode));
125
+ }
126
+ data.set(hostname, selectors);
127
+ }
128
+ return data;
129
+ }
130
+
131
+ /******************************************************************************/
132
+
133
+ async function renderCustomFilters() {
134
+ const data = await sendMessage({ what: 'getAllCustomFilters' });
135
+ if ( Boolean(data) === false ) { return; }
136
+ const storedData = new Map(data);
137
+ const domData = dataFromDOM();
138
+ const hostnames = Array.from(
139
+ new Set([
140
+ ...Array.from(storedData.keys()),
141
+ ...Array.from(domData.keys()),
142
+ ])
143
+ ).sort();
144
+ const fragment = document.createDocumentFragment();
145
+ for ( const hostname of hostnames ) {
146
+ const hostnameNode = nodeFromTemplate('customFiltersHostname');
147
+ const label = qs$(hostnameNode, 'span.hostname');
148
+ label.dataset.ugly = hostname;
149
+ const pretty = punycode.toUnicode(hostname);
150
+ label.dataset.pretty = pretty;
151
+ dom.text(label, pretty);
152
+ const storedSelectors = new Set(storedData.get(hostname));
153
+ const domSelectors = new Set(domData.get(hostname));
154
+ const selectors = Array.from(
155
+ new Set([
156
+ ...Array.from(storedSelectors),
157
+ ...Array.from(domSelectors),
158
+ ])
159
+ ).sort();
160
+ const ulSelectors = qs$(hostnameNode, '.selectors');
161
+ for ( const selector of selectors ) {
162
+ const selectorNode = nodeFromTemplate('customFiltersSelector');
163
+ const label = qs$(selectorNode, 'span.selector');
164
+ label.dataset.ugly = selector;
165
+ const pretty = toPrettySelector(selector);
166
+ label.dataset.pretty = pretty;
167
+ dom.text(label, pretty);
168
+ if ( storedSelectors.has(selector) === false ) {
169
+ dom.cl.add(selectorNode, 'removed');
170
+ }
171
+ ulSelectors.append(selectorNode);
172
+ }
173
+ fragment.append(hostnameNode);
174
+ }
175
+ dom.remove('section[data-pane="filters"] .hostnames > .hostname');
176
+ dataContainer.prepend(fragment);
177
+ }
178
+
179
+ async function debounceRenderCustomFilters() {
180
+ let { debouncer } = debounceRenderCustomFilters;
181
+ if ( debouncer === undefined ) {
182
+ debouncer = debounceRenderCustomFilters.debouncer = {};
183
+ debouncer.promise = new Promise(resolve => {
184
+ debouncer.resolve = resolve;
185
+ });
186
+ }
187
+ if ( debouncer.timer !== undefined ) {
188
+ self.clearTimeout(debouncer.timer);
189
+ }
190
+ debouncer.timer = self.setTimeout(( ) => {
191
+ const { resolve } = debounceRenderCustomFilters.debouncer;
192
+ debounceRenderCustomFilters.debouncer = undefined;
193
+ renderCustomFilters().then(resolve);
194
+ }, 151);
195
+ return debouncer.promise;
196
+ }
197
+ debounceRenderCustomFilters.debouncer = undefined;
198
+
199
+ /******************************************************************************/
200
+
201
+ function updateContentEditability() {
202
+ if ( dom.cl.has(dom.body, 'busy') ) {
203
+ dom.attr('[contenteditable]', 'contenteditable', 'false');
204
+ return;
205
+ }
206
+ dom.attr('section[data-pane="filters"] li:not(.removed) [contenteditable]',
207
+ 'contenteditable',
208
+ 'plaintext-only'
209
+ );
210
+ // No point editing a removed hostname
211
+ dom.attr('section[data-pane="filters"] li.hostname:not(:has(li.selector:not(.removed))) > div [contenteditable]',
212
+ 'contenteditable',
213
+ 'false'
214
+ );
215
+ // No point editing a removed selector
216
+ dom.attr('section[data-pane="filters"] .selector.removed [contenteditable]',
217
+ 'contenteditable',
218
+ 'false'
219
+ );
220
+ }
221
+
222
+ /******************************************************************************/
223
+
224
+ async function onHostnameChanged(target, before, after) {
225
+ const uglyAfter = punycode.toASCII(after);
226
+ if ( isValidHostname(uglyAfter) === false ) {
227
+ target.textContent = before;
228
+ return;
229
+ }
230
+
231
+ dom.cl.add(dom.body, 'busy');
232
+ updateContentEditability();
233
+
234
+ // Remove old hostname from storage
235
+ await sendMessage({ what: 'removeAllCustomFilters',
236
+ hostname: target.dataset.ugly,
237
+ });
238
+
239
+ // Add selectors under new hostname to storage
240
+ target.dataset.ugly = uglyAfter;
241
+ target.dataset.pretty = after;
242
+ await sendMessage({ what: 'addCustomFilters',
243
+ hostname: hostnameFromNode(target),
244
+ selectors: selectorsFromNode(target),
245
+ });
246
+
247
+ await debounceRenderCustomFilters();
248
+ dom.cl.remove(dom.body, 'busy');
249
+ updateContentEditability();
250
+ }
251
+
252
+ async function onSelectorChanged(target, before, after) {
253
+ // Validate selector
254
+ const parserModule = await import('./static-filtering-parser.js');
255
+ const compiler = new parserModule.ExtSelectorCompiler({ nativeCssHas: true });
256
+ const result = {};
257
+ if ( compiler.compile(after, result) === false ) {
258
+ target.textContent = before;
259
+ return;
260
+ }
261
+
262
+ const hostname = hostnameFromNode(target);
263
+
264
+ dom.cl.add(dom.body, 'busy');
265
+ updateContentEditability();
266
+
267
+ // Remove old selector from storage
268
+ await sendMessage({ what: 'removeCustomFilters',
269
+ hostname,
270
+ selectors: [ target.dataset.ugly ],
271
+ });
272
+
273
+ // Add new selector to storage
274
+ target.dataset.ugly = result.compiled;
275
+ target.dataset.pretty = result.raw;
276
+ await sendMessage({ what: 'addCustomFilters',
277
+ hostname,
278
+ selectors: [ result.compiled ],
279
+ });
280
+
281
+ await debounceRenderCustomFilters();
282
+ dom.cl.remove(dom.body, 'busy');
283
+ updateContentEditability();
284
+ }
285
+
286
+ function onTextChanged(target) {
287
+ const before = target.dataset.pretty;
288
+ const after = target.textContent.trim();
289
+ if ( after !== target.textContent ) {
290
+ target.textContent = after;
291
+ }
292
+ if ( after === before ) { return; }
293
+ if ( after === '' ) {
294
+ target.textContent = before;
295
+ return;
296
+ }
297
+ if ( target.matches('.hostname') ) {
298
+ onHostnameChanged(target, before, after);
299
+ } else if ( target.matches('.selector') ) {
300
+ onSelectorChanged(target, before, after);
301
+ }
302
+ }
303
+
304
+ /******************************************************************************/
305
+
306
+ function startEdit(ev) {
307
+ focusedEditableContent = ev.target;
308
+ }
309
+
310
+ function endEdit(ev) {
311
+ const { target } = ev;
312
+ if ( target.textContent !== target.dataset.pretty ) {
313
+ onTextChanged(target);
314
+ }
315
+ focusedEditableContent = null;
316
+ }
317
+
318
+ function commitEdit(ev) {
319
+ const { target } = ev;
320
+ if ( target === focusedEditableContent ) {
321
+ if ( ev.inputType === 'insertLineBreak' ) { target.blur(); }
322
+ return;
323
+ }
324
+ onTextChanged(target);
325
+ }
326
+
327
+ let focusedEditableContent = null;
328
+
329
+ /******************************************************************************/
330
+
331
+ function onTrashClicked(ev) {
332
+ const { target } = ev;
333
+ const node = target.closest('li.selector');
334
+ if ( node ) {
335
+ dom.cl.add(node, 'removed');
336
+ } else {
337
+ dom.cl.add(qsa$(target.closest('li.hostname'), 'li.selector'), 'removed');
338
+ }
339
+ removeSelectorsFromHostname(target);
340
+ }
341
+
342
+ function onUndoClicked(ev) {
343
+ const { target } = ev;
344
+ const node = target.closest('li.selector');
345
+ if ( node ) {
346
+ dom.cl.remove(node, 'removed');
347
+ } else {
348
+ dom.cl.remove(qsa$(target.closest('li.hostname'), 'li.selector'), 'removed');
349
+ }
350
+ unremoveSelectorsFromHostname(target);
351
+ }
352
+
353
+ /******************************************************************************/
354
+
355
+ async function importFromText(text) {
356
+ const parserModule = await import('./static-filtering-parser.js');
357
+ const parser = new parserModule.AstFilterParser({ nativeCssHas: true });
358
+ const lines = text.split(/\n/);
359
+ const hostnameToSelectorsMap = new Map();
360
+
361
+ for ( const line of lines ) {
362
+ parser.parse(line);
363
+ if ( parser.hasError() ) { continue; }
364
+ if ( parser.isCosmeticFilter() === false ) { continue; }
365
+ if ( parser.hasOptions() === false ) { continue; }
366
+ const { compiled, exception } = parser.result;
367
+ if ( compiled === undefined ) { continue; }
368
+ if ( exception ) { continue; }
369
+ const hostnames = new Set();
370
+ for ( const { hn, not, bad } of parser.getExtFilterDomainIterator() ) {
371
+ if ( bad ) { continue; }
372
+ if ( hn.includes('/') ) { continue; }
373
+ if ( hn.includes('*') ) { continue; }
374
+ if ( not ) { hostnames.length = 0; break; }
375
+ hostnames.add(hn);
376
+ }
377
+ for ( const hn of hostnames ) {
378
+ const selectors = hostnameToSelectorsMap.get(hn) || new Set();
379
+ if ( selectors.size === 0 ) {
380
+ hostnameToSelectorsMap.set(hn, selectors)
381
+ }
382
+ selectors.add(compiled);
383
+ }
384
+ }
385
+
386
+ if ( hostnameToSelectorsMap.size === 0 ) { return; }
387
+
388
+ dom.cl.add(dom.body, 'busy');
389
+ updateContentEditability();
390
+
391
+ const promises = [];
392
+ for ( const [ hostname, selectors ] of hostnameToSelectorsMap ) {
393
+ promises.push(
394
+ sendMessage({ what: 'addCustomFilters',
395
+ hostname,
396
+ selectors: Array.from(selectors),
397
+ })
398
+ );
399
+ }
400
+ await Promise.all(promises);
401
+
402
+ await debounceRenderCustomFilters();
403
+ dom.cl.remove(dom.body, 'busy');
404
+ updateContentEditability();
405
+ }
406
+
407
+ /******************************************************************************/
408
+
409
+ function importFromTextarea() {
410
+ dom.prop('section[data-pane="filters"] details', 'open', false);
411
+ const textarea = qs$('section[data-pane="filters"] .importFromText textarea');
412
+ importFromText(textarea.value);
413
+ textarea.value = '';
414
+ }
415
+
416
+ /******************************************************************************/
417
+
418
+ function importFromFile() {
419
+ const input = qs$('section[data-pane="filters"] input[type="file"]');
420
+ input.onchange = ev => {
421
+ input.onchange = null;
422
+ const file = ev.target.files[0];
423
+ if ( file === undefined || file.name === '' ) { return; }
424
+ const fr = new FileReader();
425
+ fr.onload = ( ) => {
426
+ if ( typeof fr.result !== 'string' ) { return; }
427
+ importFromText(fr.result);
428
+ };
429
+ fr.readAsText(file);
430
+ };
431
+ // Reset to empty string, this will ensure a change event is properly
432
+ // triggered if the user pick a file, even if it's the same as the last
433
+ // one picked.
434
+ input.value = '';
435
+ input.click();
436
+ dom.prop('section[data-pane="filters"] details', 'open', false);
437
+ }
438
+
439
+ /******************************************************************************/
440
+
441
+ function exportToFile() {
442
+ const lines = [];
443
+ for ( const hostnameNode of qsa$('.hostnames li.hostname') ) {
444
+ const hostname = punycode.toUnicode(hostnameFromNode(hostnameNode));
445
+ const selectors = selectorsFromNode(hostnameNode);
446
+ for ( const selector of selectors ) {
447
+ lines.push(`${hostname}##${toPrettySelector(selector)}`);
448
+ }
449
+ lines.push('');
450
+ }
451
+ const text = lines.join('\n').trim();
452
+ if ( text.length === 0 ) { return; }
453
+ const a = document.createElement('a');
454
+ a.href = `data:text/plain;charset=utf-8,${encodeURIComponent(text + '\n')}`;
455
+ dom.attr(a, 'download', 'my-ubol-filters.txt');
456
+ dom.attr(a, 'type', 'text/plain');
457
+ a.click();
458
+ dom.prop('section[data-pane="filters"] details', 'open', false);
459
+ }
460
+
461
+ /******************************************************************************/
462
+
463
+ async function start() {
464
+ renderCustomFilters();
465
+
466
+ dom.on(dataContainer, 'focusin', 'section[data-pane="filters"] [contenteditable]', startEdit);
467
+ dom.on(dataContainer, 'focusout', 'section[data-pane="filters"] [contenteditable]', endEdit);
468
+ dom.on(dataContainer, 'input', 'section[data-pane="filters"] [contenteditable]', commitEdit);
469
+ dom.on(dataContainer, 'click', 'section[data-pane="filters"] .remove', onTrashClicked);
470
+ dom.on(dataContainer, 'click', 'section[data-pane="filters"] .undo', onUndoClicked);
471
+ dom.on('section[data-pane="filters"] [data-i18n="addButton"]', 'click', importFromTextarea);
472
+ dom.on('section[data-pane="filters"] [data-i18n="importAndAppendButton"]', 'click', importFromFile);
473
+ dom.on('section[data-pane="filters"] [data-i18n="exportButton"]', 'click', exportToFile);
474
+
475
+ browser.storage.local.onChanged.addListener((changes, area) => {
476
+ if ( area !== undefined && area !== 'local' ) { return; }
477
+ if ( Object.keys(changes).some(a => a.startsWith('site.')) ) {
478
+ debounceRenderCustomFilters();
479
+ }
480
+ });
481
+ }
482
+
483
+ /******************************************************************************/
484
+
485
+ // Update pane on-demand
486
+ dom.onFirstShown(start, qs$('section[data-pane="filters"]'));
@@ -38,15 +38,41 @@ import { ubolErr } from './debug.js';
38
38
 
39
39
  /******************************************************************************/
40
40
 
41
- const perSitePendingIO = new Map();
41
+ async function flushWrites() {
42
+ while ( pendingWrites.length !== 0 ) {
43
+ const promises = pendingWrites;
44
+ pendingWrites.length = 0;
45
+ await Promise.all(promises);
46
+ }
47
+ }
48
+
49
+ async function keysFromStorage() {
50
+ await flushWrites();
51
+ return localKeys();
52
+ }
53
+
54
+ async function readFromStorage(key) {
55
+ await flushWrites();
56
+ return localRead(key);
57
+ }
58
+
59
+ async function writeToStorage(key, value) {
60
+ pendingWrites.push(localWrite(key, value));
61
+ }
62
+
63
+ async function removeFromStorage(key) {
64
+ pendingWrites.push(localRemove(key));
65
+ }
66
+
67
+ const pendingWrites = [];
42
68
 
43
69
  /******************************************************************************/
44
70
 
45
- export async function selectorsFromCustomFilters(hostname) {
71
+ export async function customFiltersFromHostname(hostname) {
46
72
  const promises = [];
47
73
  let hn = hostname;
48
74
  while ( hn !== '' ) {
49
- promises.push(localRead(`site.${hn}`));
75
+ promises.push(readFromStorage(`site.${hn}`));
50
76
  const pos = hn.indexOf('.');
51
77
  if ( pos === -1 ) { break; }
52
78
  hn = hn.slice(pos + 1);
@@ -66,19 +92,31 @@ export async function selectorsFromCustomFilters(hostname) {
66
92
  /******************************************************************************/
67
93
 
68
94
  export async function hasCustomFilters(hostname) {
69
- const selectors = await selectorsFromCustomFilters(hostname);
95
+ const selectors = await customFiltersFromHostname(hostname);
70
96
  return selectors?.length ?? 0;
71
97
  }
72
98
 
73
99
  /******************************************************************************/
74
100
 
75
101
  async function getAllCustomFilterKeys() {
76
- const storageKeys = await localKeys() || [];
102
+ const storageKeys = await keysFromStorage() || [];
77
103
  return storageKeys.filter(a => a.startsWith('site.'));
78
104
  }
79
105
 
80
106
  /******************************************************************************/
81
107
 
108
+ export async function getAllCustomFilters() {
109
+ const collect = async key => {
110
+ const selectors = await readFromStorage(key);
111
+ return [ key.slice(5), selectors.map(a => a.startsWith('0') ? a.slice(1) : a) ];
112
+ };
113
+ const keys = await getAllCustomFilterKeys();
114
+ const promises = keys.map(k => collect(k));
115
+ return Promise.all(promises);
116
+ }
117
+
118
+ /******************************************************************************/
119
+
82
120
  export function startCustomFilters(tabId, frameId) {
83
121
  return browser.scripting.executeScript({
84
122
  files: [ '/js/scripting/css-user.js' ],
@@ -102,7 +140,7 @@ export function terminateCustomFilters(tabId, frameId) {
102
140
  /******************************************************************************/
103
141
 
104
142
  export async function injectCustomFilters(tabId, frameId, hostname) {
105
- const selectors = await selectorsFromCustomFilters(hostname);
143
+ const selectors = await customFiltersFromHostname(hostname);
106
144
  if ( selectors.length === 0 ) { return; }
107
145
  const promises = [];
108
146
  const plainSelectors = selectors.filter(a => a.startsWith('{') === false);
@@ -136,9 +174,6 @@ export async function injectCustomFilters(tabId, frameId, hostname) {
136
174
  /******************************************************************************/
137
175
 
138
176
  export async function registerCustomFilters(context) {
139
- if ( perSitePendingIO.size !== 0 ) {
140
- await Promise.all(Array.from(perSitePendingIO.values()));
141
- }
142
177
  const siteKeys = await getAllCustomFilterKeys();
143
178
  if ( siteKeys.length === 0 ) { return; }
144
179
 
@@ -174,37 +209,43 @@ export async function registerCustomFilters(context) {
174
209
 
175
210
  /******************************************************************************/
176
211
 
177
- export async function addCustomFilter(hostname, selector) {
178
- const pending = perSitePendingIO.get(hostname);
179
- const promise = pending
180
- ? pending.then(( ) => addCustomFilterByHostname(hostname, selector))
181
- : addCustomFilterByHostname(hostname, selector);
182
- perSitePendingIO.set(hostname, promise);
183
- promise.then(( ) => {
184
- if ( promise !== perSitePendingIO.get(hostname) ) { return; }
185
- perSitePendingIO.delete(hostname);
186
- });
187
- return promise;
188
- }
189
-
190
- async function addCustomFilterByHostname(hostname, selector) {
212
+ export async function addCustomFilters(hostname, toAdd) {
191
213
  if ( hostname === '' ) { return false; }
192
214
  const key = `site.${hostname}`;
193
- const selectors = await localRead(key) || [];
194
- if ( selectors.includes(selector) ) { return false; }
195
- selectors.push(selector);
215
+ const selectors = await readFromStorage(key) || [];
216
+ const countBefore = selectors.length;
217
+ for ( const selector of toAdd ) {
218
+ if ( selectors.includes(selector) ) { continue; }
219
+ selectors.push(selector);
220
+ }
221
+ if ( selectors.length === countBefore ) { return false; }
196
222
  selectors.sort();
197
- await localWrite(key, selectors);
223
+ writeToStorage(key, selectors);
198
224
  return true;
199
225
  }
200
226
 
201
227
  /******************************************************************************/
202
228
 
203
- export async function removeCustomFilter(hostname, selector) {
229
+ export async function removeAllCustomFilters(hostname) {
230
+ if ( hostname === '*' ) {
231
+ const keys = await getAllCustomFilterKeys();
232
+ if ( keys.length === 0 ) { return false; }
233
+ for ( const key of keys ) {
234
+ removeFromStorage(key);
235
+ }
236
+ return true;
237
+ }
238
+ const key = `site.${hostname}`;
239
+ const selectors = await readFromStorage(key) || [];
240
+ removeFromStorage(key);
241
+ return selectors.length !== 0;
242
+ }
243
+
244
+ export async function removeCustomFilters(hostname, selectors) {
204
245
  const promises = [];
205
246
  let hn = hostname;
206
247
  while ( hn !== '' ) {
207
- promises.push(removeCustomFilterByHostname(hn, selector));
248
+ promises.push(removeCustomFiltersByKey(`site.${hn}`, selectors));
208
249
  const pos = hn.indexOf('.');
209
250
  if ( pos === -1 ) { break; }
210
251
  hn = hn.slice(pos + 1);
@@ -213,33 +254,24 @@ export async function removeCustomFilter(hostname, selector) {
213
254
  return results.some(a => a);
214
255
  }
215
256
 
216
- async function removeCustomFilterByHostname(hostname, selector) {
217
- const pending = perSitePendingIO.get(hostname);
218
- const key = `site.${hostname}`;
219
- const promise = pending
220
- ? pending.then(( ) => removeCustomFilterByKey(key, selector))
221
- : removeCustomFilterByKey(key, selector);
222
- perSitePendingIO.set(hostname, promise);
223
- promise.then(( ) => {
224
- if ( promise !== perSitePendingIO.get(hostname) ) { return; }
225
- perSitePendingIO.delete(hostname);
226
- });
227
- return promise;
228
- }
229
-
230
- async function removeCustomFilterByKey(key, selector) {
231
- const selectors = await localRead(key);
257
+ async function removeCustomFiltersByKey(key, toRemove) {
258
+ const selectors = await readFromStorage(key);
232
259
  if ( selectors === undefined ) { return false; }
233
- let i = selectors.indexOf(selector);
234
- if ( i === -1 ) {
235
- i = selectors.indexOf(`0${selector}`);
236
- if ( i === -1 ) { return false; }
260
+ const beforeCount = selectors.length;
261
+ for ( const selector of toRemove ) {
262
+ let i = selectors.indexOf(selector);
263
+ if ( i === -1 ) {
264
+ i = selectors.indexOf(`0${selector}`);
265
+ if ( i === -1 ) { continue; }
266
+ }
267
+ selectors.splice(i, 1);
237
268
  }
238
- selectors.splice(i, 1);
239
- if ( selectors.length !== 0 ) {
240
- await localWrite(key, selectors);
269
+ const afterCount = selectors.length;
270
+ if ( afterCount === beforeCount ) { return false; }
271
+ if ( afterCount !== 0 ) {
272
+ writeToStorage(key, selectors);
241
273
  } else {
242
- await localRemove(key);
274
+ removeFromStorage(key);
243
275
  }
244
276
  return true;
245
277
  }