@aigne/afs-dns 1.11.0-beta.6
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/LICENSE.md +26 -0
- package/README.md +233 -0
- package/dist/index.d.mts +840 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +1790 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +52 -0
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,840 @@
|
|
|
1
|
+
import { Route53Client } from "@aws-sdk/client-route-53";
|
|
2
|
+
import { AFSAccessMode, AFSDeleteOptions, AFSDeleteResult, AFSListOptions, AFSListResult, AFSModule, AFSReadOptions, AFSReadResult, AFSWriteEntryPayload, AFSWriteOptions, AFSWriteResult } from "@aigne/afs";
|
|
3
|
+
|
|
4
|
+
//#region src/types/record.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* DNS Record Types
|
|
7
|
+
*
|
|
8
|
+
* Standard DNS record types following RFC specifications.
|
|
9
|
+
* These types are shared across all DNS provider implementations.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Supported DNS record types
|
|
13
|
+
*/
|
|
14
|
+
type DNSRecordType = "A" | "AAAA" | "CNAME" | "MX" | "TXT" | "NS" | "SRV" | "CAA" | "PTR" | "SOA";
|
|
15
|
+
/**
|
|
16
|
+
* MX record value with priority
|
|
17
|
+
*/
|
|
18
|
+
interface MXValue {
|
|
19
|
+
priority: number;
|
|
20
|
+
value: string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* SRV record value
|
|
24
|
+
*/
|
|
25
|
+
interface SRVValue {
|
|
26
|
+
priority: number;
|
|
27
|
+
weight: number;
|
|
28
|
+
port: number;
|
|
29
|
+
target: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* CAA record value
|
|
33
|
+
*/
|
|
34
|
+
interface CAAValue {
|
|
35
|
+
flags: number;
|
|
36
|
+
tag: "issue" | "issuewild" | "iodef" | string;
|
|
37
|
+
value: string;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* SOA record value (read-only)
|
|
41
|
+
*/
|
|
42
|
+
interface SOAValue {
|
|
43
|
+
mname: string;
|
|
44
|
+
rname: string;
|
|
45
|
+
serial: number;
|
|
46
|
+
refresh: number;
|
|
47
|
+
retry: number;
|
|
48
|
+
expire: number;
|
|
49
|
+
minimum: number;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Record values type - varies by record type
|
|
53
|
+
* - A, AAAA, NS, TXT, PTR: string[] (multiple values)
|
|
54
|
+
* - CNAME: string (single value, for type safety use string[] with one element)
|
|
55
|
+
* - MX: MXValue[]
|
|
56
|
+
* - SRV: SRVValue[]
|
|
57
|
+
* - CAA: CAAValue[]
|
|
58
|
+
* - SOA: SOAValue
|
|
59
|
+
*/
|
|
60
|
+
type DNSRecordValues = string | string[] | MXValue[] | SRVValue[] | CAAValue[] | SOAValue;
|
|
61
|
+
/**
|
|
62
|
+
* A single DNS record
|
|
63
|
+
*/
|
|
64
|
+
interface DNSRecord {
|
|
65
|
+
type: DNSRecordType;
|
|
66
|
+
ttl: number;
|
|
67
|
+
values: DNSRecordValues;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* A set of records for a single name (e.g., www.example.com)
|
|
71
|
+
*/
|
|
72
|
+
interface DNSRecordSet {
|
|
73
|
+
fqdn: string;
|
|
74
|
+
records: DNSRecord[];
|
|
75
|
+
}
|
|
76
|
+
interface ValidationResult {
|
|
77
|
+
valid: boolean;
|
|
78
|
+
error?: string;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Validate A record values
|
|
82
|
+
*/
|
|
83
|
+
declare function validateARecord(values: string[]): ValidationResult;
|
|
84
|
+
/**
|
|
85
|
+
* Validate AAAA record values
|
|
86
|
+
*/
|
|
87
|
+
declare function validateAAAARecord(values: string[]): ValidationResult;
|
|
88
|
+
/**
|
|
89
|
+
* Validate CNAME record value
|
|
90
|
+
*/
|
|
91
|
+
declare function validateCNAMERecord(value: string): ValidationResult;
|
|
92
|
+
/**
|
|
93
|
+
* Validate MX record values
|
|
94
|
+
*/
|
|
95
|
+
declare function validateMXRecord(values: MXValue[]): ValidationResult;
|
|
96
|
+
/**
|
|
97
|
+
* Validate TXT record values
|
|
98
|
+
*/
|
|
99
|
+
declare function validateTXTRecord(values: string[]): ValidationResult;
|
|
100
|
+
/**
|
|
101
|
+
* Validate NS record values
|
|
102
|
+
*/
|
|
103
|
+
declare function validateNSRecord(values: string[]): ValidationResult;
|
|
104
|
+
/**
|
|
105
|
+
* Validate SRV record values
|
|
106
|
+
*/
|
|
107
|
+
declare function validateSRVRecord(values: SRVValue[]): ValidationResult;
|
|
108
|
+
/**
|
|
109
|
+
* Validate CAA record values
|
|
110
|
+
*/
|
|
111
|
+
declare function validateCAARecord(values: CAAValue[]): ValidationResult;
|
|
112
|
+
/**
|
|
113
|
+
* Validate TTL value
|
|
114
|
+
*/
|
|
115
|
+
declare function validateTTL(ttl: number): ValidationResult;
|
|
116
|
+
/**
|
|
117
|
+
* Record validation result with optional errors array
|
|
118
|
+
*/
|
|
119
|
+
interface RecordValidationResult {
|
|
120
|
+
valid: boolean;
|
|
121
|
+
errors?: string[];
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Validate a complete DNS record
|
|
125
|
+
*/
|
|
126
|
+
declare function validateRecord(record: DNSRecord): RecordValidationResult;
|
|
127
|
+
//#endregion
|
|
128
|
+
//#region src/types/zone.d.ts
|
|
129
|
+
/**
|
|
130
|
+
* DNS Zone Types
|
|
131
|
+
*
|
|
132
|
+
* Standard DNS zone type definitions shared across all providers.
|
|
133
|
+
*/
|
|
134
|
+
/**
|
|
135
|
+
* A DNS hosted zone
|
|
136
|
+
*/
|
|
137
|
+
interface DNSZone {
|
|
138
|
+
/** Domain name (e.g., "example.com") */
|
|
139
|
+
domain: string;
|
|
140
|
+
/** Provider-specific zone ID */
|
|
141
|
+
id: string;
|
|
142
|
+
/** Provider name (e.g., "route53", "cloudflare") */
|
|
143
|
+
provider: string;
|
|
144
|
+
/** Authoritative nameservers for this zone */
|
|
145
|
+
nameservers: string[];
|
|
146
|
+
/** When the zone was created */
|
|
147
|
+
createdAt?: Date;
|
|
148
|
+
/** Number of records in the zone */
|
|
149
|
+
recordCount?: number;
|
|
150
|
+
}
|
|
151
|
+
//#endregion
|
|
152
|
+
//#region src/clouddns/adapter.d.ts
|
|
153
|
+
/**
|
|
154
|
+
* Google Cloud DNS Zone interface (from @google-cloud/dns)
|
|
155
|
+
*/
|
|
156
|
+
interface CloudDNSZoneInterface {
|
|
157
|
+
name: string;
|
|
158
|
+
metadata: {
|
|
159
|
+
dnsName: string;
|
|
160
|
+
id: string;
|
|
161
|
+
nameServers?: string[];
|
|
162
|
+
creationTime?: string;
|
|
163
|
+
};
|
|
164
|
+
getRecords(): Promise<[CloudDNSRecordInterface[]]>;
|
|
165
|
+
createChange(config: {
|
|
166
|
+
add?: CloudDNSRecordInterface | CloudDNSRecordInterface[];
|
|
167
|
+
delete?: CloudDNSRecordInterface | CloudDNSRecordInterface[];
|
|
168
|
+
}): Promise<[{
|
|
169
|
+
id: string;
|
|
170
|
+
status: string;
|
|
171
|
+
}]>;
|
|
172
|
+
record(type: string, config: {
|
|
173
|
+
name: string;
|
|
174
|
+
ttl: number;
|
|
175
|
+
data: string | string[];
|
|
176
|
+
}): CloudDNSRecordInterface;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Google Cloud DNS Record interface
|
|
180
|
+
*/
|
|
181
|
+
interface CloudDNSRecordInterface {
|
|
182
|
+
name: string;
|
|
183
|
+
type: string;
|
|
184
|
+
ttl: number;
|
|
185
|
+
data: string[];
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Google Cloud DNS client interface (from @google-cloud/dns)
|
|
189
|
+
*/
|
|
190
|
+
interface CloudDNSClientInterface {
|
|
191
|
+
getZones(): Promise<[CloudDNSZoneInterface[]]>;
|
|
192
|
+
zone(name: string): CloudDNSZoneInterface | null;
|
|
193
|
+
}
|
|
194
|
+
interface CloudDNSAdapterOptions {
|
|
195
|
+
/** Google Cloud Project ID */
|
|
196
|
+
projectId?: string;
|
|
197
|
+
/** Path to service account key file */
|
|
198
|
+
keyFilename?: string;
|
|
199
|
+
/** Pre-configured client (for testing) */
|
|
200
|
+
client?: CloudDNSClientInterface;
|
|
201
|
+
}
|
|
202
|
+
declare class CloudDNSAdapter {
|
|
203
|
+
private client;
|
|
204
|
+
private zoneCache;
|
|
205
|
+
constructor(options?: CloudDNSAdapterOptions);
|
|
206
|
+
/**
|
|
207
|
+
* List all managed zones
|
|
208
|
+
*/
|
|
209
|
+
listZones(): Promise<DNSZone[]>;
|
|
210
|
+
/**
|
|
211
|
+
* List all record names in a zone
|
|
212
|
+
*/
|
|
213
|
+
listRecords(zoneDomain: string): Promise<string[]>;
|
|
214
|
+
/**
|
|
215
|
+
* Get all records for a specific name
|
|
216
|
+
*/
|
|
217
|
+
getRecord(zoneDomain: string, name: string): Promise<DNSRecordSet>;
|
|
218
|
+
/**
|
|
219
|
+
* Get zone metadata
|
|
220
|
+
*/
|
|
221
|
+
getZoneMetadata(zoneDomain: string): Promise<DNSZone>;
|
|
222
|
+
/**
|
|
223
|
+
* Set records for a name (create or update)
|
|
224
|
+
*/
|
|
225
|
+
setRecord(zoneDomain: string, name: string, records: DNSRecord[], _options?: {
|
|
226
|
+
force?: boolean;
|
|
227
|
+
}): Promise<void>;
|
|
228
|
+
/**
|
|
229
|
+
* Delete records for a name
|
|
230
|
+
*/
|
|
231
|
+
deleteRecord(zoneDomain: string, name: string, type?: string, _options?: {
|
|
232
|
+
force?: boolean;
|
|
233
|
+
}): Promise<void>;
|
|
234
|
+
/**
|
|
235
|
+
* Get zone by domain name
|
|
236
|
+
*/
|
|
237
|
+
private getZone;
|
|
238
|
+
/**
|
|
239
|
+
* Extract record name from FQDN
|
|
240
|
+
*/
|
|
241
|
+
private extractRecordName;
|
|
242
|
+
/**
|
|
243
|
+
* Parse Cloud DNS record to DNSRecord
|
|
244
|
+
*/
|
|
245
|
+
private parseRecord;
|
|
246
|
+
/**
|
|
247
|
+
* Build Cloud DNS record from DNSRecord
|
|
248
|
+
*/
|
|
249
|
+
private buildCloudRecord;
|
|
250
|
+
}
|
|
251
|
+
//#endregion
|
|
252
|
+
//#region src/errors/index.d.ts
|
|
253
|
+
/**
|
|
254
|
+
* DNS Provider Errors
|
|
255
|
+
*
|
|
256
|
+
* Custom error types and Route53 error mapping.
|
|
257
|
+
*/
|
|
258
|
+
declare class AFSDNSError extends Error {
|
|
259
|
+
readonly code: string;
|
|
260
|
+
readonly cause?: Error;
|
|
261
|
+
constructor(message: string, options?: {
|
|
262
|
+
code?: string;
|
|
263
|
+
cause?: Error;
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
declare class AFSDNSNotFoundError extends AFSDNSError {
|
|
267
|
+
constructor(message: string, options?: {
|
|
268
|
+
cause?: Error;
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
declare class AFSDNSPermissionDeniedError extends AFSDNSError {
|
|
272
|
+
constructor(message: string, options?: {
|
|
273
|
+
cause?: Error;
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
declare class AFSDNSRateLimitError extends AFSDNSError {
|
|
277
|
+
readonly retryAfter: number;
|
|
278
|
+
constructor(message: string, options?: {
|
|
279
|
+
cause?: Error;
|
|
280
|
+
retryAfter?: number;
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
declare class AFSDNSInvalidArgumentError extends AFSDNSError {
|
|
284
|
+
constructor(message: string, options?: {
|
|
285
|
+
cause?: Error;
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
declare class AFSDNSConflictError extends AFSDNSError {
|
|
289
|
+
constructor(message: string, options?: {
|
|
290
|
+
cause?: Error;
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
declare class AFSDNSNetworkError extends AFSDNSError {
|
|
294
|
+
constructor(message: string, options?: {
|
|
295
|
+
cause?: Error;
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Map Route53 error to AFS DNS error
|
|
300
|
+
*/
|
|
301
|
+
declare function mapRoute53Error(error: Error): AFSDNSError;
|
|
302
|
+
/**
|
|
303
|
+
* Check if an error is retryable
|
|
304
|
+
*/
|
|
305
|
+
declare function isRetryableError(error: Error): boolean;
|
|
306
|
+
/**
|
|
307
|
+
* Sanitize error message to remove sensitive information
|
|
308
|
+
*/
|
|
309
|
+
declare function sanitizeErrorMessage(message: string): string;
|
|
310
|
+
//#endregion
|
|
311
|
+
//#region src/permissions/types.d.ts
|
|
312
|
+
/**
|
|
313
|
+
* DNS Permission Types
|
|
314
|
+
*
|
|
315
|
+
* Defines dangerous operations and permission presets.
|
|
316
|
+
*/
|
|
317
|
+
/**
|
|
318
|
+
* Dangerous operations that are blocked by default
|
|
319
|
+
*/
|
|
320
|
+
type DangerousOperation = "modify_ns" | "modify_root" | "modify_wildcard" | "delete_zone";
|
|
321
|
+
/**
|
|
322
|
+
* Permission presets
|
|
323
|
+
*/
|
|
324
|
+
type PermissionPreset = "safe" | "standard" | "full";
|
|
325
|
+
/**
|
|
326
|
+
* Permission configuration
|
|
327
|
+
*/
|
|
328
|
+
interface PermissionConfig {
|
|
329
|
+
/** Preset mode */
|
|
330
|
+
preset?: PermissionPreset;
|
|
331
|
+
/** Explicit dangerous operation permissions */
|
|
332
|
+
dangerous?: Partial<Record<DangerousOperation, boolean>>;
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Preset definitions
|
|
336
|
+
*/
|
|
337
|
+
declare const PRESETS: Record<PermissionPreset, {
|
|
338
|
+
allowDelete: boolean;
|
|
339
|
+
dangerous: Record<DangerousOperation, boolean>;
|
|
340
|
+
}>;
|
|
341
|
+
//#endregion
|
|
342
|
+
//#region src/permissions/checker.d.ts
|
|
343
|
+
/**
|
|
344
|
+
* Operation context for permission checking
|
|
345
|
+
*/
|
|
346
|
+
interface OperationContext {
|
|
347
|
+
/** Record name (e.g., "www", "@", "*") */
|
|
348
|
+
name: string;
|
|
349
|
+
/** Record type (e.g., "A", "NS") */
|
|
350
|
+
type?: string;
|
|
351
|
+
/** Operation type */
|
|
352
|
+
operation: "read" | "write" | "delete";
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Permission check result
|
|
356
|
+
*/
|
|
357
|
+
interface PermissionResult {
|
|
358
|
+
allowed: boolean;
|
|
359
|
+
reason?: string;
|
|
360
|
+
requiredConfig?: string;
|
|
361
|
+
deniedOperation?: string;
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Check if an operation is allowed
|
|
365
|
+
*/
|
|
366
|
+
declare function checkPermission(context: OperationContext, config: PermissionConfig): PermissionResult;
|
|
367
|
+
/**
|
|
368
|
+
* Get effective permissions by merging preset with explicit config
|
|
369
|
+
*/
|
|
370
|
+
declare function getEffectivePermissions(config: PermissionConfig): {
|
|
371
|
+
allowDelete: boolean;
|
|
372
|
+
dangerous: Record<DangerousOperation, boolean>;
|
|
373
|
+
};
|
|
374
|
+
/**
|
|
375
|
+
* Detect if an operation is dangerous
|
|
376
|
+
*/
|
|
377
|
+
declare function detectDangerousOperation(context: OperationContext): DangerousOperation | null;
|
|
378
|
+
/**
|
|
379
|
+
* Create a user-friendly error message for permission denial
|
|
380
|
+
*/
|
|
381
|
+
declare function formatPermissionError(result: PermissionResult): string;
|
|
382
|
+
//#endregion
|
|
383
|
+
//#region src/security/audit-log.d.ts
|
|
384
|
+
/**
|
|
385
|
+
* Audit Logger
|
|
386
|
+
*
|
|
387
|
+
* Logs DNS write operations for security auditing.
|
|
388
|
+
*/
|
|
389
|
+
interface AuditLogEntry {
|
|
390
|
+
timestamp: number;
|
|
391
|
+
action: "create" | "update" | "delete" | "denied";
|
|
392
|
+
zone: string;
|
|
393
|
+
recordName: string;
|
|
394
|
+
recordType?: string;
|
|
395
|
+
values?: unknown[];
|
|
396
|
+
recordCount?: number;
|
|
397
|
+
operation?: string;
|
|
398
|
+
reason?: string;
|
|
399
|
+
context?: {
|
|
400
|
+
userId?: string;
|
|
401
|
+
sessionId?: string;
|
|
402
|
+
[key: string]: unknown;
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
interface AuditLogConfig {
|
|
406
|
+
/** Custom handler for log entries */
|
|
407
|
+
handler?: (entry: AuditLogEntry) => void;
|
|
408
|
+
/** Whether to mask sensitive values */
|
|
409
|
+
maskValues?: boolean;
|
|
410
|
+
/** Whether to store entries in memory */
|
|
411
|
+
storeInMemory?: boolean;
|
|
412
|
+
/** Maximum entries to keep in memory */
|
|
413
|
+
maxEntries?: number;
|
|
414
|
+
}
|
|
415
|
+
interface WriteLogParams {
|
|
416
|
+
zone: string;
|
|
417
|
+
recordName: string;
|
|
418
|
+
recordType: string;
|
|
419
|
+
action: "create" | "update";
|
|
420
|
+
values: unknown[];
|
|
421
|
+
context?: Record<string, unknown>;
|
|
422
|
+
}
|
|
423
|
+
interface DeleteLogParams {
|
|
424
|
+
zone: string;
|
|
425
|
+
recordName: string;
|
|
426
|
+
recordType?: string;
|
|
427
|
+
context?: Record<string, unknown>;
|
|
428
|
+
}
|
|
429
|
+
interface PermissionDeniedLogParams {
|
|
430
|
+
zone: string;
|
|
431
|
+
recordName: string;
|
|
432
|
+
operation: string;
|
|
433
|
+
reason: string;
|
|
434
|
+
context?: Record<string, unknown>;
|
|
435
|
+
}
|
|
436
|
+
declare class AuditLogger {
|
|
437
|
+
private readonly config;
|
|
438
|
+
private entries;
|
|
439
|
+
constructor(config?: AuditLogConfig);
|
|
440
|
+
/**
|
|
441
|
+
* Log a write operation
|
|
442
|
+
*/
|
|
443
|
+
logWrite(params: WriteLogParams): void;
|
|
444
|
+
/**
|
|
445
|
+
* Log a delete operation
|
|
446
|
+
*/
|
|
447
|
+
logDelete(params: DeleteLogParams): void;
|
|
448
|
+
/**
|
|
449
|
+
* Log a permission denied event
|
|
450
|
+
*/
|
|
451
|
+
logPermissionDenied(params: PermissionDeniedLogParams): void;
|
|
452
|
+
/**
|
|
453
|
+
* Get recent log entries (if storeInMemory is enabled)
|
|
454
|
+
*/
|
|
455
|
+
getRecentEntries(count: number): AuditLogEntry[];
|
|
456
|
+
/**
|
|
457
|
+
* Get entries by zone (if storeInMemory is enabled)
|
|
458
|
+
*/
|
|
459
|
+
getEntriesByZone(zone: string): AuditLogEntry[];
|
|
460
|
+
/**
|
|
461
|
+
* Emit a log entry
|
|
462
|
+
*/
|
|
463
|
+
private emit;
|
|
464
|
+
/**
|
|
465
|
+
* Mask sensitive values
|
|
466
|
+
*/
|
|
467
|
+
private maskValues;
|
|
468
|
+
/**
|
|
469
|
+
* Mask sensitive parts of a string
|
|
470
|
+
*/
|
|
471
|
+
private maskString;
|
|
472
|
+
}
|
|
473
|
+
//#endregion
|
|
474
|
+
//#region src/types/adapter.d.ts
|
|
475
|
+
/**
|
|
476
|
+
* DNS Adapter interface that all provider adapters must implement
|
|
477
|
+
*/
|
|
478
|
+
interface DNSAdapter {
|
|
479
|
+
/**
|
|
480
|
+
* List all zones available in the provider
|
|
481
|
+
*/
|
|
482
|
+
listZones(): Promise<DNSZone[]>;
|
|
483
|
+
/**
|
|
484
|
+
* List all record names in a zone
|
|
485
|
+
*/
|
|
486
|
+
listRecords(zoneDomain: string): Promise<string[]>;
|
|
487
|
+
/**
|
|
488
|
+
* Get all records for a specific name
|
|
489
|
+
*/
|
|
490
|
+
getRecord(zoneDomain: string, name: string): Promise<DNSRecordSet>;
|
|
491
|
+
/**
|
|
492
|
+
* Get zone metadata
|
|
493
|
+
*/
|
|
494
|
+
getZoneMetadata(zoneDomain: string): Promise<DNSZone>;
|
|
495
|
+
/**
|
|
496
|
+
* Set records for a name (create or update)
|
|
497
|
+
*/
|
|
498
|
+
setRecord(zoneDomain: string, name: string, records: DNSRecord[], options?: {
|
|
499
|
+
force?: boolean;
|
|
500
|
+
}): Promise<void>;
|
|
501
|
+
/**
|
|
502
|
+
* Delete records for a name
|
|
503
|
+
*/
|
|
504
|
+
deleteRecord(zoneDomain: string, name: string, type?: string, options?: {
|
|
505
|
+
force?: boolean;
|
|
506
|
+
}): Promise<void>;
|
|
507
|
+
}
|
|
508
|
+
//#endregion
|
|
509
|
+
//#region src/provider/dns-provider.d.ts
|
|
510
|
+
interface DNSProviderOptions {
|
|
511
|
+
/** Zone domain name (e.g., "example.com") */
|
|
512
|
+
zone: string;
|
|
513
|
+
/** DNS adapter (Route53, Cloud DNS, etc.) */
|
|
514
|
+
adapter: DNSAdapter;
|
|
515
|
+
/** Access mode (readonly or readwrite) */
|
|
516
|
+
accessMode?: AFSAccessMode;
|
|
517
|
+
/** Permission configuration for dangerous operations */
|
|
518
|
+
permissions?: PermissionConfig;
|
|
519
|
+
/** Audit logging configuration */
|
|
520
|
+
auditLog?: AuditLogConfig;
|
|
521
|
+
/** Enable rate limiting (default: true for Route53) */
|
|
522
|
+
rateLimiting?: boolean;
|
|
523
|
+
}
|
|
524
|
+
declare class DNSProvider implements AFSModule {
|
|
525
|
+
readonly name: string;
|
|
526
|
+
readonly description: string;
|
|
527
|
+
readonly accessMode: AFSAccessMode;
|
|
528
|
+
private zone;
|
|
529
|
+
private adapter;
|
|
530
|
+
private permissions;
|
|
531
|
+
private auditLogger;
|
|
532
|
+
private rateLimiter;
|
|
533
|
+
constructor(options: DNSProviderOptions);
|
|
534
|
+
list(path: string, options?: AFSListOptions): Promise<AFSListResult>;
|
|
535
|
+
read(path: string, _options?: AFSReadOptions): Promise<AFSReadResult>;
|
|
536
|
+
write(path: string, content: AFSWriteEntryPayload, _options?: AFSWriteOptions): Promise<AFSWriteResult>;
|
|
537
|
+
delete(path: string, _options?: AFSDeleteOptions): Promise<AFSDeleteResult>;
|
|
538
|
+
private normalizePath;
|
|
539
|
+
private extractRecordName;
|
|
540
|
+
private parsePathWithQuery;
|
|
541
|
+
/**
|
|
542
|
+
* Sanitize record values to prevent injection attacks
|
|
543
|
+
*/
|
|
544
|
+
private sanitizeRecordValues;
|
|
545
|
+
/**
|
|
546
|
+
* Acquire rate limit token (waits if necessary)
|
|
547
|
+
*/
|
|
548
|
+
private acquireRateLimit;
|
|
549
|
+
/**
|
|
550
|
+
* Extract values from a record for audit logging
|
|
551
|
+
*/
|
|
552
|
+
private extractValues;
|
|
553
|
+
}
|
|
554
|
+
//#endregion
|
|
555
|
+
//#region src/route53/adapter.d.ts
|
|
556
|
+
interface Route53AdapterOptions {
|
|
557
|
+
/** AWS Region */
|
|
558
|
+
region?: string;
|
|
559
|
+
/** Custom endpoint (for LocalStack) */
|
|
560
|
+
endpoint?: string;
|
|
561
|
+
/** AWS Credentials */
|
|
562
|
+
credentials?: {
|
|
563
|
+
accessKeyId: string;
|
|
564
|
+
secretAccessKey: string;
|
|
565
|
+
};
|
|
566
|
+
/** Pre-configured client (for testing) */
|
|
567
|
+
client?: Route53Client;
|
|
568
|
+
}
|
|
569
|
+
declare class Route53Adapter {
|
|
570
|
+
private client;
|
|
571
|
+
private zoneIdCache;
|
|
572
|
+
constructor(options?: Route53AdapterOptions);
|
|
573
|
+
/**
|
|
574
|
+
* List all hosted zones
|
|
575
|
+
*/
|
|
576
|
+
listZones(): Promise<DNSZone[]>;
|
|
577
|
+
/**
|
|
578
|
+
* List all record names in a zone
|
|
579
|
+
*/
|
|
580
|
+
listRecords(zoneDomain: string): Promise<string[]>;
|
|
581
|
+
/**
|
|
582
|
+
* Get all records for a specific name
|
|
583
|
+
*/
|
|
584
|
+
getRecord(zoneDomain: string, name: string): Promise<DNSRecordSet>;
|
|
585
|
+
/**
|
|
586
|
+
* Get zone metadata
|
|
587
|
+
*/
|
|
588
|
+
getZoneMetadata(zoneDomain: string): Promise<DNSZone>;
|
|
589
|
+
/**
|
|
590
|
+
* Set records for a name (create or update)
|
|
591
|
+
*/
|
|
592
|
+
setRecord(zoneDomain: string, name: string, records: DNSRecord[], _options?: {
|
|
593
|
+
force?: boolean;
|
|
594
|
+
}): Promise<void>;
|
|
595
|
+
/**
|
|
596
|
+
* Delete records for a name
|
|
597
|
+
*/
|
|
598
|
+
deleteRecord(zoneDomain: string, name: string, type?: string, _options?: {
|
|
599
|
+
force?: boolean;
|
|
600
|
+
}): Promise<void>;
|
|
601
|
+
/**
|
|
602
|
+
* Get zone ID from domain name
|
|
603
|
+
*/
|
|
604
|
+
private getZoneId;
|
|
605
|
+
/**
|
|
606
|
+
* Fetch all record sets for a zone (handles pagination)
|
|
607
|
+
*/
|
|
608
|
+
private fetchAllRecordSets;
|
|
609
|
+
/**
|
|
610
|
+
* Build FQDN from name and zone
|
|
611
|
+
*/
|
|
612
|
+
private buildFQDN;
|
|
613
|
+
/**
|
|
614
|
+
* Build Route53 ResourceRecordSet from DNSRecord
|
|
615
|
+
*/
|
|
616
|
+
private buildResourceRecordSet;
|
|
617
|
+
/**
|
|
618
|
+
* Build Route53 ResourceRecords from DNSRecord values
|
|
619
|
+
*/
|
|
620
|
+
private buildResourceRecords;
|
|
621
|
+
}
|
|
622
|
+
//#endregion
|
|
623
|
+
//#region src/route53/parser.d.ts
|
|
624
|
+
interface Route53HostedZone {
|
|
625
|
+
Id: string;
|
|
626
|
+
Name: string;
|
|
627
|
+
CallerReference: string;
|
|
628
|
+
Config: {
|
|
629
|
+
PrivateZone: boolean;
|
|
630
|
+
Comment?: string;
|
|
631
|
+
};
|
|
632
|
+
ResourceRecordSetCount?: number;
|
|
633
|
+
}
|
|
634
|
+
interface Route53ResourceRecord {
|
|
635
|
+
Value: string;
|
|
636
|
+
}
|
|
637
|
+
interface Route53AliasTarget {
|
|
638
|
+
HostedZoneId: string;
|
|
639
|
+
DNSName: string;
|
|
640
|
+
EvaluateTargetHealth: boolean;
|
|
641
|
+
}
|
|
642
|
+
interface Route53ResourceRecordSet {
|
|
643
|
+
Name: string;
|
|
644
|
+
Type: string;
|
|
645
|
+
TTL?: number;
|
|
646
|
+
ResourceRecords?: Route53ResourceRecord[];
|
|
647
|
+
AliasTarget?: Route53AliasTarget;
|
|
648
|
+
SetIdentifier?: string;
|
|
649
|
+
Weight?: number;
|
|
650
|
+
Region?: string;
|
|
651
|
+
GeoLocation?: Record<string, string>;
|
|
652
|
+
Failover?: string;
|
|
653
|
+
HealthCheckId?: string;
|
|
654
|
+
}
|
|
655
|
+
interface ParsedDNSRecord extends DNSRecord {
|
|
656
|
+
alias?: {
|
|
657
|
+
hostedZoneId: string;
|
|
658
|
+
dnsName: string;
|
|
659
|
+
evaluateTargetHealth: boolean;
|
|
660
|
+
};
|
|
661
|
+
}
|
|
662
|
+
interface ParsedRecordSet {
|
|
663
|
+
name: string;
|
|
664
|
+
records: ParsedDNSRecord[];
|
|
665
|
+
}
|
|
666
|
+
/**
|
|
667
|
+
* Parse Route53 hosted zones into DNSZone format
|
|
668
|
+
*/
|
|
669
|
+
declare function parseHostedZones(zones: Route53HostedZone[]): DNSZone[];
|
|
670
|
+
/**
|
|
671
|
+
* Parse Route53 resource record sets into grouped records by name
|
|
672
|
+
*/
|
|
673
|
+
declare function parseResourceRecordSets(recordSets: Route53ResourceRecordSet[], zoneName: string): ParsedRecordSet[];
|
|
674
|
+
/**
|
|
675
|
+
* Normalize a Route53 record name to our format
|
|
676
|
+
*
|
|
677
|
+
* - Removes trailing dot
|
|
678
|
+
* - Converts apex to @
|
|
679
|
+
* - Extracts subdomain part
|
|
680
|
+
*/
|
|
681
|
+
declare function normalizeRecordName(fqdn: string, zoneName: string): string;
|
|
682
|
+
//#endregion
|
|
683
|
+
//#region src/security/input-sanitizer.d.ts
|
|
684
|
+
/**
|
|
685
|
+
* Input Sanitizer
|
|
686
|
+
*
|
|
687
|
+
* Sanitizes DNS record values to prevent injection attacks.
|
|
688
|
+
*/
|
|
689
|
+
interface SanitizeResult {
|
|
690
|
+
valid: boolean;
|
|
691
|
+
value?: string;
|
|
692
|
+
error?: string;
|
|
693
|
+
}
|
|
694
|
+
/**
|
|
695
|
+
* Sanitize a TXT record value
|
|
696
|
+
*/
|
|
697
|
+
declare function sanitizeTXTValue(value: string): string;
|
|
698
|
+
/**
|
|
699
|
+
* Reject strings containing null bytes
|
|
700
|
+
*/
|
|
701
|
+
declare function rejectNullBytes(value: string | string[]): void;
|
|
702
|
+
/**
|
|
703
|
+
* Validate input length based on type
|
|
704
|
+
*/
|
|
705
|
+
declare function validateInputLength(value: string, type: "domain" | "label" | "txt"): {
|
|
706
|
+
valid: boolean;
|
|
707
|
+
error?: string;
|
|
708
|
+
};
|
|
709
|
+
/**
|
|
710
|
+
* Escape special characters based on record type
|
|
711
|
+
*/
|
|
712
|
+
declare function escapeSpecialCharacters(value: string, recordType: string): string;
|
|
713
|
+
/**
|
|
714
|
+
* Sanitize a record value based on type
|
|
715
|
+
*/
|
|
716
|
+
declare function sanitizeRecordValue(value: string, recordType: string): SanitizeResult;
|
|
717
|
+
//#endregion
|
|
718
|
+
//#region src/security/rate-limiter.d.ts
|
|
719
|
+
/**
|
|
720
|
+
* Rate Limiter
|
|
721
|
+
*
|
|
722
|
+
* Implements rate limiting for Route53 API calls.
|
|
723
|
+
* Route53 allows 5 requests per second per account.
|
|
724
|
+
*/
|
|
725
|
+
interface RateLimiterConfig {
|
|
726
|
+
/** Maximum requests per window */
|
|
727
|
+
maxRequests: number;
|
|
728
|
+
/** Window size in milliseconds */
|
|
729
|
+
windowMs: number;
|
|
730
|
+
/** Whether to queue requests instead of rejecting */
|
|
731
|
+
queueRequests?: boolean;
|
|
732
|
+
}
|
|
733
|
+
declare class RateLimiter {
|
|
734
|
+
private tokens;
|
|
735
|
+
private lastRefill;
|
|
736
|
+
private readonly config;
|
|
737
|
+
private queue;
|
|
738
|
+
constructor(config: RateLimiterConfig);
|
|
739
|
+
/**
|
|
740
|
+
* Try to acquire a token without waiting
|
|
741
|
+
* @returns true if token acquired, false if rate limited
|
|
742
|
+
*/
|
|
743
|
+
tryAcquire(): Promise<boolean>;
|
|
744
|
+
/**
|
|
745
|
+
* Acquire a token, waiting if necessary
|
|
746
|
+
* Only works if queueRequests is enabled
|
|
747
|
+
*/
|
|
748
|
+
acquire(): Promise<void>;
|
|
749
|
+
/**
|
|
750
|
+
* Get remaining tokens
|
|
751
|
+
*/
|
|
752
|
+
getRemaining(): number;
|
|
753
|
+
/**
|
|
754
|
+
* Get time until next refill in milliseconds
|
|
755
|
+
*/
|
|
756
|
+
getResetTime(): number;
|
|
757
|
+
/**
|
|
758
|
+
* Refill tokens based on elapsed time
|
|
759
|
+
*/
|
|
760
|
+
private refillTokens;
|
|
761
|
+
/**
|
|
762
|
+
* Schedule processing of queued requests
|
|
763
|
+
*/
|
|
764
|
+
private scheduleQueueProcessing;
|
|
765
|
+
/**
|
|
766
|
+
* Process queued requests
|
|
767
|
+
*/
|
|
768
|
+
private processQueue;
|
|
769
|
+
}
|
|
770
|
+
/**
|
|
771
|
+
* Create a rate limiter with Route53 defaults
|
|
772
|
+
*/
|
|
773
|
+
declare function createRoute53RateLimiter(overrides?: Partial<RateLimiterConfig>): RateLimiter;
|
|
774
|
+
//#endregion
|
|
775
|
+
//#region src/validation/name-validator.d.ts
|
|
776
|
+
/**
|
|
777
|
+
* Validate a domain name per RFC 1035
|
|
778
|
+
*
|
|
779
|
+
* @param domain - Domain name to validate (e.g., "example.com")
|
|
780
|
+
* @returns Validation result
|
|
781
|
+
*/
|
|
782
|
+
declare function validateDomainName(domain: string): ValidationResult;
|
|
783
|
+
/**
|
|
784
|
+
* Normalize a domain name to lowercase
|
|
785
|
+
*
|
|
786
|
+
* DNS is case-insensitive per RFC 1035.
|
|
787
|
+
*
|
|
788
|
+
* @param domain - Domain name to normalize
|
|
789
|
+
* @returns Normalized lowercase domain name
|
|
790
|
+
*/
|
|
791
|
+
declare function normalizeDomainName(domain: string): string;
|
|
792
|
+
/**
|
|
793
|
+
* Validate a record name within a zone
|
|
794
|
+
*
|
|
795
|
+
* Record names can be:
|
|
796
|
+
* - @ for apex (root domain)
|
|
797
|
+
* - * for wildcard
|
|
798
|
+
* - *.subdomain for scoped wildcard
|
|
799
|
+
* - Simple names like "www", "api"
|
|
800
|
+
* - Multi-level like "blog.dev"
|
|
801
|
+
* - Service records like "_dmarc", "_acme-challenge"
|
|
802
|
+
*
|
|
803
|
+
* @param name - Record name to validate
|
|
804
|
+
* @param zone - The zone this record belongs to
|
|
805
|
+
* @returns Validation result
|
|
806
|
+
*/
|
|
807
|
+
declare function validateRecordName(name: string, zone: string): ValidationResult;
|
|
808
|
+
//#endregion
|
|
809
|
+
//#region src/validation/write-validator.d.ts
|
|
810
|
+
interface WriteValidationResult {
|
|
811
|
+
valid: boolean;
|
|
812
|
+
error?: string;
|
|
813
|
+
}
|
|
814
|
+
/**
|
|
815
|
+
* Validate a complete write operation
|
|
816
|
+
*/
|
|
817
|
+
declare function validateWriteOperation(recordName: string, records: DNSRecord[]): WriteValidationResult;
|
|
818
|
+
/**
|
|
819
|
+
* Validate a record set (array of records)
|
|
820
|
+
*/
|
|
821
|
+
declare function validateRecordSet(records: DNSRecord[]): WriteValidationResult;
|
|
822
|
+
/**
|
|
823
|
+
* Check for CNAME conflicts - CNAME cannot coexist with other record types
|
|
824
|
+
*/
|
|
825
|
+
declare function checkCNAMEConflict(records: DNSRecord[]): WriteValidationResult;
|
|
826
|
+
/**
|
|
827
|
+
* Check CNAME at apex - CNAME is not allowed at the root domain
|
|
828
|
+
*/
|
|
829
|
+
declare function checkCNAMEAtApex(recordName: string, records: DNSRecord[]): WriteValidationResult;
|
|
830
|
+
/**
|
|
831
|
+
* Check SOA protection - SOA records cannot be written
|
|
832
|
+
*/
|
|
833
|
+
declare function checkSOAProtection(records: DNSRecord[]): WriteValidationResult;
|
|
834
|
+
/**
|
|
835
|
+
* Check for duplicate values within records
|
|
836
|
+
*/
|
|
837
|
+
declare function checkDuplicateValues(records: DNSRecord[]): WriteValidationResult;
|
|
838
|
+
//#endregion
|
|
839
|
+
export { AFSDNSConflictError, AFSDNSError, AFSDNSInvalidArgumentError, AFSDNSNetworkError, AFSDNSNotFoundError, AFSDNSPermissionDeniedError, AFSDNSRateLimitError, AuditLogConfig, AuditLogEntry, AuditLogger, CAAValue, CloudDNSAdapter, CloudDNSAdapterOptions, DNSAdapter, DNSProvider, DNSProviderOptions, DNSRecord, DNSRecordSet, DNSRecordType, DNSRecordValues, DNSZone, DangerousOperation, DeleteLogParams, MXValue, OperationContext, PRESETS, ParsedDNSRecord, ParsedRecordSet, PermissionConfig, PermissionDeniedLogParams, PermissionPreset, PermissionResult, RateLimiter, RateLimiterConfig, RecordValidationResult, Route53Adapter, Route53AdapterOptions, Route53AliasTarget, Route53HostedZone, Route53ResourceRecord, Route53ResourceRecordSet, SOAValue, SRVValue, SanitizeResult, ValidationResult, WriteLogParams, WriteValidationResult, checkCNAMEAtApex, checkCNAMEConflict, checkDuplicateValues, checkPermission, checkSOAProtection, createRoute53RateLimiter, detectDangerousOperation, escapeSpecialCharacters, formatPermissionError, getEffectivePermissions, isRetryableError, mapRoute53Error, normalizeDomainName, normalizeRecordName, parseHostedZones, parseResourceRecordSets, rejectNullBytes, sanitizeErrorMessage, sanitizeRecordValue, sanitizeTXTValue, validateAAAARecord, validateARecord, validateCAARecord, validateCNAMERecord, validateDomainName, validateInputLength, validateMXRecord, validateNSRecord, validateRecord, validateRecordName, validateRecordSet, validateSRVRecord, validateTTL, validateTXTRecord, validateWriteOperation };
|
|
840
|
+
//# sourceMappingURL=index.d.mts.map
|