npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@angular-helpers/security

v21.4.3

Published

Angular security helpers for preventing ReDoS and other security vulnerabilities

Downloads

523

Readme

Leer en Español

🌐 Documentation & Demo: https://gaspar1992.github.io/angular-helpers/

Angular Security Helpers

Security package for Angular applications that prevents common attacks like ReDoS (Regular Expression Denial of Service) using Web Workers for safe execution.

🛡️ Features

ReDoS Prevention

  • Web Worker Execution: Regular expressions are executed in a separate thread.
  • Configurable Timeout: Prevents infinite executions.
  • Complexity Analysis: Detects dangerous patterns before execution.
  • Safe Mode: Only allows patterns verified as safe.

Web Crypto API

  • Encryption/Decryption: AES-GCM support for secure data handling
  • Hashing: SHA-256 and other algorithms
  • HMAC Signing: HMAC-SHA-256/384/512 for message authentication
  • Key Management: Generate, import, and export cryptographic keys
  • Secure Random: Cryptographically secure random values
  • UUID Generation: RFC4122 v4 UUIDs

Secure Storage

  • Transparent Encryption: AES-GCM encrypted localStorage/sessionStorage
  • Ephemeral Mode: In-memory keys for single-session security
  • Passphrase Mode: PBKDF2-derived keys for cross-session persistence
  • Namespace Isolation: Organize stored data with prefixes

Input Sanitization

  • XSS Prevention: Strip dangerous tags and attributes from HTML
  • URL Validation: Allow only http/https schemes
  • HTML Escaping: Safe interpolation of user content
  • JSON Safety: Safe parsing without eval

Password Strength

  • Entropy-Based Scoring: 0-4 score with labeled strength levels
  • Pattern Detection: Detects sequences, repetitions, keyboard walks
  • Common Password Check: Blocks frequently used passwords
  • Feedback Messages: Actionable improvement suggestions

Forms Validators (sub-entries)

  • @angular-helpers/security/forms: Reactive Forms bridge — SecurityValidators.strongPassword, safeHtml, safeUrl, noScriptInjection, noSqlInjectionHints.
  • @angular-helpers/security/signal-forms: Angular v21 Signal Forms bridge — strongPassword, safeHtml, safeUrl, noScriptInjection, noSqlInjectionHints, and async hibpPassword.
  • Shared core: both paradigms delegate to the same pure helpers for guaranteed behavioural parity.

JWT Inspection

  • Client-side decode: decode, claim, isExpired, expiresIn.
  • Explicit non-verifying: signature validation must happen server-side.

CSRF Protection

  • CsrfService: double-submit token helper backed by WebCryptoService.generateRandomBytes.
  • withCsrfHeader(): functional HTTP interceptor that injects the token on POST/PUT/PATCH/DELETE.

Rate Limiter

  • Token-bucket and sliding-window policies.
  • Signal-based state: canExecute(key), remaining(key) return Signal<T>.

HIBP Leaked-Password Check

  • k-anonymity: only the first 5 hex chars of SHA-1 leave the browser.
  • Fail-open: network errors never block form submissions.

Sensitive Clipboard

  • Verified auto-clear: reads back the clipboard before clearing to avoid clobbering unrelated content.
  • Password-manager semantics: default 15-second clear, configurable.

Session Inactivity Monitor

  • NgZone-optimized: DOM events tracked outside Angular change detection.
  • Security interop: Can automatically clear SecureStorage and SensitiveClipboard upon timeout.
  • Warning states: Configurable thresholds to warn users before expiration.

Secure Cross-Window Messaging

  • HMAC-SHA-256 signatures: Every message is signed; tampered payloads are discarded.
  • Origin whitelist: Messages from non-allowed origins are rejected before any crypto work.
  • Anti-replay protection: Envelope includes timestamp + nonce; messages older than 30s are discarded.
  • SSR-safe: No-op on the server — no window access.

Builder Pattern

  • Fluent API: Intuitively build regular expressions.
  • Method Chaining: .pattern().group().quantifier()
  • Real-time Validation: Security analysis during construction.

📦 Installation

