@serve.zone/dcrouter 11.0.39 → 11.0.40

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 (50) hide show
  1. package/dist_serve/bundle.js +1 -1
  2. package/dist_ts/errors/base.errors.js +320 -0
  3. package/dist_ts/errors/error.codes.d.ts +115 -0
  4. package/dist_ts/errors/error.codes.js +136 -0
  5. package/dist_ts/monitoring/classes.metricsmanager.d.ts +178 -0
  6. package/dist_ts/monitoring/classes.metricsmanager.js +642 -0
  7. package/dist_ts/monitoring/index.d.ts +1 -0
  8. package/dist_ts/monitoring/index.js +2 -0
  9. package/dist_ts/opsserver/classes.opsserver.d.ts +37 -0
  10. package/dist_ts/opsserver/classes.opsserver.js +85 -0
  11. package/dist_ts/opsserver/handlers/api-token.handler.d.ts +6 -0
  12. package/dist_ts/opsserver/handlers/api-token.handler.js +62 -0
  13. package/dist_ts/opsserver/handlers/certificate.handler.d.ts +32 -0
  14. package/dist_ts/opsserver/handlers/certificate.handler.js +421 -0
  15. package/dist_ts/opsserver/handlers/email-ops.handler.d.ts +30 -0
  16. package/dist_ts/opsserver/handlers/email-ops.handler.js +227 -0
  17. package/dist_ts/opsserver/handlers/index.d.ts +11 -0
  18. package/dist_ts/opsserver/handlers/index.js +12 -0
  19. package/dist_ts/opsserver/handlers/radius.handler.d.ts +6 -0
  20. package/dist_ts/opsserver/handlers/radius.handler.js +295 -0
  21. package/dist_ts/opsserver/handlers/remoteingress.handler.d.ts +6 -0
  22. package/dist_ts/opsserver/handlers/remoteingress.handler.js +156 -0
  23. package/dist_ts/opsserver/handlers/route-management.handler.d.ts +14 -0
  24. package/dist_ts/opsserver/handlers/route-management.handler.js +117 -0
  25. package/dist_ts/opsserver/handlers/security.handler.d.ts +9 -0
  26. package/dist_ts/opsserver/handlers/security.handler.js +231 -0
  27. package/dist_ts/opsserver/handlers/stats.handler.d.ts +11 -0
  28. package/dist_ts/opsserver/handlers/stats.handler.js +399 -0
  29. package/dist_ts/opsserver/helpers/guards.d.ts +27 -0
  30. package/dist_ts/opsserver/helpers/guards.js +43 -0
  31. package/dist_ts/opsserver/index.d.ts +1 -0
  32. package/dist_ts/opsserver/index.js +2 -0
  33. package/dist_ts/radius/classes.accounting.manager.d.ts +218 -0
  34. package/dist_ts/radius/classes.accounting.manager.js +417 -0
  35. package/dist_ts/radius/classes.radius.server.d.ts +171 -0
  36. package/dist_ts/radius/classes.radius.server.js +385 -0
  37. package/dist_ts/radius/classes.vlan.manager.d.ts +128 -0
  38. package/dist_ts/radius/classes.vlan.manager.js +279 -0
  39. package/dist_ts/radius/index.d.ts +13 -0
  40. package/dist_ts/radius/index.js +14 -0
  41. package/dist_ts/remoteingress/classes.remoteingress-manager.d.ts +82 -0
  42. package/dist_ts/remoteingress/classes.remoteingress-manager.js +227 -0
  43. package/dist_ts/remoteingress/classes.tunnel-manager.d.ts +59 -0
  44. package/dist_ts/remoteingress/classes.tunnel-manager.js +165 -0
  45. package/dist_ts/remoteingress/index.d.ts +2 -0
  46. package/dist_ts/remoteingress/index.js +3 -0
  47. package/dist_ts_web/00_commitinfo_data.js +1 -1
  48. package/package.json +2 -2
  49. package/ts/00_commitinfo_data.ts +1 -1
  50. package/ts_web/00_commitinfo_data.ts +1 -1
