fix: Gitea Traefik routing and connection pool optimization
Some checks failed
🚀 Build & Deploy Image / Determine Build Necessity (push) Failing after 10m14s
🚀 Build & Deploy Image / Build Runtime Base Image (push) Has been skipped
🚀 Build & Deploy Image / Build Docker Image (push) Has been skipped
🚀 Build & Deploy Image / Run Tests & Quality Checks (push) Has been skipped
🚀 Build & Deploy Image / Auto-deploy to Staging (push) Has been skipped
🚀 Build & Deploy Image / Auto-deploy to Production (push) Has been skipped
Security Vulnerability Scan / Check for Dependency Changes (push) Failing after 11m25s
Security Vulnerability Scan / Composer Security Audit (push) Has been cancelled

- Remove middleware reference from Gitea Traefik labels (caused routing issues)
- Optimize Gitea connection pool settings (MAX_IDLE_CONNS=30, authentication_timeout=180s)
- Add explicit service reference in Traefik labels
- Fix intermittent 504 timeouts by improving PostgreSQL connection handling

Fixes Gitea unreachability via git.michaelschiemer.de
This commit is contained in:
2025-11-09 14:46:15 +01:00
parent 85c369e846
commit 36ef2a1e2c
1366 changed files with 104925 additions and 28719 deletions

340
docs/modules/analytics.md Normal file
View File

@@ -0,0 +1,340 @@
# Analytics Module
**Unified Analytics System for Event Tracking and User Behavior**
The Analytics Module provides a comprehensive analytics system with GDPR compliance and multiple provider support.
---
## Features
- **Event Tracking** - Track custom events
- **Page View Tracking** - Automatic and manual page view tracking
- **User Behavior Tracking** - Track user interactions
- **Multiple Providers** - Support for Google Analytics, custom endpoints, and more
- **GDPR Compliance** - Consent management and data anonymization
- **Integration with LiveComponents** - Automatic tracking of LiveComponent events
- **User Identification** - Identify users for user-level analytics
---
## Quick Start
### Basic Usage
```javascript
import { Analytics } from './modules/analytics/index.js';
// Create analytics instance
const analytics = Analytics.create({
providers: ['google-analytics'],
gdprCompliant: true,
requireConsent: true
});
// Give consent (GDPR)
analytics.giveConsent();
// Track event
await analytics.track('button_click', {
button_id: 'submit',
page: '/contact'
});
// Track page view
await analytics.trackPageView('/dashboard');
```
### Module System Integration
```html
<!-- Enable global analytics -->
<script type="module">
import { init } from './modules/analytics/index.js';
init({
providers: [
{
type: 'google-analytics',
measurementId: 'G-XXXXXXXXXX'
},
{
type: 'custom',
endpoint: '/api/analytics'
}
],
gdprCompliant: true,
requireConsent: true
});
</script>
<!-- Access globally -->
<script>
// Give consent
window.Analytics.giveConsent();
// Track event
window.Analytics.track('purchase', {
value: 99.99,
currency: 'EUR'
});
</script>
```
---
## API Reference
### Analytics.create(config)
Create a new Analytics instance.
**Parameters**:
- `config.enabled` - Enable analytics (default: true)
- `config.providers` - Array of provider configs
- `config.gdprCompliant` - Enable GDPR compliance (default: true)
- `config.requireConsent` - Require user consent (default: false)
- `config.anonymizeIp` - Anonymize IP addresses (default: true)
### analytics.track(eventName, properties)
Track a custom event.
**Parameters**:
- `eventName` - Event name
- `properties` - Event properties
**Example**:
```javascript
await analytics.track('purchase', {
value: 99.99,
currency: 'EUR',
items: [{ id: 'product-1', quantity: 1 }]
});
```
### analytics.trackPageView(path, properties)
Track a page view.
**Parameters**:
- `path` - Page path (optional, defaults to current path)
- `properties` - Additional properties
### analytics.identify(userId, traits)
Identify a user.
**Parameters**:
- `userId` - User ID
- `traits` - User traits (name, email, etc.)
**Example**:
```javascript
await analytics.identify('user-123', {
name: 'John Doe',
email: 'john@example.com'
});
```
### analytics.trackBehavior(action, target, properties)
Track user behavior.
**Parameters**:
- `action` - Action type (click, scroll, etc.)
- `target` - Target element or identifier
- `properties` - Additional properties
### analytics.giveConsent()
Give GDPR consent.
### analytics.revokeConsent()
Revoke GDPR consent.
---
## Providers
### Google Analytics
```javascript
const analytics = Analytics.create({
providers: [
{
type: 'google-analytics',
measurementId: 'G-XXXXXXXXXX'
}
]
});
```
### Custom Provider
```javascript
const analytics = Analytics.create({
providers: [
{
type: 'custom',
endpoint: '/api/analytics'
}
]
});
```
### Multiple Providers
```javascript
const analytics = Analytics.create({
providers: [
'google-analytics',
{
type: 'custom',
endpoint: '/api/analytics'
}
]
});
```
---
## GDPR Compliance
### Consent Management
```javascript
const analytics = Analytics.create({
requireConsent: true,
gdprCompliant: true
});
// Show consent banner
showConsentBanner(() => {
analytics.giveConsent();
});
```
### Data Anonymization
```javascript
// IP addresses are automatically anonymized
// PII fields are automatically removed
await analytics.track('event', {
email: 'user@example.com', // Will be removed
ip: '192.168.1.1' // Will be anonymized to 192.168.1.0
});
```
---
## Integration with LiveComponents
```javascript
import { Analytics } from './modules/analytics/index.js';
import { LiveComponent } from './modules/livecomponent/index.js';
const analytics = Analytics.create();
// Track LiveComponent actions
LiveComponent.on('action-executed', (componentId, actionName, params) => {
analytics.track('livecomponent:action', {
component_id: componentId,
action: actionName,
params
});
});
// Track component updates
LiveComponent.on('component-updated', (componentId) => {
analytics.track('livecomponent:updated', {
component_id: componentId
});
});
```
---
## Use Cases
### E-commerce Tracking
```javascript
// Track purchase
await analytics.track('purchase', {
value: 99.99,
currency: 'EUR',
items: [
{ id: 'product-1', name: 'Product 1', price: 49.99, quantity: 1 },
{ id: 'product-2', name: 'Product 2', price: 50.00, quantity: 1 }
]
});
// Track add to cart
await analytics.track('add_to_cart', {
product_id: 'product-1',
value: 49.99
});
```
### User Behavior Tracking
```javascript
// Track button clicks
document.addEventListener('click', (event) => {
if (event.target.matches('[data-track]')) {
analytics.trackBehavior('click', event.target.id, {
text: event.target.textContent
});
}
});
// Track form submissions
document.addEventListener('submit', (event) => {
analytics.track('form_submit', {
form_id: event.target.id,
form_name: event.target.name
});
});
```
### Page View Tracking
```javascript
// Automatic tracking on navigation
// Or manual tracking
await analytics.trackPageView('/dashboard', {
section: 'admin',
user_role: 'admin'
});
```
---
## Best Practices
1. **Respect User Privacy** - Always get consent before tracking
2. **Anonymize Data** - Remove PII and anonymize IPs
3. **Track Meaningful Events** - Focus on business-critical events
4. **Use Consistent Naming** - Use consistent event names
5. **Monitor Performance** - Don't let analytics slow down the app
---
## Browser Support
- **Chrome/Edge**: 90+
- **Firefox**: 88+
- **Safari**: 14+
- **Mobile**: iOS 14+, Android Chrome 90+
**Required Features**:
- ES2020 JavaScript
- Fetch API
- CustomEvent support
---
**Next**: Continue with remaining modules →

View File

