@serve.zone/dcrouter 11.0.27 → 11.0.29
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.
- package/dist_serve/bundle.js +1 -1
- package/dist_ts/config/classes.route-config-manager.js +231 -0
- package/dist_ts/config/validator.d.ts +104 -0
- package/dist_ts/config/validator.js +152 -0
- package/dist_ts/errors/base.errors.d.ts +224 -0
- package/dist_ts/errors/base.errors.js +320 -0
- package/dist_ts/errors/error.codes.d.ts +115 -0
- package/dist_ts/errors/error.codes.js +136 -0
- package/dist_ts/monitoring/classes.metricsmanager.d.ts +178 -0
- package/dist_ts/monitoring/classes.metricsmanager.js +642 -0
- package/dist_ts/monitoring/index.d.ts +1 -0
- package/dist_ts/monitoring/index.js +2 -0
- package/dist_ts/opsserver/classes.opsserver.d.ts +37 -0
- package/dist_ts/opsserver/classes.opsserver.js +85 -0
- package/dist_ts/opsserver/handlers/api-token.handler.d.ts +6 -0
- package/dist_ts/opsserver/handlers/api-token.handler.js +62 -0
- package/dist_ts/opsserver/handlers/certificate.handler.d.ts +32 -0
- package/dist_ts/opsserver/handlers/certificate.handler.js +421 -0
- package/dist_ts/opsserver/handlers/email-ops.handler.d.ts +30 -0
- package/dist_ts/opsserver/handlers/email-ops.handler.js +227 -0
- package/dist_ts/opsserver/handlers/index.d.ts +11 -0
- package/dist_ts/opsserver/handlers/index.js +12 -0
- package/dist_ts/opsserver/handlers/radius.handler.d.ts +6 -0
- package/dist_ts/opsserver/handlers/radius.handler.js +295 -0
- package/dist_ts/opsserver/handlers/remoteingress.handler.d.ts +6 -0
- package/dist_ts/opsserver/handlers/remoteingress.handler.js +156 -0
- package/dist_ts/opsserver/handlers/route-management.handler.d.ts +14 -0
- package/dist_ts/opsserver/handlers/route-management.handler.js +117 -0
- package/dist_ts/opsserver/handlers/security.handler.d.ts +9 -0
- package/dist_ts/opsserver/handlers/security.handler.js +231 -0
- package/dist_ts/opsserver/handlers/stats.handler.d.ts +11 -0
- package/dist_ts/opsserver/handlers/stats.handler.js +399 -0
- package/dist_ts/opsserver/helpers/guards.d.ts +27 -0
- package/dist_ts/opsserver/helpers/guards.js +43 -0
- package/dist_ts/opsserver/index.d.ts +1 -0
- package/dist_ts/opsserver/index.js +2 -0
- package/dist_ts/radius/classes.accounting.manager.d.ts +218 -0
- package/dist_ts/radius/classes.accounting.manager.js +417 -0
- package/dist_ts/radius/classes.radius.server.d.ts +171 -0
- package/dist_ts/radius/classes.radius.server.js +385 -0
- package/dist_ts/radius/classes.vlan.manager.d.ts +128 -0
- package/dist_ts/radius/classes.vlan.manager.js +279 -0
- package/dist_ts/radius/index.d.ts +13 -0
- package/dist_ts/radius/index.js +14 -0
- package/dist_ts/remoteingress/classes.remoteingress-manager.d.ts +82 -0
- package/dist_ts/remoteingress/classes.remoteingress-manager.js +227 -0
- package/dist_ts/remoteingress/classes.tunnel-manager.d.ts +59 -0
- package/dist_ts/remoteingress/classes.tunnel-manager.js +165 -0
- package/dist_ts/remoteingress/index.d.ts +2 -0
- package/dist_ts/remoteingress/index.js +3 -0
- package/dist_ts/security/classes.securitylogger.d.ts +144 -0
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/package.json +2 -2
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts_web/00_commitinfo_data.ts +1 -1
package/dist_serve/bundle.js
CHANGED
|
@@ -39328,4 +39328,4 @@ ibantools/jsnext/ibantools.js:
|
|
|
39328
39328
|
* @preferred
|
|
39329
39329
|
*)
|
|
39330
39330
|
*/
|
|
39331
|
-
//# sourceMappingURL=bundle-
|
|
39331
|
+
//# sourceMappingURL=bundle-1772721753301.js.map
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import * as plugins from '../plugins.js';
|
|
2
|
+
import { logger } from '../logger.js';
|
|
3
|
+
const ROUTES_PREFIX = '/config-api/routes/';
|
|
4
|
+
const OVERRIDES_PREFIX = '/config-api/overrides/';
|
|
5
|
+
export class RouteConfigManager {
|
|
6
|
+
storageManager;
|
|
7
|
+
getHardcodedRoutes;
|
|
8
|
+
getSmartProxy;
|
|
9
|
+
storedRoutes = new Map();
|
|
10
|
+
overrides = new Map();
|
|
11
|
+
warnings = [];
|
|
12
|
+
constructor(storageManager, getHardcodedRoutes, getSmartProxy) {
|
|
13
|
+
this.storageManager = storageManager;
|
|
14
|
+
this.getHardcodedRoutes = getHardcodedRoutes;
|
|
15
|
+
this.getSmartProxy = getSmartProxy;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Load persisted routes and overrides, compute warnings, apply to SmartProxy.
|
|
19
|
+
*/
|
|
20
|
+
async initialize() {
|
|
21
|
+
await this.loadStoredRoutes();
|
|
22
|
+
await this.loadOverrides();
|
|
23
|
+
this.computeWarnings();
|
|
24
|
+
this.logWarnings();
|
|
25
|
+
await this.applyRoutes();
|
|
26
|
+
}
|
|
27
|
+
// =========================================================================
|
|
28
|
+
// Merged view
|
|
29
|
+
// =========================================================================
|
|
30
|
+
getMergedRoutes() {
|
|
31
|
+
const merged = [];
|
|
32
|
+
// Hardcoded routes
|
|
33
|
+
for (const route of this.getHardcodedRoutes()) {
|
|
34
|
+
const name = route.name || '';
|
|
35
|
+
const override = this.overrides.get(name);
|
|
36
|
+
merged.push({
|
|
37
|
+
route,
|
|
38
|
+
source: 'hardcoded',
|
|
39
|
+
enabled: override ? override.enabled : true,
|
|
40
|
+
overridden: !!override,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
// Programmatic routes
|
|
44
|
+
for (const stored of this.storedRoutes.values()) {
|
|
45
|
+
merged.push({
|
|
46
|
+
route: stored.route,
|
|
47
|
+
source: 'programmatic',
|
|
48
|
+
enabled: stored.enabled,
|
|
49
|
+
overridden: false,
|
|
50
|
+
storedRouteId: stored.id,
|
|
51
|
+
createdAt: stored.createdAt,
|
|
52
|
+
updatedAt: stored.updatedAt,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
return { routes: merged, warnings: [...this.warnings] };
|
|
56
|
+
}
|
|
57
|
+
// =========================================================================
|
|
58
|
+
// Programmatic route CRUD
|
|
59
|
+
// =========================================================================
|
|
60
|
+
async createRoute(route, createdBy, enabled = true) {
|
|
61
|
+
const id = plugins.uuid.v4();
|
|
62
|
+
const now = Date.now();
|
|
63
|
+
// Ensure route has a name
|
|
64
|
+
if (!route.name) {
|
|
65
|
+
route.name = `programmatic-${id.slice(0, 8)}`;
|
|
66
|
+
}
|
|
67
|
+
const stored = {
|
|
68
|
+
id,
|
|
69
|
+
route,
|
|
70
|
+
enabled,
|
|
71
|
+
createdAt: now,
|
|
72
|
+
updatedAt: now,
|
|
73
|
+
createdBy,
|
|
74
|
+
};
|
|
75
|
+
this.storedRoutes.set(id, stored);
|
|
76
|
+
await this.persistRoute(stored);
|
|
77
|
+
await this.applyRoutes();
|
|
78
|
+
return id;
|
|
79
|
+
}
|
|
80
|
+
async updateRoute(id, patch) {
|
|
81
|
+
const stored = this.storedRoutes.get(id);
|
|
82
|
+
if (!stored)
|
|
83
|
+
return false;
|
|
84
|
+
if (patch.route) {
|
|
85
|
+
stored.route = { ...stored.route, ...patch.route };
|
|
86
|
+
}
|
|
87
|
+
if (patch.enabled !== undefined) {
|
|
88
|
+
stored.enabled = patch.enabled;
|
|
89
|
+
}
|
|
90
|
+
stored.updatedAt = Date.now();
|
|
91
|
+
await this.persistRoute(stored);
|
|
92
|
+
await this.applyRoutes();
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
async deleteRoute(id) {
|
|
96
|
+
if (!this.storedRoutes.has(id))
|
|
97
|
+
return false;
|
|
98
|
+
this.storedRoutes.delete(id);
|
|
99
|
+
await this.storageManager.delete(`${ROUTES_PREFIX}${id}.json`);
|
|
100
|
+
await this.applyRoutes();
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
async toggleRoute(id, enabled) {
|
|
104
|
+
return this.updateRoute(id, { enabled });
|
|
105
|
+
}
|
|
106
|
+
// =========================================================================
|
|
107
|
+
// Hardcoded route overrides
|
|
108
|
+
// =========================================================================
|
|
109
|
+
async setOverride(routeName, enabled, updatedBy) {
|
|
110
|
+
const override = {
|
|
111
|
+
routeName,
|
|
112
|
+
enabled,
|
|
113
|
+
updatedAt: Date.now(),
|
|
114
|
+
updatedBy,
|
|
115
|
+
};
|
|
116
|
+
this.overrides.set(routeName, override);
|
|
117
|
+
await this.storageManager.setJSON(`${OVERRIDES_PREFIX}${routeName}.json`, override);
|
|
118
|
+
this.computeWarnings();
|
|
119
|
+
await this.applyRoutes();
|
|
120
|
+
}
|
|
121
|
+
async removeOverride(routeName) {
|
|
122
|
+
if (!this.overrides.has(routeName))
|
|
123
|
+
return false;
|
|
124
|
+
this.overrides.delete(routeName);
|
|
125
|
+
await this.storageManager.delete(`${OVERRIDES_PREFIX}${routeName}.json`);
|
|
126
|
+
this.computeWarnings();
|
|
127
|
+
await this.applyRoutes();
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
// =========================================================================
|
|
131
|
+
// Private: persistence
|
|
132
|
+
// =========================================================================
|
|
133
|
+
async loadStoredRoutes() {
|
|
134
|
+
const keys = await this.storageManager.list(ROUTES_PREFIX);
|
|
135
|
+
for (const key of keys) {
|
|
136
|
+
if (!key.endsWith('.json'))
|
|
137
|
+
continue;
|
|
138
|
+
const stored = await this.storageManager.getJSON(key);
|
|
139
|
+
if (stored?.id) {
|
|
140
|
+
this.storedRoutes.set(stored.id, stored);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
if (this.storedRoutes.size > 0) {
|
|
144
|
+
logger.log('info', `Loaded ${this.storedRoutes.size} programmatic route(s) from storage`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
async loadOverrides() {
|
|
148
|
+
const keys = await this.storageManager.list(OVERRIDES_PREFIX);
|
|
149
|
+
for (const key of keys) {
|
|
150
|
+
if (!key.endsWith('.json'))
|
|
151
|
+
continue;
|
|
152
|
+
const override = await this.storageManager.getJSON(key);
|
|
153
|
+
if (override?.routeName) {
|
|
154
|
+
this.overrides.set(override.routeName, override);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (this.overrides.size > 0) {
|
|
158
|
+
logger.log('info', `Loaded ${this.overrides.size} route override(s) from storage`);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
async persistRoute(stored) {
|
|
162
|
+
await this.storageManager.setJSON(`${ROUTES_PREFIX}${stored.id}.json`, stored);
|
|
163
|
+
}
|
|
164
|
+
// =========================================================================
|
|
165
|
+
// Private: warnings
|
|
166
|
+
// =========================================================================
|
|
167
|
+
computeWarnings() {
|
|
168
|
+
this.warnings = [];
|
|
169
|
+
const hardcodedNames = new Set(this.getHardcodedRoutes().map((r) => r.name || ''));
|
|
170
|
+
// Check overrides
|
|
171
|
+
for (const [routeName, override] of this.overrides) {
|
|
172
|
+
if (!hardcodedNames.has(routeName)) {
|
|
173
|
+
this.warnings.push({
|
|
174
|
+
type: 'orphaned-override',
|
|
175
|
+
routeName,
|
|
176
|
+
message: `Orphaned override for route '${routeName}' — hardcoded route no longer exists`,
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
else if (!override.enabled) {
|
|
180
|
+
this.warnings.push({
|
|
181
|
+
type: 'disabled-hardcoded',
|
|
182
|
+
routeName,
|
|
183
|
+
message: `Route '${routeName}' is disabled via API override`,
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
// Check disabled programmatic routes
|
|
188
|
+
for (const stored of this.storedRoutes.values()) {
|
|
189
|
+
if (!stored.enabled) {
|
|
190
|
+
const name = stored.route.name || stored.id;
|
|
191
|
+
this.warnings.push({
|
|
192
|
+
type: 'disabled-programmatic',
|
|
193
|
+
routeName: name,
|
|
194
|
+
message: `Programmatic route '${name}' (id: ${stored.id}) is disabled`,
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
logWarnings() {
|
|
200
|
+
for (const w of this.warnings) {
|
|
201
|
+
logger.log('warn', w.message);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
// =========================================================================
|
|
205
|
+
// Private: apply merged routes to SmartProxy
|
|
206
|
+
// =========================================================================
|
|
207
|
+
async applyRoutes() {
|
|
208
|
+
const smartProxy = this.getSmartProxy();
|
|
209
|
+
if (!smartProxy)
|
|
210
|
+
return;
|
|
211
|
+
const enabledRoutes = [];
|
|
212
|
+
// Add enabled hardcoded routes (respecting overrides)
|
|
213
|
+
for (const route of this.getHardcodedRoutes()) {
|
|
214
|
+
const name = route.name || '';
|
|
215
|
+
const override = this.overrides.get(name);
|
|
216
|
+
if (override && !override.enabled) {
|
|
217
|
+
continue; // Skip disabled hardcoded route
|
|
218
|
+
}
|
|
219
|
+
enabledRoutes.push(route);
|
|
220
|
+
}
|
|
221
|
+
// Add enabled programmatic routes
|
|
222
|
+
for (const stored of this.storedRoutes.values()) {
|
|
223
|
+
if (stored.enabled) {
|
|
224
|
+
enabledRoutes.push(stored.route);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
await smartProxy.updateRoutes(enabledRoutes);
|
|
228
|
+
logger.log('info', `Applied ${enabledRoutes.length} routes to SmartProxy (${this.storedRoutes.size} programmatic, ${this.overrides.size} overrides)`);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5yb3V0ZS1jb25maWctbWFuYWdlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3RzL2NvbmZpZy9jbGFzc2VzLnJvdXRlLWNvbmZpZy1tYW5hZ2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sZUFBZSxDQUFDO0FBQ3pDLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFTdEMsTUFBTSxhQUFhLEdBQUcscUJBQXFCLENBQUM7QUFDNUMsTUFBTSxnQkFBZ0IsR0FBRyx3QkFBd0IsQ0FBQztBQUVsRCxNQUFNLE9BQU8sa0JBQWtCO0lBTW5CO0lBQ0E7SUFDQTtJQVBGLFlBQVksR0FBRyxJQUFJLEdBQUcsRUFBd0IsQ0FBQztJQUMvQyxTQUFTLEdBQUcsSUFBSSxHQUFHLEVBQTBCLENBQUM7SUFDOUMsUUFBUSxHQUFvQixFQUFFLENBQUM7SUFFdkMsWUFDVSxjQUE4QixFQUM5QixrQkFBMkQsRUFDM0QsYUFBOEQ7UUFGOUQsbUJBQWMsR0FBZCxjQUFjLENBQWdCO1FBQzlCLHVCQUFrQixHQUFsQixrQkFBa0IsQ0FBeUM7UUFDM0Qsa0JBQWEsR0FBYixhQUFhLENBQWlEO0lBQ3JFLENBQUM7SUFFSjs7T0FFRztJQUNJLEtBQUssQ0FBQyxVQUFVO1FBQ3JCLE1BQU0sSUFBSSxDQUFDLGdCQUFnQixFQUFFLENBQUM7UUFDOUIsTUFBTSxJQUFJLENBQUMsYUFBYSxFQUFFLENBQUM7UUFDM0IsSUFBSSxDQUFDLGVBQWUsRUFBRSxDQUFDO1FBQ3ZCLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztRQUNuQixNQUFNLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztJQUMzQixDQUFDO0lBRUQsNEVBQTRFO0lBQzVFLGNBQWM7SUFDZCw0RUFBNEU7SUFFckUsZUFBZTtRQUNwQixNQUFNLE1BQU0sR0FBbUIsRUFBRSxDQUFDO1FBRWxDLG1CQUFtQjtRQUNuQixLQUFLLE1B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
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validation result
|
|
3
|
+
*/
|
|
4
|
+
export interface IValidationResult {
|
|
5
|
+
/**
|
|
6
|
+
* Whether the validation passed
|
|
7
|
+
*/
|
|
8
|
+
valid: boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Validation errors if any
|
|
11
|
+
*/
|
|
12
|
+
errors?: string[];
|
|
13
|
+
/**
|
|
14
|
+
* Validated configuration (may include defaults)
|
|
15
|
+
*/
|
|
16
|
+
config?: any;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Validation schema types
|
|
20
|
+
*/
|
|
21
|
+
export type ValidationSchema = Record<string, {
|
|
22
|
+
/**
|
|
23
|
+
* Type of the value
|
|
24
|
+
*/
|
|
25
|
+
type: 'string' | 'number' | 'boolean' | 'object' | 'array';
|
|
26
|
+
/**
|
|
27
|
+
* Whether the field is required
|
|
28
|
+
*/
|
|
29
|
+
required?: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Default value if not specified
|
|
32
|
+
*/
|
|
33
|
+
default?: any;
|
|
34
|
+
/**
|
|
35
|
+
* Minimum value (for numbers)
|
|
36
|
+
*/
|
|
37
|
+
min?: number;
|
|
38
|
+
/**
|
|
39
|
+
* Maximum value (for numbers)
|
|
40
|
+
*/
|
|
41
|
+
max?: number;
|
|
42
|
+
/**
|
|
43
|
+
* Minimum length (for strings or arrays)
|
|
44
|
+
*/
|
|
45
|
+
minLength?: number;
|
|
46
|
+
/**
|
|
47
|
+
* Maximum length (for strings or arrays)
|
|
48
|
+
*/
|
|
49
|
+
maxLength?: number;
|
|
50
|
+
/**
|
|
51
|
+
* Pattern to match (for strings)
|
|
52
|
+
*/
|
|
53
|
+
pattern?: RegExp;
|
|
54
|
+
/**
|
|
55
|
+
* Allowed values (for strings, numbers)
|
|
56
|
+
*/
|
|
57
|
+
enum?: any[];
|
|
58
|
+
/**
|
|
59
|
+
* Nested schema (for objects)
|
|
60
|
+
*/
|
|
61
|
+
schema?: ValidationSchema;
|
|
62
|
+
/**
|
|
63
|
+
* Item schema (for arrays)
|
|
64
|
+
*/
|
|
65
|
+
items?: {
|
|
66
|
+
type: 'string' | 'number' | 'boolean' | 'object';
|
|
67
|
+
schema?: ValidationSchema;
|
|
68
|
+
};
|
|
69
|
+
/**
|
|
70
|
+
* Custom validation function
|
|
71
|
+
*/
|
|
72
|
+
validate?: (value: any) => boolean | string;
|
|
73
|
+
}>;
|
|
74
|
+
/**
|
|
75
|
+
* Configuration validator
|
|
76
|
+
* Validates configuration objects against schemas and provides default values
|
|
77
|
+
*/
|
|
78
|
+
export declare class ConfigValidator {
|
|
79
|
+
/**
|
|
80
|
+
* Validate a configuration object against a schema
|
|
81
|
+
*
|
|
82
|
+
* @param config Configuration object to validate
|
|
83
|
+
* @param schema Validation schema
|
|
84
|
+
* @returns Validation result
|
|
85
|
+
*/
|
|
86
|
+
static validate<T>(config: T, schema: ValidationSchema): IValidationResult;
|
|
87
|
+
/**
|
|
88
|
+
* Apply defaults to a configuration object based on a schema
|
|
89
|
+
*
|
|
90
|
+
* @param config Configuration object to apply defaults to
|
|
91
|
+
* @param schema Validation schema with defaults
|
|
92
|
+
* @returns Configuration with defaults applied
|
|
93
|
+
*/
|
|
94
|
+
static applyDefaults<T>(config: T, schema: ValidationSchema): T;
|
|
95
|
+
/**
|
|
96
|
+
* Throw a validation error if the configuration is invalid
|
|
97
|
+
*
|
|
98
|
+
* @param config Configuration to validate
|
|
99
|
+
* @param schema Validation schema
|
|
100
|
+
* @returns Validated configuration with defaults
|
|
101
|
+
* @throws ValidationError if validation fails
|
|
102
|
+
*/
|
|
103
|
+
static validateOrThrow<T>(config: T, schema: ValidationSchema): T;
|
|
104
|
+
}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import * as plugins from '../plugins.js';
|
|
2
|
+
import { ValidationError } from '../errors/base.errors.js';
|
|
3
|
+
/**
|
|
4
|
+
* Configuration validator
|
|
5
|
+
* Validates configuration objects against schemas and provides default values
|
|
6
|
+
*/
|
|
7
|
+
export class ConfigValidator {
|
|
8
|
+
/**
|
|
9
|
+
* Validate a configuration object against a schema
|
|
10
|
+
*
|
|
11
|
+
* @param config Configuration object to validate
|
|
12
|
+
* @param schema Validation schema
|
|
13
|
+
* @returns Validation result
|
|
14
|
+
*/
|
|
15
|
+
static validate(config, schema) {
|
|
16
|
+
const errors = [];
|
|
17
|
+
const validatedConfig = { ...config };
|
|
18
|
+
// Validate each field against the schema
|
|
19
|
+
for (const [key, rules] of Object.entries(schema)) {
|
|
20
|
+
const value = config[key];
|
|
21
|
+
// Check if required
|
|
22
|
+
if (rules.required && (value === undefined || value === null)) {
|
|
23
|
+
errors.push(`${key} is required`);
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
// If not present and not required, apply default if available
|
|
27
|
+
if ((value === undefined || value === null)) {
|
|
28
|
+
if (rules.default !== undefined) {
|
|
29
|
+
validatedConfig[key] = rules.default;
|
|
30
|
+
}
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
// Type validation
|
|
34
|
+
if (value !== undefined && value !== null) {
|
|
35
|
+
const valueType = Array.isArray(value) ? 'array' : typeof value;
|
|
36
|
+
if (valueType !== rules.type) {
|
|
37
|
+
errors.push(`${key} must be of type ${rules.type}, got ${valueType}`);
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
// Type-specific validations
|
|
41
|
+
switch (rules.type) {
|
|
42
|
+
case 'number':
|
|
43
|
+
if (rules.min !== undefined && value < rules.min) {
|
|
44
|
+
errors.push(`${key} must be at least ${rules.min}`);
|
|
45
|
+
}
|
|
46
|
+
if (rules.max !== undefined && value > rules.max) {
|
|
47
|
+
errors.push(`${key} must be at most ${rules.max}`);
|
|
48
|
+
}
|
|
49
|
+
break;
|
|
50
|
+
case 'string':
|
|
51
|
+
if (rules.minLength !== undefined && value.length < rules.minLength) {
|
|
52
|
+
errors.push(`${key} must be at least ${rules.minLength} characters`);
|
|
53
|
+
}
|
|
54
|
+
if (rules.maxLength !== undefined && value.length > rules.maxLength) {
|
|
55
|
+
errors.push(`${key} must be at most ${rules.maxLength} characters`);
|
|
56
|
+
}
|
|
57
|
+
if (rules.pattern && !rules.pattern.test(value)) {
|
|
58
|
+
errors.push(`${key} must match pattern ${rules.pattern}`);
|
|
59
|
+
}
|
|
60
|
+
break;
|
|
61
|
+
case 'array':
|
|
62
|
+
if (rules.minLength !== undefined && value.length < rules.minLength) {
|
|
63
|
+
errors.push(`${key} must have at least ${rules.minLength} items`);
|
|
64
|
+
}
|
|
65
|
+
if (rules.maxLength !== undefined && value.length > rules.maxLength) {
|
|
66
|
+
errors.push(`${key} must have at most ${rules.maxLength} items`);
|
|
67
|
+
}
|
|
68
|
+
if (rules.items && value.length > 0) {
|
|
69
|
+
for (let i = 0; i < value.length; i++) {
|
|
70
|
+
const itemType = Array.isArray(value[i]) ? 'array' : typeof value[i];
|
|
71
|
+
if (itemType !== rules.items.type) {
|
|
72
|
+
errors.push(`${key}[${i}] must be of type ${rules.items.type}, got ${itemType}`);
|
|
73
|
+
}
|
|
74
|
+
else if (rules.items.schema && itemType === 'object') {
|
|
75
|
+
const itemResult = this.validate(value[i], rules.items.schema);
|
|
76
|
+
if (!itemResult.valid) {
|
|
77
|
+
errors.push(...itemResult.errors.map(err => `${key}[${i}].${err}`));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
break;
|
|
83
|
+
case 'object':
|
|
84
|
+
if (rules.schema) {
|
|
85
|
+
const nestedResult = this.validate(value, rules.schema);
|
|
86
|
+
if (!nestedResult.valid) {
|
|
87
|
+
errors.push(...nestedResult.errors.map(err => `${key}.${err}`));
|
|
88
|
+
}
|
|
89
|
+
validatedConfig[key] = nestedResult.config;
|
|
90
|
+
}
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
// Enum validation
|
|
94
|
+
if (rules.enum && !rules.enum.includes(value)) {
|
|
95
|
+
errors.push(`${key} must be one of [${rules.enum.join(', ')}]`);
|
|
96
|
+
}
|
|
97
|
+
// Custom validation
|
|
98
|
+
if (rules.validate) {
|
|
99
|
+
const result = rules.validate(value);
|
|
100
|
+
if (result !== true) {
|
|
101
|
+
errors.push(typeof result === 'string' ? result : `${key} failed custom validation`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
valid: errors.length === 0,
|
|
108
|
+
errors: errors.length > 0 ? errors : undefined,
|
|
109
|
+
config: validatedConfig
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Apply defaults to a configuration object based on a schema
|
|
114
|
+
*
|
|
115
|
+
* @param config Configuration object to apply defaults to
|
|
116
|
+
* @param schema Validation schema with defaults
|
|
117
|
+
* @returns Configuration with defaults applied
|
|
118
|
+
*/
|
|
119
|
+
static applyDefaults(config, schema) {
|
|
120
|
+
const result = { ...config };
|
|
121
|
+
for (const [key, rules] of Object.entries(schema)) {
|
|
122
|
+
if (result[key] === undefined && rules.default !== undefined) {
|
|
123
|
+
result[key] = rules.default;
|
|
124
|
+
}
|
|
125
|
+
// Apply defaults to nested objects
|
|
126
|
+
if (result[key] && rules.type === 'object' && rules.schema) {
|
|
127
|
+
result[key] = this.applyDefaults(result[key], rules.schema);
|
|
128
|
+
}
|
|
129
|
+
// Apply defaults to array items
|
|
130
|
+
if (result[key] && rules.type === 'array' && rules.items && rules.items.schema) {
|
|
131
|
+
result[key] = result[key].map(item => typeof item === 'object' ? this.applyDefaults(item, rules.items.schema) : item);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return result;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Throw a validation error if the configuration is invalid
|
|
138
|
+
*
|
|
139
|
+
* @param config Configuration to validate
|
|
140
|
+
* @param schema Validation schema
|
|
141
|
+
* @returns Validated configuration with defaults
|
|
142
|
+
* @throws ValidationError if validation fails
|
|
143
|
+
*/
|
|
144
|
+
static validateOrThrow(config, schema) {
|
|
145
|
+
const result = this.validate(config, schema);
|
|
146
|
+
if (!result.valid) {
|
|
147
|
+
throw new ValidationError(`Configuration validation failed: ${result.errors.join(', ')}`, 'CONFIG_VALIDATION_ERROR', { data: { errors: result.errors } });
|
|
148
|
+
}
|
|
149
|
+
return result.config;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmFsaWRhdG9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vdHMvY29uZmlnL3ZhbGlkYXRvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGVBQWUsQ0FBQztBQUN6QyxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUEwRjNEOzs7R0FHRztBQUNILE1BQU0sT0FBTyxlQUFlO0lBRTFCOzs7Ozs7T0FNRztJQUNJLE1BQU0sQ0FBQyxRQUFRLENBQUksTUFBUyxFQUFFLE1BQXdCO1FBQzNELE1BQU0sTUFBTSxHQUFhLEVBQUUsQ0FBQztRQUM1QixNQUFNLGVBQWUsR0FBRyxFQUFFLEdBQUcsTUFBTSxFQUFFLENBQUM7UUFFdEMseUNBQXlDO1FBQ3pDLEtBQUssTUFBTSxDQUFDLEdBQUcsRUFBRSxLQUFLLENBQUMsSUFBSSxNQUFNLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUM7WUFDbEQsTUFBTSxLQUFLLEdBQUcsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1lBRTFCLG9CQUFvQjtZQUNwQixJQUFJLEtBQUssQ0FBQyxRQUFRLElBQUksQ0FBQyxLQUFLLEtBQUssU0FBUyxJQUFJLEtBQUssS0FBSyxJQUFJLENBQUMsRUFBRSxDQUFDO2dCQUM5RCxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsR0FBRyxjQUFjLENBQUMsQ0FBQztnQkFDbEMsU0FBUztZQUNYLENBQUM7WUFFRCw4REFBOEQ7WUFDOUQsSUFBSSxDQUFDLEtBQUssS0FBSyxTQUFTLElBQUksS0FBSyxLQUFLLElBQUksQ0FBQyxFQUFFLENBQUM7Z0JBQzVDLElBQUksS0FBSyxDQUFDLE9BQU8sS0FBSyxTQUFTLEVBQUUsQ0FBQztvQkFDaEMsZUFBZSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEtBQUssQ0FBQyxPQUFPLENBQUM7Z0JBQ3ZDLENBQUM7Z0JBQ0QsU0FBUztZQUNYLENBQUM7WUFFRCxr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
|