pnpm add @angular-helpers/security

🚀 Basic Usage

Configuration

import { provideSecurity } from '@angular-helpers/security';

bootstrapApplication(AppComponent, {
  providers: [
    provideSecurity({
      // Core services (enabled by default)
      enableRegexSecurity: true,
      enableWebCrypto: true,

      // New services (opt-in, disabled by default)
      enableSecureStorage: true,
      enableInputSanitizer: true,
      enablePasswordStrength: true,

      // Global settings
      defaultTimeout: 5000,
      safeMode: false,
    }),
  ],
});

Individual Providers

import {
  provideRegexSecurity,
  provideWebCrypto,
  provideSecureStorage,
  provideInputSanitizer,
  providePasswordStrength,
} from '@angular-helpers/security';

// Use only the services you need
bootstrapApplication(AppComponent, {
  providers: [
    provideSecureStorage({ storage: 'session', pbkdf2Iterations: 600_000 }),
    provideInputSanitizer({ allowedTags: ['b', 'i', 'em', 'strong'] }),
    providePasswordStrength(),
  ],
});

Service Injection

import { RegexSecurityService, inject } from '@angular-helpers/security';

@Component({...})
export class MyComponent {
  private regexSecurity = inject(RegexSecurityService);
}

📖 Usage Examples

1. Basic Regular Expression Test

async testEmail(email: string): Promise<boolean> {
  const result = await this.regexSecurity.testRegex(
    '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$',
    email,
    { timeout: 3000 }
  );

  return result.match;
}

2. Builder Pattern

import { RegexSecurityService } from '@angular-helpers/security';

// Fluent regular expression construction
const { pattern, security } = RegexSecurityService.builder()
  .startOfLine()
  .characterSet('a-zA-Z0-9._%+-')
  .quantifier('+')
  .append('@')
  .characterSet('a-zA-Z0-9.-')
  .quantifier('+')
  .append('\\.')
  .characterSet('a-zA-Z')
  .quantifier('{2,}')
  .endOfLine()
  .timeout(5000)
  .safeMode()
  .build();

// Direct execution
const result = await RegexSecurityService.builder()
  .pattern('^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$')
  .timeout(3000)
  .execute(email, this.regexSecurity);

3. Security Analysis

async analyzePattern(pattern: string): Promise<void> {
  const analysis = await this.regexSecurity.analyzePatternSecurity(pattern);

  if (!analysis.safe) {
    console.warn('⚠️ Pattern not safe:', analysis.warnings);
    console.info('💡 Recommendations:', analysis.recommendations);

    if (analysis.risk === 'critical') {
      throw new Error('Pattern rejected due to critical security risk');
    }
  }

  console.log(`✅ Pattern complexity: ${analysis.complexity}`);
  console.log(`🎯 Risk level: ${analysis.risk}`);
}

4. Form Validation

@Component({...})
export class FormValidationComponent {
  constructor(private regexSecurity: RegexSecurityService) {}

  async validateUsername(username: string): Promise<boolean> {
    const result = await this.regexSecurity.testRegex(
      '^[a-zA-Z0-9_]{3,20}$',
      username,
      { timeout: 1000, safeMode: true }
    );

    if (result.timeout) {
      throw new Error('Username validation timeout - possible ReDoS attack');
    }

    if (result.error) {
      console.error('Validation error:', result.error);
      return false;
    }

    return result.match;
  }

  async validateComplexInput(input: string): Promise<boolean> {
    // Builder pattern for complex validation
    const result = await RegexSecurityService
      .builder()
      .startOfLine()
      .nonCapturingGroup('[a-zA-Z]') // First letter
      .characterSet('a-zA-Z0-9_') // Allowed characters
      .quantifier('{2,19}') // Between 3 and 20 characters total
      .endOfLine()
      .timeout(2000)
      .execute(input, this.regexSecurity);

    return result.match;
  }
}

WebCryptoService

import { WebCryptoService } from '@angular-helpers/security';

export class SecureStorageComponent {
  private cryptoService = inject(WebCryptoService);

  async hashPassword(password: string): Promise<string> {
    return await this.cryptoService.hash(password, 'SHA-256');
  }