@@ -0,0 +1,180 @@
# Animation System Migration Guide
**Complete Migration Guide from Old Scroll Animation Modules to Unified Animation System**
This guide helps you migrate from the old scroll animation modules to the new unified Animation System.
---
## Overview
The Animation System consolidates 8 separate modules into one unified system:
- `scrollfx``AnimationSystem` (fade-in, zoom-in)
- `parallax``AnimationSystem` (parallax)
- `scroll-timeline``AnimationSystem` (timeline)
- `scroll-loop``AnimationSystem` (timeline with loop)
- `scroll-dependent``AnimationSystem` (dependent animations)
- `sticky-fade``AnimationSystem` (sticky-fade)
- `sticky-steps``AnimationSystem` (sticky-steps)
- `smooth-scroll` → Keep separate (different purpose)
---
## Migration Steps
### 1. Update Imports
**Before**:
```javascript
import { createTrigger } from './modules/scrollfx/index.js';
import { init as initParallax } from './modules/parallax/index.js';
```
**After**:
```javascript
import { AnimationSystem } from './modules/animation-system/index.js';
```
### 2. Update Initialization
**Before**:
```javascript
createTrigger({ element: '.fade-in', offset: 0.85 });
initParallax({ selector: '.parallax' });
```
**After**:
```javascript
const system = AnimationSystem.create();
// Auto-initializes based on HTML attributes
// Or manually:
document.querySelectorAll('.fade-in').forEach(el => {
system.registerAnimation(el, { type: 'fade-in', offset: 0.85 });
});
```
### 3. Update HTML Attributes
Most HTML attributes remain compatible, but you can use new unified attributes:
**Before**:
```html
<div class="fade-in-on-scroll" data-offset="0.85">Content</div>
<div class="parallax" data-speed="0.5">Content</div>
```
**After** (still works, or use new format):
```html
<div data-animate="fade-in" data-offset="0.85">Content</div>
<div data-parallax data-speed="0.5">Content</div>
```
---
## Module-Specific Migrations
### scrollfx → AnimationSystem
**Before**:
```javascript
import { createTrigger } from './modules/scrollfx/index.js';
createTrigger({
element: '.fade-in',
offset: 0.85,
baseDelay: 0.05,
once: true
});
```
**After**:
```javascript
import { AnimationSystem } from './modules/animation-system/index.js';
const system = AnimationSystem.create();
document.querySelectorAll('.fade-in').forEach((el, index) => {
system.registerAnimation(el, {
type: 'fade-in',
offset: 0.85,
delay: index * 0.05,
once: true
});
});
```
### parallax → AnimationSystem
**Before**:
```javascript
import { init } from './modules/parallax/index.js';
init({ selector: '.parallax', speed: 0.5 });
```
**After**:
```javascript
import { AnimationSystem } from './modules/animation-system/index.js';
const system = AnimationSystem.create();
document.querySelectorAll('.parallax').forEach(el => {
system.registerAnimation(el, {
type: 'parallax',
speed: 0.5
});
});
```
### scroll-timeline → AnimationSystem
**Before**:
```javascript
import { init } from './modules/scroll-timeline/index.js';
init({ attribute: 'data-scroll-step', triggerPoint: 0.4 });
```
**After**:
```javascript
import { AnimationSystem } from './modules/animation-system/index.js';
const system = AnimationSystem.create();
document.querySelectorAll('[data-scroll-step]').forEach(el => {
system.registerAnimation(el, {
type: 'timeline',
steps: parseInt(el.dataset.scrollSteps) || null,
triggerPoint: 0.4
});
});
```
---
## Backward Compatibility
The Animation System maintains backward compatibility with existing HTML:
- Old CSS classes still work: `.fade-in-on-scroll`, `.zoom-in`, `.parallax`
- Old data attributes still work: `data-parallax`, `data-scroll-step`, etc.
- Old module initialization still works (but deprecated)
---
## Breaking Changes
1. **Module Exports** - Old module exports are deprecated
2. **JavaScript API** - Some APIs have changed (see migration examples)
3. **Configuration** - Some config options have been renamed
---
## Testing Checklist
- [ ] All fade-in animations work
- [ ] All parallax effects work
- [ ] All timeline animations work
- [ ] All sticky animations work
- [ ] Performance is acceptable
- [ ] No console errors
- [ ] Backward compatibility maintained
---
## Support
For issues or questions, see the main [Animation System documentation](animation-system.md).

View File

@@ -0,0 +1,270 @@
# Animation System Module
**Unified Animation System for Scroll-Based Animations**
The Animation System Module consolidates all scroll animation modules into a single, unified system with backward compatibility.
---
## Features
- **Fade-In Animations** - Elements fade in when scrolling into view
- **Zoom-In Animations** - Elements zoom in when scrolling into view
- **Parallax Effects** - Parallax scrolling effects
- **Scroll Timeline** - Step-based scroll animations
- **Sticky Fade** - Fade effects on sticky elements
- **Sticky Steps** - Step-based animations on sticky elements
- **IntersectionObserver Support** - Efficient scroll detection
- **Backward Compatibility** - Works with existing HTML attributes
---
## Quick Start
### Basic Usage
```javascript
import { AnimationSystem } from './modules/animation-system/index.js';
// Create animation system
const system = AnimationSystem.create({
enabled: true,
useIntersectionObserver: true
});
// Register animation
system.registerAnimation(element, {
type: 'fade-in',
offset: 0.85,
delay: 0.1,
once: true
});
```
### Module System Integration
```html
<!-- Enable global animation system -->
<script type="module">
import { init } from './modules/animation-system/index.js';
init({
enabled: true,
useIntersectionObserver: true
});
</script>
<!-- Use data attributes (auto-initialized) -->
<div class="fade-in-on-scroll" data-offset="0.85" data-delay="0.1">
Content that fades in
</div>
<div data-parallax data-speed="0.5">
Parallax content
</div>
```
---
## API Reference
### AnimationSystem.create(config)
Create a new AnimationSystem instance.
**Parameters**:
- `config.enabled` - Enable animations (default: true)
- `config.useIntersectionObserver` - Use IntersectionObserver (default: true)
- `config.throttleDelay` - Throttle delay for scroll handler (default: 16ms)
### system.registerAnimation(element, config)
Register an animation for an element.
**Parameters**:
- `element` - HTMLElement
- `config.type` - Animation type
- `config.offset` - Trigger offset (0-1)
- `config.delay` - Animation delay
- `config.once` - Trigger only once
- `config.speed` - Parallax speed
- `config.steps` - Number of steps
- `config.triggerPoint` - Trigger point (0-1)
---
## Animation Types
### Fade-In
```javascript
system.registerAnimation(element, {
type: 'fade-in',
offset: 0.85,
delay: 0.1,
once: true
});
```
### Zoom-In
```javascript
system.registerAnimation(element, {
type: 'zoom-in',
offset: 0.85,
delay: 0.1
});
```
### Parallax
```javascript
system.registerAnimation(element, {
type: 'parallax',
speed: 0.5
});
```
### Timeline
```javascript
system.registerAnimation(element, {
type: 'timeline',
steps: 5,
triggerPoint: 0.4
});
```
### Sticky Fade
```javascript
system.registerAnimation(element, {
type: 'sticky-fade',
fadeStart: 0,
fadeEnd: 1
});
```
### Sticky Steps
```javascript
system.registerAnimation(element, {
type: 'sticky-steps',
steps: 3
});
```
---
## HTML Data Attributes
### Auto-Initialization
The system automatically initializes animations based on HTML attributes:
```html
<!-- Fade in -->
<div class="fade-in-on-scroll" data-offset="0.85" data-delay="0.1">
Content
</div>
<!-- Parallax -->
<div data-parallax data-speed="0.5">
Parallax content
</div>
<!-- Timeline -->
<div data-scroll-timeline data-scroll-steps="5">
Timeline content
</div>
<!-- Sticky fade -->
<div data-sticky-fade data-fade-start="0" data-fade-end="1">
Sticky content
</div>
```
---
## Backward Compatibility
The system maintains backward compatibility with old modules:
```html
<!-- Old scrollfx classes still work -->
<div class="fade-in-on-scroll">Content</div>
<div class="zoom-in">Content</div>
<!-- Old parallax attributes still work -->
<div class="parallax" data-speed="0.5">Content</div>
<!-- Old scroll-timeline attributes still work -->
<div data-scroll-step="0">Content</div>
```
---
## Migration Guide
### From scrollfx
**Before**:
```javascript
import { createTrigger } from './modules/scrollfx/index.js';
createTrigger({ element: '.fade-in', offset: 0.85 });
```
**After**:
```javascript
import { AnimationSystem } from './modules/animation-system/index.js';
const system = AnimationSystem.create();
document.querySelectorAll('.fade-in').forEach(el => {
system.registerAnimation(el, { type: 'fade-in', offset: 0.85 });
});
```
### From parallax
**Before**:
```javascript
import { init } from './modules/parallax/index.js';
init({ selector: '.parallax' });
```
**After**:
```javascript
import { AnimationSystem } from './modules/animation-system/index.js';
const system = AnimationSystem.create();
document.querySelectorAll('.parallax').forEach(el => {
system.registerAnimation(el, { type: 'parallax', speed: 0.5 });
});
```
---
## Best Practices
1. **Use IntersectionObserver** - More efficient than scroll listeners
2. **Set Appropriate Offsets** - Balance visibility with performance
3. **Use Once for Performance** - Set `once: true` for elements that don't need to re-animate
4. **Throttle Updates** - Use appropriate throttle delays
5. **Clean Up** - Remove animations when elements are removed
---
## Browser Support
- **Chrome/Edge**: 90+
- **Firefox**: 88+
- **Safari**: 14+
- **Mobile**: iOS 14+, Android Chrome 90+
**Required Features**:
- ES2020 JavaScript
- IntersectionObserver (for efficient detection)
- requestAnimationFrame (for smooth animations)
---
**Next**: Continue with remaining modules →

View File

