@adguard/diff-builder

中文文档
1.1.9发布于 2026/10/01MITTypeScriptCommonJS近 30 天下载 7832

A tool for generating differential updates for filter lists.

原始使用文档
文档目录11 节
  1. Contents
  2. Key Concepts
  3. Installation
  4. Quick Start
  5. Generating a patch (server / CI)
  6. Applying patches (client)
  7. CLI Reference
  8. API Reference
  9. DiffBuilder (Node.js)
  10. DiffUpdater (Node.js / Browser)
  11. Documentation

AdGuard Diff Builder

@adguard/diff-builder is an npm package for generating and applying differential updates for ad-blocking filter lists. Instead of re-downloading a full filter on every update, the server produces a compact RCS-format patch for each revision and the client fetches only the patches it has not yet applied.

Note: This package is developed in AdGuardSoftwareLimited/ext-diff-builder. The AdguardTeam/DiffBuilder repository is a public mirror.

The package ships two independent APIs and a CLI:

  • DiffBuilder — server-side (Node.js / CI): compares two filter revisions, writes a patch file, and manages the patch directory.
  • DiffUpdater — client-side (Node.js or browser): fetches pending patches from a URL and applies them to a locally stored filter.
  • diff-builder CLI — wraps DiffBuilder for use in shell scripts and CI pipelines.

Contents

Key Concepts

Filter list — a plain-text file containing ad-blocking rules. Each published revision is a snapshot of the file.

RCS patch — a compact diff in RCS format that encodes the changes between two consecutive filter revisions. Clients apply patches sequentially to advance from any past revision to the current one without downloading the full file.

Patch name — every patch file is named so its metadata can be decoded without reading the file:

<name>[-<resolution>]-<epochTimestamp>-<expirationPeriod>.patch
  • name — arbitrary identifier string (1–64 characters, no spaces).
  • resolution — optional time unit for the two numeric fields: h (hours, default), m (minutes), s (seconds).
  • epochTimestamp — time the patch was created, in the chosen resolution.
  • expirationPeriod — how long the patch is valid, in the chosen resolution.

Diff-Path tag — a metadata line written into the filter file that tells clients the URL of the patch directory:

! Diff-Path: https://example.com/filters/patches/v1.2.3-m-28334060-60.patch

DiffBuilder adds and updates this tag automatically. DiffUpdater reads it to discover where to fetch patches.

Checksum — an optional SHA-1 hash embedded in the patch's diff directive. When present, DiffUpdater validates the filter content after applying the patch and rejects it if the hash does not match.

Installation

Runtime requirements:

  • Node.js v20 or higher (for builder and CLI; the updater also runs in browsers).
  • Unix diff utility (required by the builder at runtime):
    • macOS — available by default, or via xcode-select --install.
    • Linux — available by default, or apt-get install diffutils.
    • Windows — available in WSL or Git Bash.

Add to your project:

npm install @adguard/diff-builder
# or
pnpm add @adguard/diff-builder

Quick Start

Generating a patch (server / CI)

# CLI: compare old_filter.txt → new_filter.txt, write patch to patches/
diff-builder build \
    -n my-filter \
    -t 60 \
    -r m \
    old_filter.txt \
    new_filter.txt \
    patches/

Applying patches (client)

import { DiffUpdater } from '@adguard/diff-builder/diff-updater/es';

const updatedFilter = await DiffUpdater.applyPatch({
    filterUrl: 'https://example.com/filters/filter.txt',
    filterContent: currentFilterText,
});

CLI Reference

diff-builder build [options] <old_filter> <new_filter> <path_to_patches>

Positional arguments:

ArgumentDescription
<old_filter>Path to the previous filter revision.
<new_filter>Path to the new filter revision. The file is updated in-place with the new Diff-Path tag.
<path_to_patches>Directory where patch files are stored. Created if it does not exist.

Options:

OptionRequiredDescription
-n, --name <name>YesPatch identifier: 1–64 characters, no spaces or special characters.
-t, --time <expirationPeriod>YesHow long the patch is valid, in units set by --resolution.
-r, --resolution <h|m|s>NoTime unit for --time and the embedded timestamp: h hours (default), m minutes, s seconds.
-c, --checksumNoEmbed a SHA-1 checksum of the post-patch filter content in the patch.
-d, --delete-older-than-sec <seconds>NoRemove non-empty patch files older than this many seconds. Default: 604800 (7 days).
--max-patch-size <bytes>NoMax patch size in bytes. Exceeding it skips the patch and omits Diff-Path (default 1 MB).
-v, --verboseNoPrint progress messages to stdout.

Example — 60-minute patches with checksum validation:

diff-builder build \
    -n adguard-base \
    -t 60 \
    -r m \
    -c \
    -v \
    filters/base_old.txt \
    filters/base.txt \
    filters/patches/

API Reference

DiffBuilder (Node.js)

