2026-04-22 14:36:55 -04:00
|
|
|
import * as cdk from "aws-cdk-lib";
|
|
|
|
|
import * as lambda from "aws-cdk-lib/aws-lambda";
|
|
|
|
|
import * as apigwv2 from "aws-cdk-lib/aws-apigatewayv2";
|
|
|
|
|
import * as integrations from "aws-cdk-lib/aws-apigatewayv2-integrations";
|
|
|
|
|
import * as ssm from "aws-cdk-lib/aws-ssm";
|
|
|
|
|
import * as route53 from "aws-cdk-lib/aws-route53";
|
|
|
|
|
import * as route53Targets from "aws-cdk-lib/aws-route53-targets";
|
|
|
|
|
import * as acm from "aws-cdk-lib/aws-certificatemanager";
|
|
|
|
|
import * as logs from "aws-cdk-lib/aws-logs";
|
|
|
|
|
import { Construct } from "constructs";
|
|
|
|
|
import * as path from "path";
|
|
|
|
|
|
|
|
|
|
export class DoorUnlockStack extends cdk.Stack {
|
|
|
|
|
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
|
|
|
|
|
super(scope, id, props);
|
|
|
|
|
|
|
|
|
|
const elementsApiKeyParam = ssm.StringParameter.fromSecureStringParameterAttributes(
|
|
|
|
|
this,
|
|
|
|
|
"ElementsApiKey",
|
|
|
|
|
{ parameterName: "/seahaven/door-unlock/elements-api-key" }
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const authTokenParam = ssm.StringParameter.fromSecureStringParameterAttributes(
|
|
|
|
|
this,
|
|
|
|
|
"AuthToken",
|
|
|
|
|
{ parameterName: "/seahaven/door-unlock/auth-token" }
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const doorIdParam = ssm.StringParameter.fromStringParameterName(
|
|
|
|
|
this,
|
|
|
|
|
"DoorId",
|
|
|
|
|
"/seahaven/door-unlock/door-id"
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const unlockHandler = new lambda.Function(this, "UnlockHandler", {
|
|
|
|
|
runtime: lambda.Runtime.NODEJS_20_X,
|
|
|
|
|
handler: "unlock-handler.handler",
|
|
|
|
|
code: lambda.Code.fromAsset(path.join(__dirname, "../lambda"), {
|
|
|
|
|
bundling: {
|
|
|
|
|
image: lambda.Runtime.NODEJS_20_X.bundlingImage,
|
|
|
|
|
local: {
|
|
|
|
|
tryBundle(outputDir: string) {
|
|
|
|
|
const { execSync } = require("child_process");
|
|
|
|
|
execSync(
|
|
|
|
|
`esbuild ${path.join(__dirname, "../lambda/unlock-handler.ts")} --bundle --platform=node --target=node20 --outfile=${path.join(outputDir, "unlock-handler.js")} --external:@aws-sdk/*`
|
|
|
|
|
);
|
|
|
|
|
return true;
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
}),
|
|
|
|
|
environment: {
|
|
|
|
|
ELEMENTS_API_KEY_PARAM: "/seahaven/door-unlock/elements-api-key",
|
|
|
|
|
AUTH_TOKEN_PARAM: "/seahaven/door-unlock/auth-token",
|
|
|
|
|
DOOR_ID_PARAM: "/seahaven/door-unlock/door-id",
|
|
|
|
|
},
|
|
|
|
|
timeout: cdk.Duration.seconds(10),
|
|
|
|
|
memorySize: 128,
|
|
|
|
|
logRetention: logs.RetentionDays.THREE_MONTHS,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
elementsApiKeyParam.grantRead(unlockHandler);
|
|
|
|
|
authTokenParam.grantRead(unlockHandler);
|
|
|
|
|
doorIdParam.grantRead(unlockHandler);
|
|
|
|
|
|
|
|
|
|
const httpApi = new apigwv2.HttpApi(this, "DoorUnlockApi", {
|
2026-04-28 14:43:48 -04:00
|
|
|
apiName: "door-unlock-api",
|
2026-04-22 14:36:55 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const defaultStage = httpApi.defaultStage!.node.defaultChild as apigwv2.CfnStage;
|
|
|
|
|
defaultStage.addPropertyOverride("DefaultRouteSettings", {
|
|
|
|
|
ThrottlingBurstLimit: 5,
|
|
|
|
|
ThrottlingRateLimit: 2,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
httpApi.addRoutes({
|
|
|
|
|
path: "/unlock",
|
|
|
|
|
methods: [apigwv2.HttpMethod.GET],
|
|
|
|
|
integration: new integrations.HttpLambdaIntegration(
|
|
|
|
|
"UnlockIntegration",
|
|
|
|
|
unlockHandler
|
|
|
|
|
),
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const hostedZone = route53.HostedZone.fromHostedZoneAttributes(
|
|
|
|
|
this,
|
|
|
|
|
"SeaHavenZone",
|
|
|
|
|
{
|
|
|
|
|
hostedZoneId: "Z06652411XKH89KTZD3XA",
|
|
|
|
|
zoneName: "seahaven.com",
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const certificate = acm.Certificate.fromCertificateArn(
|
|
|
|
|
this,
|
|
|
|
|
"WildcardCert",
|
|
|
|
|
"arn:aws:acm:us-east-1:328440206208:certificate/a66c0994-90d4-410a-a1d9-5595c2a3fae3"
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const domainName = new apigwv2.DomainName(this, "DoorUnlockDomain", {
|
|
|
|
|
domainName: "doorunlock.seahaven.com",
|
|
|
|
|
certificate,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
new apigwv2.ApiMapping(this, "DoorUnlockMapping", {
|
|
|
|
|
api: httpApi,
|
|
|
|
|
domainName,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
new route53.ARecord(this, "DoorUnlockARecord", {
|
|
|
|
|
zone: hostedZone,
|
|
|
|
|
recordName: "doorunlock",
|
|
|
|
|
target: route53.RecordTarget.fromAlias(
|
|
|
|
|
new route53Targets.ApiGatewayv2DomainProperties(
|
|
|
|
|
domainName.regionalDomainName,
|
|
|
|
|
domainName.regionalHostedZoneId
|
|
|
|
|
)
|
|
|
|
|
),
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
new cdk.CfnOutput(this, "ApiUrl", {
|
|
|
|
|
value: `https://doorunlock.seahaven.com/unlock`,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|