webspresso 0.0.105 → 0.0.106

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 (134) hide show
  1. package/.agents/AGENTS.md +15 -2
  2. package/.agents/CLI.md +219 -7
  3. package/.agents/FLAGS.md +118 -0
  4. package/.agents/LOGGING.md +93 -0
  5. package/.agents/METRICS.md +127 -0
  6. package/.agents/MIGRATION_JOBS.md +95 -0
  7. package/.agents/PLUGINS.md +10 -3
  8. package/.agents/QUEUE.md +42 -0
  9. package/.agents/RATE_LIMIT.md +147 -0
  10. package/.agents/SCALE_OUT.md +109 -0
  11. package/.agents/SECRETS.md +117 -0
  12. package/AGENTS.md +10 -0
  13. package/bin/commands/add-aws.js +396 -0
  14. package/bin/commands/add-ci.js +523 -0
  15. package/bin/commands/add-cloudflare.js +240 -0
  16. package/bin/commands/add-cloudrun.js +381 -0
  17. package/bin/commands/add-migration-job.js +396 -0
  18. package/bin/commands/assets-sync.js +209 -0
  19. package/bin/commands/client-generate.js +52 -0
  20. package/bin/commands/console.js +53 -0
  21. package/bin/commands/db-migrate.js +47 -2
  22. package/bin/commands/db-studio.js +84 -0
  23. package/bin/commands/deploy-check.js +242 -13
  24. package/bin/commands/export.js +87 -0
  25. package/bin/commands/secrets-pull.js +208 -0
  26. package/bin/utils/db.js +7 -1
  27. package/bin/webspresso.js +22 -0
  28. package/core/app.js +421 -0
  29. package/core/auth/authenticate.js +93 -0
  30. package/core/auth/index.js +34 -4
  31. package/core/auth/manager.js +50 -5
  32. package/core/auth/middleware.js +16 -68
  33. package/core/auth/redis-session.js +1008 -0
  34. package/core/auth/sessions.js +156 -0
  35. package/core/cache/cdn.js +296 -0
  36. package/core/cache/index.js +12 -0
  37. package/core/cache/tagged-lru.js +9 -1
  38. package/core/console/commands.js +148 -0
  39. package/core/console/context.js +260 -0
  40. package/core/console/eval.js +70 -0
  41. package/core/console/index.js +22 -0
  42. package/core/console/repl.js +102 -0
  43. package/core/errors/domain.js +1 -0
  44. package/core/events/dispatcher.js +7 -0
  45. package/core/events/signal.js +7 -0
  46. package/core/export/discovery.js +191 -0
  47. package/core/export/exporter.js +277 -0
  48. package/core/export/index.js +24 -0
  49. package/core/flags/evaluator.js +252 -0
  50. package/core/flags/hasher.js +37 -0
  51. package/core/flags/index.js +21 -0
  52. package/core/flags/manager.js +263 -0
  53. package/core/flags/store.js +126 -0
  54. package/core/health/middleware.js +3 -3
  55. package/core/http/adapter.js +74 -0
  56. package/core/http/express-adapter.js +46 -0
  57. package/core/http/hono-adapter.js +531 -0
  58. package/core/http/index.js +41 -0
  59. package/core/http/pipeline.js +485 -0
  60. package/core/index.js +336 -0
  61. package/core/limits/middleware.js +9 -1
  62. package/core/logger/formatters.js +264 -0
  63. package/core/logger/index.js +260 -0
  64. package/core/logger/trace.js +137 -0
  65. package/core/metrics/collectors.js +125 -0
  66. package/core/metrics/index.js +45 -0
  67. package/core/metrics/middleware.js +230 -0
  68. package/core/metrics/registry.js +366 -0
  69. package/core/orm/d1.js +265 -0
  70. package/core/orm/index.js +105 -5
  71. package/core/orm/migrate-cloud.js +194 -0
  72. package/core/orm/pool.js +97 -0
  73. package/core/orm/query-builder.js +9 -0
  74. package/core/queue/adapters/cloudflare.js +131 -0
  75. package/core/queue/adapters/pubsub.js +400 -0
  76. package/core/queue/adapters/sqs.js +419 -0
  77. package/core/queue/adapters/wait-until.js +77 -0
  78. package/core/queue/index.js +8 -0
  79. package/core/queue/manager.js +11 -0
  80. package/core/rate-limit/index.js +22 -0
  81. package/core/rate-limit/limiter.js +219 -0
  82. package/core/rate-limit/stores/memory.js +129 -0
  83. package/core/rate-limit/stores/redis.js +151 -0
  84. package/core/rate-limit/utils.js +112 -0
  85. package/core/resilience/circuit-breaker.js +31 -0
  86. package/core/secrets/index.js +113 -0
  87. package/core/secrets/manager.js +308 -0
  88. package/core/secrets/providers/aws.js +288 -0
  89. package/core/secrets/providers/env.js +44 -0
  90. package/core/secrets/providers/gcp.js +307 -0
  91. package/core/secrets/providers/memory.js +76 -0
  92. package/core/shutdown/shutdown-manager.js +9 -0
  93. package/core/stream/index.js +19 -0
  94. package/core/stream/text-stream.js +326 -0
  95. package/core/studio/index.js +43 -0
  96. package/core/studio/inspector.js +258 -0
  97. package/core/studio/server.js +325 -0
  98. package/core/studio/ui.js +681 -0
  99. package/index.d.ts +934 -2
  100. package/index.js +125 -3
  101. package/package.json +3 -1
  102. package/plugins/admin-panel/index.js +12 -5
  103. package/plugins/api-key/index.js +3 -2
  104. package/plugins/audit-log/index.js +3 -1
  105. package/plugins/basic-auth/index.js +3 -2
  106. package/plugins/cors.js +3 -2
  107. package/plugins/csrf/index.js +4 -3
  108. package/plugins/csv/index.js +8 -5
  109. package/plugins/email/index.js +11 -9
  110. package/plugins/index.js +3 -0
  111. package/plugins/queue/index.js +18 -2
  112. package/plugins/redirect/index.js +7 -2
  113. package/plugins/seo-checker/index.js +2 -2
  114. package/plugins/site-analytics/index.js +3 -1
  115. package/plugins/swagger.js +8 -2
  116. package/plugins/upload/gcs-provider.js +148 -0
  117. package/plugins/upload/index.js +132 -74
  118. package/plugins/upload/s3-provider.js +257 -0
  119. package/plugins/webhooks/index.js +27 -23
  120. package/plugins/xlsx/index.js +7 -5
  121. package/src/api/api-loader.js +12 -95
  122. package/src/api/define-api.js +1 -0
  123. package/src/client-runtime/constants.js +10 -0
  124. package/src/client-runtime/mount.js +2 -3
  125. package/src/dev/client-gen.js +458 -0
  126. package/src/discovery/scan-routes.js +5 -2
  127. package/src/file-router.js +2 -0
  128. package/src/helpers.js +53 -0
  129. package/src/pages/page-loader.js +12 -205
  130. package/src/plugin-manager.js +9 -1
  131. package/src/server.js +231 -140
  132. package/src/services/executor.js +9 -0
  133. package/src/services/registry.js +9 -1
  134. package/src/services/validator.js +38 -20