@@ -0,0 +1,382 @@
# Cache Manager Module
**Intelligent Caching for API Responses and Computed Values**
The Cache Manager Module provides a comprehensive caching system with multiple storage backends and caching strategies.
---
## Features
- **Memory Cache** - Fast in-memory caching
- **IndexedDB Cache** - Persistent browser storage
- **Cache Strategies** - Multiple caching strategies (cache-first, network-first, stale-while-revalidate, etc.)
- **Cache Invalidation** - Pattern-based cache invalidation
- **Cache Warming** - Preload cache values
- **Cache Analytics** - Track cache performance
- **Integration with RequestDeduplicator** - Works with LiveComponent request deduplication
---
## Quick Start
### Basic Usage
```javascript
import { CacheManager, CacheStrategy } from './modules/cache-manager/index.js';
// Create cache manager
const cache = CacheManager.create({
defaultStrategy: CacheStrategy.STALE_WHILE_REVALIDATE,
defaultTTL: 3600000 // 1 hour
});
// Get or set value
const data = await cache.getOrSet('users', async () => {
const response = await fetch('/api/users');
return await response.json();
});
// Get from cache
const cached = await cache.get('users');
// Set in cache
await cache.set('users', data, { ttl: 1800000 }); // 30 minutes
```
### Module System Integration
```html
<!-- Enable global cache manager -->
<script type="module">
import { init } from './modules/cache-manager/index.js';
init({
defaultStrategy: 'stale-while-revalidate',
enableIndexedDB: true
});
</script>
<!-- Access globally -->
<script>
// Get or set
const data = await window.CacheManager.getOrSet('key', async () => {
return await fetch('/api/data').then(r => r.json());
});
</script>
```
---
## API Reference
### CacheManager.create(config)
Create a new CacheManager instance.
**Parameters**:
- `config.defaultStrategy` - Default caching strategy
- `config.defaultTTL` - Default time-to-live in milliseconds
- `config.maxMemorySize` - Maximum items in memory cache
- `config.enableIndexedDB` - Enable IndexedDB persistence
- `config.indexedDBName` - IndexedDB database name
- `config.enableAnalytics` - Enable cache analytics
**Example**:
```javascript
const cache = CacheManager.create({
defaultStrategy: CacheStrategy.STALE_WHILE_REVALIDATE,
defaultTTL: 3600000,
maxMemorySize: 100,
enableIndexedDB: true
});
```
### cache.get(key, options)
Get value from cache.
**Parameters**:
- `key` - Cache key
- `options.strategy` - Caching strategy override
- `options.ttl` - Time-to-live override
**Returns**: `Promise<any | null>`
### cache.set(key, value, options)
Set value in cache.
**Parameters**:
- `key` - Cache key
- `value` - Value to cache
- `options.strategy` - Caching strategy
- `options.ttl` - Time-to-live
**Returns**: `Promise<void>`
### cache.getOrSet(key, computeFn, options)
Get value from cache or compute and cache it.
**Parameters**:
- `key` - Cache key
- `computeFn` - Function to compute value if not cached
- `options` - Cache options
**Returns**: `Promise<any>`
**Example**:
```javascript
const users = await cache.getOrSet('users', async () => {
const response = await fetch('/api/users');
return await response.json();
}, { ttl: 1800000 });
```
### cache.delete(key)
Delete value from cache.
**Parameters**:
- `key` - Cache key
**Returns**: `Promise<void>`
### cache.clear()
Clear all cache.
**Returns**: `Promise<void>`
### cache.invalidate(pattern)
Invalidate cache entries matching a pattern.
**Parameters**:
- `pattern` - String, RegExp, or function
**Returns**: `Promise<void>`
**Example**:
```javascript
// Invalidate all user-related cache
await cache.invalidate('user:');
// Invalidate with regex
await cache.invalidate(/^user:\d+$/);
// Invalidate with function
await cache.invalidate(key => key.startsWith('user:'));
```
### cache.warm(keys, computeFn)
Warm cache by preloading values.
**Parameters**:
- `keys` - Array of cache keys
- `computeFn` - Function to compute value for each key
**Returns**: `Promise<void>`
**Example**:
```javascript
await cache.warm(['user:1', 'user:2', 'user:3'], async (key) => {
const userId = key.split(':')[1];
const response = await fetch(`/api/users/${userId}`);
return await response.json();
});
```
### cache.getAnalytics()
Get cache performance analytics.
**Returns**: `CacheAnalytics`
**Example**:
```javascript
const analytics = cache.getAnalytics();
console.log(`Hit rate: ${analytics.hitRate}%`);
console.log(`Hits: ${analytics.hits}, Misses: ${analytics.misses}`);
```
---
## Cache Strategies
### Cache-First
Use cache if available, otherwise fetch.
```javascript
const data = await cache.getOrSet('key', fetchData, {
strategy: CacheStrategy.CACHE_FIRST
});
```
### Network-First
Try network first, fallback to cache.
```javascript
const data = await cache.getOrSet('key', fetchData, {
strategy: CacheStrategy.NETWORK_FIRST
});
```
### Stale-While-Revalidate
Return cache immediately, update in background.
```javascript
const data = await cache.getOrSet('key', fetchData, {
strategy: CacheStrategy.STALE_WHILE_REVALIDATE
});
```
### Network-Only
Always fetch from network, never use cache.
```javascript
const data = await cache.getOrSet('key', fetchData, {
strategy: CacheStrategy.NETWORK_ONLY
});
```
### Cache-Only
Only use cache, never fetch from network.
```javascript
const data = await cache.get('key', {
strategy: CacheStrategy.CACHE_ONLY
});
```
---
## Integration with RequestDeduplicator
```javascript
import { CacheManager } from './modules/cache-manager/index.js';
import { RequestDeduplicator } from './modules/livecomponent/RequestDeduplicator.js';
const cache = CacheManager.create();
const deduplicator = new RequestDeduplicator();
// Use cache with request deduplication
async function fetchWithCache(url) {
return await cache.getOrSet(url, async () => {
// Check for pending request
const pending = deduplicator.getPendingRequest('api', 'GET', { url });
if (pending) {
return await pending;
}
// Make request
const promise = fetch(url).then(r => r.json());
deduplicator.registerPendingRequest('api', 'GET', { url }, promise);
return await promise;
});
}
```
---
## Use Cases
### API Response Caching
```javascript
const cache = CacheManager.create({
defaultStrategy: CacheStrategy.STALE_WHILE_REVALIDATE,
defaultTTL: 300000 // 5 minutes
});
async function getUsers() {
return await cache.getOrSet('api:users', async () => {
const response = await fetch('/api/users');
return await response.json();
});
}
```
### Computed Value Caching
```javascript
const cache = CacheManager.create();
function expensiveComputation(input) {
// Expensive operation
return input * 2;
}
async function getComputedValue(input) {
const key = `computed:${input}`;
return await cache.getOrSet(key, () => expensiveComputation(input), {
ttl: 3600000 // Cache for 1 hour
});
}
```
### Cache Invalidation
```javascript
// Invalidate all user-related cache when user updates
async function updateUser(userId, data) {
await fetch(`/api/users/${userId}`, {
method: 'PUT',
body: JSON.stringify(data)
});
// Invalidate related cache
await cache.invalidate(`user:${userId}`);
await cache.invalidate('users:list');
}
```
### Cache Warming
```javascript
// Warm cache on page load
async function warmCache() {
await cache.warm(['user:1', 'user:2', 'user:3'], async (key) => {
const userId = key.split(':')[1];
const response = await fetch(`/api/users/${userId}`);
return await response.json();
});
}
```
---
## Best Practices
1. **Choose Appropriate Strategy** - Use cache-first for static data, network-first for dynamic data
2. **Set Appropriate TTL** - Balance freshness with performance
3. **Invalidate on Updates** - Clear cache when data changes
4. **Use Cache Warming** - Preload frequently accessed data
5. **Monitor Analytics** - Track cache performance and adjust strategy
---
## Browser Support
- **Chrome/Edge**: 90+
- **Firefox**: 88+
- **Safari**: 14+
- **Mobile**: iOS 14+, Android Chrome 90+
**Required Features**:
- ES2020 JavaScript
- IndexedDB (for persistent cache)
- Promise support
---
**Next**: Continue with Phase 3 modules →

View File

