feat(vpn,target-profiles,migrations): add startup data migrations, support scoped VPN route allow entries, and rename target profile hosts to ips

This commit is contained in:
2026-04-07 21:02:37 +00:00
parent f29ed9757e
commit 7fa6d82e58
24 changed files with 1503 additions and 1563 deletions

View File

@@ -15,6 +15,9 @@ import { StorageBackedCertManager } from './classes.storage-cert-manager.js';
import { CertProvisionScheduler } from './classes.cert-provision-scheduler.js';
// Import unified database
import { DcRouterDb, type IDcRouterDbConfig, CacheCleaner, ProxyCertDoc, AcmeCertDoc } from './db/index.js';
// Import migration runner and app version
import { createMigrationRunner } from '../ts_migrations/index.js';
import { commitinfo } from './00_commitinfo_data.js';
import { OpsServer } from './opsserver/index.js';
import { MetricsManager } from './monitoring/index.js';
@@ -775,6 +778,19 @@ export class DcRouter {
await this.dcRouterDb.start();
// Run any pending data migrations before anything else reads from the DB.
// This must complete before ConfigManagers loads profiles.
const migration = await createMigrationRunner(this.dcRouterDb.getDb(), commitinfo.version);
const migrationResult = await migration.run();
if (migrationResult.stepsApplied.length > 0) {
logger.log('info',
`smartmigration: ${migrationResult.currentVersionBefore ?? 'fresh'}${migrationResult.currentVersionAfter} ` +
`(${migrationResult.stepsApplied.length} step(s) applied in ${migrationResult.totalDurationMs}ms)`,
);
} else if (migrationResult.wasFreshInstall) {
logger.log('info', `smartmigration: fresh install stamped to ${migrationResult.currentVersionAfter}`);
}
// Start the cache cleaner for TTL-based document cleanup
const cleanupIntervalMs = (dbConfig.cleanupIntervalHours || 1) * 60 * 60 * 1000;
this.cacheCleaner = new CacheCleaner(this.dcRouterDb, {
@@ -1042,15 +1058,9 @@ export class DcRouter {
});
});
this.smartProxy.on('certificate-renewed', (event: plugins.smartproxy.ICertificateIssuedEvent) => {
logger.log('info', `Certificate renewed for ${event.domain} via ${event.source}, expires ${event.expiryDate}`);
const routeNames = this.findRouteNamesForDomain(event.domain);
this.certificateStatusMap.set(event.domain, {
status: 'valid', routeNames,
expiryDate: event.expiryDate, issuedAt: new Date().toISOString(),
source: event.source,
});
});
// Note: smartproxy v27.5.0 emits only 'certificate-issued' and 'certificate-failed'.
// Renewals come through 'certificate-issued' (with optional isRenewal? in the payload).
// The vestigial 'certificate-renewed' event from common-types.ts is never emitted.
this.smartProxy.on('certificate-failed', (event: plugins.smartproxy.ICertificateFailedEvent) => {
logger.log('error', `Certificate failed for ${event.domain} (${event.source}): ${event.error}`);