  async encryptData(
    data: string,
  ): Promise<{ ciphertext: ArrayBuffer; iv: Uint8Array; key: CryptoKey }> {
    const key = await this.cryptoService.generateAesKey(256);
    const { ciphertext, iv } = await this.cryptoService.encryptAes(key, data);
    return { ciphertext, iv, key };
  }

  async decryptData(ciphertext: ArrayBuffer, iv: Uint8Array, key: CryptoKey): Promise<string> {
    return await this.cryptoService.decryptAes(key, ciphertext, iv);
  }

  async exportKeyForStorage(key: CryptoKey): Promise<JsonWebKey> {
    return await this.cryptoService.exportKey(key);
  }

  async importKeyFromStorage(jwk: JsonWebKey): Promise<CryptoKey> {
    return await this.cryptoService.importAesKey(jwk);
  }

  generateSecureToken(length: number = 32): string {
    const bytes = this.cryptoService.generateRandomBytes(length);
    return Array.from(bytes)
      .map((b) => b.toString(16).padStart(2, '0'))
      .join('');
  }

  generateUUID(): string {
    return this.cryptoService.randomUUID();
  }

  async signAndVerify(data: string): Promise<boolean> {
    // Generate HMAC key for SHA-256
    const key = await this.cryptoService.generateHmacKey('HMAC-SHA-256');

    // Sign the data
    const signature = await this.cryptoService.sign(key, data);

    // Verify the signature
    return await this.cryptoService.verify(key, data, signature);
  }
}

SecureStorageService

import { SecureStorageService } from '@angular-helpers/security';

export class UserSettingsComponent {
  private storage = inject(SecureStorageService);

  async saveUserToken(token: string): Promise<void> {
    // Ephemeral mode (default): data survives only this session
    await this.storage.set('authToken', { token, createdAt: Date.now() });
  }

  async getUserToken(): Promise<{ token: string; createdAt: number } | null> {
    return await this.storage.get<{ token: string; createdAt: number }>('authToken');
  }

  async initWithPassphrase(passphrase: string): Promise<void> {
    // Passphrase mode: data survives page reloads
    await this.storage.initWithPassphrase(passphrase);
  }

  async saveWithNamespace(userId: string, data: unknown): Promise<void> {
    // Namespace isolation
    await this.storage.set('profile', data, `user:${userId}`);
  }

  clearUserData(userId: string): void {
    // Clear only this user's data
    this.storage.clear(`user:${userId}`);
  }
}

InputSanitizerService

import { InputSanitizerService } from '@angular-helpers/security';

export class CommentComponent {
  private sanitizer = inject(InputSanitizerService);

  sanitizeUserComment(html: string): string {
    // Strip dangerous tags, keep safe ones (b, i, em, a, etc.)
    return this.sanitizer.sanitizeHtml(html);
    // Example: '<b>Hello</b><script>alert(1)</script>' → '<b>Hello</b>'
  }

  validateUserLink(url: string): string | null {
    // Only allow http/https URLs
    return this.sanitizer.sanitizeUrl(url);
    // Example: 'javascript:alert(1)' → null
    // Example: 'https://example.com' → 'https://example.com/'
  }

  escapeForDisplay(text: string): string {
    // Safe for HTML text nodes
    return this.sanitizer.escapeHtml(text);
    // Example: '<b>hello</b>' → '&lt;b&gt;hello&lt;/b&gt;'
  }

  parseUserJson(json: string): unknown | null {
    // Safe JSON parsing without eval
    return this.sanitizer.sanitizeJson(json);
  }
}

PasswordStrengthService

import { PasswordStrengthService } from '@angular-helpers/security';

export class RegistrationComponent {
  private passwordStrength = inject(PasswordStrengthService);

