@stacksjs/ts-cloud 0.1.9 → 0.1.14

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 (150) hide show
  1. package/README.md +39 -377
  2. package/dist/bin/cli.js +1047 -424
  3. package/dist/index.d.ts +36 -3
  4. package/dist/index.js +76430 -7096
  5. package/package.json +7 -8
  6. package/dist/aws/acm.d.ts +0 -129
  7. package/dist/aws/application-autoscaling.d.ts +0 -282
  8. package/dist/aws/bedrock.d.ts +0 -2292
  9. package/dist/aws/client.d.ts +0 -79
  10. package/dist/aws/cloudformation.d.ts +0 -105
  11. package/dist/aws/cloudfront.d.ts +0 -265
  12. package/dist/aws/cloudwatch-logs.d.ts +0 -48
  13. package/dist/aws/comprehend.d.ts +0 -505
  14. package/dist/aws/connect.d.ts +0 -377
  15. package/dist/aws/deploy-imap.d.ts +0 -14
  16. package/dist/aws/dynamodb.d.ts +0 -176
  17. package/dist/aws/ec2.d.ts +0 -272
  18. package/dist/aws/ecr.d.ts +0 -149
  19. package/dist/aws/ecs.d.ts +0 -162
  20. package/dist/aws/elasticache.d.ts +0 -71
  21. package/dist/aws/elbv2.d.ts +0 -248
  22. package/dist/aws/email.d.ts +0 -175
  23. package/dist/aws/eventbridge.d.ts +0 -142
  24. package/dist/aws/iam.d.ts +0 -638
  25. package/dist/aws/imap-server.d.ts +0 -119
  26. package/dist/aws/index.d.ts +0 -192
  27. package/dist/aws/kendra.d.ts +0 -782
  28. package/dist/aws/lambda.d.ts +0 -232
  29. package/dist/aws/opensearch.d.ts +0 -87
  30. package/dist/aws/personalize.d.ts +0 -516
  31. package/dist/aws/polly.d.ts +0 -214
  32. package/dist/aws/rds.d.ts +0 -240
  33. package/dist/aws/rekognition.d.ts +0 -543
  34. package/dist/aws/route53-domains.d.ts +0 -113
  35. package/dist/aws/route53.d.ts +0 -215
  36. package/dist/aws/s3.d.ts +0 -212
  37. package/dist/aws/scheduler.d.ts +0 -140
  38. package/dist/aws/secrets-manager.d.ts +0 -170
  39. package/dist/aws/ses.d.ts +0 -288
  40. package/dist/aws/setup-phone.d.ts +0 -0
  41. package/dist/aws/setup-sms.d.ts +0 -115
  42. package/dist/aws/sms.d.ts +0 -304
  43. package/dist/aws/smtp-server.d.ts +0 -61
  44. package/dist/aws/sns.d.ts +0 -117
  45. package/dist/aws/sqs.d.ts +0 -65
  46. package/dist/aws/ssm.d.ts +0 -179
  47. package/dist/aws/sts.d.ts +0 -15
  48. package/dist/aws/support.d.ts +0 -104
  49. package/dist/aws/test-imap.d.ts +0 -0
  50. package/dist/aws/textract.d.ts +0 -403
  51. package/dist/aws/transcribe.d.ts +0 -60
  52. package/dist/aws/translate.d.ts +0 -358
  53. package/dist/aws/voice.d.ts +0 -219
  54. package/dist/config.d.ts +0 -7
  55. package/dist/deploy/index.d.ts +0 -2
  56. package/dist/deploy/static-site-external-dns.d.ts +0 -51
  57. package/dist/deploy/static-site.d.ts +0 -71
  58. package/dist/dns/cloudflare.d.ts +0 -52
  59. package/dist/dns/godaddy.d.ts +0 -38
  60. package/dist/dns/index.d.ts +0 -45
  61. package/dist/dns/porkbun.d.ts +0 -18
  62. package/dist/dns/route53-adapter.d.ts +0 -38
  63. package/dist/dns/types.d.ts +0 -77
  64. package/dist/dns/validator.d.ts +0 -78
  65. package/dist/generators/index.d.ts +0 -1
  66. package/dist/generators/infrastructure.d.ts +0 -30
  67. package/dist/push/apns.d.ts +0 -60
  68. package/dist/push/fcm.d.ts +0 -117
  69. package/dist/push/index.d.ts +0 -14
  70. package/dist/security/pre-deploy-scanner.d.ts +0 -69
  71. package/dist/ssl/acme-client.d.ts +0 -67
  72. package/dist/ssl/index.d.ts +0 -2
  73. package/dist/ssl/letsencrypt.d.ts +0 -48
  74. package/dist/types.d.ts +0 -1
  75. package/dist/utils/cli.d.ts +0 -123
  76. package/dist/validation/index.d.ts +0 -1
  77. package/dist/validation/template.d.ts +0 -23
  78. package/src/aws/acm.ts +0 -768
  79. package/src/aws/application-autoscaling.ts +0 -845
  80. package/src/aws/bedrock.ts +0 -4074
  81. package/src/aws/client.ts +0 -891
  82. package/src/aws/cloudformation.ts +0 -896
  83. package/src/aws/cloudfront.ts +0 -1531
  84. package/src/aws/cloudwatch-logs.ts +0 -154
  85. package/src/aws/comprehend.ts +0 -839
  86. package/src/aws/connect.ts +0 -1056
  87. package/src/aws/deploy-imap.ts +0 -384
  88. package/src/aws/dynamodb.ts +0 -340
  89. package/src/aws/ec2.ts +0 -1385
  90. package/src/aws/ecr.ts +0 -621
  91. package/src/aws/ecs.ts +0 -615
  92. package/src/aws/elasticache.ts +0 -301
  93. package/src/aws/elbv2.ts +0 -942
  94. package/src/aws/email.ts +0 -928
  95. package/src/aws/eventbridge.ts +0 -248
  96. package/src/aws/iam.ts +0 -1689
  97. package/src/aws/imap-server.ts +0 -2100
  98. package/src/aws/index.ts +0 -213
  99. package/src/aws/kendra.ts +0 -1097
  100. package/src/aws/lambda.ts +0 -786
  101. package/src/aws/opensearch.ts +0 -158
  102. package/src/aws/personalize.ts +0 -977
  103. package/src/aws/polly.ts +0 -559
  104. package/src/aws/rds.ts +0 -888
  105. package/src/aws/rekognition.ts +0 -846
  106. package/src/aws/route53-domains.ts +0 -359
  107. package/src/aws/route53.ts +0 -1046
  108. package/src/aws/s3.ts +0 -2334
  109. package/src/aws/scheduler.ts +0 -571
  110. package/src/aws/secrets-manager.ts +0 -769
  111. package/src/aws/ses.ts +0 -1081
  112. package/src/aws/setup-phone.ts +0 -104
  113. package/src/aws/setup-sms.ts +0 -580
  114. package/src/aws/sms.ts +0 -1735
  115. package/src/aws/smtp-server.ts +0 -531
  116. package/src/aws/sns.ts +0 -758
  117. package/src/aws/sqs.ts +0 -382
  118. package/src/aws/ssm.ts +0 -807
  119. package/src/aws/sts.ts +0 -92
  120. package/src/aws/support.ts +0 -391
  121. package/src/aws/test-imap.ts +0 -86
  122. package/src/aws/textract.ts +0 -780
  123. package/src/aws/transcribe.ts +0 -108
  124. package/src/aws/translate.ts +0 -641
  125. package/src/aws/voice.ts +0 -1379
  126. package/src/config.ts +0 -35
  127. package/src/deploy/index.ts +0 -7
  128. package/src/deploy/static-site-external-dns.ts +0 -945
  129. package/src/deploy/static-site.ts +0 -1175
  130. package/src/dns/cloudflare.ts +0 -548
  131. package/src/dns/godaddy.ts +0 -412
  132. package/src/dns/index.ts +0 -205
  133. package/src/dns/porkbun.ts +0 -362
  134. package/src/dns/route53-adapter.ts +0 -414
  135. package/src/dns/types.ts +0 -119
  136. package/src/dns/validator.ts +0 -369
  137. package/src/generators/index.ts +0 -5
  138. package/src/generators/infrastructure.ts +0 -1660
  139. package/src/index.ts +0 -163
  140. package/src/push/apns.ts +0 -452
  141. package/src/push/fcm.ts +0 -506
  142. package/src/push/index.ts +0 -58
  143. package/src/security/pre-deploy-scanner.ts +0 -655
  144. package/src/ssl/acme-client.ts +0 -478
  145. package/src/ssl/index.ts +0 -7
  146. package/src/ssl/letsencrypt.ts +0 -747
  147. package/src/types.ts +0 -2
  148. package/src/utils/cli.ts +0 -398
  149. package/src/validation/index.ts +0 -5
  150. package/src/validation/template.ts +0 -405
