@stacksjs/ts-cloud-core 0.1.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/LICENSE.md +21 -0
- package/README.md +321 -0
- package/package.json +31 -0
- package/src/advanced-features.test.ts +465 -0
- package/src/aws/cloudformation.ts +421 -0
- package/src/aws/cloudfront.ts +158 -0
- package/src/aws/credentials.test.ts +132 -0
- package/src/aws/credentials.ts +545 -0
- package/src/aws/index.ts +87 -0
- package/src/aws/s3.test.ts +188 -0
- package/src/aws/s3.ts +1088 -0
- package/src/aws/signature.test.ts +670 -0
- package/src/aws/signature.ts +1155 -0
- package/src/backup/disaster-recovery.test.ts +726 -0
- package/src/backup/disaster-recovery.ts +500 -0
- package/src/backup/index.ts +34 -0
- package/src/backup/manager.test.ts +498 -0
- package/src/backup/manager.ts +432 -0
- package/src/cicd/circleci.ts +430 -0
- package/src/cicd/github-actions.ts +424 -0
- package/src/cicd/gitlab-ci.ts +255 -0
- package/src/cicd/index.ts +8 -0
- package/src/cli/history.ts +396 -0
- package/src/cli/index.ts +10 -0
- package/src/cli/progress.ts +458 -0
- package/src/cli/repl.ts +454 -0
- package/src/cli/suggestions.ts +327 -0
- package/src/cli/table.test.ts +319 -0
- package/src/cli/table.ts +332 -0
- package/src/cloudformation/builder.test.ts +327 -0
- package/src/cloudformation/builder.ts +378 -0
- package/src/cloudformation/builders/api-gateway.ts +449 -0
- package/src/cloudformation/builders/cache.ts +334 -0
- package/src/cloudformation/builders/cdn.ts +278 -0
- package/src/cloudformation/builders/compute.ts +485 -0
- package/src/cloudformation/builders/database.ts +392 -0
- package/src/cloudformation/builders/functions.ts +343 -0
- package/src/cloudformation/builders/messaging.ts +140 -0
- package/src/cloudformation/builders/monitoring.ts +300 -0
- package/src/cloudformation/builders/network.ts +264 -0
- package/src/cloudformation/builders/queue.ts +147 -0
- package/src/cloudformation/builders/security.ts +399 -0
- package/src/cloudformation/builders/storage.ts +285 -0
- package/src/cloudformation/index.ts +30 -0
- package/src/cloudformation/types.ts +173 -0
- package/src/compliance/aws-config.ts +543 -0
- package/src/compliance/cloudtrail.ts +376 -0
- package/src/compliance/compliance.test.ts +423 -0
- package/src/compliance/guardduty.ts +446 -0
- package/src/compliance/index.ts +66 -0
- package/src/compliance/security-hub.ts +456 -0
- package/src/containers/build-optimization.ts +416 -0
- package/src/containers/containers.test.ts +508 -0
- package/src/containers/image-scanning.ts +360 -0
- package/src/containers/index.ts +9 -0
- package/src/containers/registry.ts +293 -0
- package/src/containers/service-mesh.ts +520 -0
- package/src/database/database.test.ts +762 -0
- package/src/database/index.ts +9 -0
- package/src/database/migrations.ts +444 -0
- package/src/database/performance.ts +528 -0
- package/src/database/replicas.ts +534 -0
- package/src/database/users.ts +494 -0
- package/src/dependency-graph.ts +143 -0
- package/src/deployment/ab-testing.ts +582 -0
- package/src/deployment/blue-green.ts +452 -0
- package/src/deployment/canary.ts +500 -0
- package/src/deployment/deployment.test.ts +526 -0
- package/src/deployment/index.ts +61 -0
- package/src/deployment/progressive.ts +62 -0
- package/src/dns/dns.test.ts +641 -0
- package/src/dns/dnssec.ts +315 -0
- package/src/dns/index.ts +8 -0
- package/src/dns/resolver.ts +496 -0
- package/src/dns/routing.ts +593 -0
- package/src/email/advanced/analytics.ts +445 -0
- package/src/email/advanced/index.ts +11 -0
- package/src/email/advanced/rules.ts +465 -0
- package/src/email/advanced/scheduling.ts +352 -0
- package/src/email/advanced/search.ts +412 -0
- package/src/email/advanced/shared-mailboxes.ts +404 -0
- package/src/email/advanced/templates.ts +455 -0
- package/src/email/advanced/threading.ts +281 -0
- package/src/email/analytics.ts +467 -0
- package/src/email/bounce-handling.ts +425 -0
- package/src/email/email.test.ts +431 -0
- package/src/email/handlers/__tests__/inbound.test.ts +38 -0
- package/src/email/handlers/__tests__/outbound.test.ts +37 -0
- package/src/email/handlers/converter.ts +227 -0
- package/src/email/handlers/feedback.ts +228 -0
- package/src/email/handlers/inbound.ts +169 -0
- package/src/email/handlers/outbound.ts +178 -0
- package/src/email/index.ts +15 -0
- package/src/email/reputation.ts +303 -0
- package/src/email/templates.ts +352 -0
- package/src/errors/index.test.ts +434 -0
- package/src/errors/index.ts +416 -0
- package/src/health-checks/index.ts +40 -0
- package/src/index.ts +360 -0
- package/src/intrinsic-functions.ts +118 -0
- package/src/lambda/concurrency.ts +330 -0
- package/src/lambda/destinations.ts +345 -0
- package/src/lambda/dlq.ts +425 -0
- package/src/lambda/index.ts +11 -0
- package/src/lambda/lambda.test.ts +840 -0
- package/src/lambda/layers.ts +263 -0
- package/src/lambda/versions.ts +376 -0
- package/src/lambda/vpc.ts +399 -0
- package/src/local/config.ts +114 -0
- package/src/local/index.ts +6 -0
- package/src/local/mock-aws.ts +351 -0
- package/src/modules/ai.ts +340 -0
- package/src/modules/api.ts +478 -0
- package/src/modules/auth.ts +805 -0
- package/src/modules/cache.ts +417 -0
- package/src/modules/cdn.ts +1062 -0
- package/src/modules/communication.ts +1094 -0
- package/src/modules/compute.ts +3348 -0
- package/src/modules/database.ts +554 -0
- package/src/modules/deployment.ts +1079 -0
- package/src/modules/dns.ts +337 -0
- package/src/modules/email.ts +1538 -0
- package/src/modules/filesystem.ts +515 -0
- package/src/modules/index.ts +32 -0
- package/src/modules/messaging.ts +486 -0
- package/src/modules/monitoring.ts +2086 -0
- package/src/modules/network.ts +664 -0
- package/src/modules/parameter-store.ts +325 -0
- package/src/modules/permissions.ts +1081 -0
- package/src/modules/phone.ts +494 -0
- package/src/modules/queue.ts +1260 -0
- package/src/modules/redirects.ts +464 -0
- package/src/modules/registry.ts +699 -0
- package/src/modules/search.ts +401 -0
- package/src/modules/secrets.ts +416 -0
- package/src/modules/security.ts +731 -0
- package/src/modules/sms.ts +389 -0
- package/src/modules/storage.ts +1120 -0
- package/src/modules/workflow.ts +680 -0
- package/src/multi-account/config.ts +521 -0
- package/src/multi-account/index.ts +7 -0
- package/src/multi-account/manager.ts +427 -0
- package/src/multi-region/cross-region.ts +410 -0
- package/src/multi-region/index.ts +8 -0
- package/src/multi-region/manager.ts +483 -0
- package/src/multi-region/regions.ts +435 -0
- package/src/network-security/index.ts +48 -0
- package/src/observability/index.ts +9 -0
- package/src/observability/logs.ts +522 -0
- package/src/observability/metrics.ts +460 -0
- package/src/observability/observability.test.ts +782 -0
- package/src/observability/synthetics.ts +568 -0
- package/src/observability/xray.ts +358 -0
- package/src/phone/advanced/analytics.ts +349 -0
- package/src/phone/advanced/callbacks.ts +428 -0
- package/src/phone/advanced/index.ts +8 -0
- package/src/phone/advanced/ivr-builder.ts +504 -0
- package/src/phone/advanced/recording.ts +310 -0
- package/src/phone/handlers/__tests__/incoming-call.test.ts +40 -0
- package/src/phone/handlers/incoming-call.ts +117 -0
- package/src/phone/handlers/missed-call.ts +116 -0
- package/src/phone/handlers/voicemail.ts +179 -0
- package/src/phone/index.ts +9 -0
- package/src/presets/api-backend.ts +134 -0
- package/src/presets/data-pipeline.ts +204 -0
- package/src/presets/extend.test.ts +295 -0
- package/src/presets/extend.ts +297 -0
- package/src/presets/fullstack-app.ts +144 -0
- package/src/presets/index.ts +27 -0
- package/src/presets/jamstack.ts +135 -0
- package/src/presets/microservices.ts +167 -0
- package/src/presets/ml-api.ts +208 -0
- package/src/presets/nodejs-server.ts +104 -0
- package/src/presets/nodejs-serverless.ts +114 -0
- package/src/presets/realtime-app.ts +184 -0
- package/src/presets/static-site.ts +64 -0
- package/src/presets/traditional-web-app.ts +339 -0
- package/src/presets/wordpress.ts +138 -0
- package/src/preview/github.test.ts +249 -0
- package/src/preview/github.ts +297 -0
- package/src/preview/index.ts +37 -0
- package/src/preview/manager.test.ts +440 -0
- package/src/preview/manager.ts +326 -0
- package/src/preview/notifications.test.ts +582 -0
- package/src/preview/notifications.ts +341 -0
- package/src/queue/batch-processing.ts +402 -0
- package/src/queue/dlq-monitoring.ts +402 -0
- package/src/queue/fifo.ts +342 -0
- package/src/queue/index.ts +9 -0
- package/src/queue/management.ts +428 -0
- package/src/queue/queue.test.ts +429 -0
- package/src/resource-mgmt/index.ts +39 -0
- package/src/resource-naming.ts +62 -0
- package/src/s3/index.ts +523 -0
- package/src/schema/cloud-config.schema.json +554 -0
- package/src/schema/index.ts +68 -0
- package/src/security/certificate-manager.ts +492 -0
- package/src/security/index.ts +9 -0
- package/src/security/scanning.ts +545 -0
- package/src/security/secrets-manager.ts +476 -0
- package/src/security/secrets-rotation.ts +456 -0
- package/src/security/security.test.ts +738 -0
- package/src/sms/advanced/ab-testing.ts +389 -0
- package/src/sms/advanced/analytics.ts +336 -0
- package/src/sms/advanced/campaigns.ts +523 -0
- package/src/sms/advanced/chatbot.ts +224 -0
- package/src/sms/advanced/index.ts +10 -0
- package/src/sms/advanced/link-tracking.ts +248 -0
- package/src/sms/advanced/mms.ts +308 -0
- package/src/sms/handlers/__tests__/send.test.ts +40 -0
- package/src/sms/handlers/delivery-status.ts +133 -0
- package/src/sms/handlers/receive.ts +162 -0
- package/src/sms/handlers/send.ts +174 -0
- package/src/sms/index.ts +9 -0
- package/src/stack-diff.ts +389 -0
- package/src/static-site/index.ts +85 -0
- package/src/template-builder.ts +110 -0
- package/src/template-validator.ts +574 -0
- package/src/utils/cache.ts +291 -0
- package/src/utils/diff.ts +269 -0
- package/src/utils/hash.ts +227 -0
- package/src/utils/index.ts +8 -0
- package/src/utils/parallel.ts +294 -0
- package/src/validators/credentials.test.ts +274 -0
- package/src/validators/credentials.ts +233 -0
- package/src/validators/quotas.test.ts +434 -0
- package/src/validators/quotas.ts +217 -0
- package/test/ai.test.ts +327 -0
- package/test/api.test.ts +511 -0
- package/test/auth.test.ts +632 -0
- package/test/cache.test.ts +406 -0
- package/test/cdn.test.ts +247 -0
- package/test/compute.test.ts +861 -0
- package/test/database.test.ts +523 -0
- package/test/deployment.test.ts +499 -0
- package/test/dns.test.ts +270 -0
- package/test/email.test.ts +439 -0
- package/test/filesystem.test.ts +382 -0
- package/test/integration.test.ts +350 -0
- package/test/messaging.test.ts +514 -0
- package/test/monitoring.test.ts +634 -0
- package/test/network.test.ts +425 -0
- package/test/permissions.test.ts +488 -0
- package/test/queue.test.ts +484 -0
- package/test/registry.test.ts +306 -0
- package/test/security.test.ts +462 -0
- package/test/storage.test.ts +463 -0
- package/test/template-validator.test.ts +559 -0
- package/test/workflow.test.ts +592 -0
- package/tsconfig.json +16 -0
- package/tsconfig.tsbuildinfo +1 -0
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Preset Extension and Composition Tests
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, expect, it } from 'bun:test'
|
|
6
|
+
import {
|
|
7
|
+
extendPreset,
|
|
8
|
+
composePresets,
|
|
9
|
+
withMonitoring,
|
|
10
|
+
withSecurity,
|
|
11
|
+
withDatabase,
|
|
12
|
+
withCache,
|
|
13
|
+
withCDN,
|
|
14
|
+
withQueue,
|
|
15
|
+
} from './extend'
|
|
16
|
+
import type { CloudConfig } from '@stacksjs/ts-cloud-types'
|
|
17
|
+
|
|
18
|
+
describe('extendPreset', () => {
|
|
19
|
+
it('should extend base preset with new properties', () => {
|
|
20
|
+
const base: Partial<CloudConfig> = {
|
|
21
|
+
project: {
|
|
22
|
+
name: 'Base',
|
|
23
|
+
slug: 'base',
|
|
24
|
+
region: 'us-east-1',
|
|
25
|
+
},
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const extension: Partial<CloudConfig> = {
|
|
29
|
+
infrastructure: {
|
|
30
|
+
storage: {
|
|
31
|
+
uploads: {},
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const result = extendPreset(base, extension)
|
|
37
|
+
|
|
38
|
+
expect(result.project).toEqual(base.project)
|
|
39
|
+
expect(result.infrastructure?.storage).toEqual(extension.infrastructure?.storage)
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
it('should override base properties with extension properties', () => {
|
|
43
|
+
const base: Partial<CloudConfig> = {
|
|
44
|
+
project: {
|
|
45
|
+
name: 'Base',
|
|
46
|
+
slug: 'base',
|
|
47
|
+
region: 'us-east-1',
|
|
48
|
+
},
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const extension: Partial<CloudConfig> = {
|
|
52
|
+
project: {
|
|
53
|
+
name: 'Base',
|
|
54
|
+
slug: 'base',
|
|
55
|
+
region: 'eu-west-1',
|
|
56
|
+
},
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const result = extendPreset(base, extension)
|
|
60
|
+
|
|
61
|
+
expect(result.project?.name).toBe('Base')
|
|
62
|
+
expect(result.project?.slug).toBe('base')
|
|
63
|
+
expect(result.project?.region).toBe('eu-west-1')
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
it('should merge infrastructure configurations', () => {
|
|
67
|
+
const base: Partial<CloudConfig> = {
|
|
68
|
+
infrastructure: {
|
|
69
|
+
storage: {
|
|
70
|
+
uploads: {},
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const extension: Partial<CloudConfig> = {
|
|
76
|
+
infrastructure: {
|
|
77
|
+
storage: {
|
|
78
|
+
assets: {},
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const result = extendPreset(base, extension)
|
|
84
|
+
|
|
85
|
+
expect(result.infrastructure?.storage?.uploads).toBeDefined()
|
|
86
|
+
expect(result.infrastructure?.storage?.assets).toBeDefined()
|
|
87
|
+
})
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
describe('composePresets', () => {
|
|
91
|
+
it('should compose multiple presets in order', () => {
|
|
92
|
+
const preset1: Partial<CloudConfig> = {
|
|
93
|
+
project: {
|
|
94
|
+
name: 'Project',
|
|
95
|
+
slug: 'project',
|
|
96
|
+
region: 'us-west-2',
|
|
97
|
+
},
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const preset2: Partial<CloudConfig> = {
|
|
101
|
+
project: {
|
|
102
|
+
name: 'Project',
|
|
103
|
+
slug: 'project',
|
|
104
|
+
region: 'us-east-1',
|
|
105
|
+
},
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const preset3: Partial<CloudConfig> = {
|
|
109
|
+
infrastructure: {
|
|
110
|
+
storage: {},
|
|
111
|
+
},
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const result = composePresets(preset1, preset2, preset3)
|
|
115
|
+
|
|
116
|
+
expect(result.project?.name).toBe('Project')
|
|
117
|
+
expect(result.project?.slug).toBe('project')
|
|
118
|
+
expect(result.project?.region).toBe('us-east-1')
|
|
119
|
+
expect(result.infrastructure?.storage).toBeDefined()
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
it('should apply later presets over earlier ones', () => {
|
|
123
|
+
const preset1: Partial<CloudConfig> = {
|
|
124
|
+
project: {
|
|
125
|
+
name: 'Project',
|
|
126
|
+
slug: 'project',
|
|
127
|
+
region: 'us-east-1',
|
|
128
|
+
},
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const preset2: Partial<CloudConfig> = {
|
|
132
|
+
project: {
|
|
133
|
+
name: 'Project',
|
|
134
|
+
slug: 'project',
|
|
135
|
+
region: 'eu-west-1',
|
|
136
|
+
},
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const result = composePresets(preset1, preset2)
|
|
140
|
+
|
|
141
|
+
expect(result.project?.region).toBe('eu-west-1')
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
it('should handle empty presets', () => {
|
|
145
|
+
const preset1: Partial<CloudConfig> = {
|
|
146
|
+
project: {
|
|
147
|
+
name: 'Test',
|
|
148
|
+
slug: 'test',
|
|
149
|
+
region: 'us-east-1',
|
|
150
|
+
},
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const result = composePresets(preset1, {}, {})
|
|
154
|
+
|
|
155
|
+
expect(result.project?.name).toBe('Test')
|
|
156
|
+
})
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
describe('withMonitoring', () => {
|
|
160
|
+
it('should add monitoring configuration', () => {
|
|
161
|
+
const base: Partial<CloudConfig> = {
|
|
162
|
+
project: {
|
|
163
|
+
name: 'Test',
|
|
164
|
+
slug: 'test',
|
|
165
|
+
region: 'us-east-1',
|
|
166
|
+
},
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const result = extendPreset(base, withMonitoring({
|
|
170
|
+
alarms: [],
|
|
171
|
+
}))
|
|
172
|
+
|
|
173
|
+
expect(result.infrastructure?.monitoring).toBeDefined()
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
it('should preserve existing infrastructure', () => {
|
|
177
|
+
const base: Partial<CloudConfig> = {
|
|
178
|
+
infrastructure: {
|
|
179
|
+
storage: {
|
|
180
|
+
uploads: {},
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const result = extendPreset(base, withMonitoring({
|
|
186
|
+
alarms: [],
|
|
187
|
+
}))
|
|
188
|
+
|
|
189
|
+
expect(result.infrastructure?.storage?.uploads).toBeDefined()
|
|
190
|
+
expect(result.infrastructure?.monitoring).toBeDefined()
|
|
191
|
+
})
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
describe('withSecurity', () => {
|
|
195
|
+
it('should add security configuration', () => {
|
|
196
|
+
const base: Partial<CloudConfig> = {
|
|
197
|
+
project: {
|
|
198
|
+
name: 'Test',
|
|
199
|
+
slug: 'test',
|
|
200
|
+
region: 'us-east-1',
|
|
201
|
+
},
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const result = extendPreset(base, withSecurity({
|
|
205
|
+
waf: { enabled: true },
|
|
206
|
+
}))
|
|
207
|
+
|
|
208
|
+
expect(result.infrastructure?.security).toBeDefined()
|
|
209
|
+
expect(result.infrastructure?.security?.waf?.enabled).toBe(true)
|
|
210
|
+
})
|
|
211
|
+
})
|
|
212
|
+
|
|
213
|
+
describe('withDatabase', () => {
|
|
214
|
+
it('should add database configuration', () => {
|
|
215
|
+
const base: Partial<CloudConfig> = {
|
|
216
|
+
project: {
|
|
217
|
+
name: 'Test',
|
|
218
|
+
slug: 'test',
|
|
219
|
+
region: 'us-east-1',
|
|
220
|
+
},
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const result = extendPreset(base, withDatabase({
|
|
224
|
+
postgres: {
|
|
225
|
+
instanceClass: 'db.t3.micro',
|
|
226
|
+
},
|
|
227
|
+
}))
|
|
228
|
+
|
|
229
|
+
expect(result.infrastructure?.databases?.postgres).toBeDefined()
|
|
230
|
+
expect(result.infrastructure?.databases?.postgres?.instanceClass).toBe('db.t3.micro')
|
|
231
|
+
})
|
|
232
|
+
})
|
|
233
|
+
|
|
234
|
+
describe('withCache', () => {
|
|
235
|
+
it('should add cache configuration', () => {
|
|
236
|
+
const base: Partial<CloudConfig> = {
|
|
237
|
+
project: {
|
|
238
|
+
name: 'Test',
|
|
239
|
+
slug: 'test',
|
|
240
|
+
region: 'us-east-1',
|
|
241
|
+
},
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const result = extendPreset(base, withCache({
|
|
245
|
+
redis: {
|
|
246
|
+
nodeType: 'cache.t3.small',
|
|
247
|
+
},
|
|
248
|
+
}))
|
|
249
|
+
|
|
250
|
+
expect(result.infrastructure?.cache?.redis).toBeDefined()
|
|
251
|
+
expect(result.infrastructure?.cache?.redis?.nodeType).toBe('cache.t3.small')
|
|
252
|
+
})
|
|
253
|
+
})
|
|
254
|
+
|
|
255
|
+
describe('withCDN', () => {
|
|
256
|
+
it('should add CDN configuration', () => {
|
|
257
|
+
const base: Partial<CloudConfig> = {
|
|
258
|
+
project: {
|
|
259
|
+
name: 'Test',
|
|
260
|
+
slug: 'test',
|
|
261
|
+
region: 'us-east-1',
|
|
262
|
+
},
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const result = extendPreset(base, withCDN({
|
|
266
|
+
enabled: true,
|
|
267
|
+
compress: true,
|
|
268
|
+
}))
|
|
269
|
+
|
|
270
|
+
expect(result.infrastructure?.cdn).toBeDefined()
|
|
271
|
+
expect(result.infrastructure?.cdn?.enabled).toBe(true)
|
|
272
|
+
expect(result.infrastructure?.cdn?.compress).toBe(true)
|
|
273
|
+
})
|
|
274
|
+
})
|
|
275
|
+
|
|
276
|
+
describe('withQueue', () => {
|
|
277
|
+
it('should add queue configuration', () => {
|
|
278
|
+
const base: Partial<CloudConfig> = {
|
|
279
|
+
project: {
|
|
280
|
+
name: 'Test',
|
|
281
|
+
slug: 'test',
|
|
282
|
+
region: 'us-east-1',
|
|
283
|
+
},
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
const result = extendPreset(base, withQueue({
|
|
287
|
+
jobs: {
|
|
288
|
+
fifo: false,
|
|
289
|
+
},
|
|
290
|
+
}))
|
|
291
|
+
|
|
292
|
+
expect(result.infrastructure?.queues?.jobs).toBeDefined()
|
|
293
|
+
expect(result.infrastructure?.queues?.jobs?.fifo).toBe(false)
|
|
294
|
+
})
|
|
295
|
+
})
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
import type { CloudConfig } from '@stacksjs/ts-cloud-types'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Deep merge utility for combining CloudConfig objects
|
|
5
|
+
*/
|
|
6
|
+
function deepMerge<T extends Record<string, any>>(target: T, source: Partial<T>): T {
|
|
7
|
+
const result = { ...target }
|
|
8
|
+
|
|
9
|
+
for (const key in source) {
|
|
10
|
+
const sourceValue = source[key]
|
|
11
|
+
const targetValue = result[key]
|
|
12
|
+
|
|
13
|
+
if (sourceValue === undefined) {
|
|
14
|
+
continue
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (Array.isArray(sourceValue) && Array.isArray(targetValue)) {
|
|
18
|
+
// Merge arrays by concatenating
|
|
19
|
+
result[key] = [...targetValue, ...sourceValue] as any
|
|
20
|
+
}
|
|
21
|
+
else if (
|
|
22
|
+
typeof sourceValue === 'object'
|
|
23
|
+
&& sourceValue !== null
|
|
24
|
+
&& !Array.isArray(sourceValue)
|
|
25
|
+
&& typeof targetValue === 'object'
|
|
26
|
+
&& targetValue !== null
|
|
27
|
+
&& !Array.isArray(targetValue)
|
|
28
|
+
) {
|
|
29
|
+
// Recursively merge objects
|
|
30
|
+
result[key] = deepMerge(targetValue, sourceValue)
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
// Override primitive values
|
|
34
|
+
result[key] = sourceValue as any
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return result
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Extend a base preset with custom configuration
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```typescript
|
|
46
|
+
* const myPreset = extendPreset(
|
|
47
|
+
* createNodeJsServerPreset({ name: 'My App', slug: 'my-app' }),
|
|
48
|
+
* {
|
|
49
|
+
* infrastructure: {
|
|
50
|
+
* compute: {
|
|
51
|
+
* server: {
|
|
52
|
+
* instanceType: 't3.large', // Override instance type
|
|
53
|
+
* autoScaling: {
|
|
54
|
+
* max: 20, // Increase max instances
|
|
55
|
+
* },
|
|
56
|
+
* },
|
|
57
|
+
* },
|
|
58
|
+
* database: {
|
|
59
|
+
* postgres: {
|
|
60
|
+
* instanceClass: 'db.r6g.xlarge', // Upgrade database
|
|
61
|
+
* },
|
|
62
|
+
* },
|
|
63
|
+
* },
|
|
64
|
+
* }
|
|
65
|
+
* )
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
export function extendPreset(
|
|
69
|
+
basePreset: Partial<CloudConfig>,
|
|
70
|
+
extensions: Partial<CloudConfig>,
|
|
71
|
+
): Partial<CloudConfig> {
|
|
72
|
+
return deepMerge(basePreset as Record<string, any>, extensions as Record<string, any>) as Partial<CloudConfig>
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Compose multiple presets together
|
|
77
|
+
* Later presets override earlier ones
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* ```typescript
|
|
81
|
+
* const composedPreset = composePresets(
|
|
82
|
+
* createStaticSitePreset({ name: 'Site', slug: 'site', domain: 'example.com' }),
|
|
83
|
+
* createApiBackendPreset({ name: 'API', slug: 'api' }),
|
|
84
|
+
* {
|
|
85
|
+
* // Custom overrides
|
|
86
|
+
* infrastructure: {
|
|
87
|
+
* monitoring: {
|
|
88
|
+
* alarms: [{ metric: 'CustomMetric', threshold: 100 }],
|
|
89
|
+
* },
|
|
90
|
+
* },
|
|
91
|
+
* }
|
|
92
|
+
* )
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
95
|
+
export function composePresets(
|
|
96
|
+
...presets: Partial<CloudConfig>[]
|
|
97
|
+
): Partial<CloudConfig> {
|
|
98
|
+
return presets.reduce(
|
|
99
|
+
(acc, preset) => deepMerge(acc as Record<string, any>, preset as Record<string, any>),
|
|
100
|
+
{} as Record<string, any>,
|
|
101
|
+
) as Partial<CloudConfig>
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Create a custom preset by extending an existing one
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* ```typescript
|
|
109
|
+
* const createMyCustomPreset = createPreset(
|
|
110
|
+
* (options) => createNodeJsServerPreset(options),
|
|
111
|
+
* {
|
|
112
|
+
* infrastructure: {
|
|
113
|
+
* monitoring: {
|
|
114
|
+
* dashboard: {
|
|
115
|
+
* name: 'custom-dashboard',
|
|
116
|
+
* widgets: [{ type: 'metric', metrics: ['CustomMetric'] }],
|
|
117
|
+
* },
|
|
118
|
+
* },
|
|
119
|
+
* },
|
|
120
|
+
* }
|
|
121
|
+
* )
|
|
122
|
+
*
|
|
123
|
+
* // Use it
|
|
124
|
+
* const myPreset = createMyCustomPreset({ name: 'App', slug: 'app' })
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
127
|
+
export function createPreset<TOptions extends Record<string, any>>(
|
|
128
|
+
basePresetFn: (options: TOptions) => Partial<CloudConfig>,
|
|
129
|
+
extensions: Partial<CloudConfig> | ((config: Partial<CloudConfig>, options: TOptions) => Partial<CloudConfig>),
|
|
130
|
+
): (options: TOptions) => Partial<CloudConfig> {
|
|
131
|
+
return (options: TOptions) => {
|
|
132
|
+
const baseConfig = basePresetFn(options)
|
|
133
|
+
|
|
134
|
+
if (typeof extensions === 'function') {
|
|
135
|
+
return extendPreset(baseConfig, extensions(baseConfig, options))
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return extendPreset(baseConfig, extensions)
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Merge infrastructure configurations selectively
|
|
144
|
+
* Useful for adding specific infrastructure to existing presets
|
|
145
|
+
*
|
|
146
|
+
* @example
|
|
147
|
+
* ```typescript
|
|
148
|
+
* const withRedis = mergeInfrastructure({
|
|
149
|
+
* cache: {
|
|
150
|
+
* redis: {
|
|
151
|
+
* nodeType: 'cache.t3.small',
|
|
152
|
+
* numCacheNodes: 2,
|
|
153
|
+
* },
|
|
154
|
+
* },
|
|
155
|
+
* })
|
|
156
|
+
*
|
|
157
|
+
* const myPreset = extendPreset(
|
|
158
|
+
* createApiBackendPreset({ name: 'API', slug: 'api' }),
|
|
159
|
+
* withRedis
|
|
160
|
+
* )
|
|
161
|
+
* ```
|
|
162
|
+
*/
|
|
163
|
+
export function mergeInfrastructure(
|
|
164
|
+
infrastructure: Partial<CloudConfig['infrastructure']>,
|
|
165
|
+
): Partial<CloudConfig> {
|
|
166
|
+
return {
|
|
167
|
+
infrastructure,
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Add monitoring configuration to any preset
|
|
173
|
+
*
|
|
174
|
+
* @example
|
|
175
|
+
* ```typescript
|
|
176
|
+
* const myPreset = extendPreset(
|
|
177
|
+
* createStaticSitePreset({ name: 'Site', slug: 'site' }),
|
|
178
|
+
* withMonitoring({
|
|
179
|
+
* dashboard: { name: 'my-dashboard' },
|
|
180
|
+
* alarms: [{ metric: 'Errors', threshold: 10 }],
|
|
181
|
+
* })
|
|
182
|
+
* )
|
|
183
|
+
* ```
|
|
184
|
+
*/
|
|
185
|
+
export function withMonitoring(
|
|
186
|
+
monitoring: NonNullable<CloudConfig['infrastructure']>['monitoring'],
|
|
187
|
+
): Partial<CloudConfig> {
|
|
188
|
+
return mergeInfrastructure({ monitoring })
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Add security configuration to any preset
|
|
193
|
+
*
|
|
194
|
+
* @example
|
|
195
|
+
* ```typescript
|
|
196
|
+
* const myPreset = extendPreset(
|
|
197
|
+
* createApiBackendPreset({ name: 'API', slug: 'api' }),
|
|
198
|
+
* withSecurity({
|
|
199
|
+
* waf: { enabled: true, rules: ['rateLimit', 'sqlInjection'] },
|
|
200
|
+
* })
|
|
201
|
+
* )
|
|
202
|
+
* ```
|
|
203
|
+
*/
|
|
204
|
+
export function withSecurity(
|
|
205
|
+
security: NonNullable<CloudConfig['infrastructure']>['security'],
|
|
206
|
+
): Partial<CloudConfig> {
|
|
207
|
+
return mergeInfrastructure({ security })
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Add database configuration to any preset
|
|
212
|
+
*
|
|
213
|
+
* @example
|
|
214
|
+
* ```typescript
|
|
215
|
+
* const myPreset = extendPreset(
|
|
216
|
+
* createNodeJsServerlessPreset({ name: 'App', slug: 'app' }),
|
|
217
|
+
* withDatabase({
|
|
218
|
+
* postgres: {
|
|
219
|
+
* engine: 'postgres',
|
|
220
|
+
* version: '15',
|
|
221
|
+
* instanceClass: 'db.t3.medium',
|
|
222
|
+
* multiAZ: true,
|
|
223
|
+
* },
|
|
224
|
+
* })
|
|
225
|
+
* )
|
|
226
|
+
* ```
|
|
227
|
+
*/
|
|
228
|
+
export function withDatabase(
|
|
229
|
+
databases: NonNullable<CloudConfig['infrastructure']>['databases'],
|
|
230
|
+
): Partial<CloudConfig> {
|
|
231
|
+
return mergeInfrastructure({ databases })
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Add cache configuration to any preset
|
|
236
|
+
*
|
|
237
|
+
* @example
|
|
238
|
+
* ```typescript
|
|
239
|
+
* const myPreset = extendPreset(
|
|
240
|
+
* createApiBackendPreset({ name: 'API', slug: 'api' }),
|
|
241
|
+
* withCache({
|
|
242
|
+
* redis: {
|
|
243
|
+
* nodeType: 'cache.t3.small',
|
|
244
|
+
* numCacheNodes: 2,
|
|
245
|
+
* },
|
|
246
|
+
* })
|
|
247
|
+
* )
|
|
248
|
+
* ```
|
|
249
|
+
*/
|
|
250
|
+
export function withCache(
|
|
251
|
+
cache: NonNullable<CloudConfig['infrastructure']>['cache'],
|
|
252
|
+
): Partial<CloudConfig> {
|
|
253
|
+
return mergeInfrastructure({ cache })
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Add CDN configuration to any preset
|
|
258
|
+
*
|
|
259
|
+
* @example
|
|
260
|
+
* ```typescript
|
|
261
|
+
* const myPreset = extendPreset(
|
|
262
|
+
* createNodeJsServerPreset({ name: 'App', slug: 'app' }),
|
|
263
|
+
* withCDN({
|
|
264
|
+
* enabled: true,
|
|
265
|
+
* compress: true,
|
|
266
|
+
* http3: true,
|
|
267
|
+
* })
|
|
268
|
+
* )
|
|
269
|
+
* ```
|
|
270
|
+
*/
|
|
271
|
+
export function withCDN(
|
|
272
|
+
cdn: NonNullable<CloudConfig['infrastructure']>['cdn'],
|
|
273
|
+
): Partial<CloudConfig> {
|
|
274
|
+
return mergeInfrastructure({ cdn })
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Add queue configuration to any preset
|
|
279
|
+
*
|
|
280
|
+
* @example
|
|
281
|
+
* ```typescript
|
|
282
|
+
* const myPreset = extendPreset(
|
|
283
|
+
* createNodeJsServerlessPreset({ name: 'App', slug: 'app' }),
|
|
284
|
+
* withQueue({
|
|
285
|
+
* jobs: {
|
|
286
|
+
* fifo: false,
|
|
287
|
+
* deadLetterQueue: true,
|
|
288
|
+
* },
|
|
289
|
+
* })
|
|
290
|
+
* )
|
|
291
|
+
* ```
|
|
292
|
+
*/
|
|
293
|
+
export function withQueue(
|
|
294
|
+
queues: NonNullable<CloudConfig['infrastructure']>['queues'],
|
|
295
|
+
): Partial<CloudConfig> {
|
|
296
|
+
return mergeInfrastructure({ queues })
|
|
297
|
+
}
|