@push.rocks/smartproxy 18.1.0 → 19.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/dist_ts/00_commitinfo_data.js +1 -1
  2. package/dist_ts/certificate/certificate-manager.d.ts +150 -0
  3. package/dist_ts/certificate/certificate-manager.js +505 -0
  4. package/dist_ts/certificate/events/simplified-events.d.ts +56 -0
  5. package/dist_ts/certificate/events/simplified-events.js +13 -0
  6. package/dist_ts/certificate/models/certificate-errors.d.ts +69 -0
  7. package/dist_ts/certificate/models/certificate-errors.js +141 -0
  8. package/dist_ts/certificate/models/certificate-strategy.d.ts +60 -0
  9. package/dist_ts/certificate/models/certificate-strategy.js +73 -0
  10. package/dist_ts/certificate/simplified-certificate-manager.d.ts +150 -0
  11. package/dist_ts/certificate/simplified-certificate-manager.js +501 -0
  12. package/dist_ts/common/eventUtils.d.ts +1 -2
  13. package/dist_ts/common/eventUtils.js +2 -1
  14. package/dist_ts/core/models/common-types.d.ts +1 -1
  15. package/dist_ts/core/models/common-types.js +1 -1
  16. package/dist_ts/core/utils/event-utils.d.ts +9 -9
  17. package/dist_ts/core/utils/event-utils.js +6 -14
  18. package/dist_ts/http/index.d.ts +1 -9
  19. package/dist_ts/http/index.js +5 -11
  20. package/dist_ts/http/models/http-types.d.ts +13 -1
  21. package/dist_ts/http/models/http-types.js +1 -1
  22. package/dist_ts/index.d.ts +4 -6
  23. package/dist_ts/index.js +4 -10
  24. package/dist_ts/plugins.d.ts +3 -1
  25. package/dist_ts/plugins.js +4 -2
  26. package/dist_ts/proxies/index.d.ts +3 -2
  27. package/dist_ts/proxies/index.js +4 -5
  28. package/dist_ts/proxies/network-proxy/certificate-manager.d.ts +31 -49
  29. package/dist_ts/proxies/network-proxy/certificate-manager.js +77 -374
  30. package/dist_ts/proxies/network-proxy/models/types.d.ts +12 -1
  31. package/dist_ts/proxies/network-proxy/models/types.js +1 -1
  32. package/dist_ts/proxies/network-proxy/network-proxy.d.ts +2 -7
  33. package/dist_ts/proxies/network-proxy/network-proxy.js +12 -19
  34. package/dist_ts/proxies/network-proxy/simplified-certificate-bridge.d.ts +48 -0
  35. package/dist_ts/proxies/network-proxy/simplified-certificate-bridge.js +76 -0
  36. package/dist_ts/proxies/network-proxy/websocket-handler.js +21 -7
  37. package/dist_ts/proxies/smart-proxy/cert-store.d.ts +10 -0
  38. package/dist_ts/proxies/smart-proxy/cert-store.js +70 -0
  39. package/dist_ts/proxies/smart-proxy/certificate-manager.d.ts +116 -0
  40. package/dist_ts/proxies/smart-proxy/certificate-manager.js +401 -0
  41. package/dist_ts/proxies/smart-proxy/legacy-smart-proxy.d.ts +168 -0
  42. package/dist_ts/proxies/smart-proxy/legacy-smart-proxy.js +642 -0
  43. package/dist_ts/proxies/smart-proxy/models/index.d.ts +1 -1
  44. package/dist_ts/proxies/smart-proxy/models/index.js +1 -5
  45. package/dist_ts/proxies/smart-proxy/models/interfaces.d.ts +13 -1
  46. package/dist_ts/proxies/smart-proxy/models/route-types.d.ts +26 -0
  47. package/dist_ts/proxies/smart-proxy/models/route-types.js +1 -1
  48. package/dist_ts/proxies/smart-proxy/models/simplified-smartproxy-config.d.ts +65 -0
  49. package/dist_ts/proxies/smart-proxy/models/simplified-smartproxy-config.js +31 -0
  50. package/dist_ts/proxies/smart-proxy/models/smartproxy-options.d.ts +102 -0
  51. package/dist_ts/proxies/smart-proxy/models/smartproxy-options.js +73 -0
  52. package/dist_ts/proxies/smart-proxy/network-proxy-bridge.d.ts +10 -44
  53. package/dist_ts/proxies/smart-proxy/network-proxy-bridge.js +66 -202
  54. package/dist_ts/proxies/smart-proxy/route-connection-handler.d.ts +4 -0
  55. package/dist_ts/proxies/smart-proxy/route-connection-handler.js +62 -2
  56. package/dist_ts/proxies/smart-proxy/simplified-smart-proxy.d.ts +41 -0
  57. package/dist_ts/proxies/smart-proxy/simplified-smart-proxy.js +132 -0
  58. package/dist_ts/proxies/smart-proxy/smart-proxy.d.ts +18 -13
  59. package/dist_ts/proxies/smart-proxy/smart-proxy.js +80 -198
  60. package/package.json +5 -3
  61. package/readme.md +13 -5
  62. package/readme.plan.md +1422 -617
  63. package/ts/00_commitinfo_data.ts +1 -1
  64. package/ts/common/eventUtils.ts +2 -2
  65. package/ts/core/models/common-types.ts +1 -1
  66. package/ts/core/utils/event-utils.ts +12 -21
  67. package/ts/http/index.ts +5 -12
  68. package/ts/http/models/http-types.ts +8 -4
  69. package/ts/index.ts +11 -14
  70. package/ts/plugins.ts +4 -1
  71. package/ts/proxies/index.ts +7 -4
  72. package/ts/proxies/network-proxy/certificate-manager.ts +92 -417
  73. package/ts/proxies/network-proxy/models/types.ts +14 -2
  74. package/ts/proxies/network-proxy/network-proxy.ts +13 -19
  75. package/ts/proxies/network-proxy/websocket-handler.ts +18 -6
  76. package/ts/proxies/smart-proxy/cert-store.ts +86 -0
  77. package/ts/proxies/smart-proxy/certificate-manager.ts +506 -0
  78. package/ts/proxies/smart-proxy/models/index.ts +2 -1
  79. package/ts/proxies/smart-proxy/models/interfaces.ts +14 -1
  80. package/ts/proxies/smart-proxy/models/route-types.ts +34 -4
  81. package/ts/proxies/smart-proxy/network-proxy-bridge.ts +86 -239
  82. package/ts/proxies/smart-proxy/route-connection-handler.ts +74 -1
  83. package/ts/proxies/smart-proxy/smart-proxy.ts +106 -224
  84. package/ts/certificate/acme/acme-factory.ts +0 -48
  85. package/ts/certificate/acme/challenge-handler.ts +0 -110
  86. package/ts/certificate/acme/index.ts +0 -3
  87. package/ts/certificate/events/certificate-events.ts +0 -36
  88. package/ts/certificate/index.ts +0 -75
  89. package/ts/certificate/models/certificate-types.ts +0 -109
  90. package/ts/certificate/providers/cert-provisioner.ts +0 -519
  91. package/ts/certificate/providers/index.ts +0 -3
  92. package/ts/certificate/storage/file-storage.ts +0 -234
  93. package/ts/certificate/storage/index.ts +0 -3
  94. package/ts/certificate/utils/certificate-helpers.ts +0 -50
  95. package/ts/http/port80/acme-interfaces.ts +0 -169
  96. package/ts/http/port80/challenge-responder.ts +0 -246
  97. package/ts/http/port80/index.ts +0 -13
  98. package/ts/http/port80/port80-handler.ts +0 -728