@@ -0,0 +1,396 @@
1
+ /**
2
+ * Add AWS Command
3
+ * Generate production-ready AWS configuration (apprunner.yaml, ecs-task-definition.json, deploy-aws.sh)
4
+ * Supports AWS App Runner and AWS ECS (Fargate) container deployments
5
+ * @module bin/commands/add-aws
6
+ */
7
+
8
+ 'use strict';
9
+
10
+ const fs = require('fs');
11
+ const path = require('path');
12
+ const { generateDockerfile, generateDockerignore } = require('./add-docker');
13
+
14
+ /**
15
+ * Normalize CPU value to ECS Fargate units (256, 512, 1024, 2048, 4096)
16
+ * @param {string|number} cpu
17
+ * @returns {string}
18
+ */
19
+ function normalizeEcsCpu(cpu) {
20
+ if (!cpu) return '512';
21
+ const str = String(cpu).trim().toLowerCase();
22
+ if (str === '0.25' || str === '0.25 vcpu') return '256';
23
+ if (str === '0.5' || str === '0.5 vcpu') return '512';
24
+ if (str === '1' || str === '1 vcpu') return '1024';
25
+ if (str === '2' || str === '2 vcpu') return '2048';
26
+ if (str === '4' || str === '4 vcpu') return '4096';
27
+ return str.replace(/[^0-9]/g, '') || '512';
28
+ }
29
+
30
+ /**
31
+ * Normalize Memory value to ECS Fargate MiB (512, 1024, 2048, etc.)
32
+ * @param {string|number} memory
33
+ * @returns {string}
34
+ */
35
+ function normalizeEcsMemory(memory) {
36
+ if (!memory) return '1024';
37
+ const str = String(memory).trim().toLowerCase();
38
+ if (str.endsWith('gb') || str.endsWith('g')) {
39
+ const num = parseFloat(str);
40
+ return String(Math.round(num * 1024));
41
+ }
42
+ if (str.endsWith('mib') || str.endsWith('mb') || str.endsWith('mi')) {
43
+ return str.replace(/[^0-9]/g, '') || '1024';
44
+ }
45
+ return str.replace(/[^0-9]/g, '') || '1024';
46
+ }
47
+
48
+ /**
49
+ * Generate apprunner.yaml for AWS App Runner
50
+ * @param {Object} options
51
+ * @param {string} options.appName
52
+ * @param {number} [options.port=7331]
53
+ * @param {string} [options.nodeVersion='nodejs20']
54
+ * @returns {string}
55
+ */
56
+ function generateAppRunnerYaml(options = {}) {
57
+ const {
58
+ port = 7331,
59
+ nodeVersion = 'nodejs20',
60
+ } = options;
61
+
62
+ return `# ==============================================================================
63
+ # AWS App Runner Configuration for Webspresso
64
+ # Fully-managed container & code runtime with auto-scaling and zero-ops TLS
65
+ # Docs: https://docs.aws.amazon.com/apprunner/latest/dg/config-file.html
66
+ # ==============================================================================
67
+
68
+ version: 1.0
69
+ runtime: ${nodeVersion}
70
+
71
+ build:
72
+ commands:
73
+ build:
74
+ - npm ci --omit=dev
75
+ - npm run build --if-present
76
+ env:
77
+ - name: NODE_ENV
78
+ value: production
79
+
80
+ run:
81
+ command: npm start
82
+ network:
83
+ port: "${port}"
84
+ env: PORT
85
+ env:
86
+ - name: NODE_ENV
87
+ value: production
88
+ - name: PORT
89
+ value: "${port}"
90
+ `;
91
+ }
92
+
93
+ /**
94
+ * Generate AWS ECS Task Definition JSON for AWS Fargate
95
+ * @param {Object} options
96
+ * @param {string} options.appName
97
+ * @param {string} [options.region='us-east-1']
98
+ * @param {string|number} [options.cpu='512']
99
+ * @param {string|number} [options.memory='1024']
100
+ * @param {number} [options.port=7331]
101
+ * @returns {string}
102
+ */
103
+ function generateEcsTaskDefinition(options = {}) {
104
+ const {
105
+ appName = 'webspresso-app',
106
+ region = 'us-east-1',
107
+ cpu = '512',
108
+ memory = '1024',
109
+ port = 7331,
110
+ } = options;
111
+
112
+ const normalizedCpu = normalizeEcsCpu(cpu);
113
+ const normalizedMemory = normalizeEcsMemory(memory);
114
+
115
+ const taskDef = {
116
+ family: appName,
117
+ networkMode: 'awsvpc',
118
+ requiresCompatibilities: ['FARGATE'],
119
+ cpu: normalizedCpu,
120
+ memory: normalizedMemory,
121
+ executionRoleArn: 'arn:aws:iam::YOUR_AWS_ACCOUNT_ID:role/ecsTaskExecutionRole',
122
+ taskRoleArn: 'arn:aws:iam::YOUR_AWS_ACCOUNT_ID:role/ecsTaskRole',
123
+ containerDefinitions: [
124
+ {
125
+ name: appName,
126
+ image: `YOUR_AWS_ACCOUNT_ID.dkr.ecr.${region}.amazonaws.com/${appName}:latest`,
127
+ essential: true,
128
+ portMappings: [
129
+ {
130
+ containerPort: port,
131
+ hostPort: port,
132
+ protocol: 'tcp',
133
+ },
134
+ ],
135
+ environment: [
136
+ { name: 'NODE_ENV', value: 'production' },
137
+ { name: 'PORT', value: String(port) },
138
+ ],
139
+ healthCheck: {
140
+ command: [
141
+ 'CMD-SHELL',
142
+ `node -e 'require("http").get("http://localhost:${port}/healthz", (r) => process.exit(r.statusCode === 200 ? 0 : 1))' || exit 1`,
143
+ ],
144
+ interval: 30,
145
+ timeout: 5,
146
+ retries: 3,
147
+ startPeriod: 15,
148
+ },
149
+ logConfiguration: {
150
+ logDriver: 'awslogs',
151
+ options: {
152
+ 'awslogs-group': `/ecs/${appName}`,
153
+ 'awslogs-region': region,
154
+ 'awslogs-stream-prefix': 'ecs',
155
+ 'awslogs-create-group': 'true',
156
+ },
157
+ },
158
+ },
159
+ ],
160
+ };
161
+
162
+ return JSON.stringify(taskDef, null, 2) + '\n';
163
+ }
164
+
165
+ /**
166
+ * Generate deploy-aws.sh script for automated deployment to ECR, App Runner, or ECS
167
+ * @param {Object} options
168
+ * @param {string} options.appName
169
+ * @param {string} [options.region='us-east-1']
170
+ * @param {number} [options.port=7331]
171
+ * @returns {string}
172
+ */
173
+ function generateAwsDeployScript(options = {}) {
174
+ const {
175
+ appName = 'webspresso-app',
176
+ region = 'us-east-1',
177
+ port = 7331,
178
+ } = options;
179
+
180
+ return `#!/usr/bin/env bash
181
+ set -euo pipefail
182
+
183
+ # ==============================================================================
184
+ # Webspresso AWS Deployment Automation Script
185
+ # Builds hardened Docker image, pushes to Amazon ECR, and updates App Runner / ECS
186
+ # Usage: ./deploy-aws.sh [APP_NAME] [REGION]
187
+ # ==============================================================================
188
+
189
+ APP_NAME="\${1:-${appName}}"
190
+ REGION="\${2:-\${AWS_REGION:-${region}}}"
191
+ PORT="\${PORT:-${port}}"
192
+
193
+ echo "☁️ Webspresso AWS Deployment Target: '\$APP_NAME' in '\$REGION'"
194
+
195
+ # 1. Verify AWS CLI
196
+ if ! command -v aws &> /dev/null; then
197
+ echo "❌ Error: 'aws' CLI is not installed or not in PATH."
198
+ echo "Please install AWS CLI: https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html"
199
+ exit 1
200
+ fi
201
+
202
+ # 2. Verify Docker
203
+ if ! command -v docker &> /dev/null; then
204
+ echo "❌ Error: 'docker' is not installed or not running."
205
+ exit 1
206
+ fi
207
+
208
+ # 3. Retrieve AWS Account ID
209
+ AWS_ACCOUNT_ID="\$(aws sts get-caller-identity --query Account --output text 2>/dev/null || true)"
210
+ if [ -z "\$AWS_ACCOUNT_ID" ]; then
211
+ echo "❌ Error: Could not determine AWS Account ID. Are your AWS credentials configured?"
212
+ echo "Run: aws configure"
213
+ exit 1
214
+ fi
215
+
216
+ ECR_URI="\$AWS_ACCOUNT_ID.dkr.ecr.\$REGION.amazonaws.com/\$APP_NAME"
217
+ IMAGE_TAG="\$(git rev-parse --short HEAD 2>/dev/null || echo 'latest')"
218
+
219
+ echo "🔑 Authenticated as AWS Account: \$AWS_ACCOUNT_ID"
220
+ echo "📦 Target ECR Repository: \$ECR_URI"
221
+
222
+ # 4. Ensure ECR Repository exists
223
+ aws ecr describe-repositories --repository-names "\$APP_NAME" --region "\$REGION" &>/dev/null || {
224
+ echo "📁 Creating ECR repository '\$APP_NAME'..."
225
+ aws ecr create-repository \\
226
+ --repository-name "\$APP_NAME" \\
227
+ --image-scanning-configuration scanOnPush=true \\
228
+ --region "\$REGION" >/dev/null
229
+ }
230
+
231
+ # 5. Authenticate Docker with Amazon ECR
232
+ echo "🔐 Logging in to Amazon ECR..."
233
+ aws ecr get-login-password --region "\$REGION" | docker login --username AWS --password-stdin "\$AWS_ACCOUNT_ID.dkr.ecr.\$REGION.amazonaws.com"
234
+
235
+ # 6. Build production multi-stage Docker image
236
+ echo "🔨 Building Docker image..."
237
+ docker build -t "\$APP_NAME:\$IMAGE_TAG" -t "\$ECR_URI:\$IMAGE_TAG" -t "\$ECR_URI:latest" .
238
+
239
+ # 7. Push to ECR
240
+ echo "🚀 Pushing image to Amazon ECR..."
241
+ docker push "\$ECR_URI:\$IMAGE_TAG"
242
+ docker push "\$ECR_URI:latest"
243
+
244
+ echo ""
245
+ echo "✅ Image successfully built and pushed to Amazon ECR:"
246
+ echo " \$ECR_URI:\$IMAGE_TAG"
247
+ echo " \$ECR_URI:latest"
248
+ echo ""
249
+ echo "Next steps to complete deployment:"
250
+ echo " Option A (AWS App Runner):"
251
+ echo " aws apprunner create-service --service-name \$APP_NAME \\"
252
+ echo " --source-configuration ImageRepository='{ImageIdentifier=\"'\$ECR_URI:latest'\",ImageRepositoryType=\"ECR\",ImageConfiguration={Port=\"'\$PORT'\"}}'"
253
+ echo ""
254
+ echo " Option B (AWS ECS Fargate):"
255
+ echo " aws ecs register-task-definition --cli-input-json file://ecs-task-definition.json"
256
+ echo " aws ecs update-service --cluster \$APP_NAME-cluster --service \$APP_NAME-service --force-new-deployment"
257
+ echo ""
258
+ `;
259
+ }
260
+
261
+ /**
262
+ * Register command with Commander
263
+ * @param {import('commander').Command} program
264
+ */
265
+ function registerCommand(program) {
266
+ program
267
+ .command('add:aws')
268
+ .alias('aws')
269
+ .alias('add-aws')
270
+ .description('Generate production-ready AWS deployment configuration (App Runner & ECS Fargate)')
271
+ .option('-r, --region <region>', 'AWS region', 'us-east-1')
272
+ .option('--port <port>', 'Container port (Webspresso default is 7331)', (v) => parseInt(v, 10), 7331)
273
+ .option('--cpu <cpu>', 'CPU allocation for ECS/App Runner (e.g. 512, 1024 or 1 vCPU)', '512')
274
+ .option('--memory <memory>', 'Memory allocation for ECS/App Runner (e.g. 1024, 1GB)', '1024')
275
+ .option('-f, --force', 'Overwrite existing files without prompting', false)
276
+ .action(async (...actionArgs) => {
277
+ const cmd = actionArgs[actionArgs.length - 1];
278
+ const options = (cmd && typeof cmd.opts === 'function')
279
+ ? cmd.opts()
280
+ : (actionArgs.find((a) => a && typeof a === 'object') || {});
281
+
282
+ const cwd = process.cwd();
283
+ const pkgPath = path.join(cwd, 'package.json');
284
+
285
+ if (!fs.existsSync(pkgPath)) {
286
+ console.error('❌ Not a Webspresso project! package.json was not found in current directory.');
287
+ process.exit(1);
288
+ }
289
+
290
+ let pkg = {};
291
+ try {
292
+ pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
293
+ } catch (err) {
294
+ console.error(`❌ Failed to parse package.json: ${err.message}`);
295
+ process.exit(1);
296
+ }
297
+
298
+ const appName = pkg.name ? pkg.name.replace(/[^a-zA-Z0-9_-]/g, '-') : 'webspresso-app';
299
+ const force = Boolean(options.force);
300
+ const region = options.region || 'us-east-1';
301
+ const port = options.port || 7331;
302
+ const cpu = options.cpu || '512';
303
+ const memory = options.memory || '1024';
304
+
305
+ const appRunnerPath = path.join(cwd, 'apprunner.yaml');
306
+ const ecsTaskDefPath = path.join(cwd, 'ecs-task-definition.json');
307
+ const scriptPath = path.join(cwd, 'deploy-aws.sh');
308
+ const dockerfilePath = path.join(cwd, 'Dockerfile');
309
+ const dockerignorePath = path.join(cwd, '.dockerignore');
310
+
311
+ console.log(`\n☁️ Scaffolding AWS deployment configuration for "${appName}"...`);
312
+
313
+ // 1. Ensure Dockerfile exists (needed by ECR & container deploy)
314
+ if (!fs.existsSync(dockerfilePath)) {
315
+ const dockerfileContent = generateDockerfile({ port, node: '22-alpine' });
316
+ fs.writeFileSync(dockerfilePath, dockerfileContent, 'utf8');
317
+ console.log(`✅ Created Dockerfile (configured for port ${port})`);
318
+ }
319
+
320
+ if (!fs.existsSync(dockerignorePath)) {
321
+ const dockerignoreContent = generateDockerignore();
322
+ fs.writeFileSync(dockerignorePath, dockerignoreContent, 'utf8');
323
+ console.log(`✅ Created .dockerignore`);
324
+ }
325
+
326
+ // 2. apprunner.yaml
327
+ if (fs.existsSync(appRunnerPath) && !force) {
328
+ console.log(`⚠️ ${path.basename(appRunnerPath)} already exists. Skipping (use --force to overwrite).`);
329
+ } else {
330
+ const appRunnerContent = generateAppRunnerYaml({
331
+ appName,
332
+ port,
333
+ });
334
+ fs.writeFileSync(appRunnerPath, appRunnerContent, 'utf8');
335
+ console.log(`✅ Created ${path.basename(appRunnerPath)} (AWS App Runner)`);
336
+ }
337
+
338
+ // 3. ecs-task-definition.json
339
+ if (fs.existsSync(ecsTaskDefPath) && !force) {
340
+ console.log(`⚠️ ${path.basename(ecsTaskDefPath)} already exists. Skipping (use --force to overwrite).`);
341
+ } else {
342
+ const taskDefContent = generateEcsTaskDefinition({
343
+ appName,
344
+ region,
345
+ cpu,
346
+ memory,
347
+ port,
348
+ });
349
+ fs.writeFileSync(ecsTaskDefPath, taskDefContent, 'utf8');
350
+ console.log(`✅ Created ${path.basename(ecsTaskDefPath)} (AWS ECS Fargate Task Definition)`);
351
+ }
352
+
353
+ // 4. deploy-aws.sh
354
+ if (fs.existsSync(scriptPath) && !force) {
355
+ console.log(`⚠️ ${path.basename(scriptPath)} already exists. Skipping (use --force to overwrite).`);
356
+ } else {
357
+ const scriptContent = generateAwsDeployScript({
358
+ appName,
359
+ region,
360
+ port,
361
+ });
362
+ fs.writeFileSync(scriptPath, scriptContent, { encoding: 'utf8', mode: 0o755 });
363
+ console.log(`✅ Created ${path.basename(scriptPath)} (executable)`);
364
+ }
365
+
366
+ // 5. Update package.json scripts
367
+ let modifiedPkg = false;
368
+ if (!pkg.scripts) pkg.scripts = {};
369
+ if (!pkg.scripts['aws:deploy']) {
370
+ pkg.scripts['aws:deploy'] = './deploy-aws.sh';
371
+ modifiedPkg = true;
372
+ }
373
+
374
+ if (modifiedPkg) {
375
+ try {
376
+ fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n', 'utf8');
377
+ console.log(`✅ Added "aws:deploy" script to package.json`);
378
+ } catch (_) {}
379
+ }
380
+
381
+ console.log('\n🎉 AWS deployment configuration complete!');
382
+ console.log('\nNext steps:');
383
+ console.log(' 1. Configure AWS CLI: `aws configure`');
384
+ console.log(' 2. Review ecs-task-definition.json and apprunner.yaml');
385
+ console.log(' 3. Deploy container via ECR: `npm run aws:deploy`\n');
386
+ });
387
+ }
388
+
389
+ module.exports = {
390
+ registerCommand,
391
+ generateAppRunnerYaml,
392
+ generateEcsTaskDefinition,
393
+ generateAwsDeployScript,
394
+ normalizeEcsCpu,
395
+ normalizeEcsMemory,
396
+ };