  checkPasswordStrength(password: string): void {
    const result = this.passwordStrength.assess(password);

    console.log(`Score: ${result.score}/4`); // 0-4
    console.log(`Label: ${result.label}`); // 'very-weak' to 'very-strong'
    console.log(`Entropy: ${result.entropy} bits`); // calculated entropy
    console.log('Feedback:', result.feedback); // improvement suggestions

    // Example results:
    // 'password' → score: 0, label: 'very-weak', feedback: ['This is a commonly used password']
    // 'P@ssw0rd!' → score: 2, label: 'fair', feedback: ['Avoid keyboard patterns']
    // 'xK#9mZ$vLq2@rBnT7' → score: 4, label: 'very-strong', feedback: []
  }
}

SecurityValidators (Reactive Forms)

import { FormControl, FormGroup, Validators } from '@angular/forms';
import { SecurityValidators } from '@angular-helpers/security/forms';

export class SignupFormComponent {
  form = new FormGroup({
    password: new FormControl('', [
      Validators.required,
      SecurityValidators.strongPassword({ minScore: 3 }),
    ]),
    bio: new FormControl('', [SecurityValidators.safeHtml()]),
    homepage: new FormControl('', [SecurityValidators.safeUrl({ schemes: ['https:'] })]),
    query: new FormControl('', [
      SecurityValidators.noScriptInjection(),
      SecurityValidators.noSqlInjectionHints(),
    ]),
  });
}

The validators are static factory functions — no provider registration required. They delegate to shared pure helpers, so the Signal Forms variant below produces equivalent results for the same input.

Signal Forms validators

import { signal } from '@angular/core';
import { form, required } from '@angular/forms/signals';
import {
  strongPassword,
  hibpPassword,
  safeHtml,
  safeUrl,
} from '@angular-helpers/security/signal-forms';

export class SignupSignalFormsComponent {
  model = signal({ email: '', password: '', bio: '', homepage: '' });

  f = form(this.model, (p) => {
    required(p.email);
    required(p.password);
    strongPassword(p.password, { minScore: 3 });
    hibpPassword(p.password); // async — calls HIBP via validateAsync
    safeHtml(p.bio);
    safeUrl(p.homepage, { schemes: ['https:'] });
  });
}

Sub-entry requirement: ensure @angular/forms is installed. The main entry has zero runtime dependency on @angular/forms; only the sub-entries need it.

Async HIBP rule: hibpPassword requires provideHibp() in the injector hierarchy. The rule fails open — network errors never block form submission.

JwtService

import { JwtService } from '@angular-helpers/security';

export class SessionGuard {
  private jwt = inject(JwtService);

  isAuthenticated(): boolean {
    const token = localStorage.getItem('access_token');
    if (!token) return false;
    return !this.jwt.isExpired(token, /* leewaySeconds */ 30);
  }

  currentUserId(): string | null {
    const token = localStorage.getItem('access_token');
    return token ? this.jwt.claim<string>(token, 'sub') : null;
  }
}

Security note: JwtService decodes payloads for client-side inspection only. Never trust the decoded contents for authorization decisions — signature verification must happen server-side.

CsrfService + withCsrfHeader()

import { bootstrapApplication } from '@angular/platform-browser';
import { provideHttpClient, withInterceptors } from '@angular/common/http';
import { provideSecurity, CsrfService, withCsrfHeader } from '@angular-helpers/security';

bootstrapApplication(App, {
  providers: [
    provideSecurity({ enableCsrf: true }),
    provideHttpClient(withInterceptors([withCsrfHeader()])),
  ],
});

// After login:
const csrf = inject(CsrfService);
csrf.storeToken(response.csrfToken);
// Subsequent POST/PUT/PATCH/DELETE requests automatically carry X-CSRF-Token.

RateLimiterService

import { RateLimiterService, RateLimitExceededError } from '@angular-helpers/security';

export class SearchComponent {
  private rateLimiter = inject(RateLimiterService);

  constructor() {
    this.rateLimiter.configure('search', {
      type: 'token-bucket',
      capacity: 5,
      refillPerSecond: 1,
    });
  }

  canSearch = this.rateLimiter.canExecute('search'); // Signal<boolean>
  remaining = this.rateLimiter.remaining('search'); // Signal<number>

  async search(query: string) {
    try {
      await this.rateLimiter.consume('search');
      return this.api.search(query);
    } catch (err) {
      if (err instanceof RateLimitExceededError) {
        // Show countdown using err.retryAfterMs
      }
    }
  }
}