@@ -0,0 +1,413 @@
# Error Tracking Module
**Centralized Error Tracking and Reporting**
The Error Tracking Module provides comprehensive error tracking, grouping, and reporting capabilities for production applications.
---
## Features
- **Error Collection** - Automatically capture unhandled errors and promise rejections
- **Error Grouping** - Group similar errors to reduce noise
- **Error Reporting** - Send errors to backend for analysis
- **Error Analytics** - Track error frequency and patterns
- **Integration with ErrorBoundary** - Works with LiveComponent ErrorBoundary
- **Source Map Support** - Map minified errors to source code
- **Error Filtering** - Filter out known or irrelevant errors
- **Sampling** - Control error reporting volume with sampling
---
## Quick Start
### Basic Usage
```javascript
import { ErrorTracker } from './modules/error-tracking/index.js';
// Create error tracker
const tracker = ErrorTracker.create({
endpoint: '/api/errors',
enabled: true,
sampleRate: 1.0 // Report 100% of errors
});
// Manually capture an error
try {
// Some code that might throw
} catch (error) {
tracker.captureException(error, {
type: 'user-action',
action: 'submit-form'
});
}
```
### Module System Integration
```html
<!-- Enable global error tracking -->
<script type="module">
import { init } from './modules/error-tracking/index.js';
init({
endpoint: '/api/errors',
enabled: true,
sampleRate: 0.1 // Report 10% of errors
});
</script>
<!-- Access globally -->
<script>
// Errors are automatically captured
// Or manually capture:
window.ErrorTracker.captureException(new Error('Something went wrong'), {
context: { userId: 123 }
});
</script>
```
---
## API Reference
### ErrorTracker.create(config)
Create a new ErrorTracker instance.
**Parameters**:
- `config.endpoint` - Backend endpoint for error reporting (default: '/api/errors')
- `config.enabled` - Enable error tracking (default: true)
- `config.sampleRate` - Sampling rate 0.0 to 1.0 (default: 1.0)
- `config.maxErrors` - Maximum errors to keep in memory (default: 100)
- `config.groupingWindow` - Time window for error grouping in ms (default: 60000)
- `config.includeStack` - Include stack traces (default: true)
- `config.includeContext` - Include context information (default: true)
- `config.includeUserAgent` - Include user agent (default: true)
- `config.includeUrl` - Include current URL (default: true)
- `config.filters` - Array of filter functions or regex patterns
- `config.beforeSend` - Hook to modify errors before sending
**Example**:
```javascript
const tracker = ErrorTracker.create({
endpoint: '/api/errors',
enabled: true,
sampleRate: 0.5, // Report 50% of errors
filters: [
// Filter out specific errors
/Script error/i,
(error, context) => {
// Custom filter logic
return error.message.includes('ResizeObserver');
}
],
beforeSend: (errorData) => {
// Add additional context
errorData.userId = getCurrentUserId();
errorData.sessionId = getSessionId();
return errorData;
}
});
```
### tracker.captureException(error, context)
Manually capture an exception.
**Parameters**:
- `error` - Error object or any value
- `context` - Additional context information
**Example**:
```javascript
try {
// Some code
} catch (error) {
tracker.captureException(error, {
type: 'api-call',
endpoint: '/api/users',
method: 'POST'
});
}
```
### tracker.report()
Manually flush error reports to backend.
**Example**:
```javascript
// Report errors immediately
await tracker.report();
```
### tracker.getErrorGroups()
Get grouped errors.
**Returns**: `Array<ErrorGroup>`
**Example**:
```javascript
const groups = tracker.getErrorGroups();
groups.forEach(group => {
console.log(`${group.fingerprint}: ${group.count} occurrences`);
});
```
### tracker.getErrors()
Get all captured errors.
**Returns**: `Array<ErrorData>`
### tracker.clearErrors()
Clear all captured errors.
---
## Integration with ErrorBoundary
```javascript
import { ErrorTracker } from './modules/error-tracking/index.js';
import { ErrorBoundary } from './modules/livecomponent/ErrorBoundary.js';
const tracker = ErrorTracker.create({
endpoint: '/api/errors'
});
// ErrorBoundary automatically captures errors
const errorBoundary = new ErrorBoundary(liveComponentManager);
// Listen for errors
window.addEventListener('error-tracker:error', (event) => {
const errorData = event.detail;
console.error('Error captured:', errorData);
// Show user-friendly error message
showErrorNotification(errorData.message);
});
```
---
## Error Filtering
### Filter by Regex
```javascript
const tracker = ErrorTracker.create({
filters: [
/Script error/i, // Filter out script errors
/ResizeObserver/i // Filter out ResizeObserver errors
]
});
```
### Filter by Function
```javascript
const tracker = ErrorTracker.create({
filters: [
(error, context) => {
// Filter out errors from specific domains
if (context.url && context.url.includes('localhost')) {
return false; // Don't track localhost errors
}
return true; // Track other errors
}
]
});
```
---
## Error Sampling
Control error reporting volume with sampling:
```javascript
const tracker = ErrorTracker.create({
sampleRate: 0.1 // Report only 10% of errors
});
```
---
## beforeSend Hook
Modify errors before sending to backend:
```javascript
const tracker = ErrorTracker.create({
beforeSend: (errorData) => {
// Add user information
errorData.user = {
id: getCurrentUserId(),
email: getCurrentUserEmail()
};
// Add session information
errorData.session = {
id: getSessionId(),
startTime: getSessionStartTime()
};
// Remove sensitive data
delete errorData.context.password;
// Return modified error data
return errorData;
// Or return null/false to prevent sending
// return null;
}
});
```
---
## Error Grouping
Errors are automatically grouped by:
- Error name
- Error message
- Stack trace (first 3 lines)
Similar errors are grouped together to reduce noise:
```javascript
const groups = tracker.getErrorGroups();
groups.forEach(group => {
console.log(`Error: ${group.fingerprint}`);
console.log(`Count: ${group.count}`);
console.log(`First seen: ${new Date(group.firstSeen)}`);
console.log(`Last seen: ${new Date(group.lastSeen)}`);
});
```
---
## Backend Integration
The error tracker sends errors to the backend endpoint:
```javascript
POST /api/errors
Content-Type: application/json
{
"errors": [
{
"message": "Cannot read property 'x' of undefined",
"name": "TypeError",
"stack": "...",
"timestamp": 1234567890,
"type": "unhandled",
"context": {
"url": "https://example.com/page",
"userAgent": "...",
"viewport": { "width": 1920, "height": 1080 }
}
}
],
"errorGroups": [
{
"fingerprint": "TypeError:Cannot read property...",
"count": 5,
"firstSeen": 1234567890,
"lastSeen": 1234567900
}
]
}
```
---
## Use Cases
### Production Error Tracking
```javascript
const tracker = ErrorTracker.create({
endpoint: '/api/errors',
enabled: true,
sampleRate: 0.1, // Sample 10% in production
filters: [
// Filter out known issues
/ResizeObserver/i,
/Script error/i
],
beforeSend: (errorData) => {
// Add user context
errorData.userId = getCurrentUserId();
return errorData;
}
});
```
### Development Error Tracking
```javascript
const tracker = ErrorTracker.create({
endpoint: '/api/errors',
enabled: true,
sampleRate: 1.0, // Track all errors in development
includeStack: true,
includeContext: true
});
```
### API Error Tracking
```javascript
async function apiCall(url, options) {
try {
const response = await fetch(url, options);
if (!response.ok) {
throw new Error(`API error: ${response.status}`);
}
return await response.json();
} catch (error) {
tracker.captureException(error, {
type: 'api-error',
url,
method: options.method || 'GET',
status: error.status
});
throw error;
}
}
```
---
## Best Practices
1. **Use Sampling in Production** - Set sampleRate to 0.1 or lower to reduce backend load
2. **Filter Known Issues** - Filter out errors you can't fix (e.g., browser extensions)
3. **Add Context** - Use beforeSend to add user, session, or request context
4. **Group Errors** - Let the tracker group similar errors automatically
5. **Monitor Error Groups** - Track error frequency and patterns
---
## Browser Support
- **Chrome/Edge**: 90+
- **Firefox**: 88+
- **Safari**: 14+
- **Mobile**: iOS 14+, Android Chrome 90+
**Required Features**:
- ES2020 JavaScript
- Fetch API
- Promise support
---
**Next**: [Event Bus Module](event-bus.md) →

370
docs/modules/event-bus.md Normal file
View File

