@stacksjs/cloud 0.58.48 → 0.58.50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +144 -60
- package/package.json +34 -33
- package/src/cloud/ai.ts +94 -0
- package/src/cloud/aws-sdk-layer/nodejs/package-lock.json +386 -0
- package/src/cloud/aws-sdk-layer/nodejs/package.json +15 -0
- package/src/cloud/cache.ts +0 -0
- package/src/cloud/cdn.ts +374 -0
- package/src/cloud/cli.ts +45 -0
- package/src/cloud/compute.ts +202 -0
- package/src/cloud/dashboard.ts +85 -0
- package/src/cloud/database.ts +0 -0
- package/src/cloud/deployment.ts +41 -0
- package/src/cloud/dns.ts +34 -0
- package/src/cloud/docs.ts +51 -0
- package/src/cloud/email.ts +339 -0
- package/src/cloud/file-system.ts +35 -0
- package/src/cloud/index.ts +103 -0
- package/src/cloud/jump-box.ts +48 -0
- package/src/cloud/lambda/ask/index.js +35 -0
- package/src/cloud/lambda/cli-setup/index.js +67 -0
- package/src/cloud/lambda/summarize/index.js +35 -0
- package/src/cloud/network.ts +32 -0
- package/src/cloud/package/README.md +59 -0
- package/src/cloud/package/package.json +63 -0
- package/src/cloud/permissions.ts +33 -0
- package/src/cloud/queue.ts +0 -0
- package/src/cloud/redirects.ts +45 -0
- package/src/cloud/router-layer/nodejs/package.json +15 -0
- package/src/cloud/search-engine.ts +108 -0
- package/src/cloud/security.ts +259 -0
- package/src/cloud/storage.ts +168 -0
- package/src/edge/origin-request.ts +49 -0
- package/src/helpers.ts +597 -0
- package/src/index.ts +3 -0
- package/src/runtime/README.md +116 -0
- package/src/runtime/bootstrap +3 -0
- package/src/runtime/example/lambda.ts +36 -0
- package/src/runtime/runtime.ts +830 -0
- package/src/runtime/scripts/build-layer.ts +104 -0
- package/src/runtime/scripts/publish-layer.ts +110 -0
- package/src/runtime/server.ts +39 -0
- package/src/types.ts +28 -0
package/dist/index.js
CHANGED
|
@@ -406,6 +406,7 @@ var appEnv = config2.app.env === "local" ? "dev" : config2.app.env;
|
|
|
406
406
|
var cloudName = `stacks-cloud-${appEnv}`;
|
|
407
407
|
// src/cloud/index.ts
|
|
408
408
|
import {Stack as Stack2} from "aws-cdk-lib";
|
|
409
|
+
import {config as config20} from "@stacksjs/config";
|
|
409
410
|
|
|
410
411
|
// src/cloud/ai.ts
|
|
411
412
|
import {Duration, CfnOutput as Output, aws_iam as iam, aws_lambda as lambda} from "aws-cdk-lib";
|
|
@@ -1347,7 +1348,7 @@ class CdnStack {
|
|
|
1347
1348
|
}
|
|
1348
1349
|
}
|
|
1349
1350
|
shouldDeployApi() {
|
|
1350
|
-
return config6.cloud.api;
|
|
1351
|
+
return config6.cloud.api?.deploy;
|
|
1351
1352
|
}
|
|
1352
1353
|
apiBehaviorOptions(scope, props) {
|
|
1353
1354
|
const hostname = Fn.select(2, Fn.split("/", props.webServerUrl.url));
|
|
@@ -1472,7 +1473,6 @@ class CdnStack {
|
|
|
1472
1473
|
if (this.shouldDeployApi()) {
|
|
1473
1474
|
const keysToRemove = ["_HANDLER", "_X_AMZN_TRACE_ID", "AWS_REGION", "AWS_EXECUTION_ENV", "AWS_LAMBDA_FUNCTION_NAME", "AWS_LAMBDA_FUNCTION_MEMORY_SIZE", "AWS_LAMBDA_FUNCTION_VERSION", "AWS_LAMBDA_INITIALIZATION_TYPE", "AWS_LAMBDA_LOG_GROUP_NAME", "AWS_LAMBDA_LOG_STREAM_NAME", "AWS_ACCESS_KEY", "AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "AWS_SESSION_TOKEN", "AWS_LAMBDA_RUNTIME_API", "LAMBDA_TASK_ROOT", "LAMBDA_RUNTIME_DIR", "_"];
|
|
1474
1475
|
keysToRemove.forEach((key) => delete env2[key]);
|
|
1475
|
-
behaviorOptions = this.apiBehaviorOptions(scope, props);
|
|
1476
1476
|
}
|
|
1477
1477
|
if (this.shouldDeployDocs() && !config6.app.docMode) {
|
|
1478
1478
|
behaviorOptions = {
|
|
@@ -1960,34 +1960,14 @@ class NetworkStack {
|
|
|
1960
1960
|
natGateways: 0,
|
|
1961
1961
|
subnetConfiguration: [
|
|
1962
1962
|
{
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1963
|
+
name: "public-subnet-1",
|
|
1964
|
+
subnetType: ec22.SubnetType.PUBLIC,
|
|
1965
|
+
cidrMask: 24
|
|
1966
1966
|
},
|
|
1967
1967
|
{
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
},
|
|
1972
|
-
{
|
|
1973
|
-
cidrMask: 21,
|
|
1974
|
-
name: `${props.slug}-${props.appEnv}-public-subnet-3`,
|
|
1975
|
-
subnetType: ec22.SubnetType.PUBLIC
|
|
1976
|
-
},
|
|
1977
|
-
{
|
|
1978
|
-
cidrMask: 21,
|
|
1979
|
-
name: `${props.slug}-${props.appEnv}-private-subnet-1`,
|
|
1980
|
-
subnetType: ec22.SubnetType.PRIVATE_ISOLATED
|
|
1981
|
-
},
|
|
1982
|
-
{
|
|
1983
|
-
cidrMask: 21,
|
|
1984
|
-
name: `${props.slug}-${props.appEnv}-private-subnet-2`,
|
|
1985
|
-
subnetType: ec22.SubnetType.PRIVATE_ISOLATED
|
|
1986
|
-
},
|
|
1987
|
-
{
|
|
1988
|
-
cidrMask: 21,
|
|
1989
|
-
name: `${props.slug}-${props.appEnv}-private-subnet-3`,
|
|
1990
|
-
subnetType: ec22.SubnetType.PRIVATE_ISOLATED
|
|
1968
|
+
name: "private-subnet-1",
|
|
1969
|
+
subnetType: ec22.SubnetType.PRIVATE_ISOLATED,
|
|
1970
|
+
cidrMask: 28
|
|
1991
1971
|
}
|
|
1992
1972
|
]
|
|
1993
1973
|
});
|
|
@@ -2337,11 +2317,14 @@ class PermissionsStack {
|
|
|
2337
2317
|
}
|
|
2338
2318
|
|
|
2339
2319
|
// src/cloud/compute.ts
|
|
2340
|
-
import {Duration as Duration6, CfnOutput as Output6,
|
|
2320
|
+
import {Duration as Duration6, CfnOutput as Output6, RemovalPolicy as RemovalPolicy8, aws_ec2 as ec23, aws_ecs as ecs, aws_secretsmanager as secretsmanager} from "aws-cdk-lib";
|
|
2341
2321
|
import {path as p6} from "@stacksjs/path";
|
|
2342
2322
|
import {env as env6} from "@stacksjs/env";
|
|
2323
|
+
import {LogGroup} from "aws-cdk-lib/aws-logs";
|
|
2324
|
+
import * as elbv2 from "aws-cdk-lib/aws-elasticloadbalancingv2";
|
|
2343
2325
|
|
|
2344
2326
|
class ComputeStack {
|
|
2327
|
+
lb;
|
|
2345
2328
|
apiServer;
|
|
2346
2329
|
apiServerUrl;
|
|
2347
2330
|
constructor(scope, props) {
|
|
@@ -2349,17 +2332,122 @@ class ComputeStack {
|
|
|
2349
2332
|
const fileSystem = props.fileSystem;
|
|
2350
2333
|
if (!fileSystem)
|
|
2351
2334
|
throw new Error("The file system is missing. Please make sure it was created properly.");
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2335
|
+
const cluster = new ecs.Cluster(scope, "StacksCluster", {
|
|
2336
|
+
clusterName: `${props.slug}-${props.appEnv}-web-server-cluster`,
|
|
2337
|
+
vpc
|
|
2338
|
+
});
|
|
2339
|
+
const taskDefinition = new ecs.FargateTaskDefinition(scope, "TaskDefinition", {
|
|
2340
|
+
family: `${props.appName}-${props.appEnv}-api`,
|
|
2341
|
+
memoryLimitMiB: 512,
|
|
2342
|
+
cpu: 256,
|
|
2343
|
+
runtimePlatform: {
|
|
2344
|
+
cpuArchitecture: ecs.CpuArchitecture.ARM64
|
|
2345
|
+
}
|
|
2346
|
+
});
|
|
2347
|
+
const container = taskDefinition.addContainer("WebServerContainer", {
|
|
2348
|
+
containerName: `${props.appName}-${props.appEnv}-api`,
|
|
2349
|
+
image: ecs.ContainerImage.fromAsset(p6.frameworkPath("server")),
|
|
2350
|
+
logging: new ecs.AwsLogDriver({
|
|
2351
|
+
streamPrefix: `${props.appName}-${props.appEnv}-web`,
|
|
2352
|
+
logGroup: new LogGroup(scope, "StacksApiLogs", {
|
|
2353
|
+
logGroupName: "/ecs/stacks-api",
|
|
2354
|
+
removalPolicy: RemovalPolicy8.DESTROY
|
|
2355
|
+
})
|
|
2356
|
+
}),
|
|
2357
|
+
healthCheck: {
|
|
2358
|
+
command: ["CMD-SHELL", "curl -f http://localhost:3000/health || exit 1"],
|
|
2359
|
+
interval: Duration6.seconds(10),
|
|
2360
|
+
timeout: Duration6.seconds(5),
|
|
2361
|
+
retries: 3,
|
|
2362
|
+
startPeriod: Duration6.seconds(10)
|
|
2363
|
+
}
|
|
2364
|
+
});
|
|
2365
|
+
container.addPortMappings({
|
|
2366
|
+
containerPort: 3000,
|
|
2367
|
+
hostPort: 3000
|
|
2368
|
+
});
|
|
2369
|
+
const serviceSecurityGroup = new ec23.SecurityGroup(scope, "ServiceSecurityGroup", {
|
|
2370
|
+
securityGroupName: `${props.appName}-${props.appEnv}-api-service-sg`,
|
|
2358
2371
|
vpc,
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2372
|
+
description: "Stacks Security Group for API Service"
|
|
2373
|
+
});
|
|
2374
|
+
const publicLoadBalancerSG = new ec23.SecurityGroup(scope, "PublicLoadBalancerSG", {
|
|
2375
|
+
securityGroupName: `${props.appName}-${props.appEnv}-public-load-balancer-sg`,
|
|
2376
|
+
vpc,
|
|
2377
|
+
description: "Access to the public facing load balancer"
|
|
2378
|
+
});
|
|
2379
|
+
serviceSecurityGroup.addIngressRule(publicLoadBalancerSG, ec23.Port.allTraffic(), "Ingress from the public ALB");
|
|
2380
|
+
serviceSecurityGroup.addIngressRule(publicLoadBalancerSG, ec23.Port.allTraffic(), "Ingress from the public ALB");
|
|
2381
|
+
this.lb = new elbv2.ApplicationLoadBalancer(scope, "ApplicationLoadBalancer", {
|
|
2382
|
+
loadBalancerName: `${props.appName}-${props.appEnv}-alb`,
|
|
2383
|
+
vpc,
|
|
2384
|
+
vpcSubnets: {
|
|
2385
|
+
subnets: vpc.selectSubnets({
|
|
2386
|
+
subnetType: ec23.SubnetType.PUBLIC,
|
|
2387
|
+
onePerAz: true
|
|
2388
|
+
}).subnets
|
|
2389
|
+
},
|
|
2390
|
+
internetFacing: true,
|
|
2391
|
+
idleTimeout: Duration6.seconds(30),
|
|
2392
|
+
securityGroup: publicLoadBalancerSG
|
|
2393
|
+
});
|
|
2394
|
+
const serviceTargetGroup = new elbv2.ApplicationTargetGroup(scope, "ServiceTargetGroup", {
|
|
2395
|
+
vpc,
|
|
2396
|
+
targetType: elbv2.TargetType.IP,
|
|
2397
|
+
protocol: elbv2.ApplicationProtocol.HTTP,
|
|
2398
|
+
port: 3000,
|
|
2399
|
+
healthCheck: {
|
|
2400
|
+
interval: Duration6.seconds(6),
|
|
2401
|
+
path: "/",
|
|
2402
|
+
protocol: elbv2.Protocol.HTTP,
|
|
2403
|
+
timeout: Duration6.seconds(5),
|
|
2404
|
+
healthyThresholdCount: 2,
|
|
2405
|
+
unhealthyThresholdCount: 10
|
|
2406
|
+
}
|
|
2407
|
+
});
|
|
2408
|
+
const service = new ecs.FargateService(scope, "StacksApiService", {
|
|
2409
|
+
serviceName: `${props.appName}-${props.appEnv}-api-service`,
|
|
2410
|
+
cluster,
|
|
2411
|
+
taskDefinition,
|
|
2412
|
+
desiredCount: 2,
|
|
2413
|
+
assignPublicIp: true,
|
|
2414
|
+
maxHealthyPercent: 200,
|
|
2415
|
+
vpcSubnets: vpc.selectSubnets({
|
|
2416
|
+
subnetType: ec23.SubnetType.PUBLIC,
|
|
2417
|
+
onePerAz: true
|
|
2418
|
+
}),
|
|
2419
|
+
minHealthyPercent: 75,
|
|
2420
|
+
securityGroups: [serviceSecurityGroup]
|
|
2421
|
+
});
|
|
2422
|
+
service.attachToApplicationTargetGroup(serviceTargetGroup);
|
|
2423
|
+
publicLoadBalancerSG.addIngressRule(ec23.Peer.anyIpv4(), ec23.Port.allTraffic());
|
|
2424
|
+
this.lb.addListener("HttpListener", {
|
|
2425
|
+
port: 80,
|
|
2426
|
+
defaultAction: elbv2.ListenerAction.forward([serviceTargetGroup])
|
|
2427
|
+
});
|
|
2428
|
+
props.fileSystem.connections.allowFromAnyIpv4(ec23.Port.tcp(2049));
|
|
2429
|
+
const volumeName = `${props.slug}-${props.appEnv}-efs`;
|
|
2430
|
+
taskDefinition.addVolume({
|
|
2431
|
+
name: volumeName,
|
|
2432
|
+
efsVolumeConfiguration: {
|
|
2433
|
+
fileSystemId: props.fileSystem.fileSystemId
|
|
2434
|
+
}
|
|
2435
|
+
});
|
|
2436
|
+
container.addMountPoints({
|
|
2437
|
+
sourceVolume: volumeName,
|
|
2438
|
+
containerPath: "/mnt/efs",
|
|
2439
|
+
readOnly: false
|
|
2440
|
+
});
|
|
2441
|
+
const scaling = service.autoScaleTaskCount({ maxCapacity: 2 });
|
|
2442
|
+
scaling.scaleOnCpuUtilization("CpuScaling", {
|
|
2443
|
+
targetUtilizationPercent: 50,
|
|
2444
|
+
scaleInCooldown: Duration6.seconds(60),
|
|
2445
|
+
scaleOutCooldown: Duration6.seconds(60)
|
|
2446
|
+
});
|
|
2447
|
+
scaling.scaleOnMemoryUtilization("MemoryScaling", {
|
|
2448
|
+
targetUtilizationPercent: 60,
|
|
2449
|
+
scaleInCooldown: Duration6.seconds(60),
|
|
2450
|
+
scaleOutCooldown: Duration6.seconds(60)
|
|
2363
2451
|
});
|
|
2364
2452
|
const keysToRemove = ["_HANDLER", "_X_AMZN_TRACE_ID", "AWS_REGION", "AWS_EXECUTION_ENV", "AWS_LAMBDA_FUNCTION_NAME", "AWS_LAMBDA_FUNCTION_MEMORY_SIZE", "AWS_LAMBDA_FUNCTION_VERSION", "AWS_LAMBDA_INITIALIZATION_TYPE", "AWS_LAMBDA_LOG_GROUP_NAME", "AWS_LAMBDA_LOG_STREAM_NAME", "AWS_ACCESS_KEY", "AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "AWS_SESSION_TOKEN", "AWS_LAMBDA_RUNTIME_API", "LAMBDA_TASK_ROOT", "LAMBDA_RUNTIME_DIR", "_"];
|
|
2365
2453
|
keysToRemove.forEach((key) => delete env6[key]);
|
|
@@ -2371,23 +2459,16 @@ class ComputeStack {
|
|
|
2371
2459
|
generateStringKey: Object.keys(env6).join(",").length.toString()
|
|
2372
2460
|
}
|
|
2373
2461
|
});
|
|
2374
|
-
secrets.grantRead(
|
|
2375
|
-
|
|
2376
|
-
this.apiServerUrl = new lambda5.FunctionUrl(scope, "StacksServerUrl", {
|
|
2377
|
-
function: this.apiServer,
|
|
2378
|
-
authType: lambda5.FunctionUrlAuthType.NONE,
|
|
2379
|
-
cors: {
|
|
2380
|
-
allowedOrigins: ["*"]
|
|
2381
|
-
}
|
|
2382
|
-
});
|
|
2462
|
+
secrets.grantRead(service.taskDefinition.executionRole);
|
|
2463
|
+
container.addEnvironment("SECRETS_ARN", secrets.secretArn);
|
|
2383
2464
|
const apiPrefix = "api";
|
|
2384
2465
|
new Output6(scope, "ApiUrl", {
|
|
2385
2466
|
value: `https://${props.domain}/${apiPrefix}`,
|
|
2386
2467
|
description: "The URL of the deployed application"
|
|
2387
2468
|
});
|
|
2388
2469
|
new Output6(scope, "ApiVanityUrl", {
|
|
2389
|
-
value: this.
|
|
2390
|
-
description: "The Vanity URL of the
|
|
2470
|
+
value: `http://${this.lb.loadBalancerDnsName}`,
|
|
2471
|
+
description: "The Vanity URL / DNS name of the load balancer"
|
|
2391
2472
|
});
|
|
2392
2473
|
}
|
|
2393
2474
|
}
|
|
@@ -2422,13 +2503,16 @@ class Cloud extends Stack2 {
|
|
|
2422
2503
|
});
|
|
2423
2504
|
new RedirectsStack(this, props);
|
|
2424
2505
|
new PermissionsStack(this);
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2506
|
+
let api;
|
|
2507
|
+
if (config20.cloud.api?.deploy) {
|
|
2508
|
+
api = new ComputeStack(this, {
|
|
2509
|
+
...props,
|
|
2510
|
+
vpc: network2.vpc,
|
|
2511
|
+
fileSystem: fileSystem.fileSystem,
|
|
2512
|
+
zone: dns2.zone,
|
|
2513
|
+
certificate: security2.certificate
|
|
2514
|
+
});
|
|
2515
|
+
}
|
|
2432
2516
|
const ai2 = new AiStack(this, props);
|
|
2433
2517
|
const cli4 = new CliStack(this, props);
|
|
2434
2518
|
const cdn2 = new CdnStack(this, {
|
|
@@ -2439,11 +2523,11 @@ class Cloud extends Stack2 {
|
|
|
2439
2523
|
firewall: security2.firewall,
|
|
2440
2524
|
originRequestFunction: docs2.originRequestFunction,
|
|
2441
2525
|
zone: dns2.zone,
|
|
2442
|
-
webServer: api.apiServer,
|
|
2443
|
-
webServerUrl: api.apiServerUrl,
|
|
2444
2526
|
cliSetupUrl: cli4.cliSetupUrl,
|
|
2445
2527
|
askAiUrl: ai2.askAiUrl,
|
|
2446
|
-
summarizeAiUrl: ai2.summarizeAiUrl
|
|
2528
|
+
summarizeAiUrl: ai2.summarizeAiUrl,
|
|
2529
|
+
webServer: api?.apiServer,
|
|
2530
|
+
webServerUrl: api?.apiServerUrl
|
|
2447
2531
|
});
|
|
2448
2532
|
new DeploymentStack(this, {
|
|
2449
2533
|
...props,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stacksjs/cloud",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.58.
|
|
4
|
+
"version": "0.58.50",
|
|
5
5
|
"description": "The Stacks cloud/serverless integration & implementation.",
|
|
6
6
|
"author": "Chris Breuer",
|
|
7
7
|
"license": "MIT",
|
|
@@ -40,7 +40,8 @@
|
|
|
40
40
|
],
|
|
41
41
|
"files": [
|
|
42
42
|
"README.md",
|
|
43
|
-
"dist"
|
|
43
|
+
"dist",
|
|
44
|
+
"src"
|
|
44
45
|
],
|
|
45
46
|
"scripts": {
|
|
46
47
|
"bootstrap": "bunx cdk bootstrap",
|
|
@@ -54,20 +55,20 @@
|
|
|
54
55
|
"prepublishOnly": "bun run build"
|
|
55
56
|
},
|
|
56
57
|
"peerDependencies": {
|
|
57
|
-
"@aws-sdk/client-bedrock": "^3.
|
|
58
|
-
"@aws-sdk/client-cloudformation": "^3.
|
|
59
|
-
"@aws-sdk/client-cloudfront": "^3.
|
|
60
|
-
"@aws-sdk/client-cloudwatch-logs": "^3.
|
|
61
|
-
"@aws-sdk/client-ec2": "^3.
|
|
62
|
-
"@aws-sdk/client-efs": "^3.
|
|
63
|
-
"@aws-sdk/client-iam": "^3.
|
|
64
|
-
"@aws-sdk/client-lambda": "^3.
|
|
65
|
-
"@aws-sdk/client-route-53-domains": "^3.
|
|
66
|
-
"@aws-sdk/client-s3": "^3.
|
|
67
|
-
"@aws-sdk/client-ses": "^3.
|
|
68
|
-
"@aws-sdk/client-sesv2": "^3.
|
|
69
|
-
"@aws-sdk/client-ssm": "^3.
|
|
70
|
-
"@aws-sdk/lib-dynamodb": "^3.
|
|
58
|
+
"@aws-sdk/client-bedrock": "^3.504.0",
|
|
59
|
+
"@aws-sdk/client-cloudformation": "^3.504.0",
|
|
60
|
+
"@aws-sdk/client-cloudfront": "^3.504.0",
|
|
61
|
+
"@aws-sdk/client-cloudwatch-logs": "^3.504.0",
|
|
62
|
+
"@aws-sdk/client-ec2": "^3.504.0",
|
|
63
|
+
"@aws-sdk/client-efs": "^3.504.0",
|
|
64
|
+
"@aws-sdk/client-iam": "^3.504.0",
|
|
65
|
+
"@aws-sdk/client-lambda": "^3.504.0",
|
|
66
|
+
"@aws-sdk/client-route-53-domains": "^3.504.0",
|
|
67
|
+
"@aws-sdk/client-s3": "^3.504.0",
|
|
68
|
+
"@aws-sdk/client-ses": "^3.504.0",
|
|
69
|
+
"@aws-sdk/client-sesv2": "^3.504.0",
|
|
70
|
+
"@aws-sdk/client-ssm": "^3.504.0",
|
|
71
|
+
"@aws-sdk/lib-dynamodb": "^3.506.0",
|
|
71
72
|
"@stacksjs/config": "latest",
|
|
72
73
|
"@stacksjs/env": "latest",
|
|
73
74
|
"@stacksjs/logging": "latest",
|
|
@@ -79,20 +80,20 @@
|
|
|
79
80
|
"@stacksjs/validation": "latest"
|
|
80
81
|
},
|
|
81
82
|
"dependencies": {
|
|
82
|
-
"@aws-sdk/client-bedrock": "^3.
|
|
83
|
-
"@aws-sdk/client-cloudformation": "^3.
|
|
84
|
-
"@aws-sdk/client-cloudfront": "^3.
|
|
85
|
-
"@aws-sdk/client-cloudwatch-logs": "^3.
|
|
86
|
-
"@aws-sdk/client-dynamodb": "3.
|
|
87
|
-
"@aws-sdk/client-ec2": "^3.
|
|
88
|
-
"@aws-sdk/client-efs": "^3.
|
|
89
|
-
"@aws-sdk/client-iam": "^3.
|
|
90
|
-
"@aws-sdk/client-lambda": "^3.
|
|
91
|
-
"@aws-sdk/client-route-53-domains": "^3.
|
|
92
|
-
"@aws-sdk/client-s3": "^3.
|
|
93
|
-
"@aws-sdk/client-ses": "^3.
|
|
94
|
-
"@aws-sdk/client-sesv2": "^3.
|
|
95
|
-
"@aws-sdk/client-ssm": "^3.
|
|
83
|
+
"@aws-sdk/client-bedrock": "^3.504.0",
|
|
84
|
+
"@aws-sdk/client-cloudformation": "^3.504.0",
|
|
85
|
+
"@aws-sdk/client-cloudfront": "^3.504.0",
|
|
86
|
+
"@aws-sdk/client-cloudwatch-logs": "^3.504.0",
|
|
87
|
+
"@aws-sdk/client-dynamodb": "3.506.0",
|
|
88
|
+
"@aws-sdk/client-ec2": "^3.504.0",
|
|
89
|
+
"@aws-sdk/client-efs": "^3.504.0",
|
|
90
|
+
"@aws-sdk/client-iam": "^3.504.0",
|
|
91
|
+
"@aws-sdk/client-lambda": "^3.504.0",
|
|
92
|
+
"@aws-sdk/client-route-53-domains": "^3.504.0",
|
|
93
|
+
"@aws-sdk/client-s3": "^3.504.0",
|
|
94
|
+
"@aws-sdk/client-ses": "^3.504.0",
|
|
95
|
+
"@aws-sdk/client-sesv2": "^3.504.0",
|
|
96
|
+
"@aws-sdk/client-ssm": "^3.504.0",
|
|
96
97
|
"@stacksjs/config": "latest",
|
|
97
98
|
"@stacksjs/dns": "latest",
|
|
98
99
|
"@stacksjs/env": "latest",
|
|
@@ -102,13 +103,13 @@
|
|
|
102
103
|
"@stacksjs/storage": "latest",
|
|
103
104
|
"@stacksjs/utils": "latest",
|
|
104
105
|
"@stacksjs/validation": "latest",
|
|
105
|
-
"aws-cdk": "^2.
|
|
106
|
-
"aws-cdk-lib": "^2.
|
|
106
|
+
"aws-cdk": "^2.126.0",
|
|
107
|
+
"aws-cdk-lib": "^2.126.0",
|
|
107
108
|
"aws4fetch": "^1.0.17",
|
|
108
109
|
"constructs": "^10.3.0"
|
|
109
110
|
},
|
|
110
111
|
"devDependencies": {
|
|
111
|
-
"@oclif/plugin-plugins": "^4.1
|
|
112
|
+
"@oclif/plugin-plugins": "^4.2.1",
|
|
112
113
|
"@stacksjs/cli": "latest",
|
|
113
114
|
"@stacksjs/development": "latest",
|
|
114
115
|
"@stacksjs/env": "latest",
|
package/src/cloud/ai.ts
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/* eslint-disable no-new */
|
|
2
|
+
import { Duration, CfnOutput as Output, aws_iam as iam, aws_lambda as lambda } from 'aws-cdk-lib'
|
|
3
|
+
import type { Construct } from 'constructs'
|
|
4
|
+
import { config } from '@stacksjs/config'
|
|
5
|
+
import type { NestedCloudProps } from '../types'
|
|
6
|
+
|
|
7
|
+
export interface AiStackProps extends NestedCloudProps {
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export class AiStack {
|
|
11
|
+
askAiUrl: lambda.FunctionUrl
|
|
12
|
+
summarizeAiUrl: lambda.FunctionUrl
|
|
13
|
+
|
|
14
|
+
constructor(scope: Construct, props: AiStackProps) {
|
|
15
|
+
// Define the Lambda Layer for aws-sdk
|
|
16
|
+
const awsSdkLayer = new lambda.LayerVersion(scope, 'AwsSdkLayer', {
|
|
17
|
+
code: lambda.Code.fromAsset('src/cloud/aws-sdk-layer'),
|
|
18
|
+
compatibleRuntimes: [lambda.Runtime.NODEJS_20_X],
|
|
19
|
+
description: 'Layer with aws-sdk',
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
const bedrockAccessPolicy = new iam.PolicyStatement({
|
|
23
|
+
effect: iam.Effect.ALLOW,
|
|
24
|
+
actions: [
|
|
25
|
+
'bedrock:InvokeModel',
|
|
26
|
+
'bedrock:InvokeModelWithResponseStream',
|
|
27
|
+
],
|
|
28
|
+
resources: config.ai.models?.map(model => `arn:aws:bedrock:us-east-1::foundation-model/${model}`),
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
const bedrockAccessRole = new iam.Role(scope, 'BedrockAccessRole', {
|
|
32
|
+
assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
|
|
33
|
+
managedPolicies: [
|
|
34
|
+
iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole'),
|
|
35
|
+
],
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
bedrockAccessRole.addToPolicy(bedrockAccessPolicy)
|
|
39
|
+
|
|
40
|
+
const askAi = new lambda.Function(scope, 'AskAiFunction', {
|
|
41
|
+
functionName: `${props.slug}-${props.appEnv}-ai-ask`,
|
|
42
|
+
description: 'Lambda function to invoke the AI model',
|
|
43
|
+
runtime: lambda.Runtime.NODEJS_20_X,
|
|
44
|
+
handler: 'index.handler',
|
|
45
|
+
code: lambda.Code.fromAsset('src/cloud/lambda/ask'), // path relative to the cloud root package dir
|
|
46
|
+
layers: [awsSdkLayer],
|
|
47
|
+
role: bedrockAccessRole,
|
|
48
|
+
timeout: Duration.seconds(30),
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
this.askAiUrl = new lambda.FunctionUrl(scope, 'AskAiFunctionUrl', {
|
|
52
|
+
function: askAi,
|
|
53
|
+
authType: lambda.FunctionUrlAuthType.NONE,
|
|
54
|
+
cors: {
|
|
55
|
+
allowedOrigins: ['*'],
|
|
56
|
+
},
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
const summarizeAi = new lambda.Function(scope, 'SummarizeAiFunction', {
|
|
60
|
+
functionName: `${props.slug}-${props.appEnv}-ai-summarize`,
|
|
61
|
+
description: 'Lambda function to summarize any given text',
|
|
62
|
+
runtime: lambda.Runtime.NODEJS_20_X,
|
|
63
|
+
handler: 'index.handler',
|
|
64
|
+
code: lambda.Code.fromAsset('src/cloud/lambda/summarize'),
|
|
65
|
+
layers: [awsSdkLayer],
|
|
66
|
+
role: bedrockAccessRole,
|
|
67
|
+
timeout: Duration.seconds(30),
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
this.summarizeAiUrl = new lambda.FunctionUrl(scope, 'SummarizeAiFunctionUrl', {
|
|
71
|
+
function: summarizeAi,
|
|
72
|
+
authType: lambda.FunctionUrlAuthType.NONE,
|
|
73
|
+
cors: {
|
|
74
|
+
allowedOrigins: ['*'],
|
|
75
|
+
},
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
new Output(scope, 'AiVanityAskApiUrl', {
|
|
79
|
+
value: this.askAiUrl.url,
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
new Output(scope, 'AiVanitySummarizeApiUrl', {
|
|
83
|
+
value: this.summarizeAiUrl.url,
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
new Output(scope, 'AiAskApiUrl', {
|
|
87
|
+
value: `https://${props.domain}/ai/ask`,
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
new Output(scope, 'AiSummarizeApiUrl', {
|
|
91
|
+
value: `https://${props.domain}/ai/summary`,
|
|
92
|
+
})
|
|
93
|
+
}
|
|
94
|
+
}
|