@push.rocks/smartproxy 15.0.2 → 16.0.2

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 (80) hide show
  1. package/dist_ts/00_commitinfo_data.js +1 -1
  2. package/dist_ts/certificate/index.d.ts +10 -4
  3. package/dist_ts/certificate/index.js +5 -7
  4. package/dist_ts/certificate/models/certificate-types.d.ts +35 -15
  5. package/dist_ts/certificate/providers/cert-provisioner.d.ts +41 -15
  6. package/dist_ts/certificate/providers/cert-provisioner.js +201 -41
  7. package/dist_ts/forwarding/config/forwarding-types.d.ts +40 -76
  8. package/dist_ts/forwarding/config/forwarding-types.js +19 -18
  9. package/dist_ts/forwarding/config/index.d.ts +4 -2
  10. package/dist_ts/forwarding/config/index.js +5 -3
  11. package/dist_ts/forwarding/handlers/base-handler.js +3 -1
  12. package/dist_ts/forwarding/index.d.ts +5 -6
  13. package/dist_ts/forwarding/index.js +3 -3
  14. package/dist_ts/http/models/http-types.js +1 -1
  15. package/dist_ts/http/port80/acme-interfaces.d.ts +30 -0
  16. package/dist_ts/http/port80/acme-interfaces.js +46 -1
  17. package/dist_ts/http/port80/port80-handler.d.ts +17 -2
  18. package/dist_ts/http/port80/port80-handler.js +49 -11
  19. package/dist_ts/proxies/smart-proxy/models/interfaces.d.ts +2 -61
  20. package/dist_ts/proxies/smart-proxy/models/interfaces.js +5 -4
  21. package/dist_ts/proxies/smart-proxy/models/route-types.d.ts +118 -4
  22. package/dist_ts/proxies/smart-proxy/network-proxy-bridge.d.ts +70 -4
  23. package/dist_ts/proxies/smart-proxy/network-proxy-bridge.js +193 -43
  24. package/dist_ts/proxies/smart-proxy/route-connection-handler.d.ts +2 -5
  25. package/dist_ts/proxies/smart-proxy/route-connection-handler.js +25 -146
  26. package/dist_ts/proxies/smart-proxy/route-helpers/index.d.ts +7 -0
  27. package/dist_ts/proxies/smart-proxy/route-helpers/index.js +9 -0
  28. package/dist_ts/proxies/smart-proxy/route-helpers.d.ts +54 -1
  29. package/dist_ts/proxies/smart-proxy/route-helpers.js +102 -1
  30. package/dist_ts/proxies/smart-proxy/route-manager.d.ts +3 -9
  31. package/dist_ts/proxies/smart-proxy/route-manager.js +3 -115
  32. package/dist_ts/proxies/smart-proxy/smart-proxy.d.ts +72 -10
  33. package/dist_ts/proxies/smart-proxy/smart-proxy.js +135 -268
  34. package/dist_ts/proxies/smart-proxy/timeout-manager.js +3 -3
  35. package/dist_ts/proxies/smart-proxy/utils/index.d.ts +12 -0
  36. package/dist_ts/proxies/smart-proxy/utils/index.js +19 -0
  37. package/dist_ts/proxies/smart-proxy/utils/route-helpers.d.ts +174 -0
  38. package/dist_ts/proxies/smart-proxy/utils/route-helpers.js +332 -0
  39. package/dist_ts/proxies/smart-proxy/utils/route-migration-utils.d.ts +51 -0
  40. package/dist_ts/proxies/smart-proxy/utils/route-migration-utils.js +124 -0
  41. package/dist_ts/proxies/smart-proxy/utils/route-patterns.d.ts +131 -0
  42. package/dist_ts/proxies/smart-proxy/utils/route-patterns.js +217 -0
  43. package/dist_ts/proxies/smart-proxy/utils/route-utils.d.ts +79 -0
  44. package/dist_ts/proxies/smart-proxy/utils/route-utils.js +266 -0
  45. package/dist_ts/proxies/smart-proxy/utils/route-validators.d.ts +73 -0
  46. package/dist_ts/proxies/smart-proxy/utils/route-validators.js +242 -0
  47. package/package.json +1 -1
  48. package/readme.md +139 -111
  49. package/readme.plan.md +164 -312
  50. package/ts/00_commitinfo_data.ts +1 -1
  51. package/ts/certificate/index.ts +17 -9
  52. package/ts/certificate/models/certificate-types.ts +37 -16
  53. package/ts/certificate/providers/cert-provisioner.ts +247 -54
  54. package/ts/forwarding/config/forwarding-types.ts +79 -107
  55. package/ts/forwarding/config/index.ts +4 -2
  56. package/ts/forwarding/handlers/base-handler.ts +4 -2
  57. package/ts/forwarding/index.ts +3 -2
  58. package/ts/http/models/http-types.ts +0 -1
  59. package/ts/http/port80/acme-interfaces.ts +84 -0
  60. package/ts/http/port80/port80-handler.ts +61 -15
  61. package/ts/proxies/smart-proxy/models/interfaces.ts +7 -64
  62. package/ts/proxies/smart-proxy/models/route-types.ts +152 -22
  63. package/ts/proxies/smart-proxy/network-proxy-bridge.ts +226 -55
  64. package/ts/proxies/smart-proxy/route-connection-handler.ts +36 -205
  65. package/ts/proxies/smart-proxy/route-helpers/index.ts +9 -0
  66. package/ts/proxies/smart-proxy/route-helpers.ts +165 -11
  67. package/ts/proxies/smart-proxy/route-manager.ts +3 -130
  68. package/ts/proxies/smart-proxy/smart-proxy.ts +157 -329
  69. package/ts/proxies/smart-proxy/timeout-manager.ts +2 -2
  70. package/ts/proxies/smart-proxy/utils/index.ts +40 -0
  71. package/ts/proxies/smart-proxy/utils/route-helpers.ts +455 -0
  72. package/ts/proxies/smart-proxy/utils/route-migration-utils.ts +165 -0
  73. package/ts/proxies/smart-proxy/utils/route-patterns.ts +309 -0
  74. package/ts/proxies/smart-proxy/utils/route-utils.ts +330 -0
  75. package/ts/proxies/smart-proxy/utils/route-validators.ts +269 -0
  76. package/ts/forwarding/config/domain-config.ts +0 -28
  77. package/ts/forwarding/config/domain-manager.ts +0 -283
  78. package/ts/proxies/smart-proxy/connection-handler.ts +0 -1240
  79. package/ts/proxies/smart-proxy/port-range-manager.ts +0 -211
  80. /package/ts/proxies/smart-proxy/{domain-config-manager.ts → domain-config-manager.ts.bak} +0 -0