@@ -0,0 +1,116 @@
1
+ import { NetworkProxy } from '../network-proxy/index.js';
2
+ import type { IRouteConfig } from './models/route-types.js';
3
+ export interface ICertStatus {
4
+ domain: string;
5
+ status: 'valid' | 'pending' | 'expired' | 'error';
6
+ expiryDate?: Date;
7
+ issueDate?: Date;
8
+ source: 'static' | 'acme';
9
+ error?: string;
10
+ }
11
+ export interface ICertificateData {
12
+ cert: string;
13
+ key: string;
14
+ ca?: string;
15
+ expiryDate: Date;
16
+ issueDate: Date;
17
+ }
18
+ export declare class SmartCertManager {
19
+ private routes;
20
+ private certDir;
21
+ private acmeOptions?;
22
+ private certStore;
23
+ private smartAcme;
24
+ private networkProxy;
25
+ private renewalTimer;
26
+ private pendingChallenges;
27
+ private challengeRoute;
28
+ private certStatus;
29
+ private updateRoutesCallback?;
30
+ constructor(routes: IRouteConfig[], certDir?: string, acmeOptions?: {
31
+ email?: string;
32
+ useProduction?: boolean;
33
+ port?: number;
34
+ });
35
+ setNetworkProxy(networkProxy: NetworkProxy): void;
36
+ /**
37
+ * Set callback for updating routes (used for challenge routes)
38
+ */
39
+ setUpdateRoutesCallback(callback: (routes: IRouteConfig[]) => Promise<void>): void;
40
+ /**
41
+ * Initialize certificate manager and provision certificates for all routes
42
+ */
43
+ initialize(): Promise<void>;
44
+ /**
45
+ * Provision certificates for all routes that need them
46
+ */
47
+ private provisionAllCertificates;
48
+ /**
49
+ * Provision certificate for a single route
50
+ */
51
+ provisionCertificate(route: IRouteConfig): Promise<void>;
52
+ /**
53
+ * Provision ACME certificate
54
+ */
55
+ private provisionAcmeCertificate;
56
+ /**
57
+ * Provision static certificate
58
+ */
59
+ private provisionStaticCertificate;
60
+ /**
61
+ * Apply certificate to NetworkProxy
62
+ */
63
+ private applyCertificate;
64
+ /**
65
+ * Extract domains from route configuration
66
+ */
67
+ private extractDomainsFromRoute;
68
+ /**
69
+ * Check if certificate is valid
70
+ */
71
+ private isCertificateValid;
72
+ /**
73
+ * Add challenge route to SmartProxy
74
+ */
75
+ private addChallengeRoute;
76
+ /**
77
+ * Remove challenge route from SmartProxy
78
+ */
79
+ private removeChallengeRoute;
80
+ /**
81
+ * Start renewal timer
82
+ */
83
+ private startRenewalTimer;
84
+ /**
85
+ * Check and renew certificates that are expiring
86
+ */
87
+ private checkAndRenewCertificates;
88
+ /**
89
+ * Update certificate status
90
+ */
91
+ private updateCertStatus;
92
+ /**
93
+ * Get certificate status for a route
94
+ */
95
+ getCertificateStatus(routeName: string): ICertStatus | undefined;
96
+ /**
97
+ * Force renewal of a certificate
98
+ */
99
+ renewCertificate(routeName: string): Promise<void>;
100
+ /**
101
+ * Setup challenge handler integration with SmartProxy routing
102
+ */
103
+ private setupChallengeHandler;
104
+ /**
105
+ * Stop certificate manager
106
+ */
107
+ stop(): Promise<void>;
108
+ /**
109
+ * Get ACME options (for recreating after route updates)
110
+ */
111
+ getAcmeOptions(): {
112
+ email?: string;
113
+ useProduction?: boolean;
114
+ port?: number;
115
+ } | undefined;
116
+ }
@@ -0,0 +1,401 @@
1
+ import * as plugins from '../../plugins.js';
2
+ import { NetworkProxy } from '../network-proxy/index.js';
3
+ import { CertStore } from './cert-store.js';
4
+ export class SmartCertManager {
5
+ constructor(routes, certDir = './certs', acmeOptions) {
6
+ this.routes = routes;
7
+ this.certDir = certDir;
8
+ this.acmeOptions = acmeOptions;
9
+ this.smartAcme = null;
10
+ this.networkProxy = null;
11
+ this.renewalTimer = null;
12
+ this.pendingChallenges = new Map();
13
+ this.challengeRoute = null;
14
+ // Track certificate status by route name
15
+ this.certStatus = new Map();
16
+ this.certStore = new CertStore(certDir);
17
+ }
18
+ setNetworkProxy(networkProxy) {
19
+ this.networkProxy = networkProxy;
20
+ }
21
+ /**
22
+ * Set callback for updating routes (used for challenge routes)
23
+ */
24
+ setUpdateRoutesCallback(callback) {
25
+ this.updateRoutesCallback = callback;
26
+ }
27
+ /**
28
+ * Initialize certificate manager and provision certificates for all routes
29
+ */
30
+ async initialize() {
31
+ // Create certificate directory if it doesn't exist
32
+ await this.certStore.initialize();
33
+ // Initialize SmartAcme if we have any ACME routes
34
+ const hasAcmeRoutes = this.routes.some(r => r.action.tls?.certificate === 'auto');
35
+ if (hasAcmeRoutes && this.acmeOptions?.email) {
36
+ // Create HTTP-01 challenge handler
37
+ const http01Handler = new plugins.smartacme.handlers.Http01MemoryHandler();
38
+ // Set up challenge handler integration with our routing
39
+ this.setupChallengeHandler(http01Handler);
40
+ // Create SmartAcme instance with built-in MemoryCertManager and HTTP-01 handler
41
+ this.smartAcme = new plugins.smartacme.SmartAcme({
42
+ accountEmail: this.acmeOptions.email,
43
+ environment: this.acmeOptions.useProduction ? 'production' : 'integration',
44
+ certManager: new plugins.smartacme.certmanagers.MemoryCertManager(),
45
+ challengeHandlers: [http01Handler]
46
+ });
47
+ await this.smartAcme.start();
48
+ }
49
+ // Provision certificates for all routes
50
+ await this.provisionAllCertificates();
51
+ // Start renewal timer
52
+ this.startRenewalTimer();
53
+ }
54
+ /**
55
+ * Provision certificates for all routes that need them
56
+ */
57
+ async provisionAllCertificates() {
58
+ const certRoutes = this.routes.filter(r => r.action.tls?.mode === 'terminate' ||
59
+ r.action.tls?.mode === 'terminate-and-reencrypt');
60
+ for (const route of certRoutes) {
61
+ try {
62
+ await this.provisionCertificate(route);
63
+ }
64
+ catch (error) {
65
+ console.error(`Failed to provision certificate for route ${route.name}: ${error}`);
66
+ }
67
+ }
68
+ }
69
+ /**
70
+ * Provision certificate for a single route
71
+ */
72
+ async provisionCertificate(route) {
73
+ const tls = route.action.tls;
74
+ if (!tls || (tls.mode !== 'terminate' && tls.mode !== 'terminate-and-reencrypt')) {
75
+ return;
76
+ }
77
+ const domains = this.extractDomainsFromRoute(route);
78
+ if (domains.length === 0) {
79
+ console.warn(`Route ${route.name} has TLS termination but no domains`);
80
+ return;
81
+ }
82
+ const primaryDomain = domains[0];
83
+ if (tls.certificate === 'auto') {
84
+ // ACME certificate
85
+ await this.provisionAcmeCertificate(route, domains);
86
+ }
87
+ else if (typeof tls.certificate === 'object') {
88
+ // Static certificate
89
+ await this.provisionStaticCertificate(route, primaryDomain, tls.certificate);
90
+ }
91
+ }
92
+ /**
93
+ * Provision ACME certificate
94
+ */
95
+ async provisionAcmeCertificate(route, domains) {
96
+ if (!this.smartAcme) {
97
+ throw new Error('SmartAcme not initialized');
98
+ }
99
+ const primaryDomain = domains[0];
100
+ const routeName = route.name || primaryDomain;
101
+ // Check if we already have a valid certificate
102
+ const existingCert = await this.certStore.getCertificate(routeName);
103
+ if (existingCert && this.isCertificateValid(existingCert)) {
104
+ console.log(`Using existing valid certificate for ${primaryDomain}`);
105
+ await this.applyCertificate(primaryDomain, existingCert);
106
+ this.updateCertStatus(routeName, 'valid', 'acme', existingCert);
107
+ return;
108
+ }
109
+ console.log(`Requesting ACME certificate for ${domains.join(', ')}`);
110
+ this.updateCertStatus(routeName, 'pending', 'acme');
111
+ try {
112
+ // Add challenge route before requesting certificate
113
+ await this.addChallengeRoute();
114
+ try {
115
+ // Use smartacme to get certificate
116
+ const cert = await this.smartAcme.getCertificateForDomain(primaryDomain);
117
+ // SmartAcme's Cert object has these properties:
118
+ // - publicKey: The certificate PEM string
119
+ // - privateKey: The private key PEM string
120
+ // - csr: Certificate signing request
121
+ // - validUntil: Timestamp in milliseconds
122
+ // - domainName: The domain name
123
+ const certData = {
124
+ cert: cert.publicKey,
125
+ key: cert.privateKey,
126
+ ca: cert.publicKey, // Use same as cert for now
127
+ expiryDate: new Date(cert.validUntil),
128
+ issueDate: new Date(cert.created)
129
+ };
130
+ await this.certStore.saveCertificate(routeName, certData);
131
+ await this.applyCertificate(primaryDomain, certData);
132
+ this.updateCertStatus(routeName, 'valid', 'acme', certData);
133
+ console.log(`Successfully provisioned ACME certificate for ${primaryDomain}`);
134
+ }
135
+ catch (error) {
136
+ console.error(`Failed to provision ACME certificate for ${primaryDomain}: ${error}`);
137
+ this.updateCertStatus(routeName, 'error', 'acme', undefined, error.message);
138
+ throw error;
139
+ }
140
+ finally {
141
+ // Always remove challenge route after provisioning
142
+ await this.removeChallengeRoute();
143
+ }
144
+ }
145
+ catch (error) {
146
+ // Handle outer try-catch from adding challenge route
147
+ console.error(`Failed to setup ACME challenge for ${primaryDomain}: ${error}`);
148
+ this.updateCertStatus(routeName, 'error', 'acme', undefined, error.message);
149
+ throw error;
150
+ }
151
+ }
152
+ /**
153
+ * Provision static certificate
154
+ */
155
+ async provisionStaticCertificate(route, domain, certConfig) {
156
+ const routeName = route.name || domain;
157
+ try {
158
+ let key = certConfig.key;
159
+ let cert = certConfig.cert;
160
+ // Load from files if paths are provided
161
+ if (certConfig.keyFile) {
162
+ const keyFile = await plugins.smartfile.SmartFile.fromFilePath(certConfig.keyFile);
163
+ key = keyFile.contents.toString();
164
+ }
165
+ if (certConfig.certFile) {
166
+ const certFile = await plugins.smartfile.SmartFile.fromFilePath(certConfig.certFile);
167
+ cert = certFile.contents.toString();
168
+ }
169
+ // Parse certificate to get dates
170
+ // Parse certificate to get dates - for now just use defaults
171
+ // TODO: Implement actual certificate parsing if needed
172
+ const certInfo = { validTo: new Date(Date.now() + 90 * 24 * 60 * 60 * 1000), validFrom: new Date() };
173
+ const certData = {
174
+ cert,
175
+ key,
176
+ expiryDate: certInfo.validTo,
177
+ issueDate: certInfo.validFrom
178
+ };
179
+ // Save to store for consistency
180
+ await this.certStore.saveCertificate(routeName, certData);
181
+ await this.applyCertificate(domain, certData);
182
+ this.updateCertStatus(routeName, 'valid', 'static', certData);
183
+ console.log(`Successfully loaded static certificate for ${domain}`);
184
+ }
185
+ catch (error) {
186
+ console.error(`Failed to provision static certificate for ${domain}: ${error}`);
187
+ this.updateCertStatus(routeName, 'error', 'static', undefined, error.message);
188
+ throw error;
189
+ }
190
+ }
191
+ /**
192
+ * Apply certificate to NetworkProxy
193
+ */
194
+ async applyCertificate(domain, certData) {
195
+ if (!this.networkProxy) {
196
+ console.warn('NetworkProxy not set, cannot apply certificate');
197
+ return;
198
+ }
199
+ // Apply certificate to NetworkProxy
200
+ this.networkProxy.updateCertificate(domain, certData.cert, certData.key);
201
+ // Also apply for wildcard if it's a subdomain
202
+ if (domain.includes('.') && !domain.startsWith('*.')) {
203
+ const parts = domain.split('.');
204
+ if (parts.length >= 2) {
205
+ const wildcardDomain = `*.${parts.slice(-2).join('.')}`;
206
+ this.networkProxy.updateCertificate(wildcardDomain, certData.cert, certData.key);
207
+ }
208
+ }
209
+ }
210
+ /**
211
+ * Extract domains from route configuration
212
+ */
213
+ extractDomainsFromRoute(route) {
214
+ if (!route.match.domains) {
215
+ return [];
216
+ }
217
+ const domains = Array.isArray(route.match.domains)
218
+ ? route.match.domains
219
+ : [route.match.domains];
220
+ // Filter out wildcards and patterns
221
+ return domains.filter(d => !d.includes('*') &&
222
+ !d.includes('{') &&
223
+ d.includes('.'));
224
+ }
225
+ /**
226
+ * Check if certificate is valid
227
+ */
228
+ isCertificateValid(cert) {
229
+ const now = new Date();
230
+ const expiryThreshold = new Date(now.getTime() + 30 * 24 * 60 * 60 * 1000); // 30 days
231
+ return cert.expiryDate > expiryThreshold;
232
+ }
233
+ /**
234
+ * Add challenge route to SmartProxy
235
+ */
236
+ async addChallengeRoute() {
237
+ if (!this.updateRoutesCallback) {
238
+ throw new Error('No route update callback set');
239
+ }
240
+ if (!this.challengeRoute) {
241
+ throw new Error('Challenge route not initialized');
242
+ }
243
+ const challengeRoute = this.challengeRoute;
244
+ const updatedRoutes = [...this.routes, challengeRoute];
245
+ await this.updateRoutesCallback(updatedRoutes);
246
+ }
247
+ /**
248
+ * Remove challenge route from SmartProxy
249
+ */
250
+ async removeChallengeRoute() {
251
+ if (!this.updateRoutesCallback) {
252
+ return;
253
+ }
254
+ const filteredRoutes = this.routes.filter(r => r.name !== 'acme-challenge');
255
+ await this.updateRoutesCallback(filteredRoutes);
256
+ }
257
+ /**
258
+ * Start renewal timer
259
+ */
260
+ startRenewalTimer() {
261
+ // Check for renewals every 12 hours
262
+ this.renewalTimer = setInterval(() => {
263
+ this.checkAndRenewCertificates();
264
+ }, 12 * 60 * 60 * 1000);
265
+ // Also do an immediate check
266
+ this.checkAndRenewCertificates();
267
+ }
268
+ /**
269
+ * Check and renew certificates that are expiring
270
+ */
271
+ async checkAndRenewCertificates() {
272
+ for (const route of this.routes) {
273
+ if (route.action.tls?.certificate === 'auto') {
274
+ const routeName = route.name || this.extractDomainsFromRoute(route)[0];
275
+ const cert = await this.certStore.getCertificate(routeName);
276
+ if (cert && !this.isCertificateValid(cert)) {
277
+ console.log(`Certificate for ${routeName} needs renewal`);
278
+ try {
279
+ await this.provisionCertificate(route);
280
+ }
281
+ catch (error) {
282
+ console.error(`Failed to renew certificate for ${routeName}: ${error}`);
283
+ }
284
+ }
285
+ }
286
+ }
287
+ }
288
+ /**
289
+ * Update certificate status
290
+ */
291
+ updateCertStatus(routeName, status, source, certData, error) {
292
+ this.certStatus.set(routeName, {
293
+ domain: routeName,
294
+ status,
295
+ source,
296
+ expiryDate: certData?.expiryDate,
297
+ issueDate: certData?.issueDate,
298
+ error
299
+ });
300
+ }
301
+ /**
302
+ * Get certificate status for a route
303
+ */
304
+ getCertificateStatus(routeName) {
305
+ return this.certStatus.get(routeName);
306
+ }
307
+ /**
308
+ * Force renewal of a certificate
309
+ */
310
+ async renewCertificate(routeName) {
311
+ const route = this.routes.find(r => r.name === routeName);
312
+ if (!route) {
313
+ throw new Error(`Route ${routeName} not found`);
314
+ }
315
+ // Remove existing certificate to force renewal
316
+ await this.certStore.deleteCertificate(routeName);
317
+ await this.provisionCertificate(route);
318
+ }
319
+ /**
320
+ * Setup challenge handler integration with SmartProxy routing
321
+ */
322
+ setupChallengeHandler(http01Handler) {
323
+ // Create a challenge route that delegates to SmartAcme's HTTP-01 handler
324
+ const challengeRoute = {
325
+ name: 'acme-challenge',
326
+ priority: 1000, // High priority
327
+ match: {
328
+ ports: 80,
329
+ path: '/.well-known/acme-challenge/*'
330
+ },
331
+ action: {
332
+ type: 'static',
333
+ handler: async (context) => {
334
+ // Extract the token from the path
335
+ const token = context.path?.split('/').pop();
336
+ if (!token) {
337
+ return { status: 404, body: 'Not found' };
338
+ }
339
+ // Create mock request/response objects for SmartAcme
340
+ const mockReq = {
341
+ url: context.path,
342
+ method: 'GET',
343
+ headers: context.headers || {}
344
+ };
345
+ let responseData = null;
346
+ const mockRes = {
347
+ statusCode: 200,
348
+ setHeader: (name, value) => { },
349
+ end: (data) => {
350
+ responseData = data;
351
+ }
352
+ };
353
+ // Use SmartAcme's handler
354
+ const handled = await new Promise((resolve) => {
355
+ http01Handler.handleRequest(mockReq, mockRes, () => {
356
+ resolve(false);
357
+ });
358
+ // Give it a moment to process
359
+ setTimeout(() => resolve(true), 100);
360
+ });
361
+ if (handled && responseData) {
362
+ return {
363
+ status: mockRes.statusCode,
364
+ headers: { 'Content-Type': 'text/plain' },
365
+ body: responseData
366
+ };
367
+ }
368
+ else {
369
+ return { status: 404, body: 'Not found' };
370
+ }
371
+ }
372
+ }
373
+ };
374
+ // Store the challenge route to add it when needed
375
+ this.challengeRoute = challengeRoute;
376
+ }
377
+ /**
378
+ * Stop certificate manager
379
+ */
380
+ async stop() {
381
+ if (this.renewalTimer) {
382
+ clearInterval(this.renewalTimer);
383
+ this.renewalTimer = null;
384
+ }
385
+ if (this.smartAcme) {
386
+ await this.smartAcme.stop();
387
+ }
388
+ // Remove any active challenge routes
389
+ if (this.pendingChallenges.size > 0) {
390
+ this.pendingChallenges.clear();
391
+ await this.removeChallengeRoute();
392
+ }
393
+ }
394
+ /**
395
+ * Get ACME options (for recreating after route updates)
396
+ */
397
+ getAcmeOptions() {
398
+ return this.acmeOptions;
399
+ }
400
+ }
401
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2VydGlmaWNhdGUtbWFuYWdlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3RzL3Byb3hpZXMvc21hcnQtcHJveHkvY2VydGlmaWNhdGUtbWFuYWdlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGtCQUFrQixDQUFDO0FBQzVDLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUV6RCxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFtQjVDLE1BQU0sT0FBTyxnQkFBZ0I7SUFjM0IsWUFDVSxNQUFzQixFQUN0QixVQUFrQixTQUFTLEVBQzNCLFdBSVA7UUFOTyxXQUFNLEdBQU4sTUFBTSxDQUFnQjtRQUN0QixZQUFPLEdBQVAsT0FBTyxDQUFvQjtRQUMzQixnQkFBVyxHQUFYLFdBQVcsQ0FJbEI7UUFuQkssY0FBUyxHQUF1QyxJQUFJLENBQUM7UUFDckQsaUJBQVksR0FBd0IsSUFBSSxDQUFDO1FBQ3pDLGlCQUFZLEdBQTBCLElBQUksQ0FBQztRQUMzQyxzQkFBaUIsR0FBd0IsSUFBSSxHQUFHLEVBQUUsQ0FBQztRQUNuRCxtQkFBYyxHQUF3QixJQUFJLENBQUM7UUFFbkQseUNBQXlDO1FBQ2pDLGVBQVUsR0FBNkIsSUFBSSxHQUFHLEVBQUUsQ0FBQztRQWN2RCxJQUFJLENBQUMsU0FBUyxHQUFHLElBQUksU0FBUyxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQzFDLENBQUM7SUFFTSxlQUFlLENBQUMsWUFBMEI7UUFDL0MsSUFBSSxDQUFDLFlBQVksR0FBRyxZQUFZLENBQUM7SUFDbkMsQ0FBQztJQUVEOztPQUVHO0lBQ0ksdUJBQXVCLENBQUMsUUFBbUQ7UUFDaEYsSUFBSSxDQUFDLG9CQUFvQixHQUFHLFFBQVEsQ0FBQztJQUN2QyxDQUFDO0lBRUQ7O09BRUc7SUFDSSxLQUFLLENBQUMsVUFBVTtRQUNyQixtREFBbUQ7UUFDbkQsTUFBTSxJ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