@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
JavaScript
/**
* 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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