@@ -0,0 +1,370 @@
# Event Bus Module
**Centralized Event System for Cross-Module Communication**
The Event Bus Module provides a pub/sub event system for decoupled communication between modules, components, and services.
---
## Features
- **Pub/Sub Pattern** - Publish and subscribe to events
- **Namespaced Events** - Organize events with namespaces (e.g., 'user:created')
- **Event Filtering** - Filter events by data or conditions
- **Event History** - Track event history for debugging
- **Integration with LiveComponents** - Works seamlessly with LiveComponents
- **Integration with SSE** - Integrate with Server-Sent Events
- **Wildcard Support** - Subscribe to event patterns
- **Middleware Support** - Transform or filter events with middleware
---
## Quick Start
### Basic Usage
```javascript
import { EventBus } from './modules/event-bus/index.js';
// Create event bus
const bus = EventBus.create();
// Subscribe to an event
const unsubscribe = bus.on('user:created', (user) => {
console.log('User created:', user);
});
// Emit an event
bus.emit('user:created', { id: 1, name: 'John' });
// Unsubscribe
unsubscribe();
```
### Module System Integration
```html
<!-- Enable global event bus -->
<script type="module">
import { init } from './modules/event-bus/index.js';
init({
enableHistory: true,
maxHistorySize: 100
});
</script>
<!-- Access globally -->
<script>
// Subscribe
window.EventBus.on('user:created', (user) => {
console.log('User created:', user);
});
// Emit
window.EventBus.emit('user:created', { id: 1, name: 'John' });
</script>
```
---
## API Reference
### EventBus.create(config)
Create a new EventBus instance.
**Parameters**:
- `config.enableHistory` - Enable event history (default: false)
- `config.maxHistorySize` - Maximum history size (default: 100)
- `config.enableWildcards` - Enable wildcard patterns (default: true)
**Example**:
```javascript
const bus = EventBus.create({
enableHistory: true,
maxHistorySize: 50
});
```
### bus.on(eventName, callback, options)
Subscribe to an event.
**Parameters**:
- `eventName` - Event name (supports wildcards: 'user:*', '*')
- `callback` - Callback function: `(data, eventName, options) => void`
- `options.once` - Subscribe only once (default: false)
- `options.priority` - Subscription priority (default: 0)
- `options.filter` - Filter function: `(data, options) => boolean`
**Returns**: Unsubscribe function
**Example**:
```javascript
// Basic subscription
const unsubscribe = bus.on('user:created', (user) => {
console.log('User created:', user);
});
// Once subscription
bus.once('user:created', (user) => {
console.log('User created (once):', user);
});
// Priority subscription
bus.on('user:created', (user) => {
console.log('High priority handler');
}, { priority: 10 });
// Filtered subscription
bus.on('user:created', (user) => {
console.log('Admin user created');
}, {
filter: (user) => user.role === 'admin'
});
```
### bus.once(eventName, callback, options)
Subscribe to an event once (auto-unsubscribe after first emission).
**Parameters**: Same as `on()`
**Returns**: Unsubscribe function
### bus.off(eventName, callback)
Unsubscribe from an event.
**Parameters**:
- `eventName` - Event name
- `callback` - Callback function to remove
### bus.emit(eventName, data, options)
Emit an event.
**Parameters**:
- `eventName` - Event name
- `data` - Event data
- `options` - Event options
**Example**:
```javascript
bus.emit('user:created', { id: 1, name: 'John' });
bus.emit('user:updated', { id: 1, name: 'Jane' }, { source: 'api' });
```
### bus.use(middleware)
Add middleware to transform or filter events.
**Parameters**:
- `middleware` - Middleware function: `(eventName, data, options) => data | null | false`
**Example**:
```javascript
// Logging middleware
bus.use((eventName, data, options) => {
console.log(`Event: ${eventName}`, data);
return data; // Continue
});
// Filtering middleware
bus.use((eventName, data, options) => {
if (eventName.startsWith('debug:')) {
return null; // Block debug events in production
}
return data;
});
```
### bus.getHistory(filter)
Get event history.
**Parameters**:
- `filter` - Optional filter (string for event name, or function)
**Returns**: `Array<EventHistoryItem>`
**Example**:
```javascript
// Get all history
const history = bus.getHistory();
// Get history for specific event
const userHistory = bus.getHistory('user:created');
// Get history with custom filter
const recentHistory = bus.getHistory((item) => {
return Date.now() - item.timestamp < 60000; // Last minute
});
```
---
## Namespaced Events
Organize events with namespaces:
```javascript
// Subscribe to namespace
bus.on('user:*', (data, eventName) => {
console.log(`User event: ${eventName}`, data);
});
// Emit namespaced events
bus.emit('user:created', { id: 1 });
bus.emit('user:updated', { id: 1 });
bus.emit('user:deleted', { id: 1 });
```
---
## Wildcard Support
Subscribe to event patterns:
```javascript
// Subscribe to all events
bus.on('*', (data, eventName) => {
console.log(`Event: ${eventName}`, data);
});
// Subscribe to pattern
bus.on('user:*', (data, eventName) => {
console.log(`User event: ${eventName}`, data);
});
```
---
## Integration with LiveComponents
```javascript
import { EventBus } from './modules/event-bus/index.js';
import { LiveComponentManager } from './modules/livecomponent/index.js';
const bus = EventBus.create();
const lcManager = LiveComponentManager.getInstance();
// Listen for LiveComponent events
bus.on('livecomponent:action-executed', (data) => {
console.log('Action executed:', data);
});
// Emit LiveComponent events
lcManager.on('action-executed', (componentId, actionName, params) => {
bus.emit('livecomponent:action-executed', {
componentId,
actionName,
params
});
});
```
---
## Integration with SSE
```javascript
import { EventBus } from './modules/event-bus/index.js';
import { SseClient } from './modules/sse/index.js';
const bus = EventBus.create();
const sse = new SseClient(['updates']);
// Forward SSE messages to event bus
sse.on('message', (data) => {
bus.emit('sse:message', data);
});
// Listen for SSE events
bus.on('sse:message', (data) => {
console.log('SSE message:', data);
});
```
---
## Use Cases
### Module Communication
```javascript
// Module A
const bus = EventBus.create();
bus.emit('module-a:data-ready', { data: [...] });
// Module B
bus.on('module-a:data-ready', (data) => {
processData(data);
});
```
### Component Communication
```javascript
// Component A
bus.emit('component:user-selected', { userId: 123 });
// Component B
bus.on('component:user-selected', (data) => {
loadUserDetails(data.userId);
});
```
### Global Notifications
```javascript
// Emit notification
bus.emit('notification:show', {
type: 'success',
message: 'Operation completed'
});
// Listen for notifications
bus.on('notification:show', (data) => {
showNotification(data.type, data.message);
});
```
### Analytics Events
```javascript
// Track events
bus.on('*', (data, eventName) => {
// Send to analytics
analytics.track(eventName, data);
});
```
---
## Best Practices
1. **Use Namespaces** - Organize events with namespaces (e.g., 'user:created')
2. **Document Events** - Document all events and their data structures
3. **Use TypeScript** - Use TypeScript definitions for type safety
4. **Clean Up Subscriptions** - Always unsubscribe when done
5. **Use Middleware** - Use middleware for cross-cutting concerns (logging, analytics)
---
## Browser Support
- **Chrome/Edge**: 90+
- **Firefox**: 88+
- **Safari**: 14+
- **Mobile**: iOS 14+, Android Chrome 90+
**Required Features**:
- ES2020 JavaScript
- Map and Set support
---
**Next**: Continue with Phase 2 modules →

364
docs/modules/router.md Normal file
View File

