@serve.zone/dcrouter 9.1.0 → 9.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/dist_serve/bundle.js +1 -1
  2. package/dist_ts/00_commitinfo_data.js +1 -1
  3. package/dist_ts/cache/classes.cache.cleaner.d.ts +47 -0
  4. package/dist_ts/cache/classes.cache.cleaner.js +130 -0
  5. package/dist_ts/cache/classes.cached.document.d.ts +76 -0
  6. package/dist_ts/cache/classes.cached.document.js +100 -0
  7. package/dist_ts/cache/classes.cachedb.d.ts +60 -0
  8. package/dist_ts/cache/classes.cachedb.js +126 -0
  9. package/dist_ts/cache/documents/classes.cached.email.d.ts +125 -0
  10. package/dist_ts/cache/documents/classes.cached.email.js +337 -0
  11. package/dist_ts/cache/documents/classes.cached.ip.reputation.d.ts +119 -0
  12. package/dist_ts/cache/documents/classes.cached.ip.reputation.js +323 -0
  13. package/dist_ts/cache/documents/index.d.ts +2 -0
  14. package/dist_ts/cache/documents/index.js +3 -0
  15. package/dist_ts/cache/index.d.ts +4 -0
  16. package/dist_ts/cache/index.js +7 -0
  17. package/dist_ts/monitoring/classes.metricscache.d.ts +32 -0
  18. package/dist_ts/monitoring/classes.metricscache.js +63 -0
  19. package/dist_ts/opsserver/handlers/admin.handler.d.ts +31 -0
  20. package/dist_ts/opsserver/handlers/admin.handler.js +180 -0
  21. package/dist_ts/opsserver/handlers/config.handler.d.ts +9 -0
  22. package/dist_ts/opsserver/handlers/config.handler.js +169 -0
  23. package/dist_ts/opsserver/handlers/logs.handler.d.ts +17 -0
  24. package/dist_ts/opsserver/handlers/logs.handler.js +215 -0
  25. package/dist_ts/security/classes.securitylogger.js +235 -0
  26. package/dist_ts/storage/classes.storagemanager.d.ts +82 -0
  27. package/dist_ts/storage/classes.storagemanager.js +344 -0
  28. package/dist_ts/storage/index.d.ts +1 -0
  29. package/dist_ts/storage/index.js +3 -0
  30. package/dist_ts_web/00_commitinfo_data.js +1 -1
  31. package/package.json +1 -1
  32. package/ts/00_commitinfo_data.ts +1 -1
  33. package/ts_web/00_commitinfo_data.ts +1 -1