HibpService

import { HibpService } from '@angular-helpers/security';

export class RegistrationComponent {
  private hibp = inject(HibpService);

  async checkPassword(password: string) {
    const { leaked, count, error } = await this.hibp.isPasswordLeaked(password);
    if (error) return; // fail-open on network failures
    if (leaked) alert(`This password has appeared in ${count} data breaches.`);
  }
}

SensitiveClipboardService

import { SensitiveClipboardService } from '@angular-helpers/security';

export class ApiKeyPanel {
  private sensitiveClipboard = inject(SensitiveClipboardService);

  async copy(value: string) {
    await this.sensitiveClipboard.copy(value, { clearAfterMs: 15_000 });
  }
}

The service reads the clipboard before clearing and skips the clear if the content no longer matches what was copied — so third-party copies by the user are never overwritten.

SessionIdleService

import { SessionIdleService } from '@angular-helpers/security';

export class AppComponent {
  private sessionIdle = inject(SessionIdleService);

  ngOnInit() {
    this.sessionIdle.start({
      timeoutMs: 15 * 60 * 1000, // 15 minutes
      warningThresholdMs: 60 * 1000, // 1 minute warning
      autoClearStorage: true,
      autoClearClipboard: true,
    });

    // React to states
    effect(() => {
      if (this.sessionIdle.isWarning()) {
        console.warn(`Session will expire in ${this.sessionIdle.timeRemaining()}ms`);
      }
    });

    // React to timeout
    this.sessionIdle.onTimeout.subscribe(() => {
      this.authService.logout();
    });
  }
}

The service tracks DOM events (mousemove, keydown, etc.) outside the Angular Zone to prevent change detection spam. It can automatically clear SecureStorageService and SensitiveClipboardService when the session times out.

SecureMessageService

import { SecureMessageService, provideSecureMessage } from '@angular-helpers/security';

// app.config.ts
bootstrapApplication(AppComponent, {
  providers: [provideSecureMessage()],
});

// parent-app.component.ts
export class ParentComponent {
  private channel = inject(SecureMessageService);

  async ngOnInit() {
    // 1. Generate a shared key (transport it to the iframe via a secure channel)
    const key = await this.channel.generateChannelKey();

    // 2. Configure: only accept messages from the iframe origin
    this.channel.configure({
      allowedOrigins: ['https://child-app.example.com'],
      signingKey: key,
    });

    // 3. React to incoming messages
    this.channel.messages$<{ type: string; payload: unknown }>().subscribe(({ data, origin }) => {
      console.log('Verified message from', origin, data);
    });

    // 4. Or use the Signal for reactive UI
    effect(() => {
      const msg = this.channel.lastMessage()();
      if (msg) console.log('Last message:', msg.data);
    });
  }

  async sendToChild(iframe: HTMLIFrameElement) {
    await this.channel.send(
      iframe.contentWindow!,
      { type: 'INIT', payload: { userId: 42 } },
      'https://child-app.example.com', // targetOrigin — never '*'
    );
  }
}

Key exchange: SecureMessageService does not perform automatic key negotiation — transport the CryptoKey to the other context via a secure out-of-band channel (e.g., derive it from a shared secret using WebCryptoService.generateHmacKey() seeded by a passphrase). Once both sides share the key, all message integrity is handled automatically.

🔧 Advanced Configuration

Security Options

interface RegexSecurityConfig {
  timeout?: number; // Timeout in ms (default: 5000)
  maxComplexity?: number; // Max complexity (default: 10)
  allowBacktracking?: boolean; // Allow backtracking (default: false)
  safeMode?: boolean; // Safe mode (default: false)
}

Builder Options

interface RegexBuilderOptions {
  global?: boolean; // 'g' flag
  ignoreCase?: boolean; // 'i' flag
  multiline?: boolean; // 'm' flag
  dotAll?: boolean; // 's' flag
  unicode?: boolean; // 'u' flag
  sticky?: boolean; // 'y' flag
}

🛡️ Security Features

Dangerous Pattern Detection