@@ -0,0 +1,421 @@
1
+ import * as plugins from '../../plugins.js';
2
+ import * as interfaces from '../../../dist_ts_interfaces/index.js';
3
+ export class CertificateHandler {
4
+ opsServerRef;
5
+ constructor(opsServerRef) {
6
+ this.opsServerRef = opsServerRef;
7
+ this.registerHandlers();
8
+ }
9
+ registerHandlers() {
10
+ const viewRouter = this.opsServerRef.viewRouter;
11
+ const adminRouter = this.opsServerRef.adminRouter;
12
+ // ---- Read endpoints (viewRouter — valid identity required via middleware) ----
13
+ // Get Certificate Overview
14
+ viewRouter.addTypedHandler(new plugins.typedrequest.TypedHandler('getCertificateOverview', async (dataArg) => {
15
+ const certificates = await this.buildCertificateOverview();
16
+ const summary = this.buildSummary(certificates);
17
+ return { certificates, summary };
18
+ }));
19
+ // ---- Write endpoints (adminRouter — admin identity required via middleware) ----
20
+ // Legacy route-based reprovision (backward compat)
21
+ adminRouter.addTypedHandler(new plugins.typedrequest.TypedHandler('reprovisionCertificate', async (dataArg) => {
22
+ return this.reprovisionCertificateByRoute(dataArg.routeName);
23
+ }));
24
+ // Domain-based reprovision (preferred)
25
+ adminRouter.addTypedHandler(new plugins.typedrequest.TypedHandler('reprovisionCertificateDomain', async (dataArg) => {
26
+ return this.reprovisionCertificateDomain(dataArg.domain);
27
+ }));
28
+ // Delete certificate
29
+ adminRouter.addTypedHandler(new plugins.typedrequest.TypedHandler('deleteCertificate', async (dataArg) => {
30
+ return this.deleteCertificate(dataArg.domain);
31
+ }));
32
+ // Export certificate
33
+ adminRouter.addTypedHandler(new plugins.typedrequest.TypedHandler('exportCertificate', async (dataArg) => {
34
+ return this.exportCertificate(dataArg.domain);
35
+ }));
36
+ // Import certificate
37
+ adminRouter.addTypedHandler(new plugins.typedrequest.TypedHandler('importCertificate', async (dataArg) => {
38
+ return this.importCertificate(dataArg.cert);
39
+ }));
40
+ }
41
+ /**
42
+ * Build domain-centric certificate overview.
43
+ * Instead of one row per route, we produce one row per unique domain.
44
+ */
45
+ async buildCertificateOverview() {
46
+ const dcRouter = this.opsServerRef.dcRouterRef;
47
+ const smartProxy = dcRouter.smartProxy;
48
+ if (!smartProxy)
49
+ return [];
50
+ const routes = smartProxy.routeManager.getRoutes();
51
+ // Phase 1: Collect unique domains with their associated route info
52
+ const domainMap = new Map();
53
+ for (const route of routes) {
54
+ if (!route.name)
55
+ continue;
56
+ const tls = route.action?.tls;
57
+ if (!tls)
58
+ continue;
59
+ // Skip passthrough routes - they don't manage certificates
60
+ if (tls.mode === 'passthrough')
61
+ continue;
62
+ const routeDomains = route.match.domains
63
+ ? (Array.isArray(route.match.domains) ? route.match.domains : [route.match.domains])
64
+ : [];
65
+ // Determine source
66
+ let source = 'none';
67
+ if (tls.certificate === 'auto') {
68
+ if (smartProxy.settings.certProvisionFunction) {
69
+ source = 'provision-function';
70
+ }
71
+ else {
72
+ source = 'acme';
73
+ }
74
+ }
75
+ else if (tls.certificate && typeof tls.certificate === 'object') {
76
+ source = 'static';
77
+ }
78
+ const canReprovision = source === 'acme' || source === 'provision-function';
79
+ const tlsMode = tls.mode;
80
+ for (const domain of routeDomains) {
81
+ const existing = domainMap.get(domain);
82
+ if (existing) {
83
+ // Add this route name to the existing domain entry
84
+ if (!existing.routeNames.includes(route.name)) {
85
+ existing.routeNames.push(route.name);
86
+ }
87
+ // Upgrade source if more specific
88
+ if (existing.source === 'none' && source !== 'none') {
89
+ existing.source = source;
90
+ existing.canReprovision = canReprovision;
91
+ }
92
+ }
93
+ else {
94
+ domainMap.set(domain, {
95
+ routeNames: [route.name],
96
+ source,
97
+ tlsMode,
98
+ canReprovision,
99
+ });
100
+ }
101
+ }
102
+ }
103
+ // Phase 2: Resolve status for each unique domain
104
+ const certificates = [];
105
+ for (const [domain, info] of domainMap) {
106
+ let status = 'unknown';
107
+ let expiryDate;
108
+ let issuedAt;
109
+ let issuer;
110
+ let error;
111
+ // Check event-based status from certificateStatusMap (now keyed by domain)
112
+ const eventStatus = dcRouter.certificateStatusMap.get(domain);
113
+ if (eventStatus) {
114
+ status = eventStatus.status;
115
+ expiryDate = eventStatus.expiryDate;
116
+ issuedAt = eventStatus.issuedAt;
117
+ error = eventStatus.error;
118
+ if (eventStatus.source) {
119
+ issuer = eventStatus.source;
120
+ }
121
+ }
122
+ // Try SmartProxy certificate status if no event data
123
+ if (status === 'unknown' && info.routeNames.length > 0) {
124
+ try {
125
+ const rustStatus = await smartProxy.getCertificateStatus(info.routeNames[0]);
126
+ if (rustStatus) {
127
+ if (rustStatus.expiryDate)
128
+ expiryDate = rustStatus.expiryDate;
129
+ if (rustStatus.issuer)
130
+ issuer = rustStatus.issuer;
131
+ if (rustStatus.issuedAt)
132
+ issuedAt = rustStatus.issuedAt;
133
+ if (rustStatus.status === 'valid' || rustStatus.status === 'expired') {
134
+ status = rustStatus.status;
135
+ }
136
+ }
137
+ }
138
+ catch {
139
+ // Rust bridge may not support this command yet — ignore
140
+ }
141
+ }
142
+ // Check persisted cert data from StorageManager
143
+ if (status === 'unknown') {
144
+ const cleanDomain = domain.replace(/^\*\.?/, '');
145
+ let certData = await dcRouter.storageManager.getJSON(`/certs/${cleanDomain}`);
146
+ if (!certData) {
147
+ // Also check certStore path (proxy-certs)
148
+ certData = await dcRouter.storageManager.getJSON(`/proxy-certs/${domain}`);
149
+ }
150
+ if (certData?.validUntil) {
151
+ expiryDate = new Date(certData.validUntil).toISOString();
152
+ if (certData.created) {
153
+ issuedAt = new Date(certData.created).toISOString();
154
+ }
155
+ issuer = 'smartacme-dns-01';
156
+ }
157
+ else if (certData?.publicKey) {
158
+ // certStore has the cert — parse PEM for expiry
159
+ try {
160
+ const x509 = new plugins.crypto.X509Certificate(certData.publicKey);
161
+ expiryDate = new Date(x509.validTo).toISOString();
162
+ issuedAt = new Date(x509.validFrom).toISOString();
163
+ }
164
+ catch { /* PEM parsing failed */ }
165
+ status = 'valid';
166
+ issuer = 'cert-store';
167
+ }
168
+ else if (certData) {
169
+ status = 'valid';
170
+ issuer = 'cert-store';
171
+ }
172
+ }
173
+ // Compute status from expiry date
174
+ if (expiryDate && (status === 'valid' || status === 'unknown')) {
175
+ const expiry = new Date(expiryDate);
176
+ const now = new Date();
177
+ const daysUntilExpiry = (expiry.getTime() - now.getTime()) / (1000 * 60 * 60 * 24);
178
+ if (daysUntilExpiry < 0) {
179
+ status = 'expired';
180
+ }
181
+ else if (daysUntilExpiry < 30) {
182
+ status = 'expiring';
183
+ }
184
+ else {
185
+ status = 'valid';
186
+ }
187
+ }
188
+ // Static certs with no other info default to 'valid'
189
+ if (info.source === 'static' && status === 'unknown') {
190
+ status = 'valid';
191
+ }
192
+ // ACME/provision-function routes with no cert data are still provisioning
193
+ if (status === 'unknown' && (info.source === 'acme' || info.source === 'provision-function')) {
194
+ status = 'provisioning';
195
+ }
196
+ // Phase 3: Attach backoff info
197
+ let backoffInfo;
198
+ if (dcRouter.certProvisionScheduler) {
199
+ const bi = await dcRouter.certProvisionScheduler.getBackoffInfo(domain);
200
+ if (bi) {
201
+ backoffInfo = bi;
202
+ }
203
+ }
204
+ certificates.push({
205
+ domain,
206
+ routeNames: info.routeNames,
207
+ status,
208
+ source: info.source,
209
+ tlsMode: info.tlsMode,
210
+ expiryDate,
211
+ issuer,
212
+ issuedAt,
213
+ error,
214
+ canReprovision: info.canReprovision,
215
+ backoffInfo,
216
+ });
217
+ }
218
+ return certificates;
219
+ }
220
+ buildSummary(certificates) {
221
+ const summary = { total: 0, valid: 0, expiring: 0, expired: 0, failed: 0, unknown: 0 };
222
+ summary.total = certificates.length;
223
+ for (const cert of certificates) {
224
+ switch (cert.status) {
225
+ case 'valid':
226
+ summary.valid++;
227
+ break;
228
+ case 'expiring':
229
+ summary.expiring++;
230
+ break;
231
+ case 'expired':
232
+ summary.expired++;
233
+ break;
234
+ case 'failed':
235
+ summary.failed++;
236
+ break;
237
+ case 'provisioning': // count as unknown
238
+ case 'unknown':
239
+ summary.unknown++;
240
+ break;
241
+ }
242
+ }
243
+ return summary;
244
+ }
245
+ /**
246
+ * Legacy route-based reprovisioning
247
+ */
248
+ async reprovisionCertificateByRoute(routeName) {
249
+ const dcRouter = this.opsServerRef.dcRouterRef;
250
+ const smartProxy = dcRouter.smartProxy;
251
+ if (!smartProxy) {
252
+ return { success: false, message: 'SmartProxy is not running' };
253
+ }
254
+ try {
255
+ await smartProxy.provisionCertificate(routeName);
256
+ // Clear event-based status for domains in this route
257
+ for (const [domain, entry] of dcRouter.certificateStatusMap) {
258
+ if (entry.routeNames.includes(routeName)) {
259
+ dcRouter.certificateStatusMap.delete(domain);
260
+ }
261
+ }
262
+ return { success: true, message: `Certificate reprovisioning triggered for route '${routeName}'` };
263
+ }
264
+ catch (err) {
265
+ return { success: false, message: err.message || 'Failed to reprovision certificate' };
266
+ }
267
+ }
268
+ /**
269
+ * Domain-based reprovisioning — clears backoff first, then triggers provision
270
+ */
271
+ async reprovisionCertificateDomain(domain) {
272
+ const dcRouter = this.opsServerRef.dcRouterRef;
273
+ const smartProxy = dcRouter.smartProxy;
274
+ if (!smartProxy) {
275
+ return { success: false, message: 'SmartProxy is not running' };
276
+ }
277
+ // Clear backoff for this domain (user override)
278
+ if (dcRouter.certProvisionScheduler) {
279
+ await dcRouter.certProvisionScheduler.clearBackoff(domain);
280
+ }
281
+ // Clear status map entry so it gets refreshed
282
+ dcRouter.certificateStatusMap.delete(domain);
283
+ // Try to provision via SmartAcme directly
284
+ if (dcRouter.smartAcme) {
285
+ try {
286
+ await dcRouter.smartAcme.getCertificateForDomain(domain);
287
+ return { success: true, message: `Certificate reprovisioning triggered for domain '${domain}'` };
288
+ }
289
+ catch (err) {
290
+ return { success: false, message: err.message || `Failed to reprovision certificate for ${domain}` };
291
+ }
292
+ }
293
+ // Fallback: try provisioning via the first matching route
294
+ const routeNames = dcRouter.findRouteNamesForDomain(domain);
295
+ if (routeNames.length > 0) {
296
+ try {
297
+ await smartProxy.provisionCertificate(routeNames[0]);
298
+ return { success: true, message: `Certificate reprovisioning triggered for domain '${domain}' via route '${routeNames[0]}'` };
299
+ }
300
+ catch (err) {
301
+ return { success: false, message: err.message || `Failed to reprovision certificate for ${domain}` };
302
+ }
303
+ }
304
+ return { success: false, message: `No routes found for domain '${domain}'` };
305
+ }
306
+ /**
307
+ * Delete certificate data for a domain from storage
308
+ */
309
+ async deleteCertificate(domain) {
310
+ const dcRouter = this.opsServerRef.dcRouterRef;
311
+ const cleanDomain = domain.replace(/^\*\.?/, '');
312
+ // Delete from all known storage paths
313
+ const paths = [
314
+ `/proxy-certs/${domain}`,
315
+ `/proxy-certs/${cleanDomain}`,
316
+ `/certs/${cleanDomain}`,
317
+ ];
318
+ for (const path of paths) {
319
+ try {
320
+ await dcRouter.storageManager.delete(path);
321
+ }
322
+ catch {
323
+ // Path may not exist — ignore
324
+ }
325
+ }
326
+ // Clear from in-memory status map
327
+ dcRouter.certificateStatusMap.delete(domain);
328
+ // Clear backoff info
329
+ if (dcRouter.certProvisionScheduler) {
330
+ await dcRouter.certProvisionScheduler.clearBackoff(domain);
331
+ }
332
+ return { success: true, message: `Certificate data deleted for '${domain}'` };
333
+ }
334
+ /**
335
+ * Export certificate data for a domain as ICert-shaped JSON
336
+ */
337
+ async exportCertificate(domain) {
338
+ const dcRouter = this.opsServerRef.dcRouterRef;
339
+ const cleanDomain = domain.replace(/^\*\.?/, '');
340
+ // Try SmartAcme /certs/ path first (has full ICert fields)
341
+ let certData = await dcRouter.storageManager.getJSON(`/certs/${cleanDomain}`);
342
+ if (certData && certData.publicKey && certData.privateKey) {
343
+ return {
344
+ success: true,
345
+ cert: {
346
+ id: certData.id || plugins.crypto.randomUUID(),
347
+ domainName: certData.domainName || domain,
348
+ created: certData.created || Date.now(),
349
+ validUntil: certData.validUntil || 0,
350
+ privateKey: certData.privateKey,
351
+ publicKey: certData.publicKey,
352
+ csr: certData.csr || '',
353
+ },
354
+ };
355
+ }
356
+ // Fallback: try /proxy-certs/ with original domain
357
+ certData = await dcRouter.storageManager.getJSON(`/proxy-certs/${domain}`);
358
+ if (!certData || !certData.publicKey) {
359
+ // Try with clean domain
360
+ certData = await dcRouter.storageManager.getJSON(`/proxy-certs/${cleanDomain}`);
361
+ }
362
+ if (certData && certData.publicKey && certData.privateKey) {
363
+ return {
364
+ success: true,
365
+ cert: {
366
+ id: plugins.crypto.randomUUID(),
367
+ domainName: domain,
368
+ created: certData.validFrom || Date.now(),
369
+ validUntil: certData.validUntil || 0,
370
+ privateKey: certData.privateKey,
371
+ publicKey: certData.publicKey,
372
+ csr: '',
373
+ },
374
+ };
375
+ }
376
+ return { success: false, message: `No certificate data found for '${domain}'` };
377
+ }
378
+ /**
379
+ * Import a certificate from ICert-shaped JSON
380
+ */
381
+ async importCertificate(cert) {
382
+ // Validate PEM content
383
+ if (!cert.publicKey || !cert.publicKey.includes('-----BEGIN CERTIFICATE-----')) {
384
+ return { success: false, message: 'Invalid publicKey: must contain a PEM-encoded certificate' };
385
+ }
386
+ if (!cert.privateKey || !cert.privateKey.includes('-----BEGIN')) {
387
+ return { success: false, message: 'Invalid privateKey: must contain a PEM-encoded key' };
388
+ }
389
+ const dcRouter = this.opsServerRef.dcRouterRef;
390
+ const cleanDomain = cert.domainName.replace(/^\*\.?/, '');
391
+ // Save to /certs/ (SmartAcme-compatible path)
392
+ await dcRouter.storageManager.setJSON(`/certs/${cleanDomain}`, {
393
+ id: cert.id,
394
+ domainName: cert.domainName,
395
+ created: cert.created,
396
+ validUntil: cert.validUntil,
397
+ privateKey: cert.privateKey,
398
+ publicKey: cert.publicKey,
399
+ csr: cert.csr || '',
400
+ });
401
+ // Also save to /proxy-certs/ (proxy-cert format)
402
+ await dcRouter.storageManager.setJSON(`/proxy-certs/${cert.domainName}`, {
403
+ domain: cert.domainName,
404
+ publicKey: cert.publicKey,
405
+ privateKey: cert.privateKey,
406
+ ca: undefined,
407
+ validUntil: cert.validUntil,
408
+ validFrom: cert.created,
409
+ });
410
+ // Update in-memory status map
411
+ dcRouter.certificateStatusMap.set(cert.domainName, {
412
+ status: 'valid',
413
+ source: 'static',
414
+ expiryDate: cert.validUntil ? new Date(cert.validUntil).toISOString() : undefined,
415
+ issuedAt: cert.created ? new Date(cert.created).toISOString() : undefined,
416
+ routeNames: [],
417
+ });
418
+ return { success: true, message: `Certificate imported for '${cert.domainName}'` };
419
+ }
420
+ }
421
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2VydGlmaWNhdGUuaGFuZGxlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3RzL29wc3NlcnZlci9oYW5kbGVycy9jZXJ0aWZpY2F0ZS5oYW5kbGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sa0JBQWtCLENBQUM7QUFFNUMsT0FBTyxLQUFLLFVBQVUsTUFBTSxpQ0FBaUMsQ0FBQztBQUU5RCxNQUFNLE9BQU8sa0JBQWtCO0lBQ1Q7SUFBcEIsWUFBb0IsWUFBdUI7UUFBdkIsaUJBQVksR0FBWixZQUFZLENBQVc7UUFDekMsSUFBSSxDQUFDLGdCQUFnQixFQUFFLENBQUM7SUFDMUIsQ0FBQztJQUVPLGdCQUFnQjtRQUN0QixNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDLFVBQVUsQ0FBQztRQUNoRCxNQUFNLFdBQVcsR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDLFdBQVcsQ0FBQztRQUVsRCxpRkFBaUY7UUFFakYsMkJBQTJCO1FBQzNCLFVBQVUsQ0FBQyxlQUFlLENBQ3hCLElBQUksT0FBTyxDQUFDLFlBQVksQ0FBQyxZQUFZLENBQ25DLHdCQUF3QixFQUN4QixLQUFLLEVBQUUsT0FBTyxFQUFFLEVBQUU7WUFDaEIsTUFBTSxZQUFZLEdBQUcsTUFBTSxJQUFJLENBQUMsd0JBQXdCLEVBQUUsQ0FBQztZQUMzRCxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDLFlBQVksQ0FBQyxDQUFDO1lBQ2hELE9BQU8sRUFBRSxZQUFZLEVBQUUsT0FBTyxFQUFFLENBQUM7UUFDbkMsQ0FBQyxDQUNGLENBQ0YsQ0FBQztRQUVGLG1GQUFtRjtRQUVuRixtREFBbUQ7UUFDbkQsV0FBVyxDQUFDLGVBQWUsQ0FDekIsSUFBSSxPQUFPLENBQUMsWUFBWSxDQUFDLFlBQVksQ0FDbkMsd0JBQXdCLEVBQ3hCLEtBQUssRUFBRSxPQUFPLEVBQUUsRUFBRTtZQUNoQixPQUFP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
@@ -0,0 +1,30 @@
1
+ import type { OpsServer } from '../classes.opsserver.js';
2
+ export declare class EmailOpsHandler {
3
+ private opsServerRef;
4
+ constructor(opsServerRef: OpsServer);
5
+ private registerHandlers;
6
+ /**
7
+ * Get all queue items mapped to catalog IEmail format
8
+ */
9
+ private getAllQueueEmails;
10
+ /**
11
+ * Get a single email detail by ID
12
+ */
13
+ private getEmailDetail;
14
+ /**
15
+ * Map a queue item to catalog IEmail format
16
+ */
17
+ private mapQueueItemToEmail;
18
+ /**
19
+ * Map a queue item to catalog IEmailDetail format
20
+ */
21
+ private mapQueueItemToEmailDetail;
22
+ /**
23
+ * Map queue status to catalog TEmailStatus
24
+ */
25
+ private mapStatus;
26
+ /**
27
+ * Format byte size to human-readable string
28
+ */
29
+ private formatSize;
30
+ }