@@ -0,0 +1,180 @@
1
+ import * as plugins from '../../plugins.js';
2
+ import * as interfaces from '../../../dist_ts_interfaces/index.js';
3
+ export class AdminHandler {
4
+ opsServerRef;
5
+ typedrouter = new plugins.typedrequest.TypedRouter();
6
+ // JWT instance
7
+ smartjwtInstance;
8
+ // Simple in-memory user storage (in production, use proper database)
9
+ users = new Map();
10
+ constructor(opsServerRef) {
11
+ this.opsServerRef = opsServerRef;
12
+ // Add this handler's router to the parent
13
+ this.opsServerRef.typedrouter.addTypedRouter(this.typedrouter);
14
+ }
15
+ async initialize() {
16
+ await this.initializeJwt();
17
+ this.initializeDefaultUsers();
18
+ this.registerHandlers();
19
+ }
20
+ async initializeJwt() {
21
+ this.smartjwtInstance = new plugins.smartjwt.SmartJwt();
22
+ await this.smartjwtInstance.init();
23
+ // For development, create new keypair each time
24
+ // In production, load from storage like cloudly does
25
+ await this.smartjwtInstance.createNewKeyPair();
26
+ }
27
+ initializeDefaultUsers() {
28
+ // Add default admin user
29
+ const adminId = plugins.uuid.v4();
30
+ this.users.set(adminId, {
31
+ id: adminId,
32
+ username: 'admin',
33
+ password: 'admin',
34
+ role: 'admin',
35
+ });
36
+ }
37
+ registerHandlers() {
38
+ // Admin Login Handler
39
+ this.typedrouter.addTypedHandler(new plugins.typedrequest.TypedHandler('adminLoginWithUsernameAndPassword', async (dataArg) => {
40
+ try {
41
+ // Find user by username and password
42
+ let user = null;
43
+ for (const [_, userData] of this.users) {
44
+ if (userData.username === dataArg.username && userData.password === dataArg.password) {
45
+ user = userData;
46
+ break;
47
+ }
48
+ }
49
+ if (!user) {
50
+ throw new plugins.typedrequest.TypedResponseError('login failed');
51
+ }
52
+ const expiresAtTimestamp = Date.now() + 3600 * 1000 * 24; // 24 hours
53
+ const jwt = await this.smartjwtInstance.createJWT({
54
+ userId: user.id,
55
+ status: 'loggedIn',
56
+ expiresAt: expiresAtTimestamp,
57
+ });
58
+ return {
59
+ identity: {
60
+ jwt,
61
+ userId: user.id,
62
+ name: user.username,
63
+ expiresAt: expiresAtTimestamp,
64
+ role: user.role,
65
+ type: 'user',
66
+ },
67
+ };
68
+ }
69
+ catch (error) {
70
+ if (error instanceof plugins.typedrequest.TypedResponseError) {
71
+ throw error;
72
+ }
73
+ throw new plugins.typedrequest.TypedResponseError('login failed');
74
+ }
75
+ }));
76
+ // Admin Logout Handler
77
+ this.typedrouter.addTypedHandler(new plugins.typedrequest.TypedHandler('adminLogout', async (dataArg) => {
78
+ // In a real implementation, you might want to blacklist the JWT
79
+ // For now, just return success
80
+ return {
81
+ success: true,
82
+ };
83
+ }));
84
+ // Verify Identity Handler
85
+ this.typedrouter.addTypedHandler(new plugins.typedrequest.TypedHandler('verifyIdentity', async (dataArg) => {
86
+ if (!dataArg.identity?.jwt) {
87
+ return {
88
+ valid: false,
89
+ };
90
+ }
91
+ try {
92
+ const jwtData = await this.smartjwtInstance.verifyJWTAndGetData(dataArg.identity.jwt);
93
+ // Check if expired
94
+ if (jwtData.expiresAt < Date.now()) {
95
+ return {
96
+ valid: false,
97
+ };
98
+ }
99
+ // Check if logged in
100
+ if (jwtData.status !== 'loggedIn') {
101
+ return {
102
+ valid: false,
103
+ };
104
+ }
105
+ // Find user
106
+ const user = this.users.get(jwtData.userId);
107
+ if (!user) {
108
+ return {
109
+ valid: false,
110
+ };
111
+ }
112
+ return {
113
+ valid: true,
114
+ identity: {
115
+ jwt: dataArg.identity.jwt,
116
+ userId: user.id,
117
+ name: user.username,
118
+ expiresAt: jwtData.expiresAt,
119
+ role: user.role,
120
+ type: 'user',
121
+ },
122
+ };
123
+ }
124
+ catch (error) {
125
+ return {
126
+ valid: false,
127
+ };
128
+ }
129
+ }));
130
+ }
131
+ /**
132
+ * Create a guard for valid identity (matching cloudly pattern)
133
+ */
134
+ validIdentityGuard = new plugins.smartguard.Guard(async (dataArg) => {
135
+ if (!dataArg.identity?.jwt) {
136
+ return false;
137
+ }
138
+ try {
139
+ const jwtData = await this.smartjwtInstance.verifyJWTAndGetData(dataArg.identity.jwt);
140
+ // Check expiration
141
+ if (jwtData.expiresAt < Date.now()) {
142
+ return false;
143
+ }
144
+ // Check status
145
+ if (jwtData.status !== 'loggedIn') {
146
+ return false;
147
+ }
148
+ // Verify data hasn't been tampered with
149
+ if (dataArg.identity.expiresAt !== jwtData.expiresAt) {
150
+ return false;
151
+ }
152
+ if (dataArg.identity.userId !== jwtData.userId) {
153
+ return false;
154
+ }
155
+ return true;
156
+ }
157
+ catch (error) {
158
+ return false;
159
+ }
160
+ }, {
161
+ failedHint: 'identity is not valid',
162
+ name: 'validIdentityGuard',
163
+ });
164
+ /**
165
+ * Create a guard for admin identity (matching cloudly pattern)
166
+ */
167
+ adminIdentityGuard = new plugins.smartguard.Guard(async (dataArg) => {
168
+ // First check if identity is valid
169
+ const isValid = await this.validIdentityGuard.exec(dataArg);
170
+ if (!isValid) {
171
+ return false;
172
+ }
173
+ // Check if user has admin role
174
+ return dataArg.identity.role === 'admin';
175
+ }, {
176
+ failedHint: 'user is not admin',
177
+ name: 'adminIdentityGuard',
178
+ });
179
+ }
180
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWRtaW4uaGFuZGxlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3RzL29wc3NlcnZlci9oYW5kbGVycy9hZG1pbi5oYW5kbGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sa0JBQWtCLENBQUM7QUFFNUMsT0FBTyxLQUFLLFVBQVUsTUFBTSxpQ0FBaUMsQ0FBQztBQVE5RCxNQUFNLE9BQU8sWUFBWTtJQWNIO0lBYmIsV0FBVyxHQUFHLElBQUksT0FBTyxDQUFDLFlBQVksQ0FBQyxXQUFXLEVBQUUsQ0FBQztJQUU1RCxlQUFlO0lBQ1IsZ0JBQWdCLENBQXNDO0lBRTdELHFFQUFxRTtJQUM3RCxLQUFLLEdBQUcsSUFBSSxHQUFHLEVBS25CLENBQUM7SUFFTCxZQUFvQixZQUF1QjtRQUF2QixpQkFBWSxHQUFaLFlBQVksQ0FBVztRQUN6QywwQ0FBMEM7UUFDMUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxXQUFXLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQztJQUNqRSxDQUFDO0lBRU0sS0FBSyxDQUFDLFVBQVU7UUFDckIsTUFBTSxJQUFJLENBQUMsYUFBYSxFQUFFLENBQUM7UUFDM0IsSUFBSSxDQUFDLHNCQUFzQixFQUFFLENBQUM7UUFDOUIsSUFBSSxDQUFDLGdCQUFnQixFQUFFLENBQUM7SUFDMUIsQ0FBQztJQUVPLEtBQUssQ0FBQyxhQUFhO1FBQ3pCLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxJQUFJLE9BQU8sQ0FBQyxRQUFRLENBQUMsUUFBUSxFQUFFLENBQUM7UUFDeEQsTUFBTSxJQUFJLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxFQUFFLENBQUM7UUFFbkMsZ0RBQWdEO1FBQ2hELHFEQUFxRDtRQUNyRCxNQUFNLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO0lBQ2pELENBQUM7SUFFTyxzQkFBc0I7UUFDNUIseUJBQXlCO1FB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
@@ -0,0 +1,9 @@
1
+ import * as plugins from '../../plugins.js';
2
+ import type { OpsServer } from '../classes.opsserver.js';
3
+ export declare class ConfigHandler {
4
+ private opsServerRef;
5
+ typedrouter: plugins.typedrequest.TypedRouter;
6
+ constructor(opsServerRef: OpsServer);
7
+ private registerHandlers;
8
+ private getConfiguration;
9
+ }
@@ -0,0 +1,169 @@
1
+ import * as plugins from '../../plugins.js';
2
+ import * as paths from '../../paths.js';
3
+ import * as interfaces from '../../../dist_ts_interfaces/index.js';
4
+ export class ConfigHandler {
5
+ opsServerRef;
6
+ typedrouter = new plugins.typedrequest.TypedRouter();
7
+ constructor(opsServerRef) {
8
+ this.opsServerRef = opsServerRef;
9
+ // Add this handler's router to the parent
10
+ this.opsServerRef.typedrouter.addTypedRouter(this.typedrouter);
11
+ this.registerHandlers();
12
+ }
13
+ registerHandlers() {
14
+ // Get Configuration Handler (read-only)
15
+ this.typedrouter.addTypedHandler(new plugins.typedrequest.TypedHandler('getConfiguration', async (dataArg, toolsArg) => {
16
+ const config = await this.getConfiguration();
17
+ return {
18
+ config,
19
+ section: dataArg.section,
20
+ };
21
+ }));
22
+ }
23
+ async getConfiguration() {
24
+ const dcRouter = this.opsServerRef.dcRouterRef;
25
+ const opts = dcRouter.options;
26
+ const resolvedPaths = dcRouter.resolvedPaths;
27
+ // --- System ---
28
+ const storageBackend = opts.storage?.readFunction
29
+ ? 'custom'
30
+ : opts.storage?.fsPath
31
+ ? 'filesystem'
32
+ : 'memory';
33
+ const system = {
34
+ baseDir: resolvedPaths.dcrouterHomeDir,
35
+ dataDir: resolvedPaths.dataDir,
36
+ publicIp: opts.publicIp || null,
37
+ proxyIps: opts.proxyIps || [],
38
+ uptime: Math.floor(process.uptime()),
39
+ storageBackend,
40
+ storagePath: opts.storage?.fsPath || null,
41
+ };
42
+ // --- SmartProxy ---
43
+ let acmeInfo = null;
44
+ if (opts.smartProxyConfig?.acme) {
45
+ const acme = opts.smartProxyConfig.acme;
46
+ acmeInfo = {
47
+ enabled: acme.enabled !== false,
48
+ accountEmail: acme.accountEmail || '',
49
+ useProduction: acme.useProduction !== false,
50
+ autoRenew: acme.autoRenew !== false,
51
+ renewThresholdDays: acme.renewThresholdDays || 30,
52
+ };
53
+ }
54
+ let routeCount = 0;
55
+ if (dcRouter.routeConfigManager) {
56
+ try {
57
+ const merged = await dcRouter.routeConfigManager.getMergedRoutes();
58
+ routeCount = merged.routes.length;
59
+ }
60
+ catch {
61
+ routeCount = opts.smartProxyConfig?.routes?.length || 0;
62
+ }
63
+ }
64
+ else if (opts.smartProxyConfig?.routes) {
65
+ routeCount = opts.smartProxyConfig.routes.length;
66
+ }
67
+ const smartProxy = {
68
+ enabled: !!dcRouter.smartProxy,
69
+ routeCount,
70
+ acme: acmeInfo,
71
+ };
72
+ // --- Email ---
73
+ let emailDomains = [];
74
+ if (dcRouter.emailServer && dcRouter.emailServer.domainRegistry) {
75
+ emailDomains = dcRouter.emailServer.domainRegistry.getAllDomains();
76
+ }
77
+ else if (opts.emailConfig?.domains) {
78
+ emailDomains = opts.emailConfig.domains.map((d) => typeof d === 'string' ? d : d.domain);
79
+ }
80
+ let portMapping = null;
81
+ if (opts.emailPortConfig?.portMapping) {
82
+ portMapping = {};
83
+ for (const [ext, int] of Object.entries(opts.emailPortConfig.portMapping)) {
84
+ portMapping[String(ext)] = int;
85
+ }
86
+ }
87
+ const email = {
88
+ enabled: !!dcRouter.emailServer,
89
+ ports: opts.emailConfig?.ports || [],
90
+ portMapping,
91
+ hostname: opts.emailConfig?.hostname || null,
92
+ domains: emailDomains,
93
+ emailRouteCount: opts.emailConfig?.routes?.length || 0,
94
+ receivedEmailsPath: opts.emailPortConfig?.receivedEmailsPath || null,
95
+ };
96
+ // --- DNS ---
97
+ const dnsRecords = (opts.dnsRecords || []).map(r => ({
98
+ name: r.name,
99
+ type: r.type,
100
+ value: r.value,
101
+ ttl: r.ttl,
102
+ }));
103
+ const dns = {
104
+ enabled: !!dcRouter.dnsServer,
105
+ port: 53,
106
+ nsDomains: opts.dnsNsDomains || [],
107
+ scopes: opts.dnsScopes || [],
108
+ recordCount: dnsRecords.length,
109
+ records: dnsRecords,
110
+ dnsChallenge: !!opts.dnsChallenge?.cloudflareApiKey,
111
+ };
112
+ // --- TLS ---
113
+ let tlsSource = 'none';
114
+ if (opts.tls?.certPath && opts.tls?.keyPath) {
115
+ tlsSource = 'static';
116
+ }
117
+ else if (opts.smartProxyConfig?.acme?.enabled !== false && opts.smartProxyConfig?.acme) {
118
+ tlsSource = 'acme';
119
+ }
120
+ const tls = {
121
+ contactEmail: opts.tls?.contactEmail || opts.smartProxyConfig?.acme?.accountEmail || null,
122
+ domain: opts.tls?.domain || null,
123
+ source: tlsSource,
124
+ certPath: opts.tls?.certPath || null,
125
+ keyPath: opts.tls?.keyPath || null,
126
+ };
127
+ // --- Cache ---
128
+ const cacheConfig = opts.cacheConfig;
129
+ const cache = {
130
+ enabled: cacheConfig?.enabled !== false,
131
+ storagePath: cacheConfig?.storagePath || resolvedPaths.defaultTsmDbPath,
132
+ dbName: cacheConfig?.dbName || 'dcrouter',
133
+ defaultTTLDays: cacheConfig?.defaultTTLDays || 30,
134
+ cleanupIntervalHours: cacheConfig?.cleanupIntervalHours || 1,
135
+ ttlConfig: cacheConfig?.ttlConfig ? { ...cacheConfig.ttlConfig } : {},
136
+ };
137
+ // --- RADIUS ---
138
+ const radiusCfg = opts.radiusConfig;
139
+ const radius = {
140
+ enabled: !!dcRouter.radiusServer,
141
+ authPort: radiusCfg?.authPort || null,
142
+ acctPort: radiusCfg?.acctPort || null,
143
+ bindAddress: radiusCfg?.bindAddress || null,
144
+ clientCount: radiusCfg?.clients?.length || 0,
145
+ vlanDefaultVlan: radiusCfg?.vlanAssignment?.defaultVlan ?? null,
146
+ vlanAllowUnknownMacs: radiusCfg?.vlanAssignment?.allowUnknownMacs ?? null,
147
+ vlanMappingCount: radiusCfg?.vlanAssignment?.mappings?.length || 0,
148
+ };
149
+ // --- Remote Ingress ---
150
+ const riCfg = opts.remoteIngressConfig;
151
+ const remoteIngress = {
152
+ enabled: !!dcRouter.remoteIngressManager,
153
+ tunnelPort: riCfg?.tunnelPort || null,
154
+ hubDomain: riCfg?.hubDomain || null,
155
+ tlsConfigured: !!(riCfg?.tls?.certPath && riCfg?.tls?.keyPath),
156
+ };
157
+ return {
158
+ system,
159
+ smartProxy,
160
+ email,
161
+ dns,
162
+ tls,
163
+ cache,
164
+ radius,
165
+ remoteIngress,
166
+ };
167
+ }
168
+ }
169
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZmlnLmhhbmRsZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi90cy9vcHNzZXJ2ZXIvaGFuZGxlcnMvY29uZmlnLmhhbmRsZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxrQkFBa0IsQ0FBQztBQUM1QyxPQUFPLEtBQUssS0FBSyxNQUFNLGdCQUFnQixDQUFDO0FBRXhDLE9BQU8sS0FBSyxVQUFVLE1BQU0saUNBQWlDLENBQUM7QUFFOUQsTUFBTSxPQUFPLGFBQWE7SUFHSjtJQUZiLFdBQVcsR0FBRyxJQUFJLE9BQU8sQ0FBQyxZQUFZLENBQUMsV0FBVyxFQUFFLENBQUM7SUFFNUQsWUFBb0IsWUFBdUI7UUFBdkIsaUJBQVksR0FBWixZQUFZLENBQVc7UUFDekMsMENBQTBDO1FBQzFDLElBQUksQ0FBQyxZQUFZLENBQUMsV0FBVyxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUM7UUFDL0QsSUFBSSxDQUFDLGdCQUFnQixFQUFFLENBQUM7SUFDMUIsQ0FBQztJQUVPLGdCQUFnQjtRQUN0Qix3Q0FBd0M7UUFDeEMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxlQUFlLENBQzlCLElBQUksT0FBTyxDQUFDLFlBQVksQ0FBQyxZQUFZLENBQ25DLGtCQUFrQixFQUNsQixLQUFLLEVBQUUsT0FBTyxFQUFFLFFBQVEsRUFBRSxFQUFFO1lBQzFCLE1BQU0sTUFBTSxHQUFHLE1BQU0sSUFBSSxDQUFDLGdCQUFnQixFQUFFLENBQUM7WUFDN0MsT0FBTztnQkFDTCxNQUFNO2dCQUNOLE9BQU8sRUFBRSxPQUFPLENBQUMsT0FBTzthQUN6QixDQUFDO1FBQ0osQ0FBQyxDQUNGLENBQ0YsQ0FBQztJQUNKLENBQUM7SUFFTyxLQUFLLENBQUMsZ0JBQWdCO1FBQzVCLE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxZQUFZLENBQUMsV0FBVyxDQUFDO1FBQy9DLE1BQU0sSUFBSSxH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
@@ -0,0 +1,17 @@
1
+ import * as plugins from '../../plugins.js';
2
+ import type { OpsServer } from '../classes.opsserver.js';
3
+ export declare class LogsHandler {
4
+ private opsServerRef;
5
+ typedrouter: plugins.typedrequest.TypedRouter;
6
+ constructor(opsServerRef: OpsServer);
7
+ private registerHandlers;
8
+ private static mapLogLevel;
9
+ private static deriveCategory;
10
+ private getRecentLogs;
11
+ /**
12
+ * Add a log destination to the base logger that pushes entries
13
+ * to all connected ops_dashboard TypedSocket clients.
14
+ */
15
+ private setupLogPushDestination;
16
+ private setupLogStream;
17
+ }
@@ -0,0 +1,215 @@
1
+ import * as plugins from '../../plugins.js';
2
+ import * as interfaces from '../../../dist_ts_interfaces/index.js';
3
+ import { logBuffer, baseLogger } from '../../logger.js';
4
+ export class LogsHandler {
5
+ opsServerRef;
6
+ typedrouter = new plugins.typedrequest.TypedRouter();
7
+ constructor(opsServerRef) {
8
+ this.opsServerRef = opsServerRef;
9
+ // Add this handler's router to the parent
10
+ this.opsServerRef.typedrouter.addTypedRouter(this.typedrouter);
11
+ this.registerHandlers();
12
+ this.setupLogPushDestination();
13
+ }
14
+ registerHandlers() {
15
+ // Get Recent Logs Handler
16
+ this.typedrouter.addTypedHandler(new plugins.typedrequest.TypedHandler('getRecentLogs', async (dataArg, toolsArg) => {
17
+ const logs = await this.getRecentLogs(dataArg.level, dataArg.category, dataArg.limit || 100, dataArg.offset || 0, dataArg.search, dataArg.timeRange);
18
+ return {
19
+ logs,
20
+ total: logs.length, // TODO: Implement proper total count
21
+ hasMore: false, // TODO: Implement proper pagination
22
+ };
23
+ }));
24
+ // Get Log Stream Handler
25
+ this.typedrouter.addTypedHandler(new plugins.typedrequest.TypedHandler('getLogStream', async (dataArg, toolsArg) => {
26
+ // Create a virtual stream for log streaming
27
+ const virtualStream = new plugins.typedrequest.VirtualStream();
28
+ // Set up log streaming
29
+ const streamLogs = this.setupLogStream(virtualStream, dataArg.filters?.level, dataArg.filters?.category, dataArg.follow);
30
+ // Start streaming
31
+ streamLogs.start();
32
+ // VirtualStream handles cleanup automatically
33
+ return {
34
+ logStream: virtualStream, // Cast to IVirtualStream interface
35
+ };
36
+ }));
37
+ }
38
+ static mapLogLevel(smartlogLevel) {
39
+ switch (smartlogLevel) {
40
+ case 'silly':
41
+ case 'debug':
42
+ return 'debug';
43
+ case 'warn':
44
+ return 'warn';
45
+ case 'error':
46
+ return 'error';
47
+ default:
48
+ return 'info';
49
+ }
50
+ }
51
+ static deriveCategory(zone, message) {
52
+ const msg = (message || '').toLowerCase();
53
+ if (msg.includes('[security:') || msg.includes('security'))
54
+ return 'security';
55
+ if (zone === 'email' || msg.includes('email') || msg.includes('smtp') || msg.includes('mta'))
56
+ return 'email';
57
+ if (zone === 'dns' || msg.includes('dns'))
58
+ return 'dns';
59
+ if (msg.includes('smtp'))
60
+ return 'smtp';
61
+ return 'system';
62
+ }
63
+ async getRecentLogs(level, category, limit = 100, offset = 0, search, timeRange) {
64
+ // Compute a timestamp cutoff from timeRange
65
+ let since;
66
+ if (timeRange) {
67
+ const rangeMs = {
68
+ '1h': 3600000,
69
+ '6h': 21600000,
70
+ '24h': 86400000,
71
+ '7d': 604800000,
72
+ '30d': 2592000000,
73
+ };
74
+ since = Date.now() - (rangeMs[timeRange] || 86400000);
75
+ }
76
+ // Map the UI level to smartlog levels for filtering
77
+ const smartlogLevels = level
78
+ ? level === 'debug'
79
+ ? ['debug', 'silly']
80
+ : level === 'info'
81
+ ? ['info', 'ok', 'success', 'note', 'lifecycle']
82
+ : [level]
83
+ : undefined;
84
+ // Fetch a larger batch from buffer, then apply category filter client-side
85
+ const rawEntries = logBuffer.getEntries({
86
+ level: smartlogLevels,
87
+ search,
88
+ since,
89
+ limit: limit * 3, // over-fetch to compensate for category filtering
90
+ offset: 0,
91
+ });
92
+ // Map ILogPackage → UI log format and apply category filter
93
+ const mapped = [];
94
+ for (const pkg of rawEntries) {
95
+ const uiLevel = LogsHandler.mapLogLevel(pkg.level);
96
+ const uiCategory = LogsHandler.deriveCategory(pkg.context?.zone, pkg.message);
97
+ if (category && uiCategory !== category)
98
+ continue;
99
+ mapped.push({
100
+ timestamp: pkg.timestamp,
101
+ level: uiLevel,
102
+ category: uiCategory,
103
+ message: pkg.message,
104
+ metadata: pkg.data,
105
+ });
106
+ if (mapped.length >= limit)
107
+ break;
108
+ }
109
+ return mapped;
110
+ }
111
+ /**
112
+ * Add a log destination to the base logger that pushes entries
113
+ * to all connected ops_dashboard TypedSocket clients.
114
+ */
115
+ setupLogPushDestination() {
116
+ const opsServerRef = this.opsServerRef;
117
+ baseLogger.addLogDestination({
118
+ async handleLog(logPackage) {
119
+ // Access the TypedSocket server instance from OpsServer
120
+ const typedsocket = opsServerRef.server?.typedserver?.typedsocket;
121
+ if (!typedsocket)
122
+ return;
123
+ let connections;
124
+ try {
125
+ connections = await typedsocket.findAllTargetConnectionsByTag('role', 'ops_dashboard');
126
+ }
127
+ catch {
128
+ return;
129
+ }
130
+ if (connections.length === 0)
131
+ return;
132
+ const entry = {
133
+ timestamp: logPackage.timestamp || Date.now(),
134
+ level: LogsHandler.mapLogLevel(logPackage.level),
135
+ category: LogsHandler.deriveCategory(logPackage.context?.zone, logPackage.message),
136
+ message: logPackage.message,
137
+ metadata: logPackage.data,
138
+ };
139
+ for (const conn of connections) {
140
+ try {
141
+ const push = typedsocket.createTypedRequest('pushLogEntry', conn);
142
+ push.fire({ entry }).catch(() => { }); // fire-and-forget
143
+ }
144
+ catch {
145
+ // connection may have closed
146
+ }
147
+ }
148
+ },
149
+ });
150
+ }
151
+ setupLogStream(virtualStream, levelFilter, categoryFilter, follow = true) {
152
+ let intervalId = null;
153
+ let logIndex = 0;
154
+ const start = () => {
155
+ if (!follow) {
156
+ // Send existing logs and close
157
+ this.getRecentLogs(levelFilter?.[0], categoryFilter?.[0], 100, 0).then(logs => {
158
+ logs.forEach(log => {
159
+ const logData = JSON.stringify(log);
160
+ const encoder = new TextEncoder();
161
+ virtualStream.sendData(encoder.encode(logData));
162
+ });
163
+ // VirtualStream doesn't have end() method - it closes automatically
164
+ });
165
+ return;
166
+ }
167
+ // For follow mode, simulate real-time log streaming
168
+ intervalId = setInterval(async () => {
169
+ const categories = ['smtp', 'dns', 'security', 'system', 'email'];
170
+ const levels = ['info', 'warn', 'error', 'debug'];
171
+ const mockCategory = categories[Math.floor(Math.random() * categories.length)];
172
+ const mockLevel = levels[Math.floor(Math.random() * levels.length)];
173
+ // Filter by requested criteria
174
+ if (levelFilter && !levelFilter.includes(mockLevel))
175
+ return;
176
+ if (categoryFilter && !categoryFilter.includes(mockCategory))
177
+ return;
178
+ const logEntry = {
179
+ timestamp: Date.now(),
180
+ level: mockLevel,
181
+ category: mockCategory,
182
+ message: `Real-time log ${logIndex++} from ${mockCategory}`,
183
+ metadata: {
184
+ requestId: plugins.uuid.v4(),
185
+ },
186
+ };
187
+ const logData = JSON.stringify(logEntry);
188
+ const encoder = new TextEncoder();
189
+ try {
190
+ await virtualStream.sendData(encoder.encode(logData));
191
+ }
192
+ catch {
193
+ // Stream closed or errored — clean up to prevent interval leak
194
+ clearInterval(intervalId);
195
+ intervalId = null;
196
+ }
197
+ }, 2000); // Send a log every 2 seconds
198
+ // TODO: Hook into actual logger events
199
+ // logger.on('log', (logEntry) => {
200
+ // if (matchesCriteria(logEntry, level, service)) {
201
+ // virtualStream.sendData(formatLogEntry(logEntry));
202
+ // }
203
+ // });
204
+ };
205
+ const stop = () => {
206
+ if (intervalId) {
207
+ clearInterval(intervalId);
208
+ intervalId = null;
209
+ }
210
+ // TODO: Unhook from logger events
211
+ };
212
+ return { start, stop };
213
+ }
214
+ }
215
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9ncy5oYW5kbGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vdHMvb3Bzc2VydmVyL2hhbmRsZXJzL2xvZ3MuaGFuZGxlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGtCQUFrQixDQUFDO0FBRTVDLE9BQU8sS0FBSyxVQUFVLE1BQU0saUNBQWlDLENBQUM7QUFDOUQsT0FBTyxFQUFFLFNBQVMsRUFBRSxVQUFVLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUV4RCxNQUFNLE9BQU8sV0FBVztJQUdGO0lBRmIsV0FBVyxHQUFHLElBQUksT0FBTyxDQUFDLFlBQVksQ0FBQyxXQUFXLEVBQUUsQ0FBQztJQUU1RCxZQUFvQixZQUF1QjtRQUF2QixpQkFBWSxHQUFaLFlBQVksQ0FBVztRQUN6QywwQ0FBMEM7UUFDMUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxXQUFXLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUMvRCxJQUFJLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztRQUN4QixJQUFJLENBQUMsdUJBQXVCLEVBQUUsQ0FBQztJQUNqQyxDQUFDO0lBRU8sZ0JBQWdCO1FBQ3RCLDBCQUEwQjtRQUMxQixJQUFJLENBQUMsV0FBVyxDQUFDLGVBQWUsQ0FDOUIsSUFBSSxPQUFPLENBQUMsWUFBWSxDQUFDLFlBQVksQ0FDbkMsZUFBZSxFQUNmLEtBQUssRUFBRSxPQUFPLEVBQUUsUUFBUSxFQUFFLEVBQUU7WUFDMUIsTUFBTSxJQUFJLEdBQUcsTUFBTSxJQUFJLENBQUMsYUFBYSxDQUNuQyxPQUFPLENBQUMsS0FBSyxFQUNiLE9BQU8sQ0FBQyxRQUFRLEVBQ2hCLE9BQU8sQ0FBQyxLQUFLLElBQUksR0FBRyxFQUNwQixPQUFPLENBQUMsTUFBTSxJQUFJLENBQUMsRUFDbkIsT0FBTyxDQUFDLE1BQU0sRUFDZCxPQUFPLENBQUMsU0FBUyxDQUNsQixDQUFDO1lBRUYs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