The service automatically detects:

  • Nested quantifiers: **, ++ (catastrophic backtracking)
  • Lookaheads/lookbehinds: (?=), (?!), (?<=), (?<!)
  • Atomic groups: (?>)
  • Recursive patterns: Deeply nested groups
  • Complex quantifiers: {n,m} with high values
  • Greedy wildcards: .*, .+ with variable characters

Risk Levels

  • 🟢 Low: Simple and safe patterns
  • 🟡 Medium: Patterns with lookahead/lookbehind
  • 🟠 High: Patterns with complex quantifiers
  • 🔴 Critical: Patterns with catastrophic backtracking

Attack Prevention

  • Timeout: Stops execution after the time limit
  • Web Worker: Isolates execution from the main thread
  • Pre-analysis: Rejects dangerous patterns before execution
  • Match limit: Prevents infinite loops

📊 Metrics and Monitoring

Execution Results

interface RegexTestResult {
  match: boolean; // If there was a match
  matches?: RegExpMatchArray[]; // All matches found
  groups?: { [key: string]: string }; // Captured groups
  executionTime: number; // Execution time in ms
  timeout: boolean; // If there was a timeout
  error?: string; // Error if one occurred
}

Security Analysis

interface RegexSecurityResult {
  safe: boolean; // If the pattern is safe
  complexity: number; // Complexity level (0-∞)
  risk: 'low' | 'medium' | 'high' | 'critical';
  warnings: string[]; // Security warnings
  recommendations: string[]; // Improvement recommendations
}

🔄 Form Integration

Angular Validators

import { AbstractControl, ValidationErrors } from '@angular/forms';

export class SecurityValidators {
  constructor(private regexSecurity: RegexSecurityService) {}

  async securePattern(pattern: string, config?: RegexSecurityConfig) {
    return async (control: AbstractControl): Promise<ValidationErrors | null> => {
      const value = control.value;

      if (!value) return null;

      try {
        const result = await this.regexSecurity.testRegex(pattern, value, config);

        if (!result.match) {
          return { securePattern: { value, reason: 'Pattern does not match' } };
        }

        if (result.timeout) {
          return { securePattern: { value, reason: 'Pattern execution timeout' } };
        }

        return null;
      } catch (error) {
        return { securePattern: { value, reason: (error as Error).message } };
      }
    };
  }
}

Usage in Template Forms

@Component({...})
export class SecureFormComponent {
  private regexSecurity = inject(RegexSecurityService);
  private securityValidators = inject(SecurityValidators);

  emailValidator = this.securityValidators.securePattern(
    '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$',
    { timeout: 3000, safeMode: true }
  );
}

🚨 Best Practices

1. Use Safe Mode in Production

// In production, always use safeMode
const config = { safeMode: true, timeout: 3000 };

2. Appropriate Timeout

// For form validations: 1-3 seconds
// For text processing: 5-10 seconds
// Never more than 30 seconds

3. Pre-analysis

// Always analyze user-provided patterns
const analysis = await this.regexSecurity.analyzePatternSecurity(pattern);
if (!analysis.safe) {
  // Consider using a safer alternative pattern
}

4. Error Handling

try {
  const result = await this.regexSecurity.testRegex(pattern, text, config);
  // Process result
} catch (error) {
  // Handle error safely
  console.error('Regex security error:', error);
  // Fallback to a simpler validation
}

🔍 Debugging

Security Logging

The service includes automatic logging:

// Enables detailed logging
console.log('Regex security initialized');
console.log('Pattern analysis completed:', analysis);
console.log('Pattern execution completed:', result);

Performance Monitoring

// Monitor execution times
if (result.executionTime > 1000) {
  console.warn('Slow regex pattern:', pattern, result.executionTime + 'ms');
}

📝 License

MIT License - see the LICENSE file for details.

🤝 Contributions

Contributions are welcome. Please:

  1. Create an issue to discuss changes
  2. Fork the repository
  3. Create a feature branch
  4. Send a pull request

📚 Additional Resources


⚠️ Warning: This package helps prevent ReDoS but does not replace other security practices. Always validate and sanitize user inputs.