@stacksjs/cloud 0.59.10 → 0.61.0

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 (48) hide show
  1. package/dist/index.js +843 -754
  2. package/package.json +30 -30
  3. package/src/cloud/ai.ts +5 -12
  4. package/src/cloud/aws-sdk-layer/nodejs/package-lock.json +8 -6
  5. package/src/cloud/aws-sdk-layer/nodejs/package.json +2 -2
  6. package/src/cloud/cdn.ts +41 -20
  7. package/src/cloud/cli.ts +1 -3
  8. package/src/cloud/compute.ts +39 -17
  9. package/src/cloud/dashboard.ts +0 -1
  10. package/src/cloud/database.ts +34 -0
  11. package/src/cloud/deployment.ts +8 -7
  12. package/src/cloud/dns.ts +0 -1
  13. package/src/cloud/docs.ts +3 -4
  14. package/src/cloud/email.ts +57 -40
  15. package/src/cloud/index.ts +9 -9
  16. package/src/cloud/jump-box.ts +0 -1
  17. package/src/cloud/lambda/ask/{index.js → index.cjs} +16 -15
  18. package/src/cloud/lambda/summarize/index.cjs +36 -0
  19. package/src/cloud/permissions.ts +3 -3
  20. package/src/cloud/queue.ts +73 -53
  21. package/src/cloud/redirects.ts +11 -4
  22. package/src/cloud/router-layer/nodejs/package.json +2 -2
  23. package/src/cloud/security.ts +19 -11
  24. package/src/edge/origin-request.ts +2 -1
  25. package/src/helpers.ts +147 -132
  26. package/dist/cloud/ai.d.ts +0 -10
  27. package/dist/cloud/cdn.d.ts +0 -44
  28. package/dist/cloud/cli.d.ts +0 -9
  29. package/dist/cloud/compute.d.ts +0 -17
  30. package/dist/cloud/deployment.d.ts +0 -14
  31. package/dist/cloud/dns.d.ts +0 -7
  32. package/dist/cloud/docs.d.ts +0 -9
  33. package/dist/cloud/email.d.ts +0 -10
  34. package/dist/cloud/file-system.d.ts +0 -12
  35. package/dist/cloud/index.d.ts +0 -41
  36. package/dist/cloud/jump-box.d.ts +0 -12
  37. package/dist/cloud/network.d.ts +0 -9
  38. package/dist/cloud/permissions.d.ts +0 -7
  39. package/dist/cloud/queue.d.ts +0 -24
  40. package/dist/cloud/redirects.d.ts +0 -9
  41. package/dist/cloud/security.d.ts +0 -14
  42. package/dist/cloud/storage.d.ts +0 -18
  43. package/dist/edge/origin-request.d.ts +0 -1
  44. package/dist/helpers.d.ts +0 -67
  45. package/dist/index.d.ts +0 -2
  46. package/dist/types.d.ts +0 -26
  47. package/src/cloud/lambda/summarize/index.js +0 -35
  48. /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('+') ? options.adminPhone.toString() : `+${options.adminPhone.toString()}`,
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('+') ? options.registrantPhone.toString() : `+${options.registrantPhone.toString()}`,
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('+') ? options.techPhone.toString() : `+${options.techPhone.toString()}`,
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 && data.Reservations[0] && data.Reservations[0].Instances && data.Reservations[0].Instances[0])
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 = data.Users?.filter((user) => {
199
- const userNameLower = user.UserName?.toLowerCase()
200
- return userNameLower !== 'stacks' && userNameLower !== teamName.toLowerCase() && userNameLower?.includes(teamName.toLowerCase())
201
- }) || []
202
-
203
- if (!users || users.length === 0)
204
- return ok(`No Stacks IAM users found for team ${teamName}`)
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(policies.AttachedPolicies?.map(policy =>
216
- iam.detachUserPolicy({ UserName: userName, PolicyArn: policy.PolicyArn || '' }),
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(accessKeys.AccessKeyMetadata?.map(key =>
224
- iam.deleteAccessKey({ UserName: userName, AccessKeyId: key.AccessKeyId || '' }),
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(`Error deleting user: ${error}`)
233
- return err(handleError('Error deleting Stacks IAM users', error))
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(objects.Contents.map(object =>
263
- s3.deleteObject({ Bucket: bucketName, Key: object.Key || '' }).catch(error => handleError(error)),
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(versions.Versions.map(version =>
275
- s3.deleteObject({ Bucket: bucketName, Key: version.Key || '', VersionId: version.VersionId }),
276
- )).catch(error => handleError(error))
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(versions.DeleteMarkers.map(marker =>
285
- s3.deleteObject({ Bucket: bucketName, Key: marker.Key || '', VersionId: marker.VersionId }),
286
- )).catch(error => handleError(error))
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(uploads.Uploads.map(upload =>
297
- s3.abortMultipartUpload({ Bucket: bucketName, Key: upload.Key || '', UploadId: upload.UploadId }),
298
- )).catch(error => handleError(error))
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
- return err(handleError('Error deleting stacks buckets', error))
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
- catch (error) {
319
- return err(handleError('Error deleting stacks buckets', error as Error))
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
- return err(handleError('Error deleting stacks functions', error))
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
- catch (error) {
363
- return err(handleError('Error deleting log groups', error as Error))
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
- return err(handleError('Error deleting parameter store', error))
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
- await runCommand(
393
- `bunx rimraf ${p.cloudPath('cdk.out/')} ${p.cloudPath('cdk.context.json')}`,
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(response.Buckets?.some(bucket => bucket.Name?.includes(config.app.name?.toLocaleLowerCase() || 'stacks')) || false)
409
- }
410
- catch (error) {
411
- return err(handleError('Error checking if the app has been deployed', error as Error))
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('The jump–box you are trying to add already exists. Please remove it & wait until it finished terminating.')
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
- let sgId: string | undefined
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 && instance.Instances[0]
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 && data.Reservations[0] && data.Reservations[0].Instances && data.Reservations[0].Instances[0]) {
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 && securityGroups[0])
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 && data.Reservations[0] && data.Reservations[0].Instances && data.Reservations[0].Instances[0]) {
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 && securityGroups[0])
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({ StackStatusFilter: ['CREATE_COMPLETE', 'UPDATE_COMPLETE'] })
555
- const isStacksCloudPresent = data.StackSummaries?.some(stack => stack.StackName === stackName)
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({ StackStatusFilter: ['CREATE_FAILED', 'UPDATE_FAILED', 'ROLLBACK_COMPLETE', 'UPDATE_ROLLBACK_COMPLETE'] })
563
- const isStacksCloudPresent = data.StackSummaries?.some(stack => stack.StackName === cloudName)
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({
@@ -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
- }
@@ -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
- }
@@ -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
- }
@@ -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
- }