UNPKG

@push.rocks/smartproxy

Version:

A powerful proxy package with unified route-based configuration for high traffic management. Features include SSL/TLS support, flexible routing patterns, WebSocket handling, advanced security options, and automatic ACME certificate management.

149 lines 11.6 kB
/** * PathMatcher provides comprehensive path matching functionality * Supporting exact matches, wildcards, and parameter extraction */ export class PathMatcher { /** * Convert a path pattern to a regex and extract parameter names * Supports: * - Exact paths: /api/users * - Wildcards: /api/* * - Parameters: /api/users/:id * - Mixed: /api/users/:id/* */ static patternToRegex(pattern) { const paramNames = []; let regexPattern = pattern; // Escape special regex characters except : and * regexPattern = regexPattern.replace(/[.+?^${}()|[\]\\]/g, '\\$&'); // Handle path parameters (:param) regexPattern = regexPattern.replace(/:(\w+)/g, (match, paramName) => { paramNames.push(paramName); return '([^/]+)'; // Match any non-slash characters }); // Handle wildcards regexPattern = regexPattern.replace(/\*/g, '(.*)'); // Ensure the pattern matches from start regexPattern = `^${regexPattern}`; // If pattern doesn't end with wildcard, ensure it matches to end // But only for patterns that don't have parameters or wildcards if (!pattern.includes('*') && !pattern.includes(':') && !pattern.endsWith('/')) { regexPattern = `${regexPattern}$`; } return { regex: new RegExp(regexPattern), paramNames }; } /** * Match a path pattern against a request path * @param pattern The pattern to match * @param path The request path to test * @returns Match result with params and remainder */ static match(pattern, path) { // Handle null/undefined cases if (!pattern || !path) { return { matches: false }; } // Normalize paths (remove trailing slashes unless it's just "/") const normalizedPattern = pattern === '/' ? '/' : pattern.replace(/\/$/, ''); const normalizedPath = path === '/' ? '/' : path.replace(/\/$/, ''); // Exact match (most common case) if (normalizedPattern === normalizedPath) { return { matches: true, pathMatch: normalizedPath, pathRemainder: '', params: {} }; } // Pattern matching (wildcards and parameters) const { regex, paramNames } = this.patternToRegex(normalizedPattern); const match = normalizedPath.match(regex); if (!match) { return { matches: false }; } // Extract parameters const params = {}; paramNames.forEach((name, index) => { params[name] = match[index + 1]; }); // Calculate path match and remainder let pathMatch = match[0]; let pathRemainder = normalizedPath.substring(pathMatch.length); // Handle wildcard captures if (normalizedPattern.includes('*') && match.length > paramNames.length + 1) { const wildcardCapture = match[match.length - 1]; if (wildcardCapture) { // Ensure pathRemainder includes leading slash if it had one pathRemainder = wildcardCapture.startsWith('/') ? wildcardCapture : '/' + wildcardCapture; pathMatch = normalizedPath.substring(0, normalizedPath.length - wildcardCapture.length); } } // Clean up path match (remove trailing slash if present) if (pathMatch !== '/' && pathMatch.endsWith('/')) { pathMatch = pathMatch.slice(0, -1); } return { matches: true, pathMatch, pathRemainder, params }; } /** * Check if a pattern contains parameters or wildcards */ static isDynamicPattern(pattern) { return pattern.includes(':') || pattern.includes('*'); } /** * Calculate the specificity of a path pattern * Higher values mean more specific patterns */ static calculateSpecificity(pattern) { if (!pattern) return 0; let score = 0; // Exact paths are most specific if (!this.isDynamicPattern(pattern)) { score += 100; } // Count path segments const segments = pattern.split('/').filter(s => s.length > 0); score += segments.length * 10; // Count static segments (more static = more specific) const staticSegments = segments.filter(s => !s.startsWith(':') && s !== '*'); score += staticSegments.length * 20; // Penalize wildcards and parameters const wildcards = (pattern.match(/\*/g) || []).length; const params = (pattern.match(/:/g) || []).length; score -= wildcards * 30; // Wildcards are very generic score -= params * 10; // Parameters are somewhat generic // Bonus for longer patterns score += pattern.length; return score; } /** * Find all matching patterns from a list * Returns patterns sorted by specificity (most specific first) */ static findAllMatches(patterns, path) { const matches = patterns .map(pattern => ({ pattern, result: this.match(pattern, path) })) .filter(({ result }) => result.matches); // Sort by specificity (highest first) return matches.sort((a, b) => this.calculateSpecificity(b.pattern) - this.calculateSpecificity(a.pattern)); } /** * Instance method for interface compliance */ match(pattern, path) { return PathMatcher.match(pattern, path); } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGF0aC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3RzL2NvcmUvcm91dGluZy9tYXRjaGVycy9wYXRoLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUVBOzs7R0FHRztBQUNILE1BQU0sT0FBTyxXQUFXO0lBQ3RCOzs7Ozs7O09BT0c7SUFDSyxNQUFNLENBQUMsY0FBYyxDQUFDLE9BQWU7UUFJM0MsTUFBTSxVQUFVLEdBQWEsRUFBRSxDQUFDO1FBQ2hDLElBQUksWUFBWSxHQUFHLE9BQU8sQ0FBQztRQUUzQixpREFBaUQ7UUFDakQsWUFBWSxHQUFHLFlBQVksQ0FBQyxPQUFPLENBQUMsb0JBQW9CLEVBQUUsTUFBTSxDQUFDLENBQUM7UUFFbEUsa0NBQWtDO1FBQ2xDLFlBQVksR0FBRyxZQUFZLENBQUMsT0FBTyxDQUFDLFNBQVMsRUFBRSxDQUFDLEtBQUssRUFBRSxTQUFTLEVBQUUsRUFBRTtZQUNsRSxVQUFVLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDO1lBQzNCLE9BQU8sU0FBUyxDQUFDLENBQUMsaUNBQWlDO1FBQ3JELENBQUMsQ0FBQyxDQUFDO1FBRUgsbUJBQW1CO1FBQ25CLFlBQVksR0FBRyxZQUFZLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBRSxNQUFNLENBQUMsQ0FBQztRQUVuRCx3Q0FBd0M7UUFDeEMsWUFBWSxHQUFHLElBQUksWUFBWSxFQUFFLENBQUM7UUFFbEMsaUVBQWlFO1FBQ2pFLGdFQUFnRTtRQUNoRSxJQUFJLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDL0UsWUFBWSxHQUFHLEdBQUcsWUFBWSxHQUFHLENBQUM7UUFDcEMsQ0FBQztRQUVELE9BQU87WUFDTCxLQUFLLEVBQUUsSUFBSSxNQUFNLENBQUMs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