Generates a patch file from two filter revisions and manages the patch directory. Requires Node.js and the system diff utility.

CJS

const { DiffBuilder } = require('@adguard/diff-builder');

ESM

import { DiffBuilder } from '@adguard/diff-builder/es';

DiffBuilder.buildDiff(params)

await DiffBuilder.buildDiff({
    oldFilterPath,   // string — path to the previous filter revision
    newFilterPath,   // string — path to the new filter revision (updated in-place)
    patchesPath,     // string — directory to read/write patch files
    name,            // string — patch identifier (1–64 chars, no spaces)
    time,            // number — expiration period in units of `resolution`
    resolution,      // 'h' | 'm' | 's' — time unit (default: 'h')
    checksum,        // boolean — embed SHA-1 checksum (default: false)
    deleteOlderThanSec, // number — TTL for old patches in seconds (default: 604800)
    maxPatchSize,    // number — max patch size in bytes (default: 1048576)
    verbose,         // boolean — print progress messages (default: false)
});

When called:

  1. If no meaningful changes exist between the two filters, the function exits without writing any files.
  2. Otherwise it creates a new patch file in patchesPath, updates the Diff-Path tag in newFilterPath, and removes expired patches.
  3. If the generated patch is larger than maxPatchSize, it is not written: the Diff-Path tag is not added to newFilterPath, and empty placeholder patches are removed from patchesPath.

Errors:

  • Rejects if the generated patch fails self-validation: the patch cannot be applied to the old filter, or the patched old filter differs from the new one. The underlying error is attached as cause.
  • The new filter and the patch files are not written on rejection; expired patches may already have been deleted.

DiffUpdater (Node.js / Browser)

Fetches and applies pending patches to bring a locally stored filter up to date. Compatible with both Node.js and browser environments — does not use fs, path, or child_process.

CJS

const { DiffUpdater } = require('@adguard/diff-builder/diff-updater');

ESM

import { DiffUpdater } from '@adguard/diff-builder/diff-updater/es';

DiffUpdater.applyPatch(params)

const updatedFilter = await DiffUpdater.applyPatch({
    filterUrl,      // string — URL of the filter file (used to resolve patch URLs)
    filterContent,  // string — current filter text stored by the client
    verbose,        // boolean — print progress messages (default: false)
});
// Returns the updated filter content as a string.

The function:

  1. Reads the Diff-Path tag from filterContent to locate the patch directory.
  2. Fetches the patch file at that URL. If the server returns 204 or 404, the filter is already current and the original filterContent is returned unchanged.
  3. Applies the RCS operations from the patch to filterContent.
  4. If the patch contains a checksum, validates the result and throws if it does not match.
  5. Reads the new Diff-Path tag from the updated content and repeats until no further patches are available.

Errors:

  • Throws UnacceptableResponseError if the server returns an HTTP status other than 200, 204, or 404.
  • Throws a generic Error if a patch is malformed or checksum validation fails.
import {
    DiffUpdater,
    UnacceptableResponseError,
} from '@adguard/diff-builder/diff-updater/es';

try {
    const updated = await DiffUpdater.applyPatch({ filterUrl, filterContent });
} catch (err) {
    if (err instanceof UnacceptableResponseError) {
        // Network/server error — handle or retry
    }
    throw err;
}

Documentation

版本与发布记录

@adguard/diff-builder 共发布 26 个版本,首次发布于 2023/12/19;过去 12 个月发布了 6 个版本。

版本发布日期距今
1.1.9latest2026/10/011 个月前
1.1.82026/10/011 个月前
1.1.72026/06/304 个月前
1.1.62026/06/204 个月前
1.1.52026/06/184 个月前
1.1.42026/04/017 个月前

关于 @adguard/diff-builder 的常见问题

@adguard/diff-builder 是什么?

A tool for generating differential updates for filter lists.

如何安装 @adguard/diff-builder?

在项目目录运行 npm install @adguard/diff-builder,或使用 pnpm add / yarn add / bun add。它还提供命令行工具 diff-builder,可以用 npx diff-builder 直接运行。

@adguard/diff-builder 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@adguard/diff-builder 支持 ESM 还是 CommonJS?

以 CommonJS 形式发布,可以直接 require();在 ES Module 项目中也可以用 import 引入(Node.js 会把 module.exports 作为默认导出)。

@adguard/diff-builder 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=20。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@adguard/diff-builder 可以商用吗?

@adguard/diff-builder 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@adguard/diff-builder 的下载量有多少?

根据 npm 官方下载统计,@adguard/diff-builder 在 2026/10/05 – 2026/11/03 这 30 天内被下载 7,832 次,日均约 261 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@adguard/diff-builder 还在维护吗?

最新版本 1.1.9 发布于 2026/10/01(1 个月前);至今共发布 26 个版本,其中过去 12 个月发布了 6 个;首次发布于 2023/12/19。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。