@openhi/constructs 0.0.86 → 0.0.87

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/lib/index.mjs CHANGED
@@ -673,13 +673,13 @@ var CognitoUserPoolKmsKey = class extends Key {
673
673
  */
674
674
  CognitoUserPoolKmsKey.SSM_PARAM_NAME = "COGNITO_USER_POOL_KMS_KEY";
675
675
 
676
- // src/components/cognito/pre-token-generation-lambda.ts
676
+ // src/components/cognito/post-authentication-lambda.ts
677
677
  import fs from "fs";
678
678
  import path from "path";
679
679
  import { Runtime } from "aws-cdk-lib/aws-lambda";
680
680
  import { NodejsFunction } from "aws-cdk-lib/aws-lambda-nodejs";
681
681
  import { Construct } from "constructs";
682
- var HANDLER_NAME = "pre-token-generation.handler.js";
682
+ var HANDLER_NAME = "post-authentication.handler.js";
683
683
  function resolveHandlerEntry(dirname) {
684
684
  const sameDir = path.join(dirname, HANDLER_NAME);
685
685
  if (fs.existsSync(sameDir)) {
@@ -688,9 +688,9 @@ function resolveHandlerEntry(dirname) {
688
688
  const fromLib = path.join(dirname, "..", "..", "..", "lib", HANDLER_NAME);
689
689
  return fromLib;
690
690
  }
691
- var PreTokenGenerationLambda = class extends Construct {
691
+ var PostAuthenticationLambda = class extends Construct {
692
692
  constructor(scope) {
693
- super(scope, "pre-token-generation-lambda");
693
+ super(scope, "post-authentication-lambda");
694
694
  this.lambda = new NodejsFunction(this, "handler", {
695
695
  entry: resolveHandlerEntry(__dirname),
696
696
  runtime: Runtime.NODEJS_LATEST,
@@ -699,24 +699,50 @@ var PreTokenGenerationLambda = class extends Construct {
699
699
  }
700
700
  };
701
701
 
702
- // src/components/dynamodb/data-store-historical-archive.ts
702
+ // src/components/cognito/pre-token-generation-lambda.ts
703
703
  import fs2 from "fs";
704
704
  import path2 from "path";
705
- import { Duration as Duration2, RemovalPolicy as RemovalPolicy2, Size } from "aws-cdk-lib";
706
- import * as kinesisfirehose from "aws-cdk-lib/aws-kinesisfirehose";
707
705
  import { Runtime as Runtime2 } from "aws-cdk-lib/aws-lambda";
708
706
  import { NodejsFunction as NodejsFunction2 } from "aws-cdk-lib/aws-lambda-nodejs";
709
- import * as s3 from "aws-cdk-lib/aws-s3";
710
707
  import { Construct as Construct2 } from "constructs";
711
- var HANDLER_NAME2 = "firehose-archive-transform.handler.js";
708
+ var HANDLER_NAME2 = "pre-token-generation.handler.js";
712
709
  function resolveHandlerEntry2(dirname) {
713
710
  const sameDir = path2.join(dirname, HANDLER_NAME2);
714
711
  if (fs2.existsSync(sameDir)) {
715
712
  return sameDir;
716
713
  }
717
- return path2.join(dirname, "..", "..", "..", "lib", HANDLER_NAME2);
714
+ const fromLib = path2.join(dirname, "..", "..", "..", "lib", HANDLER_NAME2);
715
+ return fromLib;
718
716
  }
719
- var DataStoreHistoricalArchive = class extends Construct2 {
717
+ var PreTokenGenerationLambda = class extends Construct2 {
718
+ constructor(scope) {
719
+ super(scope, "pre-token-generation-lambda");
720
+ this.lambda = new NodejsFunction2(this, "handler", {
721
+ entry: resolveHandlerEntry2(__dirname),
722
+ runtime: Runtime2.NODEJS_LATEST,
723
+ memorySize: 1024
724
+ });
725
+ }
726
+ };
727
+
728
+ // src/components/dynamodb/data-store-historical-archive.ts
729
+ import fs3 from "fs";
730
+ import path3 from "path";
731
+ import { Duration as Duration2, RemovalPolicy as RemovalPolicy2, Size } from "aws-cdk-lib";
732
+ import * as kinesisfirehose from "aws-cdk-lib/aws-kinesisfirehose";
733
+ import { Runtime as Runtime3 } from "aws-cdk-lib/aws-lambda";
734
+ import { NodejsFunction as NodejsFunction3 } from "aws-cdk-lib/aws-lambda-nodejs";
735
+ import * as s3 from "aws-cdk-lib/aws-s3";
736
+ import { Construct as Construct3 } from "constructs";
737
+ var HANDLER_NAME3 = "firehose-archive-transform.handler.js";
738
+ function resolveHandlerEntry3(dirname) {
739
+ const sameDir = path3.join(dirname, HANDLER_NAME3);
740
+ if (fs3.existsSync(sameDir)) {
741
+ return sameDir;
742
+ }
743
+ return path3.join(dirname, "..", "..", "..", "lib", HANDLER_NAME3);
744
+ }
745
+ var DataStoreHistoricalArchive = class extends Construct3 {
720
746
  constructor(scope, id, props) {
721
747
  super(scope, id);
722
748
  this.archiveBucket = new s3.Bucket(this, "ArchiveBucket", {
@@ -736,9 +762,9 @@ var DataStoreHistoricalArchive = class extends Construct2 {
736
762
  versioned: false
737
763
  }) : void 0;
738
764
  this.putEventsFailureDlqBucket = putEventsFailureDlqBucket;
739
- this.transformFunction = new NodejsFunction2(this, "FirehoseTransform", {
740
- entry: resolveHandlerEntry2(__dirname),
741
- runtime: Runtime2.NODEJS_LATEST,
765
+ this.transformFunction = new NodejsFunction3(this, "FirehoseTransform", {
766
+ entry: resolveHandlerEntry3(__dirname),
767
+ runtime: Runtime3.NODEJS_LATEST,
742
768
  memorySize: 512,
743
769
  timeout: Duration2.minutes(1),
744
770
  description: "Firehose transform: filter CURRENT resource rows, S3 keys, EventBridge PutEvents",
@@ -909,27 +935,27 @@ var OpsEventBus = class _OpsEventBus extends EventBus2 {
909
935
  };
910
936
 
911
937
  // src/components/postgres/data-store-postgres-replica.ts
912
- import fs3 from "fs";
913
- import path3 from "path";
938
+ import fs4 from "fs";
939
+ import path4 from "path";
914
940
  import { Duration as Duration3, Stack as Stack2 } from "aws-cdk-lib";
915
941
  import * as ec2 from "aws-cdk-lib/aws-ec2";
916
- import { Runtime as Runtime3, StartingPosition } from "aws-cdk-lib/aws-lambda";
942
+ import { Runtime as Runtime4, StartingPosition } from "aws-cdk-lib/aws-lambda";
917
943
  import { KinesisEventSource } from "aws-cdk-lib/aws-lambda-event-sources";
918
- import { NodejsFunction as NodejsFunction3 } from "aws-cdk-lib/aws-lambda-nodejs";
944
+ import { NodejsFunction as NodejsFunction4 } from "aws-cdk-lib/aws-lambda-nodejs";
919
945
  import * as rds from "aws-cdk-lib/aws-rds";
920
- import { Construct as Construct3 } from "constructs";
921
- var HANDLER_NAME3 = "data-store-postgres-replication.handler.js";
946
+ import { Construct as Construct4 } from "constructs";
947
+ var HANDLER_NAME4 = "data-store-postgres-replication.handler.js";
922
948
  var DEFAULT_DATABASE_NAME = "openhi";
923
949
  var SCHEMA_NAME_PATTERN = /^[a-z_][a-z0-9_]{0,62}$/;
924
950
  var POSTGRES_REPLICA_CLUSTER_ARN_SSM_NAME = "POSTGRES_REPLICA_CLUSTER_ARN";
925
951
  var POSTGRES_REPLICA_SECRET_ARN_SSM_NAME = "POSTGRES_REPLICA_SECRET_ARN";
926
952
  var POSTGRES_REPLICA_DATABASE_NAME_SSM_NAME = "POSTGRES_REPLICA_DATABASE_NAME";
927
- function resolveHandlerEntry3(dirname) {
928
- const sameDir = path3.join(dirname, HANDLER_NAME3);
929
- if (fs3.existsSync(sameDir)) {
953
+ function resolveHandlerEntry4(dirname) {
954
+ const sameDir = path4.join(dirname, HANDLER_NAME4);
955
+ if (fs4.existsSync(sameDir)) {
930
956
  return sameDir;
931
957
  }
932
- return path3.join(dirname, "..", "..", "..", "lib", HANDLER_NAME3);
958
+ return path4.join(dirname, "..", "..", "..", "lib", HANDLER_NAME4);
933
959
  }
934
960
  function getPostgresReplicaSchemaName(branchHash) {
935
961
  const candidate = `b_${branchHash.toLowerCase()}`;
@@ -940,7 +966,7 @@ function getPostgresReplicaSchemaName(branchHash) {
940
966
  }
941
967
  return candidate;
942
968
  }
943
- var DataStorePostgresReplica = class extends Construct3 {
969
+ var DataStorePostgresReplica = class extends Construct4 {
944
970
  /**
945
971
  * Resolve the cluster ARN published by an upstream {@link DataStorePostgresReplica}.
946
972
  * Use from any stack that needs to grant `rds-data:ExecuteStatement` against
@@ -1009,9 +1035,9 @@ var DataStorePostgresReplica = class extends Construct3 {
1009
1035
  enableDataApi: true
1010
1036
  });
1011
1037
  this.publishCoordinatesToSsm();
1012
- this.replicationFunction = new NodejsFunction3(this, "ReplicationFunction", {
1013
- entry: resolveHandlerEntry3(__dirname),
1014
- runtime: Runtime3.NODEJS_LATEST,
1038
+ this.replicationFunction = new NodejsFunction4(this, "ReplicationFunction", {
1039
+ entry: resolveHandlerEntry4(__dirname),
1040
+ runtime: Runtime4.NODEJS_LATEST,
1015
1041
  memorySize: 512,
1016
1042
  timeout: Duration3.minutes(1),
1017
1043
  vpc: this.vpc,
@@ -1095,8 +1121,8 @@ var ChildHostedZone = class extends HostedZone {
1095
1121
  ChildHostedZone.SSM_PARAM_NAME = "CHILDHOSTEDZONE";
1096
1122
 
1097
1123
  // src/components/route-53/root-hosted-zone.ts
1098
- import { Construct as Construct4 } from "constructs";
1099
- var RootHostedZone = class extends Construct4 {
1124
+ import { Construct as Construct5 } from "constructs";
1125
+ var RootHostedZone = class extends Construct5 {
1100
1126
  };
1101
1127
 
1102
1128
  // src/components/static-hosting/static-hosting.ts
@@ -1107,9 +1133,9 @@ import {
1107
1133
  import { S3BucketOrigin } from "aws-cdk-lib/aws-cloudfront-origins";
1108
1134
  import { Bucket as Bucket2 } from "aws-cdk-lib/aws-s3";
1109
1135
  import { Duration as Duration5 } from "aws-cdk-lib/core";
1110
- import { Construct as Construct5 } from "constructs";
1136
+ import { Construct as Construct6 } from "constructs";
1111
1137
  var STATIC_HOSTING_SERVICE_TYPE = "website";
1112
- var _StaticHosting = class _StaticHosting extends Construct5 {
1138
+ var _StaticHosting = class _StaticHosting extends Construct6 {
1113
1139
  constructor(scope, id, props = {}) {
1114
1140
  super(scope, id);
1115
1141
  const stack = OpenHiService.of(scope);
@@ -1169,7 +1195,9 @@ import {
1169
1195
  UserPoolDomain as UserPoolDomain2,
1170
1196
  UserPoolOperation
1171
1197
  } from "aws-cdk-lib/aws-cognito";
1198
+ import { PolicyStatement } from "aws-cdk-lib/aws-iam";
1172
1199
  import { Key as Key2 } from "aws-cdk-lib/aws-kms";
1200
+ import { Stack as Stack3 } from "aws-cdk-lib/core";
1173
1201
  var _OpenHiAuthService = class _OpenHiAuthService extends OpenHiService {
1174
1202
  /**
1175
1203
  * Returns an IUserPool by looking up the Auth stack's User Pool ID from SSM.
@@ -1247,7 +1275,9 @@ var _OpenHiAuthService = class _OpenHiAuthService extends OpenHiService {
1247
1275
  this.props = props;
1248
1276
  this.userPoolKmsKey = this.createUserPoolKmsKey();
1249
1277
  this.preTokenGenerationLambda = this.createPreTokenGenerationLambda();
1278
+ this.postAuthenticationLambda = this.createPostAuthenticationLambda();
1250
1279
  this.userPool = this.createUserPool();
1280
+ this.grantPostAuthenticationPermissions();
1251
1281
  this.userPoolClient = this.createUserPoolClient();
1252
1282
  this.userPoolDomain = this.createUserPoolDomain();
1253
1283
  this.fixtureSeederClient = this.createFixtureSeederClient();
@@ -1274,6 +1304,15 @@ var _OpenHiAuthService = class _OpenHiAuthService extends OpenHiService {
1274
1304
  const construct = new PreTokenGenerationLambda(this);
1275
1305
  return construct.lambda;
1276
1306
  }
1307
+ /**
1308
+ * Creates the Post Authentication Lambda (Cognito trigger). Calls
1309
+ * AdminUserGlobalSignOut on every sign-in to enforce single-device-per-user
1310
+ * sessions per ADR 2026-03-17-01.
1311
+ */
1312
+ createPostAuthenticationLambda() {
1313
+ const construct = new PostAuthenticationLambda(this);
1314
+ return construct.lambda;
1315
+ }
1277
1316
  /**
1278
1317
  * Creates the Cognito User Pool and exports its ID to SSM.
1279
1318
  * Look up via {@link OpenHiAuthService.userPoolFromConstruct}.
@@ -1289,6 +1328,10 @@ var _OpenHiAuthService = class _OpenHiAuthService extends OpenHiService {
1289
1328
  this.preTokenGenerationLambda,
1290
1329
  LambdaVersion.V2_0
1291
1330
  );
1331
+ userPool.addTrigger(
1332
+ UserPoolOperation.POST_AUTHENTICATION,
1333
+ this.postAuthenticationLambda
1334
+ );
1292
1335
  new DiscoverableStringParameter(this, "user-pool-param", {
1293
1336
  ssmParamName: CognitoUserPool.SSM_PARAM_NAME,
1294
1337
  stringValue: userPool.userPoolId,
@@ -1296,6 +1339,33 @@ var _OpenHiAuthService = class _OpenHiAuthService extends OpenHiService {
1296
1339
  });
1297
1340
  return userPool;
1298
1341
  }
1342
+ /**
1343
+ * Grants the Post Authentication Lambda permission to call
1344
+ * `cognito-idp:AdminUserGlobalSignOut`.
1345
+ *
1346
+ * Scoped via `Stack.of(this).formatArn` rather than `userPool.userPoolArn`
1347
+ * because the User Pool registers this Lambda as a Post Authentication
1348
+ * trigger, creating the cycle:
1349
+ * userPool → lambda (trigger ARN) → role policy → userPool ARN.
1350
+ * Using `formatArn` avoids referencing the User Pool resource directly
1351
+ * while still scoping to user pools in this account+region. The Lambda
1352
+ * is invoked only by Cognito with a Cognito-provided `event.userPoolId`,
1353
+ * so the runtime target is constrained by the trigger contract.
1354
+ */
1355
+ grantPostAuthenticationPermissions() {
1356
+ this.postAuthenticationLambda.addToRolePolicy(
1357
+ new PolicyStatement({
1358
+ actions: ["cognito-idp:AdminUserGlobalSignOut"],
1359
+ resources: [
1360
+ Stack3.of(this).formatArn({
1361
+ service: "cognito-idp",
1362
+ resource: "userpool",
1363
+ resourceName: "*"
1364
+ })
1365
+ ]
1366
+ })
1367
+ );
1368
+ }
1299
1369
  /**
1300
1370
  * Creates the User Pool Client and exports its ID to SSM (AUTH service type).
1301
1371
  * Look up via {@link OpenHiAuthService.userPoolClientFromConstruct}.
@@ -1480,7 +1550,7 @@ import {
1480
1550
  } from "aws-cdk-lib/aws-apigatewayv2";
1481
1551
  import { HttpUserPoolAuthorizer } from "aws-cdk-lib/aws-apigatewayv2-authorizers";
1482
1552
  import { HttpLambdaIntegration } from "aws-cdk-lib/aws-apigatewayv2-integrations";
1483
- import { Effect, PolicyStatement } from "aws-cdk-lib/aws-iam";
1553
+ import { Effect, PolicyStatement as PolicyStatement2 } from "aws-cdk-lib/aws-iam";
1484
1554
  import {
1485
1555
  ARecord,
1486
1556
  HostedZone as HostedZone3,
@@ -1591,52 +1661,52 @@ _OpenHiDataService.SERVICE_TYPE = "data";
1591
1661
  var OpenHiDataService = _OpenHiDataService;
1592
1662
 
1593
1663
  // src/data/lambda/cors-options-lambda.ts
1594
- import fs4 from "fs";
1595
- import path4 from "path";
1596
- import { Runtime as Runtime4 } from "aws-cdk-lib/aws-lambda";
1597
- import { NodejsFunction as NodejsFunction4 } from "aws-cdk-lib/aws-lambda-nodejs";
1598
- import { Construct as Construct6 } from "constructs";
1599
- var HANDLER_NAME4 = "cors-options-lambda.handler.js";
1600
- function resolveHandlerEntry4(dirname) {
1601
- const sameDir = path4.join(dirname, HANDLER_NAME4);
1602
- if (fs4.existsSync(sameDir)) {
1664
+ import fs5 from "fs";
1665
+ import path5 from "path";
1666
+ import { Runtime as Runtime5 } from "aws-cdk-lib/aws-lambda";
1667
+ import { NodejsFunction as NodejsFunction5 } from "aws-cdk-lib/aws-lambda-nodejs";
1668
+ import { Construct as Construct7 } from "constructs";
1669
+ var HANDLER_NAME5 = "cors-options-lambda.handler.js";
1670
+ function resolveHandlerEntry5(dirname) {
1671
+ const sameDir = path5.join(dirname, HANDLER_NAME5);
1672
+ if (fs5.existsSync(sameDir)) {
1603
1673
  return sameDir;
1604
1674
  }
1605
- const fromLib = path4.join(dirname, "..", "..", "..", "lib", HANDLER_NAME4);
1675
+ const fromLib = path5.join(dirname, "..", "..", "..", "lib", HANDLER_NAME5);
1606
1676
  return fromLib;
1607
1677
  }
1608
- var CorsOptionsLambda = class extends Construct6 {
1678
+ var CorsOptionsLambda = class extends Construct7 {
1609
1679
  constructor(scope, id = "cors-options-lambda") {
1610
1680
  super(scope, id);
1611
- this.lambda = new NodejsFunction4(this, "handler", {
1612
- entry: resolveHandlerEntry4(__dirname),
1613
- runtime: Runtime4.NODEJS_LATEST,
1681
+ this.lambda = new NodejsFunction5(this, "handler", {
1682
+ entry: resolveHandlerEntry5(__dirname),
1683
+ runtime: Runtime5.NODEJS_LATEST,
1614
1684
  memorySize: 128
1615
1685
  });
1616
1686
  }
1617
1687
  };
1618
1688
 
1619
1689
  // src/data/lambda/rest-api-lambda.ts
1620
- import fs5 from "fs";
1621
- import path5 from "path";
1622
- import { Runtime as Runtime5 } from "aws-cdk-lib/aws-lambda";
1623
- import { NodejsFunction as NodejsFunction5 } from "aws-cdk-lib/aws-lambda-nodejs";
1624
- import { Construct as Construct7 } from "constructs";
1625
- var HANDLER_NAME5 = "rest-api-lambda.handler.js";
1626
- function resolveHandlerEntry5(dirname) {
1627
- const sameDir = path5.join(dirname, HANDLER_NAME5);
1628
- if (fs5.existsSync(sameDir)) {
1690
+ import fs6 from "fs";
1691
+ import path6 from "path";
1692
+ import { Runtime as Runtime6 } from "aws-cdk-lib/aws-lambda";
1693
+ import { NodejsFunction as NodejsFunction6 } from "aws-cdk-lib/aws-lambda-nodejs";
1694
+ import { Construct as Construct8 } from "constructs";
1695
+ var HANDLER_NAME6 = "rest-api-lambda.handler.js";
1696
+ function resolveHandlerEntry6(dirname) {
1697
+ const sameDir = path6.join(dirname, HANDLER_NAME6);
1698
+ if (fs6.existsSync(sameDir)) {
1629
1699
  return sameDir;
1630
1700
  }
1631
- const fromLib = path5.join(dirname, "..", "..", "..", "lib", HANDLER_NAME5);
1701
+ const fromLib = path6.join(dirname, "..", "..", "..", "lib", HANDLER_NAME6);
1632
1702
  return fromLib;
1633
1703
  }
1634
- var RestApiLambda = class extends Construct7 {
1704
+ var RestApiLambda = class extends Construct8 {
1635
1705
  constructor(scope, props) {
1636
1706
  super(scope, "rest-api-lambda");
1637
- this.lambda = new NodejsFunction5(this, "handler", {
1638
- entry: resolveHandlerEntry5(__dirname),
1639
- runtime: Runtime5.NODEJS_LATEST,
1707
+ this.lambda = new NodejsFunction6(this, "handler", {
1708
+ entry: resolveHandlerEntry6(__dirname),
1709
+ runtime: Runtime6.NODEJS_LATEST,
1640
1710
  memorySize: 1024,
1641
1711
  environment: {
1642
1712
  DYNAMO_TABLE_NAME: props.dynamoTableName,
@@ -1778,7 +1848,7 @@ var _OpenHiRestApiService = class _OpenHiRestApiService extends OpenHiService {
1778
1848
  postgresSchema
1779
1849
  });
1780
1850
  lambda.addToRolePolicy(
1781
- new PolicyStatement({
1851
+ new PolicyStatement2({
1782
1852
  effect: Effect.ALLOW,
1783
1853
  actions: [
1784
1854
  "rds-data:ExecuteStatement",
@@ -1788,7 +1858,7 @@ var _OpenHiRestApiService = class _OpenHiRestApiService extends OpenHiService {
1788
1858
  })
1789
1859
  );
1790
1860
  lambda.addToRolePolicy(
1791
- new PolicyStatement({
1861
+ new PolicyStatement2({
1792
1862
  effect: Effect.ALLOW,
1793
1863
  actions: ["secretsmanager:GetSecretValue"],
1794
1864
  resources: [postgresSecretArn]
@@ -1807,14 +1877,14 @@ var _OpenHiRestApiService = class _OpenHiRestApiService extends OpenHiService {
1807
1877
  ];
1808
1878
  dataStoreTable.grant(lambda, ...dynamoActions);
1809
1879
  lambda.addToRolePolicy(
1810
- new PolicyStatement({
1880
+ new PolicyStatement2({
1811
1881
  effect: Effect.ALLOW,
1812
1882
  actions: [...dynamoActions],
1813
1883
  resources: [`${dataStoreTable.tableArn}/index/*`]
1814
1884
  })
1815
1885
  );
1816
1886
  lambda.addToRolePolicy(
1817
- new PolicyStatement({
1887
+ new PolicyStatement2({
1818
1888
  effect: Effect.ALLOW,
1819
1889
  actions: [
1820
1890
  "ssm:GetParameter",
@@ -1993,6 +2063,7 @@ export {
1993
2063
  POSTGRES_REPLICA_CLUSTER_ARN_SSM_NAME,
1994
2064
  POSTGRES_REPLICA_DATABASE_NAME_SSM_NAME,
1995
2065
  POSTGRES_REPLICA_SECRET_ARN_SSM_NAME,
2066
+ PostAuthenticationLambda,
1996
2067
  PreTokenGenerationLambda,
1997
2068
  REST_API_BASE_URL_SSM_NAME,
1998
2069
  RootGraphqlApi,