@@ -1,412 +0,0 @@
1
- /**
2
- * GoDaddy DNS Provider
3
- * API documentation: https://developer.godaddy.com/doc/endpoint/domains
4
- */
5
-
6
- import type {
7
- CreateRecordResult,
8
- DeleteRecordResult,
9
- DnsProvider,
10
- DnsRecord,
11
- DnsRecordResult,
12
- DnsRecordType,
13
- ListRecordsResult,
14
- } from './types'
15
-
16
- const GODADDY_API_URL = 'https://api.godaddy.com'
17
- const GODADDY_OTE_API_URL = 'https://api.ote-godaddy.com' // Test environment
18
-
19
- interface GoDaddyRecord {
20
- type: string
21
- name: string
22
- data: string
23
- ttl: number
24
- priority?: number
25
- }
26
-
27
- export class GoDaddyProvider implements DnsProvider {
28
- readonly name = 'godaddy'
29
- private apiKey: string
30
- private apiSecret: string
31
- private baseUrl: string
32
-
33
- constructor(
34
- apiKey: string,
35
- apiSecret: string,
36
- environment: 'production' | 'ote' = 'production',
37
- ) {
38
- this.apiKey = apiKey
39
- this.apiSecret = apiSecret
40
- this.baseUrl = environment === 'ote' ? GODADDY_OTE_API_URL : GODADDY_API_URL
41
- }
42
-
43
- /**
44
- * Make an authenticated API request to GoDaddy
45
- */
46
- private async request<T>(
47
- method: string,
48
- endpoint: string,
49
- body?: any,
50
- ): Promise<T> {
51
- const url = `${this.baseUrl}${endpoint}`
52
-
53
- const headers: Record<string, string> = {
54
- 'Authorization': `sso-key ${this.apiKey}:${this.apiSecret}`,
55
- 'Content-Type': 'application/json',
56
- 'Accept': 'application/json',
57
- }
58
-
59
- const options: RequestInit = {
60
- method,
61
- headers,
62
- }
63
-
64
- if (body) {
65
- options.body = JSON.stringify(body)
66
- }
67
-
68
- const response = await fetch(url, options)
69
-
70
- // GoDaddy returns 204 for successful DELETE operations
71
- if (response.status === 204) {
72
- return {} as T
73
- }
74
-
75
- // For successful requests with content
76
- if (response.ok) {
77
- const text = await response.text()
78
- if (text) {
79
- return JSON.parse(text) as T
80
- }
81
- return {} as T
82
- }
83
-
84
- // Handle errors
85
- let errorMessage = `GoDaddy API error: ${response.status} ${response.statusText}`
86
- try {
87
- const errorData = await response.json() as Record<string, any>
88
- if (errorData.message) {
89
- errorMessage = `GoDaddy API error: ${errorData.message}`
90
- }
91
- if (errorData.fields) {
92
- errorMessage += ` - Fields: ${JSON.stringify(errorData.fields)}`
93
- }
94
- }
95
- catch {
96
- // Ignore JSON parse errors for error response
97
- }
98
-
99
- throw new Error(errorMessage)
100
- }
101
-
102
- /**
103
- * Extract the subdomain from a full record name
104
- * GoDaddy uses @ for root domain
105
- */
106
- private getSubdomain(recordName: string, domain: string): string {
107
- // Remove trailing dots
108
- const cleanName = recordName.replace(/\.$/, '')
109
- const cleanDomain = domain.replace(/\.$/, '')
110
-
111
- // If the record name equals the domain, return @ (root)
112
- if (cleanName === cleanDomain) {
113
- return '@'
114
- }
115
-
116
- // Remove the domain suffix to get the subdomain
117
- if (cleanName.endsWith(`.${cleanDomain}`)) {
118
- return cleanName.slice(0, -(cleanDomain.length + 1))
119
- }
120
-
121
- // If no match, return the full name as subdomain
122
- return cleanName
123
- }
124
-
125
- /**
126
- * Get the root domain from a full domain name
127
- */
128
- private getRootDomain(domain: string): string {
129
- const parts = domain.replace(/\.$/, '').split('.')
130
- if (parts.length >= 2) {
131
- return parts.slice(-2).join('.')
132
- }
133
- return domain
134
- }
135
-
136
- /**
137
- * Convert DnsRecord to GoDaddy record format
138
- */
139
- private toGoDaddyRecord(record: DnsRecord, domain: string): GoDaddyRecord {
140
- const rootDomain = this.getRootDomain(domain)
141
- const subdomain = this.getSubdomain(record.name, rootDomain)
142
-
143
- const gdRecord: GoDaddyRecord = {
144
- type: record.type,
145
- name: subdomain,
146
- data: record.content,
147
- ttl: record.ttl || 600,
148
- }
149
-
150
- if (record.type === 'MX' && record.priority !== undefined) {
151
- gdRecord.priority = record.priority
152
- }
153
-
154
- return gdRecord
155
- }
156
-
157
- /**
158
- * Convert GoDaddy record to DnsRecordResult format
159
- */
160
- private fromGoDaddyRecord(record: GoDaddyRecord, domain: string): DnsRecordResult {
161
- const rootDomain = this.getRootDomain(domain)
162
- let name = record.name
163
-
164
- // Convert @ to domain name and subdomain to full name
165
- if (name === '@') {
166
- name = rootDomain
167
- }
168
- else if (!name.endsWith(rootDomain)) {
169
- name = `${name}.${rootDomain}`
170
- }
171
-
172
- return {
173
- name,
174
- type: record.type as DnsRecordType,
175
- content: record.data,
176
- ttl: record.ttl,
177
- priority: record.priority,
178
- }
179
- }
180
-
181
- async createRecord(domain: string, record: DnsRecord): Promise<CreateRecordResult> {
182
- try {
183
- const rootDomain = this.getRootDomain(domain)
184
- const gdRecord = this.toGoDaddyRecord(record, domain)
185
-
186
- // GoDaddy's PATCH endpoint adds records
187
- await this.request(
188
- 'PATCH',
189
- `/v1/domains/${rootDomain}/records`,
190
- [gdRecord],
191
- )
192
-
193
- return {
194
- success: true,
195
- message: 'Record created successfully',
196
- }
197
- }
198
- catch (error) {
199
- return {
200
- success: false,
201
- message: error instanceof Error ? error.message : 'Unknown error',
202
- }
203
- }
204
- }
205
-
206
- async upsertRecord(domain: string, record: DnsRecord): Promise<CreateRecordResult> {
207
- try {
208
- const rootDomain = this.getRootDomain(domain)
209
- const gdRecord = this.toGoDaddyRecord(record, domain)
210
-
211
- // GoDaddy's PUT replaces all records of a specific type/name
212
- await this.request(
213
- 'PUT',
214
- `/v1/domains/${rootDomain}/records/${record.type}/${gdRecord.name}`,
215
- [gdRecord],
216
- )
217
-
218
- return {
219
- success: true,
220
- message: 'Record upserted successfully',
221
- }
222
- }
223
- catch (error) {
224
- // If PUT fails (record doesn't exist), try PATCH
225
- return this.createRecord(domain, record)
226
- }
227
- }
228
-
229
- async deleteRecord(domain: string, record: DnsRecord): Promise<DeleteRecordResult> {
230
- try {
231
- const rootDomain = this.getRootDomain(domain)
232
- const subdomain = this.getSubdomain(record.name, rootDomain)
233
-
234
- // GoDaddy doesn't have a direct delete endpoint
235
- // We need to get all records of this type/name and PUT back without the target
236
-
237
- const existingRecords = await this.request<GoDaddyRecord[]>(
238
- 'GET',
239
- `/v1/domains/${rootDomain}/records/${record.type}/${subdomain}`,
240
- )
241
-
242
- // Filter out the record to delete
243
- const remainingRecords = existingRecords.filter(
244
- r => r.data !== record.content,
245
- )
246
-
247
- if (remainingRecords.length === existingRecords.length) {
248
- // Record not found
249
- return {
250
- success: false,
251
- message: 'Record not found',
252
- }
253
- }
254
-
255
- if (remainingRecords.length === 0) {
256
- // GoDaddy doesn't allow empty record sets for some types
257
- // Use DELETE endpoint if available, otherwise PUT an empty array
258
- try {
259
- await this.request(
260
- 'DELETE',
261
- `/v1/domains/${rootDomain}/records/${record.type}/${subdomain}`,
262
- )
263
- }
264
- catch {
265
- // Some record types can't be fully deleted, that's OK
266
- }
267
- }
268
- else {
269
- // Replace with remaining records
270
- await this.request(
271
- 'PUT',
272
- `/v1/domains/${rootDomain}/records/${record.type}/${subdomain}`,
273
- remainingRecords,
274
- )
275
- }
276
-
277
- return {
278
- success: true,
279
- message: 'Record deleted successfully',
280
- }
281
- }
282
- catch (error) {
283
- return {
284
- success: false,
285
- message: error instanceof Error ? error.message : 'Unknown error',
286
- }
287
- }
288
- }
289
-
290
- async listRecords(domain: string, type?: DnsRecordType): Promise<ListRecordsResult> {
291
- try {
292
- const rootDomain = this.getRootDomain(domain)
293
-
294
- let endpoint = `/v1/domains/${rootDomain}/records`
295
- if (type) {
296
- endpoint = `/v1/domains/${rootDomain}/records/${type}`
297
- }
298
-
299
- const records = await this.request<GoDaddyRecord[]>('GET', endpoint)
300
-
301
- return {
302
- success: true,
303
- records: records.map(r => this.fromGoDaddyRecord(r, domain)),
304
- }
305
- }
306
- catch (error) {
307
- return {
308
- success: false,
309
- records: [],
310
- message: error instanceof Error ? error.message : 'Unknown error',
311
- }
312
- }
313
- }
314
-
315
- async canManageDomain(domain: string): Promise<boolean> {
316
- try {
317
- const rootDomain = this.getRootDomain(domain)
318
- // Try to get domain details
319
- await this.request('GET', `/v1/domains/${rootDomain}`)
320
- return true
321
- }
322
- catch {
323
- return false
324
- }
325
- }
326
-
327
- /**
328
- * List all domains managed by this GoDaddy account
329
- */
330
- async listDomains(): Promise<string[]> {
331
- try {
332
- const response = await this.request<Array<{ domain: string }>>('GET', '/v1/domains')
333
- return response.map(d => d.domain)
334
- }
335
- catch {
336
- return []
337
- }
338
- }
339
-
340
- /**
341
- * Get domain details (GoDaddy-specific)
342
- */
343
- async getDomainDetails(domain: string): Promise<{
344
- domain: string
345
- status: string
346
- nameServers?: string[]
347
- expires?: string
348
- } | null> {
349
- try {
350
- const rootDomain = this.getRootDomain(domain)
351
- const details = await this.request<any>('GET', `/v1/domains/${rootDomain}`)
352
-
353
- return {
354
- domain: details.domain,
355
- status: details.status,
356
- nameServers: details.nameServers,
357
- expires: details.expires,
358
- }
359
- }
360
- catch {
361
- return null
362
- }
363
- }
364
-
365
- /**
366
- * Update nameservers for a domain (GoDaddy-specific)
367
- */
368
- async updateNameServers(domain: string, nameservers: string[]): Promise<boolean> {
369
- try {
370
- const rootDomain = this.getRootDomain(domain)
371
- await this.request(
372
- 'PUT',
373
- `/v1/domains/${rootDomain}/records/NS`,
374
- nameservers.map(ns => ({
375
- type: 'NS',
376
- name: '@',
377
- data: ns,
378
- ttl: 3600,
379
- })),
380
- )
381
- return true
382
- }
383
- catch {
384
- return false
385
- }
386
- }
387
-
388
- /**
389
- * Check domain availability (GoDaddy-specific)
390
- */
391
- async checkDomainAvailability(domain: string): Promise<{
392
- available: boolean
393
- price?: number
394
- currency?: string
395
- }> {
396
- try {
397
- const result = await this.request<any>(
398
- 'GET',
399
- `/v1/domains/available?domain=${encodeURIComponent(domain)}`,
400
- )
401
-
402
- return {
403
- available: result.available,
404
- price: result.price,
405
- currency: result.currency,
406
- }
407
- }
408
- catch {
409
- return { available: false }
410
- }
411
- }
412
- }
package/src/dns/index.ts DELETED
@@ -1,205 +0,0 @@
1
- /**
2
- * DNS Provider Module
3
- * Unified DNS management for Route53, Porkbun, and GoDaddy
4
- */
5
-
6
- export * from './types'
7
- export { PorkbunProvider } from './porkbun'
8
- export { GoDaddyProvider } from './godaddy'
9
- export { CloudflareProvider } from './cloudflare'
10
- export { Route53Provider } from './route53-adapter'
11
- export {
12
- UnifiedDnsValidator,
13
- createPorkbunValidator,
14
- createGoDaddyValidator,
15
- createRoute53Validator,
16
- } from './validator'
17
-
18
- import type { DnsProvider, DnsProviderConfig } from './types'
19
- import { CloudflareProvider } from './cloudflare'
20
- import { GoDaddyProvider } from './godaddy'
21
- import { PorkbunProvider } from './porkbun'
22
- import { Route53Provider } from './route53-adapter'
23
-
24
- /**
25
- * Create a DNS provider from configuration
26
- */
27
- export function createDnsProvider(config: DnsProviderConfig): DnsProvider {
28
- switch (config.provider) {
29
- case 'route53':
30
- return new Route53Provider(config.region, config.hostedZoneId)
31
-
32
- case 'porkbun':
33
- return new PorkbunProvider(config.apiKey, config.secretKey)
34
-
35
- case 'godaddy':
36
- return new GoDaddyProvider(config.apiKey, config.apiSecret, config.environment)
37
-
38
- case 'cloudflare':
39
- return new CloudflareProvider(config.apiToken)
40
-
41
- default:
42
- throw new Error(`Unknown DNS provider: ${(config as any).provider}`)
43
- }
44
- }
45
-
46
- /**
47
- * Auto-detect DNS provider for a domain
48
- * Tries each provider to see which one can manage the domain
49
- */
50
- export async function detectDnsProvider(
51
- domain: string,
52
- configs: DnsProviderConfig[],
53
- ): Promise<DnsProvider | null> {
54
- for (const config of configs) {
55
- const provider = createDnsProvider(config)
56
- if (await provider.canManageDomain(domain)) {
57
- return provider
58
- }
59
- }
60
- return null
61
- }
62
-
63
- /**
64
- * DNS Provider factory with environment variable support
65
- */
66
- export class DnsProviderFactory {
67
- private providers: Map<string, DnsProvider> = new Map()
68
- private configs: DnsProviderConfig[] = []
69
-
70
- /**
71
- * Add provider configuration
72
- */
73
- addConfig(config: DnsProviderConfig): this {
74
- this.configs.push(config)
75
- return this
76
- }
77
-
78
- /**
79
- * Add Route53 provider
80
- */
81
- addRoute53(region?: string, hostedZoneId?: string): this {
82
- this.configs.push({
83
- provider: 'route53',
84
- region,
85
- hostedZoneId,
86
- })
87
- return this
88
- }
89
-
90
- /**
91
- * Add Porkbun provider
92
- */
93
- addPorkbun(apiKey: string, secretKey: string): this {
94
- this.configs.push({
95
- provider: 'porkbun',
96
- apiKey,
97
- secretKey,
98
- })
99
- return this
100
- }
101
-
102
- /**
103
- * Add GoDaddy provider
104
- */
105
- addGoDaddy(apiKey: string, apiSecret: string, environment?: 'production' | 'ote'): this {
106
- this.configs.push({
107
- provider: 'godaddy',
108
- apiKey,
109
- apiSecret,
110
- environment,
111
- })
112
- return this
113
- }
114
-
115
- /**
116
- * Add Cloudflare provider
117
- */
118
- addCloudflare(apiToken: string): this {
119
- this.configs.push({
120
- provider: 'cloudflare',
121
- apiToken,
122
- })
123
- return this
124
- }
125
-
126
- /**
127
- * Load providers from environment variables
128
- */
129
- loadFromEnv(): this {
130
- // Route53 (uses AWS credentials from environment)
131
- if (process.env.AWS_ACCESS_KEY_ID || process.env.AWS_REGION) {
132
- this.addRoute53(process.env.AWS_REGION)
133
- }
134
-
135
- // Porkbun
136
- const porkbunApiKey = process.env.PORKBUN_API_KEY
137
- const porkbunSecretKey = process.env.PORKBUN_SECRET_KEY
138
- if (porkbunApiKey && porkbunSecretKey) {
139
- this.addPorkbun(porkbunApiKey, porkbunSecretKey)
140
- }
141
-
142
- // GoDaddy
143
- const godaddyApiKey = process.env.GODADDY_API_KEY
144
- const godaddyApiSecret = process.env.GODADDY_API_SECRET
145
- if (godaddyApiKey && godaddyApiSecret) {
146
- const env = process.env.GODADDY_ENVIRONMENT as 'production' | 'ote' | undefined
147
- this.addGoDaddy(godaddyApiKey, godaddyApiSecret, env)
148
- }
149
-
150
- // Cloudflare
151
- const cloudflareApiToken = process.env.CLOUDFLARE_API_TOKEN
152
- if (cloudflareApiToken) {
153
- this.addCloudflare(cloudflareApiToken)
154
- }
155
-
156
- return this
157
- }
158
-
159
- /**
160
- * Get a provider by name
161
- */
162
- getProvider(name: 'route53' | 'porkbun' | 'godaddy' | 'cloudflare'): DnsProvider | null {
163
- // Check cache
164
- const cached = this.providers.get(name)
165
- if (cached) {
166
- return cached
167
- }
168
-
169
- // Find config
170
- const config = this.configs.find(c => c.provider === name)
171
- if (!config) {
172
- return null
173
- }
174
-
175
- // Create and cache provider
176
- const provider = createDnsProvider(config)
177
- this.providers.set(name, provider)
178
- return provider
179
- }
180
-
181
- /**
182
- * Auto-detect provider for a domain
183
- */
184
- async getProviderForDomain(domain: string): Promise<DnsProvider | null> {
185
- for (const config of this.configs) {
186
- const provider = createDnsProvider(config)
187
- if (await provider.canManageDomain(domain)) {
188
- return provider
189
- }
190
- }
191
- return null
192
- }
193
-
194
- /**
195
- * Get all configured providers
196
- */
197
- getAllProviders(): DnsProvider[] {
198
- return this.configs.map(config => createDnsProvider(config))
199
- }
200
- }
201
-
202
- /**
203
- * Default factory instance (can be configured globally)
204
- */
205
- export const dnsProviders: DnsProviderFactory = new DnsProviderFactory()