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