xypriss 1.1.4 → 1.2.1

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 (106) hide show
  1. package/dist/cjs/src/index.js +56 -0
  2. package/dist/cjs/src/index.js.map +1 -1
  3. package/dist/cjs/src/plugins/modules/PluginRegistry.js +6 -38
  4. package/dist/cjs/src/plugins/modules/PluginRegistry.js.map +1 -1
  5. package/dist/cjs/src/plugins/modules/builtin/JWTAuthPlugin.js +1 -1
  6. package/dist/cjs/src/plugins/modules/builtin/JWTAuthPlugin.js.map +1 -1
  7. package/dist/cjs/src/plugins/modules/builtin/SmartCachePlugin.js +1 -1
  8. package/dist/cjs/src/plugins/modules/builtin/SmartCachePlugin.js.map +1 -1
  9. package/dist/cjs/src/plugins/modules/core/CachePlugin.js +4 -4
  10. package/dist/cjs/src/plugins/modules/core/CachePlugin.js.map +1 -1
  11. package/dist/cjs/src/plugins/modules/core/PerformancePlugin.js +2 -2
  12. package/dist/cjs/src/plugins/modules/core/PerformancePlugin.js.map +1 -1
  13. package/dist/cjs/src/plugins/modules/core/SecurityPlugin.js +2 -2
  14. package/dist/cjs/src/plugins/modules/core/SecurityPlugin.js.map +1 -1
  15. package/dist/cjs/src/plugins/modules/index.js +304 -0
  16. package/dist/cjs/src/plugins/modules/index.js.map +1 -0
  17. package/dist/cjs/src/plugins/modules/network/builtin/CompressionPlugin.js +410 -0
  18. package/dist/cjs/src/plugins/modules/network/builtin/CompressionPlugin.js.map +1 -0
  19. package/dist/cjs/src/plugins/modules/network/builtin/ConnectionPlugin.js +797 -0
  20. package/dist/cjs/src/plugins/modules/network/builtin/ConnectionPlugin.js.map +1 -0
  21. package/dist/cjs/src/plugins/modules/network/builtin/ProxyPlugin.js +409 -0
  22. package/dist/cjs/src/plugins/modules/network/builtin/ProxyPlugin.js.map +1 -0
  23. package/dist/cjs/src/plugins/modules/network/builtin/RateLimitPlugin.js +606 -0
  24. package/dist/cjs/src/plugins/modules/network/builtin/RateLimitPlugin.js.map +1 -0
  25. package/dist/cjs/src/plugins/modules/network/core/NetworkPlugin.js +225 -0
  26. package/dist/cjs/src/plugins/modules/network/core/NetworkPlugin.js.map +1 -0
  27. package/dist/cjs/src/plugins/modules/network/core/NetworkPluginFactory.js +40 -0
  28. package/dist/cjs/src/plugins/modules/network/core/NetworkPluginFactory.js.map +1 -0
  29. package/dist/cjs/src/plugins/modules/network/index.js +120 -0
  30. package/dist/cjs/src/plugins/modules/network/index.js.map +1 -0
  31. package/dist/cjs/src/plugins/modules/network/types/NetworkTypes.js +24 -0
  32. package/dist/cjs/src/plugins/modules/network/types/NetworkTypes.js.map +1 -0
  33. package/dist/cjs/src/plugins/modules/network/utils/NetworkPluginUtils.js +63 -0
  34. package/dist/cjs/src/plugins/modules/network/utils/NetworkPluginUtils.js.map +1 -0
  35. package/dist/cjs/src/plugins/modules/types/PluginTypes.js +1 -0
  36. package/dist/cjs/src/plugins/modules/types/PluginTypes.js.map +1 -1
  37. package/dist/cjs/src/server/FastServer.js +111 -2
  38. package/dist/cjs/src/server/FastServer.js.map +1 -1
  39. package/dist/cjs/src/server/conf/networkConnectionConf.js +25 -0
  40. package/dist/cjs/src/server/conf/networkConnectionConf.js.map +1 -0
  41. package/dist/cjs/src/server/conf/proxyConfig.js +23 -0
  42. package/dist/cjs/src/server/conf/proxyConfig.js.map +1 -0
  43. package/dist/cjs/src/server/conf/rateLimitConfig.js +35 -0
  44. package/dist/cjs/src/server/conf/rateLimitConfig.js.map +1 -0
  45. package/dist/cjs/src/server/const/default.js +6 -0
  46. package/dist/cjs/src/server/const/default.js.map +1 -1
  47. package/dist/cjs/src/server/handlers/NotFoundHandler.js +217 -0
  48. package/dist/cjs/src/server/handlers/NotFoundHandler.js.map +1 -0
  49. package/dist/cjs/src/server/handlers/templates/notFoundTemp.js +163 -0
  50. package/dist/cjs/src/server/handlers/templates/notFoundTemp.js.map +1 -0
  51. package/dist/esm/mods/security/src/components/cache/UFSIMC.js +5 -5
  52. package/dist/esm/mods/security/src/components/cache/UFSIMC.js.map +1 -1
  53. package/dist/esm/mods/security/src/components/cache/cacheSys.utils.js +3 -3
  54. package/dist/esm/mods/security/src/components/cache/cacheSys.utils.js.map +1 -1
  55. package/dist/esm/src/index.js +18 -0
  56. package/dist/esm/src/index.js.map +1 -1
  57. package/dist/esm/src/plugins/modules/PluginRegistry.js +6 -38
  58. package/dist/esm/src/plugins/modules/PluginRegistry.js.map +1 -1
  59. package/dist/esm/src/plugins/modules/builtin/JWTAuthPlugin.js +1 -1
  60. package/dist/esm/src/plugins/modules/builtin/JWTAuthPlugin.js.map +1 -1
  61. package/dist/esm/src/plugins/modules/builtin/SmartCachePlugin.js +1 -1
  62. package/dist/esm/src/plugins/modules/builtin/SmartCachePlugin.js.map +1 -1
  63. package/dist/esm/src/plugins/modules/core/CachePlugin.js +4 -4
  64. package/dist/esm/src/plugins/modules/core/CachePlugin.js.map +1 -1
  65. package/dist/esm/src/plugins/modules/core/PerformancePlugin.js +2 -2
  66. package/dist/esm/src/plugins/modules/core/PerformancePlugin.js.map +1 -1
  67. package/dist/esm/src/plugins/modules/core/SecurityPlugin.js +2 -2
  68. package/dist/esm/src/plugins/modules/core/SecurityPlugin.js.map +1 -1
  69. package/dist/esm/src/plugins/modules/index.js +275 -0
  70. package/dist/esm/src/plugins/modules/index.js.map +1 -0
  71. package/dist/esm/src/plugins/modules/network/builtin/CompressionPlugin.js +389 -0
  72. package/dist/esm/src/plugins/modules/network/builtin/CompressionPlugin.js.map +1 -0
  73. package/dist/esm/src/plugins/modules/network/builtin/ConnectionPlugin.js +776 -0
  74. package/dist/esm/src/plugins/modules/network/builtin/ConnectionPlugin.js.map +1 -0
  75. package/dist/esm/src/plugins/modules/network/builtin/ProxyPlugin.js +407 -0
  76. package/dist/esm/src/plugins/modules/network/builtin/ProxyPlugin.js.map +1 -0
  77. package/dist/esm/src/plugins/modules/network/builtin/RateLimitPlugin.js +585 -0
  78. package/dist/esm/src/plugins/modules/network/builtin/RateLimitPlugin.js.map +1 -0
  79. package/dist/esm/src/plugins/modules/network/core/NetworkPlugin.js +223 -0
  80. package/dist/esm/src/plugins/modules/network/core/NetworkPlugin.js.map +1 -0
  81. package/dist/esm/src/plugins/modules/network/core/NetworkPluginFactory.js +38 -0
  82. package/dist/esm/src/plugins/modules/network/core/NetworkPluginFactory.js.map +1 -0
  83. package/dist/esm/src/plugins/modules/network/index.js +109 -0
  84. package/dist/esm/src/plugins/modules/network/index.js.map +1 -0
  85. package/dist/esm/src/plugins/modules/network/types/NetworkTypes.js +24 -0
  86. package/dist/esm/src/plugins/modules/network/types/NetworkTypes.js.map +1 -0
  87. package/dist/esm/src/plugins/modules/network/utils/NetworkPluginUtils.js +61 -0
  88. package/dist/esm/src/plugins/modules/network/utils/NetworkPluginUtils.js.map +1 -0
  89. package/dist/esm/src/plugins/modules/types/PluginTypes.js +1 -0
  90. package/dist/esm/src/plugins/modules/types/PluginTypes.js.map +1 -1
  91. package/dist/esm/src/server/FastServer.js +111 -2
  92. package/dist/esm/src/server/FastServer.js.map +1 -1
  93. package/dist/esm/src/server/conf/networkConnectionConf.js +23 -0
  94. package/dist/esm/src/server/conf/networkConnectionConf.js.map +1 -0
  95. package/dist/esm/src/server/conf/proxyConfig.js +21 -0
  96. package/dist/esm/src/server/conf/proxyConfig.js.map +1 -0
  97. package/dist/esm/src/server/conf/rateLimitConfig.js +33 -0
  98. package/dist/esm/src/server/conf/rateLimitConfig.js.map +1 -0
  99. package/dist/esm/src/server/const/default.js +6 -0
  100. package/dist/esm/src/server/const/default.js.map +1 -1
  101. package/dist/esm/src/server/handlers/NotFoundHandler.js +194 -0
  102. package/dist/esm/src/server/handlers/NotFoundHandler.js.map +1 -0
  103. package/dist/esm/src/server/handlers/templates/notFoundTemp.js +161 -0
  104. package/dist/esm/src/server/handlers/templates/notFoundTemp.js.map +1 -0
  105. package/dist/index.d.ts +5085 -14
  106. package/package.json +8 -7
