keypointjs 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,808 @@
1
+ # KeypointJS - Complete Documentation
2
+
3
+ <div align="center">
4
+
5
+ ![KeypointJS Banner](./assets/banner.png)
6
+
7
+ </div>
8
+
9
+ Based on your complete codebase, here is the comprehensive documentation:
10
+
11
+ <div align="center">
12
+ <p align="center">
13
+ <img alt="GitHub" src="https://img.shields.io/github/license/anasbex-dev/keypointjs?color=blue">
14
+ <img alt="npm" src="https://img.shields.io/npm/v/keypointjs">
15
+ <img alt="Node.js" src="https://img.shields.io/badge/Node.js-%3E%3D18.0.0-green">
16
+ <img alt="TypeScript" src="https://img.shields.io/badge/TypeScript-Ready-blue">
17
+ <img alt="Tests" src="https://img.shields.io/badge/tests-100%25%20passing-brightgreen">
18
+ </p>
19
+ **A Modern, Extensible Authentication & Authorization Framework for Node.js**
20
+
21
+ [Getting Started](#-quick-start) • [Documentation](#-documentation) • [Examples](#-examples) • [Contributing](./CONTRIBUTING.md)
22
+
23
+ </div>
24
+
25
+
26
+
27
+ # Project Overview
28
+
29
+ KeypointJS is a sophisticated, layered authentication and authorization framework for Node.js with built-in security features, plugin architecture, and real-time capabilities.
30
+
31
+ # Architecture
32
+
33
+ Layered Middleware System
34
+
35
+ ```
36
+ ┌─────────────────────────────────┐
37
+ │ Layer 0: Pre-processing Hooks │
38
+ ├─────────────────────────────────┤
39
+ │ Layer 1: Protocol Engine │
40
+ ├─────────────────────────────────┤
41
+ │ Layer 2: CORS Middleware │
42
+ ├─────────────────────────────────┤
43
+ │ Layer 3: Keypoint Validation │
44
+ ├─────────────────────────────────┤
45
+ │ Layer 4: Policy Check │
46
+ ├─────────────────────────────────┤
47
+ │ Layer 5: Plugin Processing │
48
+ ├─────────────────────────────────┤
49
+ │ Layer 6: Route Execution │
50
+ ├─────────────────────────────────┤
51
+ │ Layer 7: Response Processing │
52
+ └─────────────────────────────────┘
53
+ ```
54
+
55
+ # File Structure & Responsibilities
56
+
57
+ ## Core Components (core/)
58
+
59
+ - Context.js - Request Context Base Class
60
+
61
+ - Request/Response wrapper
62
+ - State management
63
+ - Plugin data storage
64
+ - Helper methods for JSON, text, HTML
65
+ responses
66
+ - Header and query parameter accessors
67
+
68
+ ## ProtocolEngine.js - Protocol Detection & Processing
69
+
70
+ - HTTP/HTTPS/WebSocket protocol detection
71
+ - Request body parsing (JSON, form data)
72
+ - IP extraction from headers
73
+ - Body size limiting
74
+ - Protocol validation
75
+
76
+ # Keypoint System (keypoint/)
77
+
78
+ ## Keypoint.js - Keypoint Entity
79
+
80
+ - Keypoint data model (keyId, secret, scopes, protocols)
81
+ - Scope validation methods
82
+ - Expiration checking
83
+ - Origin and protocol validation
84
+ - Rate limit configuration
85
+
86
+ ## KeypointContext.js - Enhanced Context
87
+
88
+ - Extends base Context class
89
+ - Keypoint-specific methods (scope checking, rate limiting)
90
+ - Access logging
91
+ - Security validation (origin, protocol)
92
+ - Authentication state management
93
+
94
+ ## KeypointStorage.js - Storage Abstraction
95
+
96
+ - In-memory storage with indexing
97
+ - File-based storage option
98
+ - CRUD operations with indexing by secret, name, scope
99
+ - Cleanup of expired keypoints
100
+ - List operations with filtering
101
+
102
+ ## KeypointValidator.js - Authentication Validator
103
+
104
+ - Extracts keypoint from request headers/query
105
+ - Validates keypoint existence and expiration
106
+ - Secret verification
107
+ - Context attachment
108
+
109
+ ## ScopeManager.js - Scope Management System
110
+
111
+ - Scope definition and hierarchy
112
+ - Inheritance system
113
+ - Scope validation and expansion
114
+ - Pattern matching for wildcard scopes
115
+ - Scope tree generation
116
+
117
+ # Policy Engine (policy/)
118
+
119
+ ## PolicyEngine.js - Policy Evaluation Engine
120
+
121
+ - Rule-based access control
122
+ - Policy registration and evaluation
123
+ - Built-in policy templates (allow, deny)
124
+ - Context-based decision making
125
+
126
+ ## PolicyRule.js - Rule Definitions
127
+
128
+ - Base PolicyRule class
129
+ - Built-in rules: method, origin, IP, time window, rate limit, scope, protocol
130
+ - Rule evaluation with metadata
131
+ - Priority and enablement controls
132
+
133
+ ## AccessDecision.js - Decision Management
134
+
135
+ - Access decision data structure
136
+ Allow/Deny decision creation
137
+ - Rule result aggregation
138
+ - Merge operations for chained decisions
139
+ - Debug information generation
140
+
141
+ # Plugin System (plugins/)
142
+
143
+ ## PluginManager.js - Plugin Orchestration
144
+
145
+ - Plugin registration and lifecycle management
146
+ - Middleware chain composition
147
+ - Event and hook system
148
+ - Built-in hooks for request lifecycle
149
+ - Plugin statistics and management
150
+
151
+ ## AuditLogger.js - Comprehensive Logging
152
+
153
+ - Request/response logging
154
+ - File-based logging with rotation
155
+ - Console output with colors
156
+ - Queryable log storage
157
+ · Error tracking and reporting
158
+
159
+ ## RateLimiter.js - Rate Limiting
160
+
161
+ - Keypoint-based rate limiting
162
+ - Time window enforcement
163
+ - Request counting per window
164
+
165
+ ## WebSocketGuard.js - WebSocket Security
166
+
167
+ - WebSocket server integration
168
+ - Keypoint validation for WebSocket connections
169
+ - Connection management and monitoring
170
+ - Message handling and broadcasting
171
+ - Ping/pong keepalive
172
+
173
+ # Router (router/)
174
+
175
+ ## MinimalRouter.js - Simple HTTP Router
176
+
177
+ - Method-based route registration
178
+ - Direct path matching
179
+ - Request handling with context
180
+ - Route management
181
+
182
+ # Main Framework (keypointJS.js)
183
+
184
+ - Main class orchestrating all components
185
+ - Server creation and management
186
+ - Configuration system
187
+ - Statistics and health checks
188
+ - Event emission system
189
+ - Error handling
190
+
191
+ # Quick Start
192
+
193
+ Installation & Setup
194
+
195
+ ```javascript
196
+ import { KeypointJS } from './src/keypointJS.js';
197
+
198
+ // Initialize the framework
199
+ const api = new KeypointJS({
200
+ requireKeypoint: true,
201
+ strictMode: false,
202
+ enableCORS: true,
203
+ maxRequestSize: '5mb'
204
+ });
205
+
206
+ // Create and store a keypoint
207
+ const keypoint = await api.createKeypoint({
208
+ keyId: 'test_key',
209
+ secret: 'test_secret',
210
+ scopes: ['api:public', 'users:read'],
211
+ protocols: ['https', 'wss'],
212
+ allowedOrigins: ['https://example.com'],
213
+ rateLimit: {
214
+ requests: 1000,
215
+ window: 3600 // 1 hour
216
+ }
217
+ });
218
+
219
+ // Define routes
220
+ api.get('/api/data', (ctx) => {
221
+ return ctx.json({
222
+ data: 'protected data',
223
+ keypointId: ctx.getKeypointId(),
224
+ scopes: ctx.keypoint?.scopes
225
+ });
226
+ });
227
+
228
+ api.post('/api/webhook', (ctx) => {
229
+ const body = ctx.body;
230
+ // Process webhook
231
+ return ctx.json({ received: true });
232
+ });
233
+
234
+ // Start server
235
+ api.listen(3000, 'localhost', () => {
236
+ console.log('Server running on port 3000');
237
+ });
238
+ ```
239
+
240
+ # Authentication Flow
241
+
242
+ 1. Request with Keypoint
243
+
244
+ ```http
245
+ GET /api/data HTTP/1.1
246
+ Host: localhost:3000
247
+ X-Keypoint-ID: test_key
248
+ X-Keypoint-Secret: test_secret
249
+ ```
250
+
251
+ 2. Validation Process
252
+
253
+ ```javascript
254
+ // Layer-by-layer processing:
255
+ 1. ProtocolEngine: Detect protocol, parse body
256
+ 2. KeypointValidator: Extract and validate keypoint
257
+ 3. PolicyEngine: Evaluate access rules
258
+ 4. Router: Execute route handler
259
+ 5. Response: Return formatted response
260
+ ```
261
+
262
+ 3. Scope-Based Authorization
263
+
264
+ ```javascript
265
+ // Route requiring specific scope
266
+ api.get('/api/users', (ctx) => {
267
+ if (!ctx.hasScope('users:read')) {
268
+ return ctx.status(403).json({ error: 'Insufficient scope' });
269
+ }
270
+ // Return user data
271
+ });
272
+ ```
273
+
274
+ # Configuration Options
275
+
276
+ KeypointJS Constructor Options
277
+
278
+ ```javascript
279
+ const api = new KeypointJS({
280
+ // Core settings
281
+ requireKeypoint: true, // Require authentication
282
+ strictMode: true, // Strict validation mode
283
+
284
+ // Security
285
+ validateOrigin: true, // Validate request origin
286
+ validateProtocol: true, // Validate protocol
287
+ enableCORS: false, // Enable CORS
288
+ corsOrigins: ['*'], // Allowed origins
289
+
290
+ // Performance
291
+ maxRequestSize: '10mb', // Max request body size
292
+
293
+ // Headers
294
+ defaultResponseHeaders: {
295
+ 'X-Powered-By': 'KeypointJS',
296
+ 'X-Content-Type-Options': 'nosniff'
297
+ },
298
+
299
+ // Storage
300
+ keypointStorage: new MemoryKeypointStorage() // Custom storage
301
+ });
302
+ ```
303
+
304
+ Keypoint Configuration
305
+
306
+ ```javascript
307
+ const keypoint = {
308
+ keyId: 'unique_id', // Required
309
+ secret: 'secure_password', // Required
310
+ name: 'Production Key', // Optional
311
+ scopes: ['api:write', 'admin'],
312
+ protocols: ['https', 'wss'], // Allowed protocols
313
+ allowedOrigins: ['https://app.com'],
314
+ allowedIps: ['192.168.1.0/24'],
315
+ rateLimit: {
316
+ requests: 1000, // Requests per window
317
+ window: 3600 // Seconds (1 hour)
318
+ },
319
+ expiresAt: new Date('2024-12-31'),
320
+ metadata: {
321
+ userId: 'user_123',
322
+ environment: 'production'
323
+ }
324
+ };
325
+ ```
326
+
327
+ # Plugin System
328
+
329
+ Built-in Plugins
330
+
331
+ 1. Audit Logger
332
+
333
+ ```javascript
334
+ import { AuditLogger } from './plugins/AuditLogger.js';
335
+
336
+ api.registerPlugin(new AuditLogger({
337
+ logLevel: 'info',
338
+ logToConsole: true,
339
+ logToFile: true,
340
+ filePath: './logs/audit.log',
341
+ maxFileSize: '50mb'
342
+ }));
343
+ ```
344
+
345
+ 2. Rate Limiter
346
+
347
+ ```javascript
348
+ import { RateLimiter } from './plugins/RateLimiter.js';
349
+
350
+ api.registerPlugin(new RateLimiter({
351
+ window: 60000 // 1 minute in milliseconds
352
+ }));
353
+ ```
354
+
355
+ 3. WebSocket Guard
356
+
357
+ ```javascript
358
+ import { WebSocketGuard } from './plugins/WebSocketGuard.js';
359
+
360
+ const wsGuard = api.enableWebSocket({
361
+ path: '/ws',
362
+ requireKeypoint: true,
363
+ pingInterval: 30000,
364
+ maxConnections: 1000
365
+ });
366
+
367
+ wsGuard.onConnection((connection) => {
368
+ console.log('New WebSocket connection:', connection.id);
369
+ });
370
+
371
+ wsGuard.onMessage('chat', (message, connection) => {
372
+ // Handle chat messages
373
+ return { type: 'chat_response', data: 'Message received' };
374
+ });
375
+ ```
376
+
377
+ Custom Plugin Creation
378
+
379
+ ```javascript
380
+ export class CustomPlugin {
381
+ constructor(options = {}) {
382
+ this.name = 'CustomPlugin';
383
+ this.options = options;
384
+ }
385
+
386
+ async process(ctx, next) {
387
+ const startTime = Date.now();
388
+ const result = await next(ctx);
389
+ const duration = Date.now() - startTime;
390
+
391
+ ctx.setPluginData(this.name, { duration });
392
+ return result;
393
+ }
394
+
395
+ initialize() {
396
+ console.log(`${this.name} initialized`);
397
+ }
398
+
399
+ cleanup() {
400
+ console.log(`${this.name} cleaned up`);
401
+ }
402
+ }
403
+
404
+ // Register custom plugin
405
+ api.registerPlugin(new CustomPlugin({ debug: true }));
406
+ ```
407
+
408
+ # Security Features
409
+
410
+ Rate Limiting
411
+
412
+ ```javascript
413
+ // Built-in rate limiting rule
414
+ api.addPolicyRule(
415
+ BuiltInRules.rateLimitRule(100, 60) // 100 requests per minute
416
+ );
417
+
418
+ // Keypoint-specific rate limiting
419
+ const keypoint = new Keypoint({
420
+ keyId: 'limited_key',
421
+ secret: 'secret',
422
+ rateLimit: {
423
+ requests: 50, // 50 requests
424
+ window: 300 // per 5 minutes
425
+ }
426
+ });
427
+ ```
428
+
429
+ IP Whitelisting/Blacklisting
430
+
431
+ ```javascript
432
+ api.addPolicyRule(
433
+ BuiltInRules.ipRule(
434
+ ['192.168.1.0/24'], // Allowed IPs
435
+ ['10.0.0.5', '172.16.0.0/12'] // Blocked IPs
436
+ )
437
+ );
438
+ ```
439
+
440
+ Time-Based Access Control
441
+
442
+ ```javascript
443
+ // Only allow access between 9 AM and 5 PM
444
+ api.addPolicyRule(
445
+ BuiltInRules.timeWindowRule(9, 17)
446
+ );
447
+ ```
448
+
449
+ Protocol Enforcement
450
+
451
+ ```javascript
452
+ // Only allow HTTPS and WSS protocols
453
+ api.addPolicyRule(
454
+ BuiltInRules.protocolRule(['https', 'wss'])
455
+ );
456
+ ```
457
+
458
+ # WebSocket Support
459
+
460
+ Setup WebSocket Server
461
+
462
+ ```javascript
463
+ // Enable WebSocket support
464
+ const wsGuard = api.enableWebSocket({
465
+ path: '/realtime',
466
+ requireKeypoint: true,
467
+ keypointHeader: 'x-keypoint-id'
468
+ });
469
+
470
+ // Handle WebSocket connections
471
+ wsGuard.onConnection((connection) => {
472
+ console.log('Connected:', {
473
+ id: connection.id,
474
+ keypointId: connection.keypointId,
475
+ ip: connection.ip
476
+ });
477
+ });
478
+
479
+ // Broadcast messages
480
+ wsGuard.broadcast({
481
+ type: 'notification',
482
+ data: 'System update'
483
+ }, {
484
+ scope: 'admin' // Only send to admin keypoints
485
+ });
486
+
487
+ // Send to specific connection
488
+ wsGuard.sendToConnection('connection_id', {
489
+ type: 'private',
490
+ data: 'Secret message'
491
+ });
492
+ ```
493
+
494
+ WebSocket Message Handling
495
+
496
+ ```javascript
497
+ wsGuard.onMessage('subscribe', async (message, connection) => {
498
+ const { channel } = message;
499
+
500
+ // Validate subscription rights
501
+ if (channel === 'admin' && !connection.scopes?.includes('admin')) {
502
+ return { type: 'error', error: 'Access denied' };
503
+ }
504
+
505
+ connection.metadata.subscriptions =
506
+ connection.metadata.subscriptions || [];
507
+ connection.metadata.subscriptions.push(channel);
508
+
509
+ return {
510
+ type: 'subscribed',
511
+ channel,
512
+ timestamp: new Date().toISOString()
513
+ };
514
+ });
515
+ ```
516
+
517
+ # Monitoring & Statistics
518
+
519
+ Framework Statistics
520
+
521
+ ```javascript
522
+ const stats = api.getStats();
523
+
524
+ console.log('Framework Statistics:', {
525
+ uptime: stats.uptimeFormatted,
526
+ totalRequests: stats.requests,
527
+ successRate: stats.successRate,
528
+ activeKeypoints: stats.keypoints.active,
529
+ totalPlugins: stats.plugins.totalPlugins,
530
+ activeConnections: wsGuard?.getStats()?.totalConnections || 0
531
+ });
532
+ ```
533
+
534
+ Health Check Endpoint
535
+
536
+ ```javascript
537
+ api.get('/health', async (ctx) => {
538
+ const health = await api.healthCheck();
539
+ return ctx.json(health);
540
+ });
541
+ ```
542
+
543
+ Audit Log Querying
544
+
545
+ ```javascript
546
+ const auditLogger = api.pluginManager.getPlugin('AuditLogger');
547
+
548
+ const logs = await auditLogger.queryLogs({
549
+ startDate: '2024-01-01',
550
+ endDate: '2024-01-31',
551
+ keypointId: 'specific_key',
552
+ level: 'error',
553
+ limit: 100
554
+ });
555
+ ```
556
+
557
+ # Storage Options
558
+
559
+ Memory Storage (Default)
560
+
561
+ ```javascript
562
+ import { MemoryKeypointStorage } from './keypoint/KeypointStorage.js';
563
+
564
+ const api = new KeypointJS({
565
+ keypointStorage: new MemoryKeypointStorage()
566
+ });
567
+ ```
568
+
569
+ # File Storage
570
+
571
+ ```javascript
572
+ import { FileKeypointStorage } from './keypoint/KeypointStorage.js';
573
+
574
+ const api = new KeypointJS({
575
+ keypointStorage: new FileKeypointStorage('./data/keypoints.json')
576
+ });
577
+ ```
578
+
579
+ # Custom Storage Implementation
580
+
581
+ ```javascript
582
+ export class CustomKeypointStorage extends KeypointStorage {
583
+ constructor(databaseClient) {
584
+ super('custom');
585
+ this.db = databaseClient;
586
+ }
587
+
588
+ async set(keypoint) {
589
+ // Save to database
590
+ await this.db.collection('keypoints').insertOne(keypoint);
591
+ return super.set(keypoint);
592
+ }
593
+
594
+ async get(keyId) {
595
+ // Try memory cache first
596
+ const cached = super.get(keyId);
597
+ if (cached) return cached;
598
+
599
+ // Fallback to database
600
+ const doc = await this.db.collection('keypoints').findOne({ keyId });
601
+ if (doc) {
602
+ super.set(doc);
603
+ return doc;
604
+ }
605
+ return null;
606
+ }
607
+ }
608
+ ```
609
+
610
+ # Testing & Debugging
611
+
612
+ Error Handling
613
+
614
+ ```javascript
615
+ // Global error handler
616
+ api.use(async (ctx, next) => {
617
+ try {
618
+ await next();
619
+ } catch (error) {
620
+ console.error('Request failed:', {
621
+ path: ctx.path,
622
+ method: ctx.method,
623
+ keypointId: ctx.getKeypointId(),
624
+ error: error.message,
625
+ stack: process.env.NODE_ENV === 'development' ? error.stack : undefined
626
+ });
627
+
628
+ return ctx.status(error.code || 500).json({
629
+ error: error.message,
630
+ code: error.code,
631
+ requestId: ctx.id
632
+ });
633
+ }
634
+ });
635
+ ```
636
+
637
+ Debug Middleware
638
+
639
+ ```javascript
640
+ api.use(async (ctx, next) => {
641
+ console.log('Incoming request:', {
642
+ id: ctx.id,
643
+ method: ctx.method,
644
+ path: ctx.path,
645
+ ip: ctx.ip,
646
+ keypointId: ctx.getKeypointId()
647
+ });
648
+
649
+ const start = Date.now();
650
+ await next();
651
+ const duration = Date.now() - start;
652
+
653
+ console.log('Request completed:', {
654
+ id: ctx.id,
655
+ duration: `${duration}ms`,
656
+ status: ctx.response.status
657
+ });
658
+ });
659
+ ```
660
+
661
+ # Production Deployment
662
+
663
+ Docker Configuration
664
+
665
+ ```dockerfile
666
+ FROM node:18-alpine
667
+
668
+ WORKDIR /app
669
+
670
+ COPY package*.json ./
671
+ RUN npm ci --only=production
672
+
673
+ COPY . .
674
+
675
+ # Create non-root user
676
+ RUN addgroup -g 1001 -S nodejs && \
677
+ adduser -S nodejs -u 1001
678
+
679
+ USER nodejs
680
+
681
+ EXPOSE 3000
682
+
683
+ HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
684
+ CMD node -e "require('http').get('http://localhost:3000/health', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"
685
+
686
+ CMD ["node", "server.js"]
687
+ ```
688
+
689
+ # Environment Configuration
690
+
691
+ ```javascript
692
+ const api = new KeypointJS({
693
+ requireKeypoint: process.env.REQUIRE_KEYPOINT !== 'false',
694
+ strictMode: process.env.NODE_ENV === 'production',
695
+ maxRequestSize: process.env.MAX_REQUEST_SIZE || '10mb',
696
+ enableCORS: process.env.ENABLE_CORS === 'true',
697
+ corsOrigins: process.env.CORS_ORIGINS?.split(',') || []
698
+ });
699
+
700
+ // Load keypoints from environment
701
+ if (process.env.KEYPOINTS) {
702
+ const keypoints = JSON.parse(process.env.KEYPOINTS);
703
+ for (const kp of keypoints) {
704
+ await api.createKeypoint(kp);
705
+ }
706
+ }
707
+ ```
708
+
709
+ # Performance Optimization
710
+
711
+ Connection Pooling
712
+
713
+ ```javascript
714
+ // Reuse HTTP agents for better performance
715
+ import http from 'http';
716
+ import https from 'https';
717
+
718
+ const httpAgent = new http.Agent({
719
+ keepAlive: true,
720
+ maxSockets: 100,
721
+ keepAliveMsecs: 1000
722
+ });
723
+
724
+ const httpsAgent = new https.Agent({
725
+ keepAlive: true,
726
+ maxSockets: 100,
727
+ keepAliveMsecs: 1000
728
+ });
729
+
730
+ // Use in outgoing requests
731
+ const response = await fetch(url, {
732
+ agent: url.startsWith('https') ? httpsAgent : httpAgent
733
+ });
734
+ ```
735
+
736
+ Caching Strategy
737
+
738
+ ```javascript
739
+ import NodeCache from 'node-cache';
740
+
741
+ const keypointCache = new NodeCache({
742
+ stdTTL: 300, // 5 minutes
743
+ checkperiod: 60
744
+ });
745
+
746
+ // Cache middleware
747
+ api.use(async (ctx, next) => {
748
+ if (ctx.method === 'GET') {
749
+ const cacheKey = `${ctx.getKeypointId()}:${ctx.path}`;
750
+ const cached = keypointCache.get(cacheKey);
751
+
752
+ if (cached) {
753
+ return ctx.json(cached);
754
+ }
755
+
756
+ await next();
757
+
758
+ if (ctx.response.status === 200) {
759
+ keypointCache.set(cacheKey, ctx.response.body);
760
+ }
761
+ } else {
762
+ await next();
763
+ }
764
+ });
765
+ ```
766
+
767
+ # Security Best Practices
768
+
769
+ - 1. Always use HTTPS in production
770
+ - 2. Rotate keypoint secrets regularly (every 90 days)
771
+ - 3. Implement IP whitelisting for sensitive endpoints
772
+ - 4. Use scope-based authorization instead of role-based
773
+ - 5. Enable audit logging for compliance
774
+ - 6. Set reasonable rate limits per keypoint
775
+ - 7. Validate origins and protocols for each keypoint
776
+ - 8. Monitor failed authentication attempts
777
+ - 9. Clean up expired keypoints regularly
778
+ - 10. Use secure secret storage (not plaintext in code)
779
+
780
+ # Contributing
781
+
782
+ ### To contribute to KeypointJS:
783
+
784
+ - 1. Fork the repository
785
+ - 2. Create a feature branch (git checkout -b feature/amazing-feature)
786
+ - 3. Add tests for your changes
787
+ - 4. Ensure all tests pass (npm test)
788
+ - 5. Commit your changes (git commit -m 'Add amazing feature')
789
+ - 6. Push to the branch (git push origin feature/amazing-feature)
790
+ - 7. Open a Pull Request
791
+
792
+ # License
793
+
794
+ Apache-2.0 license - see the LICENSE file for details.
795
+
796
+ # Support
797
+
798
+ - Documentation: Full API documentation in source code
799
+ - Issues: Report bugs via GitHub issues
800
+ - Contributions: PRs welcome for bug fixes and features
801
+ - Questions: Open a discussion for usage questions
802
+
803
+ ---
804
+
805
+ ## Created Base ♥️ KeypointJS
806
+ ### AnasBex - (⁠づ⁠ ̄⁠ ⁠³⁠ ̄⁠)⁠づ
807
+
808
+ KeypointJS provides a comprehensive, layered approach to API security with extensibility through plugins, real-time capabilities via WebSocket, and detailed monitoring through audit logging. The framework is production-ready with built-in security features and can be extended to meet specific requirements.