@stacksjs/ts-cloud 0.1.8 → 0.1.9
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/bin/cli.js +1 -1
- package/package.json +18 -16
- package/src/aws/acm.ts +768 -0
- package/src/aws/application-autoscaling.ts +845 -0
- package/src/aws/bedrock.ts +4074 -0
- package/src/aws/client.ts +891 -0
- package/src/aws/cloudformation.ts +896 -0
- package/src/aws/cloudfront.ts +1531 -0
- package/src/aws/cloudwatch-logs.ts +154 -0
- package/src/aws/comprehend.ts +839 -0
- package/src/aws/connect.ts +1056 -0
- package/src/aws/deploy-imap.ts +384 -0
- package/src/aws/dynamodb.ts +340 -0
- package/src/aws/ec2.ts +1385 -0
- package/src/aws/ecr.ts +621 -0
- package/src/aws/ecs.ts +615 -0
- package/src/aws/elasticache.ts +301 -0
- package/src/aws/elbv2.ts +942 -0
- package/src/aws/email.ts +928 -0
- package/src/aws/eventbridge.ts +248 -0
- package/src/aws/iam.ts +1689 -0
- package/src/aws/imap-server.ts +2100 -0
- package/src/aws/index.ts +213 -0
- package/src/aws/kendra.ts +1097 -0
- package/src/aws/lambda.ts +786 -0
- package/src/aws/opensearch.ts +158 -0
- package/src/aws/personalize.ts +977 -0
- package/src/aws/polly.ts +559 -0
- package/src/aws/rds.ts +888 -0
- package/src/aws/rekognition.ts +846 -0
- package/src/aws/route53-domains.ts +359 -0
- package/src/aws/route53.ts +1046 -0
- package/src/aws/s3.ts +2334 -0
- package/src/aws/scheduler.ts +571 -0
- package/src/aws/secrets-manager.ts +769 -0
- package/src/aws/ses.ts +1081 -0
- package/src/aws/setup-phone.ts +104 -0
- package/src/aws/setup-sms.ts +580 -0
- package/src/aws/sms.ts +1735 -0
- package/src/aws/smtp-server.ts +531 -0
- package/src/aws/sns.ts +758 -0
- package/src/aws/sqs.ts +382 -0
- package/src/aws/ssm.ts +807 -0
- package/src/aws/sts.ts +92 -0
- package/src/aws/support.ts +391 -0
- package/src/aws/test-imap.ts +86 -0
- package/src/aws/textract.ts +780 -0
- package/src/aws/transcribe.ts +108 -0
- package/src/aws/translate.ts +641 -0
- package/src/aws/voice.ts +1379 -0
- package/src/config.ts +35 -0
- package/src/deploy/index.ts +7 -0
- package/src/deploy/static-site-external-dns.ts +945 -0
- package/src/deploy/static-site.ts +1175 -0
- package/src/dns/cloudflare.ts +548 -0
- package/src/dns/godaddy.ts +412 -0
- package/src/dns/index.ts +205 -0
- package/src/dns/porkbun.ts +362 -0
- package/src/dns/route53-adapter.ts +414 -0
- package/src/dns/types.ts +119 -0
- package/src/dns/validator.ts +369 -0
- package/src/generators/index.ts +5 -0
- package/src/generators/infrastructure.ts +1660 -0
- package/src/index.ts +163 -0
- package/src/push/apns.ts +452 -0
- package/src/push/fcm.ts +506 -0
- package/src/push/index.ts +58 -0
- package/src/security/pre-deploy-scanner.ts +655 -0
- package/src/ssl/acme-client.ts +478 -0
- package/src/ssl/index.ts +7 -0
- package/src/ssl/letsencrypt.ts +747 -0
- package/src/types.ts +2 -0
- package/src/utils/cli.ts +398 -0
- package/src/validation/index.ts +5 -0
- package/src/validation/template.ts +405 -0
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Route53 DNS Provider Adapter
|
|
3
|
+
* Wraps the existing Route53Client to implement the DnsProvider interface
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { Route53Client } from '../aws/route53'
|
|
7
|
+
import type {
|
|
8
|
+
CreateRecordResult,
|
|
9
|
+
DeleteRecordResult,
|
|
10
|
+
DnsProvider,
|
|
11
|
+
DnsRecord,
|
|
12
|
+
DnsRecordResult,
|
|
13
|
+
DnsRecordType,
|
|
14
|
+
ListRecordsResult,
|
|
15
|
+
} from './types'
|
|
16
|
+
|
|
17
|
+
export class Route53Provider implements DnsProvider {
|
|
18
|
+
readonly name = 'route53'
|
|
19
|
+
private client: Route53Client
|
|
20
|
+
private hostedZoneCache: Map<string, string> = new Map()
|
|
21
|
+
private providedHostedZoneId?: string
|
|
22
|
+
|
|
23
|
+
constructor(region: string = 'us-east-1', hostedZoneId?: string) {
|
|
24
|
+
this.client = new Route53Client(region)
|
|
25
|
+
this.providedHostedZoneId = hostedZoneId
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Get the root domain from a full domain name
|
|
30
|
+
*/
|
|
31
|
+
private getRootDomain(domain: string): string {
|
|
32
|
+
const parts = domain.replace(/\.$/, '').split('.')
|
|
33
|
+
if (parts.length >= 2) {
|
|
34
|
+
return parts.slice(-2).join('.')
|
|
35
|
+
}
|
|
36
|
+
return domain
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Get the hosted zone ID for a domain
|
|
41
|
+
*/
|
|
42
|
+
private async getHostedZoneId(domain: string): Promise<string | null> {
|
|
43
|
+
// If a hosted zone ID was provided, use it
|
|
44
|
+
if (this.providedHostedZoneId) {
|
|
45
|
+
return this.providedHostedZoneId
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const rootDomain = this.getRootDomain(domain)
|
|
49
|
+
|
|
50
|
+
// Check cache
|
|
51
|
+
const cached = this.hostedZoneCache.get(rootDomain)
|
|
52
|
+
if (cached) {
|
|
53
|
+
return cached
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Find the hosted zone
|
|
57
|
+
const zone = await this.client.findHostedZoneForDomain(domain)
|
|
58
|
+
if (zone) {
|
|
59
|
+
const zoneId = zone.Id.replace('/hostedzone/', '')
|
|
60
|
+
this.hostedZoneCache.set(rootDomain, zoneId)
|
|
61
|
+
return zoneId
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return null
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Ensure domain name ends with a dot (Route53 requirement)
|
|
69
|
+
*/
|
|
70
|
+
private normalizeName(name: string): string {
|
|
71
|
+
return name.endsWith('.') ? name : `${name}.`
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async createRecord(domain: string, record: DnsRecord): Promise<CreateRecordResult> {
|
|
75
|
+
try {
|
|
76
|
+
const hostedZoneId = await this.getHostedZoneId(domain)
|
|
77
|
+
if (!hostedZoneId) {
|
|
78
|
+
return {
|
|
79
|
+
success: false,
|
|
80
|
+
message: `No hosted zone found for domain: ${domain}`,
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const recordName = this.normalizeName(record.name)
|
|
85
|
+
let recordValue = record.content
|
|
86
|
+
|
|
87
|
+
// TXT records need to be quoted
|
|
88
|
+
if (record.type === 'TXT' && !recordValue.startsWith('"')) {
|
|
89
|
+
recordValue = `"${recordValue}"`
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// MX records need priority prefix
|
|
93
|
+
if (record.type === 'MX' && record.priority !== undefined) {
|
|
94
|
+
recordValue = `${record.priority} ${recordValue}`
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const result = await this.client.changeResourceRecordSets({
|
|
98
|
+
HostedZoneId: hostedZoneId,
|
|
99
|
+
ChangeBatch: {
|
|
100
|
+
Comment: `Created by ts-cloud DNS provider`,
|
|
101
|
+
Changes: [{
|
|
102
|
+
Action: 'CREATE',
|
|
103
|
+
ResourceRecordSet: {
|
|
104
|
+
Name: recordName,
|
|
105
|
+
Type: record.type,
|
|
106
|
+
TTL: record.ttl || 300,
|
|
107
|
+
ResourceRecords: [{ Value: recordValue }],
|
|
108
|
+
},
|
|
109
|
+
}],
|
|
110
|
+
},
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
return {
|
|
114
|
+
success: true,
|
|
115
|
+
id: result.ChangeInfo?.Id,
|
|
116
|
+
message: 'Record created successfully',
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
return {
|
|
121
|
+
success: false,
|
|
122
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
async upsertRecord(domain: string, record: DnsRecord): Promise<CreateRecordResult> {
|
|
128
|
+
try {
|
|
129
|
+
const hostedZoneId = await this.getHostedZoneId(domain)
|
|
130
|
+
if (!hostedZoneId) {
|
|
131
|
+
return {
|
|
132
|
+
success: false,
|
|
133
|
+
message: `No hosted zone found for domain: ${domain}`,
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const recordName = this.normalizeName(record.name)
|
|
138
|
+
let recordValue = record.content
|
|
139
|
+
|
|
140
|
+
// TXT records need to be quoted
|
|
141
|
+
if (record.type === 'TXT' && !recordValue.startsWith('"')) {
|
|
142
|
+
recordValue = `"${recordValue}"`
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// MX records need priority prefix
|
|
146
|
+
if (record.type === 'MX' && record.priority !== undefined) {
|
|
147
|
+
recordValue = `${record.priority} ${recordValue}`
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const result = await this.client.changeResourceRecordSets({
|
|
151
|
+
HostedZoneId: hostedZoneId,
|
|
152
|
+
ChangeBatch: {
|
|
153
|
+
Comment: `Upserted by ts-cloud DNS provider`,
|
|
154
|
+
Changes: [{
|
|
155
|
+
Action: 'UPSERT',
|
|
156
|
+
ResourceRecordSet: {
|
|
157
|
+
Name: recordName,
|
|
158
|
+
Type: record.type,
|
|
159
|
+
TTL: record.ttl || 300,
|
|
160
|
+
ResourceRecords: [{ Value: recordValue }],
|
|
161
|
+
},
|
|
162
|
+
}],
|
|
163
|
+
},
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
return {
|
|
167
|
+
success: true,
|
|
168
|
+
id: result.ChangeInfo?.Id,
|
|
169
|
+
message: 'Record upserted successfully',
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
catch (error) {
|
|
173
|
+
return {
|
|
174
|
+
success: false,
|
|
175
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
async deleteRecord(domain: string, record: DnsRecord): Promise<DeleteRecordResult> {
|
|
181
|
+
try {
|
|
182
|
+
const hostedZoneId = await this.getHostedZoneId(domain)
|
|
183
|
+
if (!hostedZoneId) {
|
|
184
|
+
return {
|
|
185
|
+
success: false,
|
|
186
|
+
message: `No hosted zone found for domain: ${domain}`,
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const recordName = this.normalizeName(record.name)
|
|
191
|
+
let recordValue = record.content
|
|
192
|
+
|
|
193
|
+
// TXT records need to be quoted
|
|
194
|
+
if (record.type === 'TXT' && !recordValue.startsWith('"')) {
|
|
195
|
+
recordValue = `"${recordValue}"`
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// MX records need priority prefix
|
|
199
|
+
if (record.type === 'MX' && record.priority !== undefined) {
|
|
200
|
+
recordValue = `${record.priority} ${recordValue}`
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
await this.client.changeResourceRecordSets({
|
|
204
|
+
HostedZoneId: hostedZoneId,
|
|
205
|
+
ChangeBatch: {
|
|
206
|
+
Comment: `Deleted by ts-cloud DNS provider`,
|
|
207
|
+
Changes: [{
|
|
208
|
+
Action: 'DELETE',
|
|
209
|
+
ResourceRecordSet: {
|
|
210
|
+
Name: recordName,
|
|
211
|
+
Type: record.type,
|
|
212
|
+
TTL: record.ttl || 300,
|
|
213
|
+
ResourceRecords: [{ Value: recordValue }],
|
|
214
|
+
},
|
|
215
|
+
}],
|
|
216
|
+
},
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
return {
|
|
220
|
+
success: true,
|
|
221
|
+
message: 'Record deleted successfully',
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
catch (error) {
|
|
225
|
+
return {
|
|
226
|
+
success: false,
|
|
227
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
async listRecords(domain: string, type?: DnsRecordType): Promise<ListRecordsResult> {
|
|
233
|
+
try {
|
|
234
|
+
const hostedZoneId = await this.getHostedZoneId(domain)
|
|
235
|
+
if (!hostedZoneId) {
|
|
236
|
+
return {
|
|
237
|
+
success: false,
|
|
238
|
+
records: [],
|
|
239
|
+
message: `No hosted zone found for domain: ${domain}`,
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const result = await this.client.listResourceRecordSets({
|
|
244
|
+
HostedZoneId: hostedZoneId,
|
|
245
|
+
StartRecordType: type,
|
|
246
|
+
})
|
|
247
|
+
|
|
248
|
+
const records: DnsRecordResult[] = []
|
|
249
|
+
|
|
250
|
+
for (const rs of result.ResourceRecordSets) {
|
|
251
|
+
// Filter by type if specified
|
|
252
|
+
if (type && rs.Type !== type) {
|
|
253
|
+
continue
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Skip alias records for now (they don't have ResourceRecords)
|
|
257
|
+
if (rs.AliasTarget) {
|
|
258
|
+
continue
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
for (const rr of rs.ResourceRecords || []) {
|
|
262
|
+
let content = rr.Value
|
|
263
|
+
let priority: number | undefined
|
|
264
|
+
|
|
265
|
+
// Extract MX priority
|
|
266
|
+
if (rs.Type === 'MX') {
|
|
267
|
+
const parts = content.split(' ')
|
|
268
|
+
if (parts.length >= 2) {
|
|
269
|
+
priority = Number.parseInt(parts[0], 10)
|
|
270
|
+
content = parts.slice(1).join(' ')
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// Remove TXT record quotes
|
|
275
|
+
if (rs.Type === 'TXT' && content.startsWith('"') && content.endsWith('"')) {
|
|
276
|
+
content = content.slice(1, -1)
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
records.push({
|
|
280
|
+
name: rs.Name.replace(/\.$/, ''),
|
|
281
|
+
type: rs.Type as DnsRecordType,
|
|
282
|
+
content,
|
|
283
|
+
ttl: rs.TTL,
|
|
284
|
+
priority,
|
|
285
|
+
})
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
return {
|
|
290
|
+
success: true,
|
|
291
|
+
records,
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
catch (error) {
|
|
295
|
+
return {
|
|
296
|
+
success: false,
|
|
297
|
+
records: [],
|
|
298
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
async canManageDomain(domain: string): Promise<boolean> {
|
|
304
|
+
const hostedZoneId = await this.getHostedZoneId(domain)
|
|
305
|
+
return hostedZoneId !== null
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* List all domains (hosted zones) managed in Route53
|
|
310
|
+
*/
|
|
311
|
+
async listDomains(): Promise<string[]> {
|
|
312
|
+
try {
|
|
313
|
+
const result = await this.client.listHostedZones()
|
|
314
|
+
return result.HostedZones.map(z => z.Name.replace(/\.$/, ''))
|
|
315
|
+
}
|
|
316
|
+
catch {
|
|
317
|
+
return []
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Get the underlying Route53Client for advanced operations
|
|
323
|
+
*/
|
|
324
|
+
getRoute53Client(): Route53Client {
|
|
325
|
+
return this.client
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Create an alias record (Route53-specific feature)
|
|
330
|
+
* Useful for CloudFront, ALB, etc.
|
|
331
|
+
*/
|
|
332
|
+
async createAliasRecord(params: {
|
|
333
|
+
domain: string
|
|
334
|
+
name: string
|
|
335
|
+
targetHostedZoneId: string
|
|
336
|
+
targetDnsName: string
|
|
337
|
+
evaluateTargetHealth?: boolean
|
|
338
|
+
type?: 'A' | 'AAAA'
|
|
339
|
+
}): Promise<CreateRecordResult> {
|
|
340
|
+
try {
|
|
341
|
+
const hostedZoneId = await this.getHostedZoneId(params.domain)
|
|
342
|
+
if (!hostedZoneId) {
|
|
343
|
+
return {
|
|
344
|
+
success: false,
|
|
345
|
+
message: `No hosted zone found for domain: ${params.domain}`,
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
const result = await this.client.createAliasRecord({
|
|
350
|
+
HostedZoneId: hostedZoneId,
|
|
351
|
+
Name: this.normalizeName(params.name),
|
|
352
|
+
TargetHostedZoneId: params.targetHostedZoneId,
|
|
353
|
+
TargetDNSName: params.targetDnsName,
|
|
354
|
+
EvaluateTargetHealth: params.evaluateTargetHealth,
|
|
355
|
+
Type: params.type,
|
|
356
|
+
})
|
|
357
|
+
|
|
358
|
+
return {
|
|
359
|
+
success: true,
|
|
360
|
+
id: result.ChangeInfo?.Id,
|
|
361
|
+
message: 'Alias record created successfully',
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
catch (error) {
|
|
365
|
+
return {
|
|
366
|
+
success: false,
|
|
367
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Create CloudFront alias record (convenience method)
|
|
374
|
+
*/
|
|
375
|
+
async createCloudFrontAlias(params: {
|
|
376
|
+
domain: string
|
|
377
|
+
name: string
|
|
378
|
+
cloudFrontDomainName: string
|
|
379
|
+
}): Promise<CreateRecordResult> {
|
|
380
|
+
return this.createAliasRecord({
|
|
381
|
+
domain: params.domain,
|
|
382
|
+
name: params.name,
|
|
383
|
+
targetHostedZoneId: Route53Client.CloudFrontHostedZoneId,
|
|
384
|
+
targetDnsName: params.cloudFrontDomainName,
|
|
385
|
+
evaluateTargetHealth: false,
|
|
386
|
+
})
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Create ALB alias record (convenience method)
|
|
391
|
+
*/
|
|
392
|
+
async createAlbAlias(params: {
|
|
393
|
+
domain: string
|
|
394
|
+
name: string
|
|
395
|
+
albDnsName: string
|
|
396
|
+
region: string
|
|
397
|
+
}): Promise<CreateRecordResult> {
|
|
398
|
+
const hostedZoneId = Route53Client.ALBHostedZoneIds[params.region]
|
|
399
|
+
if (!hostedZoneId) {
|
|
400
|
+
return {
|
|
401
|
+
success: false,
|
|
402
|
+
message: `Unknown region for ALB: ${params.region}`,
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
return this.createAliasRecord({
|
|
407
|
+
domain: params.domain,
|
|
408
|
+
name: params.name,
|
|
409
|
+
targetHostedZoneId: hostedZoneId,
|
|
410
|
+
targetDnsName: params.albDnsName,
|
|
411
|
+
evaluateTargetHealth: true,
|
|
412
|
+
})
|
|
413
|
+
}
|
|
414
|
+
}
|
package/src/dns/types.ts
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DNS Provider Types
|
|
3
|
+
* Common interfaces for DNS provider abstraction
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export type DnsRecordType = 'A' | 'AAAA' | 'CNAME' | 'TXT' | 'MX' | 'NS' | 'SRV' | 'CAA'
|
|
7
|
+
|
|
8
|
+
export interface DnsRecord {
|
|
9
|
+
name: string
|
|
10
|
+
type: DnsRecordType
|
|
11
|
+
content: string
|
|
12
|
+
/** Alias for content - some providers use 'value' instead */
|
|
13
|
+
value?: string
|
|
14
|
+
ttl?: number
|
|
15
|
+
priority?: number // For MX and SRV records
|
|
16
|
+
weight?: number // For SRV records
|
|
17
|
+
port?: number // For SRV records
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface DnsRecordResult extends DnsRecord {
|
|
21
|
+
id?: string
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface CreateRecordResult {
|
|
25
|
+
success: boolean
|
|
26
|
+
id?: string
|
|
27
|
+
message?: string
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface DeleteRecordResult {
|
|
31
|
+
success: boolean
|
|
32
|
+
message?: string
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface ListRecordsResult {
|
|
36
|
+
success: boolean
|
|
37
|
+
records: DnsRecordResult[]
|
|
38
|
+
message?: string
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Common DNS Provider interface
|
|
43
|
+
* All DNS providers (Route53, Porkbun, GoDaddy, etc.) implement this
|
|
44
|
+
*/
|
|
45
|
+
export interface DnsProvider {
|
|
46
|
+
/**
|
|
47
|
+
* Provider name for logging/identification
|
|
48
|
+
*/
|
|
49
|
+
readonly name: string
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Create a DNS record
|
|
53
|
+
*/
|
|
54
|
+
createRecord(domain: string, record: DnsRecord): Promise<CreateRecordResult>
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Update an existing DNS record (upsert behavior)
|
|
58
|
+
*/
|
|
59
|
+
upsertRecord(domain: string, record: DnsRecord): Promise<CreateRecordResult>
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Delete a DNS record
|
|
63
|
+
*/
|
|
64
|
+
deleteRecord(domain: string, record: DnsRecord): Promise<DeleteRecordResult>
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* List all DNS records for a domain
|
|
68
|
+
*/
|
|
69
|
+
listRecords(domain: string, type?: DnsRecordType): Promise<ListRecordsResult>
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Check if the provider can manage this domain
|
|
73
|
+
*/
|
|
74
|
+
canManageDomain(domain: string): Promise<boolean>
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* List all domains managed by this provider
|
|
78
|
+
* Returns an array of domain names (e.g., ['example.com', 'mysite.org'])
|
|
79
|
+
*/
|
|
80
|
+
listDomains(): Promise<string[]>
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* DNS Provider configuration types
|
|
85
|
+
*/
|
|
86
|
+
export interface Route53ProviderConfig {
|
|
87
|
+
provider: 'route53'
|
|
88
|
+
region?: string
|
|
89
|
+
hostedZoneId?: string // Optional - will be auto-discovered if not provided
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export interface PorkbunProviderConfig {
|
|
93
|
+
provider: 'porkbun'
|
|
94
|
+
apiKey: string
|
|
95
|
+
secretKey: string
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export interface GoDaddyProviderConfig {
|
|
99
|
+
provider: 'godaddy'
|
|
100
|
+
apiKey: string
|
|
101
|
+
apiSecret: string
|
|
102
|
+
environment?: 'production' | 'ote' // OTE = test environment
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export interface CloudflareProviderConfig {
|
|
106
|
+
provider: 'cloudflare'
|
|
107
|
+
apiToken: string // API Token (recommended) - create at https://dash.cloudflare.com/profile/api-tokens
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export type DnsProviderConfig = Route53ProviderConfig | PorkbunProviderConfig | GoDaddyProviderConfig | CloudflareProviderConfig
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Extended configuration for certificate validation
|
|
114
|
+
*/
|
|
115
|
+
export interface CertificateValidationConfig {
|
|
116
|
+
provider: DnsProviderConfig
|
|
117
|
+
waitForValidation?: boolean
|
|
118
|
+
maxWaitMinutes?: number
|
|
119
|
+
}
|