@jaypie/constructs 1.2.17 → 1.2.19
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/cjs/JaypieDynamoDb.d.ts +1 -1
- package/dist/cjs/JaypieNextJs.d.ts +9 -1
- package/dist/cjs/JaypieWebSocket.d.ts +115 -0
- package/dist/cjs/JaypieWebSocketLambda.d.ts +26 -0
- package/dist/cjs/JaypieWebSocketTable.d.ts +100 -0
- package/dist/cjs/__tests__/JaypieWebSocket.spec.d.ts +1 -0
- package/dist/cjs/index.cjs +449 -55
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.ts +3 -0
- package/dist/esm/JaypieDynamoDb.d.ts +1 -1
- package/dist/esm/JaypieNextJs.d.ts +9 -1
- package/dist/esm/JaypieWebSocket.d.ts +115 -0
- package/dist/esm/JaypieWebSocketLambda.d.ts +26 -0
- package/dist/esm/JaypieWebSocketTable.d.ts +100 -0
- package/dist/esm/__tests__/JaypieWebSocket.spec.d.ts +1 -0
- package/dist/esm/index.d.ts +3 -0
- package/dist/esm/index.js +406 -17
- package/dist/esm/index.js.map +1 -1
- package/package.json +3 -3
package/dist/esm/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as cdk from 'aws-cdk-lib';
|
|
2
|
-
import { Tags, Stack, Fn, CfnOutput, SecretValue, Duration, RemovalPolicy, CfnStack } from 'aws-cdk-lib';
|
|
2
|
+
import { Tags, Stack, Fn, CfnOutput, SecretValue, Duration, RemovalPolicy, CfnStack, ArnFormat } from 'aws-cdk-lib';
|
|
3
3
|
import * as s3 from 'aws-cdk-lib/aws-s3';
|
|
4
4
|
import { Bucket, StorageClass, BucketAccessControl, EventType } from 'aws-cdk-lib/aws-s3';
|
|
5
5
|
import { Construct } from 'constructs';
|
|
@@ -10,6 +10,7 @@ import * as route53Targets from 'aws-cdk-lib/aws-route53-targets';
|
|
|
10
10
|
import * as secretsmanager from 'aws-cdk-lib/aws-secretsmanager';
|
|
11
11
|
import { DatadogLambda } from 'datadog-cdk-constructs-v2';
|
|
12
12
|
import { ConfigurationError } from '@jaypie/errors';
|
|
13
|
+
import * as iam from 'aws-cdk-lib/aws-iam';
|
|
13
14
|
import { Role, PolicyStatement, Policy, FederatedPrincipal, Effect, ServicePrincipal, ManagedPolicy } from 'aws-cdk-lib/aws-iam';
|
|
14
15
|
import * as acm from 'aws-cdk-lib/aws-certificatemanager';
|
|
15
16
|
import * as lambda from 'aws-cdk-lib/aws-lambda';
|
|
@@ -31,6 +32,8 @@ import * as path from 'path';
|
|
|
31
32
|
import { Trail, ReadWriteType } from 'aws-cdk-lib/aws-cloudtrail';
|
|
32
33
|
import { CfnPermissionSet, CfnAssignment } from 'aws-cdk-lib/aws-sso';
|
|
33
34
|
import { CfnApplication } from 'aws-cdk-lib/aws-sam';
|
|
35
|
+
import * as apigatewayv2 from 'aws-cdk-lib/aws-apigatewayv2';
|
|
36
|
+
import * as apigatewayv2Integrations from 'aws-cdk-lib/aws-apigatewayv2-integrations';
|
|
34
37
|
|
|
35
38
|
const CDK$2 = {
|
|
36
39
|
ACCOUNT: {
|
|
@@ -3185,13 +3188,19 @@ class JaypieMongoDbSecret extends JaypieEnvSecret {
|
|
|
3185
3188
|
class JaypieNextJs extends Construct {
|
|
3186
3189
|
constructor(scope, id, props) {
|
|
3187
3190
|
super(scope, id);
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
+
// Determine if we should use a custom domain
|
|
3192
|
+
const useDomain = props?.domainProps !== false;
|
|
3193
|
+
// Resolve domain name only if using a custom domain
|
|
3194
|
+
const domainName = useDomain
|
|
3195
|
+
? typeof props?.domainName === "string"
|
|
3196
|
+
? props.domainName
|
|
3197
|
+
: envHostname(props?.domainName)
|
|
3198
|
+
: undefined;
|
|
3191
3199
|
this.domainName = domainName;
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
.replace(/[^a-zA-Z0-9]/g, "_")
|
|
3200
|
+
// Use domain name or construct ID for cache policy naming
|
|
3201
|
+
const cachePolicyIdentifier = domainName
|
|
3202
|
+
? domainName.replace(/\./g, "-").replace(/[^a-zA-Z0-9]/g, "_")
|
|
3203
|
+
: id.replace(/[^a-zA-Z0-9]/g, "_");
|
|
3195
3204
|
// Resolve environment from array or object syntax
|
|
3196
3205
|
const environment = resolveEnvironment(props?.environment);
|
|
3197
3206
|
const envSecrets = props?.envSecrets || {};
|
|
@@ -3228,27 +3237,32 @@ class JaypieNextJs extends Construct {
|
|
|
3228
3237
|
}, {});
|
|
3229
3238
|
const nextjs = new Nextjs(this, "NextJsApp", {
|
|
3230
3239
|
nextjsPath,
|
|
3231
|
-
|
|
3232
|
-
|
|
3233
|
-
|
|
3234
|
-
|
|
3235
|
-
|
|
3236
|
-
|
|
3240
|
+
// Only configure custom domain if useDomain is true
|
|
3241
|
+
...(useDomain &&
|
|
3242
|
+
domainName && {
|
|
3243
|
+
domainProps: {
|
|
3244
|
+
domainName,
|
|
3245
|
+
hostedZone: resolveHostedZone(this, {
|
|
3246
|
+
zone: props?.hostedZone,
|
|
3247
|
+
}),
|
|
3248
|
+
},
|
|
3249
|
+
}),
|
|
3237
3250
|
environment: {
|
|
3238
3251
|
...jaypieLambdaEnv(),
|
|
3239
3252
|
...environment,
|
|
3240
3253
|
...secretsEnvironment,
|
|
3241
3254
|
...jaypieSecretsEnvironment,
|
|
3242
3255
|
...nextPublicEnv,
|
|
3243
|
-
NEXT_PUBLIC_SITE_URL
|
|
3256
|
+
// NEXT_PUBLIC_SITE_URL will be set after construct creation for CloudFront URL
|
|
3257
|
+
...(domainName && { NEXT_PUBLIC_SITE_URL: `https://${domainName}` }),
|
|
3244
3258
|
},
|
|
3245
3259
|
overrides: {
|
|
3246
3260
|
nextjsDistribution: {
|
|
3247
3261
|
imageCachePolicyProps: {
|
|
3248
|
-
cachePolicyName: `NextJsImageCachePolicy-${
|
|
3262
|
+
cachePolicyName: `NextJsImageCachePolicy-${cachePolicyIdentifier}`,
|
|
3249
3263
|
},
|
|
3250
3264
|
serverCachePolicyProps: {
|
|
3251
|
-
cachePolicyName: `NextJsServerCachePolicy-${
|
|
3265
|
+
cachePolicyName: `NextJsServerCachePolicy-${cachePolicyIdentifier}`,
|
|
3252
3266
|
},
|
|
3253
3267
|
},
|
|
3254
3268
|
nextjsImage: {
|
|
@@ -3263,6 +3277,10 @@ class JaypieNextJs extends Construct {
|
|
|
3263
3277
|
},
|
|
3264
3278
|
},
|
|
3265
3279
|
});
|
|
3280
|
+
// Set NEXT_PUBLIC_SITE_URL to CloudFront URL when no custom domain
|
|
3281
|
+
if (!domainName) {
|
|
3282
|
+
nextjs.serverFunction.lambdaFunction.addEnvironment("NEXT_PUBLIC_SITE_URL", `https://${nextjs.distribution.distributionDomain}`);
|
|
3283
|
+
}
|
|
3266
3284
|
addDatadogLayers(nextjs.imageOptimizationFunction);
|
|
3267
3285
|
addDatadogLayers(nextjs.serverFunction.lambdaFunction);
|
|
3268
3286
|
// Grant secret read permissions
|
|
@@ -4103,5 +4121,376 @@ class JaypieTraceSigningKeySecret extends JaypieEnvSecret {
|
|
|
4103
4121
|
}
|
|
4104
4122
|
}
|
|
4105
4123
|
|
|
4106
|
-
|
|
4124
|
+
//
|
|
4125
|
+
//
|
|
4126
|
+
// Main
|
|
4127
|
+
//
|
|
4128
|
+
class JaypieWebSocket extends Construct {
|
|
4129
|
+
constructor(scope, id, props = {}) {
|
|
4130
|
+
super(scope, id);
|
|
4131
|
+
const { certificate = true, connect, default: defaultHandler, disconnect, handler, host: propsHost, logRetention = logs.RetentionDays.THREE_MONTHS, name, roleTag = CDK$2.ROLE.API, routes = {}, stageName = "production", zone: propsZone, } = props;
|
|
4132
|
+
// Validate: either handler OR individual handlers, not both
|
|
4133
|
+
const hasIndividualHandlers = connect || disconnect || defaultHandler;
|
|
4134
|
+
if (handler && hasIndividualHandlers) {
|
|
4135
|
+
throw new Error("Cannot specify both 'handler' and individual route handlers (connect/disconnect/default)");
|
|
4136
|
+
}
|
|
4137
|
+
// Determine zone from props or environment
|
|
4138
|
+
let zone = propsZone;
|
|
4139
|
+
if (!zone && process.env.CDK_ENV_HOSTED_ZONE) {
|
|
4140
|
+
zone = process.env.CDK_ENV_HOSTED_ZONE;
|
|
4141
|
+
}
|
|
4142
|
+
// Determine host from props or environment
|
|
4143
|
+
let host;
|
|
4144
|
+
if (typeof propsHost === "string") {
|
|
4145
|
+
host = propsHost;
|
|
4146
|
+
}
|
|
4147
|
+
else if (typeof propsHost === "object") {
|
|
4148
|
+
// Resolve host from HostConfig using envHostname()
|
|
4149
|
+
host = envHostname(propsHost);
|
|
4150
|
+
}
|
|
4151
|
+
else if (process.env.CDK_ENV_WS_HOST_NAME) {
|
|
4152
|
+
host = process.env.CDK_ENV_WS_HOST_NAME;
|
|
4153
|
+
}
|
|
4154
|
+
else if (process.env.CDK_ENV_WS_SUBDOMAIN &&
|
|
4155
|
+
process.env.CDK_ENV_HOSTED_ZONE) {
|
|
4156
|
+
host = mergeDomain(process.env.CDK_ENV_WS_SUBDOMAIN, process.env.CDK_ENV_HOSTED_ZONE);
|
|
4157
|
+
}
|
|
4158
|
+
const apiName = name || constructEnvName("WebSocket");
|
|
4159
|
+
// Create WebSocket API
|
|
4160
|
+
this._api = new apigatewayv2.WebSocketApi(this, "Api", {
|
|
4161
|
+
apiName,
|
|
4162
|
+
});
|
|
4163
|
+
Tags.of(this._api).add(CDK$2.TAG.ROLE, roleTag);
|
|
4164
|
+
// Add routes with Lambda integrations
|
|
4165
|
+
const connectHandler = handler || connect;
|
|
4166
|
+
const disconnectHandler = handler || disconnect;
|
|
4167
|
+
const defaultRouteHandler = handler || defaultHandler;
|
|
4168
|
+
if (connectHandler) {
|
|
4169
|
+
this._api.addRoute("$connect", {
|
|
4170
|
+
integration: new apigatewayv2Integrations.WebSocketLambdaIntegration("ConnectIntegration", connectHandler),
|
|
4171
|
+
});
|
|
4172
|
+
}
|
|
4173
|
+
if (disconnectHandler) {
|
|
4174
|
+
this._api.addRoute("$disconnect", {
|
|
4175
|
+
integration: new apigatewayv2Integrations.WebSocketLambdaIntegration("DisconnectIntegration", disconnectHandler),
|
|
4176
|
+
});
|
|
4177
|
+
}
|
|
4178
|
+
if (defaultRouteHandler) {
|
|
4179
|
+
this._api.addRoute("$default", {
|
|
4180
|
+
integration: new apigatewayv2Integrations.WebSocketLambdaIntegration("DefaultIntegration", defaultRouteHandler),
|
|
4181
|
+
});
|
|
4182
|
+
}
|
|
4183
|
+
// Add custom routes
|
|
4184
|
+
for (const [routeKey, routeHandler] of Object.entries(routes)) {
|
|
4185
|
+
this._api.addRoute(routeKey, {
|
|
4186
|
+
integration: new apigatewayv2Integrations.WebSocketLambdaIntegration(`${routeKey}Integration`, routeHandler),
|
|
4187
|
+
});
|
|
4188
|
+
}
|
|
4189
|
+
// Create log group for access logs
|
|
4190
|
+
// Note: logGroup is created for future use when API Gateway v2 WebSocket
|
|
4191
|
+
// access logging is fully supported in CDK
|
|
4192
|
+
new logs.LogGroup(this, "AccessLogs", {
|
|
4193
|
+
removalPolicy: RemovalPolicy.DESTROY,
|
|
4194
|
+
retention: logRetention,
|
|
4195
|
+
});
|
|
4196
|
+
// Create stage
|
|
4197
|
+
this._stage = new apigatewayv2.WebSocketStage(this, "Stage", {
|
|
4198
|
+
autoDeploy: true,
|
|
4199
|
+
stageName,
|
|
4200
|
+
webSocketApi: this._api,
|
|
4201
|
+
});
|
|
4202
|
+
Tags.of(this._stage).add(CDK$2.TAG.ROLE, roleTag);
|
|
4203
|
+
// Set up custom domain if host and zone are provided
|
|
4204
|
+
let hostedZone;
|
|
4205
|
+
let certificateToUse;
|
|
4206
|
+
if (host && zone) {
|
|
4207
|
+
hostedZone = resolveHostedZone(this, { zone });
|
|
4208
|
+
// Use resolveCertificate to create certificate at stack level (enables reuse)
|
|
4209
|
+
certificateToUse = resolveCertificate(this, {
|
|
4210
|
+
certificate,
|
|
4211
|
+
domainName: host,
|
|
4212
|
+
roleTag: CDK$2.ROLE.HOSTING,
|
|
4213
|
+
zone: hostedZone,
|
|
4214
|
+
});
|
|
4215
|
+
this._certificate = certificateToUse;
|
|
4216
|
+
this._host = host;
|
|
4217
|
+
if (certificateToUse) {
|
|
4218
|
+
// Create custom domain
|
|
4219
|
+
this._domainName = new apigatewayv2.DomainName(this, "DomainName", {
|
|
4220
|
+
certificate: certificateToUse,
|
|
4221
|
+
domainName: host,
|
|
4222
|
+
});
|
|
4223
|
+
Tags.of(this._domainName).add(CDK$2.TAG.ROLE, roleTag);
|
|
4224
|
+
// Map domain to stage
|
|
4225
|
+
new apigatewayv2.ApiMapping(this, "ApiMapping", {
|
|
4226
|
+
api: this._api,
|
|
4227
|
+
domainName: this._domainName,
|
|
4228
|
+
stage: this._stage,
|
|
4229
|
+
});
|
|
4230
|
+
// Create DNS record
|
|
4231
|
+
new route53.ARecord(this, "AliasRecord", {
|
|
4232
|
+
recordName: host,
|
|
4233
|
+
target: route53.RecordTarget.fromAlias(new route53Targets.ApiGatewayv2DomainProperties(this._domainName.regionalDomainName, this._domainName.regionalHostedZoneId)),
|
|
4234
|
+
zone: hostedZone,
|
|
4235
|
+
});
|
|
4236
|
+
// Also create AAAA record for IPv6
|
|
4237
|
+
new route53.AaaaRecord(this, "AaaaAliasRecord", {
|
|
4238
|
+
recordName: host,
|
|
4239
|
+
target: route53.RecordTarget.fromAlias(new route53Targets.ApiGatewayv2DomainProperties(this._domainName.regionalDomainName, this._domainName.regionalHostedZoneId)),
|
|
4240
|
+
zone: hostedZone,
|
|
4241
|
+
});
|
|
4242
|
+
}
|
|
4243
|
+
}
|
|
4244
|
+
// Grant all handlers permission to manage connections
|
|
4245
|
+
const allHandlers = new Set();
|
|
4246
|
+
if (connectHandler)
|
|
4247
|
+
allHandlers.add(connectHandler);
|
|
4248
|
+
if (disconnectHandler)
|
|
4249
|
+
allHandlers.add(disconnectHandler);
|
|
4250
|
+
if (defaultRouteHandler)
|
|
4251
|
+
allHandlers.add(defaultRouteHandler);
|
|
4252
|
+
Object.values(routes).forEach((h) => allHandlers.add(h));
|
|
4253
|
+
for (const lambdaHandler of allHandlers) {
|
|
4254
|
+
this.grantManageConnections(lambdaHandler);
|
|
4255
|
+
}
|
|
4256
|
+
}
|
|
4257
|
+
//
|
|
4258
|
+
//
|
|
4259
|
+
// Public accessors
|
|
4260
|
+
//
|
|
4261
|
+
get api() {
|
|
4262
|
+
return this._api;
|
|
4263
|
+
}
|
|
4264
|
+
get apiId() {
|
|
4265
|
+
return this._api.apiId;
|
|
4266
|
+
}
|
|
4267
|
+
get certificate() {
|
|
4268
|
+
return this._certificate;
|
|
4269
|
+
}
|
|
4270
|
+
get domainName() {
|
|
4271
|
+
return this._domainName?.name;
|
|
4272
|
+
}
|
|
4273
|
+
/**
|
|
4274
|
+
* The WebSocket endpoint URL.
|
|
4275
|
+
* Uses custom domain if configured, otherwise returns the default stage URL.
|
|
4276
|
+
*/
|
|
4277
|
+
get endpoint() {
|
|
4278
|
+
if (this._host) {
|
|
4279
|
+
return `wss://${this._host}`;
|
|
4280
|
+
}
|
|
4281
|
+
return this._stage.url;
|
|
4282
|
+
}
|
|
4283
|
+
get host() {
|
|
4284
|
+
return this._host;
|
|
4285
|
+
}
|
|
4286
|
+
get stage() {
|
|
4287
|
+
return this._stage;
|
|
4288
|
+
}
|
|
4289
|
+
/**
|
|
4290
|
+
* The callback URL for API Gateway Management API.
|
|
4291
|
+
* Use this URL to send messages to connected clients.
|
|
4292
|
+
*/
|
|
4293
|
+
get callbackUrl() {
|
|
4294
|
+
if (this._host) {
|
|
4295
|
+
return `https://${this._host}`;
|
|
4296
|
+
}
|
|
4297
|
+
// Extract callback URL from stage URL
|
|
4298
|
+
// Stage URL: wss://abc123.execute-api.us-east-1.amazonaws.com/production
|
|
4299
|
+
// Callback URL: https://abc123.execute-api.us-east-1.amazonaws.com/production
|
|
4300
|
+
return this._stage.url.replace("wss://", "https://");
|
|
4301
|
+
}
|
|
4302
|
+
//
|
|
4303
|
+
//
|
|
4304
|
+
// Public methods
|
|
4305
|
+
//
|
|
4306
|
+
/**
|
|
4307
|
+
* Grant a Lambda function permission to manage WebSocket connections
|
|
4308
|
+
* (post to connections, delete connections).
|
|
4309
|
+
*/
|
|
4310
|
+
grantManageConnections(grantee) {
|
|
4311
|
+
return iam.Grant.addToPrincipal({
|
|
4312
|
+
actions: ["execute-api:ManageConnections"],
|
|
4313
|
+
grantee: grantee.grantPrincipal,
|
|
4314
|
+
resourceArns: [
|
|
4315
|
+
Stack.of(this).formatArn({
|
|
4316
|
+
arnFormat: ArnFormat.SLASH_RESOURCE_SLASH_RESOURCE_NAME,
|
|
4317
|
+
resource: this._api.apiId,
|
|
4318
|
+
resourceName: `${this._stage.stageName}/*`,
|
|
4319
|
+
service: "execute-api",
|
|
4320
|
+
}),
|
|
4321
|
+
],
|
|
4322
|
+
});
|
|
4323
|
+
}
|
|
4324
|
+
}
|
|
4325
|
+
|
|
4326
|
+
/**
|
|
4327
|
+
* JaypieWebSocketLambda - A Lambda function optimized for WebSocket handlers.
|
|
4328
|
+
*
|
|
4329
|
+
* Provides sensible defaults for WebSocket event handling:
|
|
4330
|
+
* - 30 second timeout (same as API handlers)
|
|
4331
|
+
* - API role tag
|
|
4332
|
+
*
|
|
4333
|
+
* @example
|
|
4334
|
+
* ```typescript
|
|
4335
|
+
* const handler = new JaypieWebSocketLambda(this, "ChatHandler", {
|
|
4336
|
+
* code: "dist/handlers",
|
|
4337
|
+
* handler: "chat.handler",
|
|
4338
|
+
* secrets: ["MONGODB_URI"],
|
|
4339
|
+
* });
|
|
4340
|
+
*
|
|
4341
|
+
* new JaypieWebSocket(this, "Chat", {
|
|
4342
|
+
* host: "ws.example.com",
|
|
4343
|
+
* handler,
|
|
4344
|
+
* });
|
|
4345
|
+
* ```
|
|
4346
|
+
*/
|
|
4347
|
+
class JaypieWebSocketLambda extends JaypieLambda {
|
|
4348
|
+
constructor(scope, id, props) {
|
|
4349
|
+
super(scope, id, {
|
|
4350
|
+
roleTag: CDK$2.ROLE.API,
|
|
4351
|
+
timeout: Duration.seconds(CDK$2.DURATION.EXPRESS_API),
|
|
4352
|
+
...props,
|
|
4353
|
+
});
|
|
4354
|
+
}
|
|
4355
|
+
}
|
|
4356
|
+
|
|
4357
|
+
//
|
|
4358
|
+
//
|
|
4359
|
+
// Main
|
|
4360
|
+
//
|
|
4361
|
+
/**
|
|
4362
|
+
* JaypieWebSocketTable - DynamoDB table for storing WebSocket connection IDs.
|
|
4363
|
+
*
|
|
4364
|
+
* Provides a simple table structure for tracking active WebSocket connections:
|
|
4365
|
+
* - Partition key: connectionId (String)
|
|
4366
|
+
* - TTL attribute: expiresAt (for automatic cleanup)
|
|
4367
|
+
* - Optional GSI: userId-index (for looking up connections by user)
|
|
4368
|
+
*
|
|
4369
|
+
* @example
|
|
4370
|
+
* ```typescript
|
|
4371
|
+
* const connectionTable = new JaypieWebSocketTable(this, "Connections");
|
|
4372
|
+
*
|
|
4373
|
+
* const ws = new JaypieWebSocket(this, "Chat", {
|
|
4374
|
+
* host: "ws.example.com",
|
|
4375
|
+
* handler: chatHandler,
|
|
4376
|
+
* });
|
|
4377
|
+
*
|
|
4378
|
+
* // Grant Lambda access to the table
|
|
4379
|
+
* connectionTable.grantReadWriteData(chatHandler);
|
|
4380
|
+
*
|
|
4381
|
+
* // Pass table name to Lambda
|
|
4382
|
+
* chatHandler.addEnvironment("CONNECTION_TABLE", connectionTable.tableName);
|
|
4383
|
+
* ```
|
|
4384
|
+
*
|
|
4385
|
+
* @example
|
|
4386
|
+
* // With user index for looking up all connections for a user
|
|
4387
|
+
* const connectionTable = new JaypieWebSocketTable(this, "Connections", {
|
|
4388
|
+
* userIndex: true,
|
|
4389
|
+
* ttl: Duration.hours(12),
|
|
4390
|
+
* });
|
|
4391
|
+
*/
|
|
4392
|
+
class JaypieWebSocketTable extends Construct {
|
|
4393
|
+
constructor(scope, id, props = {}) {
|
|
4394
|
+
super(scope, id);
|
|
4395
|
+
const { roleTag = CDK$2.ROLE.STORAGE, tableName, ttl = Duration.hours(24), userIndex = false, } = props;
|
|
4396
|
+
this._ttlDuration = ttl;
|
|
4397
|
+
// Build global secondary indexes
|
|
4398
|
+
const globalSecondaryIndexes = [];
|
|
4399
|
+
if (userIndex) {
|
|
4400
|
+
globalSecondaryIndexes.push({
|
|
4401
|
+
indexName: "userId-index",
|
|
4402
|
+
partitionKey: { name: "userId", type: dynamodb.AttributeType.STRING },
|
|
4403
|
+
sortKey: { name: "connectedAt", type: dynamodb.AttributeType.STRING },
|
|
4404
|
+
});
|
|
4405
|
+
}
|
|
4406
|
+
// Create the table
|
|
4407
|
+
this._table = new dynamodb.TableV2(this, "Table", {
|
|
4408
|
+
billing: dynamodb.Billing.onDemand(),
|
|
4409
|
+
globalSecondaryIndexes: globalSecondaryIndexes.length > 0 ? globalSecondaryIndexes : undefined,
|
|
4410
|
+
partitionKey: {
|
|
4411
|
+
name: "connectionId",
|
|
4412
|
+
type: dynamodb.AttributeType.STRING,
|
|
4413
|
+
},
|
|
4414
|
+
removalPolicy: RemovalPolicy.DESTROY,
|
|
4415
|
+
tableName: tableName || constructEnvName("WebSocketConnections"),
|
|
4416
|
+
timeToLiveAttribute: "expiresAt",
|
|
4417
|
+
});
|
|
4418
|
+
Tags.of(this._table).add(CDK$2.TAG.ROLE, roleTag);
|
|
4419
|
+
}
|
|
4420
|
+
//
|
|
4421
|
+
//
|
|
4422
|
+
// Public accessors
|
|
4423
|
+
//
|
|
4424
|
+
/**
|
|
4425
|
+
* The underlying DynamoDB TableV2 construct.
|
|
4426
|
+
*/
|
|
4427
|
+
get table() {
|
|
4428
|
+
return this._table;
|
|
4429
|
+
}
|
|
4430
|
+
/**
|
|
4431
|
+
* The name of the DynamoDB table.
|
|
4432
|
+
*/
|
|
4433
|
+
get tableName() {
|
|
4434
|
+
return this._table.tableName;
|
|
4435
|
+
}
|
|
4436
|
+
/**
|
|
4437
|
+
* The ARN of the DynamoDB table.
|
|
4438
|
+
*/
|
|
4439
|
+
get tableArn() {
|
|
4440
|
+
return this._table.tableArn;
|
|
4441
|
+
}
|
|
4442
|
+
/**
|
|
4443
|
+
* TTL duration for connections in seconds.
|
|
4444
|
+
* Use this to calculate expiresAt when storing connections.
|
|
4445
|
+
*/
|
|
4446
|
+
get ttlSeconds() {
|
|
4447
|
+
return this._ttlDuration.toSeconds();
|
|
4448
|
+
}
|
|
4449
|
+
//
|
|
4450
|
+
//
|
|
4451
|
+
// Grant methods
|
|
4452
|
+
//
|
|
4453
|
+
/**
|
|
4454
|
+
* Grant read permissions to the table.
|
|
4455
|
+
*/
|
|
4456
|
+
grantReadData(grantee) {
|
|
4457
|
+
return this._table.grantReadData(grantee);
|
|
4458
|
+
}
|
|
4459
|
+
/**
|
|
4460
|
+
* Grant write permissions to the table.
|
|
4461
|
+
*/
|
|
4462
|
+
grantWriteData(grantee) {
|
|
4463
|
+
return this._table.grantWriteData(grantee);
|
|
4464
|
+
}
|
|
4465
|
+
/**
|
|
4466
|
+
* Grant read and write permissions to the table.
|
|
4467
|
+
*/
|
|
4468
|
+
grantReadWriteData(grantee) {
|
|
4469
|
+
return this._table.grantReadWriteData(grantee);
|
|
4470
|
+
}
|
|
4471
|
+
//
|
|
4472
|
+
//
|
|
4473
|
+
// Convenience methods
|
|
4474
|
+
//
|
|
4475
|
+
/**
|
|
4476
|
+
* Add the table name to a Lambda function's environment variables.
|
|
4477
|
+
* Also grants read/write access to the table.
|
|
4478
|
+
*/
|
|
4479
|
+
connectLambda(lambdaFunction, options = {}) {
|
|
4480
|
+
const { envKey = "CONNECTION_TABLE", readOnly = false } = options;
|
|
4481
|
+
// Add environment variable
|
|
4482
|
+
if ("addEnvironment" in lambdaFunction) {
|
|
4483
|
+
lambdaFunction.addEnvironment(envKey, this.tableName);
|
|
4484
|
+
}
|
|
4485
|
+
// Grant permissions
|
|
4486
|
+
if (readOnly) {
|
|
4487
|
+
this.grantReadData(lambdaFunction.grantPrincipal);
|
|
4488
|
+
}
|
|
4489
|
+
else {
|
|
4490
|
+
this.grantReadWriteData(lambdaFunction.grantPrincipal);
|
|
4491
|
+
}
|
|
4492
|
+
}
|
|
4493
|
+
}
|
|
4494
|
+
|
|
4495
|
+
export { CDK$2 as CDK, JaypieAccountLoggingBucket, JaypieApiGateway, JaypieAppStack, JaypieBucketQueuedLambda, JaypieCertificate, JaypieDatadogBucket, JaypieDatadogForwarder, JaypieDatadogSecret, JaypieDistribution, JaypieDnsRecord, JaypieDynamoDb, JaypieEnvSecret, JaypieEventsRule, JaypieExpressLambda, JaypieGitHubDeployRole, JaypieHostedZone, JaypieInfrastructureStack, JaypieLambda, JaypieMongoDbSecret, JaypieNextJs, JaypieOpenAiSecret, JaypieOrganizationTrail, JaypieQueuedLambda, JaypieSsoPermissions, JaypieSsoSyncApplication, JaypieStack, JaypieStaticWebBucket, JaypieTraceSigningKeySecret, JaypieWebDeploymentBucket, JaypieWebSocket, JaypieWebSocketLambda, JaypieWebSocketTable, addDatadogLayers, clearAllCertificateCaches, clearAllSecretsCaches, clearCertificateCache, clearSecretsCache, constructEnvName, constructStackName, constructTagger, envHostname, extendDatadogRole, isEnv, isProductionEnv, isSandboxEnv, isValidHostname$1 as isValidHostname, isValidSubdomain, jaypieLambdaEnv, mergeDomain, resolveCertificate, resolveDatadogForwarderFunction, resolveDatadogLayers, resolveDatadogLoggingDestination, resolveEnvironment, resolveHostedZone, resolveParamsAndSecrets, resolveSecrets };
|
|
4107
4496
|
//# sourceMappingURL=index.js.map
|