@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
package/src/aws/sts.ts
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AWS STS Operations
|
|
3
|
+
* Direct API calls without AWS CLI dependency
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { AWSClient } from './client'
|
|
7
|
+
|
|
8
|
+
export interface CallerIdentity {
|
|
9
|
+
UserId?: string
|
|
10
|
+
Account?: string
|
|
11
|
+
Arn?: string
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* STS (Security Token Service) management using direct API calls
|
|
16
|
+
*/
|
|
17
|
+
export class STSClient {
|
|
18
|
+
private client: AWSClient
|
|
19
|
+
private region: string
|
|
20
|
+
|
|
21
|
+
constructor(region: string = 'us-east-1', profile?: string) {
|
|
22
|
+
this.region = region
|
|
23
|
+
this.client = new AWSClient()
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Get information about the IAM identity whose credentials are used to call the operation
|
|
28
|
+
*/
|
|
29
|
+
async getCallerIdentity(): Promise<CallerIdentity> {
|
|
30
|
+
const result = await this.client.request({
|
|
31
|
+
service: 'sts',
|
|
32
|
+
region: this.region,
|
|
33
|
+
method: 'POST',
|
|
34
|
+
path: '/',
|
|
35
|
+
headers: {
|
|
36
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
37
|
+
},
|
|
38
|
+
body: 'Action=GetCallerIdentity&Version=2011-06-15',
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
// Parse XML response
|
|
42
|
+
// The response will be in XML format like:
|
|
43
|
+
// <GetCallerIdentityResponse>
|
|
44
|
+
// <GetCallerIdentityResult>
|
|
45
|
+
// <Account>123456789012</Account>
|
|
46
|
+
// <UserId>AIDAI...</UserId>
|
|
47
|
+
// <Arn>arn:aws:iam::...</Arn>
|
|
48
|
+
// </GetCallerIdentityResult>
|
|
49
|
+
// </GetCallerIdentityResponse>
|
|
50
|
+
|
|
51
|
+
if (typeof result === 'string') {
|
|
52
|
+
const accountMatch = result.match(/<Account>(\d+)<\/Account>/)
|
|
53
|
+
const userIdMatch = result.match(/<UserId>([^<]+)<\/UserId>/)
|
|
54
|
+
const arnMatch = result.match(/<Arn>([^<]+)<\/Arn>/)
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
Account: accountMatch?.[1],
|
|
58
|
+
UserId: userIdMatch?.[1],
|
|
59
|
+
Arn: arnMatch?.[1],
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Handle parsed XML response - the structure can be either:
|
|
64
|
+
// 1. { GetCallerIdentityResponse: { GetCallerIdentityResult: { Account, UserId, Arn } } }
|
|
65
|
+
// 2. { GetCallerIdentityResult: { Account, UserId, Arn } } (more common)
|
|
66
|
+
const identityResult = result?.GetCallerIdentityResponse?.GetCallerIdentityResult
|
|
67
|
+
|| result?.GetCallerIdentityResult
|
|
68
|
+
|
|
69
|
+
if (identityResult) {
|
|
70
|
+
return {
|
|
71
|
+
Account: String(identityResult.Account),
|
|
72
|
+
UserId: identityResult.UserId,
|
|
73
|
+
Arn: identityResult.Arn,
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Direct object structure
|
|
78
|
+
if (result?.Account) {
|
|
79
|
+
return {
|
|
80
|
+
Account: String(result.Account),
|
|
81
|
+
UserId: result.UserId,
|
|
82
|
+
Arn: result.Arn,
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
Account: undefined,
|
|
88
|
+
UserId: undefined,
|
|
89
|
+
Arn: undefined,
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AWS Support API Operations
|
|
3
|
+
* Automates support ticket creation for service limit increases and sandbox exits
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { AWSClient } from './client'
|
|
7
|
+
|
|
8
|
+
export interface SupportCase {
|
|
9
|
+
caseId?: string
|
|
10
|
+
displayId?: string
|
|
11
|
+
subject?: string
|
|
12
|
+
status?: string
|
|
13
|
+
serviceCode?: string
|
|
14
|
+
categoryCode?: string
|
|
15
|
+
severityCode?: string
|
|
16
|
+
submittedBy?: string
|
|
17
|
+
timeCreated?: string
|
|
18
|
+
recentCommunications?: {
|
|
19
|
+
communications?: Array<{
|
|
20
|
+
body?: string
|
|
21
|
+
submittedBy?: string
|
|
22
|
+
timeCreated?: string
|
|
23
|
+
}>
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface CreateCaseParams {
|
|
28
|
+
subject: string
|
|
29
|
+
communicationBody: string
|
|
30
|
+
serviceCode: string
|
|
31
|
+
categoryCode: string
|
|
32
|
+
severityCode?: 'low' | 'normal' | 'high' | 'urgent' | 'critical'
|
|
33
|
+
ccEmailAddresses?: string[]
|
|
34
|
+
language?: string
|
|
35
|
+
issueType?: 'customer-service' | 'technical'
|
|
36
|
+
attachmentSetId?: string
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface SupportService {
|
|
40
|
+
code: string
|
|
41
|
+
name: string
|
|
42
|
+
categories?: Array<{
|
|
43
|
+
code: string
|
|
44
|
+
name: string
|
|
45
|
+
}>
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* AWS Support client for creating and managing support cases
|
|
50
|
+
*/
|
|
51
|
+
export class SupportClient {
|
|
52
|
+
private client: AWSClient
|
|
53
|
+
private region: string
|
|
54
|
+
|
|
55
|
+
constructor(region: string = 'us-east-1') {
|
|
56
|
+
this.region = region
|
|
57
|
+
this.client = new AWSClient()
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Create a new support case
|
|
62
|
+
*/
|
|
63
|
+
async createCase(params: CreateCaseParams): Promise<{ caseId?: string }> {
|
|
64
|
+
const result = await this.client.request({
|
|
65
|
+
service: 'support',
|
|
66
|
+
region: this.region,
|
|
67
|
+
method: 'POST',
|
|
68
|
+
path: '/',
|
|
69
|
+
headers: {
|
|
70
|
+
'Content-Type': 'application/x-amz-json-1.1',
|
|
71
|
+
'X-Amz-Target': 'AWSSupport_20130415.CreateCase',
|
|
72
|
+
},
|
|
73
|
+
body: JSON.stringify({
|
|
74
|
+
subject: params.subject,
|
|
75
|
+
communicationBody: params.communicationBody,
|
|
76
|
+
serviceCode: params.serviceCode,
|
|
77
|
+
categoryCode: params.categoryCode,
|
|
78
|
+
severityCode: params.severityCode || 'normal',
|
|
79
|
+
ccEmailAddresses: params.ccEmailAddresses,
|
|
80
|
+
language: params.language || 'en',
|
|
81
|
+
issueType: params.issueType || 'customer-service',
|
|
82
|
+
attachmentSetId: params.attachmentSetId,
|
|
83
|
+
}),
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
return result as { caseId?: string }
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Get details of a support case
|
|
91
|
+
*/
|
|
92
|
+
async describeCase(caseId: string): Promise<SupportCase | null> {
|
|
93
|
+
const result = await this.client.request({
|
|
94
|
+
service: 'support',
|
|
95
|
+
region: this.region,
|
|
96
|
+
method: 'POST',
|
|
97
|
+
path: '/',
|
|
98
|
+
headers: {
|
|
99
|
+
'Content-Type': 'application/x-amz-json-1.1',
|
|
100
|
+
'X-Amz-Target': 'AWSSupport_20130415.DescribeCases',
|
|
101
|
+
},
|
|
102
|
+
body: JSON.stringify({
|
|
103
|
+
caseIdList: [caseId],
|
|
104
|
+
includeResolvedCases: true,
|
|
105
|
+
includeCommunications: true,
|
|
106
|
+
}),
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
const cases = (result as { cases?: SupportCase[] }).cases
|
|
110
|
+
return cases?.[0] || null
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* List all support cases
|
|
115
|
+
*/
|
|
116
|
+
async listCases(options?: {
|
|
117
|
+
includeResolved?: boolean
|
|
118
|
+
maxResults?: number
|
|
119
|
+
nextToken?: string
|
|
120
|
+
}): Promise<{ cases: SupportCase[], nextToken?: string }> {
|
|
121
|
+
const result = await this.client.request({
|
|
122
|
+
service: 'support',
|
|
123
|
+
region: this.region,
|
|
124
|
+
method: 'POST',
|
|
125
|
+
path: '/',
|
|
126
|
+
headers: {
|
|
127
|
+
'Content-Type': 'application/x-amz-json-1.1',
|
|
128
|
+
'X-Amz-Target': 'AWSSupport_20130415.DescribeCases',
|
|
129
|
+
},
|
|
130
|
+
body: JSON.stringify({
|
|
131
|
+
includeResolvedCases: options?.includeResolved ?? false,
|
|
132
|
+
maxResults: options?.maxResults,
|
|
133
|
+
nextToken: options?.nextToken,
|
|
134
|
+
includeCommunications: true,
|
|
135
|
+
}),
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
return result as { cases: SupportCase[], nextToken?: string }
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Add a communication to an existing case
|
|
143
|
+
*/
|
|
144
|
+
async addCommunication(caseId: string, message: string, ccEmailAddresses?: string[]): Promise<boolean> {
|
|
145
|
+
const result = await this.client.request({
|
|
146
|
+
service: 'support',
|
|
147
|
+
region: this.region,
|
|
148
|
+
method: 'POST',
|
|
149
|
+
path: '/',
|
|
150
|
+
headers: {
|
|
151
|
+
'Content-Type': 'application/x-amz-json-1.1',
|
|
152
|
+
'X-Amz-Target': 'AWSSupport_20130415.AddCommunicationToCase',
|
|
153
|
+
},
|
|
154
|
+
body: JSON.stringify({
|
|
155
|
+
caseId,
|
|
156
|
+
communicationBody: message,
|
|
157
|
+
ccEmailAddresses,
|
|
158
|
+
}),
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
return (result as { result?: boolean }).result ?? true
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Resolve a support case
|
|
166
|
+
*/
|
|
167
|
+
async resolveCase(caseId: string): Promise<{ initialCaseStatus?: string, finalCaseStatus?: string }> {
|
|
168
|
+
const result = await this.client.request({
|
|
169
|
+
service: 'support',
|
|
170
|
+
region: this.region,
|
|
171
|
+
method: 'POST',
|
|
172
|
+
path: '/',
|
|
173
|
+
headers: {
|
|
174
|
+
'Content-Type': 'application/x-amz-json-1.1',
|
|
175
|
+
'X-Amz-Target': 'AWSSupport_20130415.ResolveCase',
|
|
176
|
+
},
|
|
177
|
+
body: JSON.stringify({
|
|
178
|
+
caseId,
|
|
179
|
+
}),
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
return result as { initialCaseStatus?: string, finalCaseStatus?: string }
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Get available services and categories for support cases
|
|
187
|
+
*/
|
|
188
|
+
async describeServices(serviceCodeList?: string[]): Promise<SupportService[]> {
|
|
189
|
+
const result = await this.client.request({
|
|
190
|
+
service: 'support',
|
|
191
|
+
region: this.region,
|
|
192
|
+
method: 'POST',
|
|
193
|
+
path: '/',
|
|
194
|
+
headers: {
|
|
195
|
+
'Content-Type': 'application/x-amz-json-1.1',
|
|
196
|
+
'X-Amz-Target': 'AWSSupport_20130415.DescribeServices',
|
|
197
|
+
},
|
|
198
|
+
body: JSON.stringify({
|
|
199
|
+
serviceCodeList,
|
|
200
|
+
language: 'en',
|
|
201
|
+
}),
|
|
202
|
+
})
|
|
203
|
+
|
|
204
|
+
return (result as { services?: SupportService[] }).services || []
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Get available severity levels
|
|
209
|
+
*/
|
|
210
|
+
async describeSeverityLevels(): Promise<Array<{ code: string, name: string }>> {
|
|
211
|
+
const result = await this.client.request({
|
|
212
|
+
service: 'support',
|
|
213
|
+
region: this.region,
|
|
214
|
+
method: 'POST',
|
|
215
|
+
path: '/',
|
|
216
|
+
headers: {
|
|
217
|
+
'Content-Type': 'application/x-amz-json-1.1',
|
|
218
|
+
'X-Amz-Target': 'AWSSupport_20130415.DescribeSeverityLevels',
|
|
219
|
+
},
|
|
220
|
+
body: JSON.stringify({
|
|
221
|
+
language: 'en',
|
|
222
|
+
}),
|
|
223
|
+
})
|
|
224
|
+
|
|
225
|
+
return (result as { severityLevels?: Array<{ code: string, name: string }> }).severityLevels || []
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
export interface SmsSandboxExitParams {
|
|
230
|
+
companyName: string
|
|
231
|
+
useCase: string
|
|
232
|
+
expectedMonthlyVolume: number
|
|
233
|
+
websiteUrl?: string
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
export interface SmsSpendLimitIncreaseParams {
|
|
237
|
+
companyName: string
|
|
238
|
+
currentLimit: number
|
|
239
|
+
requestedLimit: number
|
|
240
|
+
useCase: string
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
export interface SesSandboxExitParams {
|
|
244
|
+
companyName: string
|
|
245
|
+
websiteUrl: string
|
|
246
|
+
useCase: string
|
|
247
|
+
expectedDailyVolume: number
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
export interface ConnectPhoneNumberIncreaseParams {
|
|
251
|
+
companyName: string
|
|
252
|
+
instanceId: string
|
|
253
|
+
currentLimit: number
|
|
254
|
+
requestedLimit: number
|
|
255
|
+
useCase: string
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Pre-built support case templates for common requests
|
|
260
|
+
*/
|
|
261
|
+
export const SupportTemplates = {
|
|
262
|
+
/**
|
|
263
|
+
* Request to exit SMS sandbox
|
|
264
|
+
*/
|
|
265
|
+
smsSandboxExit: (params: SmsSandboxExitParams): CreateCaseParams => ({
|
|
266
|
+
subject: 'Request to exit SMS sandbox for production use',
|
|
267
|
+
serviceCode: 'service-limit-increase',
|
|
268
|
+
categoryCode: 'service-limit-increase-sms-pinpoint',
|
|
269
|
+
severityCode: 'normal',
|
|
270
|
+
communicationBody: `Hello,
|
|
271
|
+
|
|
272
|
+
I would like to request that our AWS account be moved out of the SMS sandbox to enable production SMS messaging.
|
|
273
|
+
|
|
274
|
+
**Company/Project**: ${params.companyName}
|
|
275
|
+
**Website**: ${params.websiteUrl || 'N/A'}
|
|
276
|
+
|
|
277
|
+
**Use Case**:
|
|
278
|
+
${params.useCase}
|
|
279
|
+
|
|
280
|
+
**Expected Monthly SMS Volume**: ${params.expectedMonthlyVolume.toLocaleString()} messages
|
|
281
|
+
|
|
282
|
+
**Message Types**:
|
|
283
|
+
- Transactional (verification codes, order confirmations, etc.)
|
|
284
|
+
- Account notifications
|
|
285
|
+
|
|
286
|
+
**Opt-out Handling**:
|
|
287
|
+
We have implemented standard opt-out handling with STOP, UNSUBSCRIBE, CANCEL, END, and QUIT keywords.
|
|
288
|
+
|
|
289
|
+
**Compliance**:
|
|
290
|
+
- We will only send SMS to users who have explicitly opted in
|
|
291
|
+
- We will include opt-out instructions in promotional messages
|
|
292
|
+
- We will honor all opt-out requests immediately
|
|
293
|
+
|
|
294
|
+
Thank you for reviewing this request.`,
|
|
295
|
+
}),
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Request to increase SMS spending limit
|
|
299
|
+
*/
|
|
300
|
+
smsSpendLimitIncrease: (params: SmsSpendLimitIncreaseParams): CreateCaseParams => ({
|
|
301
|
+
subject: `Request to increase SMS spending limit from $${params.currentLimit} to $${params.requestedLimit}`,
|
|
302
|
+
serviceCode: 'service-limit-increase',
|
|
303
|
+
categoryCode: 'service-limit-increase-sms-pinpoint',
|
|
304
|
+
severityCode: 'normal',
|
|
305
|
+
communicationBody: `Hello,
|
|
306
|
+
|
|
307
|
+
I would like to request an increase to our monthly SMS spending limit.
|
|
308
|
+
|
|
309
|
+
**Company/Project**: ${params.companyName}
|
|
310
|
+
|
|
311
|
+
**Current Limit**: $${params.currentLimit}/month
|
|
312
|
+
**Requested Limit**: $${params.requestedLimit}/month
|
|
313
|
+
|
|
314
|
+
**Justification**:
|
|
315
|
+
${params.useCase}
|
|
316
|
+
|
|
317
|
+
**Message Types**:
|
|
318
|
+
- Transactional notifications
|
|
319
|
+
- Verification codes
|
|
320
|
+
- Account alerts
|
|
321
|
+
|
|
322
|
+
We have proper opt-out handling in place and comply with all SMS messaging regulations.
|
|
323
|
+
|
|
324
|
+
Thank you for reviewing this request.`,
|
|
325
|
+
}),
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Request SES production access (exit sandbox)
|
|
329
|
+
*/
|
|
330
|
+
sesSandboxExit: (params: SesSandboxExitParams): CreateCaseParams => ({
|
|
331
|
+
subject: 'Request to move out of Amazon SES sandbox',
|
|
332
|
+
serviceCode: 'service-limit-increase',
|
|
333
|
+
categoryCode: 'service-limit-increase-ses-702',
|
|
334
|
+
severityCode: 'normal',
|
|
335
|
+
communicationBody: `Hello,
|
|
336
|
+
|
|
337
|
+
I would like to request that our AWS account be moved out of the Amazon SES sandbox to enable production email sending.
|
|
338
|
+
|
|
339
|
+
**Company/Project**: ${params.companyName}
|
|
340
|
+
**Website**: ${params.websiteUrl}
|
|
341
|
+
|
|
342
|
+
**Use Case**:
|
|
343
|
+
${params.useCase}
|
|
344
|
+
|
|
345
|
+
**Expected Daily Email Volume**: ${params.expectedDailyVolume.toLocaleString()} emails
|
|
346
|
+
|
|
347
|
+
**Email Types**:
|
|
348
|
+
- Transactional emails (password resets, order confirmations, etc.)
|
|
349
|
+
- Account notifications
|
|
350
|
+
- System alerts
|
|
351
|
+
|
|
352
|
+
**Compliance**:
|
|
353
|
+
- We will only send emails to users who have explicitly opted in
|
|
354
|
+
- We have implemented proper bounce and complaint handling
|
|
355
|
+
- We will include unsubscribe links in all marketing emails
|
|
356
|
+
- We maintain a clean mailing list and honor all unsubscribe requests
|
|
357
|
+
|
|
358
|
+
**Technical Setup**:
|
|
359
|
+
- Domain verification: Complete (DKIM, SPF, DMARC configured)
|
|
360
|
+
- Bounce/complaint handling: SNS notifications configured
|
|
361
|
+
- Email authentication: Fully implemented
|
|
362
|
+
|
|
363
|
+
Thank you for reviewing this request.`,
|
|
364
|
+
}),
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* Request Connect phone number limit increase
|
|
368
|
+
*/
|
|
369
|
+
connectPhoneNumberIncrease: (params: ConnectPhoneNumberIncreaseParams): CreateCaseParams => ({
|
|
370
|
+
subject: `Request to increase Amazon Connect phone number limit from ${params.currentLimit} to ${params.requestedLimit}`,
|
|
371
|
+
serviceCode: 'service-limit-increase',
|
|
372
|
+
categoryCode: 'service-limit-increase-connect',
|
|
373
|
+
severityCode: 'normal',
|
|
374
|
+
communicationBody: `Hello,
|
|
375
|
+
|
|
376
|
+
I would like to request an increase to our Amazon Connect phone number limit.
|
|
377
|
+
|
|
378
|
+
**Company/Project**: ${params.companyName}
|
|
379
|
+
**Connect Instance ID**: ${params.instanceId}
|
|
380
|
+
|
|
381
|
+
**Current Limit**: ${params.currentLimit} phone numbers
|
|
382
|
+
**Requested Limit**: ${params.requestedLimit} phone numbers
|
|
383
|
+
|
|
384
|
+
**Use Case**:
|
|
385
|
+
${params.useCase}
|
|
386
|
+
|
|
387
|
+
Thank you for reviewing this request.`,
|
|
388
|
+
}),
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
export default SupportClient
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* Test script to run the IMAP server locally
|
|
4
|
+
* This reads emails from S3 and serves them via IMAP
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* bun run src/aws/test-imap.ts
|
|
8
|
+
*
|
|
9
|
+
* Then configure Mail.app:
|
|
10
|
+
* IMAP Server: localhost
|
|
11
|
+
* Port: 1143 (or 143 if running as root)
|
|
12
|
+
* Username: chris
|
|
13
|
+
* Password: test123
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { startImapServer } from './imap-server'
|
|
17
|
+
|
|
18
|
+
async function main() {
|
|
19
|
+
console.log('Starting IMAP-to-S3 bridge server...')
|
|
20
|
+
console.log('')
|
|
21
|
+
|
|
22
|
+
const port = Number.parseInt(process.env.IMAP_PORT || '1143', 10)
|
|
23
|
+
const sslPort = Number.parseInt(process.env.IMAPS_PORT || '1993', 10)
|
|
24
|
+
|
|
25
|
+
const server = await startImapServer({
|
|
26
|
+
port, // Use 1143 for non-root, or 143 if running as root
|
|
27
|
+
sslPort, // Use 1993 for non-root, or 993 if running as root
|
|
28
|
+
host: '0.0.0.0',
|
|
29
|
+
region: 'us-east-1',
|
|
30
|
+
bucket: 'stacks-production-email',
|
|
31
|
+
prefix: 'incoming/',
|
|
32
|
+
domain: 'stacksjs.com',
|
|
33
|
+
users: {
|
|
34
|
+
chris: {
|
|
35
|
+
password: 'test123',
|
|
36
|
+
email: 'chris@stacksjs.com',
|
|
37
|
+
},
|
|
38
|
+
blake: {
|
|
39
|
+
password: 'test123',
|
|
40
|
+
email: 'blake@stacksjs.com',
|
|
41
|
+
},
|
|
42
|
+
glenn: {
|
|
43
|
+
password: 'test123',
|
|
44
|
+
email: 'glenn@stacksjs.com',
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
// To enable TLS, provide certificate paths:
|
|
48
|
+
// tls: {
|
|
49
|
+
// key: '/path/to/key.pem',
|
|
50
|
+
// cert: '/path/to/cert.pem',
|
|
51
|
+
// },
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
console.log('')
|
|
55
|
+
console.log('='.repeat(60))
|
|
56
|
+
console.log('IMAP-to-S3 Bridge Server Running')
|
|
57
|
+
console.log('='.repeat(60))
|
|
58
|
+
console.log('')
|
|
59
|
+
console.log('Mail.app Settings:')
|
|
60
|
+
console.log(' Account Type: IMAP')
|
|
61
|
+
console.log(' Incoming Server: localhost')
|
|
62
|
+
console.log(` Port: ${port}`)
|
|
63
|
+
console.log(' Username: chris (or blake, glenn)')
|
|
64
|
+
console.log(' Password: test123')
|
|
65
|
+
console.log(` SSL: Off (or ${sslPort} with SSL)`)
|
|
66
|
+
console.log('')
|
|
67
|
+
console.log('For production, use ports 143/993 (requires root or port forwarding)')
|
|
68
|
+
console.log('Set IMAP_PORT and IMAPS_PORT environment variables to change ports')
|
|
69
|
+
console.log('')
|
|
70
|
+
console.log('Press Ctrl+C to stop')
|
|
71
|
+
|
|
72
|
+
// Handle graceful shutdown
|
|
73
|
+
process.on('SIGINT', async () => {
|
|
74
|
+
console.log('\nShutting down...')
|
|
75
|
+
await server.stop()
|
|
76
|
+
process.exit(0)
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
process.on('SIGTERM', async () => {
|
|
80
|
+
console.log('\nShutting down...')
|
|
81
|
+
await server.stop()
|
|
82
|
+
process.exit(0)
|
|
83
|
+
})
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
main().catch(console.error)
|