@stacksjs/cloud 0.59.11 → 0.61.1
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/index.js +843 -754
- package/package.json +30 -30
- package/src/cloud/ai.ts +5 -12
- package/src/cloud/aws-sdk-layer/nodejs/package-lock.json +7 -6
- package/src/cloud/aws-sdk-layer/nodejs/package.json +2 -2
- package/src/cloud/cdn.ts +41 -20
- package/src/cloud/cli.ts +1 -3
- package/src/cloud/compute.ts +39 -17
- package/src/cloud/dashboard.ts +0 -1
- package/src/cloud/database.ts +34 -0
- package/src/cloud/deployment.ts +8 -7
- package/src/cloud/dns.ts +0 -1
- package/src/cloud/docs.ts +3 -4
- package/src/cloud/email.ts +57 -40
- package/src/cloud/index.ts +9 -9
- package/src/cloud/jump-box.ts +0 -1
- package/src/cloud/lambda/ask/{index.js → index.cjs} +16 -15
- package/src/cloud/lambda/summarize/index.cjs +36 -0
- package/src/cloud/permissions.ts +3 -3
- package/src/cloud/queue.ts +73 -53
- package/src/cloud/redirects.ts +11 -4
- package/src/cloud/router-layer/nodejs/package.json +2 -2
- package/src/cloud/security.ts +19 -11
- package/src/edge/origin-request.ts +2 -1
- package/src/helpers.ts +147 -132
- package/dist/cloud/ai.d.ts +0 -10
- package/dist/cloud/cdn.d.ts +0 -44
- package/dist/cloud/cli.d.ts +0 -9
- package/dist/cloud/compute.d.ts +0 -17
- package/dist/cloud/deployment.d.ts +0 -14
- package/dist/cloud/dns.d.ts +0 -7
- package/dist/cloud/docs.d.ts +0 -9
- package/dist/cloud/email.d.ts +0 -10
- package/dist/cloud/file-system.d.ts +0 -12
- package/dist/cloud/index.d.ts +0 -41
- package/dist/cloud/jump-box.d.ts +0 -12
- package/dist/cloud/network.d.ts +0 -9
- package/dist/cloud/permissions.d.ts +0 -7
- package/dist/cloud/queue.d.ts +0 -24
- package/dist/cloud/redirects.d.ts +0 -9
- package/dist/cloud/security.d.ts +0 -14
- package/dist/cloud/storage.d.ts +0 -18
- package/dist/edge/origin-request.d.ts +0 -1
- package/dist/helpers.d.ts +0 -67
- package/dist/index.d.ts +0 -2
- package/dist/types.d.ts +0 -26
- package/src/cloud/lambda/summarize/index.js +0 -35
- /package/src/cloud/lambda/cli-setup/{index.js → index.cjs} +0 -0
package/src/helpers.ts
CHANGED
|
@@ -4,14 +4,14 @@ import { CloudWatchLogsClient, DeleteLogGroupCommand, DescribeLogGroupsCommand }
|
|
|
4
4
|
import { EC2, _InstanceType as InstanceType } from '@aws-sdk/client-ec2'
|
|
5
5
|
import { DescribeFileSystemsCommand, EFSClient } from '@aws-sdk/client-efs'
|
|
6
6
|
import { IAM } from '@aws-sdk/client-iam'
|
|
7
|
-
import { SSM } from '@aws-sdk/client-ssm'
|
|
8
7
|
import { Lambda } from '@aws-sdk/client-lambda'
|
|
9
8
|
import type { CountryCode } from '@aws-sdk/client-route-53-domains'
|
|
10
9
|
import { ContactType, Route53Domains } from '@aws-sdk/client-route-53-domains'
|
|
11
10
|
import { ListBucketsCommand, S3 } from '@aws-sdk/client-s3'
|
|
11
|
+
import { SSM } from '@aws-sdk/client-ssm'
|
|
12
|
+
import { runCommand } from '@stacksjs/cli'
|
|
12
13
|
import { config } from '@stacksjs/config'
|
|
13
14
|
import { err, handleError, ok } from '@stacksjs/error-handling'
|
|
14
|
-
import { runCommand } from '@stacksjs/cli'
|
|
15
15
|
import { log } from '@stacksjs/logging'
|
|
16
16
|
import { path as p } from '@stacksjs/path'
|
|
17
17
|
import { slug } from '@stacksjs/strings'
|
|
@@ -27,11 +27,9 @@ export async function getSecurityGroupId(securityGroupName: string) {
|
|
|
27
27
|
Filters: [{ Name: 'group-name', Values: [securityGroupName] }],
|
|
28
28
|
})
|
|
29
29
|
|
|
30
|
-
if (!SecurityGroups)
|
|
31
|
-
return err(`Security group ${securityGroupName} not found`)
|
|
30
|
+
if (!SecurityGroups) return err(`Security group ${securityGroupName} not found`)
|
|
32
31
|
|
|
33
|
-
if (SecurityGroups[0])
|
|
34
|
-
return ok(SecurityGroups[0].GroupId)
|
|
32
|
+
if (SecurityGroups[0]) return ok(SecurityGroups[0].GroupId)
|
|
35
33
|
|
|
36
34
|
return err(`Security group ${securityGroupName} not found`)
|
|
37
35
|
}
|
|
@@ -100,7 +98,9 @@ export function purchaseDomain(domain: string, options: PurchaseOptions) {
|
|
|
100
98
|
State: options.adminState,
|
|
101
99
|
CountryCode: options.adminCountry,
|
|
102
100
|
ZipCode: options.adminZip.toString(),
|
|
103
|
-
PhoneNumber: options.adminPhone.toString().includes('+')
|
|
101
|
+
PhoneNumber: options.adminPhone.toString().includes('+')
|
|
102
|
+
? options.adminPhone.toString()
|
|
103
|
+
: `+${options.adminPhone.toString()}`,
|
|
104
104
|
Email: options.adminEmail,
|
|
105
105
|
},
|
|
106
106
|
RegistrantContact: {
|
|
@@ -114,7 +114,9 @@ export function purchaseDomain(domain: string, options: PurchaseOptions) {
|
|
|
114
114
|
State: options.registrantState,
|
|
115
115
|
CountryCode: options.registrantCountry,
|
|
116
116
|
ZipCode: options.registrantZip.toString(),
|
|
117
|
-
PhoneNumber: options.registrantPhone.toString().includes('+')
|
|
117
|
+
PhoneNumber: options.registrantPhone.toString().includes('+')
|
|
118
|
+
? options.registrantPhone.toString()
|
|
119
|
+
: `+${options.registrantPhone.toString()}`,
|
|
118
120
|
Email: options.registrantEmail,
|
|
119
121
|
},
|
|
120
122
|
TechContact: {
|
|
@@ -128,7 +130,9 @@ export function purchaseDomain(domain: string, options: PurchaseOptions) {
|
|
|
128
130
|
State: options.techState,
|
|
129
131
|
CountryCode: options.techCountry,
|
|
130
132
|
ZipCode: options.techZip.toString(),
|
|
131
|
-
PhoneNumber: options.techPhone.toString().includes('+')
|
|
133
|
+
PhoneNumber: options.techPhone.toString().includes('+')
|
|
134
|
+
? options.techPhone.toString()
|
|
135
|
+
: `+${options.techPhone.toString()}`,
|
|
132
136
|
Email: options.techEmail,
|
|
133
137
|
},
|
|
134
138
|
PrivacyProtectAdminContact: options.privacyAdmin || options.privacy || true,
|
|
@@ -138,15 +142,13 @@ export function purchaseDomain(domain: string, options: PurchaseOptions) {
|
|
|
138
142
|
|
|
139
143
|
try {
|
|
140
144
|
return ok(route53domains.registerDomain(params))
|
|
141
|
-
}
|
|
142
|
-
catch (error: any) {
|
|
145
|
+
} catch (error: any) {
|
|
143
146
|
return err(error)
|
|
144
147
|
}
|
|
145
148
|
}
|
|
146
149
|
|
|
147
150
|
export async function getJumpBoxInstanceId(name?: string) {
|
|
148
|
-
if (!name)
|
|
149
|
-
name = `${cloudName}/JumpBox`
|
|
151
|
+
if (!name) name = `${cloudName}/JumpBox`
|
|
150
152
|
|
|
151
153
|
const ec2 = new EC2({ region: 'us-east-1' })
|
|
152
154
|
const data = await ec2.describeInstances({
|
|
@@ -158,18 +160,15 @@ export async function getJumpBoxInstanceId(name?: string) {
|
|
|
158
160
|
],
|
|
159
161
|
})
|
|
160
162
|
|
|
161
|
-
if (data.Reservations
|
|
162
|
-
return data.Reservations[0].Instances[0].InstanceId
|
|
163
|
+
if (data.Reservations?.[0].Instances?.[0]) return data.Reservations[0].Instances[0].InstanceId
|
|
163
164
|
|
|
164
165
|
return undefined
|
|
165
166
|
}
|
|
166
167
|
|
|
167
168
|
export async function deleteEc2Instance(id: string, stackName?: string) {
|
|
168
|
-
if (!stackName)
|
|
169
|
-
stackName = cloudName
|
|
169
|
+
if (!stackName) stackName = cloudName
|
|
170
170
|
|
|
171
|
-
if (!id)
|
|
172
|
-
return err(`Instance ${id} not found`)
|
|
171
|
+
if (!id) return err(`Instance ${id} not found`)
|
|
173
172
|
|
|
174
173
|
const ec2 = new EC2({ region: 'us-east-1' })
|
|
175
174
|
await ec2.terminateInstances({ InstanceIds: [id] })
|
|
@@ -178,13 +177,11 @@ export async function deleteEc2Instance(id: string, stackName?: string) {
|
|
|
178
177
|
}
|
|
179
178
|
|
|
180
179
|
export async function deleteJumpBox(stackName?: string) {
|
|
181
|
-
if (!stackName)
|
|
182
|
-
stackName = cloudName
|
|
180
|
+
if (!stackName) stackName = cloudName
|
|
183
181
|
|
|
184
182
|
const jumpBoxId = await getJumpBoxInstanceId()
|
|
185
183
|
|
|
186
|
-
if (!jumpBoxId)
|
|
187
|
-
return err('Jump-box not found')
|
|
184
|
+
if (!jumpBoxId) return err('Jump-box not found')
|
|
188
185
|
|
|
189
186
|
log.info(`Deleting jump-box ${jumpBoxId}...`)
|
|
190
187
|
|
|
@@ -195,13 +192,17 @@ export async function deleteIamUsers() {
|
|
|
195
192
|
const iam = new IAM({ region: 'us-east-1' })
|
|
196
193
|
const data = await iam.listUsers({})
|
|
197
194
|
const teamName = slug(config.team.name)
|
|
198
|
-
const users =
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
195
|
+
const users =
|
|
196
|
+
data.Users?.filter((user) => {
|
|
197
|
+
const userNameLower = user.UserName?.toLowerCase()
|
|
198
|
+
return (
|
|
199
|
+
userNameLower !== 'stacks' &&
|
|
200
|
+
userNameLower !== teamName.toLowerCase() &&
|
|
201
|
+
userNameLower?.includes(teamName.toLowerCase())
|
|
202
|
+
)
|
|
203
|
+
}) || []
|
|
204
|
+
|
|
205
|
+
if (!users || users.length === 0) return ok(`No Stacks IAM users found for team ${teamName}`)
|
|
205
206
|
|
|
206
207
|
const promises = users.map(async (user) => {
|
|
207
208
|
const userName = user.UserName || ''
|
|
@@ -212,25 +213,35 @@ export async function deleteIamUsers() {
|
|
|
212
213
|
const policies = await iam.listAttachedUserPolicies({ UserName: userName })
|
|
213
214
|
|
|
214
215
|
// Detach each policy
|
|
215
|
-
await Promise.all(
|
|
216
|
-
|
|
217
|
-
|
|
216
|
+
await Promise.all(
|
|
217
|
+
policies.AttachedPolicies?.map((policy) =>
|
|
218
|
+
iam.detachUserPolicy({
|
|
219
|
+
UserName: userName,
|
|
220
|
+
PolicyArn: policy.PolicyArn || '',
|
|
221
|
+
}),
|
|
222
|
+
) || [],
|
|
223
|
+
)
|
|
218
224
|
|
|
219
225
|
// Get the list of access keys for the user
|
|
220
226
|
const accessKeys = await iam.listAccessKeys({ UserName: userName })
|
|
221
227
|
|
|
222
228
|
// Delete each access key
|
|
223
|
-
await Promise.all(
|
|
224
|
-
|
|
225
|
-
|
|
229
|
+
await Promise.all(
|
|
230
|
+
accessKeys.AccessKeyMetadata?.map((key) =>
|
|
231
|
+
iam.deleteAccessKey({
|
|
232
|
+
UserName: userName,
|
|
233
|
+
AccessKeyId: key.AccessKeyId || '',
|
|
234
|
+
}),
|
|
235
|
+
) || [],
|
|
236
|
+
)
|
|
226
237
|
|
|
227
238
|
// Now delete the user
|
|
228
239
|
return iam.deleteUser({ UserName: userName })
|
|
229
240
|
})
|
|
230
241
|
|
|
231
242
|
await Promise.all(promises).catch((error: Error) => {
|
|
232
|
-
console.error(
|
|
233
|
-
return err(handleError('Error deleting Stacks IAM users'
|
|
243
|
+
console.error(error)
|
|
244
|
+
return err(handleError('Error deleting Stacks IAM users'))
|
|
234
245
|
})
|
|
235
246
|
|
|
236
247
|
return ok(`Stacks IAM users deleted for team ${teamName}`)
|
|
@@ -240,10 +251,9 @@ export async function deleteStacksBuckets() {
|
|
|
240
251
|
try {
|
|
241
252
|
const s3 = new S3({ region: 'us-east-1' })
|
|
242
253
|
const data = await s3.listBuckets({})
|
|
243
|
-
const stacksBuckets = data.Buckets?.filter(bucket => bucket.Name?.includes('stacks'))
|
|
254
|
+
const stacksBuckets = data.Buckets?.filter((bucket) => bucket.Name?.includes('stacks'))
|
|
244
255
|
|
|
245
|
-
if (!stacksBuckets)
|
|
246
|
-
return err('No stacks buckets found')
|
|
256
|
+
if (!stacksBuckets) return err('No stacks buckets found')
|
|
247
257
|
|
|
248
258
|
const promises = stacksBuckets.map(async (bucket) => {
|
|
249
259
|
const bucketName = bucket.Name || ''
|
|
@@ -259,9 +269,11 @@ export async function deleteStacksBuckets() {
|
|
|
259
269
|
if (objects.Contents) {
|
|
260
270
|
log.info('Deleting bucket objects...')
|
|
261
271
|
|
|
262
|
-
await Promise.all(
|
|
263
|
-
|
|
264
|
-
|
|
272
|
+
await Promise.all(
|
|
273
|
+
objects.Contents.map((object) =>
|
|
274
|
+
s3.deleteObject({ Bucket: bucketName, Key: object.Key || '' }).catch((error) => handleError(error)),
|
|
275
|
+
),
|
|
276
|
+
)
|
|
265
277
|
|
|
266
278
|
log.info(`Finished deleting objects from bucket ${bucketName}`)
|
|
267
279
|
}
|
|
@@ -271,9 +283,15 @@ export async function deleteStacksBuckets() {
|
|
|
271
283
|
const versions = await s3.listObjectVersions({ Bucket: bucketName })
|
|
272
284
|
|
|
273
285
|
if (versions.Versions) {
|
|
274
|
-
await Promise.all(
|
|
275
|
-
|
|
276
|
-
|
|
286
|
+
await Promise.all(
|
|
287
|
+
versions.Versions.map((version) =>
|
|
288
|
+
s3.deleteObject({
|
|
289
|
+
Bucket: bucketName,
|
|
290
|
+
Key: version.Key || '',
|
|
291
|
+
VersionId: version.VersionId,
|
|
292
|
+
}),
|
|
293
|
+
),
|
|
294
|
+
).catch((error) => handleError(error))
|
|
277
295
|
log.info(`Finished deleting versions from bucket ${bucketName}`)
|
|
278
296
|
}
|
|
279
297
|
|
|
@@ -281,9 +299,15 @@ export async function deleteStacksBuckets() {
|
|
|
281
299
|
log.info(`Deleting bucket ${bucketName} delete markers...`)
|
|
282
300
|
|
|
283
301
|
if (versions.DeleteMarkers) {
|
|
284
|
-
await Promise.all(
|
|
285
|
-
|
|
286
|
-
|
|
302
|
+
await Promise.all(
|
|
303
|
+
versions.DeleteMarkers.map((marker) =>
|
|
304
|
+
s3.deleteObject({
|
|
305
|
+
Bucket: bucketName,
|
|
306
|
+
Key: marker.Key || '',
|
|
307
|
+
VersionId: marker.VersionId,
|
|
308
|
+
}),
|
|
309
|
+
),
|
|
310
|
+
).catch((error) => handleError(error))
|
|
287
311
|
|
|
288
312
|
log.info(`Finished deleting delete markers from bucket ${bucketName}`)
|
|
289
313
|
}
|
|
@@ -293,42 +317,47 @@ export async function deleteStacksBuckets() {
|
|
|
293
317
|
if (uploads.Uploads) {
|
|
294
318
|
log.info('Aborting bucket multipart uploads...')
|
|
295
319
|
|
|
296
|
-
await Promise.all(
|
|
297
|
-
|
|
298
|
-
|
|
320
|
+
await Promise.all(
|
|
321
|
+
uploads.Uploads.map((upload) =>
|
|
322
|
+
s3.abortMultipartUpload({
|
|
323
|
+
Bucket: bucketName,
|
|
324
|
+
Key: upload.Key || '',
|
|
325
|
+
UploadId: upload.UploadId,
|
|
326
|
+
}),
|
|
327
|
+
),
|
|
328
|
+
).catch((error) => handleError(error))
|
|
299
329
|
|
|
300
330
|
log.info(`Finished aborting multipart uploads from bucket ${bucketName}`)
|
|
301
331
|
}
|
|
302
332
|
|
|
303
|
-
await s3.deleteBucket({ Bucket: bucketName }).catch(error => handleError(error))
|
|
333
|
+
await s3.deleteBucket({ Bucket: bucketName }).catch((error) => handleError(error))
|
|
304
334
|
|
|
305
335
|
log.info(`Bucket ${bucketName} deleted`)
|
|
306
|
-
}
|
|
307
|
-
catch (error) {
|
|
336
|
+
} catch (error) {
|
|
308
337
|
log.info(`Error listing bucket ${bucketName} versions`, error)
|
|
309
338
|
}
|
|
310
339
|
})
|
|
311
340
|
|
|
312
341
|
await Promise.all(promises).catch((error: Error) => {
|
|
313
|
-
|
|
342
|
+
console.error(error)
|
|
343
|
+
return err(handleError('Error deleting stacks buckets'))
|
|
314
344
|
})
|
|
315
345
|
|
|
316
346
|
return ok('Stacks buckets deleted')
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
return err(handleError('Error deleting stacks buckets'
|
|
347
|
+
} catch (error) {
|
|
348
|
+
console.error(error)
|
|
349
|
+
return err(handleError('Error deleting stacks buckets'))
|
|
320
350
|
}
|
|
321
351
|
}
|
|
322
352
|
|
|
323
353
|
export async function deleteStacksFunctions() {
|
|
324
354
|
const lambda = new Lambda({ region: 'us-east-1' })
|
|
325
355
|
const data = await lambda.listFunctions({})
|
|
326
|
-
const stacksFunctions = data.Functions?.filter(func => func.FunctionName?.includes('stacks')) || []
|
|
356
|
+
const stacksFunctions = data.Functions?.filter((func) => func.FunctionName?.includes('stacks')) || []
|
|
327
357
|
|
|
328
|
-
if (!stacksFunctions || stacksFunctions.length === 0)
|
|
329
|
-
return ok('No stacks functions found')
|
|
358
|
+
if (!stacksFunctions || stacksFunctions.length === 0) return ok('No stacks functions found')
|
|
330
359
|
|
|
331
|
-
const promises = stacksFunctions.map(func => lambda.deleteFunction({ FunctionName: func.FunctionName || '' }))
|
|
360
|
+
const promises = stacksFunctions.map((func) => lambda.deleteFunction({ FunctionName: func.FunctionName || '' }))
|
|
332
361
|
|
|
333
362
|
await Promise.all(promises).catch((error: Error) => {
|
|
334
363
|
if (error.message.includes('it is a replicated function')) {
|
|
@@ -337,7 +366,8 @@ export async function deleteStacksFunctions() {
|
|
|
337
366
|
return ok('CloudFront is still deleting the some functions. Try again later.')
|
|
338
367
|
}
|
|
339
368
|
|
|
340
|
-
|
|
369
|
+
console.error(error)
|
|
370
|
+
return err(handleError('Error deleting stacks functions'))
|
|
341
371
|
})
|
|
342
372
|
|
|
343
373
|
return ok('Stacks functions deleted')
|
|
@@ -348,19 +378,17 @@ export async function deleteLogGroups() {
|
|
|
348
378
|
const client = new CloudWatchLogsClient({ region: 'us-east-1' })
|
|
349
379
|
const logGroups: DescribeLogGroupsCommandOutput = await client.send(new DescribeLogGroupsCommand({}))
|
|
350
380
|
|
|
351
|
-
if (!logGroups?.logGroups)
|
|
352
|
-
return err('No log groups found')
|
|
381
|
+
if (!logGroups?.logGroups) return err('No log groups found')
|
|
353
382
|
|
|
354
383
|
for (const group of logGroups.logGroups) {
|
|
355
384
|
if (group.logGroupName?.includes('stacks'))
|
|
356
|
-
|
|
357
385
|
await client.send(new DeleteLogGroupCommand({ logGroupName: group.logGroupName }))
|
|
358
386
|
}
|
|
359
387
|
|
|
360
388
|
return ok('Log groups deleted')
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
return err(handleError('Error deleting log groups'
|
|
389
|
+
} catch (error) {
|
|
390
|
+
console.error(error)
|
|
391
|
+
return err(handleError('Error deleting log groups'))
|
|
364
392
|
}
|
|
365
393
|
}
|
|
366
394
|
|
|
@@ -368,18 +396,17 @@ export async function deleteParameterStore() {
|
|
|
368
396
|
const ssm = new SSM({ region: 'us-east-1' })
|
|
369
397
|
const data = await ssm.describeParameters({})
|
|
370
398
|
|
|
371
|
-
if (!data.Parameters)
|
|
372
|
-
return ok('No parameters found')
|
|
399
|
+
if (!data.Parameters) return ok('No parameters found')
|
|
373
400
|
|
|
374
|
-
const stacksParameters = data.Parameters.filter(param => param.Name?.includes('stacks')) || []
|
|
401
|
+
const stacksParameters = data.Parameters.filter((param) => param.Name?.includes('stacks')) || []
|
|
375
402
|
|
|
376
|
-
if (!stacksParameters || stacksParameters.length === 0)
|
|
377
|
-
return ok('No stacks parameters found')
|
|
403
|
+
if (!stacksParameters || stacksParameters.length === 0) return ok('No stacks parameters found')
|
|
378
404
|
|
|
379
|
-
const promises = stacksParameters.map(param => ssm.deleteParameter({ Name: param.Name || '' }))
|
|
405
|
+
const promises = stacksParameters.map((param) => ssm.deleteParameter({ Name: param.Name || '' }))
|
|
380
406
|
|
|
381
407
|
await Promise.all(promises).catch((error: Error) => {
|
|
382
|
-
|
|
408
|
+
console.error(error)
|
|
409
|
+
return err(handleError('Error deleting parameter store'))
|
|
383
410
|
})
|
|
384
411
|
|
|
385
412
|
return ok('Parameter store deleted')
|
|
@@ -388,14 +415,10 @@ export async function deleteParameterStore() {
|
|
|
388
415
|
export async function deleteCdkRemnants() {
|
|
389
416
|
try {
|
|
390
417
|
// TODO: use $ once we can use CDK past Bun v1.0.8
|
|
391
|
-
return ok(
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
)
|
|
396
|
-
}
|
|
397
|
-
catch (error) {
|
|
398
|
-
return err(handleError('Error deleting CDK remnants', error as Error))
|
|
418
|
+
return ok(await runCommand(`bunx rimraf ${p.cloudPath('cdk.out/')} ${p.cloudPath('cdk.context.json')}`))
|
|
419
|
+
} catch (error) {
|
|
420
|
+
console.error(error)
|
|
421
|
+
return err(handleError('Error deleting CDK remnants'))
|
|
399
422
|
}
|
|
400
423
|
}
|
|
401
424
|
|
|
@@ -405,62 +428,57 @@ export async function hasBeenDeployed() {
|
|
|
405
428
|
try {
|
|
406
429
|
const response = await s3.send(new ListBucketsCommand({}))
|
|
407
430
|
|
|
408
|
-
return ok(
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
431
|
+
return ok(
|
|
432
|
+
response.Buckets?.some((bucket) => bucket.Name?.includes(config.app.name?.toLocaleLowerCase() || 'stacks')) ||
|
|
433
|
+
false,
|
|
434
|
+
)
|
|
435
|
+
} catch (error) {
|
|
436
|
+
console.error(error)
|
|
437
|
+
return err(handleError('Error checking if the app has been deployed'))
|
|
412
438
|
}
|
|
413
439
|
}
|
|
414
440
|
|
|
415
441
|
export async function getJumpBoxInstanceProfileName() {
|
|
416
442
|
const iam = new IAM({ region: 'us-east-1' })
|
|
417
443
|
const data = await iam.listInstanceProfiles({})
|
|
418
|
-
const instanceProfile = data.InstanceProfiles?.find(profile => profile.InstanceProfileName?.includes('JumpBox'))
|
|
444
|
+
const instanceProfile = data.InstanceProfiles?.find((profile) => profile.InstanceProfileName?.includes('JumpBox'))
|
|
419
445
|
|
|
420
|
-
if (!instanceProfile)
|
|
421
|
-
return err('Jump-box IAM instance profile not found')
|
|
446
|
+
if (!instanceProfile) return err('Jump-box IAM instance profile not found')
|
|
422
447
|
|
|
423
448
|
return ok(instanceProfile?.InstanceProfileName)
|
|
424
449
|
}
|
|
425
450
|
|
|
426
451
|
export async function addJumpBox(stackName?: string) {
|
|
427
|
-
if (!stackName)
|
|
428
|
-
stackName = cloudName
|
|
452
|
+
if (!stackName) stackName = cloudName
|
|
429
453
|
|
|
430
454
|
if (await getJumpBoxInstanceId())
|
|
431
|
-
return err(
|
|
455
|
+
return err(
|
|
456
|
+
'The jump–box you are trying to add already exists. Please remove it & wait until it finished terminating.',
|
|
457
|
+
)
|
|
432
458
|
|
|
433
459
|
const ec2 = new EC2({ region: 'us-east-1' })
|
|
434
460
|
|
|
435
461
|
const r = await getJumpBoxSecurityGroupName()
|
|
436
462
|
|
|
437
|
-
if (r.isErr())
|
|
438
|
-
return err(r.error)
|
|
463
|
+
if (r.isErr()) return err(r.error)
|
|
439
464
|
|
|
440
|
-
if (!r.value)
|
|
441
|
-
return err('Security group not found when adding jump-box')
|
|
465
|
+
if (!r.value) return err('Security group not found when adding jump-box')
|
|
442
466
|
|
|
443
467
|
const result = await getSecurityGroupId(r.value)
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
if (result.isErr())
|
|
447
|
-
return err(result.error)
|
|
448
|
-
else
|
|
449
|
-
sgId = result.value
|
|
468
|
+
if (result.isErr()) return err(result.error)
|
|
469
|
+
const sgId = result.value
|
|
450
470
|
|
|
451
|
-
if (!sgId)
|
|
452
|
-
return err('Security group not found when adding jump-box')
|
|
471
|
+
if (!sgId) return err('Security group not found when adding jump-box')
|
|
453
472
|
|
|
454
473
|
const client = new EFSClient({ region: 'us-east-1' })
|
|
455
474
|
const command = new DescribeFileSystemsCommand({})
|
|
456
475
|
const data = await client.send(command)
|
|
457
476
|
|
|
458
477
|
const fileSystemName = `stacks-${config.app.env}-efs`
|
|
459
|
-
const fileSystem = data.FileSystems?.find(fs => fs.Name === fileSystemName)
|
|
478
|
+
const fileSystem = data.FileSystems?.find((fs) => fs.Name === fileSystemName)
|
|
460
479
|
const fileSystemId = fileSystem?.FileSystemId
|
|
461
480
|
|
|
462
|
-
if (!fileSystem || !fileSystemId)
|
|
463
|
-
return err(`EFS file system ${fileSystemName} not found`)
|
|
481
|
+
if (!fileSystem || !fileSystemId) return err(`EFS file system ${fileSystemName} not found`)
|
|
464
482
|
|
|
465
483
|
const userDataScript = `
|
|
466
484
|
#!/bin/bash
|
|
@@ -476,12 +494,10 @@ git clone https://github.com/stacksjs/stacks.git /mnt/efs
|
|
|
476
494
|
const base64UserData = btoa(userDataScript)
|
|
477
495
|
const res = await getJumpBoxInstanceProfileName()
|
|
478
496
|
|
|
479
|
-
if (res.isErr())
|
|
480
|
-
return err(res.error)
|
|
497
|
+
if (res.isErr()) return err(res.error)
|
|
481
498
|
|
|
482
499
|
const jumpBoxInstanceProfileName: string | undefined = res.value
|
|
483
|
-
if (!jumpBoxInstanceProfileName)
|
|
484
|
-
return err('Jump-box IAM instance profile not found')
|
|
500
|
+
if (!jumpBoxInstanceProfileName) return err('Jump-box IAM instance profile not found')
|
|
485
501
|
|
|
486
502
|
const instance = await ec2.runInstances({
|
|
487
503
|
ImageId: 'ami-03a6eaae9938c858c', // Amazon Linux 2023 AMI
|
|
@@ -508,7 +524,7 @@ git clone https://github.com/stacksjs/stacks.git /mnt/efs
|
|
|
508
524
|
},
|
|
509
525
|
})
|
|
510
526
|
|
|
511
|
-
return instance.Instances
|
|
527
|
+
return instance.Instances?.[0]
|
|
512
528
|
? ok(`Jump-box created with id ${instance.Instances[0].InstanceId}`)
|
|
513
529
|
: err('Jump-box creation failed')
|
|
514
530
|
}
|
|
@@ -516,18 +532,16 @@ git clone https://github.com/stacksjs/stacks.git /mnt/efs
|
|
|
516
532
|
export async function getJumpBoxSecurityGroupName() {
|
|
517
533
|
const jumpBoxId = await getJumpBoxInstanceId()
|
|
518
534
|
|
|
519
|
-
if (!jumpBoxId)
|
|
520
|
-
return err('Jump-box not found')
|
|
535
|
+
if (!jumpBoxId) return err('Jump-box not found')
|
|
521
536
|
|
|
522
537
|
const ec2 = new EC2({ region: 'us-east-1' })
|
|
523
538
|
const data = await ec2.describeInstances({ InstanceIds: [jumpBoxId] })
|
|
524
539
|
|
|
525
|
-
if (data.Reservations
|
|
540
|
+
if (data.Reservations?.[0].Instances?.[0]) {
|
|
526
541
|
const instance = data.Reservations[0].Instances[0]
|
|
527
542
|
const securityGroups = instance.SecurityGroups
|
|
528
543
|
|
|
529
|
-
if (securityGroups
|
|
530
|
-
return ok(securityGroups[0].GroupName)
|
|
544
|
+
if (securityGroups?.[0]) return ok(securityGroups[0].GroupName)
|
|
531
545
|
}
|
|
532
546
|
|
|
533
547
|
return err('Security group not found')
|
|
@@ -537,12 +551,11 @@ export async function getSecurityGroupFromInstanceId(instanceId: string) {
|
|
|
537
551
|
const ec2 = new EC2({ region: 'us-east-1' })
|
|
538
552
|
const data = await ec2.describeInstances({ InstanceIds: [instanceId] })
|
|
539
553
|
|
|
540
|
-
if (data.Reservations
|
|
554
|
+
if (data.Reservations?.[0].Instances?.[0]) {
|
|
541
555
|
const instance = data.Reservations[0].Instances[0]
|
|
542
556
|
const securityGroups = instance.SecurityGroups
|
|
543
557
|
|
|
544
|
-
if (securityGroups
|
|
545
|
-
return securityGroups[0].GroupId // Returns the ID of the first security group
|
|
558
|
+
if (securityGroups?.[0]) return securityGroups[0].GroupId // Returns the ID of the first security group
|
|
546
559
|
}
|
|
547
560
|
|
|
548
561
|
return undefined
|
|
@@ -551,16 +564,20 @@ export async function getSecurityGroupFromInstanceId(instanceId: string) {
|
|
|
551
564
|
export async function isFirstDeployment() {
|
|
552
565
|
const stackName = cloudName
|
|
553
566
|
const cloudFormation = new CloudFormation()
|
|
554
|
-
const data = await cloudFormation.listStacks({
|
|
555
|
-
|
|
567
|
+
const data = await cloudFormation.listStacks({
|
|
568
|
+
StackStatusFilter: ['CREATE_COMPLETE', 'UPDATE_COMPLETE'],
|
|
569
|
+
})
|
|
570
|
+
const isStacksCloudPresent = data.StackSummaries?.some((stack) => stack.StackName === stackName)
|
|
556
571
|
|
|
557
572
|
return !isStacksCloudPresent
|
|
558
573
|
}
|
|
559
574
|
|
|
560
575
|
export async function isFailedState() {
|
|
561
576
|
const cloudFormation = new CloudFormation()
|
|
562
|
-
const data = await cloudFormation.listStacks({
|
|
563
|
-
|
|
577
|
+
const data = await cloudFormation.listStacks({
|
|
578
|
+
StackStatusFilter: ['CREATE_FAILED', 'UPDATE_FAILED', 'ROLLBACK_COMPLETE', 'UPDATE_ROLLBACK_COMPLETE'],
|
|
579
|
+
})
|
|
580
|
+
const isStacksCloudPresent = data.StackSummaries?.some((stack) => stack.StackName === cloudName)
|
|
564
581
|
|
|
565
582
|
return !isStacksCloudPresent
|
|
566
583
|
}
|
|
@@ -573,12 +590,10 @@ export async function getOrCreateTimestamp(): Promise<string> {
|
|
|
573
590
|
const response = await ssm.getParameter({ Name: parameterName })
|
|
574
591
|
const timestamp = response.Parameter ? response.Parameter.Value : undefined
|
|
575
592
|
|
|
576
|
-
if (!timestamp)
|
|
577
|
-
throw new Error('Timestamp parameter not found')
|
|
593
|
+
if (!timestamp) throw new Error('Timestamp parameter not found')
|
|
578
594
|
|
|
579
595
|
return timestamp
|
|
580
|
-
}
|
|
581
|
-
catch (error: any) {
|
|
596
|
+
} catch (error: any) {
|
|
582
597
|
const timestamp = new Date().getTime().toString()
|
|
583
598
|
log.debug(`Creating timestamp parameter ${parameterName} with value ${timestamp}`)
|
|
584
599
|
await ssm.putParameter({
|
package/dist/cloud/ai.d.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { aws_lambda as lambda } from 'aws-cdk-lib';
|
|
2
|
-
import type { Construct } from 'constructs';
|
|
3
|
-
import type { NestedCloudProps } from '../types';
|
|
4
|
-
export interface AiStackProps extends NestedCloudProps {
|
|
5
|
-
}
|
|
6
|
-
export declare class AiStack {
|
|
7
|
-
askAiUrl: lambda.FunctionUrl;
|
|
8
|
-
summarizeAiUrl: lambda.FunctionUrl;
|
|
9
|
-
constructor(scope: Construct, props: AiStackProps);
|
|
10
|
-
}
|
package/dist/cloud/cdn.d.ts
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import type { aws_certificatemanager as acm, aws_lambda as lambda, aws_s3 as s3, aws_wafv2 as wafv2 } from 'aws-cdk-lib';
|
|
2
|
-
import { aws_cloudfront as cloudfront, aws_route53 as route53 } from 'aws-cdk-lib';
|
|
3
|
-
import type { Construct } from 'constructs';
|
|
4
|
-
import type { ApplicationLoadBalancer } from 'aws-cdk-lib/aws-elasticloadbalancingv2';
|
|
5
|
-
import type { NestedCloudProps } from '../types';
|
|
6
|
-
export interface CdnStackProps extends NestedCloudProps {
|
|
7
|
-
certificate: acm.Certificate;
|
|
8
|
-
logBucket: s3.Bucket;
|
|
9
|
-
publicBucket: s3.Bucket;
|
|
10
|
-
firewall: wafv2.CfnWebACL;
|
|
11
|
-
originRequestFunction: lambda.Function;
|
|
12
|
-
zone: route53.IHostedZone;
|
|
13
|
-
webServer?: lambda.Function;
|
|
14
|
-
webServerUrl?: lambda.FunctionUrl;
|
|
15
|
-
cliSetupUrl: lambda.FunctionUrl;
|
|
16
|
-
askAiUrl: lambda.FunctionUrl;
|
|
17
|
-
summarizeAiUrl: lambda.FunctionUrl;
|
|
18
|
-
lb?: ApplicationLoadBalancer;
|
|
19
|
-
}
|
|
20
|
-
export declare class CdnStack {
|
|
21
|
-
distribution: cloudfront.Distribution;
|
|
22
|
-
originAccessIdentity: cloudfront.OriginAccessIdentity;
|
|
23
|
-
cdnCachePolicy: cloudfront.CachePolicy;
|
|
24
|
-
apiCachePolicy: cloudfront.CachePolicy | undefined;
|
|
25
|
-
vanityUrl: string;
|
|
26
|
-
realtimeLogConfig: cloudfront.RealtimeLogConfig;
|
|
27
|
-
props: CdnStackProps;
|
|
28
|
-
constructor(scope: Construct, props: CdnStackProps);
|
|
29
|
-
getCookieBehavior(behavior: string | undefined): cloudfront.CacheCookieBehavior | undefined;
|
|
30
|
-
allowedMethods(): cloudfront.AllowedMethods;
|
|
31
|
-
cachedMethods(): cloudfront.CachedMethods;
|
|
32
|
-
allowedMethodsFromString(methods?: 'ALL' | 'GET_HEAD' | 'GET_HEAD_OPTIONS'): cloudfront.AllowedMethods;
|
|
33
|
-
cachedMethodsFromString(methods?: 'GET_HEAD' | 'GET_HEAD_OPTIONS'): cloudfront.CachedMethods;
|
|
34
|
-
shouldDeployApi(): any;
|
|
35
|
-
apiBehaviorOptions(scope: Construct, props: CdnStackProps): Record<string, cloudfront.BehaviorOptions>;
|
|
36
|
-
docsBehaviorOptions(props: CdnStackProps): Record<string, cloudfront.BehaviorOptions>;
|
|
37
|
-
aiBehaviorOptions(scope: Construct, props: CdnStackProps): Record<string, cloudfront.BehaviorOptions>;
|
|
38
|
-
cliSetupBehaviorOptions(scope: Construct, props: CdnStackProps): Record<string, cloudfront.BehaviorOptions>;
|
|
39
|
-
shouldDeployAiEndpoints(): any;
|
|
40
|
-
shouldDeployCliSetup(): any;
|
|
41
|
-
shouldDeployDocs(): any;
|
|
42
|
-
additionalBehaviors(scope: Construct, props: CdnStackProps): Record<string, cloudfront.BehaviorOptions>;
|
|
43
|
-
setApiCachePolicy(scope: Construct): cloudfront.CachePolicy;
|
|
44
|
-
}
|
package/dist/cloud/cli.d.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { aws_lambda as lambda } from 'aws-cdk-lib';
|
|
2
|
-
import type { Construct } from 'constructs';
|
|
3
|
-
import type { NestedCloudProps } from '../types';
|
|
4
|
-
export interface CliStackProps extends NestedCloudProps {
|
|
5
|
-
}
|
|
6
|
-
export declare class CliStack {
|
|
7
|
-
cliSetupUrl: lambda.FunctionUrl;
|
|
8
|
-
constructor(scope: Construct, props: CliStackProps);
|
|
9
|
-
}
|
package/dist/cloud/compute.d.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import type { aws_certificatemanager as acm, aws_efs as efs } from 'aws-cdk-lib';
|
|
2
|
-
import { aws_ec2 as ec2, aws_ecs as ecs, aws_route53 as route53 } from 'aws-cdk-lib';
|
|
3
|
-
import type { Construct } from 'constructs';
|
|
4
|
-
import * as elbv2 from 'aws-cdk-lib/aws-elasticloadbalancingv2';
|
|
5
|
-
import type { NestedCloudProps } from '../types';
|
|
6
|
-
export interface ComputeStackProps extends NestedCloudProps {
|
|
7
|
-
vpc: ec2.Vpc;
|
|
8
|
-
fileSystem: efs.FileSystem;
|
|
9
|
-
zone: route53.IHostedZone;
|
|
10
|
-
certificate: acm.Certificate;
|
|
11
|
-
}
|
|
12
|
-
export declare class ComputeStack {
|
|
13
|
-
lb: elbv2.ApplicationLoadBalancer;
|
|
14
|
-
cluster: ecs.Cluster;
|
|
15
|
-
taskDefinition: ecs.FargateTaskDefinition;
|
|
16
|
-
constructor(scope: Construct, props: ComputeStackProps);
|
|
17
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import type { aws_cloudfront as cloudfront, aws_s3 as s3 } from 'aws-cdk-lib';
|
|
2
|
-
import type { Construct } from 'constructs';
|
|
3
|
-
import type { NestedCloudProps } from '../types';
|
|
4
|
-
export interface DeploymentStackProps extends NestedCloudProps {
|
|
5
|
-
publicBucket: s3.Bucket;
|
|
6
|
-
privateBucket: s3.Bucket;
|
|
7
|
-
cdn: cloudfront.Distribution;
|
|
8
|
-
}
|
|
9
|
-
export declare class DeploymentStack {
|
|
10
|
-
privateSource: string;
|
|
11
|
-
docsSource: string;
|
|
12
|
-
websiteSource: string;
|
|
13
|
-
constructor(scope: Construct, props: DeploymentStackProps);
|
|
14
|
-
}
|