@@ -0,0 +1,776 @@
1
+ import { performance } from 'perf_hooks';
2
+ import { NetworkPlugin } from '../core/NetworkPlugin.js';
3
+ import { promises, constants } from 'fs';
4
+ import { resolve } from 'path';
5
+ import { RandomTokens } from 'xypriss-security';
6
+ import * as crypto from 'crypto';
7
+ import { NetworkCategory } from '../types/NetworkTypes.js';
8
+
9
+ /**
10
+ * Connection Plugin
11
+ *
12
+ * Handles HTTP/2, connection pooling, keep-alive management, and connection optimization
13
+ * Provides advanced connection management features for XyPriss servers
14
+ */
15
+ // MIME type lookup with fallback for ESM compatibility
16
+ const getMimeType = (path) => {
17
+ const ext = path.split(".").pop()?.toLowerCase();
18
+ const mimeMap = {
19
+ css: "text/css",
20
+ js: "application/javascript",
21
+ json: "application/json",
22
+ html: "text/html",
23
+ htm: "text/html",
24
+ txt: "text/plain",
25
+ xml: "application/xml",
26
+ png: "image/png",
27
+ jpg: "image/jpeg",
28
+ jpeg: "image/jpeg",
29
+ gif: "image/gif",
30
+ svg: "image/svg+xml",
31
+ ico: "image/x-icon",
32
+ woff: "font/woff",
33
+ woff2: "font/woff2",
34
+ ttf: "font/ttf",
35
+ eot: "application/vnd.ms-fontobject",
36
+ };
37
+ return mimeMap[ext || ""] || "application/octet-stream";
38
+ };
39
+ /**
40
+ * Connection management plugin for optimizing HTTP connections
41
+ */
42
+ class ConnectionPlugin extends NetworkPlugin {
43
+ constructor(config = {}) {
44
+ super(config);
45
+ this.id = "xypriss.network.connection";
46
+ this.name = "Connection Management Plugin";
47
+ this.version = "1.0.0";
48
+ this.networkCategory = NetworkCategory.CONNECTION;
49
+ // Connection-specific state
50
+ this.connectionPool = new Map();
51
+ this.activeConnections = 0;
52
+ this.connectionTimeouts = new Map();
53
+ this.keepAliveStats = {
54
+ totalConnections: 0,
55
+ reuseCount: 0,
56
+ timeoutCount: 0,
57
+ };
58
+ this.http2Stats = {
59
+ maxStreams: 100,
60
+ serverPushEnabled: false,
61
+ configured: false,
62
+ };
63
+ this.maxConnections = config.connectionPool?.maxConnections || 1000;
64
+ // Use a reasonable default for static files directory
65
+ this.staticBaseDir = config.staticBaseDir || process.cwd();
66
+ }
67
+ /**
68
+ * Initialize connection management
69
+ */
70
+ async initializeNetwork() {
71
+ // Set up connection pool monitoring
72
+ this.startConnectionMonitoring();
73
+ // Configure HTTP/2 if enabled
74
+ if (this.getConnectionConfig().http2?.enabled) {
75
+ await this.configureHTTP2();
76
+ }
77
+ // Set up keep-alive management
78
+ if (this.getConnectionConfig().keepAlive?.enabled !== false) {
79
+ this.configureKeepAlive();
80
+ }
81
+ }
82
+ /**
83
+ * Execute connection management logic
84
+ */
85
+ async executeNetwork(context) {
86
+ const startTime = performance.now();
87
+ try {
88
+ // Get or create connection info
89
+ const connectionKey = this.getConnectionKey(context);
90
+ let connectionInfo = this.connectionPool.get(connectionKey);
91
+ if (!connectionInfo) {
92
+ connectionInfo = await this.createConnection(context);
93
+ this.connectionPool.set(connectionKey, connectionInfo);
94
+ this.activeConnections++;
95
+ }
96
+ else {
97
+ // Update existing connection
98
+ connectionInfo.lastUsed = Date.now();
99
+ connectionInfo.requestCount++;
100
+ this.keepAliveStats.reuseCount++;
101
+ }
102
+ // Apply connection optimizations
103
+ await this.applyConnectionOptimizations(context, connectionInfo);
104
+ // Set up connection cleanup
105
+ this.setupConnectionCleanup(connectionKey, connectionInfo);
106
+ const executionTime = performance.now() - startTime;
107
+ return {
108
+ success: true,
109
+ executionTime,
110
+ shouldContinue: true,
111
+ data: {
112
+ connectionId: connectionInfo.id,
113
+ isReused: connectionInfo.requestCount > 1,
114
+ protocol: connectionInfo.protocol,
115
+ },
116
+ modifications: {
117
+ headers: this.getConnectionHeaders(connectionInfo),
118
+ },
119
+ networkMetrics: {
120
+ processingTime: executionTime,
121
+ memoryUsage: process.memoryUsage().heapUsed,
122
+ cpuUsage: process.cpuUsage().user,
123
+ },
124
+ };
125
+ }
126
+ catch (error) {
127
+ return {
128
+ success: false,
129
+ executionTime: performance.now() - startTime,
130
+ shouldContinue: true,
131
+ error,
132
+ };
133
+ }
134
+ }
135
+ /**
136
+ * Create new connection info
137
+ */
138
+ async createConnection(context) {
139
+ const config = this.getConnectionConfig();
140
+ return {
141
+ id: this.generateConnectionId(),
142
+ remoteAddress: context.connection.remoteAddress || "unknown",
143
+ protocol: context.connection.protocol,
144
+ encrypted: context.connection.encrypted,
145
+ created: Date.now(),
146
+ lastUsed: Date.now(),
147
+ requestCount: 1,
148
+ keepAlive: config.keepAlive?.enabled !== false,
149
+ http2: config.http2?.enabled || false,
150
+ maxRequests: config.keepAlive?.maxRequests || 1000,
151
+ timeout: config.keepAlive?.timeout || 30000,
152
+ };
153
+ }
154
+ /**
155
+ * Apply connection optimizations
156
+ */
157
+ async applyConnectionOptimizations(context, connectionInfo) {
158
+ const { res } = context;
159
+ // Set keep-alive headers
160
+ if (connectionInfo.keepAlive) {
161
+ res.setHeader("Connection", "keep-alive");
162
+ res.setHeader("Keep-Alive", `timeout=${connectionInfo.timeout / 1000}, max=${connectionInfo.maxRequests}`);
163
+ }
164
+ // Set HTTP/2 server push hints if supported
165
+ if (connectionInfo.http2 && res.push) {
166
+ await this.setupHTTP2ServerPush(context, res);
167
+ }
168
+ // Apply connection-specific timeouts
169
+ this.applyConnectionTimeouts(context, connectionInfo);
170
+ }
171
+ /**
172
+ * Set up HTTP/2 server push with intelligent resource detection
173
+ */
174
+ async setupHTTP2ServerPush(context, res) {
175
+ const { req } = context;
176
+ const http2Res = res; // HTTP/2 response with push method
177
+ const config = this.getConnectionConfig();
178
+ if (!config.http2?.enabled || !http2Res.push) {
179
+ return;
180
+ }
181
+ try {
182
+ // Analyze request to determine critical resources to push
183
+ const criticalResources = await this.identifyCriticalResources(req);
184
+ for (const resource of criticalResources) {
185
+ // Check if resource should be pushed based on cache headers and client hints
186
+ if (await this.shouldPushResource(req, resource)) {
187
+ await this.pushResource(http2Res, resource);
188
+ }
189
+ }
190
+ }
191
+ catch (error) {
192
+ // Log error but don't fail the request
193
+ console.warn("HTTP/2 server push failed:", error);
194
+ }
195
+ }
196
+ /**
197
+ * Identify critical resources based on request analysis and file existence
198
+ */
199
+ async identifyCriticalResources(req) {
200
+ const potentialResources = [];
201
+ const userAgent = req.get("user-agent") || "";
202
+ const acceptHeader = req.get("accept") || "";
203
+ // Analyze request path and headers to determine critical resources
204
+ if (req.path === "/" || req.path.endsWith(".html")) {
205
+ // For HTML pages, push critical CSS and JS
206
+ if (acceptHeader.includes("text/css")) {
207
+ potentialResources.push("/assets/critical.css", "/css/main.css", "/styles/app.css");
208
+ }
209
+ if (acceptHeader.includes("application/javascript")) {
210
+ potentialResources.push("/assets/app.js", "/js/main.js", "/scripts/app.js");
211
+ }
212
+ }
213
+ // Add resources based on user agent (mobile vs desktop)
214
+ if (userAgent.includes("Mobile")) {
215
+ potentialResources.push("/assets/mobile.css", "/css/mobile.css");
216
+ }
217
+ else {
218
+ potentialResources.push("/assets/desktop.css", "/css/desktop.css");
219
+ }
220
+ // Filter resources to only include those that actually exist
221
+ const existingResources = [];
222
+ for (const resource of potentialResources) {
223
+ if (await this.resourceExists(resource)) {
224
+ existingResources.push(resource);
225
+ }
226
+ }
227
+ return existingResources;
228
+ }
229
+ /**
230
+ * Determine if a resource should be pushed based on cache headers and client hints
231
+ */
232
+ async shouldPushResource(req, resource) {
233
+ // Check client cache control directives
234
+ const cacheControl = req.get("cache-control") || "";
235
+ // Don't push if client explicitly doesn't want cached resources
236
+ if (cacheControl.includes("no-cache") ||
237
+ cacheControl.includes("no-store")) {
238
+ return false;
239
+ }
240
+ // Check if resource is already in client cache using proper ETag comparison
241
+ const ifNoneMatch = req.get("if-none-match");
242
+ if (ifNoneMatch) {
243
+ const resourceETag = await this.generateResourceETag(resource);
244
+ // Parse multiple ETags from If-None-Match header
245
+ const clientETags = ifNoneMatch
246
+ .split(",")
247
+ .map((etag) => etag.trim());
248
+ for (const clientETag of clientETags) {
249
+ if (clientETag === "*" ||
250
+ clientETag === resourceETag ||
251
+ clientETag === `W/${resourceETag}`) {
252
+ return false; // Resource is already cached
253
+ }
254
+ }
255
+ }
256
+ // Check if resource was recently modified using If-Modified-Since
257
+ const ifModifiedSince = req.get("if-modified-since");
258
+ if (ifModifiedSince) {
259
+ const modifiedSince = new Date(ifModifiedSince);
260
+ const resourceModified = await this.getResourceModificationTime(resource);
261
+ if (resourceModified <= modifiedSince) {
262
+ return false; // Resource hasn't been modified
263
+ }
264
+ }
265
+ // Check client connection type for bandwidth optimization
266
+ const connection = req.get("connection") || "";
267
+ if (connection.includes("slow") || req.get("save-data") === "on") {
268
+ // Only push critical resources for slow connections
269
+ return this.isCriticalResource(resource);
270
+ }
271
+ return true;
272
+ }
273
+ /**
274
+ * Get resource modification time from actual file system
275
+ */
276
+ async getResourceModificationTime(resource) {
277
+ try {
278
+ const filePath = this.resolveResourcePath(resource);
279
+ const stats = await promises.stat(filePath);
280
+ return stats.mtime;
281
+ }
282
+ catch (error) {
283
+ // If file doesn't exist or can't be accessed, return current time
284
+ // This ensures ETags and cache headers still work
285
+ return new Date();
286
+ }
287
+ }
288
+ /**
289
+ * Resolve resource path to actual file system path
290
+ */
291
+ resolveResourcePath(resource) {
292
+ // Remove leading slash and resolve relative to static base directory
293
+ const relativePath = resource.startsWith("/")
294
+ ? resource.slice(1)
295
+ : resource;
296
+ return resolve(this.staticBaseDir, relativePath);
297
+ }
298
+ /**
299
+ * Check if a resource exists and is accessible
300
+ */
301
+ async resourceExists(resource) {
302
+ try {
303
+ const filePath = this.resolveResourcePath(resource);
304
+ await promises.access(filePath, constants.R_OK);
305
+ const stats = await promises.stat(filePath);
306
+ return stats.isFile();
307
+ }
308
+ catch (error) {
309
+ return false;
310
+ }
311
+ }
312
+ /**
313
+ * Determine if a resource is critical for page rendering
314
+ */
315
+ isCriticalResource(resource) {
316
+ // Critical resources that should always be pushed for performance
317
+ const criticalPatterns = [
318
+ /\/critical\./,
319
+ /\/main\./,
320
+ /\/app\./,
321
+ /\/styles?\./,
322
+ /\/fonts?\//,
323
+ ];
324
+ return criticalPatterns.some((pattern) => pattern.test(resource));
325
+ }
326
+ /**
327
+ * Push a resource using HTTP/2 server push with proper content handling
328
+ */
329
+ async pushResource(http2Res, resource) {
330
+ return new Promise(async (resolve) => {
331
+ const resourceETag = await this.generateResourceETag(resource);
332
+ const lastModified = await this.getResourceModificationTime(resource);
333
+ http2Res.push(resource, {
334
+ request: {
335
+ accept: this.getAcceptHeaderForResource(resource),
336
+ "user-agent": "XyPriss-ServerPush/1.0",
337
+ },
338
+ response: {
339
+ "content-type": this.getContentType(resource),
340
+ "cache-control": this.getCacheControlForResource(resource),
341
+ etag: resourceETag,
342
+ "last-modified": lastModified.toUTCString(),
343
+ "x-pushed-by": "xypriss",
344
+ vary: "Accept-Encoding",
345
+ },
346
+ }, async (err, pushStream) => {
347
+ if (err) {
348
+ resolve();
349
+ return;
350
+ }
351
+ try {
352
+ // Generate appropriate content for the resource
353
+ const content = await this.generateResourceContent(resource);
354
+ // Set content length
355
+ pushStream.setHeader("content-length", Buffer.byteLength(content));
356
+ // Send the content
357
+ pushStream.end(content);
358
+ resolve();
359
+ }
360
+ catch (error) {
361
+ // If content generation fails, send minimal fallback
362
+ const fallbackContent = this.getFallbackContent(resource);
363
+ pushStream.end(fallbackContent);
364
+ resolve();
365
+ }
366
+ });
367
+ });
368
+ }
369
+ /**
370
+ * Generate appropriate cache control header for resource type
371
+ */
372
+ getCacheControlForResource(resource) {
373
+ if (resource.includes("/fonts/") || resource.includes("/images/")) {
374
+ // Long cache for static assets
375
+ return "public, max-age=31536000, immutable";
376
+ }
377
+ else if (resource.endsWith(".css") || resource.endsWith(".js")) {
378
+ // Medium cache for stylesheets and scripts
379
+ return "public, max-age=86400, must-revalidate";
380
+ }
381
+ else {
382
+ // Short cache for dynamic content
383
+ return "public, max-age=3600, must-revalidate";
384
+ }
385
+ }
386
+ /**
387
+ * Generate content for a resource by reading from file system
388
+ */
389
+ async generateResourceContent(resource) {
390
+ try {
391
+ const filePath = this.resolveResourcePath(resource);
392
+ // Check if file exists and is readable
393
+ await promises.access(filePath, constants.R_OK);
394
+ // Read file content
395
+ const content = await promises.readFile(filePath, "utf8");
396
+ return content;
397
+ }
398
+ catch (error) {
399
+ // If file doesn't exist or can't be read, generate fallback content
400
+ if (resource.endsWith(".css")) {
401
+ return this.generateCSSContent(resource);
402
+ }
403
+ else if (resource.endsWith(".js")) {
404
+ return this.generateJSContent(resource);
405
+ }
406
+ else if (resource.endsWith(".json")) {
407
+ return this.generateJSONContent(resource);
408
+ }
409
+ else {
410
+ return this.generateGenericContent(resource);
411
+ }
412
+ }
413
+ }
414
+ /**
415
+ * Generate CSS content for stylesheets
416
+ */
417
+ generateCSSContent(resource) {
418
+ const resourceName = resource.split("/").pop()?.replace(".css", "") || "default";
419
+ return `/* ${resourceName} stylesheet - Generated by XyPriss */
420
+ body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; }
421
+ .${resourceName} { display: block; margin: 0; padding: 0; }
422
+ /* Optimized for ${resource} */`;
423
+ }
424
+ /**
425
+ * Generate JavaScript content for scripts
426
+ */
427
+ generateJSContent(resource) {
428
+ const resourceName = resource.split("/").pop()?.replace(".js", "") || "default";
429
+ return `// ${resourceName} script - Generated by Nehonix XyPriss
430
+ (function() {
431
+ 'use strict';
432
+ console.log('${resourceName} loaded via HTTP/2 server push');
433
+ // Optimized for ${resource}
434
+ })();`;
435
+ }
436
+ /**
437
+ * Generate JSON content for data resources
438
+ */
439
+ generateJSONContent(resource) {
440
+ const resourceName = resource.split("/").pop()?.replace(".json", "") || "default";
441
+ return JSON.stringify({
442
+ resource: resourceName,
443
+ pushedBy: "xypriss",
444
+ timestamp: new Date().toISOString(),
445
+ path: resource,
446
+ }, null, 2);
447
+ }
448
+ /**
449
+ * Generate generic content for other resource types
450
+ */
451
+ generateGenericContent(resource) {
452
+ return `Resource: ${resource}
453
+ Generated by: XyPriss HTTP/2 Server Push
454
+ Timestamp: ${new Date().toISOString()}
455
+ Content-Type: ${this.getContentType(resource)}`;
456
+ }
457
+ /**
458
+ * Get fallback content when resource generation fails
459
+ */
460
+ getFallbackContent(resource) {
461
+ return `/* Fallback content for ${resource} */`;
462
+ }
463
+ /**
464
+ * Generate ETag for a resource based on file stats
465
+ */
466
+ async generateResourceETag(resource) {
467
+ try {
468
+ const filePath = this.resolveResourcePath(resource);
469
+ const stats = await promises.stat(filePath);
470
+ // Create ETag based on file modification time and size
471
+ const resourceHash = crypto
472
+ .createHash("md5")
473
+ .update(`${resource}-${stats.mtime.getTime()}-${stats.size}`)
474
+ .digest("hex")
475
+ .substring(0, 16);
476
+ return `"${resourceHash}"`;
477
+ }
478
+ catch (error) {
479
+ // If file doesn't exist, create ETag based on resource path
480
+ const resourceHash = crypto
481
+ .createHash("md5")
482
+ .update(resource)
483
+ .digest("hex")
484
+ .substring(0, 16);
485
+ return `"${resourceHash}"`;
486
+ }
487
+ }
488
+ /**
489
+ * Get appropriate Accept header for resource type
490
+ */
491
+ getAcceptHeaderForResource(resource) {
492
+ if (resource.endsWith(".css")) {
493
+ return "text/css,*/*;q=0.1";
494
+ }
495
+ if (resource.endsWith(".js")) {
496
+ return "application/javascript,*/*;q=0.1";
497
+ }
498
+ if (resource.endsWith(".json")) {
499
+ return "application/json,*/*;q=0.1";
500
+ }
501
+ return "*/*";
502
+ }
503
+ /**
504
+ * Apply connection timeouts
505
+ */
506
+ applyConnectionTimeouts(context, _connectionInfo) {
507
+ const { req, res } = context;
508
+ const config = this.getConnectionConfig();
509
+ // Request timeout
510
+ if (config.timeouts?.request) {
511
+ req.setTimeout(config.timeouts.request, () => {
512
+ if (!res.headersSent) {
513
+ res.status(408).json({ error: "Request timeout" });
514
+ }
515
+ });
516
+ }
517
+ // Response timeout
518
+ if (config.timeouts?.response) {
519
+ res.setTimeout(config.timeouts.response, () => {
520
+ if (!res.headersSent) {
521
+ res.status(504).json({ error: "Response timeout" });
522
+ }
523
+ });
524
+ }
525
+ }
526
+ /**
527
+ * Set up connection cleanup
528
+ */
529
+ setupConnectionCleanup(connectionKey, connectionInfo) {
530
+ // Clear existing timeout
531
+ const existingTimeout = this.connectionTimeouts.get(connectionKey);
532
+ if (existingTimeout) {
533
+ clearTimeout(existingTimeout);
534
+ }
535
+ // Set new cleanup timeout
536
+ const timeout = setTimeout(() => {
537
+ this.cleanupConnection(connectionKey);
538
+ }, connectionInfo.timeout);
539
+ this.connectionTimeouts.set(connectionKey, timeout);
540
+ }
541
+ /**
542
+ * Clean up connection
543
+ */
544
+ cleanupConnection(connectionKey) {
545
+ const connectionInfo = this.connectionPool.get(connectionKey);
546
+ if (connectionInfo) {
547
+ this.connectionPool.delete(connectionKey);
548
+ this.activeConnections--;
549
+ this.keepAliveStats.timeoutCount++;
550
+ }
551
+ const timeout = this.connectionTimeouts.get(connectionKey);
552
+ if (timeout) {
553
+ clearTimeout(timeout);
554
+ this.connectionTimeouts.delete(connectionKey);
555
+ }
556
+ }
557
+ /**
558
+ * Get connection headers
559
+ */
560
+ getConnectionHeaders(connectionInfo) {
561
+ const headers = {};
562
+ if (connectionInfo.keepAlive) {
563
+ headers["Connection"] = "keep-alive";
564
+ headers["Keep-Alive"] = `timeout=${connectionInfo.timeout / 1000}, max=${connectionInfo.maxRequests}`;
565
+ }
566
+ if (connectionInfo.http2) {
567
+ headers["Alt-Svc"] = 'h2=":443"; ma=86400';
568
+ }
569
+ return headers;
570
+ }
571
+ /**
572
+ * Configure HTTP/2 settings and optimizations
573
+ */
574
+ async configureHTTP2() {
575
+ const config = this.getConnectionConfig();
576
+ if (!config.http2?.enabled) {
577
+ return;
578
+ }
579
+ // Set HTTP/2 specific connection parameters
580
+ const http2Config = config.http2;
581
+ // Configure stream limits
582
+ if (http2Config.maxConcurrentStreams) {
583
+ this.http2Stats.maxStreams = http2Config.maxConcurrentStreams;
584
+ }
585
+ // Configure server push settings (enabled by default for HTTP/2)
586
+ this.http2Stats.serverPushEnabled = true;
587
+ // Configure frame size and window size optimizations
588
+ this.http2Stats.configured = true;
589
+ }
590
+ /**
591
+ * Configure keep-alive
592
+ */
593
+ configureKeepAlive() {
594
+ // Keep-alive configuration
595
+ const config = this.getConnectionConfig();
596
+ // Set up periodic cleanup of idle connections
597
+ setInterval(() => {
598
+ this.cleanupIdleConnections();
599
+ }, config.keepAlive?.maxIdleTime || 60000);
600
+ }
601
+ /**
602
+ * Clean up idle connections
603
+ */
604
+ cleanupIdleConnections() {
605
+ const now = Date.now();
606
+ const config = this.getConnectionConfig();
607
+ const maxIdleTime = config.keepAlive?.maxIdleTime || 60000;
608
+ for (const [key, connectionInfo] of this.connectionPool.entries()) {
609
+ if (now - connectionInfo.lastUsed > maxIdleTime) {
610
+ this.cleanupConnection(key);
611
+ }
612
+ }
613
+ }
614
+ /**
615
+ * Start connection monitoring
616
+ */
617
+ startConnectionMonitoring() {
618
+ setInterval(() => {
619
+ this.updateHealthStatus();
620
+ }, 30000); // Update health every 30 seconds
621
+ }
622
+ /**
623
+ * Generate secure connection ID using xypriss-security
624
+ */
625
+ generateConnectionId() {
626
+ try {
627
+ // Use secure token generation for connection IDs
628
+ const secureToken = RandomTokens.generateSecureToken(16);
629
+ return `conn_${Date.now()}_${secureToken}`;
630
+ }
631
+ catch (error) {
632
+ // Fallback to crypto random bytes
633
+ const randomBytes = crypto.randomBytes(8).toString("hex");
634
+ return `conn_${Date.now()}_${randomBytes}`;
635
+ }
636
+ }
637
+ /**
638
+ * Get connection key for pooling
639
+ */
640
+ getConnectionKey(context) {
641
+ return `${context.connection.remoteAddress}:${context.connection.remotePort}`;
642
+ }
643
+ /**
644
+ * Get content type for resource using mime-types library
645
+ */
646
+ getContentType(resource) {
647
+ try {
648
+ // Use mime-types library for accurate content type detection
649
+ const mimeType = getMimeType(resource);
650
+ return mimeType || "text/plain";
651
+ }
652
+ catch (error) {
653
+ // Fallback to basic detection if mime-types fails
654
+ if (resource.endsWith(".css"))
655
+ return "text/css";
656
+ if (resource.endsWith(".js"))
657
+ return "application/javascript";
658
+ if (resource.endsWith(".json"))
659
+ return "application/json";
660
+ if (resource.endsWith(".html"))
661
+ return "text/html";
662
+ if (resource.endsWith(".png"))
663
+ return "image/png";
664
+ if (resource.endsWith(".jpg") || resource.endsWith(".jpeg"))
665
+ return "image/jpeg";
666
+ if (resource.endsWith(".gif"))
667
+ return "image/gif";
668
+ if (resource.endsWith(".svg"))
669
+ return "image/svg+xml";
670
+ return "text/plain";
671
+ }
672
+ }
673
+ /**
674
+ * Get connection configuration
675
+ */
676
+ getConnectionConfig() {
677
+ return this.config;
678
+ }
679
+ /**
680
+ * Validate connection configuration
681
+ */
682
+ validateNetworkConfig(config) {
683
+ if (config.connectionPool?.maxConnections &&
684
+ config.connectionPool.maxConnections < 1) {
685
+ return false;
686
+ }
687
+ if (config.keepAlive?.timeout && config.keepAlive.timeout < 1000) {
688
+ return false;
689
+ }
690
+ return true;
691
+ }
692
+ /**
693
+ * Check network health
694
+ */
695
+ async checkNetworkHealth() {
696
+ const errorRate = this.performanceMetrics.errorCount /
697
+ Math.max(this.performanceMetrics.totalExecutions, 1);
698
+ const connectionUtilization = this.activeConnections / this.maxConnections;
699
+ return {
700
+ healthy: errorRate < 0.1 && connectionUtilization < 0.9,
701
+ status: errorRate < 0.05 && connectionUtilization < 0.7
702
+ ? "healthy"
703
+ : errorRate < 0.1 && connectionUtilization < 0.9
704
+ ? "degraded"
705
+ : "unhealthy",
706
+ metrics: {
707
+ responseTime: this.performanceMetrics.averageExecutionTime,
708
+ errorRate,
709
+ throughput: this.performanceMetrics.totalExecutions,
710
+ connections: this.activeConnections,
711
+ },
712
+ lastCheck: new Date(),
713
+ };
714
+ }
715
+ /**
716
+ * Get connection statistics
717
+ */
718
+ getConnectionStats() {
719
+ return {
720
+ activeConnections: this.activeConnections,
721
+ maxConnections: this.maxConnections,
722
+ connectionPoolSize: this.connectionPool.size,
723
+ keepAliveStats: { ...this.keepAliveStats },
724
+ };
725
+ }
726
+ /**
727
+ * Serve a static file with proper headers and caching
728
+ */
729
+ async serveStaticFile(resource, res) {
730
+ try {
731
+ const filePath = this.resolveResourcePath(resource);
732
+ // Check if file exists and is readable
733
+ await promises.access(filePath, constants.R_OK);
734
+ const stats = await promises.stat(filePath);
735
+ if (!stats.isFile()) {
736
+ return false;
737
+ }
738
+ // Set content type
739
+ const contentType = this.getContentType(resource);
740
+ res.setHeader("Content-Type", contentType);
741
+ // Set cache headers
742
+ const cacheControl = this.getCacheControlForResource(resource);
743
+ res.setHeader("Cache-Control", cacheControl);
744
+ // Set ETag and Last-Modified headers
745
+ const etag = await this.generateResourceETag(resource);
746
+ res.setHeader("ETag", etag);
747
+ res.setHeader("Last-Modified", stats.mtime.toUTCString());
748
+ // Set content length
749
+ res.setHeader("Content-Length", stats.size);
750
+ // Read and send file
751
+ const content = await promises.readFile(filePath);
752
+ res.end(content);
753
+ return true;
754
+ }
755
+ catch (error) {
756
+ return false;
757
+ }
758
+ }
759
+ /**
760
+ * Cleanup resources
761
+ */
762
+ async destroy() {
763
+ // Clear all timeouts
764
+ for (const timeout of this.connectionTimeouts.values()) {
765
+ clearTimeout(timeout);
766
+ }
767
+ this.connectionTimeouts.clear();
768
+ // Clear connection pool
769
+ this.connectionPool.clear();
770
+ this.activeConnections = 0;
771
+ await super.destroy();
772
+ }
773
+ }
774
+
775
+ export { ConnectionPlugin };
776
+ //# sourceMappingURL=ConnectionPlugin.js.map