npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@ductri/adblocker

v1.26.23

Published

ductridev adblocker library

Downloads

3

Readme


This is forked from AdBlocker

Getting Started

Install: npm install --save @ductri/adblocker.

Usage

There are multiple ways you can create an instance of the blocking engine to start blocking ads:

If you already have filters locally:

import { FiltersEngine } from '@ductri/adblocker';
const engine = FiltersEngine.parse(fs.readFileSync('easylist.txt', 'utf-8'));

Fetching lists from URLs:

import { FiltersEngine } from '@ductri/adblocker';
engine = await FiltersEngine.fromLists(fetch, [
 'https://easylist.to/easylist/easylist.txt'
]);

Use ready-made configs to block ads and optionally trackers:

import { FiltersEngine } from '@ductri/adblocker';
engine = await FiltersEngine.fromPrebuiltAdsOnly(fetch); // ads only
engine = await FiltersEngine.fromPrebuiltAdsAndTracking(fetch); // ads and tracking

Once you have your engine, start matching requests and block ads:

import { Request } from '@ductri/adblocker';

const { match } = engine.match(Request.fromRawDetails({
  type: 'script',
  url: 'https://domain.com/ads.js',
}));

Request Abstraction

To abstract over network requests independently from platforms (Node.js, WebExtension, etc.), the Request provides a unified APIs and helpers functions for initialization on different platforms:

import { Request } from '@ductri/adblocker';

const request = Request.fromRawDetails({
  url: 'https://sub.example.com',
  type: 'main_frame',
});

console.log(request.isMainFrame()); // true
console.log(request.url); // https://sub.example.com
console.log(request.hostname); // sub.example.com
console.log(request.domain); // example.com

Manipulating Individual Filters

Content blockers usually manipulate two kinds of filters: network and cosmetics. The former allows to specify which network requests should be blocked (or redirected), usually from the WebRequest API of extensions. The later allows to alter the DOM of pages directly, hiding elements or injecting scripts.

Network Filters

Here is how one can parse and match individual network filters using the NetworkFilter class. It offers multiple accessors and helpers to parse, match and manipulate network filters.

import { NetworkFilter } from '@ductri/adblocker';

// Parse filter from string
const filter = NetworkFilter.parse('||domain.com/ads.js$script');

// Filter attributes
console.log(filter.isHostnameAnchor()); // true
console.log(filter.getHostname()); // 'domain.com'
console.log(filter.getFilter()); // '/ads.js'

// Request options
console.log(filter.fromScript()); // true = can match 'script' requests
console.log(filter.fromImage()); // false = cannot match 'image' requests

Matching network filter against requests:

import { Request } from '@ductri/adblocker';

const request = Request.fromRawDetails({
  type: 'script',
  url: 'https://sub.domain.com/ads.js?param=42',
  sourceUrl: 'https://frame-domain.com',
});

console.log(filter.match(request)); // true

Cosmetic Filters

Similarly, one can parse cosmetic filters using the CosmeticFilter class.

const { CosmeticFilter } = require('@ductri/adblocker');

// Parsing filter from string
const filter = CosmeticFilter.parse('domain.*,domain2.com###selector');

// Properties
console.log(filter.hasHostnameConstraint()); // true
console.log(filter.getSelector()); // '#selector'
console.log(filter.isUnhide()); // false

// Matching a cosmetic filter requires both a hostname and domain
filter.match('sub.domain.com', 'domain.com'); // true

Filters Engine

Manipulating filters at a low level is useful to build tooling or debugging, but they are not appropriate for efficient blocking of requests (it would require iterating on all the filters to know if a request needs to be blocked). Instead, we can make use of the FiltersEngine class which can be seen as a "container" for both network and cosmetic filters. The filters are organized in a very compact way which also enables fast matching.

import { FiltersEngine, NetworkFilter, CosmeticFilter, Request } from '@ductri/adblocker';

// Parse multiple filters at once
let engine = FiltersEngine.parse(`
! This is a custom list
||domain.com/ads.js$script

###selector
domain.com,entity.*##+js(script,args1)
`);

Updating an existing engine with new filters:

// Update with individual filters
engine.update({
  newNetworkFilters: [NetworkFilter.parse('/ads.js')]
  newCosmeticFilters: [CosmeticFilter.parse('###selector')],
});

Serializing an engine to Uint8Array and reloading it to its original form:

// Serialize the full engine to a Uint8Array for caching
const serialized = engine.serialize();
engine = FiltersEngine.deserialize(serialized);

Matching requests:

// Matching network filters
const {
  match, // `true` if there is a match
  redirect, // data url to redirect to if any
  exception, // instance of NetworkFilter exception if any
  filter, // instance of NetworkFilter which matched
} = engine.match(Request.fromRawDetails({
  type: 'script',
  url: 'https://sub.domain.com/ads.js',
}));

Checking for CSP injection rules for a given frame:

// Matching CSP (content security policy) filters.
const directives = engine.getCSPDirectives(Request.fromRawDetails({
  type: 'main_frame',
  url: 'https://sub.domain.com/',
}));

Checking for cosmetics injection:

// Matching cosmetic filters
const {
  styles, // stylesheet to inject in the page
  scripts, // Array of scriptlets to inject in the page
} = engine.getCosmeticsFilters({
  url: 'https://sub.domain.com/path',
  hostname: 'sub.domain.com',
  domain: 'domain.com',
});