@@ -0,0 +1,364 @@
# Router Enhancement Module
**Enhanced Routing with Guards, Middleware, and Analytics**
The Router Enhancement Module provides advanced routing capabilities with access control, middleware, lazy loading, and analytics.
---
## Features
- **Route Guards** - Access control for routes (auth, permissions, roles)
- **Route Middleware** - Cross-cutting concerns (analytics, loading, etc.)
- **Lazy Route Loading** - Load routes on demand
- **Route Analytics** - Track navigation patterns
- **Integration with LiveComponents** - Seamless integration with LiveComponent system
- **History & Hash Modes** - Support for both history and hash routing
---
## Quick Start
### Basic Usage
```javascript
import { Router, BuiltInGuards, BuiltInMiddleware } from './modules/router/index.js';
// Create router
const router = Router.create({
mode: 'history',
base: '/',
enableAnalytics: true
});
// Register routes
router.routes([
{
path: '/',
component: () => '<div>Home</div>',
name: 'home',
title: 'Home'
},
{
path: '/dashboard',
component: () => '<div>Dashboard</div>',
name: 'dashboard',
title: 'Dashboard',
guards: ['auth'],
middleware: ['analytics', 'loading']
},
{
path: '/admin',
component: () => import('./components/Admin.js'),
name: 'admin',
title: 'Admin',
guards: ['auth', 'role:admin'],
lazy: true
}
]);
// Register guards
router.guard('auth', async (to, from) => {
const isAuthenticated = await checkAuth();
if (!isAuthenticated) {
return '/login'; // Redirect to login
}
return true; // Allow navigation
});
// Add global middleware
router.use(BuiltInMiddleware.analytics);
router.use(BuiltInMiddleware.scrollToTop);
// Navigate
await router.navigate('/dashboard');
```
---
## API Reference
### Router.create(config)
Create a new Router instance.
**Parameters**:
- `config.mode` - Routing mode: 'history' or 'hash'
- `config.base` - Base path
- `config.enableAnalytics` - Enable route analytics
### router.route(path, config)
Register a single route.
**Parameters**:
- `path` - Route path
- `config.component` - Component (string, function, or HTMLElement)
- `config.name` - Route name
- `config.title` - Page title
- `config.guards` - Array of guard names
- `config.middleware` - Array of middleware
- `config.lazy` - Lazy load component
### router.guard(name, guardFn)
Register a route guard.
**Parameters**:
- `name` - Guard name
- `guardFn` - Guard function: `(to, from, context) => boolean | string`
### router.use(middleware)
Add global middleware.
**Parameters**:
- `middleware` - Middleware instance, function, or built-in name
### router.beforeEach(hook)
Add before navigation hook.
**Parameters**:
- `hook` - Hook function: `(to, from) => boolean | string | void`
### router.afterEach(hook)
Add after navigation hook.
**Parameters**:
- `hook` - Hook function: `(to, from) => void`
### router.navigate(path, options)
Navigate to a route.
**Parameters**:
- `path` - Route path
- `options.container` - Container element
- `options.updateHistory` - Update browser history
**Returns**: `Promise<boolean>`
---
## Route Guards
### Authentication Guard
```javascript
router.guard('auth', async (to, from) => {
if (!isAuthenticated()) {
return '/login';
}
return true;
});
// Use in route
router.route('/dashboard', {
component: DashboardComponent,
guards: ['auth']
});
```
### Role Guard
```javascript
router.guard('admin', async (to, from) => {
if (getUserRole() !== 'admin') {
return '/unauthorized';
}
return true;
});
// Use in route
router.route('/admin', {
component: AdminComponent,
guards: ['auth', 'admin']
});
```
### Built-in Guards
```javascript
// Use built-in guards
router.route('/dashboard', {
component: DashboardComponent,
guards: ['auth'] // Uses BuiltInGuards.auth
});
router.route('/login', {
component: LoginComponent,
guards: ['guest'] // Uses BuiltInGuards.guest
});
```
---
## Route Middleware
### Analytics Middleware
```javascript
// Use built-in analytics middleware
router.use('analytics');
// Or custom middleware
router.use(RouteMiddleware.create('custom', async (to, from, next) => {
// Track navigation
analytics.track('page_view', { path: to.path });
next();
}));
```
### Loading Middleware
```javascript
router.use('loading'); // Shows loading indicator during navigation
```
### Scroll to Top Middleware
```javascript
router.use('scroll-to-top'); // Scrolls to top after navigation
```
---
## Lazy Route Loading
```javascript
router.route('/admin', {
component: () => import('./components/Admin.js'),
lazy: true
});
// Or with dynamic import
router.route('/user/:id', {
component: async (route) => {
const UserComponent = await import('./components/User.js');
return UserComponent.default(route.params.id);
},
lazy: true
});
```
---
## Integration with LiveComponents
```javascript
import { Router } from './modules/router/index.js';
import { LiveComponent } from './modules/livecomponent/index.js';
const router = Router.create();
router.route('/dashboard', {
component: async (route) => {
// Initialize LiveComponents after navigation
const container = document.querySelector('main');
container.innerHTML = '<div data-live-component="dashboard"></div>';
// Initialize LiveComponent
const component = container.querySelector('[data-live-component]');
LiveComponent.init(component);
return container;
}
});
```
---
## Route Analytics
```javascript
const router = Router.create({ enableAnalytics: true });
// Get analytics
const analytics = router.getAnalytics();
console.log('Total navigations:', analytics.totalNavigations);
console.log('Navigation history:', analytics.navigations);
// Listen for navigation events
window.addEventListener('router:navigation', (event) => {
const { to, from, timestamp } = event.detail;
console.log(`Navigated from ${from} to ${to}`);
});
```
---
## Use Cases
### Protected Routes
```javascript
router.routes([
{
path: '/',
component: HomeComponent,
name: 'home'
},
{
path: '/dashboard',
component: DashboardComponent,
name: 'dashboard',
guards: ['auth']
},
{
path: '/admin',
component: AdminComponent,
name: 'admin',
guards: ['auth', 'admin']
}
]);
```
### Route with Middleware
```javascript
router.route('/api-data', {
component: ApiDataComponent,
middleware: ['analytics', 'loading']
});
```
### Lazy Loading
```javascript
router.route('/heavy-page', {
component: () => import('./pages/HeavyPage.js'),
lazy: true,
guards: ['auth']
});
```
---
## Best Practices
1. **Use Guards for Access Control** - Protect routes with guards
2. **Use Middleware for Cross-Cutting Concerns** - Analytics, loading, etc.
3. **Lazy Load Heavy Routes** - Improve initial load time
4. **Track Navigation** - Use analytics to understand user behavior
5. **Handle Errors** - Provide fallback routes for errors
---
## Browser Support
- **Chrome/Edge**: 90+
- **Firefox**: 88+
- **Safari**: 14+
- **Mobile**: iOS 14+, Android Chrome 90+
**Required Features**:
- ES2020 JavaScript
- History API (for history mode)
- Promise support
---
**Next**: [Analytics Module](analytics.md) →

382
docs/modules/security.md Normal file
View File

@@ -0,0 +1,382 @@
# Security Module
**Security Utilities: CSRF, XSS Protection, and CSP Helpers**
The Security Module provides comprehensive security utilities for client-side security management.
---
## Features
- **CSRF Token Management** - Automatic token refresh and management
- **XSS Protection** - HTML sanitization and input validation
- **Content Security Policy** - CSP validation and helpers
- **Security Headers Validation** - Client-side security header checks
---
## Quick Start
### Basic Usage
```javascript
import { SecurityManager } from './modules/security/index.js';
// Create security manager
const security = SecurityManager.create({
csrf: {
autoRefresh: true,
refreshInterval: 30 * 60 * 1000 // 30 minutes
},
xss: {
enabled: true,
sanitizeOnInput: false
}
});
// Get CSRF token
const token = security.getCsrfToken();
// Use in fetch request
const response = await fetch('/api/endpoint', {
method: 'POST',
headers: {
...security.getCsrfTokenHeader(),
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
```
### Module System Integration
```html
<!-- Enable global security manager -->
<script type="module">
import { init } from './modules/security/index.js';
init({
csrf: {
autoRefresh: true
}
});
</script>
<!-- Access globally -->
<script>
// Get CSRF token
const token = window.SecurityManager.getCsrfToken();
// Refresh token
await window.SecurityManager.refreshCsrfToken();
</script>
```
---
## API Reference
### SecurityManager.create(config)
Create a new SecurityManager instance.
**Parameters**:
- `config.csrf` - CSRF manager configuration
- `config.xss` - XSS protection configuration
- `config.csp` - CSP configuration
**Example**:
```javascript
const security = SecurityManager.create({
csrf: {
tokenName: '_token',
headerName: 'X-CSRF-TOKEN',
autoRefresh: true,
refreshInterval: 30 * 60 * 1000
},
xss: {
enabled: true,
sanitizeOnInput: false
}
});
```
### security.getCsrfToken()
Get current CSRF token.
**Returns**: `string | null`
### security.getCsrfTokenHeader()
Get CSRF token header object for use in fetch requests.
**Returns**: `Record<string, string>`
**Example**:
```javascript
const headers = {
...security.getCsrfTokenHeader(),
'Content-Type': 'application/json'
};
```
### security.refreshCsrfToken()
Manually refresh CSRF token.
**Returns**: `Promise<void>`
### security.escapeHtml(text)
Escape HTML to prevent XSS.
**Parameters**:
- `text` - Text to escape
**Returns**: `string`
**Example**:
```javascript
const safe = security.escapeHtml('<script>alert("xss")</script>');
// Returns: &lt;script&gt;alert(&quot;xss&quot;)&lt;/script&gt;
```
### security.validateUrl(url)
Validate URL to prevent XSS.
**Parameters**:
- `url` - URL to validate
**Returns**: `boolean`
**Example**:
```javascript
if (security.validateUrl(userInput)) {
// Safe to use
} else {
// Potentially dangerous
}
```
### security.validateSecurityHeaders()
Validate security headers.
**Returns**: `SecurityHeadersValidation`
**Example**:
```javascript
const validation = security.validateSecurityHeaders();
if (!validation.valid) {
console.warn('Security issues:', validation.issues);
}
```
---
## CSRF Token Management
### Automatic Token Refresh
```javascript
const security = SecurityManager.create({
csrf: {
autoRefresh: true,
refreshInterval: 30 * 60 * 1000 // Refresh every 30 minutes
}
});
```
### Manual Token Refresh
```javascript
await security.refreshCsrfToken();
```
### Using Token in Requests
```javascript
// Get token header
const headers = security.getCsrfTokenHeader();
// Use in fetch
const response = await fetch('/api/endpoint', {
method: 'POST',
headers: {
...headers,
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
```
---
## XSS Protection
### HTML Sanitization
```javascript
const security = SecurityManager.create({
xss: {
enabled: true,
sanitizeOnInput: true // Auto-sanitize on input
}
});
// Manual sanitization
const safe = security.sanitizeHtml(userInput);
```
### HTML Escaping
```javascript
const escaped = security.escapeHtml('<script>alert("xss")</script>');
```
### URL Validation
```javascript
if (security.validateUrl(userInput)) {
// Safe URL
window.location.href = userInput;
} else {
// Potentially dangerous
console.error('Invalid URL');
}
```
---
## Content Security Policy
### CSP Validation
```javascript
const security = SecurityManager.create({
csp: {
enabled: true
}
});
// CSP is automatically validated on init
// Check validation results
const validation = security.validateSecurityHeaders();
```
---
## Integration with LiveComponents
```javascript
import { SecurityManager } from './modules/security/index.js';
import { LiveComponentManager } from './modules/livecomponent/index.js';
const security = SecurityManager.create();
// LiveComponents automatically use CSRF tokens
// But you can also manually update tokens
security.csrfManager.updateAllTokens();
```
---
## Integration with Forms
```javascript
import { SecurityManager } from './modules/security/index.js';
const security = SecurityManager.create();
// Forms automatically get updated CSRF tokens
// Listen for token refresh events
window.addEventListener('csrf:token-refreshed', (event) => {
console.log('CSRF token refreshed:', event.detail.token);
});
```
---
## Use Cases
### API Requests with CSRF
```javascript
const security = SecurityManager.create();
async function apiCall(url, data) {
const response = await fetch(url, {
method: 'POST',
headers: {
...security.getCsrfTokenHeader(),
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
return response.json();
}
```
### User Input Sanitization
```javascript
const security = SecurityManager.create();
function handleUserInput(input) {
// Sanitize HTML
const sanitized = security.sanitizeHtml(input);
// Escape for display
const escaped = security.escapeHtml(input);
// Validate URL
if (security.validateUrl(input)) {
// Safe to use as URL
}
}
```
### Security Headers Check
```javascript
const security = SecurityManager.create();
// Validate security headers
const validation = security.validateSecurityHeaders();
if (!validation.valid) {
console.warn('Security issues detected:', validation.issues);
// Report to backend or show warning
}
```
---
## Best Practices
1. **Always Use CSRF Tokens** - Include CSRF tokens in all state-changing requests
2. **Sanitize User Input** - Sanitize HTML before displaying user content
3. **Validate URLs** - Always validate URLs before using them
4. **Enable Auto-Refresh** - Keep CSRF tokens fresh with auto-refresh
5. **Check Security Headers** - Validate security headers in development
---
## Browser Support
- **Chrome/Edge**: 90+
- **Firefox**: 88+
- **Safari**: 14+
- **Mobile**: iOS 14+, Android Chrome 90+
**Required Features**:
- ES2020 JavaScript
- Fetch API
- CustomEvent support
---
**Next**: [Cache Manager Module](cache-manager.md) →

