bloom-filter-driver
v1.0.2
Published
HTTP driver for BloomFilterProcess
Maintainers
Readme
Bloom Filter Driver (TypeScript / Node.js HTTP Client)
BloomFilterDriver is a lightweight client library (SDK) written in TypeScript, acting as a communication bridge between Node.js/TypeScript applications (such as BloomFilterApplication) and the Bloom Filter processing server (BloomFilterProcess) via the HTTP REST protocol.
The library is architected independently, adhering to Clean Architecture principles with clear layer separation. It provides full TypeScript type safety, robust data validation mechanisms, and request lifecycle management (Timeout & Cancellation) via AbortSignal.
Prerequisites
Since BloomFilterDriver acts as an HTTP REST client SDK, you must ensure that the BloomFilterProcess server is running and ready to accept connections before making any API calls from your application.
You can pull and run the official Docker image of the processing server from Docker Hub:
# Pull the latest image from Docker Hub
docker pull hongphucle1010/bloom-filter-process:latest
# Run the container on port 8080 (or your custom baseUrl port)
docker run -d -p 8080:8080 --name bloom-filter-process hongphucle1010/bloom-filter-process:latestInstallation
You can install the library using common package managers:
npm install bloom-filter-driver
# or
yarn add bloom-filter-driver
# or
pnpm add bloom-filter-driverNote for Local Development: If you are working directly within the driver repository, make sure to install dependencies and build the source code before using or linking it to your application:
npm install npm run build
Initialization & Configuration
To use the library, you need to instantiate a BloomFilterDriver object with a BloomDriverConfig.
import { BloomFilterDriver } from 'bloom-filter-driver';
const driver = new BloomFilterDriver({
baseUrl: 'http://localhost:8080', // Base URL of the BloomFilterProcess server
timeoutMs: 5000, // (Optional) Maximum waiting time per request (default: 5000ms)
// fetchImpl: customFetch // (Optional) Custom fetch implementation (useful for mocking/unit testing)
});Request Lifecycle Management (Timeout & Cancellation)
All API methods in the driver support an optional options?: { signal?: AbortSignal } parameter. This allows you to:
- Automatically cancel requests that exceed the configured
timeoutMs. - Manually cancel requests from the outside using an
AbortController.
const controller = new AbortController();
try {
await driver.add(
{ bfName: 'users-bf', data: '[email protected]' },
{ signal: controller.signal }
);
} catch (error) {
// Handle request cancellation or errors
}
// To manually cancel an ongoing request:
controller.abort();Architecture & Design
The driver is divided into specialized modules to ensure maintainability and scalability:
┌─────────────────────────────────────────────────────────┐
│ BloomFilterDriver │ (Main Facade Layer)
└────────────┬───────────────────────────────┬────────────┘
│ │
▼ ▼
┌─────────────────────────┐ ┌─────────────────────────┐
│ BloomApiClient │ │ RangeApiClient │ (Business Client Layer)
└────────────┬────────────┘ └────────────┬────────────┘
│ │
└───────────────┬───────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ HttpClient │ (HTTP & Timeout Handling)
└────────────────────────────┬────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ DriverValidator │ (Input Validation Layer)
└─────────────────────────────────────────────────────────┘BloomFilterDriver: The main Facade layer aggregating all methods for interacting with Bloom Filters and RangeLH.BloomApiClient: Manages endpoints related to Bloom Filter structures (/bloom/*).RangeApiClient: Manages endpoints related to RangeLH hierarchical index structures (/rangelh/*).HttpClient: Encapsulatesfetch, handles URL construction, sets HTTP headers, managesAbortController, and standardizes HTTP errors.DriverValidator: Validates input data (filter names, ranges, probabilities, configuration parameters) before sending requests to the server.
📚 API Reference
1. Bloom Filter API (BloomApiClient)
Specialized APIs for Standard Bloom Filters and Counting Bloom Filters.
createBloom(payload: BloomCreatePayload, options?: DriverRequestOptions): Promise<void>
Initializes and configures a new Bloom filter on the server before use.
await driver.createBloom({
bfName: 'users-bf', // Identifier of the bloom filter
expectedValues: 100000, // Expected number of elements to be added
bloomType: 'standard', // 'standard' | 'counting' (default: 'standard')
falsePositiveProbability: 0.01, // (Optional) Desired false positive probability (e.g., 1%)
counterBits: 4 // (Optional) Number of bits per counter (only used when bloomType is 'counting', from 1-8)
});Note: The library provides an alias function
configureBloomequivalent tocreateBloomfor backward compatibility. UsingcreateBloomis recommended for new projects.
add(payload: BloomDataPayload, options?: DriverRequestOptions): Promise<void>
Adds an element (string data) to the Bloom filter.
await driver.add({
bfName: 'users-bf',
data: '[email protected]'
});mightContain(payload: BloomDataPayload, options?: DriverRequestOptions): Promise<boolean>
Checks whether an element might exist in the Bloom filter.
const isPresent = await driver.mightContain({
bfName: 'users-bf',
data: '[email protected]'
});
if (isPresent) {
console.log('Element MIGHT exist (subject to the configured false positive probability).');
} else {
console.log('Element DEFINITELY DOES NOT exist in the filter.');
}remove(payload: BloomDataPayload, options?: DriverRequestOptions): Promise<void>
Removes an element from the Bloom filter. (Requires the filter to be initialized with bloomType: 'counting').
await driver.remove({
bfName: 'users-bf',
data: '[email protected]'
});benchLoadSequentialKeys(payload: BloomBenchSequentialPayload, options?: DriverRequestOptions): Promise<void>
API supporting high-performance bulk insertion of simulated sequential keys directly on the server (requiring only 1 HTTP call and 1 persistence operation). Typically used for benchmarking or generating sample data.
await driver.benchLoadSequentialKeys({
bfName: 'users-bf',
from: 1, // (Optional) Starting index (default: 1)
to: 100000, // Ending index
keyWidth: 10 // (Optional) Width of zero-padded numeric string (default: 10)
});
// The server will automatically load keys such as: "k-0000000001", "k-0000000002", ..., "k-0000100000"2. RangeLH API (RangeApiClient)
RangeLH (Range Linear Hashing) is an advanced key-distributed index structure supporting optimized point queries, range queries, and aggregations.
createRange(payload: RangeCreatePayload, options?: DriverRequestOptions): Promise<void>
Initializes the RangeLH index structure with advanced tuning parameters.
await driver.createRange({
bfName: 'orders-range',
config: {
masterInitNumBucket: 2, // Initial number of buckets for Master Index
masterSplitPolicy: 0.5, // Bucket split policy/ratio
expectedNItems: 1000000, // Total expected number of elements
fpProbBloomRF: 0.01, // False positive probability for child Bloom Filters
deltaBloomRF: 10, // Delta range parameter for the filter
keyLength: 20, // Fixed length of the key string (from 1-64)
maxBytesString: 8, // Maximum bytes for the string value portion (from 1-8)
floatScale: 100 // Scaling factor for floating-point data
}
});addRange(payload: RangePayload, options?: DriverRequestOptions): Promise<void>
Adds a single key/identifier pair to the RangeLH index.
await driver.addRange({
bfName: 'orders-range',
key: '2026-05-17T12:00:00Z'
});addRangeBulk(payload: RangeBulkAddPayload, options?: DriverRequestOptions): Promise<void>
Adds multiple keys simultaneously (bulk insert) to the RangeLH index, conserving bandwidth and minimizing network latency.
await driver.addRangeBulk({
bfName: 'orders-range',
keys: [
'2026-05-17T12:00:00Z',
'2026-05-17T13:00:00Z',
'2026-05-17T14:00:00Z'
]
});removeRange(payload: RangePayload, options?: DriverRequestOptions): Promise<void>
Removes a key from the RangeLH index.
await driver.removeRange({
bfName: 'orders-range',
key: '2026-05-17T12:00:00Z'
});pointQuery(payload: PointQueryPayload, options?: DriverRequestOptions): Promise<string[]>
Performs a point query to retrieve a list of exactly matching keys.
const results = await driver.pointQuery({
bfName: 'orders-range',
key: '2026-05-17T12:00:00Z'
});
// results: string[] (List of matching keys/values found)rangeQuery(payload: RangeQueryPayload, options?: DriverRequestOptions): Promise<string[]>
Performs a range query to retrieve a list of keys falling within the range from from to to.
const results = await driver.rangeQuery({
bfName: 'orders-range',
from: '2026-05-01T00:00:00Z',
to: '2026-05-31T23:59:59Z'
});
// results: string[] (List of keys within the specified query range/timeframe)aggregate(payload: RangeAggregatePayload, options?: DriverRequestOptions): Promise<number>
Performs data aggregation over a specific key range.
const totalOrders = await driver.aggregate({
bfName: 'orders-range',
from: '2026-05-01T00:00:00Z',
to: '2026-05-31T23:59:59Z',
op: 'count' // Supported operations: 'sum' | 'avg' | 'min' | 'max' | 'count'
});
console.log(`Total orders in May: ${totalOrders}`);⚠️ Error Handling
All errors originating from the driver (including input validation errors, network errors, timeouts, or server-side business errors) are thrown as BloomDriverError objects.
import { BloomFilterDriver, BloomDriverError } from 'bloom-filter-driver';
const driver = new BloomFilterDriver({ baseUrl: 'http://localhost:8080' });
async function execute() {
try {
// Attempt to send invalid data (empty string)
await driver.add({ bfName: 'users-bf', data: '' });
} catch (error) {
if (error instanceof BloomDriverError) {
console.error('[BloomDriverError] Error message:', error.message);
if (error.status) {
console.error('HTTP status code:', error.status);
}
if (error.responseBody) {
console.error('Server response body:', error.responseBody);
}
} else {
console.error('[Unknown error]:', error);
}
}
}🛠️ Build & Publish (For Developers)
Main commands for developing the bloom-filter-driver package:
Linting & Formatting:
npm run lintCompile TypeScript source code to JavaScript (
distdirectory):npm run buildPackage and publish to NPM registry:
npm publish(Note: The
prepublishOnlyscript inpackage.jsonautomatically triggers thebuildprocess before publishing to ensure the published code is always up to date).
