@stacksjs/cloud 0.59.11 → 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 +7 -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
@@ -1,23 +1,23 @@
1
+ import { config } from '@stacksjs/config'
1
2
  import { Stack } from 'aws-cdk-lib'
2
3
  import type { Construct } from 'constructs'
3
- import { config } from '@stacksjs/config'
4
4
  import type { CloudOptions } from '../types'
5
5
  import { AiStack } from './ai'
6
6
  import { CdnStack } from './cdn'
7
7
  import { CliStack } from './cli'
8
+ import { ComputeStack } from './compute'
9
+ import { DeploymentStack } from './deployment'
8
10
  import { DnsStack } from './dns'
9
11
  import { DocsStack } from './docs'
10
- import { StorageStack } from './storage'
11
- import { SecurityStack } from './security'
12
- import { DeploymentStack } from './deployment'
13
- import { JumpBoxStack } from './jump-box'
12
+ import { EmailStack } from './email'
14
13
  import { FileSystemStack } from './file-system'
14
+ import { JumpBoxStack } from './jump-box'
15
15
  import { NetworkStack } from './network'
16
- import { RedirectsStack } from './redirects'
17
- import { EmailStack } from './email'
18
16
  import { PermissionsStack } from './permissions'
19
- import { ComputeStack } from './compute'
20
17
  import { QueueStack } from './queue'
18
+ import { RedirectsStack } from './redirects'
19
+ import { SecurityStack } from './security'
20
+ import { StorageStack } from './storage'
21
21
 
22
22
  // import { DashboardStack } from './dashboard'
23
23
 