View File

@@ -0,0 +1,397 @@
# State Manager Module
**Centralized, Reactive State Management for Client-Side State**
The State Manager Module provides a centralized state management system similar to Redux or Vuex, with support for state persistence, cross-tab synchronization, and integration with LiveComponents.
---
## Features
- **Reactive State Store** - Subscribe to state changes and react automatically
- **State Persistence** - Automatically save and restore state from localStorage or sessionStorage
- **Cross-Tab Synchronization** - Keep state synchronized across browser tabs
- **Integration with LiveComponents** - Seamless integration with LiveComponent state
- **Time-Travel Debugging** - Debug state changes with history and time-travel
- **Middleware Support** - Extend functionality with custom middleware
---
## Quick Start
### Basic Usage
```javascript
import { StateManager } from './modules/state-manager/index.js';
// Create a state manager
const store = StateManager.create({
initialState: {
user: { name: '', email: '' },
cart: { items: [], total: 0 },
ui: { sidebarOpen: false }
}
});
// Set state
store.set('user.name', 'John Doe');
store.set('cart.items', [{ id: 1, name: 'Product' }]);
// Get state
const userName = store.get('user.name');
const cartItems = store.get('cart.items', []);
// Subscribe to changes
const unsubscribe = store.subscribe('cart.items', (items) => {
console.log('Cart items changed:', items);
updateCartUI(items);
});
// Unsubscribe
unsubscribe();
```
### Module System Integration
```html
<!-- Enable global state manager -->
<script type="module">
import { init } from './modules/state-manager/index.js';
init({
initialState: {
user: {},
cart: {}
},
persistence: {
enabled: true,
storage: 'localStorage',
key: 'app-state'
}
});
</script>
<!-- Access globally -->
<script>
window.StateManager.set('user.name', 'John');
const name = window.StateManager.get('user.name');
</script>
```
---
## API Reference
### StateManager.create(config)
Create a new StateManager instance.
**Parameters**:
- `config.initialState` - Initial state object
- `config.maxHistorySize` - Maximum history size (default: 50)
- `config.enableHistory` - Enable history for time-travel (default: false)
- `config.persistence.enabled` - Enable state persistence (default: false)
- `config.persistence.storage` - Storage type: 'localStorage' or 'sessionStorage' (default: 'localStorage')
- `config.persistence.key` - Storage key (default: 'app-state')
- `config.persistence.paths` - Array of paths to persist (empty = all)
- `config.sync.enabled` - Enable cross-tab synchronization (default: false)
**Example**:
```javascript
const store = StateManager.create({
initialState: { user: {}, cart: {} },
persistence: {
enabled: true,
storage: 'localStorage',
paths: ['user', 'cart'] // Only persist these paths
},
sync: {
enabled: true // Sync across tabs
}
});
```
### store.getState()
Get the entire state object.
**Returns**: `Record<string, any>`
### store.get(path, defaultValue)
Get state at a specific path.
**Parameters**:
- `path` - Dot-separated path (e.g., 'user.name')
- `defaultValue` - Default value if path doesn't exist
**Returns**: `any`
**Example**:
```javascript
const userName = store.get('user.name', 'Guest');
const cartTotal = store.get('cart.total', 0);
```
### store.set(path, value)
Set state at a specific path.
**Parameters**:
- `path` - Dot-separated path
- `value` - Value to set
**Example**:
```javascript
store.set('user.name', 'John Doe');
store.set('cart.items', [{ id: 1, name: 'Product' }]);
```
### store.dispatch(action)
Dispatch an action (Redux-style).
**Parameters**:
- `action` - Action object with `type` property, or a thunk function
**Example**:
```javascript
// Simple action
store.dispatch({
type: 'ADD_TO_CART',
productId: 123,
quantity: 1
});
// Thunk (async action)
store.dispatch(async (dispatch, getState) => {
const response = await fetch('/api/products');
const products = await response.json();
dispatch({ type: 'SET_PRODUCTS', products });
});
```
### store.subscribe(path, callback)
Subscribe to state changes at a specific path.
**Parameters**:
- `path` - Dot-separated path, or '*' for all changes
- `callback` - Callback function: `(newValue, oldValue, path) => void`
**Returns**: Unsubscribe function
**Example**:
```javascript
const unsubscribe = store.subscribe('cart.items', (items, oldItems, path) => {
console.log(`Cart items changed at ${path}:`, items);
updateCartUI(items);
});
// Later...
unsubscribe();
```
### store.subscribeAll(callback)
Subscribe to all state changes.
**Parameters**:
- `callback` - Callback function: `(state) => void`
**Returns**: Unsubscribe function
### store.use(middleware)
Add middleware to the state manager.
**Parameters**:
- `middleware` - Middleware function: `(action, getState) => action | null`
**Example**:
```javascript
// Logging middleware
store.use((action, getState) => {
console.log('Action:', action);
console.log('Current state:', getState());
return action; // Return action to continue, or null to block
});
// Validation middleware
store.use((action, getState) => {
if (action.type === 'SET' && action.path === 'user.email') {
if (!isValidEmail(action.value)) {
console.error('Invalid email');
return null; // Block the action
}
}
return action;
});
```
### store.getHistory()
Get action history for time-travel debugging.
**Returns**: `Array<HistoryPoint>`
### store.timeTravel(index)
Time-travel to a specific history point.
**Parameters**:
- `index` - History index
### store.reset()
Reset state to initial state.
### store.destroy()
Destroy the state manager and clean up resources.
---
## Integration with LiveComponents
```javascript
import { StateManager } from './modules/state-manager/index.js';
import { LiveComponentManager } from './modules/livecomponent/index.js';
const store = StateManager.create();
const lcManager = LiveComponentManager.getInstance();
// Sync LiveComponent state with StateManager
lcManager.on('component:state-updated', (componentId, state) => {
store.set(`livecomponents.${componentId}`, state);
});
// Update LiveComponent from StateManager
store.subscribe('livecomponents', (state) => {
Object.entries(state).forEach(([componentId, componentState]) => {
lcManager.updateComponentState(componentId, componentState);
});
});
```
---
## Use Cases
### User Preferences
```javascript
const store = StateManager.create({
initialState: {
preferences: {
theme: 'light',
language: 'en',
notifications: true
}
},
persistence: {
enabled: true,
storage: 'localStorage',
paths: ['preferences']
}
});
// Save preference
store.set('preferences.theme', 'dark');
// Load preference
const theme = store.get('preferences.theme', 'light');
```
### Shopping Cart
```javascript
const store = StateManager.create({
initialState: {
cart: {
items: [],
total: 0
}
},
persistence: {
enabled: true,
storage: 'sessionStorage',
paths: ['cart']
},
sync: {
enabled: true // Sync cart across tabs
}
});
// Add item
store.set('cart.items', [
...store.get('cart.items', []),
{ id: 1, name: 'Product', price: 99.99 }
]);
// Calculate total
store.subscribe('cart.items', (items) => {
const total = items.reduce((sum, item) => sum + item.price, 0);
store.set('cart.total', total);
});
```
### UI State
```javascript
const store = StateManager.create({
initialState: {
ui: {
sidebarOpen: false,
modalOpen: false,
activeTab: 'home'
}
}
});
// Toggle sidebar
store.set('ui.sidebarOpen', !store.get('ui.sidebarOpen'));
// Subscribe to UI changes
store.subscribe('ui', (uiState) => {
updateUI(uiState);
});
```
---
## Best Practices
1. **Use Scoped State Managers** - Create separate state managers for different features
2. **Persist Only Necessary Data** - Use `paths` to limit what gets persisted
3. **Use Middleware for Cross-Cutting Concerns** - Logging, validation, etc.
4. **Subscribe Selectively** - Only subscribe to paths you need
5. **Clean Up Subscriptions** - Always call unsubscribe when done
---
## Performance Considerations
- State updates are synchronous and immediate
- Subscriptions are called synchronously (be careful with expensive operations)
- Persistence is debounced internally
- Cross-tab sync uses BroadcastChannel (efficient)
---
## Browser Support
- **Chrome/Edge**: 38+
- **Firefox**: 38+
- **Safari**: 15.4+
- **Mobile**: iOS 15.4+, Android Chrome 38+
**Required Features**:
- ES2020 JavaScript
- BroadcastChannel (for cross-tab sync)
- localStorage/sessionStorage (for persistence)
---
**Next**: [Validation Module](validation.md) →

