xypriss 1.2.4 → 1.3.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.
Files changed (103) hide show
  1. package/README.md +51 -3
  2. package/dist/cjs/mods/security/src/components/cache/index.js +1 -1
  3. package/dist/cjs/shared/logger/Logger.js +1 -0
  4. package/dist/cjs/shared/logger/Logger.js.map +1 -1
  5. package/dist/cjs/src/cluster/bun-cluster-manager.js +1567 -0
  6. package/dist/cjs/src/cluster/bun-cluster-manager.js.map +1 -0
  7. package/dist/cjs/src/cluster/cluster-manager.js +1 -1
  8. package/dist/cjs/src/cluster/cluster-manager.js.map +1 -1
  9. package/dist/cjs/src/cluster/index.js +25 -6
  10. package/dist/cjs/src/cluster/index.js.map +1 -1
  11. package/dist/cjs/src/cluster/memory-manager.js +463 -0
  12. package/dist/cjs/src/cluster/memory-manager.js.map +1 -0
  13. package/dist/cjs/src/cluster/modules/BunIPCManager.js +603 -0
  14. package/dist/cjs/src/cluster/modules/BunIPCManager.js.map +1 -0
  15. package/dist/cjs/src/cluster/modules/ClusterFactory.js +22 -1
  16. package/dist/cjs/src/cluster/modules/ClusterFactory.js.map +1 -1
  17. package/dist/cjs/src/cluster/modules/CpuMonitor.js +658 -0
  18. package/dist/cjs/src/cluster/modules/CpuMonitor.js.map +1 -0
  19. package/dist/cjs/src/cluster/modules/ProcessMonitor.js +513 -0
  20. package/dist/cjs/src/cluster/modules/ProcessMonitor.js.map +1 -0
  21. package/dist/cjs/src/plugins/server-maintenance-plugin.js +1 -1
  22. package/dist/cjs/src/server/FastServer.js +64 -43
  23. package/dist/cjs/src/server/FastServer.js.map +1 -1
  24. package/dist/cjs/src/server/components/fastapi/ClusterManagerComponent.js +226 -10
  25. package/dist/cjs/src/server/components/fastapi/ClusterManagerComponent.js.map +1 -1
  26. package/dist/cjs/src/server/const/Cluster.config.js +174 -31
  27. package/dist/cjs/src/server/const/Cluster.config.js.map +1 -1
  28. package/dist/cjs/src/server/const/default.js +11 -2
  29. package/dist/cjs/src/server/const/default.js.map +1 -1
  30. package/dist/cjs/src/server/utils/PortManager.js +26 -15
  31. package/dist/cjs/src/server/utils/PortManager.js.map +1 -1
  32. package/dist/esm/mods/security/src/components/cache/index.js +1 -1
  33. package/dist/esm/shared/logger/Logger.js +1 -0
  34. package/dist/esm/shared/logger/Logger.js.map +1 -1
  35. package/dist/esm/src/cluster/bun-cluster-manager.js +1565 -0
  36. package/dist/esm/src/cluster/bun-cluster-manager.js.map +1 -0
  37. package/dist/esm/src/cluster/cluster-manager.js +1 -1
  38. package/dist/esm/src/cluster/cluster-manager.js.map +1 -1
  39. package/dist/esm/src/cluster/index.js +25 -6
  40. package/dist/esm/src/cluster/index.js.map +1 -1
  41. package/dist/esm/src/cluster/memory-manager.js +461 -0
  42. package/dist/esm/src/cluster/memory-manager.js.map +1 -0
  43. package/dist/esm/src/cluster/modules/BunIPCManager.js +601 -0
  44. package/dist/esm/src/cluster/modules/BunIPCManager.js.map +1 -0
  45. package/dist/esm/src/cluster/modules/ClusterFactory.js +22 -1
  46. package/dist/esm/src/cluster/modules/ClusterFactory.js.map +1 -1
  47. package/dist/esm/src/cluster/modules/CpuMonitor.js +656 -0
  48. package/dist/esm/src/cluster/modules/CpuMonitor.js.map +1 -0
  49. package/dist/esm/src/cluster/modules/ProcessMonitor.js +511 -0
  50. package/dist/esm/src/cluster/modules/ProcessMonitor.js.map +1 -0
  51. package/dist/esm/src/plugins/server-maintenance-plugin.js +1 -1
  52. package/dist/esm/src/server/FastServer.js +64 -43
  53. package/dist/esm/src/server/FastServer.js.map +1 -1
  54. package/dist/esm/src/server/components/fastapi/ClusterManagerComponent.js +226 -10
  55. package/dist/esm/src/server/components/fastapi/ClusterManagerComponent.js.map +1 -1
  56. package/dist/esm/src/server/const/Cluster.config.js +174 -31
  57. package/dist/esm/src/server/const/Cluster.config.js.map +1 -1
  58. package/dist/esm/src/server/const/default.js +11 -2
  59. package/dist/esm/src/server/const/default.js.map +1 -1
  60. package/dist/esm/src/server/utils/PortManager.js +26 -15
  61. package/dist/esm/src/server/utils/PortManager.js.map +1 -1
  62. package/dist/index.d.ts +78 -1
  63. package/package.json +3 -1
  64. package/dist/cjs/src/plugins/modules/network/index.js +0 -120
  65. package/dist/cjs/src/plugins/modules/network/index.js.map +0 -1
  66. package/dist/cjs/src/server/plugins/PluginEngine.js +0 -378
  67. package/dist/cjs/src/server/plugins/PluginEngine.js.map +0 -1
  68. package/dist/cjs/src/server/plugins/PluginRegistry.js +0 -339
  69. package/dist/cjs/src/server/plugins/PluginRegistry.js.map +0 -1
  70. package/dist/cjs/src/server/plugins/builtin/JWTAuthPlugin.js +0 -591
  71. package/dist/cjs/src/server/plugins/builtin/JWTAuthPlugin.js.map +0 -1
  72. package/dist/cjs/src/server/plugins/builtin/ResponseTimePlugin.js +0 -413
  73. package/dist/cjs/src/server/plugins/builtin/ResponseTimePlugin.js.map +0 -1
  74. package/dist/cjs/src/server/plugins/builtin/SmartCachePlugin.js +0 -843
  75. package/dist/cjs/src/server/plugins/builtin/SmartCachePlugin.js.map +0 -1
  76. package/dist/cjs/src/server/plugins/core/CachePlugin.js +0 -1975
  77. package/dist/cjs/src/server/plugins/core/CachePlugin.js.map +0 -1
  78. package/dist/cjs/src/server/plugins/core/PerformancePlugin.js +0 -894
  79. package/dist/cjs/src/server/plugins/core/PerformancePlugin.js.map +0 -1
  80. package/dist/cjs/src/server/plugins/core/SecurityPlugin.js +0 -799
  81. package/dist/cjs/src/server/plugins/core/SecurityPlugin.js.map +0 -1
  82. package/dist/cjs/src/server/plugins/types/PluginTypes.js +0 -47
  83. package/dist/cjs/src/server/plugins/types/PluginTypes.js.map +0 -1
  84. package/dist/esm/src/plugins/modules/network/index.js +0 -109
  85. package/dist/esm/src/plugins/modules/network/index.js.map +0 -1
  86. package/dist/esm/src/server/plugins/PluginEngine.js +0 -376
  87. package/dist/esm/src/server/plugins/PluginEngine.js.map +0 -1
  88. package/dist/esm/src/server/plugins/PluginRegistry.js +0 -337
  89. package/dist/esm/src/server/plugins/PluginRegistry.js.map +0 -1
  90. package/dist/esm/src/server/plugins/builtin/JWTAuthPlugin.js +0 -589
  91. package/dist/esm/src/server/plugins/builtin/JWTAuthPlugin.js.map +0 -1
  92. package/dist/esm/src/server/plugins/builtin/ResponseTimePlugin.js +0 -411
  93. package/dist/esm/src/server/plugins/builtin/ResponseTimePlugin.js.map +0 -1
  94. package/dist/esm/src/server/plugins/builtin/SmartCachePlugin.js +0 -841
  95. package/dist/esm/src/server/plugins/builtin/SmartCachePlugin.js.map +0 -1
  96. package/dist/esm/src/server/plugins/core/CachePlugin.js +0 -1973
  97. package/dist/esm/src/server/plugins/core/CachePlugin.js.map +0 -1
  98. package/dist/esm/src/server/plugins/core/PerformancePlugin.js +0 -872
  99. package/dist/esm/src/server/plugins/core/PerformancePlugin.js.map +0 -1
  100. package/dist/esm/src/server/plugins/core/SecurityPlugin.js +0 -797
  101. package/dist/esm/src/server/plugins/core/SecurityPlugin.js.map +0 -1
  102. package/dist/esm/src/server/plugins/types/PluginTypes.js +0 -47
  103. package/dist/esm/src/server/plugins/types/PluginTypes.js.map +0 -1