@@ -92,7 +92,7 @@ export class Cloud extends Stack {
92
92
  // we use an async init() method here because we need to wait for the
93
93
 
94
94
  async init() {
95
- if (config.cloud.api?.deploy) {
95
+ if (config.api?.deploy) {
96
96
  const props = this.props
97
97
  this.api = new ComputeStack(this, {
98
98
  ...props,
@@ -1,4 +1,3 @@
1
- /* eslint-disable no-new */
2
1
  import type { aws_efs as efs } from 'aws-cdk-lib'
3
2
  import { CfnOutput as Output, aws_ec2 as ec2, aws_iam as iam } from 'aws-cdk-lib'
4
3
  import type { Construct } from 'constructs'
@@ -5,24 +5,25 @@ async function handler(event) {
5
5
 
6
6
  // Extract the 'question' property from the request body
7
7
  const question = requestBody.question
8
- // eslint-disable-next-line no-console
9
8
  console.log(`Question received: ${question}`)
10
9
 
11
10
  const bedrockRuntime = new AWS.BedrockRuntime({ apiVersion: '2023-09-30' })
12
- const res = await bedrockRuntime.invokeModel({
13
- modelId: 'amazon.titan-text-express-v1',
14
- contentType: 'application/json',
15
- accept: '*/*',
16
- body: JSON.stringify({
17
- inputText: question,
18
- textGenerationConfig: {
19
- maxTokenCount: 300,
20
- stopSequences: [],
21
- temperature: 0.1,
22
- topP: 0.9,
23
- },
24
- }),
25
- }).promise()
11
+ const res = await bedrockRuntime
12
+ .invokeModel({
13
+ modelId: 'amazon.titan-text-express-v1',
14
+ contentType: 'application/json',
15
+ accept: '*/*',
16
+ body: JSON.stringify({
17
+ inputText: question,
18
+ textGenerationConfig: {
19
+ maxTokenCount: 300,
20
+ stopSequences: [],
21
+ temperature: 0.1,
22
+ topP: 0.9,
23
+ },
24
+ }),
25
+ })
26
+ .promise()
26
27
 
27
28
  return {
28
29
  statusCode: 200,
@@ -0,0 +1,36 @@
1
+ const AWS = require('aws-sdk')
2
+
3
+ async function handler(event) {
4
+ const requestBody = JSON.parse(event.body)
5
+
6
+ // Extract the 'question' property from the request body
7
+ const text = requestBody.text
8
+ console.log(`Text received: ${text}`)
9
+
10
+ const bedrockRuntime = new AWS.BedrockRuntime({ apiVersion: '2023-09-30' })
11
+ const res = await bedrockRuntime
12
+ .invokeModel({
13
+ modelId: 'amazon.titan-text-express-v1',
14
+ contentType: 'application/json',
15
+ accept: '*/*',
16
+ body: JSON.stringify({
17
+ inputText: `Summarize the following text: ${text}`,
18
+ textGenerationConfig: {
19
+ maxTokenCount: 512,
20
+ stopSequences: [],
21
+ temperature: 0,
22
+ topP: 0.9,
23
+ },
24
+ }),
25
+ })
26
+ .promise()
27
+
28
+ return {
29
+ statusCode: 200,
30
+ body: res.body.toString(),
31
+ }
32
+ }
33
+
34
+ module.exports = {
35
+ handler,
36
+ }
@@ -1,8 +1,8 @@
1
- import { SecretValue, aws_iam as iam } from 'aws-cdk-lib'
2
- import type { Construct } from 'constructs'
3
1
  import { config } from '@stacksjs/config'
4
- import { string } from '@stacksjs/strings'
5
2
  import { env } from '@stacksjs/env'
3
+ import { string } from '@stacksjs/strings'
4
+ import { SecretValue, aws_iam as iam } from 'aws-cdk-lib'
5
+ import type { Construct } from 'constructs'
6
6
  import type { NestedCloudProps } from '../types'
7
7
 
8
8
  export interface PermissionsStackProps extends NestedCloudProps {
@@ -1,11 +1,11 @@
1
- import type { Cluster, TaskDefinition } from 'aws-cdk-lib/aws-ecs'
2
- import { aws_ec2 as ec2 } from 'aws-cdk-lib'
3
- import type { Construct } from 'constructs'
4
- import { pascalCase, slug } from '@stacksjs/strings'
5
- import { fs } from '@stacksjs/storage'
6
1
  import { path } from '@stacksjs/path'
2
+ import { fs } from '@stacksjs/storage'
3
+ import { pascalCase, slug } from '@stacksjs/strings'
4
+ import { aws_ec2 as ec2 } from 'aws-cdk-lib'
5
+ import type { Cluster, TaskDefinition } from 'aws-cdk-lib/aws-ecs'
7
6
  import { Rule, Schedule } from 'aws-cdk-lib/aws-events'
8
7
  import { EcsTask } from 'aws-cdk-lib/aws-events-targets'
8
+ import type { Construct } from 'constructs'
9
9
  import type { NestedCloudProps } from '../types'
10
10
 
11
11
  export interface QueueStackProps extends NestedCloudProps {
@@ -25,15 +25,16 @@ export class QueueStack {
25
25
  async init() {
26
26
  const jobsDir = path.jobsPath()
27
27
  const actionsDir = path.appPath('Actions')
28
+ const ormActionDir = path.projectStoragePath('framework/orm/Actions')
28
29
 
29
30
  const jobFiles = await fs.readdir(jobsDir)
30
31
  const actionFiles = await fs.readdir(actionsDir)
32
+ const ormActionFiles = await fs.readdir(ormActionDir)
31
33
  const jobs = []
32
34
 
33
35
  // then, need to loop through all app/Jobs/*.ts and create a rule for each, potentially overwriting the Schedule.ts jobs
34
36
  for (const file of jobFiles) {
35
- if (!file.endsWith('.ts'))
36
- continue
37
+ if (!file.endsWith('.ts')) continue
37
38
 
38
39
  const jobPath = path.jobsPath(file)
39
40
 
@@ -43,12 +44,24 @@ export class QueueStack {
43
44
  jobs.push(job)
44
45
  }
45
46
 
47
+ for (const ormFile of ormActionFiles) {
48
+ if (!ormFile.endsWith('.ts')) continue
49
+
50
+ const ormActionPath = path.projectStoragePath(`framework/orm/Actions/${ormFile}`)
51
+
52
+ // Await the loading of the job module
53
+ const ormAction = await this.loadModule(ormActionPath)
54
+ this.createQueueRule(ormAction, ormFile)
55
+ jobs.push(ormAction)
56
+ }
57
+
46
58
  for (const file of actionFiles) {
47
- if (!file.endsWith('.ts'))
48
- continue
59
+ if (!file.endsWith('.ts')) continue
49
60
 
50
61
  const actionPath = path.appPath(`Actions/${file}`)
51
62
 
63
+ console.log(actionPath)
64
+
52
65
  // Await the loading of the job module
53
66
  const action = await this.loadModule(actionPath)
54
67
  this.createQueueRule(action, file)
@@ -57,7 +70,13 @@ export class QueueStack {
57
70
  }
58
71
 
59
72
  // Helper function to convert a rate string to a cron object for AWS Schedule
60
- cronScheduleFromRate(rate: string): { minute?: string, hour?: string, month?: string, weekDay?: string, year?: string } {
73
+ cronScheduleFromRate(rate: string): {
74
+ minute?: string
75
+ hour?: string
76
+ month?: string
77
+ weekDay?: string
78
+ year?: string
79
+ } {
61
80
  // Assuming the rate is in standard cron format, split it to map to the AWS Schedule.cron() parameters
62
81
  const parts = rate.split(' ')
63
82
  return {
@@ -81,8 +100,7 @@ export class QueueStack {
81
100
  const rate = module.default?.rate
82
101
 
83
102
  // if no rate or job is disabled, no need to schedule, skip
84
- if (!rate || module.default?.enabled === false)
85
- return
103
+ if (!rate || module.default?.enabled === false) return
86
104
 
87
105
  // Convert the rate to a Schedule object
88
106
  const schedule = Schedule.cron(this.cronScheduleFromRate(rate))
@@ -96,47 +114,49 @@ export class QueueStack {
96
114
  schedule,
97
115
  })
98
116
 
99
- rule.addTarget(new EcsTask({
100
- cluster: this.props.cluster,
101
- taskDefinition: this.props.taskDefinition,
102
- containerOverrides: [
103
- {
104
- containerName: `${this.props.appName}-${this.props.appEnv}-api`,
105
- environment: [
106
- {
107
- name: 'QUEUE_WORKER',
108
- value: 'true',
109
- },
110
- {
111
- name: 'JOB',
112
- value: file,
113
- },
114
- {
115
- name: 'JOB_BACKOFF_FACTOR',
116
- value: module.default?.backoffFactor,
117
- },
118
- {
119
- name: 'JOB_RETRIES',
120
- value: module.default?.tries,
121
- },
122
- {
123
- name: 'JOB_INITIAL_DELAY',
124
- value: module.default?.initialDelay,
125
- },
126
- {
127
- name: 'JOB_JITTER',
128
- value: module.default?.jitter,
129
- },
130
- ],
117
+ rule.addTarget(
118
+ new EcsTask({
119
+ cluster: this.props.cluster,
120
+ taskDefinition: this.props.taskDefinition,
121
+ containerOverrides: [
122
+ {
123
+ containerName: `${this.props.appName}-${this.props.appEnv}-api`,
124
+ environment: [
125
+ {
126
+ name: 'QUEUE_WORKER',
127
+ value: 'true',
128
+ },
129
+ {
130
+ name: 'JOB',
131
+ value: file,
132
+ },
133
+ {
134
+ name: 'JOB_BACKOFF_FACTOR',
135
+ value: module.default?.backoffFactor,
136
+ },
137
+ {
138
+ name: 'JOB_RETRIES',
139
+ value: module.default?.tries,
140
+ },
141
+ {
142
+ name: 'JOB_INITIAL_DELAY',
143
+ value: module.default?.initialDelay,
144
+ },
145
+ {
146
+ name: 'JOB_JITTER',
147
+ value: module.default?.jitter,
148
+ },
149
+ ],
150
+ },
151
+ ],
152
+
153
+ retryAttempts: 1, // we utilize a custom retry mechanism in the job itself
154
+ // retryAttempts: module.default.tries || 3,
155
+
156
+ subnetSelection: {
157
+ subnetType: ec2.SubnetType.PUBLIC, // SubnetType.PRIVATE_WITH_EGRESS
131
158
  },
132
- ],
133
-
134
- retryAttempts: 1, // we utilize a custom retry mechanism in the job itself
135
- // retryAttempts: module.default.tries || 3,
136
-
137
- subnetSelection: {
138
- subnetType: ec2.SubnetType.PUBLIC, // SubnetType.PRIVATE_WITH_EGRESS
139
- },
140
- }))
159
+ }),
160
+ )
141
161
  }
142
162
  }
@@ -1,4 +1,3 @@
1
- /* eslint-disable no-new */
2
1
  import { config } from '@stacksjs/config'
3
2
  import { RemovalPolicy, aws_route53 as route53, aws_s3 as s3 } from 'aws-cdk-lib'
4
3
  import type { Construct } from 'constructs'
@@ -15,8 +14,13 @@ export class RedirectsStack {
15
14
  // for each redirect, create a bucket & redirect it to the APP_URL
16
15
  config.dns.redirects?.forEach((redirect) => {
17
16
  // TODO: use string-ts function here instead
18
- const slug = redirect.split('.').map((part, index) => index === 0 ? part : part.charAt(0).toUpperCase() + part.slice(1)).join('') // creates a CamelCase slug from the redirect
19
- const hostedZone = route53.HostedZone.fromLookup(scope, 'HostedZone', { domainName: redirect })
17
+ const slug = redirect
18
+ .split('.')
19
+ .map((part, index) => (index === 0 ? part : part.charAt(0).toUpperCase() + part.slice(1)))
20
+ .join('') // creates a CamelCase slug from the redirect
21
+ const hostedZone = route53.HostedZone.fromLookup(scope, 'HostedZone', {
22
+ domainName: redirect,
23
+ })
20
24
 
21
25
  const redirectBucket = new s3.Bucket(scope, `RedirectBucket${slug}`, {
22
26
  bucketName: `${redirect}-redirect`,
@@ -37,7 +41,10 @@ export class RedirectsStack {
37
41
 
38
42
  // TODO: fix this – redirects do not work yet
39
43
  config.dns.redirects?.forEach((redirect) => {
40
- const slug = redirect.split('.').map((part, index) => index === 0 ? part : part.charAt(0).toUpperCase() + part.slice(1)).join('') // creates a CamelCase slug from the redirect
44
+ const slug = redirect
45
+ .split('.')
46
+ .map((part, index) => (index === 0 ? part : part.charAt(0).toUpperCase() + part.slice(1)))
47
+ .join('') // creates a CamelCase slug from the redirect
41
48
  const hostedZone = route53.HostedZone.fromLookup(scope, `RedirectHostedZone${slug}`, { domainName: redirect })
42
49
  this.redirectZones.push(hostedZone)
43
50
  })
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stacks-router-layer",
3
- "version": "0.59.11",
3
+ "version": "0.61.0",
4
4
  "description": "",
5
5
  "author": "",
6
6
  "license": "MIT",
@@ -10,6 +10,6 @@
10
10
  "test": "echo \"Error: no test specified\" && exit 1"
11
11
  },
12
12
  "dependencies": {
13
- "@stacksjs/router": "^0.59.10"
13
+ "@stacksjs/router": "^0.59.11"
14
14
  }
15
15
  }
@@ -1,7 +1,14 @@
1
1
  // waf and encryption
2
2
  import { config } from '@stacksjs/config'
3
3
  import type { aws_route53 as route53 } from 'aws-cdk-lib'
4
- import { Duration, RemovalPolicy, Tags, aws_certificatemanager as acm, aws_kms as kms, aws_wafv2 as wafv2 } from 'aws-cdk-lib'
4
+ import {
5
+ Duration,
6
+ RemovalPolicy,
7
+ Tags,
8
+ aws_certificatemanager as acm,
9
+ aws_kms as kms,
10
+ aws_wafv2 as wafv2,
11
+ } from 'aws-cdk-lib'
5
12
  import type { Construct } from 'constructs'
6
13
  import type { NestedCloudProps } from '../types'
7
14
 
@@ -17,8 +24,7 @@ export class SecurityStack {
17
24
  constructor(scope: Construct, props: StorageStackProps) {
18
25
  const firewallOptions = config.cloud.firewall
19
26
 
20
- if (!firewallOptions)
21
- throw new Error('No firewall options found in config')
27
+ if (!firewallOptions) throw new Error('No firewall options found in config')
22
28
 
23
29
  const options = {
24
30
  defaultAction: { allow: {} },
@@ -28,13 +34,15 @@ export class SecurityStack {
28
34
  cloudWatchMetricsEnabled: true,
29
35
  metricName: 'firewallMetric',
30
36
  },
31
- rules: this.getFirewallRules(),
37
+ rules: this.getFirewallRules(scope),
32
38
  }
33
39
 
34
40
  this.firewall = new wafv2.CfnWebACL(scope, 'StacksWebFirewall', options)
35
41
  Tags.of(this.firewall).add('Name', 'waf-cloudfront', { priority: 300 })
36
42
  Tags.of(this.firewall).add('Purpose', 'CloudFront', { priority: 300 })
37
- Tags.of(this.firewall).add('CreatedBy', 'CloudFormation', { priority: 300 })
43
+ Tags.of(this.firewall).add('CreatedBy', 'CloudFormation', {
44
+ priority: 300,
45
+ })
38
46
 
39
47
  this.kmsKey = new kms.Key(scope, 'EncryptionKey', {
40
48
  alias: 'stacks-encryption-key',
@@ -51,7 +59,7 @@ export class SecurityStack {
51
59
  })
52
60
  }
53
61
 
54
- getFirewallRules() {
62
+ getFirewallRules(scope: Construct): wafv2.CfnWebACL.RuleProperty[] {
55
63
  const rules: wafv2.CfnWebACL.RuleProperty[] = []
56
64
  const priorities = []
57
65
 
@@ -61,9 +69,9 @@ export class SecurityStack {
61
69
  name: 'CountryRule',
62
70
  priority: priorities.length,
63
71
  statement: {
64
- geoMatchStatement: {
65
- countryCodes: config.security.firewall.countryCodes,
66
- },
72
+ // geoMatchStatement: {
73
+ // countryCodes: config.security.firewall.countryCodes,
74
+ // },
67
75
  },
68
76
  action: {
69
77
  block: {},
@@ -77,11 +85,11 @@ export class SecurityStack {
77
85
  }
78
86
 
79
87
  if (config.security.firewall?.ipAddresses?.length) {
80
- const ipSet = new wafv2.CfnIPSet(this, 'IpSet', {
88
+ const ipSet = new wafv2.CfnIPSet(scope, 'IpSet', {
81
89
  name: 'IpSet',
82
90
  description: 'IP Set',
83
91
  scope: 'CLOUDFRONT',
84
- addresses: config.security.firewall.ipAddresses,
92
+ addresses: config.security.firewall.ipAddresses as string[],
85
93
  ipAddressVersion: 'IPV4',
86
94
  })
87
95
 
@@ -7,7 +7,8 @@ const config = {
7
7
  const regexSuffixless = /\/[^/.]+$/ // e.g. "/some/page" but not "/", "/some/" or "/some.jpg"
8
8
  const regexTrailingSlash = /.+\/$/ // e.g. "/some/" or "/some/page/" but not root "/"
9
9
 
10
- export function handler(event, context, callback) {
10
+ // TODO: need to improve types here
11
+ export function handler(event: any, context: any, callback: any) {
11
12
  const { request } = event.Records[0].cf
12
13
  const { uri } = request
13
14
  const { suffix, appendToDirs } = config