462
docs/modules/validation.md Normal file
View File

@@ -0,0 +1,462 @@
# Validation Module
**Standalone Validation System for Fields, Forms, and Data**
The Validation Module provides a comprehensive validation system that can be used independently or integrated with form-handling and LiveComponents.
---
## Features
- **Schema-Based Validation** - Define validation rules in a schema
- **Field-Level Validation** - Validate individual fields
- **Async Validation** - Support for asynchronous validation (e.g., API checks)
- **Custom Validation Rules** - Register your own validation rules
- **Integration with form-handling** - Works seamlessly with form-handling module
- **Integration with LiveComponents** - Validate LiveComponent data
- **HTML5 Attribute Support** - Automatically reads validation rules from HTML attributes
---
## Quick Start
### Basic Usage
```javascript
import { Validator } from './modules/validation/index.js';
// Create validator with schema
const validator = Validator.create({
email: ['required', 'email'],
age: [
'required',
'number',
{ rule: 'min', options: { value: 18 } },
{ rule: 'max', options: { value: 100 } }
],
password: [
'required',
{ rule: 'minLength', options: { value: 8 } }
]
});
// Validate data
const result = await validator.validate({
email: 'user@example.com',
age: 25,
password: 'secret123'
});
if (result.valid) {
console.log('Validation passed');
} else {
console.log('Validation errors:', result.errors);
}
```
### From HTML Form
```javascript
import { Validator } from './modules/validation/index.js';
// Create validator from form element
const form = document.querySelector('#my-form');
const validator = Validator.fromForm(form);
// Validate form data
const formData = new FormData(form);
const data = Object.fromEntries(formData);
const result = await validator.validate(data);
```
---
## API Reference
### Validator.create(schema)
Create a new Validator instance with a schema.
**Parameters**:
- `schema` - Validation schema object
**Example**:
```javascript
const validator = Validator.create({
email: 'email',
age: ['required', 'number', { rule: 'min', options: { value: 18 } }]
});
```
### Validator.fromForm(form)
Create a validator from an HTML form element, reading validation rules from HTML attributes.
**Parameters**:
- `form` - HTMLFormElement
**Example**:
```html
<form id="my-form">
<input type="email" name="email" required />
<input type="number" name="age" min="18" max="100" required />
<input type="password" name="password" minlength="8" required />
</form>
```
```javascript
const form = document.querySelector('#my-form');
const validator = Validator.fromForm(form);
```
### validator.validate(data)
Validate entire data object against schema.
**Parameters**:
- `data` - Data object to validate
**Returns**: `Promise<ValidationResults>`
**Example**:
```javascript
const result = await validator.validate({
email: 'user@example.com',
age: 25
});
console.log(result.valid); // true or false
console.log(result.errors); // { email: ['...'], age: ['...'] }
```
### validator.validateField(fieldName, value)
Validate a single field.
**Parameters**:
- `fieldName` - Field name
- `value` - Field value
**Returns**: `Promise<ValidationResult>`
**Example**:
```javascript
const result = await validator.validateField('email', 'user@example.com');
console.log(result.valid); // true or false
console.log(result.errors); // ['error message']
```
### validator.validateFields(data, fieldNames)
Validate specific fields.
**Parameters**:
- `data` - Data object
- `fieldNames` - Array of field names to validate
**Returns**: `Promise<ValidationResults>`
### validator.registerRule(name, rule)
Register a custom validation rule.
**Parameters**:
- `name` - Rule name
- `rule` - Validation function: `(value, options) => boolean | string`
**Example**:
```javascript
validator.registerRule('customRule', (value, options) => {
if (value === options.expected) {
return true;
}
return options.message || 'Validation failed';
});
// Use custom rule
const validator = Validator.create({
field: { rule: 'customRule', options: { expected: 'test', message: 'Must be "test"' } }
});
```
---
## Built-in Validation Rules
### required
Field must have a value.
```javascript
email: 'required'
// or
email: { rule: 'required', options: { message: 'Email is required' } }
```
### email
Valid email address format.
```javascript
email: 'email'
```
### url
Valid URL format.
```javascript
website: 'url'
```
### min / max
Minimum/maximum numeric value.
```javascript
age: [
{ rule: 'min', options: { value: 18 } },
{ rule: 'max', options: { value: 100 } }
]
```
### minLength / maxLength
Minimum/maximum string length.
```javascript
password: [
{ rule: 'minLength', options: { value: 8 } },
{ rule: 'maxLength', options: { value: 128 } }
]
```
### pattern
Regex pattern validation.
```javascript
username: {
rule: 'pattern',
options: {
value: '^[a-zA-Z0-9_]+$',
message: 'Username can only contain letters, numbers, and underscores'
}
}
```
### number
Must be a valid number.
```javascript
price: 'number'
```
### integer
Must be an integer.
```javascript
quantity: 'integer'
```
### phone
Valid phone number format.
```javascript
phone: 'phone'
```
### postalCode
Valid postal code (supports DE, US, UK, FR).
```javascript
postalCode: {
rule: 'postalCode',
options: { country: 'DE' }
}
```
### custom
Custom validation function.
```javascript
field: {
rule: 'custom',
options: {
validator: (value, options) => {
// Custom validation logic
return value === options.expected ? true : 'Value must be ' + options.expected;
},
expected: 'test'
}
}
```
---
## Async Validation
```javascript
const validator = Validator.create({
email: {
rule: 'custom',
async: true,
validator: async (value, options) => {
// Check if email exists via API
const response = await fetch(`/api/check-email?email=${value}`);
const data = await response.json();
if (data.exists) {
return 'Email already exists';
}
return true;
}
}
});
const result = await validator.validate({ email: 'user@example.com' });
```
---
## Integration with form-handling
```javascript
import { Validator } from './modules/validation/index.js';
import { FormHandler } from './modules/form-handling/index.js';
const form = document.querySelector('#my-form');
const validator = Validator.fromForm(form);
const formHandler = FormHandler.create(form);
// Use validator with form handler
formHandler.validator = validator;
```
---
## Integration with LiveComponents
```javascript
import { Validator } from './modules/validation/index.js';
import { LiveComponentManager } from './modules/livecomponent/index.js';
const validator = Validator.create({
email: ['required', 'email'],
name: ['required', { rule: 'minLength', options: { value: 2 } }]
});
// Validate before action
const lcManager = LiveComponentManager.getInstance();
lcManager.on('action:before-execute', async (componentId, actionName, params) => {
if (actionName === 'submitForm') {
const result = await validator.validate(params);
if (!result.valid) {
// Handle validation errors
return false; // Prevent action
}
}
});
```
---
## Use Cases
### Form Validation
```javascript
const validator = Validator.create({
email: ['required', 'email'],
password: [
'required',
{ rule: 'minLength', options: { value: 8 } }
],
confirmPassword: [
'required',
{
rule: 'custom',
validator: (value, options) => {
const password = options.password;
return value === password ? true : 'Passwords do not match';
},
options: { password: formData.password }
}
]
});
```
### API Response Validation
```javascript
const validator = Validator.create({
id: ['required', 'integer'],
name: ['required', { rule: 'minLength', options: { value: 1 } }],
email: ['required', 'email']
});
// Validate API response
const response = await fetch('/api/user');
const data = await response.json();
const result = await validator.validate(data);
if (!result.valid) {
console.error('Invalid API response:', result.errors);
}
```
### User Input Validation
```javascript
// Validate on input
const validator = Validator.create({
search: {
rule: 'minLength',
options: { value: 3, message: 'Search must be at least 3 characters' }
}
});
const input = document.querySelector('#search');
input.addEventListener('input', async (e) => {
const result = await validator.validateField('search', e.target.value);
if (!result.valid) {
showError(result.errors[0]);
} else {
hideError();
}
});
```
---
## Best Practices
1. **Use Schema-Based Validation** - Define validation rules in a schema for reusability
2. **Register Custom Rules** - Create reusable custom validation rules
3. **Validate Early** - Validate on blur or input for better UX
4. **Show Clear Errors** - Display validation errors clearly to users
5. **Use Async Validation Sparingly** - Only for necessary checks (e.g., email uniqueness)
---
## Browser Support
- **Chrome/Edge**: 90+
- **Firefox**: 88+
- **Safari**: 14+
- **Mobile**: iOS 14+, Android Chrome 90+
**Required Features**:
- ES2020 JavaScript
- Promise support
- Async/await support
---
**Next**: [Error Tracking Module](error-tracking.md) →