@@ -0,0 +1,269 @@
1
+ /**
2
+ * Route Validators
3
+ *
4
+ * This file provides utility functions for validating route configurations.
5
+ * These validators help ensure that route configurations are valid and correctly structured.
6
+ */
7
+
8
+ import type { IRouteConfig, IRouteMatch, IRouteAction, TPortRange } from '../models/route-types.js';
9
+
10
+ /**
11
+ * Validates a port range or port number
12
+ * @param port Port number or port range
13
+ * @returns True if valid, false otherwise
14
+ */
15
+ export function isValidPort(port: TPortRange): boolean {
16
+ if (typeof port === 'number') {
17
+ return port > 0 && port < 65536; // Valid port range is 1-65535
18
+ } else if (Array.isArray(port)) {
19
+ return port.every(p => typeof p === 'number' && p > 0 && p < 65536);
20
+ }
21
+ return false;
22
+ }
23
+
24
+ /**
25
+ * Validates a domain string
26
+ * @param domain Domain string to validate
27
+ * @returns True if valid, false otherwise
28
+ */
29
+ export function isValidDomain(domain: string): boolean {
30
+ // Basic domain validation regex - allows wildcards (*.example.com)
31
+ const domainRegex = /^(\*\.)?([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/;
32
+ return domainRegex.test(domain);
33
+ }
34
+
35
+ /**
36
+ * Validates a route match configuration
37
+ * @param match Route match configuration to validate
38
+ * @returns { valid: boolean, errors: string[] } Validation result
39
+ */
40
+ export function validateRouteMatch(match: IRouteMatch): { valid: boolean; errors: string[] } {
41
+ const errors: string[] = [];
42
+
43
+ // Validate ports
44
+ if (match.ports !== undefined) {
45
+ if (!isValidPort(match.ports)) {
46
+ errors.push('Invalid port number or port range in match.ports');
47
+ }
48
+ }
49
+
50
+ // Validate domains
51
+ if (match.domains !== undefined) {
52
+ if (typeof match.domains === 'string') {
53
+ if (!isValidDomain(match.domains)) {
54
+ errors.push(`Invalid domain format: ${match.domains}`);
55
+ }
56
+ } else if (Array.isArray(match.domains)) {
57
+ for (const domain of match.domains) {
58
+ if (!isValidDomain(domain)) {
59
+ errors.push(`Invalid domain format: ${domain}`);
60
+ }
61
+ }
62
+ } else {
63
+ errors.push('Domains must be a string or an array of strings');
64
+ }
65
+ }
66
+
67
+ // Validate path
68
+ if (match.path !== undefined) {
69
+ if (typeof match.path !== 'string' || !match.path.startsWith('/')) {
70
+ errors.push('Path must be a string starting with /');
71
+ }
72
+ }
73
+
74
+ return {
75
+ valid: errors.length === 0,
76
+ errors
77
+ };
78
+ }
79
+
80
+ /**
81
+ * Validates a route action configuration
82
+ * @param action Route action configuration to validate
83
+ * @returns { valid: boolean, errors: string[] } Validation result
84
+ */
85
+ export function validateRouteAction(action: IRouteAction): { valid: boolean; errors: string[] } {
86
+ const errors: string[] = [];
87
+
88
+ // Validate action type
89
+ if (!action.type) {
90
+ errors.push('Action type is required');
91
+ } else if (!['forward', 'redirect', 'static', 'block'].includes(action.type)) {
92
+ errors.push(`Invalid action type: ${action.type}`);
93
+ }
94
+
95
+ // Validate target for 'forward' action
96
+ if (action.type === 'forward') {
97
+ if (!action.target) {
98
+ errors.push('Target is required for forward action');
99
+ } else {
100
+ // Validate target host
101
+ if (!action.target.host) {
102
+ errors.push('Target host is required');
103
+ }
104
+
105
+ // Validate target port
106
+ if (!action.target.port || !isValidPort(action.target.port)) {
107
+ errors.push('Valid target port is required');
108
+ }
109
+ }
110
+
111
+ // Validate TLS options for forward actions
112
+ if (action.tls) {
113
+ if (!['passthrough', 'terminate', 'terminate-and-reencrypt'].includes(action.tls.mode)) {
114
+ errors.push(`Invalid TLS mode: ${action.tls.mode}`);
115
+ }
116
+
117
+ // For termination modes, validate certificate
118
+ if (['terminate', 'terminate-and-reencrypt'].includes(action.tls.mode)) {
119
+ if (action.tls.certificate !== 'auto' &&
120
+ (!action.tls.certificate || !action.tls.certificate.key || !action.tls.certificate.cert)) {
121
+ errors.push('Certificate must be "auto" or an object with key and cert properties');
122
+ }
123
+ }
124
+ }
125
+ }
126
+
127
+ // Validate redirect for 'redirect' action
128
+ if (action.type === 'redirect') {
129
+ if (!action.redirect) {
130
+ errors.push('Redirect configuration is required for redirect action');
131
+ } else {
132
+ if (!action.redirect.to) {
133
+ errors.push('Redirect target (to) is required');
134
+ }
135
+
136
+ if (action.redirect.status &&
137
+ ![301, 302, 303, 307, 308].includes(action.redirect.status)) {
138
+ errors.push('Invalid redirect status code');
139
+ }
140
+ }
141
+ }
142
+
143
+ // Validate static file config for 'static' action
144
+ if (action.type === 'static') {
145
+ if (!action.static) {
146
+ errors.push('Static file configuration is required for static action');
147
+ } else {
148
+ if (!action.static.root) {
149
+ errors.push('Static file root directory is required');
150
+ }
151
+ }
152
+ }
153
+
154
+ return {
155
+ valid: errors.length === 0,
156
+ errors
157
+ };
158
+ }
159
+
160
+ /**
161
+ * Validates a complete route configuration
162
+ * @param route Route configuration to validate
163
+ * @returns { valid: boolean, errors: string[] } Validation result
164
+ */
165
+ export function validateRouteConfig(route: IRouteConfig): { valid: boolean; errors: string[] } {
166
+ const errors: string[] = [];
167
+
168
+ // Check for required properties
169
+ if (!route.match) {
170
+ errors.push('Route match configuration is required');
171
+ }
172
+
173
+ if (!route.action) {
174
+ errors.push('Route action configuration is required');
175
+ }
176
+
177
+ // Validate match configuration
178
+ if (route.match) {
179
+ const matchValidation = validateRouteMatch(route.match);
180
+ if (!matchValidation.valid) {
181
+ errors.push(...matchValidation.errors.map(err => `Match: ${err}`));
182
+ }
183
+ }
184
+
185
+ // Validate action configuration
186
+ if (route.action) {
187
+ const actionValidation = validateRouteAction(route.action);
188
+ if (!actionValidation.valid) {
189
+ errors.push(...actionValidation.errors.map(err => `Action: ${err}`));
190
+ }
191
+ }
192
+
193
+ // Ensure the route has a unique identifier
194
+ if (!route.id && !route.name) {
195
+ errors.push('Route should have either an id or a name for identification');
196
+ }
197
+
198
+ return {
199
+ valid: errors.length === 0,
200
+ errors
201
+ };
202
+ }
203
+
204
+ /**
205
+ * Validate an array of route configurations
206
+ * @param routes Array of route configurations to validate
207
+ * @returns { valid: boolean, errors: { index: number, errors: string[] }[] } Validation result
208
+ */
209
+ export function validateRoutes(routes: IRouteConfig[]): {
210
+ valid: boolean;
211
+ errors: { index: number; errors: string[] }[]
212
+ } {
213
+ const results: { index: number; errors: string[] }[] = [];
214
+
215
+ routes.forEach((route, index) => {
216
+ const validation = validateRouteConfig(route);
217
+ if (!validation.valid) {
218
+ results.push({
219
+ index,
220
+ errors: validation.errors
221
+ });
222
+ }
223
+ });
224
+
225
+ return {
226
+ valid: results.length === 0,
227
+ errors: results
228
+ };
229
+ }
230
+
231
+ /**
232
+ * Check if a route configuration has the required properties for a specific action type
233
+ * @param route Route configuration to check
234
+ * @param actionType Expected action type
235
+ * @returns True if the route has the necessary properties, false otherwise
236
+ */
237
+ export function hasRequiredPropertiesForAction(route: IRouteConfig, actionType: string): boolean {
238
+ if (!route.action || route.action.type !== actionType) {
239
+ return false;
240
+ }
241
+
242
+ switch (actionType) {
243
+ case 'forward':
244
+ return !!route.action.target && !!route.action.target.host && !!route.action.target.port;
245
+ case 'redirect':
246
+ return !!route.action.redirect && !!route.action.redirect.to;
247
+ case 'static':
248
+ return !!route.action.static && !!route.action.static.root;
249
+ case 'block':
250
+ return true; // Block action doesn't require additional properties
251
+ default:
252
+ return false;
253
+ }
254
+ }
255
+
256
+ /**
257
+ * Throws an error if the route config is invalid, returns the config if valid
258
+ * Useful for immediate validation when creating routes
259
+ * @param route Route configuration to validate
260
+ * @returns The validated route configuration
261
+ * @throws Error if the route configuration is invalid
262
+ */
263
+ export function assertValidRoute(route: IRouteConfig): IRouteConfig {
264
+ const validation = validateRouteConfig(route);
265
+ if (!validation.valid) {
266
+ throw new Error(`Invalid route configuration: ${validation.errors.join(', ')}`);
267
+ }
268
+ return route;
269
+ }
@@ -1,28 +0,0 @@
1
- import type { IForwardConfig } from './forwarding-types.js';
2
-
3
- /**
4
- * Domain configuration with unified forwarding configuration
5
- */
6
- export interface IDomainConfig {
7
- // Core properties - domain patterns
8
- domains: string[];
9
-
10
- // Unified forwarding configuration
11
- forwarding: IForwardConfig;
12
- }
13
-
14
- /**
15
- * Helper function to create a domain configuration
16
- */
17
- export function createDomainConfig(
18
- domains: string | string[],
19
- forwarding: IForwardConfig
20
- ): IDomainConfig {
21
- // Normalize domains to an array
22
- const domainArray = Array.isArray(domains) ? domains : [domains];
23
-
24
- return {
25
- domains: domainArray,
26
- forwarding
27
- };
28
- }
@@ -1,283 +0,0 @@
1
- import * as plugins from '../../plugins.js';
2
- import type { IDomainConfig } from './domain-config.js';
3
- import { ForwardingHandler } from '../handlers/base-handler.js';
4
- import { ForwardingHandlerEvents } from './forwarding-types.js';
5
- import { ForwardingHandlerFactory } from '../factory/forwarding-factory.js';
6
-
7
- /**
8
- * Events emitted by the DomainManager
9
- */
10
- export enum DomainManagerEvents {
11
- DOMAIN_ADDED = 'domain-added',
12
- DOMAIN_REMOVED = 'domain-removed',
13
- DOMAIN_MATCHED = 'domain-matched',
14
- DOMAIN_MATCH_FAILED = 'domain-match-failed',
15
- CERTIFICATE_NEEDED = 'certificate-needed',
16
- CERTIFICATE_LOADED = 'certificate-loaded',
17
- ERROR = 'error'
18
- }
19
-
20
- /**
21
- * Manages domains and their forwarding handlers
22
- */
23
- export class DomainManager extends plugins.EventEmitter {
24
- private domainConfigs: IDomainConfig[] = [];
25
- private domainHandlers: Map<string, ForwardingHandler> = new Map();
26
-
27
- /**
28
- * Create a new DomainManager
29
- * @param initialDomains Optional initial domain configurations
30
- */
31
- constructor(initialDomains?: IDomainConfig[]) {
32
- super();
33
-
34
- if (initialDomains) {
35
- this.setDomainConfigs(initialDomains);
36
- }
37
- }
38
-
39
- /**
40
- * Set or replace all domain configurations
41
- * @param configs Array of domain configurations
42
- */
43
- public async setDomainConfigs(configs: IDomainConfig[]): Promise<void> {
44
- // Clear existing handlers
45
- this.domainHandlers.clear();
46
-
47
- // Store new configurations
48
- this.domainConfigs = [...configs];
49
-
50
- // Initialize handlers for each domain
51
- for (const config of this.domainConfigs) {
52
- await this.createHandlersForDomain(config);
53
- }
54
- }
55
-
56
- /**
57
- * Add a new domain configuration
58
- * @param config The domain configuration to add
59
- */
60
- public async addDomainConfig(config: IDomainConfig): Promise<void> {
61
- // Check if any of these domains already exist
62
- for (const domain of config.domains) {
63
- if (this.domainHandlers.has(domain)) {
64
- // Remove existing handler for this domain
65
- this.domainHandlers.delete(domain);
66
- }
67
- }
68
-
69
- // Add the new configuration
70
- this.domainConfigs.push(config);
71
-
72
- // Create handlers for the new domain
73
- await this.createHandlersForDomain(config);
74
-
75
- this.emit(DomainManagerEvents.DOMAIN_ADDED, {
76
- domains: config.domains,
77
- forwardingType: config.forwarding.type
78
- });
79
- }
80
-
81
- /**
82
- * Remove a domain configuration
83
- * @param domain The domain to remove
84
- * @returns True if the domain was found and removed
85
- */
86
- public removeDomainConfig(domain: string): boolean {
87
- // Find the config that includes this domain
88
- const index = this.domainConfigs.findIndex(config =>
89
- config.domains.includes(domain)
90
- );
91
-
92
- if (index === -1) {
93
- return false;
94
- }
95
-
96
- // Get the config
97
- const config = this.domainConfigs[index];
98
-
99
- // Remove all handlers for this config
100
- for (const domainName of config.domains) {
101
- this.domainHandlers.delete(domainName);
102
- }
103
-
104
- // Remove the config
105
- this.domainConfigs.splice(index, 1);
106
-
107
- this.emit(DomainManagerEvents.DOMAIN_REMOVED, {
108
- domains: config.domains
109
- });
110
-
111
- return true;
112
- }
113
-
114
- /**
115
- * Find the handler for a domain
116
- * @param domain The domain to find a handler for
117
- * @returns The handler or undefined if no match
118
- */
119
- public findHandlerForDomain(domain: string): ForwardingHandler | undefined {
120
- // Try exact match
121
- if (this.domainHandlers.has(domain)) {
122
- return this.domainHandlers.get(domain);
123
- }
124
-
125
- // Try wildcard matches
126
- const wildcardHandler = this.findWildcardHandler(domain);
127
- if (wildcardHandler) {
128
- return wildcardHandler;
129
- }
130
-
131
- // No match found
132
- return undefined;
133
- }
134
-
135
- /**
136
- * Handle a connection for a domain
137
- * @param domain The domain
138
- * @param socket The client socket
139
- * @returns True if the connection was handled
140
- */
141
- public handleConnection(domain: string, socket: plugins.net.Socket): boolean {
142
- const handler = this.findHandlerForDomain(domain);
143
-
144
- if (!handler) {
145
- this.emit(DomainManagerEvents.DOMAIN_MATCH_FAILED, {
146
- domain,
147
- remoteAddress: socket.remoteAddress
148
- });
149
- return false;
150
- }
151
-
152
- this.emit(DomainManagerEvents.DOMAIN_MATCHED, {
153
- domain,
154
- handlerType: handler.constructor.name,
155
- remoteAddress: socket.remoteAddress
156
- });
157
-
158
- // Handle the connection
159
- handler.handleConnection(socket);
160
- return true;
161
- }
162
-
163
- /**
164
- * Handle an HTTP request for a domain
165
- * @param domain The domain
166
- * @param req The HTTP request
167
- * @param res The HTTP response
168
- * @returns True if the request was handled
169
- */
170
- public handleHttpRequest(domain: string, req: plugins.http.IncomingMessage, res: plugins.http.ServerResponse): boolean {
171
- const handler = this.findHandlerForDomain(domain);
172
-
173
- if (!handler) {
174
- this.emit(DomainManagerEvents.DOMAIN_MATCH_FAILED, {
175
- domain,
176
- remoteAddress: req.socket.remoteAddress
177
- });
178
- return false;
179
- }
180
-
181
- this.emit(DomainManagerEvents.DOMAIN_MATCHED, {
182
- domain,
183
- handlerType: handler.constructor.name,
184
- remoteAddress: req.socket.remoteAddress
185
- });
186
-
187
- // Handle the request
188
- handler.handleHttpRequest(req, res);
189
- return true;
190
- }
191
-
192
- /**
193
- * Create handlers for a domain configuration
194
- * @param config The domain configuration
195
- */
196
- private async createHandlersForDomain(config: IDomainConfig): Promise<void> {
197
- try {
198
- // Create a handler for this forwarding configuration
199
- const handler = ForwardingHandlerFactory.createHandler(config.forwarding);
200
-
201
- // Initialize the handler
202
- await handler.initialize();
203
-
204
- // Set up event forwarding
205
- this.setupHandlerEvents(handler, config);
206
-
207
- // Store the handler for each domain in the config
208
- for (const domain of config.domains) {
209
- this.domainHandlers.set(domain, handler);
210
- }
211
- } catch (error) {
212
- this.emit(DomainManagerEvents.ERROR, {
213
- domains: config.domains,
214
- error: error instanceof Error ? error.message : String(error)
215
- });
216
- }
217
- }
218
-
219
- /**
220
- * Set up event forwarding from a handler
221
- * @param handler The handler
222
- * @param config The domain configuration for this handler
223
- */
224
- private setupHandlerEvents(handler: ForwardingHandler, config: IDomainConfig): void {
225
- // Forward relevant events
226
- handler.on(ForwardingHandlerEvents.CERTIFICATE_NEEDED, (data) => {
227
- this.emit(DomainManagerEvents.CERTIFICATE_NEEDED, {
228
- ...data,
229
- domains: config.domains
230
- });
231
- });
232
-
233
- handler.on(ForwardingHandlerEvents.CERTIFICATE_LOADED, (data) => {
234
- this.emit(DomainManagerEvents.CERTIFICATE_LOADED, {
235
- ...data,
236
- domains: config.domains
237
- });
238
- });
239
-
240
- handler.on(ForwardingHandlerEvents.ERROR, (data) => {
241
- this.emit(DomainManagerEvents.ERROR, {
242
- ...data,
243
- domains: config.domains
244
- });
245
- });
246
- }
247
-
248
- /**
249
- * Find a handler for a domain using wildcard matching
250
- * @param domain The domain to find a handler for
251
- * @returns The handler or undefined if no match
252
- */
253
- private findWildcardHandler(domain: string): ForwardingHandler | undefined {
254
- // Exact match already checked in findHandlerForDomain
255
-
256
- // Try subdomain wildcard (*.example.com)
257
- if (domain.includes('.')) {
258
- const parts = domain.split('.');
259
- if (parts.length > 2) {
260
- const wildcardDomain = `*.${parts.slice(1).join('.')}`;
261
- if (this.domainHandlers.has(wildcardDomain)) {
262
- return this.domainHandlers.get(wildcardDomain);
263
- }
264
- }
265
- }
266
-
267
- // Try full wildcard
268
- if (this.domainHandlers.has('*')) {
269
- return this.domainHandlers.get('*');
270
- }
271
-
272
- // No match found
273
- return undefined;
274
- }
275
-
276
- /**
277
- * Get all domain configurations
278
- * @returns Array of domain configurations
279
- */
280
- public getDomainConfigs(): IDomainConfig[] {
281
- return [...this.domainConfigs];
282
- }
283
- }