UNPKG

proxy-connection

Version:

Proxy client with automatic connection management, health checking, and fetch-like API

283 lines 10.5 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.SnowflakeGenerator = exports.SnowflakeConfigs = void 0; exports.generateSnowflakeId = generateSnowflakeId; exports.generateSnowflakeIds = generateSnowflakeIds; exports.createSnowflakeGenerator = createSnowflakeGenerator; exports.createCustomSnowflakeGenerator = createCustomSnowflakeGenerator; exports.parseSnowflakeId = parseSnowflakeId; exports.getAutoMachineId = getAutoMachineId; const os_1 = __importDefault(require("os")); const crypto_1 = __importDefault(require("crypto")); /** * Snowflake ID Generator * * Generates unique 64-bit IDs based on timestamp, machine ID, and sequence number * Format: [timestamp:Xbits][machineId:Ybits][sequence:Zbits] where X+Y+Z = 64 */ // Default configuration (Twitter Snowflake compatible) const DEFAULT_EPOCH = 1420070400000; // Custom epoch (January 1, 2015 UTC) const DEFAULT_MACHINE_ID_BITS = 10; const DEFAULT_SEQUENCE_BITS = 12; class SnowflakeGenerator { machineId; sequence = 0; lastTimestamp = 0; // Configuration epoch; machineIdBits; sequenceBits; timestampBits; // Calculated limits and shifts maxMachineId; maxSequence; machineIdShift; timestampShift; constructor(machineId, config = {}) { // Set configuration with defaults this.epoch = config.epoch ?? DEFAULT_EPOCH; this.machineIdBits = config.machineIdBits ?? DEFAULT_MACHINE_ID_BITS; this.sequenceBits = config.sequenceBits ?? DEFAULT_SEQUENCE_BITS; this.timestampBits = 64 - this.machineIdBits - this.sequenceBits; // Validate configuration if (this.timestampBits <= 0) { throw new Error('Invalid configuration: timestamp bits must be positive'); } if (this.machineIdBits <= 0 || this.sequenceBits <= 0) { throw new Error('Invalid configuration: machine ID and sequence bits must be positive'); } if (this.timestampBits + this.machineIdBits + this.sequenceBits !== 64) { throw new Error('Invalid configuration: total bits must equal 64'); } // Calculate limits and shifts this.maxMachineId = (1 << this.machineIdBits) - 1; this.maxSequence = (1 << this.sequenceBits) - 1; this.machineIdShift = this.sequenceBits; this.timestampShift = this.sequenceBits + this.machineIdBits; // Determine machineId automatically if not passed explicitly or passed as 'auto' let resolvedMachineId; if (machineId === undefined || machineId === 'auto') { resolvedMachineId = getAutoMachineId(this.maxMachineId); } else { resolvedMachineId = machineId; } // Validate machine ID if (resolvedMachineId < 0 || resolvedMachineId > this.maxMachineId) { throw new Error(`Machine ID must be between 0 and ${this.maxMachineId}`); } this.machineId = resolvedMachineId; } /** * Generate a new Snowflake ID * @returns {string} 64-bit ID as string */ generate() { let timestamp = Date.now(); // Handle clock moving backwards if (timestamp < this.lastTimestamp) { throw new Error('Clock moved backwards. Cannot generate ID'); } // If same millisecond, increment sequence if (timestamp === this.lastTimestamp) { this.sequence = (this.sequence + 1) & this.maxSequence; // If sequence overflows, wait for next millisecond if (this.sequence === 0) { timestamp = this.waitNextMillis(timestamp); } } else { this.sequence = 0; } this.lastTimestamp = timestamp; // Generate the ID using BigInt to avoid overflow const timestampPart = BigInt(timestamp - this.epoch) << BigInt(this.timestampShift); const machineIdPart = BigInt(this.machineId) << BigInt(this.machineIdShift); const sequencePart = BigInt(this.sequence); const id = timestampPart | machineIdPart | sequencePart; return id.toString(); } /** * Generate multiple IDs * @param count Number of IDs to generate * @returns Array of Snowflake IDs */ generateBatch(count) { const ids = []; for (let i = 0; i < count; i++) { ids.push(this.generate()); } return ids; } /** * Wait for next millisecond * @param lastTimestamp Previous timestamp * @returns New timestamp */ waitNextMillis(lastTimestamp) { let timestamp = Date.now(); while (timestamp <= lastTimestamp) { timestamp = Date.now(); } return timestamp; } /** * Parse Snowflake ID to extract components * @param id Snowflake ID string * @returns Object with timestamp, machineId, and sequence */ static parse(id, config = {}) { // Use provided config or defaults const epoch = config.epoch ?? DEFAULT_EPOCH; const machineIdBits = config.machineIdBits ?? DEFAULT_MACHINE_ID_BITS; const sequenceBits = config.sequenceBits ?? DEFAULT_SEQUENCE_BITS; // Calculate shifts and masks const maxMachineId = (1 << machineIdBits) - 1; const maxSequence = (1 << sequenceBits) - 1; const machineIdShift = sequenceBits; const timestampShift = sequenceBits + machineIdBits; const idNum = BigInt(id); const timestamp = Number((idNum >> BigInt(timestampShift)) + BigInt(epoch)); const machineId = Number((idNum >> BigInt(machineIdShift)) & BigInt(maxMachineId)); const sequence = Number(idNum & BigInt(maxSequence)); return { timestamp, machineId, sequence, date: new Date(timestamp) }; } /** * Parse Snowflake ID using this generator's configuration * @param id Snowflake ID string * @returns Object with timestamp, machineId, and sequence */ parse(id) { const idNum = BigInt(id); const timestamp = Number((idNum >> BigInt(this.timestampShift)) + BigInt(this.epoch)); const machineId = Number((idNum >> BigInt(this.machineIdShift)) & BigInt(this.maxMachineId)); const sequence = Number(idNum & BigInt(this.maxSequence)); return { timestamp, machineId, sequence, date: new Date(timestamp) }; } /** * Get generator configuration */ getConfig() { return { epoch: this.epoch, machineIdBits: this.machineIdBits, sequenceBits: this.sequenceBits, timestampBits: this.timestampBits, maxMachineId: this.maxMachineId, maxSequence: this.maxSequence }; } } exports.SnowflakeGenerator = SnowflakeGenerator; // Default instance (auto machineId) const defaultGenerator = new SnowflakeGenerator('auto'); /** * Generate a Snowflake ID using default generator * @returns Snowflake ID string */ function generateSnowflakeId() { return defaultGenerator.generate(); } /** * Generate multiple Snowflake IDs * @param count Number of IDs to generate * @returns Array of Snowflake IDs */ function generateSnowflakeIds(count) { return defaultGenerator.generateBatch(count); } /** * Create a new Snowflake generator with custom machine ID and configuration * @param machineId Machine ID (0 to maxMachineId based on config) * @param config Optional configuration for bit allocation * @returns SnowflakeGenerator instance */ function createSnowflakeGenerator(machineId, config) { return new SnowflakeGenerator(machineId, config); } function createCustomSnowflakeGenerator(config, machineId) { return new SnowflakeGenerator(machineId ?? 'auto', config); } /** * Parse Snowflake ID to extract components using default configuration * @param id Snowflake ID string * @param config Optional configuration (should match the generator's config) * @returns Object with timestamp, machineId, sequence, and date */ function parseSnowflakeId(id, config) { return SnowflakeGenerator.parse(id, config); } /** * Try to get a unique machine ID based on MAC address, hostname, or fallback to random. * @param maxMachineId Maximum allowed machineId (by bit width) */ function getAutoMachineId(maxMachineId) { // 1. MAC address (first non-loopback) const nets = os_1.default.networkInterfaces(); for (const name of Object.keys(nets)) { for (const net of nets[name] || []) { if (!net.internal && net.mac && net.mac !== '00:00:00:00:00:00') { const macHash = crypto_1.default.createHash('md5').update(net.mac).digest(); const macByte = macHash?.[0]; if (typeof macByte === 'number') { return macByte % (maxMachineId + 1); } } } } // 2. Hostname try { const hostname = os_1.default.hostname(); const hostHash = crypto_1.default.createHash('md5').update(hostname).digest(); const hostByte = hostHash?.[0]; if (typeof hostByte === 'number') { return hostByte % (maxMachineId + 1); } } catch { // ignore } // 3. Fallback: random return Math.floor(Math.random() * (maxMachineId + 1)); } // Predefined configurations for common use cases exports.SnowflakeConfigs = { /** Standard Twitter Snowflake: 42-bit timestamp, 10-bit machine, 12-bit sequence */ STANDARD: { epoch: DEFAULT_EPOCH, machineIdBits: 10, sequenceBits: 12 }, /** High frequency: 41-bit timestamp, 8-bit machine, 15-bit sequence (32K/ms per machine) */ HIGH_FREQUENCY: { epoch: DEFAULT_EPOCH, machineIdBits: 8, sequenceBits: 15 }, /** Many machines: 40-bit timestamp, 14-bit machine, 10-bit sequence (16K machines, 1K/ms each) */ MANY_MACHINES: { epoch: DEFAULT_EPOCH, machineIdBits: 14, sequenceBits: 10 }, /** Minimal machines: 44-bit timestamp, 6-bit machine, 14-bit sequence (64 machines, 16K/ms each) */ MINIMAL_MACHINES: { epoch: DEFAULT_EPOCH, machineIdBits: 6, sequenceBits: 14 } }; //# sourceMappingURL=index.js.map