@@ -1,841 +0,0 @@
1
- import { CachePlugin } from '../core/CachePlugin.js';
2
- import { PluginPriority } from '../types/PluginTypes.js';
3
-
4
- /**
5
- * Smart Cache Plugin
6
- *
7
- * Intelligent caching plugin with <0.5ms execution overhead
8
- * leveraging XyPrissJS cache systems for optimal performance.
9
- */
10
- /**
11
- * Smart Cache Plugin for intelligent request caching
12
- */
13
- class SmartCachePlugin extends CachePlugin {
14
- constructor() {
15
- super(...arguments);
16
- this.id = "nehonix.ftfy.cache";
17
- this.name = "Smart Cache Plugin";
18
- this.version = "1.0.0";
19
- this.priority = PluginPriority.HIGH;
20
- // Cache configuration
21
- this.cacheStrategy = "hybrid";
22
- this.compressionEnabled = true;
23
- this.encryptionEnabled = true; // Keep encryption for security
24
- // Smart caching rules
25
- this.cachingRules = new Map();
26
- // Cache analytics
27
- this.cacheAnalytics = {
28
- totalRequests: 0,
29
- cacheableRequests: 0,
30
- cacheHits: 0,
31
- cacheMisses: 0,
32
- cacheSkips: 0,
33
- averageHitTime: 0,
34
- averageMissTime: 0,
35
- compressionSavings: 0,
36
- };
37
- // Dynamic TTL adjustment based on request patterns
38
- this.requestPatterns = new Map();
39
- // Background prefetching queue and worker
40
- this.prefetchQueue = [];
41
- this.prefetchWorkerActive = false;
42
- this.prefetchStats = {
43
- totalPrefetched: 0,
44
- successfulPrefetches: 0,
45
- failedPrefetches: 0,
46
- averagePrefetchTime: 0,
47
- };
48
- }
49
- /**
50
- * Initialize smart cache plugin
51
- */
52
- async initializeCachePlugin(context) {
53
- // Setup default caching rules
54
- this.setupDefaultCachingRules();
55
- // Configure custom rules from settings
56
- if (context.config.customSettings.cachingRules) {
57
- this.configureCachingRules(context.config.customSettings.cachingRules);
58
- }
59
- // Setup cache analytics cleanup
60
- this.setupAnalyticsCleanup();
61
- // Setup dynamic TTL adjustment
62
- this.setupDynamicTTLAdjustment();
63
- context.logger.info("Smart Cache Plugin initialized with intelligent caching rules");
64
- }
65
- /**
66
- * Check if request should be cached (plugin-specific logic)
67
- */
68
- shouldCacheRequest(context) {
69
- const { req } = context;
70
- // Apply smart caching rules
71
- for (const [ruleName, rule] of this.cachingRules.entries()) {
72
- if (rule.enabled && rule.pattern.test(req.path)) {
73
- // Check additional conditions
74
- if (this.shouldApplyRule(context, rule)) {
75
- return true;
76
- }
77
- }
78
- }
79
- // Fallback to intelligent heuristics
80
- return this.applyIntelligentCaching(context);
81
- }
82
- /**
83
- * Get custom cache key components
84
- */
85
- getCustomKeyComponents(context) {
86
- const { req } = context;
87
- const components = [];
88
- // Add user-specific components for personalized content
89
- if (context.security.isAuthenticated) {
90
- components.push(`user:${context.security.userId}`);
91
- // Add role-based caching
92
- if (context.security.roles.length > 0) {
93
- components.push(`roles:${context.security.roles.sort().join(",")}`);
94
- }
95
- }
96
- // Add device type for responsive caching
97
- const userAgent = req.headers["user-agent"];
98
- if (userAgent) {
99
- const deviceType = this.detectDeviceType(userAgent);
100
- components.push(`device:${deviceType}`);
101
- }
102
- // Add language for i18n caching
103
- const acceptLanguage = req.headers["accept-language"];
104
- if (acceptLanguage) {
105
- const primaryLanguage = acceptLanguage.split(",")[0].split("-")[0];
106
- components.push(`lang:${primaryLanguage}`);
107
- }
108
- // Add API version for versioned APIs
109
- const apiVersion = req.headers["api-version"] || req.query.version;
110
- if (apiVersion) {
111
- components.push(`version:${apiVersion}`);
112
- }
113
- return components;
114
- }
115
- /**
116
- * Get custom TTL for request
117
- */
118
- getCustomTTL(context) {
119
- const { req } = context;
120
- const route = this.normalizeRoute(req.path);
121
- // Check if we have pattern data for dynamic TTL
122
- const pattern = this.requestPatterns.get(route);
123
- if (pattern) {
124
- return this.calculateDynamicTTL(pattern);
125
- }
126
- // Apply rule-based TTL
127
- for (const [ruleName, rule] of this.cachingRules.entries()) {
128
- if (rule.enabled && rule.pattern.test(req.path)) {
129
- return rule.ttl;
130
- }
131
- }
132
- // Default TTL based on content type
133
- return this.getDefaultTTLByContentType(req.path);
134
- }
135
- /**
136
- * Handle custom cache operations
137
- */
138
- async handleCustomCacheOperation(context, operation) {
139
- switch (operation) {
140
- case "analyze":
141
- return await this.analyzeCachePerformance(context);
142
- case "optimize":
143
- return await this.optimizeCacheStrategy(context);
144
- case "prefetch":
145
- return await this.prefetchRelatedContent(context);
146
- default:
147
- return { operation, supported: false };
148
- }
149
- }
150
- /**
151
- * Precompile cache operations
152
- */
153
- async precompileCacheOperations() {
154
- // Pre-warm route normalization
155
- this.normalizeRoute("/api/users/123");
156
- // Pre-warm device detection
157
- this.detectDeviceType("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
158
- // Pre-warm TTL calculation
159
- this.calculateDynamicTTL({
160
- frequency: 10,
161
- lastAccess: Date.now(),
162
- averageResponseTime: 100,
163
- volatility: 0.1,
164
- });
165
- }
166
- // ===== SMART CACHING LOGIC =====
167
- /**
168
- * Setup default caching rules
169
- */
170
- setupDefaultCachingRules() {
171
- // Static assets - long TTL
172
- this.cachingRules.set("static", {
173
- pattern: /\.(css|js|png|jpg|jpeg|gif|svg|ico|woff|woff2|ttf|eot)$/,
174
- ttl: 86400000, // 24 hours
175
- enabled: true,
176
- compression: true,
177
- tags: ["static"],
178
- });
179
- // API responses - medium TTL
180
- this.cachingRules.set("api", {
181
- pattern: /^\/api\/(?!auth|admin)/,
182
- ttl: 300000, // 5 minutes
183
- enabled: true,
184
- compression: true,
185
- tags: ["api"],
186
- });
187
- // Public pages - short TTL
188
- this.cachingRules.set("public", {
189
- pattern: /^\/(?!admin|dashboard|profile)/,
190
- ttl: 60000, // 1 minute
191
- enabled: true,
192
- compression: true,
193
- tags: ["public"],
194
- });
195
- // User-specific content - very short TTL
196
- this.cachingRules.set("user", {
197
- pattern: /^\/(profile|dashboard|settings)/,
198
- ttl: 30000, // 30 seconds
199
- enabled: true,
200
- compression: false,
201
- tags: ["user"],
202
- });
203
- }
204
- /**
205
- * Configure custom caching rules
206
- */
207
- configureCachingRules(rules) {
208
- for (const rule of rules) {
209
- this.cachingRules.set(rule.name, {
210
- pattern: new RegExp(rule.pattern),
211
- ttl: rule.ttl || 300000,
212
- enabled: rule.enabled !== false,
213
- compression: rule.compression !== false,
214
- tags: rule.tags || [],
215
- });
216
- }
217
- }
218
- /**
219
- * Check if caching rule should be applied
220
- */
221
- shouldApplyRule(context, rule) {
222
- const { req } = context;
223
- // Don't cache authenticated requests for public rules
224
- if (rule.tags.includes("public") && context.security.isAuthenticated) {
225
- return false;
226
- }
227
- // Don't cache if request has cache-control: no-cache
228
- const cacheControl = req.headers["cache-control"];
229
- if (cacheControl && cacheControl.includes("no-cache")) {
230
- return false;
231
- }
232
- // Don't cache if request has pragma: no-cache
233
- const pragma = req.headers.pragma;
234
- if (pragma && pragma.includes("no-cache")) {
235
- return false;
236
- }
237
- return true;
238
- }
239
- /**
240
- * Apply intelligent caching heuristics
241
- */
242
- applyIntelligentCaching(context) {
243
- const { req } = context;
244
- // Analyze request characteristics
245
- const hasQueryParams = Object.keys(req.query).length > 0;
246
- const hasBody = req.body && Object.keys(req.body).length > 0;
247
- const isIdempotent = ["GET", "HEAD", "OPTIONS"].includes(req.method);
248
- // Don't cache non-idempotent requests
249
- if (!isIdempotent) {
250
- return false;
251
- }
252
- // Don't cache requests with complex query parameters
253
- if (hasQueryParams && this.hasComplexQueryParams(req.query)) {
254
- return false;
255
- }
256
- // Cache simple GET requests
257
- if (req.method === "GET" && !hasBody) {
258
- return true;
259
- }
260
- return false;
261
- }
262
- /**
263
- * Calculate dynamic TTL based on request patterns
264
- */
265
- calculateDynamicTTL(pattern) {
266
- const baseTime = 300000; // 5 minutes base
267
- // Adjust based on frequency (more frequent = longer cache)
268
- const frequencyMultiplier = Math.min(pattern.frequency / 10, 2);
269
- // Adjust based on volatility (more volatile = shorter cache)
270
- const volatilityMultiplier = Math.max(1 - pattern.volatility, 0.1);
271
- // Adjust based on response time (slower = longer cache)
272
- const responseTimeMultiplier = Math.min(pattern.averageResponseTime / 100, 3);
273
- return Math.round(baseTime *
274
- frequencyMultiplier *
275
- volatilityMultiplier *
276
- responseTimeMultiplier);
277
- }
278
- /**
279
- * Get default TTL by content type
280
- */
281
- getDefaultTTLByContentType(path) {
282
- if (path.match(/\.(css|js)$/)) {
283
- return 3600000; // 1 hour for CSS/JS
284
- }
285
- if (path.match(/\.(png|jpg|jpeg|gif|svg|ico)$/)) {
286
- return 86400000; // 24 hours for images
287
- }
288
- if (path.startsWith("/api/")) {
289
- return 300000; // 5 minutes for API
290
- }
291
- return 60000; // 1 minute default
292
- }
293
- // ===== ANALYTICS AND OPTIMIZATION =====
294
- /**
295
- * Analyze cache performance
296
- */
297
- async analyzeCachePerformance(context) {
298
- const hitRate = this.cacheAnalytics.totalRequests > 0
299
- ? (this.cacheAnalytics.cacheHits /
300
- this.cacheAnalytics.totalRequests) *
301
- 100
302
- : 0;
303
- const cacheableRate = this.cacheAnalytics.totalRequests > 0
304
- ? (this.cacheAnalytics.cacheableRequests /
305
- this.cacheAnalytics.totalRequests) *
306
- 100
307
- : 0;
308
- return {
309
- hitRate: Math.round(hitRate * 100) / 100,
310
- cacheableRate: Math.round(cacheableRate * 100) / 100,
311
- totalRequests: this.cacheAnalytics.totalRequests,
312
- cacheHits: this.cacheAnalytics.cacheHits,
313
- cacheMisses: this.cacheAnalytics.cacheMisses,
314
- averageHitTime: this.cacheAnalytics.averageHitTime,
315
- averageMissTime: this.cacheAnalytics.averageMissTime,
316
- compressionSavings: this.cacheAnalytics.compressionSavings,
317
- topPatterns: this.getTopRequestPatterns(),
318
- };
319
- }
320
- /**
321
- * Optimize cache strategy
322
- */
323
- async optimizeCacheStrategy(context) {
324
- const optimizations = [];
325
- // Analyze hit rates by rule
326
- for (const [ruleName, rule] of this.cachingRules.entries()) {
327
- // Suggest optimizations based on performance
328
- if (rule.enabled) {
329
- optimizations.push(`Rule '${ruleName}' is active`);
330
- }
331
- }
332
- // Suggest TTL adjustments
333
- const ttlSuggestions = this.suggestTTLOptimizations();
334
- optimizations.push(...ttlSuggestions);
335
- return {
336
- optimizations,
337
- suggestions: this.generateSmartOptimizationSuggestions(),
338
- };
339
- }
340
- /**
341
- * Prefetch related content
342
- */
343
- async prefetchRelatedContent(context) {
344
- const { req } = context;
345
- const relatedUrls = this.identifyRelatedContent(req.path);
346
- // Queue related URLs for background prefetching
347
- const queuedUrls = [];
348
- for (const url of relatedUrls) {
349
- const priority = this.calculatePrefetchPriority(url, context);
350
- // Only queue high-priority URLs to avoid overwhelming the system
351
- if (priority > 0.5) {
352
- this.queueForPrefetch(url, priority, context);
353
- queuedUrls.push(url);
354
- }
355
- }
356
- // Start background prefetch worker if not already active
357
- if (!this.prefetchWorkerActive && this.prefetchQueue.length > 0) {
358
- this.startPrefetchWorker();
359
- }
360
- return {
361
- prefetched: queuedUrls.length,
362
- urls: queuedUrls,
363
- queueSize: this.prefetchQueue.length,
364
- };
365
- }
366
- /**
367
- * Queue a URL for background prefetching
368
- */
369
- queueForPrefetch(url, priority, context) {
370
- // Avoid duplicate entries
371
- const existingIndex = this.prefetchQueue.findIndex((item) => item.url === url);
372
- if (existingIndex >= 0) {
373
- // Update priority if higher
374
- if (this.prefetchQueue[existingIndex].priority < priority) {
375
- this.prefetchQueue[existingIndex].priority = priority;
376
- this.prefetchQueue[existingIndex].timestamp = Date.now();
377
- }
378
- return;
379
- }
380
- // Add to queue
381
- this.prefetchQueue.push({
382
- url,
383
- priority,
384
- timestamp: Date.now(),
385
- context: {
386
- method: context.req.method,
387
- headers: context.req.headers,
388
- baseUrl: `${context.req.protocol}://${context.req.get("host")}`,
389
- },
390
- });
391
- // Sort by priority (highest first)
392
- this.prefetchQueue.sort((a, b) => b.priority - a.priority);
393
- // Limit queue size to prevent memory issues
394
- if (this.prefetchQueue.length > 100) {
395
- this.prefetchQueue = this.prefetchQueue.slice(0, 100);
396
- }
397
- }
398
- /**
399
- * Calculate prefetch priority for a URL
400
- */
401
- calculatePrefetchPriority(url, context) {
402
- let priority = 0.3; // Base priority
403
- // Check request patterns
404
- const pattern = this.requestPatterns.get(url);
405
- if (pattern) {
406
- // Higher frequency = higher priority
407
- priority += Math.min(pattern.frequency / 100, 0.4);
408
- // Recent access = higher priority
409
- const timeSinceAccess = Date.now() - pattern.lastAccess;
410
- if (timeSinceAccess < 300000) {
411
- // 5 minutes
412
- priority += 0.2;
413
- }
414
- // Lower volatility = higher priority (more stable content)
415
- priority += (1 - pattern.volatility) * 0.1;
416
- }
417
- // Check if URL matches high-priority patterns
418
- if (url.includes("/api/") || url.includes("/static/")) {
419
- priority += 0.2;
420
- }
421
- // Check if it's a common resource type
422
- if (url.match(/\.(css|js|png|jpg|jpeg|gif|svg|woff|woff2)$/)) {
423
- priority += 0.3;
424
- }
425
- return Math.min(priority, 1.0);
426
- }
427
- /**
428
- * Start the background prefetch worker
429
- */
430
- async startPrefetchWorker() {
431
- if (this.prefetchWorkerActive)
432
- return;
433
- this.prefetchWorkerActive = true;
434
- try {
435
- while (this.prefetchQueue.length > 0) {
436
- const item = this.prefetchQueue.shift();
437
- if (!item)
438
- break;
439
- // Skip items that are too old (older than 5 minutes)
440
- if (Date.now() - item.timestamp > 300000) {
441
- continue;
442
- }
443
- await this.performPrefetch(item);
444
- // Small delay to prevent overwhelming the server
445
- await new Promise((resolve) => setTimeout(resolve, 10));
446
- }
447
- }
448
- catch (error) {
449
- console.error("Prefetch worker error:", error);
450
- }
451
- finally {
452
- this.prefetchWorkerActive = false;
453
- }
454
- }
455
- /**
456
- * Perform actual prefetch operation
457
- */
458
- async performPrefetch(item) {
459
- const startTime = Date.now();
460
- try {
461
- // Perform actual HTTP request for prefetching to warm up the cache
462
- const response = await this.performActualPrefetchRequest(item.url, item.context);
463
- if (response.success) {
464
- this.prefetchStats.successfulPrefetches++;
465
- // Update request patterns
466
- this.updateRequestPattern(item.url, Date.now() - startTime);
467
- }
468
- else {
469
- this.prefetchStats.failedPrefetches++;
470
- }
471
- this.prefetchStats.totalPrefetched++;
472
- // Update average prefetch time
473
- const prefetchTime = Date.now() - startTime;
474
- this.prefetchStats.averagePrefetchTime =
475
- (this.prefetchStats.averagePrefetchTime *
476
- (this.prefetchStats.totalPrefetched - 1) +
477
- prefetchTime) /
478
- this.prefetchStats.totalPrefetched;
479
- }
480
- catch (error) {
481
- this.prefetchStats.failedPrefetches++;
482
- this.prefetchStats.totalPrefetched++;
483
- console.error(`Prefetch failed for ${item.url}:`, error);
484
- }
485
- }
486
- /**
487
- * Perform actual prefetch request with real HTTP call
488
- */
489
- async performActualPrefetchRequest(url, context) {
490
- try {
491
- // Construct full URL if relative
492
- let fullUrl = url;
493
- if (context?.baseUrl && !url.startsWith("http")) {
494
- fullUrl = `${context.baseUrl}${url.startsWith("/") ? url : "/" + url}`;
495
- }
496
- // Prepare request options
497
- const requestOptions = {
498
- method: context?.method || "GET",
499
- headers: {
500
- "User-Agent": "XyPrissJS-SmartCache/1.0",
501
- Accept: "*/*",
502
- "Cache-Control": "no-cache", // Force fresh fetch for prefetching
503
- ...this.getFilteredHeaders(context?.headers),
504
- },
505
- timeout: 5000, // 5 second timeout for prefetch requests
506
- redirect: "follow",
507
- maxRedirects: 3,
508
- };
509
- // Use Node.js built-in fetch if available (Node 18+), otherwise use a fallback
510
- let response;
511
- let responseData;
512
- if (typeof fetch !== "undefined") {
513
- // Use native fetch
514
- response = await fetch(fullUrl, requestOptions);
515
- if (response.ok) {
516
- // Try to get response data based on content type
517
- const contentType = response.headers.get("content-type") || "";
518
- if (contentType.includes("application/json")) {
519
- responseData = await response.json();
520
- }
521
- else if (contentType.includes("text/")) {
522
- responseData = await response.text();
523
- }
524
- else {
525
- // For binary data, just get the size
526
- const buffer = await response.arrayBuffer();
527
- responseData = {
528
- size: buffer.byteLength,
529
- type: "binary",
530
- };
531
- }
532
- }
533
- else {
534
- throw new Error(`HTTP ${response.status}: ${response.statusText}`);
535
- }
536
- }
537
- else {
538
- // Fallback using Node.js http/https modules
539
- response = await this.makeHttpRequest(fullUrl, requestOptions);
540
- responseData = response.data;
541
- }
542
- // Cache the prefetched content
543
- await this.cachePrefetchedContent(url, responseData, response);
544
- return {
545
- success: true,
546
- data: responseData,
547
- statusCode: response.status || response.statusCode,
548
- headers: response.headers,
549
- };
550
- }
551
- catch (error) {
552
- console.warn(`Prefetch failed for ${url}:`, error);
553
- return {
554
- success: false,
555
- error: error instanceof Error ? error.message : "Unknown error",
556
- };
557
- }
558
- }
559
- /**
560
- * Filter headers to only include safe ones for prefetching
561
- */
562
- getFilteredHeaders(headers) {
563
- if (!headers)
564
- return {};
565
- const safeHeaders = {};
566
- const allowedHeaders = [
567
- "accept",
568
- "accept-language",
569
- "accept-encoding",
570
- "user-agent",
571
- ];
572
- for (const [key, value] of Object.entries(headers)) {
573
- if (allowedHeaders.includes(key.toLowerCase()) &&
574
- typeof value === "string") {
575
- safeHeaders[key] = value;
576
- }
577
- }
578
- return safeHeaders;
579
- }
580
- /**
581
- * Make HTTP request using Node.js built-in modules
582
- */
583
- async makeHttpRequest(url, options) {
584
- return new Promise((resolve, reject) => {
585
- const urlObj = new URL(url);
586
- const isHttps = urlObj.protocol === "https:";
587
- // Dynamically import http/https modules
588
- const httpModule = isHttps ? require("https") : require("http");
589
- const requestOptions = {
590
- hostname: urlObj.hostname,
591
- port: urlObj.port || (isHttps ? 443 : 80),
592
- path: urlObj.pathname + urlObj.search,
593
- method: options.method || "GET",
594
- headers: options.headers || {},
595
- timeout: options.timeout || 5000,
596
- };
597
- const req = httpModule.request(requestOptions, (res) => {
598
- let data = "";
599
- res.on("data", (chunk) => {
600
- data += chunk;
601
- });
602
- res.on("end", () => {
603
- resolve({
604
- statusCode: res.statusCode,
605
- headers: res.headers,
606
- data: data,
607
- });
608
- });
609
- });
610
- req.on("error", (error) => {
611
- reject(error);
612
- });
613
- req.on("timeout", () => {
614
- req.destroy();
615
- reject(new Error("Request timeout"));
616
- });
617
- req.end();
618
- });
619
- }
620
- /**
621
- * Cache the prefetched content
622
- */
623
- async cachePrefetchedContent(url, data, response) {
624
- try {
625
- // Generate cache key for the prefetched content
626
- const cacheKey = this.generatePrefetchCacheKey(url);
627
- // Determine TTL based on response headers
628
- const ttl = this.calculatePrefetchTTL(response);
629
- // Store in cache with appropriate metadata
630
- const cacheEntry = {
631
- url,
632
- data,
633
- timestamp: Date.now(),
634
- statusCode: response.status || response.statusCode,
635
- headers: response.headers,
636
- prefetched: true,
637
- };
638
- // Use the plugin's cache if available
639
- if (this.cache) {
640
- await this.cache.set(cacheKey, cacheEntry, { ttl });
641
- }
642
- }
643
- catch (error) {
644
- console.warn(`Failed to cache prefetched content for ${url}:`, error);
645
- }
646
- }
647
- /**
648
- * Generate cache key for prefetched content
649
- */
650
- generatePrefetchCacheKey(url) {
651
- return `prefetch:${url}`;
652
- }
653
- /**
654
- * Calculate TTL for prefetched content based on response headers
655
- */
656
- calculatePrefetchTTL(response) {
657
- const headers = response.headers || {};
658
- // Check Cache-Control header
659
- const cacheControl = headers["cache-control"] || headers.get?.("cache-control");
660
- if (cacheControl) {
661
- const maxAgeMatch = cacheControl.match(/max-age=(\d+)/);
662
- if (maxAgeMatch) {
663
- return parseInt(maxAgeMatch[1]) * 1000; // Convert to milliseconds
664
- }
665
- }
666
- // Check Expires header
667
- const expires = headers["expires"] || headers.get?.("expires");
668
- if (expires) {
669
- const expiresDate = new Date(expires);
670
- const now = new Date();
671
- if (expiresDate > now) {
672
- return expiresDate.getTime() - now.getTime();
673
- }
674
- }
675
- // Default TTL for prefetched content (5 minutes)
676
- return 300000;
677
- }
678
- /**
679
- * Update request pattern data
680
- */
681
- updateRequestPattern(url, responseTime) {
682
- const pattern = this.requestPatterns.get(url) || {
683
- frequency: 0,
684
- lastAccess: 0,
685
- averageResponseTime: 0,
686
- volatility: 0.5,
687
- };
688
- pattern.frequency++;
689
- pattern.lastAccess = Date.now();
690
- pattern.averageResponseTime =
691
- (pattern.averageResponseTime * (pattern.frequency - 1) +
692
- responseTime) /
693
- pattern.frequency;
694
- this.requestPatterns.set(url, pattern);
695
- }
696
- // ===== UTILITY METHODS =====
697
- /**
698
- * Normalize route for pattern tracking
699
- */
700
- normalizeRoute(path) {
701
- return path
702
- .replace(/\/\d+/g, "/:id")
703
- .replace(/\/[a-f0-9-]{36}/g, "/:uuid")
704
- .replace(/\?.*$/, "");
705
- }
706
- /**
707
- * Detect device type from user agent
708
- */
709
- detectDeviceType(userAgent) {
710
- if (/Mobile|Android|iPhone|iPad/.test(userAgent)) {
711
- return "mobile";
712
- }
713
- if (/Tablet|iPad/.test(userAgent)) {
714
- return "tablet";
715
- }
716
- return "desktop";
717
- }
718
- /**
719
- * Check for complex query parameters
720
- */
721
- hasComplexQueryParams(query) {
722
- const complexParams = [
723
- "search",
724
- "filter",
725
- "sort",
726
- "timestamp",
727
- "random",
728
- ];
729
- return complexParams.some((param) => param in query);
730
- }
731
- /**
732
- * Get top request patterns
733
- */
734
- getTopRequestPatterns() {
735
- const patterns = Array.from(this.requestPatterns.entries())
736
- .sort((a, b) => b[1].frequency - a[1].frequency)
737
- .slice(0, 10);
738
- return patterns.map(([route, data]) => ({
739
- route,
740
- frequency: data.frequency,
741
- averageResponseTime: data.averageResponseTime,
742
- volatility: data.volatility,
743
- }));
744
- }
745
- /**
746
- * Suggest TTL optimizations
747
- */
748
- suggestTTLOptimizations() {
749
- const suggestions = [];
750
- for (const [route, pattern] of this.requestPatterns.entries()) {
751
- if (pattern.frequency > 50 && pattern.volatility < 0.1) {
752
- suggestions.push(`Increase TTL for high-frequency, stable route: ${route}`);
753
- }
754
- if (pattern.volatility > 0.8) {
755
- suggestions.push(`Decrease TTL for volatile route: ${route}`);
756
- }
757
- }
758
- return suggestions;
759
- }
760
- /**
761
- * Generate optimization suggestions
762
- */
763
- generateSmartOptimizationSuggestions() {
764
- const suggestions = [];
765
- const hitRate = this.cacheAnalytics.totalRequests > 0
766
- ? (this.cacheAnalytics.cacheHits /
767
- this.cacheAnalytics.totalRequests) *
768
- 100
769
- : 0;
770
- if (hitRate < 30) {
771
- suggestions.push("Consider increasing TTL values to improve hit rate");
772
- }
773
- if (hitRate > 90) {
774
- suggestions.push("Excellent cache performance - consider expanding caching rules");
775
- }
776
- if (this.cacheAnalytics.averageMissTime >
777
- this.cacheAnalytics.averageHitTime * 10) {
778
- suggestions.push("High miss penalty - consider cache warming strategies");
779
- }
780
- return suggestions;
781
- }
782
- /**
783
- * Identify related content for prefetching
784
- */
785
- identifyRelatedContent(path) {
786
- const related = [];
787
- // Simple related content identification
788
- if (path.startsWith("/api/users/")) {
789
- related.push("/api/users/profile", "/api/users/preferences");
790
- }
791
- if (path.startsWith("/api/products/")) {
792
- related.push("/api/products/categories", "/api/products/featured");
793
- }
794
- return related;
795
- }
796
- /**
797
- * Setup analytics cleanup
798
- */
799
- setupAnalyticsCleanup() {
800
- // Reset analytics every hour
801
- setInterval(() => {
802
- this.resetAnalytics();
803
- }, 3600000); // 1 hour
804
- }
805
- /**
806
- * Setup dynamic TTL adjustment
807
- */
808
- setupDynamicTTLAdjustment() {
809
- // Analyze patterns every 10 minutes
810
- setInterval(() => {
811
- this.analyzeRequestPatterns();
812
- }, 600000); // 10 minutes
813
- }
814
- /**
815
- * Reset analytics
816
- */
817
- resetAnalytics() {
818
- // Keep some historical data, reset counters
819
- this.cacheAnalytics.totalRequests = 0;
820
- this.cacheAnalytics.cacheableRequests = 0;
821
- this.cacheAnalytics.cacheHits = 0;
822
- this.cacheAnalytics.cacheMisses = 0;
823
- this.cacheAnalytics.cacheSkips = 0;
824
- }
825
- /**
826
- * Analyze request patterns for optimization
827
- */
828
- analyzeRequestPatterns() {
829
- const now = Date.now();
830
- // Clean up old patterns
831
- for (const [route, pattern] of this.requestPatterns.entries()) {
832
- if (now - pattern.lastAccess > 3600000) {
833
- // 1 hour
834
- this.requestPatterns.delete(route);
835
- }
836
- }
837
- }
838
- }
839
-
840
- export { SmartCachePlugin };
841
- //# sourceMappingURL=SmartCachePlugin.js.map