
Research
Malicious npm Packages Impersonate Flashbots SDKs, Targeting Ethereum Wallet Credentials
Four npm packages disguised as cryptographic tools steal developer credentials and send them to attacker-controlled Telegram infrastructure.
@cookiefirst/fastdetect
Advanced tools
High-performance device detection library optimized for API usage with comprehensive device, browser, and OS detection
High-performance device detection library optimized for API usage with comprehensive device, browser, and OS detection.
npm install @cookiefirst/fastdetect
yarn add @cookiefirst/fastdetect
pnpm add @cookiefirst/fastdetect
import FastDetect from '@cookiefirst/fastdetect';
const detector = new FastDetect();
const result = detector.parse('Mozilla/5.0 (iPhone; CPU iPhone OS 16_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1');
console.log(result);
// Output:
// {
// browser: { name: 'Safari', version: '16.6', major: '16', engine: 'WebKit', isMobile: true },
// os: { name: 'iOS', version: '16.6', family: 'iOS' },
// device: { type: 'smartphone', brand: 'Apple', model: 'iPhone' },
// bot: { isBot: false, name: null, category: null },
// userAgent: '...',
// timestamp: 1703932800000
// }
import { BrowserParser, DeviceParser } from '@cookiefirst/fastdetect';
const browserParser = new BrowserParser();
const deviceParser = new DeviceParser();
const browser = browserParser.parse(userAgent);
const device = deviceParser.parse(userAgent);
import express from 'express';
import FastDetect from '@cookiefirst/fastdetect';
const app = express();
const detector = new FastDetect({ cacheSize: 5000 });
app.use((req, res, next) => {
req.device = detector.parse(req.headers['user-agent'] || '');
next();
});
app.get('/api/analytics', (req, res) => {
const { device } = req;
// Log device information for analytics
console.log(`Device: ${device.device.type}, Browser: ${device.browser.name}`);
res.json({ success: true });
});
new FastDetect(options?: ParseOptions)
Options:
cacheSize?: number
- LRU cache size (default: 1000)skipCache?: boolean
- Disable caching (default: false)detailed?: boolean
- Enable detailed parsing (default: false)parse(userAgent: string, options?: ParseOptions): DetectionResult
Parse complete device information from user agent string.
const result = detector.parse('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36');
parseBrowser(userAgent: string): BrowserInfo
Parse browser information only (lightweight).
const browser = detector.parseBrowser(userAgent);
// { name: 'Chrome', version: '91.0.4472.124', major: '91', engine: 'Blink' }
parseDevice(userAgent: string): DeviceInfo
Parse device information only.
const device = detector.parseDevice(userAgent);
// { type: 'smartphone', brand: 'Apple', model: 'iPhone 14 Pro' }
parseOS(userAgent: string): OSInfo
Parse operating system information only.
const os = detector.parseOS(userAgent);
// { name: 'iOS', version: '16.6', family: 'iOS' }
parseBot(userAgent: string): BotInfo
Parse bot/crawler information only.
const bot = detector.parseBot(userAgent);
// { isBot: true, name: 'Googlebot', category: 'search-engine' }
detector.isMobile(userAgent) // boolean
detector.isTablet(userAgent) // boolean
detector.isDesktop(userAgent) // boolean
detector.isBot(userAgent) // boolean
detector.clearCache() // Clear cache
detector.getCacheStats() // Get cache statistics
FastDetect is optimized for high-throughput API usage:
Device Detection Performance Test
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Mobile Detection: 97,843 ops/sec
โ Browser Parsing: 45,672 ops/sec
โ Complete Parsing: 28,941 ops/sec
โ Cache Hit: 892,456 ops/sec
โ Memory Usage: 1.2MB (1000 entries)
const detector = new FastDetect({
cacheSize: 2000, // Increase cache for high-traffic APIs
skipCache: false // Enable caching for better performance
});
// Monitor cache performance
const stats = detector.getCacheStats();
console.log(`Cache hit rate: ${stats.hitRate}%`);
// Clear cache periodically in long-running processes
setInterval(() => {
const stats = detector.getCacheStats();
if (stats.hitRate < 50) {
detector.clearCache(); // Clear ineffective cache
}
}, 300000); // Every 5 minutes
Recommended defaults by environment:
cacheSize: 200โ1000
cacheSize: 1000โ5000
skipCache: true
on parse callsExamples
// 1) Tune via env var with safe default
const detector = new FastDetect({
cacheSize: Number(process.env.FD_CACHE_SIZE ?? 1000)
});
// 2) Disable caching for specific calls (e.g., batch jobs)
detector.parse(ua, { skipCache: true });
// 3) Monitor and adjust based on hit rate
const { hitRate, size, capacity } = detector.getCacheStats();
if (hitRate < 50) {
// Consider recreating detector with a smaller cacheSize or using skipCache
}
โ ๏ธ Important: FastDetect is optimized for server-side usage. For browser usage, consider the lightweight alternatives:
// โ
Recommended for browsers (lightweight)
import { BrowserParser } from 'fastdetect/parsers/browser';
const browserParser = new BrowserParser();
const browser = browserParser.parse(navigator.userAgent);
// Before (ua-parser-js)
import { UAParser } from 'ua-parser-js';
const parser = new UAParser();
const result = parser.setUA(userAgent).getResult();
// After (FastDetect)
import FastDetect from '@cookiefirst/fastdetect';
const detector = new FastDetect();
const result = detector.parse(userAgent);
// Mapping
result.browser.name // โ Same
result.device.type // โ Same concept
result.os.name // โ Same
// Before (mobile-detect)
import MobileDetect from 'mobile-detect';
const md = new MobileDetect(userAgent);
const isMobile = md.mobile();
// After (FastDetect)
import FastDetect from '@cookiefirst/fastdetect';
const detector = new FastDetect();
const isMobile = detector.isMobile(userAgent);
npm test # Run all tests
npm run test:coverage # Run with coverage
npm run benchmark # Performance benchmarks
AGPL-3.0 License - see LICENSE file for details.
Contributions are welcome! Please read our Contributing Guide for details.
git clone https://github.com/cookiefirst-dds/fastdetect.git
cd fastdetect
npm install
npm run build
npm test
src/parsers/
import FastDetect from '@cookiefirst/fastdetect';
import express from 'express';
const app = express();
const detector = new FastDetect({ cacheSize: 10000 });
// Analytics middleware
app.use('/api', (req, res, next) => {
const userAgent = req.headers['user-agent'];
const detection = detector.parse(userAgent || '');
// Log for analytics
console.log({
timestamp: Date.now(),
deviceType: detection.device.type,
browser: detection.browser.name,
os: detection.os.name,
isBot: detection.bot.isBot
});
// Add to request for downstream handlers
req.deviceInfo = detection;
next();
});
app.get('/api/content', (req, res) => {
const { deviceInfo } = req;
// Serve optimized content based on device
if (deviceInfo.device.type === 'smartphone') {
res.json({ content: 'mobile-optimized-content' });
} else {
res.json({ content: 'desktop-content' });
}
});
import FastDetect from '@cookiefirst/fastdetect';
const detector = new FastDetect();
function handleRequest(userAgent: string) {
const detection = detector.parse(userAgent);
if (detection.bot.isBot) {
console.log(`Bot detected: ${detection.bot.name} (${detection.bot.category})`);
// Handle different bot types
switch (detection.bot.category) {
case 'search-engine':
return { action: 'allow', priority: 'high' };
case 'ai-crawler':
return { action: 'rate-limit', priority: 'medium' };
case 'seo-tool':
return { action: 'allow', priority: 'low' };
default:
return { action: 'block', priority: 'none' };
}
}
return { action: 'allow', priority: 'high' };
}
import FastDetect from '@cookiefirst/fastdetect';
const detector = new FastDetect();
function getAvailableFeatures(userAgent: string) {
const detection = detector.parse(userAgent);
const features = [];
// Device-specific features
switch (detection.device.type) {
case 'smartphone':
features.push('touch', 'geolocation', 'camera', 'push-notifications');
break;
case 'tablet':
features.push('touch', 'large-screen', 'orientation');
break;
case 'desktop':
features.push('keyboard', 'mouse', 'large-screen', 'file-system');
break;
case 'smart-tv':
features.push('large-screen', 'remote-control');
break;
}
// Browser-specific features
if (detection.browser.name === 'Chrome' &&
parseInt(detection.browser.major || '0') >= 90) {
features.push('webrtc', 'webassembly', 'service-worker');
}
return features;
}
import FastDetect from '@cookiefirst/fastdetect';
const detector = new FastDetect({ cacheSize: 5000 });
// Process large user agent logs efficiently
function processUserAgentLogs(userAgents: string[]) {
const results = [];
const uniqueUAs = [...new Set(userAgents)]; // Deduplicate for performance
// Process unique user agents once
const detectionMap = new Map();
for (const ua of uniqueUAs) {
detectionMap.set(ua, detector.parse(ua));
}
// Map results back to original array
for (const ua of userAgents) {
results.push(detectionMap.get(ua));
}
return results;
}
import FastDetect from '@cookiefirst/fastdetect';
import { DeviceParser } from '@cookiefirst/fastdetect/parsers/device';
// Extend DeviceParser for custom patterns
class CustomDeviceParser extends DeviceParser {
parse(userAgent: string) {
const result = super.parse(userAgent);
// Add custom business logic
if (userAgent.includes('CustomDevice')) {
result.brand = 'CustomBrand';
result.model = 'Custom Model';
}
return result;
}
}
const detector = new FastDetect();
// Replace internal parser (advanced usage)
detector['deviceParser'] = new CustomDeviceParser();
import FastDetect from '@cookiefirst/fastdetect';
const detector = new FastDetect({ cacheSize: 2000 });
// Monitor performance metrics
setInterval(() => {
const stats = detector.getCacheStats();
console.log('FastDetect Performance Metrics:');
console.log(`Cache Size: ${stats.size}/${stats.capacity}`);
console.log(`Hit Rate: ${stats.hitRate}%`);
console.log(`Total Hits: ${stats.hits}`);
console.log(`Total Misses: ${stats.misses}`);
// Alert if performance degrades
if (stats.hitRate < 70) {
console.warn('Cache hit rate below 70%, consider increasing cache size');
}
}, 60000); // Every minute
// pages/api/device-info.ts
import type { NextApiRequest, NextApiResponse } from 'next';
import FastDetect from '@cookiefirst/fastdetect';
const detector = new FastDetect();
export default function handler(req: NextApiRequest, res: NextApiResponse) {
const userAgent = req.headers['user-agent'] || '';
const deviceInfo = detector.parse(userAgent);
res.status(200).json(deviceInfo);
}
// Middleware example
// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import FastDetect from '@cookiefirst/fastdetect';
const detector = new FastDetect();
export function middleware(request: NextRequest) {
const userAgent = request.headers.get('user-agent') || '';
const deviceInfo = detector.parse(userAgent);
// Add device info to headers
const response = NextResponse.next();
response.headers.set('x-device-type', deviceInfo.device.type);
response.headers.set('x-is-mobile', deviceInfo.device.type === 'smartphone' ? 'true' : 'false');
return response;
}
import fastify from 'fastify';
import FastDetect from '@cookiefirst/fastdetect';
const detector = new FastDetect();
// Create Fastify plugin
const deviceDetectionPlugin = async (fastify: any) => {
fastify.decorateRequest('device', null);
fastify.addHook('preHandler', async (request: any) => {
const userAgent = request.headers['user-agent'] || '';
request.device = detector.parse(userAgent);
});
};
const app = fastify();
app.register(deviceDetectionPlugin);
app.get('/api/info', async (request: any, reply) => {
return { deviceInfo: request.device };
});
interface DetectionResult {
browser: BrowserInfo;
os: OSInfo;
device: DeviceInfo;
bot: BotInfo;
userAgent: string;
timestamp: number;
}
interface BrowserInfo {
name: string;
version: string | null;
major: string | null;
engine?: string;
isMobile?: boolean;
isWebView?: boolean;
}
interface DeviceInfo {
type: 'smartphone' | 'tablet' | 'desktop' | 'laptop' | 'smart-tv' |
'gaming-console' | 'wearable' | 'iot-device' | 'automotive' |
'vr-headset' | 'e-reader' | 'unknown';
brand: string;
model: string | null;
marketingName?: string;
}
interface OSInfo {
name: string;
version: string | null;
family?: string;
architecture?: string;
}
interface BotInfo {
isBot: boolean;
name: string | null;
category: string | null;
company?: string;
purpose?: string;
}
Use Appropriate Cache Size
// High-traffic API (>10k requests/min)
const detector = new FastDetect({ cacheSize: 5000 });
// Low-traffic API (<1k requests/min)
const detector = new FastDetect({ cacheSize: 500 });
Deduplicate User Agents
// Efficient batch processing
const uniqueUAs = [...new Set(userAgents)];
const results = uniqueUAs.map(ua => detector.parse(ua));
Use Quick Detection Methods
// Fast path for simple checks
if (detector.isMobile(userAgent)) {
// Mobile-specific logic
} else {
// Desktop logic
}
Monitor Cache Performance
const stats = detector.getCacheStats();
if (stats.hitRate < 80) {
// Consider increasing cache size or investigating patterns
}
Q: High memory usage A: Reduce cache size or clear cache periodically
detector.clearCache(); // Clear when hit rate is low
Q: Low cache hit rate A: User agents are highly diverse; increase cache size
const detector = new FastDetect({ cacheSize: 3000 });
Q: Inaccurate detection A: Please report with user agent string for pattern updates
Q: Bundle size too large A: Use modular imports for tree-shaking
import { BrowserParser } from '@cookiefirst/fastdetect/parsers/browser';
Note: Acknowledgments reflect inspiration for patterns and API design. No code was copied from these sources.
Made with โค๏ธ for the JavaScript community
FastDetect is optimized for production API usage. Star โญ us on GitHub if this project helps you!
FAQs
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Four npm packages disguised as cryptographic tools steal developer credentials and send them to attacker-controlled Telegram infrastructure.
Security News
Ruby maintainers from Bundler and rbenv teams are building rv to bring Python uv's speed and unified tooling approach to Ruby development.
Security News
Following last weekโs supply chain attack, Nx published findings on the GitHub Actions exploit and moved npm publishing to Trusted Publishers.