@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
package/src/aws/sns.ts DELETED
@@ -1,758 +0,0 @@
1
- /**
2
- * AWS SNS (Simple Notification Service) Operations
3
- * Direct API calls without AWS SDK dependency
4
- */
5
-
6
- import { AWSClient } from './client'
7
-
8
- export interface SNSTopicAttributes {
9
- TopicArn?: string
10
- DisplayName?: string
11
- Policy?: string
12
- Owner?: string
13
- SubscriptionsPending?: string
14
- SubscriptionsConfirmed?: string
15
- SubscriptionsDeleted?: string
16
- DeliveryPolicy?: string
17
- EffectiveDeliveryPolicy?: string
18
- KmsMasterKeyId?: string
19
- }
20
-
21
- export interface SNSSubscriptionAttributes {
22
- SubscriptionArn?: string
23
- TopicArn?: string
24
- Protocol?: string
25
- Endpoint?: string
26
- Owner?: string
27
- ConfirmationWasAuthenticated?: string
28
- RawMessageDelivery?: string
29
- FilterPolicy?: string
30
- }
31
-
32
- export type SNSProtocol = 'http' | 'https' | 'email' | 'email-json' | 'sms' | 'sqs' | 'application' | 'lambda'
33
-
34
- /**
35
- * SNS service management using direct API calls
36
- */
37
- export class SNSClient {
38
- private client: AWSClient
39
- private region: string
40
-
41
- constructor(region: string = 'us-east-1') {
42
- this.region = region
43
- this.client = new AWSClient()
44
- }
45
-
46
- /**
47
- * Build form-encoded body for SNS API
48
- */
49
- private buildFormBody(params: Record<string, string | undefined>): string {
50
- const entries = Object.entries(params)
51
- .filter(([, value]) => value !== undefined)
52
- .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value!)}`)
53
- return entries.join('&')
54
- }
55
-
56
- /**
57
- * Create a new SNS topic
58
- */
59
- async createTopic(params: {
60
- Name: string
61
- DisplayName?: string
62
- Tags?: Array<{ Key: string, Value: string }>
63
- Attributes?: Record<string, string>
64
- }): Promise<{ TopicArn?: string }> {
65
- const formParams: Record<string, string | undefined> = {
66
- Action: 'CreateTopic',
67
- Version: '2010-03-31',
68
- Name: params.Name,
69
- }
70
-
71
- if (params.DisplayName) {
72
- formParams['Attributes.entry.1.key'] = 'DisplayName'
73
- formParams['Attributes.entry.1.value'] = params.DisplayName
74
- }
75
-
76
- if (params.Tags) {
77
- params.Tags.forEach((tag, index) => {
78
- formParams[`Tags.member.${index + 1}.Key`] = tag.Key
79
- formParams[`Tags.member.${index + 1}.Value`] = tag.Value
80
- })
81
- }
82
-
83
- if (params.Attributes) {
84
- let attrIndex = params.DisplayName ? 2 : 1
85
- Object.entries(params.Attributes).forEach(([key, value]) => {
86
- formParams[`Attributes.entry.${attrIndex}.key`] = key
87
- formParams[`Attributes.entry.${attrIndex}.value`] = value
88
- attrIndex++
89
- })
90
- }
91
-
92
- const result = await this.client.request({
93
- service: 'sns',
94
- region: this.region,
95
- method: 'POST',
96
- path: '/',
97
- headers: {
98
- 'Content-Type': 'application/x-www-form-urlencoded',
99
- },
100
- body: this.buildFormBody(formParams),
101
- })
102
-
103
- return {
104
- TopicArn: result?.CreateTopicResponse?.CreateTopicResult?.TopicArn
105
- || result?.TopicArn,
106
- }
107
- }
108
-
109
- /**
110
- * Delete an SNS topic
111
- */
112
- async deleteTopic(topicArn: string): Promise<void> {
113
- await this.client.request({
114
- service: 'sns',
115
- region: this.region,
116
- method: 'POST',
117
- path: '/',
118
- headers: {
119
- 'Content-Type': 'application/x-www-form-urlencoded',
120
- },
121
- body: this.buildFormBody({
122
- Action: 'DeleteTopic',
123
- Version: '2010-03-31',
124
- TopicArn: topicArn,
125
- }),
126
- })
127
- }
128
-
129
- /**
130
- * List all SNS topics
131
- */
132
- async listTopics(nextToken?: string): Promise<{
133
- Topics?: Array<{ TopicArn?: string }>
134
- NextToken?: string
135
- }> {
136
- const formParams: Record<string, string | undefined> = {
137
- Action: 'ListTopics',
138
- Version: '2010-03-31',
139
- }
140
-
141
- if (nextToken) {
142
- formParams.NextToken = nextToken
143
- }
144
-
145
- const result = await this.client.request({
146
- service: 'sns',
147
- region: this.region,
148
- method: 'POST',
149
- path: '/',
150
- headers: {
151
- 'Content-Type': 'application/x-www-form-urlencoded',
152
- },
153
- body: this.buildFormBody(formParams),
154
- })
155
-
156
- // Handle both response formats (with and without ListTopicsResponse wrapper)
157
- const listResult = result?.ListTopicsResponse?.ListTopicsResult || result?.ListTopicsResult
158
- const topics = listResult?.Topics?.member
159
- return {
160
- Topics: Array.isArray(topics) ? topics : topics ? [topics] : [],
161
- NextToken: listResult?.NextToken,
162
- }
163
- }
164
-
165
- /**
166
- * Get topic attributes
167
- */
168
- async getTopicAttributes(topicArn: string): Promise<SNSTopicAttributes> {
169
- const result = await this.client.request({
170
- service: 'sns',
171
- region: this.region,
172
- method: 'POST',
173
- path: '/',
174
- headers: {
175
- 'Content-Type': 'application/x-www-form-urlencoded',
176
- },
177
- body: this.buildFormBody({
178
- Action: 'GetTopicAttributes',
179
- Version: '2010-03-31',
180
- TopicArn: topicArn,
181
- }),
182
- })
183
-
184
- const attributes = result?.GetTopicAttributesResponse?.GetTopicAttributesResult?.Attributes?.entry
185
- const attrs: SNSTopicAttributes = { TopicArn: topicArn }
186
-
187
- if (Array.isArray(attributes)) {
188
- attributes.forEach((entry: { key: string, value: string }) => {
189
- (attrs as any)[entry.key] = entry.value
190
- })
191
- }
192
-
193
- return attrs
194
- }
195
-
196
- /**
197
- * Set topic attributes
198
- */
199
- async setTopicAttributes(params: {
200
- TopicArn: string
201
- AttributeName: string
202
- AttributeValue: string
203
- }): Promise<void> {
204
- await this.client.request({
205
- service: 'sns',
206
- region: this.region,
207
- method: 'POST',
208
- path: '/',
209
- headers: {
210
- 'Content-Type': 'application/x-www-form-urlencoded',
211
- },
212
- body: this.buildFormBody({
213
- Action: 'SetTopicAttributes',
214
- Version: '2010-03-31',
215
- TopicArn: params.TopicArn,
216
- AttributeName: params.AttributeName,
217
- AttributeValue: params.AttributeValue,
218
- }),
219
- })
220
- }
221
-
222
- /**
223
- * Subscribe to a topic
224
- */
225
- async subscribe(params: {
226
- TopicArn: string
227
- Protocol: SNSProtocol
228
- Endpoint: string
229
- Attributes?: Record<string, string>
230
- ReturnSubscriptionArn?: boolean
231
- }): Promise<{ SubscriptionArn?: string }> {
232
- const formParams: Record<string, string | undefined> = {
233
- Action: 'Subscribe',
234
- Version: '2010-03-31',
235
- TopicArn: params.TopicArn,
236
- Protocol: params.Protocol,
237
- Endpoint: params.Endpoint,
238
- }
239
-
240
- if (params.ReturnSubscriptionArn) {
241
- formParams.ReturnSubscriptionArn = 'true'
242
- }
243
-
244
- if (params.Attributes) {
245
- let attrIndex = 1
246
- Object.entries(params.Attributes).forEach(([key, value]) => {
247
- formParams[`Attributes.entry.${attrIndex}.key`] = key
248
- formParams[`Attributes.entry.${attrIndex}.value`] = value
249
- attrIndex++
250
- })
251
- }
252
-
253
- const result = await this.client.request({
254
- service: 'sns',
255
- region: this.region,
256
- method: 'POST',
257
- path: '/',
258
- headers: {
259
- 'Content-Type': 'application/x-www-form-urlencoded',
260
- },
261
- body: this.buildFormBody(formParams),
262
- })
263
-
264
- return {
265
- SubscriptionArn: result?.SubscribeResponse?.SubscribeResult?.SubscriptionArn
266
- || result?.SubscriptionArn,
267
- }
268
- }
269
-
270
- /**
271
- * Unsubscribe from a topic
272
- */
273
- async unsubscribe(subscriptionArn: string): Promise<void> {
274
- await this.client.request({
275
- service: 'sns',
276
- region: this.region,
277
- method: 'POST',
278
- path: '/',
279
- headers: {
280
- 'Content-Type': 'application/x-www-form-urlencoded',
281
- },
282
- body: this.buildFormBody({
283
- Action: 'Unsubscribe',
284
- Version: '2010-03-31',
285
- SubscriptionArn: subscriptionArn,
286
- }),
287
- })
288
- }
289
-
290
- /**
291
- * List subscriptions for a topic
292
- */
293
- async listSubscriptionsByTopic(topicArn: string, nextToken?: string): Promise<{
294
- Subscriptions?: SNSSubscriptionAttributes[]
295
- NextToken?: string
296
- }> {
297
- const formParams: Record<string, string | undefined> = {
298
- Action: 'ListSubscriptionsByTopic',
299
- Version: '2010-03-31',
300
- TopicArn: topicArn,
301
- }
302
-
303
- if (nextToken) {
304
- formParams.NextToken = nextToken
305
- }
306
-
307
- const result = await this.client.request({
308
- service: 'sns',
309
- region: this.region,
310
- method: 'POST',
311
- path: '/',
312
- headers: {
313
- 'Content-Type': 'application/x-www-form-urlencoded',
314
- },
315
- body: this.buildFormBody(formParams),
316
- })
317
-
318
- const subs = result?.ListSubscriptionsByTopicResponse?.ListSubscriptionsByTopicResult?.Subscriptions?.member
319
- return {
320
- Subscriptions: Array.isArray(subs) ? subs : subs ? [subs] : [],
321
- NextToken: result?.ListSubscriptionsByTopicResponse?.ListSubscriptionsByTopicResult?.NextToken,
322
- }
323
- }
324
-
325
- /**
326
- * Publish a message to a topic
327
- */
328
- async publish(params: {
329
- TopicArn?: string
330
- TargetArn?: string
331
- PhoneNumber?: string
332
- Message: string
333
- Subject?: string
334
- MessageStructure?: 'json'
335
- MessageAttributes?: Record<string, {
336
- DataType: 'String' | 'Number' | 'Binary'
337
- StringValue?: string
338
- BinaryValue?: string
339
- }>
340
- }): Promise<{ MessageId?: string }> {
341
- const formParams: Record<string, string | undefined> = {
342
- Action: 'Publish',
343
- Version: '2010-03-31',
344
- Message: params.Message,
345
- }
346
-
347
- if (params.TopicArn) formParams.TopicArn = params.TopicArn
348
- if (params.TargetArn) formParams.TargetArn = params.TargetArn
349
- if (params.PhoneNumber) formParams.PhoneNumber = params.PhoneNumber
350
- if (params.Subject) formParams.Subject = params.Subject
351
- if (params.MessageStructure) formParams.MessageStructure = params.MessageStructure
352
-
353
- if (params.MessageAttributes) {
354
- let attrIndex = 1
355
- Object.entries(params.MessageAttributes).forEach(([name, attr]) => {
356
- formParams[`MessageAttributes.entry.${attrIndex}.Name`] = name
357
- formParams[`MessageAttributes.entry.${attrIndex}.Value.DataType`] = attr.DataType
358
- if (attr.StringValue) {
359
- formParams[`MessageAttributes.entry.${attrIndex}.Value.StringValue`] = attr.StringValue
360
- }
361
- if (attr.BinaryValue) {
362
- formParams[`MessageAttributes.entry.${attrIndex}.Value.BinaryValue`] = attr.BinaryValue
363
- }
364
- attrIndex++
365
- })
366
- }
367
-
368
- const result = await this.client.request({
369
- service: 'sns',
370
- region: this.region,
371
- method: 'POST',
372
- path: '/',
373
- headers: {
374
- 'Content-Type': 'application/x-www-form-urlencoded',
375
- },
376
- body: this.buildFormBody(formParams),
377
- })
378
-
379
- return {
380
- MessageId: result?.PublishResponse?.PublishResult?.MessageId
381
- || result?.MessageId,
382
- }
383
- }
384
-
385
- /**
386
- * Publish SMS message directly (without topic)
387
- */
388
- async publishSMS(phoneNumber: string, message: string, senderId?: string): Promise<{ MessageId?: string }> {
389
- const messageAttributes: Record<string, { DataType: 'String', StringValue: string }> = {}
390
-
391
- if (senderId) {
392
- messageAttributes['AWS.SNS.SMS.SenderID'] = {
393
- DataType: 'String',
394
- StringValue: senderId,
395
- }
396
- }
397
-
398
- return this.publish({
399
- PhoneNumber: phoneNumber,
400
- Message: message,
401
- MessageAttributes: Object.keys(messageAttributes).length > 0 ? messageAttributes : undefined,
402
- })
403
- }
404
-
405
- /**
406
- * Subscribe an email address to a topic
407
- */
408
- async subscribeEmail(topicArn: string, email: string): Promise<{ SubscriptionArn?: string }> {
409
- return this.subscribe({
410
- TopicArn: topicArn,
411
- Protocol: 'email',
412
- Endpoint: email,
413
- })
414
- }
415
-
416
- /**
417
- * Subscribe a Lambda function to a topic
418
- */
419
- async subscribeLambda(topicArn: string, lambdaArn: string): Promise<{ SubscriptionArn?: string }> {
420
- return this.subscribe({
421
- TopicArn: topicArn,
422
- Protocol: 'lambda',
423
- Endpoint: lambdaArn,
424
- })
425
- }
426
-
427
- /**
428
- * Subscribe an SQS queue to a topic
429
- */
430
- async subscribeSqs(topicArn: string, queueArn: string, rawMessageDelivery?: boolean): Promise<{ SubscriptionArn?: string }> {
431
- const attributes: Record<string, string> = {}
432
- if (rawMessageDelivery) {
433
- attributes.RawMessageDelivery = 'true'
434
- }
435
-
436
- return this.subscribe({
437
- TopicArn: topicArn,
438
- Protocol: 'sqs',
439
- Endpoint: queueArn,
440
- Attributes: Object.keys(attributes).length > 0 ? attributes : undefined,
441
- })
442
- }
443
-
444
- /**
445
- * Subscribe an HTTP/HTTPS endpoint to a topic
446
- */
447
- async subscribeHttp(topicArn: string, url: string, rawMessageDelivery?: boolean): Promise<{ SubscriptionArn?: string }> {
448
- const protocol: SNSProtocol = url.startsWith('https') ? 'https' : 'http'
449
- const attributes: Record<string, string> = {}
450
- if (rawMessageDelivery) {
451
- attributes.RawMessageDelivery = 'true'
452
- }
453
-
454
- return this.subscribe({
455
- TopicArn: topicArn,
456
- Protocol: protocol,
457
- Endpoint: url,
458
- Attributes: Object.keys(attributes).length > 0 ? attributes : undefined,
459
- })
460
- }
461
-
462
- /**
463
- * Subscribe an SMS number to a topic
464
- */
465
- async subscribeSms(topicArn: string, phoneNumber: string): Promise<{ SubscriptionArn?: string }> {
466
- return this.subscribe({
467
- TopicArn: topicArn,
468
- Protocol: 'sms',
469
- Endpoint: phoneNumber,
470
- })
471
- }
472
-
473
- /**
474
- * Check if topic exists
475
- */
476
- async topicExists(topicArn: string): Promise<boolean> {
477
- try {
478
- await this.getTopicAttributes(topicArn)
479
- return true
480
- }
481
- catch (error: any) {
482
- if (error.code === 'NotFound' || error.statusCode === 404) {
483
- return false
484
- }
485
- throw error
486
- }
487
- }
488
-
489
- /**
490
- * Get SMS attributes (sandbox status, spending limits, etc.)
491
- */
492
- async getSMSAttributes(): Promise<{
493
- MonthlySpendLimit?: string
494
- DeliveryStatusIAMRole?: string
495
- DeliveryStatusSuccessSamplingRate?: string
496
- DefaultSenderID?: string
497
- DefaultSMSType?: 'Promotional' | 'Transactional'
498
- UsageReportS3Bucket?: string
499
- }> {
500
- const result = await this.client.request({
501
- service: 'sns',
502
- region: this.region,
503
- method: 'POST',
504
- path: '/',
505
- headers: {
506
- 'Content-Type': 'application/x-www-form-urlencoded',
507
- },
508
- body: this.buildFormBody({
509
- Action: 'GetSMSAttributes',
510
- Version: '2010-03-31',
511
- }),
512
- })
513
-
514
- const attrs = result?.GetSMSAttributesResponse?.GetSMSAttributesResult?.attributes?.entry
515
- const attributes: Record<string, string> = {}
516
-
517
- if (Array.isArray(attrs)) {
518
- attrs.forEach((entry: { key: string, value: string }) => {
519
- attributes[entry.key] = entry.value
520
- })
521
- } else if (attrs) {
522
- attributes[attrs.key] = attrs.value
523
- }
524
-
525
- return attributes
526
- }
527
-
528
- /**
529
- * Set SMS attributes (sender ID, message type, etc.)
530
- */
531
- async setSMSAttributes(attributes: {
532
- MonthlySpendLimit?: string
533
- DeliveryStatusIAMRole?: string
534
- DeliveryStatusSuccessSamplingRate?: string
535
- DefaultSenderID?: string
536
- DefaultSMSType?: 'Promotional' | 'Transactional'
537
- UsageReportS3Bucket?: string
538
- }): Promise<void> {
539
- const formParams: Record<string, string | undefined> = {
540
- Action: 'SetSMSAttributes',
541
- Version: '2010-03-31',
542
- }
543
-
544
- let attrIndex = 1
545
- Object.entries(attributes).forEach(([key, value]) => {
546
- if (value !== undefined) {
547
- formParams[`attributes.entry.${attrIndex}.key`] = key
548
- formParams[`attributes.entry.${attrIndex}.value`] = value
549
- attrIndex++
550
- }
551
- })
552
-
553
- await this.client.request({
554
- service: 'sns',
555
- region: this.region,
556
- method: 'POST',
557
- path: '/',
558
- headers: {
559
- 'Content-Type': 'application/x-www-form-urlencoded',
560
- },
561
- body: this.buildFormBody(formParams),
562
- })
563
- }
564
-
565
- /**
566
- * Check if phone number is opted out
567
- */
568
- async checkIfPhoneNumberIsOptedOut(phoneNumber: string): Promise<boolean> {
569
- const result = await this.client.request({
570
- service: 'sns',
571
- region: this.region,
572
- method: 'POST',
573
- path: '/',
574
- headers: {
575
- 'Content-Type': 'application/x-www-form-urlencoded',
576
- },
577
- body: this.buildFormBody({
578
- Action: 'CheckIfPhoneNumberIsOptedOut',
579
- Version: '2010-03-31',
580
- phoneNumber: phoneNumber,
581
- }),
582
- })
583
-
584
- return result?.CheckIfPhoneNumberIsOptedOutResponse?.CheckIfPhoneNumberIsOptedOutResult?.isOptedOut === 'true'
585
- }
586
-
587
- /**
588
- * List phone numbers that have opted out of receiving SMS
589
- */
590
- async listPhoneNumbersOptedOut(nextToken?: string): Promise<{
591
- phoneNumbers?: string[]
592
- nextToken?: string
593
- }> {
594
- const formParams: Record<string, string | undefined> = {
595
- Action: 'ListPhoneNumbersOptedOut',
596
- Version: '2010-03-31',
597
- }
598
- if (nextToken) formParams.nextToken = nextToken
599
-
600
- const result = await this.client.request({
601
- service: 'sns',
602
- region: this.region,
603
- method: 'POST',
604
- path: '/',
605
- headers: {
606
- 'Content-Type': 'application/x-www-form-urlencoded',
607
- },
608
- body: this.buildFormBody(formParams),
609
- })
610
-
611
- const phones = result?.ListPhoneNumbersOptedOutResponse?.ListPhoneNumbersOptedOutResult?.phoneNumbers?.member
612
- return {
613
- phoneNumbers: Array.isArray(phones) ? phones : phones ? [phones] : [],
614
- nextToken: result?.ListPhoneNumbersOptedOutResponse?.ListPhoneNumbersOptedOutResult?.nextToken,
615
- }
616
- }
617
-
618
- /**
619
- * Opt a phone number back in to receive SMS (requires user consent)
620
- */
621
- async optInPhoneNumber(phoneNumber: string): Promise<void> {
622
- await this.client.request({
623
- service: 'sns',
624
- region: this.region,
625
- method: 'POST',
626
- path: '/',
627
- headers: {
628
- 'Content-Type': 'application/x-www-form-urlencoded',
629
- },
630
- body: this.buildFormBody({
631
- Action: 'OptInPhoneNumber',
632
- Version: '2010-03-31',
633
- phoneNumber: phoneNumber,
634
- }),
635
- })
636
- }
637
-
638
- /**
639
- * List sandbox phone numbers (for SMS sandbox mode)
640
- */
641
- async listSMSSandboxPhoneNumbers(nextToken?: string): Promise<{
642
- PhoneNumbers?: Array<{
643
- PhoneNumber?: string
644
- Status?: 'Pending' | 'Verified'
645
- }>
646
- NextToken?: string
647
- }> {
648
- const formParams: Record<string, string | undefined> = {
649
- Action: 'ListSMSSandboxPhoneNumbers',
650
- Version: '2010-03-31',
651
- }
652
- if (nextToken) formParams.NextToken = nextToken
653
-
654
- const result = await this.client.request({
655
- service: 'sns',
656
- region: this.region,
657
- method: 'POST',
658
- path: '/',
659
- headers: {
660
- 'Content-Type': 'application/x-www-form-urlencoded',
661
- },
662
- body: this.buildFormBody(formParams),
663
- })
664
-
665
- const phones = result?.ListSMSSandboxPhoneNumbersResponse?.ListSMSSandboxPhoneNumbersResult?.PhoneNumbers?.member
666
- return {
667
- PhoneNumbers: Array.isArray(phones) ? phones : phones ? [phones] : [],
668
- NextToken: result?.ListSMSSandboxPhoneNumbersResponse?.ListSMSSandboxPhoneNumbersResult?.NextToken,
669
- }
670
- }
671
-
672
- /**
673
- * Create a sandbox phone number for testing
674
- */
675
- async createSMSSandboxPhoneNumber(phoneNumber: string, languageCode?: string): Promise<void> {
676
- await this.client.request({
677
- service: 'sns',
678
- region: this.region,
679
- method: 'POST',
680
- path: '/',
681
- headers: {
682
- 'Content-Type': 'application/x-www-form-urlencoded',
683
- },
684
- body: this.buildFormBody({
685
- Action: 'CreateSMSSandboxPhoneNumber',
686
- Version: '2010-03-31',
687
- PhoneNumber: phoneNumber,
688
- LanguageCode: languageCode || 'en-US',
689
- }),
690
- })
691
- }
692
-
693
- /**
694
- * Verify a sandbox phone number with OTP
695
- */
696
- async verifySMSSandboxPhoneNumber(phoneNumber: string, oneTimePassword: string): Promise<void> {
697
- await this.client.request({
698
- service: 'sns',
699
- region: this.region,
700
- method: 'POST',
701
- path: '/',
702
- headers: {
703
- 'Content-Type': 'application/x-www-form-urlencoded',
704
- },
705
- body: this.buildFormBody({
706
- Action: 'VerifySMSSandboxPhoneNumber',
707
- Version: '2010-03-31',
708
- PhoneNumber: phoneNumber,
709
- OneTimePassword: oneTimePassword,
710
- }),
711
- })
712
- }
713
-
714
- /**
715
- * Delete a sandbox phone number
716
- */
717
- async deleteSMSSandboxPhoneNumber(phoneNumber: string): Promise<void> {
718
- await this.client.request({
719
- service: 'sns',
720
- region: this.region,
721
- method: 'POST',
722
- path: '/',
723
- headers: {
724
- 'Content-Type': 'application/x-www-form-urlencoded',
725
- },
726
- body: this.buildFormBody({
727
- Action: 'DeleteSMSSandboxPhoneNumber',
728
- Version: '2010-03-31',
729
- PhoneNumber: phoneNumber,
730
- }),
731
- })
732
- }
733
-
734
- /**
735
- * Get SMS sandbox account status
736
- */
737
- async getSMSSandboxAccountStatus(): Promise<{
738
- IsInSandbox: boolean
739
- }> {
740
- const result = await this.client.request({
741
- service: 'sns',
742
- region: this.region,
743
- method: 'POST',
744
- path: '/',
745
- headers: {
746
- 'Content-Type': 'application/x-www-form-urlencoded',
747
- },
748
- body: this.buildFormBody({
749
- Action: 'GetSMSSandboxAccountStatus',
750
- Version: '2010-03-31',
751
- }),
752
- })
753
-
754
- return {
755
- IsInSandbox: result?.GetSMSSandboxAccountStatusResponse?.GetSMSSandboxAccountStatusResult?.IsInSandbox === 'true',
756
- }
757
- }
758
- }