@openhi/constructs 0.0.85 → 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.
Files changed (34) hide show
  1. package/lib/{chunk-SWSN6GDD.mjs → chunk-CEOAGPYY.mjs} +1 -5
  2. package/lib/chunk-CEOAGPYY.mjs.map +1 -0
  3. package/lib/chunk-X5MHU7DA.mjs +298 -0
  4. package/lib/chunk-X5MHU7DA.mjs.map +1 -0
  5. package/lib/data-store-postgres-replication.handler.d.mts +55 -0
  6. package/lib/data-store-postgres-replication.handler.d.ts +55 -0
  7. package/lib/data-store-postgres-replication.handler.js +448 -0
  8. package/lib/data-store-postgres-replication.handler.js.map +1 -0
  9. package/lib/data-store-postgres-replication.handler.mjs +313 -0
  10. package/lib/data-store-postgres-replication.handler.mjs.map +1 -0
  11. package/lib/firehose-archive-transform.handler.js +0 -4
  12. package/lib/firehose-archive-transform.handler.js.map +1 -1
  13. package/lib/firehose-archive-transform.handler.mjs +5 -290
  14. package/lib/firehose-archive-transform.handler.mjs.map +1 -1
  15. package/lib/index.d.mts +230 -5
  16. package/lib/index.d.ts +231 -6
  17. package/lib/index.js +489 -117
  18. package/lib/index.js.map +1 -1
  19. package/lib/index.mjs +468 -97
  20. package/lib/index.mjs.map +1 -1
  21. package/lib/post-authentication.handler.d.mts +5 -0
  22. package/lib/post-authentication.handler.d.ts +5 -0
  23. package/lib/post-authentication.handler.js +45 -0
  24. package/lib/post-authentication.handler.js.map +1 -0
  25. package/lib/post-authentication.handler.mjs +25 -0
  26. package/lib/post-authentication.handler.mjs.map +1 -0
  27. package/lib/rest-api-lambda.handler.js +636 -153
  28. package/lib/rest-api-lambda.handler.js.map +1 -1
  29. package/lib/rest-api-lambda.handler.mjs +639 -153
  30. package/lib/rest-api-lambda.handler.mjs.map +1 -1
  31. package/package.json +20 -11
  32. package/scripts/generate-operations.js +2 -2
  33. package/scripts/generate-routes.js +1 -1
  34. package/lib/chunk-SWSN6GDD.mjs.map +0 -1
package/lib/index.js CHANGED
@@ -94,6 +94,7 @@ var require_lib = __commonJS({
94
94
  var src_exports = {};
95
95
  __export(src_exports, {
96
96
  ChildHostedZone: () => ChildHostedZone,
97
+ CognitoFixtureSeederClient: () => CognitoFixtureSeederClient,
97
98
  CognitoUserPool: () => CognitoUserPool,
98
99
  CognitoUserPoolClient: () => CognitoUserPoolClient,
99
100
  CognitoUserPoolDomain: () => CognitoUserPoolDomain,
@@ -103,6 +104,7 @@ __export(src_exports, {
103
104
  DATA_STORE_CHANGE_EVENT_SOURCE: () => DATA_STORE_CHANGE_EVENT_SOURCE,
104
105
  DataEventBus: () => DataEventBus,
105
106
  DataStoreHistoricalArchive: () => DataStoreHistoricalArchive,
107
+ DataStorePostgresReplica: () => DataStorePostgresReplica,
106
108
  DiscoverableStringParameter: () => DiscoverableStringParameter,
107
109
  DynamoDbDataStore: () => DynamoDbDataStore,
108
110
  OpenHiApp: () => OpenHiApp,
@@ -115,6 +117,10 @@ __export(src_exports, {
115
117
  OpenHiService: () => OpenHiService,
116
118
  OpenHiStage: () => OpenHiStage,
117
119
  OpsEventBus: () => OpsEventBus,
120
+ POSTGRES_REPLICA_CLUSTER_ARN_SSM_NAME: () => POSTGRES_REPLICA_CLUSTER_ARN_SSM_NAME,
121
+ POSTGRES_REPLICA_DATABASE_NAME_SSM_NAME: () => POSTGRES_REPLICA_DATABASE_NAME_SSM_NAME,
122
+ POSTGRES_REPLICA_SECRET_ARN_SSM_NAME: () => POSTGRES_REPLICA_SECRET_ARN_SSM_NAME,
123
+ PostAuthenticationLambda: () => PostAuthenticationLambda,
118
124
  PreTokenGenerationLambda: () => PreTokenGenerationLambda,
119
125
  REST_API_BASE_URL_SSM_NAME: () => REST_API_BASE_URL_SSM_NAME,
120
126
  RootGraphqlApi: () => RootGraphqlApi,
@@ -124,7 +130,8 @@ __export(src_exports, {
124
130
  STATIC_HOSTING_SERVICE_TYPE: () => STATIC_HOSTING_SERVICE_TYPE,
125
131
  StaticHosting: () => StaticHosting,
126
132
  buildFhirCurrentResourceChangeDetail: () => buildFhirCurrentResourceChangeDetail,
127
- getDynamoDbDataStoreTableName: () => getDynamoDbDataStoreTableName
133
+ getDynamoDbDataStoreTableName: () => getDynamoDbDataStoreTableName,
134
+ getPostgresReplicaSchemaName: () => getPostgresReplicaSchemaName
128
135
  });
129
136
  module.exports = __toCommonJS(src_exports);
130
137
 
@@ -402,6 +409,10 @@ var OpenHiService = class extends import_aws_cdk_lib4.Stack {
402
409
  this.environmentHash = environmentHash;
403
410
  this.branchHash = branchHash;
404
411
  this.stackHash = stackHash;
412
+ this.node.setContext(
413
+ `availability-zones:account=${account}:region=${region}`,
414
+ [`${region}a`, `${region}b`, `${region}c`]
415
+ );
405
416
  import_aws_cdk_lib4.Tags.of(this).add(`${appName}:repo-name`, repoName.slice(0, 255));
406
417
  import_aws_cdk_lib4.Tags.of(this).add(`${appName}:branch-name`, branchName.slice(0, 255));
407
418
  import_aws_cdk_lib4.Tags.of(this).add(`${appName}:service-type`, id.slice(0, 255));
@@ -578,9 +589,47 @@ var _RootGraphqlApi = class _RootGraphqlApi extends import_aws_appsync.GraphqlAp
578
589
  _RootGraphqlApi.SSM_PARAM_NAME = "ROOT_GRAPHQL_API";
579
590
  var RootGraphqlApi = _RootGraphqlApi;
580
591
 
581
- // src/components/cognito/cognito-user-pool.ts
592
+ // src/components/cognito/cognito-fixture-seeder-client.ts
593
+ var import_aws_cdk_lib6 = require("aws-cdk-lib");
582
594
  var import_aws_cognito = require("aws-cdk-lib/aws-cognito");
583
- var CognitoUserPool = class extends import_aws_cognito.UserPool {
595
+ var CognitoFixtureSeederClient = class extends import_aws_cognito.UserPoolClient {
596
+ constructor(scope, props) {
597
+ const { userPool, ...rest } = props;
598
+ super(scope, "fixture-seeder-client", {
599
+ userPool,
600
+ generateSecret: false,
601
+ authFlows: {
602
+ userPassword: true
603
+ },
604
+ // No OAuth flows — the seeder calls Cognito's `InitiateAuth`
605
+ // directly with USER_PASSWORD_AUTH, not through the hosted-UI
606
+ // OAuth grant flows the SPA client uses. `disableOAuth: true`
607
+ // causes CDK to omit `AllowedOAuthFlowsUserPoolClient` entirely;
608
+ // passing an empty `oAuth` block instead still flips that flag on
609
+ // and Cognito rejects the create call for missing flows/scopes.
610
+ disableOAuth: true,
611
+ // Short-lived tokens: a seeder run takes seconds, not hours.
612
+ // 1h access-token validity is the minimum Cognito permits and is
613
+ // plenty for a fixture run.
614
+ accessTokenValidity: import_aws_cdk_lib6.Duration.hours(1),
615
+ idTokenValidity: import_aws_cdk_lib6.Duration.hours(1),
616
+ refreshTokenValidity: import_aws_cdk_lib6.Duration.days(1),
617
+ preventUserExistenceErrors: true,
618
+ ...rest
619
+ });
620
+ }
621
+ };
622
+ /**
623
+ * SSM parameter name suffix used to publish this client's ID for
624
+ * cross-stack lookups. Built into a full parameter name via
625
+ * `buildParameterName` with `serviceType` AUTH (since the auth stack
626
+ * owns this resource).
627
+ */
628
+ CognitoFixtureSeederClient.SSM_PARAM_NAME = "COGNITO_FIXTURE_SEEDER_CLIENT";
629
+
630
+ // src/components/cognito/cognito-user-pool.ts
631
+ var import_aws_cognito2 = require("aws-cdk-lib/aws-cognito");
632
+ var CognitoUserPool = class extends import_aws_cognito2.UserPool {
584
633
  constructor(scope, props = {}) {
585
634
  const service = OpenHiService.of(scope);
586
635
  super(scope, "user-pool", {
@@ -594,7 +643,7 @@ var CognitoUserPool = class extends import_aws_cognito.UserPool {
594
643
  userVerification: {
595
644
  emailSubject: "Verify your email!",
596
645
  emailBody: "Your verification code is {####}.",
597
- emailStyle: import_aws_cognito.VerificationEmailStyle.CODE
646
+ emailStyle: import_aws_cognito2.VerificationEmailStyle.CODE
598
647
  },
599
648
  removalPolicy: props.removalPolicy ?? service.removalPolicy,
600
649
  /**
@@ -614,8 +663,8 @@ var CognitoUserPool = class extends import_aws_cognito.UserPool {
614
663
  CognitoUserPool.SSM_PARAM_NAME = "COGNITO_USER_POOL";
615
664
 
616
665
  // src/components/cognito/cognito-user-pool-client.ts
617
- var import_aws_cognito2 = require("aws-cdk-lib/aws-cognito");
618
- var CognitoUserPoolClient = class extends import_aws_cognito2.UserPoolClient {
666
+ var import_aws_cognito3 = require("aws-cdk-lib/aws-cognito");
667
+ var CognitoUserPoolClient = class extends import_aws_cognito3.UserPoolClient {
619
668
  constructor(scope, props) {
620
669
  super(scope, "user-pool-client", {
621
670
  /**
@@ -642,8 +691,8 @@ var CognitoUserPoolClient = class extends import_aws_cognito2.UserPoolClient {
642
691
  CognitoUserPoolClient.SSM_PARAM_NAME = "COGNITO_USER_POOL_CLIENT";
643
692
 
644
693
  // src/components/cognito/cognito-user-pool-domain.ts
645
- var import_aws_cognito3 = require("aws-cdk-lib/aws-cognito");
646
- var CognitoUserPoolDomain = class extends import_aws_cognito3.UserPoolDomain {
694
+ var import_aws_cognito4 = require("aws-cdk-lib/aws-cognito");
695
+ var CognitoUserPoolDomain = class extends import_aws_cognito4.UserPoolDomain {
647
696
  constructor(scope, props) {
648
697
  const id = props.cognitoDomain?.domainPrefix ? "cognito-domain" : "custom-domain";
649
698
  super(scope, id, {
@@ -674,13 +723,13 @@ var CognitoUserPoolKmsKey = class extends import_aws_kms.Key {
674
723
  */
675
724
  CognitoUserPoolKmsKey.SSM_PARAM_NAME = "COGNITO_USER_POOL_KMS_KEY";
676
725
 
677
- // src/components/cognito/pre-token-generation-lambda.ts
726
+ // src/components/cognito/post-authentication-lambda.ts
678
727
  var import_node_fs = __toESM(require("fs"));
679
728
  var import_node_path = __toESM(require("path"));
680
729
  var import_aws_lambda = require("aws-cdk-lib/aws-lambda");
681
730
  var import_aws_lambda_nodejs = require("aws-cdk-lib/aws-lambda-nodejs");
682
731
  var import_constructs = require("constructs");
683
- var HANDLER_NAME = "pre-token-generation.handler.js";
732
+ var HANDLER_NAME = "post-authentication.handler.js";
684
733
  function resolveHandlerEntry(dirname) {
685
734
  const sameDir = import_node_path.default.join(dirname, HANDLER_NAME);
686
735
  if (import_node_fs.default.existsSync(sameDir)) {
@@ -689,9 +738,9 @@ function resolveHandlerEntry(dirname) {
689
738
  const fromLib = import_node_path.default.join(dirname, "..", "..", "..", "lib", HANDLER_NAME);
690
739
  return fromLib;
691
740
  }
692
- var PreTokenGenerationLambda = class extends import_constructs.Construct {
741
+ var PostAuthenticationLambda = class extends import_constructs.Construct {
693
742
  constructor(scope) {
694
- super(scope, "pre-token-generation-lambda");
743
+ super(scope, "post-authentication-lambda");
695
744
  this.lambda = new import_aws_lambda_nodejs.NodejsFunction(this, "handler", {
696
745
  entry: resolveHandlerEntry(__dirname),
697
746
  runtime: import_aws_lambda.Runtime.NODEJS_LATEST,
@@ -700,6 +749,32 @@ var PreTokenGenerationLambda = class extends import_constructs.Construct {
700
749
  }
701
750
  };
702
751
 
752
+ // src/components/cognito/pre-token-generation-lambda.ts
753
+ var import_node_fs2 = __toESM(require("fs"));
754
+ var import_node_path2 = __toESM(require("path"));
755
+ var import_aws_lambda2 = require("aws-cdk-lib/aws-lambda");
756
+ var import_aws_lambda_nodejs2 = require("aws-cdk-lib/aws-lambda-nodejs");
757
+ var import_constructs2 = require("constructs");
758
+ var HANDLER_NAME2 = "pre-token-generation.handler.js";
759
+ function resolveHandlerEntry2(dirname) {
760
+ const sameDir = import_node_path2.default.join(dirname, HANDLER_NAME2);
761
+ if (import_node_fs2.default.existsSync(sameDir)) {
762
+ return sameDir;
763
+ }
764
+ const fromLib = import_node_path2.default.join(dirname, "..", "..", "..", "lib", HANDLER_NAME2);
765
+ return fromLib;
766
+ }
767
+ var PreTokenGenerationLambda = class extends import_constructs2.Construct {
768
+ constructor(scope) {
769
+ super(scope, "pre-token-generation-lambda");
770
+ this.lambda = new import_aws_lambda_nodejs2.NodejsFunction(this, "handler", {
771
+ entry: resolveHandlerEntry2(__dirname),
772
+ runtime: import_aws_lambda2.Runtime.NODEJS_LATEST,
773
+ memorySize: 1024
774
+ });
775
+ }
776
+ };
777
+
703
778
  // src/components/dynamodb/dynamodb-stream-record.ts
704
779
  function dynamodbValueToJs(av) {
705
780
  if (av.S !== void 0) {
@@ -749,10 +824,6 @@ var EXCLUDED_CHANGE_DETAIL_KEYS = /* @__PURE__ */ new Set([
749
824
  "GSI1SK",
750
825
  "GSI2PK",
751
826
  "GSI2SK",
752
- "GSI3PK",
753
- "GSI3SK",
754
- "GSI4PK",
755
- "GSI4SK",
756
827
  /** Full FHIR JSON may contain PII; never list or ship in the bus payload. */
757
828
  "resource"
758
829
  ]);
@@ -826,23 +897,23 @@ function buildFhirCurrentResourceChangeDetail(record, keys) {
826
897
  }
827
898
 
828
899
  // src/components/dynamodb/data-store-historical-archive.ts
829
- var import_node_fs2 = __toESM(require("fs"));
830
- var import_node_path2 = __toESM(require("path"));
831
- var import_aws_cdk_lib6 = require("aws-cdk-lib");
900
+ var import_node_fs3 = __toESM(require("fs"));
901
+ var import_node_path3 = __toESM(require("path"));
902
+ var import_aws_cdk_lib7 = require("aws-cdk-lib");
832
903
  var kinesisfirehose = __toESM(require("aws-cdk-lib/aws-kinesisfirehose"));
833
- var import_aws_lambda2 = require("aws-cdk-lib/aws-lambda");
834
- var import_aws_lambda_nodejs2 = require("aws-cdk-lib/aws-lambda-nodejs");
904
+ var import_aws_lambda3 = require("aws-cdk-lib/aws-lambda");
905
+ var import_aws_lambda_nodejs3 = require("aws-cdk-lib/aws-lambda-nodejs");
835
906
  var s3 = __toESM(require("aws-cdk-lib/aws-s3"));
836
- var import_constructs2 = require("constructs");
837
- var HANDLER_NAME2 = "firehose-archive-transform.handler.js";
838
- function resolveHandlerEntry2(dirname) {
839
- const sameDir = import_node_path2.default.join(dirname, HANDLER_NAME2);
840
- if (import_node_fs2.default.existsSync(sameDir)) {
907
+ var import_constructs3 = require("constructs");
908
+ var HANDLER_NAME3 = "firehose-archive-transform.handler.js";
909
+ function resolveHandlerEntry3(dirname) {
910
+ const sameDir = import_node_path3.default.join(dirname, HANDLER_NAME3);
911
+ if (import_node_fs3.default.existsSync(sameDir)) {
841
912
  return sameDir;
842
913
  }
843
- return import_node_path2.default.join(dirname, "..", "..", "..", "lib", HANDLER_NAME2);
914
+ return import_node_path3.default.join(dirname, "..", "..", "..", "lib", HANDLER_NAME3);
844
915
  }
845
- var DataStoreHistoricalArchive = class extends import_constructs2.Construct {
916
+ var DataStoreHistoricalArchive = class extends import_constructs3.Construct {
846
917
  constructor(scope, id, props) {
847
918
  super(scope, id);
848
919
  this.archiveBucket = new s3.Bucket(this, "ArchiveBucket", {
@@ -850,7 +921,7 @@ var DataStoreHistoricalArchive = class extends import_constructs2.Construct {
850
921
  encryption: s3.BucketEncryption.S3_MANAGED,
851
922
  enforceSSL: true,
852
923
  removalPolicy: props.removalPolicy,
853
- autoDeleteObjects: props.removalPolicy === import_aws_cdk_lib6.RemovalPolicy.DESTROY,
924
+ autoDeleteObjects: props.removalPolicy === import_aws_cdk_lib7.RemovalPolicy.DESTROY,
854
925
  versioned: true
855
926
  });
856
927
  const putEventsFailureDlqBucket = props.dataEventBus ? new s3.Bucket(this, "PutEventsFailureDlq", {
@@ -858,15 +929,15 @@ var DataStoreHistoricalArchive = class extends import_constructs2.Construct {
858
929
  encryption: s3.BucketEncryption.S3_MANAGED,
859
930
  enforceSSL: true,
860
931
  removalPolicy: props.removalPolicy,
861
- autoDeleteObjects: props.removalPolicy === import_aws_cdk_lib6.RemovalPolicy.DESTROY,
932
+ autoDeleteObjects: props.removalPolicy === import_aws_cdk_lib7.RemovalPolicy.DESTROY,
862
933
  versioned: false
863
934
  }) : void 0;
864
935
  this.putEventsFailureDlqBucket = putEventsFailureDlqBucket;
865
- this.transformFunction = new import_aws_lambda_nodejs2.NodejsFunction(this, "FirehoseTransform", {
866
- entry: resolveHandlerEntry2(__dirname),
867
- runtime: import_aws_lambda2.Runtime.NODEJS_LATEST,
936
+ this.transformFunction = new import_aws_lambda_nodejs3.NodejsFunction(this, "FirehoseTransform", {
937
+ entry: resolveHandlerEntry3(__dirname),
938
+ runtime: import_aws_lambda3.Runtime.NODEJS_LATEST,
868
939
  memorySize: 512,
869
- timeout: import_aws_cdk_lib6.Duration.minutes(1),
940
+ timeout: import_aws_cdk_lib7.Duration.minutes(1),
870
941
  description: "Firehose transform: filter CURRENT resource rows, S3 keys, EventBridge PutEvents",
871
942
  environment: props.dataEventBus && putEventsFailureDlqBucket ? {
872
943
  DATA_EVENT_BUS_NAME: props.dataEventBus.eventBusName,
@@ -882,16 +953,16 @@ var DataStoreHistoricalArchive = class extends import_constructs2.Construct {
882
953
  const processor = new kinesisfirehose.LambdaFunctionProcessor(
883
954
  this.transformFunction,
884
955
  {
885
- bufferInterval: import_aws_cdk_lib6.Duration.seconds(60),
886
- bufferSize: import_aws_cdk_lib6.Size.mebibytes(3),
956
+ bufferInterval: import_aws_cdk_lib7.Duration.seconds(60),
957
+ bufferSize: import_aws_cdk_lib7.Size.mebibytes(3),
887
958
  retries: 3
888
959
  }
889
960
  );
890
961
  const destination = new kinesisfirehose.S3Bucket(this.archiveBucket, {
891
962
  compression: kinesisfirehose.Compression.GZIP,
892
- bufferingInterval: import_aws_cdk_lib6.Duration.seconds(300),
963
+ bufferingInterval: import_aws_cdk_lib7.Duration.seconds(300),
893
964
  // Firehose requires SizeInMBs ≥ 64 when dynamic partitioning is enabled.
894
- bufferingSize: import_aws_cdk_lib6.Size.mebibytes(64),
965
+ bufferingSize: import_aws_cdk_lib7.Size.mebibytes(64),
895
966
  processors: [processor],
896
967
  errorOutputPrefix: "errors/!{firehose:error-output-type}/!{timestamp:yyyy/MM/dd/HH}/",
897
968
  loggingConfig: new kinesisfirehose.EnableLogging()
@@ -954,7 +1025,15 @@ var DynamoDbDataStore = class extends import_aws_dynamodb.Table {
954
1025
  type: import_aws_dynamodb.AttributeType.STRING
955
1026
  },
956
1027
  projectionType: import_aws_dynamodb.ProjectionType.INCLUDE,
957
- nonKeyAttributes: ["srcType", "srcId", "path", "srcPk", "srcSk", "ts"]
1028
+ nonKeyAttributes: [
1029
+ "summary",
1030
+ "vid",
1031
+ "lastUpdated",
1032
+ "createdDate",
1033
+ "modifiedDate",
1034
+ "createdById",
1035
+ "modifiedById"
1036
+ ]
958
1037
  });
959
1038
  this.addGlobalSecondaryIndex({
960
1039
  indexName: "GSI2",
@@ -967,32 +1046,12 @@ var DynamoDbDataStore = class extends import_aws_dynamodb.Table {
967
1046
  type: import_aws_dynamodb.AttributeType.STRING
968
1047
  },
969
1048
  projectionType: import_aws_dynamodb.ProjectionType.INCLUDE,
970
- nonKeyAttributes: ["resourcePk", "resourceSk", "display", "status"]
971
- });
972
- this.addGlobalSecondaryIndex({
973
- indexName: "GSI3",
974
- partitionKey: {
975
- name: "GSI3PK",
976
- type: import_aws_dynamodb.AttributeType.STRING
977
- },
978
- sortKey: {
979
- name: "GSI3SK",
980
- type: import_aws_dynamodb.AttributeType.STRING
981
- },
982
- projectionType: import_aws_dynamodb.ProjectionType.INCLUDE,
983
- nonKeyAttributes: ["resourcePk", "resourceSk"]
984
- });
985
- this.addGlobalSecondaryIndex({
986
- indexName: "GSI4",
987
- partitionKey: {
988
- name: "GSI4PK",
989
- type: import_aws_dynamodb.AttributeType.STRING
990
- },
991
- sortKey: {
992
- name: "GSI4SK",
993
- type: import_aws_dynamodb.AttributeType.STRING
994
- },
995
- projectionType: import_aws_dynamodb.ProjectionType.ALL
1049
+ nonKeyAttributes: [
1050
+ "id",
1051
+ "currentTenant",
1052
+ "currentWorkspace",
1053
+ "displayName"
1054
+ ]
996
1055
  });
997
1056
  }
998
1057
  };
@@ -1041,8 +1100,172 @@ var OpsEventBus = class _OpsEventBus extends import_aws_events2.EventBus {
1041
1100
  }
1042
1101
  };
1043
1102
 
1103
+ // src/components/postgres/data-store-postgres-replica.ts
1104
+ var import_node_fs4 = __toESM(require("fs"));
1105
+ var import_node_path4 = __toESM(require("path"));
1106
+ var import_aws_cdk_lib8 = require("aws-cdk-lib");
1107
+ var ec2 = __toESM(require("aws-cdk-lib/aws-ec2"));
1108
+ var import_aws_lambda4 = require("aws-cdk-lib/aws-lambda");
1109
+ var import_aws_lambda_event_sources = require("aws-cdk-lib/aws-lambda-event-sources");
1110
+ var import_aws_lambda_nodejs4 = require("aws-cdk-lib/aws-lambda-nodejs");
1111
+ var rds = __toESM(require("aws-cdk-lib/aws-rds"));
1112
+ var import_constructs4 = require("constructs");
1113
+ var HANDLER_NAME4 = "data-store-postgres-replication.handler.js";
1114
+ var DEFAULT_DATABASE_NAME = "openhi";
1115
+ var SCHEMA_NAME_PATTERN = /^[a-z_][a-z0-9_]{0,62}$/;
1116
+ var POSTGRES_REPLICA_CLUSTER_ARN_SSM_NAME = "POSTGRES_REPLICA_CLUSTER_ARN";
1117
+ var POSTGRES_REPLICA_SECRET_ARN_SSM_NAME = "POSTGRES_REPLICA_SECRET_ARN";
1118
+ var POSTGRES_REPLICA_DATABASE_NAME_SSM_NAME = "POSTGRES_REPLICA_DATABASE_NAME";
1119
+ function resolveHandlerEntry4(dirname) {
1120
+ const sameDir = import_node_path4.default.join(dirname, HANDLER_NAME4);
1121
+ if (import_node_fs4.default.existsSync(sameDir)) {
1122
+ return sameDir;
1123
+ }
1124
+ return import_node_path4.default.join(dirname, "..", "..", "..", "lib", HANDLER_NAME4);
1125
+ }
1126
+ function getPostgresReplicaSchemaName(branchHash) {
1127
+ const candidate = `b_${branchHash.toLowerCase()}`;
1128
+ if (!SCHEMA_NAME_PATTERN.test(candidate)) {
1129
+ throw new Error(
1130
+ `Branch hash ${JSON.stringify(branchHash)} produces an invalid Postgres schema name ${JSON.stringify(candidate)}; expected /[a-z_][a-z0-9_]{0,62}/.`
1131
+ );
1132
+ }
1133
+ return candidate;
1134
+ }
1135
+ var DataStorePostgresReplica = class extends import_constructs4.Construct {
1136
+ /**
1137
+ * Resolve the cluster ARN published by an upstream {@link DataStorePostgresReplica}.
1138
+ * Use from any stack that needs to grant `rds-data:ExecuteStatement` against
1139
+ * the cluster.
1140
+ */
1141
+ static clusterArnFromConstruct(scope) {
1142
+ return DiscoverableStringParameter.valueForLookupName(scope, {
1143
+ ssmParamName: POSTGRES_REPLICA_CLUSTER_ARN_SSM_NAME,
1144
+ serviceType: "data"
1145
+ });
1146
+ }
1147
+ /**
1148
+ * Resolve the credentials secret ARN published by an upstream
1149
+ * {@link DataStorePostgresReplica}. Use from any stack that needs to grant
1150
+ * `secretsmanager:GetSecretValue` against the secret.
1151
+ */
1152
+ static secretArnFromConstruct(scope) {
1153
+ return DiscoverableStringParameter.valueForLookupName(scope, {
1154
+ ssmParamName: POSTGRES_REPLICA_SECRET_ARN_SSM_NAME,
1155
+ serviceType: "data"
1156
+ });
1157
+ }
1158
+ /**
1159
+ * Resolve the database name published by an upstream
1160
+ * {@link DataStorePostgresReplica}.
1161
+ */
1162
+ static databaseNameFromConstruct(scope) {
1163
+ return DiscoverableStringParameter.valueForLookupName(scope, {
1164
+ ssmParamName: POSTGRES_REPLICA_DATABASE_NAME_SSM_NAME,
1165
+ serviceType: "data"
1166
+ });
1167
+ }
1168
+ constructor(scope, id, props) {
1169
+ super(scope, id);
1170
+ this.databaseName = props.databaseName ?? DEFAULT_DATABASE_NAME;
1171
+ this.schemaName = getPostgresReplicaSchemaName(props.branchHash);
1172
+ const region = import_aws_cdk_lib8.Stack.of(this).region;
1173
+ this.vpc = props.vpc ?? new ec2.Vpc(this, "Vpc", {
1174
+ availabilityZones: [`${region}a`, `${region}b`],
1175
+ natGateways: 0,
1176
+ subnetConfiguration: [
1177
+ {
1178
+ name: "isolated",
1179
+ subnetType: ec2.SubnetType.PRIVATE_ISOLATED,
1180
+ cidrMask: 24
1181
+ }
1182
+ ]
1183
+ });
1184
+ this.cluster = new rds.DatabaseCluster(this, "Cluster", {
1185
+ clusterIdentifier: `openhi-dstore-pg-${props.stackHash}`,
1186
+ engine: rds.DatabaseClusterEngine.auroraPostgres({
1187
+ version: rds.AuroraPostgresEngineVersion.VER_16_4
1188
+ }),
1189
+ vpc: this.vpc,
1190
+ vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED },
1191
+ writer: rds.ClusterInstance.serverlessV2("writer"),
1192
+ serverlessV2MinCapacity: props.minCapacity ?? 1,
1193
+ serverlessV2MaxCapacity: props.maxCapacity ?? 2,
1194
+ defaultDatabaseName: this.databaseName,
1195
+ credentials: rds.Credentials.fromGeneratedSecret("openhi_admin"),
1196
+ storageEncrypted: true,
1197
+ removalPolicy: props.removalPolicy,
1198
+ // Phase 2 of ADR 2026-04-17-01: the REST API Lambda queries Postgres
1199
+ // via the RDS Data API (HTTPS) so it can stay out of the cluster's VPC.
1200
+ // Direct `pg` from the replication Lambda continues to work in parallel.
1201
+ enableDataApi: true
1202
+ });
1203
+ this.publishCoordinatesToSsm();
1204
+ this.replicationFunction = new import_aws_lambda_nodejs4.NodejsFunction(this, "ReplicationFunction", {
1205
+ entry: resolveHandlerEntry4(__dirname),
1206
+ runtime: import_aws_lambda4.Runtime.NODEJS_LATEST,
1207
+ memorySize: 512,
1208
+ timeout: import_aws_cdk_lib8.Duration.minutes(1),
1209
+ vpc: this.vpc,
1210
+ vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED },
1211
+ description: "Replicates DynamoDB current-resource changes into the Postgres `resources` JSONB table (ADR 2026-04-17-01).",
1212
+ environment: {
1213
+ OPENHI_PG_HOST: this.cluster.clusterEndpoint.hostname,
1214
+ OPENHI_PG_PORT: this.cluster.clusterEndpoint.port.toString(),
1215
+ OPENHI_PG_DATABASE: this.databaseName,
1216
+ OPENHI_PG_SCHEMA: this.schemaName,
1217
+ OPENHI_PG_SECRET_ARN: this.cluster.secret.secretArn,
1218
+ OPENHI_PG_SSL: "true"
1219
+ },
1220
+ bundling: {
1221
+ minify: true,
1222
+ sourceMap: false,
1223
+ // pg has conditional/optional deps (pg-native, pg-cloudflare) that
1224
+ // historically misbehave when bundled by esbuild; keep it as a real
1225
+ // node_module in the Lambda zip instead.
1226
+ nodeModules: ["pg"]
1227
+ }
1228
+ });
1229
+ this.cluster.secret.grantRead(this.replicationFunction);
1230
+ this.cluster.connections.allowDefaultPortFrom(this.replicationFunction);
1231
+ this.replicationFunction.addEventSource(
1232
+ new import_aws_lambda_event_sources.KinesisEventSource(props.kinesisStream, {
1233
+ startingPosition: import_aws_lambda4.StartingPosition.LATEST,
1234
+ batchSize: 100,
1235
+ maxBatchingWindow: import_aws_cdk_lib8.Duration.seconds(5),
1236
+ retryAttempts: 10,
1237
+ bisectBatchOnError: true,
1238
+ parallelizationFactor: 2,
1239
+ reportBatchItemFailures: true
1240
+ })
1241
+ );
1242
+ }
1243
+ /**
1244
+ * Publishes the cluster ARN, secret ARN, and database name as discoverable
1245
+ * SSM parameters so the REST API stack (and any future read-side consumer)
1246
+ * can wire RDS Data API access without a direct CDK cross-stack reference.
1247
+ */
1248
+ publishCoordinatesToSsm() {
1249
+ new DiscoverableStringParameter(this, "cluster-arn-param", {
1250
+ ssmParamName: POSTGRES_REPLICA_CLUSTER_ARN_SSM_NAME,
1251
+ stringValue: this.cluster.clusterArn,
1252
+ description: "ARN of the Aurora Serverless v2 cluster backing the Postgres replication tier (ADR 2026-04-17-01)."
1253
+ });
1254
+ new DiscoverableStringParameter(this, "secret-arn-param", {
1255
+ ssmParamName: POSTGRES_REPLICA_SECRET_ARN_SSM_NAME,
1256
+ stringValue: this.cluster.secret.secretArn,
1257
+ description: "ARN of the Secrets Manager secret with credentials for the Postgres replication tier."
1258
+ });
1259
+ new DiscoverableStringParameter(this, "database-name-param", {
1260
+ ssmParamName: POSTGRES_REPLICA_DATABASE_NAME_SSM_NAME,
1261
+ stringValue: this.databaseName,
1262
+ description: "Database name within the Postgres replication cluster."
1263
+ });
1264
+ }
1265
+ };
1266
+
1044
1267
  // src/components/route-53/child-hosted-zone.ts
1045
- var import_aws_cdk_lib7 = require("aws-cdk-lib");
1268
+ var import_aws_cdk_lib9 = require("aws-cdk-lib");
1046
1269
  var import_aws_route53 = require("aws-cdk-lib/aws-route53");
1047
1270
  var ChildHostedZone = class extends import_aws_route53.HostedZone {
1048
1271
  constructor(scope, id, props) {
@@ -1051,7 +1274,7 @@ var ChildHostedZone = class extends import_aws_route53.HostedZone {
1051
1274
  zone: props.parentHostedZone,
1052
1275
  recordName: this.zoneName,
1053
1276
  values: this.hostedZoneNameServers || [],
1054
- ttl: import_aws_cdk_lib7.Duration.minutes(5)
1277
+ ttl: import_aws_cdk_lib9.Duration.minutes(5)
1055
1278
  });
1056
1279
  }
1057
1280
  };
@@ -1061,8 +1284,8 @@ var ChildHostedZone = class extends import_aws_route53.HostedZone {
1061
1284
  ChildHostedZone.SSM_PARAM_NAME = "CHILDHOSTEDZONE";
1062
1285
 
1063
1286
  // src/components/route-53/root-hosted-zone.ts
1064
- var import_constructs3 = require("constructs");
1065
- var RootHostedZone = class extends import_constructs3.Construct {
1287
+ var import_constructs5 = require("constructs");
1288
+ var RootHostedZone = class extends import_constructs5.Construct {
1066
1289
  };
1067
1290
 
1068
1291
  // src/components/static-hosting/static-hosting.ts
@@ -1070,9 +1293,9 @@ var import_aws_cloudfront = require("aws-cdk-lib/aws-cloudfront");
1070
1293
  var import_aws_cloudfront_origins = require("aws-cdk-lib/aws-cloudfront-origins");
1071
1294
  var import_aws_s3 = require("aws-cdk-lib/aws-s3");
1072
1295
  var import_core = require("aws-cdk-lib/core");
1073
- var import_constructs4 = require("constructs");
1296
+ var import_constructs6 = require("constructs");
1074
1297
  var STATIC_HOSTING_SERVICE_TYPE = "website";
1075
- var _StaticHosting = class _StaticHosting extends import_constructs4.Construct {
1298
+ var _StaticHosting = class _StaticHosting extends import_constructs6.Construct {
1076
1299
  constructor(scope, id, props = {}) {
1077
1300
  super(scope, id);
1078
1301
  const stack = OpenHiService.of(scope);
@@ -1124,8 +1347,11 @@ _StaticHosting.SSM_PARAM_NAME_DISTRIBUTION_ARN = "STATIC_HOSTING_DISTRIBUTION_AR
1124
1347
  var StaticHosting = _StaticHosting;
1125
1348
 
1126
1349
  // src/services/open-hi-auth-service.ts
1127
- var import_aws_cognito4 = require("aws-cdk-lib/aws-cognito");
1350
+ var import_config4 = __toESM(require_lib());
1351
+ var import_aws_cognito5 = require("aws-cdk-lib/aws-cognito");
1352
+ var import_aws_iam = require("aws-cdk-lib/aws-iam");
1128
1353
  var import_aws_kms2 = require("aws-cdk-lib/aws-kms");
1354
+ var import_core2 = require("aws-cdk-lib/core");
1129
1355
  var _OpenHiAuthService = class _OpenHiAuthService extends OpenHiService {
1130
1356
  /**
1131
1357
  * Returns an IUserPool by looking up the Auth stack's User Pool ID from SSM.
@@ -1135,7 +1361,7 @@ var _OpenHiAuthService = class _OpenHiAuthService extends OpenHiService {
1135
1361
  ssmParamName: CognitoUserPool.SSM_PARAM_NAME,
1136
1362
  serviceType: _OpenHiAuthService.SERVICE_TYPE
1137
1363
  });
1138
- return import_aws_cognito4.UserPool.fromUserPoolId(scope, "user-pool", userPoolId);
1364
+ return import_aws_cognito5.UserPool.fromUserPoolId(scope, "user-pool", userPoolId);
1139
1365
  }
1140
1366
  /**
1141
1367
  * Returns an IUserPoolClient by looking up the Auth stack's User Pool Client ID from SSM.
@@ -1148,12 +1374,33 @@ var _OpenHiAuthService = class _OpenHiAuthService extends OpenHiService {
1148
1374
  serviceType: _OpenHiAuthService.SERVICE_TYPE
1149
1375
  }
1150
1376
  );
1151
- return import_aws_cognito4.UserPoolClient.fromUserPoolClientId(
1377
+ return import_aws_cognito5.UserPoolClient.fromUserPoolClientId(
1152
1378
  scope,
1153
1379
  "user-pool-client",
1154
1380
  userPoolClientId
1155
1381
  );
1156
1382
  }
1383
+ /**
1384
+ * Returns the dedicated fixture-seeder IUserPoolClient by looking up
1385
+ * its ID from SSM. Only non-prod auth stacks publish this parameter
1386
+ * (per the conditional in {@link createFixtureSeederClient}); calling
1387
+ * this against a prod-deployed stack will fail at lookup time.
1388
+ *
1389
+ * Consumed by `OpenHiRestApiService` (in non-prod) so the authorizer
1390
+ * accepts tokens issued by this client, and by the seed-fixtures CLI
1391
+ * to drive USER_PASSWORD_AUTH against this client's ID.
1392
+ */
1393
+ static fixtureSeederClientFromConstruct(scope) {
1394
+ const clientId = DiscoverableStringParameter.valueForLookupName(scope, {
1395
+ ssmParamName: CognitoFixtureSeederClient.SSM_PARAM_NAME,
1396
+ serviceType: _OpenHiAuthService.SERVICE_TYPE
1397
+ });
1398
+ return import_aws_cognito5.UserPoolClient.fromUserPoolClientId(
1399
+ scope,
1400
+ "fixture-seeder-client",
1401
+ clientId
1402
+ );
1403
+ }
1157
1404
  /**
1158
1405
  * Returns an IUserPoolDomain by looking up the Auth stack's User Pool Domain from SSM.
1159
1406
  */
@@ -1162,7 +1409,7 @@ var _OpenHiAuthService = class _OpenHiAuthService extends OpenHiService {
1162
1409
  ssmParamName: CognitoUserPoolDomain.SSM_PARAM_NAME,
1163
1410
  serviceType: _OpenHiAuthService.SERVICE_TYPE
1164
1411
  });
1165
- return import_aws_cognito4.UserPoolDomain.fromDomainName(scope, "user-pool-domain", domainName);
1412
+ return import_aws_cognito5.UserPoolDomain.fromDomainName(scope, "user-pool-domain", domainName);
1166
1413
  }
1167
1414
  /**
1168
1415
  * Returns an IKey (KMS) by looking up the Auth stack's User Pool KMS Key ARN from SSM.
@@ -1182,9 +1429,12 @@ var _OpenHiAuthService = class _OpenHiAuthService extends OpenHiService {
1182
1429
  this.props = props;
1183
1430
  this.userPoolKmsKey = this.createUserPoolKmsKey();
1184
1431
  this.preTokenGenerationLambda = this.createPreTokenGenerationLambda();
1432
+ this.postAuthenticationLambda = this.createPostAuthenticationLambda();
1185
1433
  this.userPool = this.createUserPool();
1434
+ this.grantPostAuthenticationPermissions();
1186
1435
  this.userPoolClient = this.createUserPoolClient();
1187
1436
  this.userPoolDomain = this.createUserPoolDomain();
1437
+ this.fixtureSeederClient = this.createFixtureSeederClient();
1188
1438
  }
1189
1439
  /**
1190
1440
  * Creates the KMS key for the Cognito User Pool and exports its ARN to SSM.
@@ -1208,6 +1458,15 @@ var _OpenHiAuthService = class _OpenHiAuthService extends OpenHiService {
1208
1458
  const construct = new PreTokenGenerationLambda(this);
1209
1459
  return construct.lambda;
1210
1460
  }
1461
+ /**
1462
+ * Creates the Post Authentication Lambda (Cognito trigger). Calls
1463
+ * AdminUserGlobalSignOut on every sign-in to enforce single-device-per-user
1464
+ * sessions per ADR 2026-03-17-01.
1465
+ */
1466
+ createPostAuthenticationLambda() {
1467
+ const construct = new PostAuthenticationLambda(this);
1468
+ return construct.lambda;
1469
+ }
1211
1470
  /**
1212
1471
  * Creates the Cognito User Pool and exports its ID to SSM.
1213
1472
  * Look up via {@link OpenHiAuthService.userPoolFromConstruct}.
@@ -1219,9 +1478,13 @@ var _OpenHiAuthService = class _OpenHiAuthService extends OpenHiService {
1219
1478
  customSenderKmsKey: this.userPoolKmsKey
1220
1479
  });
1221
1480
  userPool.addTrigger(
1222
- import_aws_cognito4.UserPoolOperation.PRE_TOKEN_GENERATION_CONFIG,
1481
+ import_aws_cognito5.UserPoolOperation.PRE_TOKEN_GENERATION_CONFIG,
1223
1482
  this.preTokenGenerationLambda,
1224
- import_aws_cognito4.LambdaVersion.V2_0
1483
+ import_aws_cognito5.LambdaVersion.V2_0
1484
+ );
1485
+ userPool.addTrigger(
1486
+ import_aws_cognito5.UserPoolOperation.POST_AUTHENTICATION,
1487
+ this.postAuthenticationLambda
1225
1488
  );
1226
1489
  new DiscoverableStringParameter(this, "user-pool-param", {
1227
1490
  ssmParamName: CognitoUserPool.SSM_PARAM_NAME,
@@ -1230,6 +1493,33 @@ var _OpenHiAuthService = class _OpenHiAuthService extends OpenHiService {
1230
1493
  });
1231
1494
  return userPool;
1232
1495
  }
1496
+ /**
1497
+ * Grants the Post Authentication Lambda permission to call
1498
+ * `cognito-idp:AdminUserGlobalSignOut`.
1499
+ *
1500
+ * Scoped via `Stack.of(this).formatArn` rather than `userPool.userPoolArn`
1501
+ * because the User Pool registers this Lambda as a Post Authentication
1502
+ * trigger, creating the cycle:
1503
+ * userPool → lambda (trigger ARN) → role policy → userPool ARN.
1504
+ * Using `formatArn` avoids referencing the User Pool resource directly
1505
+ * while still scoping to user pools in this account+region. The Lambda
1506
+ * is invoked only by Cognito with a Cognito-provided `event.userPoolId`,
1507
+ * so the runtime target is constrained by the trigger contract.
1508
+ */
1509
+ grantPostAuthenticationPermissions() {
1510
+ this.postAuthenticationLambda.addToRolePolicy(
1511
+ new import_aws_iam.PolicyStatement({
1512
+ actions: ["cognito-idp:AdminUserGlobalSignOut"],
1513
+ resources: [
1514
+ import_core2.Stack.of(this).formatArn({
1515
+ service: "cognito-idp",
1516
+ resource: "userpool",
1517
+ resourceName: "*"
1518
+ })
1519
+ ]
1520
+ })
1521
+ );
1522
+ }
1233
1523
  /**
1234
1524
  * Creates the User Pool Client and exports its ID to SSM (AUTH service type).
1235
1525
  * Look up via {@link OpenHiAuthService.userPoolClientFromConstruct}.
@@ -1246,6 +1536,31 @@ var _OpenHiAuthService = class _OpenHiAuthService extends OpenHiService {
1246
1536
  });
1247
1537
  return client;
1248
1538
  }
1539
+ /**
1540
+ * Creates the dedicated USER_PASSWORD_AUTH app client for the
1541
+ * `@openhi/seed-fixtures` CLI, **only** in non-prod environments.
1542
+ * Returns `undefined` when this stack is being deployed to a prod
1543
+ * stage so the prod auth stack carries no fixture-seeder code path.
1544
+ *
1545
+ * Operator post-deploy: create a `fixture-seeder` Cognito user with
1546
+ * a service password (manually via console or scripted with
1547
+ * `aws cognito-idp admin-create-user`); the CLI consumes those creds
1548
+ * via env vars to drive `InitiateAuth`.
1549
+ */
1550
+ createFixtureSeederClient() {
1551
+ if (this.ohEnv.ohStage.stageType === import_config4.OPEN_HI_STAGE.PROD) {
1552
+ return void 0;
1553
+ }
1554
+ const client = new CognitoFixtureSeederClient(this, {
1555
+ userPool: this.userPool
1556
+ });
1557
+ new DiscoverableStringParameter(this, "fixture-seeder-client-param", {
1558
+ ssmParamName: CognitoFixtureSeederClient.SSM_PARAM_NAME,
1559
+ stringValue: client.userPoolClientId,
1560
+ description: "Cognito User Pool Client ID for the OpenHI fixture-seeder CLI (USER_PASSWORD_AUTH; non-prod only); cross-stack reference"
1561
+ });
1562
+ return client;
1563
+ }
1249
1564
  /**
1250
1565
  * Creates the User Pool Domain (Cognito hosted UI) and exports domain name to SSM.
1251
1566
  * Look up via {@link OpenHiAuthService.userPoolDomainFromConstruct}.
@@ -1372,13 +1687,14 @@ _OpenHiGlobalService.SERVICE_TYPE = "global";
1372
1687
  var OpenHiGlobalService = _OpenHiGlobalService;
1373
1688
 
1374
1689
  // src/services/open-hi-rest-api-service.ts
1690
+ var import_config5 = __toESM(require_lib());
1375
1691
  var import_aws_apigatewayv22 = require("aws-cdk-lib/aws-apigatewayv2");
1376
1692
  var import_aws_apigatewayv2_authorizers = require("aws-cdk-lib/aws-apigatewayv2-authorizers");
1377
1693
  var import_aws_apigatewayv2_integrations = require("aws-cdk-lib/aws-apigatewayv2-integrations");
1378
- var import_aws_iam = require("aws-cdk-lib/aws-iam");
1694
+ var import_aws_iam2 = require("aws-cdk-lib/aws-iam");
1379
1695
  var import_aws_route533 = require("aws-cdk-lib/aws-route53");
1380
1696
  var import_aws_route53_targets = require("aws-cdk-lib/aws-route53-targets");
1381
- var import_core2 = require("aws-cdk-lib/core");
1697
+ var import_core3 = require("aws-cdk-lib/core");
1382
1698
 
1383
1699
  // src/services/open-hi-data-service.ts
1384
1700
  var import_aws_dynamodb2 = require("aws-cdk-lib/aws-dynamodb");
@@ -1424,7 +1740,11 @@ var _OpenHiDataService = class _OpenHiDataService extends OpenHiService {
1424
1740
  "data-store-change-stream",
1425
1741
  {
1426
1742
  streamName: `openhi-dstore-cdc-${this.branchHash}`,
1427
- streamMode: kinesis.StreamMode.ON_DEMAND
1743
+ streamMode: kinesis.StreamMode.ON_DEMAND,
1744
+ // CDK default for kinesis.Stream is RETAIN, which strands the stream
1745
+ // when a non-prod stack is destroyed. Use the service's policy so
1746
+ // non-prod tears down cleanly while prod retains.
1747
+ removalPolicy: this.removalPolicy
1428
1748
  }
1429
1749
  );
1430
1750
  this.dataStore = this.createDataStore();
@@ -1438,6 +1758,16 @@ var _OpenHiDataService = class _OpenHiDataService extends OpenHiService {
1438
1758
  dataEventBus: this.dataEventBus
1439
1759
  }
1440
1760
  );
1761
+ this.dataStorePostgresReplica = new DataStorePostgresReplica(
1762
+ this,
1763
+ "data-store-postgres-replica",
1764
+ {
1765
+ kinesisStream: this.dataStoreChangeStream,
1766
+ removalPolicy: this.removalPolicy,
1767
+ stackHash: this.stackHash,
1768
+ branchHash: this.branchHash
1769
+ }
1770
+ );
1441
1771
  }
1442
1772
  /**
1443
1773
  * Creates the data event bus.
@@ -1468,57 +1798,61 @@ _OpenHiDataService.SERVICE_TYPE = "data";
1468
1798
  var OpenHiDataService = _OpenHiDataService;
1469
1799
 
1470
1800
  // src/data/lambda/cors-options-lambda.ts
1471
- var import_node_fs3 = __toESM(require("fs"));
1472
- var import_node_path3 = __toESM(require("path"));
1473
- var import_aws_lambda3 = require("aws-cdk-lib/aws-lambda");
1474
- var import_aws_lambda_nodejs3 = require("aws-cdk-lib/aws-lambda-nodejs");
1475
- var import_constructs5 = require("constructs");
1476
- var HANDLER_NAME3 = "cors-options-lambda.handler.js";
1477
- function resolveHandlerEntry3(dirname) {
1478
- const sameDir = import_node_path3.default.join(dirname, HANDLER_NAME3);
1479
- if (import_node_fs3.default.existsSync(sameDir)) {
1801
+ var import_node_fs5 = __toESM(require("fs"));
1802
+ var import_node_path5 = __toESM(require("path"));
1803
+ var import_aws_lambda5 = require("aws-cdk-lib/aws-lambda");
1804
+ var import_aws_lambda_nodejs5 = require("aws-cdk-lib/aws-lambda-nodejs");
1805
+ var import_constructs7 = require("constructs");
1806
+ var HANDLER_NAME5 = "cors-options-lambda.handler.js";
1807
+ function resolveHandlerEntry5(dirname) {
1808
+ const sameDir = import_node_path5.default.join(dirname, HANDLER_NAME5);
1809
+ if (import_node_fs5.default.existsSync(sameDir)) {
1480
1810
  return sameDir;
1481
1811
  }
1482
- const fromLib = import_node_path3.default.join(dirname, "..", "..", "..", "lib", HANDLER_NAME3);
1812
+ const fromLib = import_node_path5.default.join(dirname, "..", "..", "..", "lib", HANDLER_NAME5);
1483
1813
  return fromLib;
1484
1814
  }
1485
- var CorsOptionsLambda = class extends import_constructs5.Construct {
1815
+ var CorsOptionsLambda = class extends import_constructs7.Construct {
1486
1816
  constructor(scope, id = "cors-options-lambda") {
1487
1817
  super(scope, id);
1488
- this.lambda = new import_aws_lambda_nodejs3.NodejsFunction(this, "handler", {
1489
- entry: resolveHandlerEntry3(__dirname),
1490
- runtime: import_aws_lambda3.Runtime.NODEJS_LATEST,
1818
+ this.lambda = new import_aws_lambda_nodejs5.NodejsFunction(this, "handler", {
1819
+ entry: resolveHandlerEntry5(__dirname),
1820
+ runtime: import_aws_lambda5.Runtime.NODEJS_LATEST,
1491
1821
  memorySize: 128
1492
1822
  });
1493
1823
  }
1494
1824
  };
1495
1825
 
1496
1826
  // src/data/lambda/rest-api-lambda.ts
1497
- var import_node_fs4 = __toESM(require("fs"));
1498
- var import_node_path4 = __toESM(require("path"));
1499
- var import_aws_lambda4 = require("aws-cdk-lib/aws-lambda");
1500
- var import_aws_lambda_nodejs4 = require("aws-cdk-lib/aws-lambda-nodejs");
1501
- var import_constructs6 = require("constructs");
1502
- var HANDLER_NAME4 = "rest-api-lambda.handler.js";
1503
- function resolveHandlerEntry4(dirname) {
1504
- const sameDir = import_node_path4.default.join(dirname, HANDLER_NAME4);
1505
- if (import_node_fs4.default.existsSync(sameDir)) {
1827
+ var import_node_fs6 = __toESM(require("fs"));
1828
+ var import_node_path6 = __toESM(require("path"));
1829
+ var import_aws_lambda6 = require("aws-cdk-lib/aws-lambda");
1830
+ var import_aws_lambda_nodejs6 = require("aws-cdk-lib/aws-lambda-nodejs");
1831
+ var import_constructs8 = require("constructs");
1832
+ var HANDLER_NAME6 = "rest-api-lambda.handler.js";
1833
+ function resolveHandlerEntry6(dirname) {
1834
+ const sameDir = import_node_path6.default.join(dirname, HANDLER_NAME6);
1835
+ if (import_node_fs6.default.existsSync(sameDir)) {
1506
1836
  return sameDir;
1507
1837
  }
1508
- const fromLib = import_node_path4.default.join(dirname, "..", "..", "..", "lib", HANDLER_NAME4);
1838
+ const fromLib = import_node_path6.default.join(dirname, "..", "..", "..", "lib", HANDLER_NAME6);
1509
1839
  return fromLib;
1510
1840
  }
1511
- var RestApiLambda = class extends import_constructs6.Construct {
1841
+ var RestApiLambda = class extends import_constructs8.Construct {
1512
1842
  constructor(scope, props) {
1513
1843
  super(scope, "rest-api-lambda");
1514
- this.lambda = new import_aws_lambda_nodejs4.NodejsFunction(this, "handler", {
1515
- entry: resolveHandlerEntry4(__dirname),
1516
- runtime: import_aws_lambda4.Runtime.NODEJS_LATEST,
1844
+ this.lambda = new import_aws_lambda_nodejs6.NodejsFunction(this, "handler", {
1845
+ entry: resolveHandlerEntry6(__dirname),
1846
+ runtime: import_aws_lambda6.Runtime.NODEJS_LATEST,
1517
1847
  memorySize: 1024,
1518
1848
  environment: {
1519
1849
  DYNAMO_TABLE_NAME: props.dynamoTableName,
1520
1850
  BRANCH_TAG_VALUE: props.branchTagValue,
1521
- HTTP_API_TAG_VALUE: props.httpApiTagValue
1851
+ HTTP_API_TAG_VALUE: props.httpApiTagValue,
1852
+ OPENHI_PG_CLUSTER_ARN: props.postgresClusterArn,
1853
+ OPENHI_PG_SECRET_ARN: props.postgresSecretArn,
1854
+ OPENHI_PG_DATABASE: props.postgresDatabase,
1855
+ OPENHI_PG_SCHEMA: props.postgresSchema
1522
1856
  },
1523
1857
  bundling: {
1524
1858
  minify: true,
@@ -1637,11 +1971,36 @@ var _OpenHiRestApiService = class _OpenHiRestApiService extends OpenHiService {
1637
1971
  */
1638
1972
  createRestApiLambdaAndRoutes(hostedZone, domainName) {
1639
1973
  const dataStoreTable = OpenHiDataService.dynamoDbDataStoreFromConstruct(this);
1974
+ const postgresClusterArn = DataStorePostgresReplica.clusterArnFromConstruct(this);
1975
+ const postgresSecretArn = DataStorePostgresReplica.secretArnFromConstruct(this);
1976
+ const postgresDatabase = DataStorePostgresReplica.databaseNameFromConstruct(this);
1977
+ const postgresSchema = getPostgresReplicaSchemaName(this.branchHash);
1640
1978
  const { lambda } = new RestApiLambda(this, {
1641
1979
  dynamoTableName: dataStoreTable.tableName,
1642
1980
  branchTagValue: this.branchName,
1643
- httpApiTagValue: RootHttpApi.SSM_PARAM_NAME
1981
+ httpApiTagValue: RootHttpApi.SSM_PARAM_NAME,
1982
+ postgresClusterArn,
1983
+ postgresSecretArn,
1984
+ postgresDatabase,
1985
+ postgresSchema
1644
1986
  });
1987
+ lambda.addToRolePolicy(
1988
+ new import_aws_iam2.PolicyStatement({
1989
+ effect: import_aws_iam2.Effect.ALLOW,
1990
+ actions: [
1991
+ "rds-data:ExecuteStatement",
1992
+ "rds-data:BatchExecuteStatement"
1993
+ ],
1994
+ resources: [postgresClusterArn]
1995
+ })
1996
+ );
1997
+ lambda.addToRolePolicy(
1998
+ new import_aws_iam2.PolicyStatement({
1999
+ effect: import_aws_iam2.Effect.ALLOW,
2000
+ actions: ["secretsmanager:GetSecretValue"],
2001
+ resources: [postgresSecretArn]
2002
+ })
2003
+ );
1645
2004
  const dynamoActions = [
1646
2005
  "dynamodb:GetItem",
1647
2006
  "dynamodb:Query",
@@ -1655,15 +2014,15 @@ var _OpenHiRestApiService = class _OpenHiRestApiService extends OpenHiService {
1655
2014
  ];
1656
2015
  dataStoreTable.grant(lambda, ...dynamoActions);
1657
2016
  lambda.addToRolePolicy(
1658
- new import_aws_iam.PolicyStatement({
1659
- effect: import_aws_iam.Effect.ALLOW,
2017
+ new import_aws_iam2.PolicyStatement({
2018
+ effect: import_aws_iam2.Effect.ALLOW,
1660
2019
  actions: [...dynamoActions],
1661
2020
  resources: [`${dataStoreTable.tableArn}/index/*`]
1662
2021
  })
1663
2022
  );
1664
2023
  lambda.addToRolePolicy(
1665
- new import_aws_iam.PolicyStatement({
1666
- effect: import_aws_iam.Effect.ALLOW,
2024
+ new import_aws_iam2.PolicyStatement({
2025
+ effect: import_aws_iam2.Effect.ALLOW,
1667
2026
  actions: [
1668
2027
  "ssm:GetParameter",
1669
2028
  "ssm:GetParameters",
@@ -1721,10 +2080,16 @@ var _OpenHiRestApiService = class _OpenHiRestApiService extends OpenHiService {
1721
2080
  createRootHttpApi(domainName) {
1722
2081
  const userPool = OpenHiAuthService.userPoolFromConstruct(this);
1723
2082
  const userPoolClient = OpenHiAuthService.userPoolClientFromConstruct(this);
2083
+ const userPoolClients = [userPoolClient];
2084
+ if (this.ohEnv.ohStage.stageType !== import_config5.OPEN_HI_STAGE.PROD) {
2085
+ userPoolClients.push(
2086
+ OpenHiAuthService.fixtureSeederClientFromConstruct(this)
2087
+ );
2088
+ }
1724
2089
  const cognitoAuthorizer = new import_aws_apigatewayv2_authorizers.HttpUserPoolAuthorizer(
1725
2090
  "cognito-authorizer",
1726
2091
  userPool,
1727
- { userPoolClients: [userPoolClient] }
2092
+ { userPoolClients }
1728
2093
  );
1729
2094
  const { corsPreflight: cors, ...restRootHttpApiProps } = this.props.rootHttpApiProps ?? {};
1730
2095
  const corsPreflight = cors !== void 0 ? {
@@ -1743,7 +2108,7 @@ var _OpenHiRestApiService = class _OpenHiRestApiService extends OpenHiService {
1743
2108
  "Authorization"
1744
2109
  ],
1745
2110
  allowCredentials: cors.allowCredentials ?? true,
1746
- maxAge: cors.maxAge ?? import_core2.Duration.days(1),
2111
+ maxAge: cors.maxAge ?? import_core3.Duration.days(1),
1747
2112
  ...cors.exposeHeaders !== void 0 && {
1748
2113
  exposeHeaders: cors.exposeHeaders
1749
2114
  }
@@ -1807,6 +2172,7 @@ var OpenHiGraphqlService = _OpenHiGraphqlService;
1807
2172
  // Annotate the CommonJS export names for ESM import in node:
1808
2173
  0 && (module.exports = {
1809
2174
  ChildHostedZone,
2175
+ CognitoFixtureSeederClient,
1810
2176
  CognitoUserPool,
1811
2177
  CognitoUserPoolClient,
1812
2178
  CognitoUserPoolDomain,
@@ -1816,6 +2182,7 @@ var OpenHiGraphqlService = _OpenHiGraphqlService;
1816
2182
  DATA_STORE_CHANGE_EVENT_SOURCE,
1817
2183
  DataEventBus,
1818
2184
  DataStoreHistoricalArchive,
2185
+ DataStorePostgresReplica,
1819
2186
  DiscoverableStringParameter,
1820
2187
  DynamoDbDataStore,
1821
2188
  OpenHiApp,
@@ -1828,6 +2195,10 @@ var OpenHiGraphqlService = _OpenHiGraphqlService;
1828
2195
  OpenHiService,
1829
2196
  OpenHiStage,
1830
2197
  OpsEventBus,
2198
+ POSTGRES_REPLICA_CLUSTER_ARN_SSM_NAME,
2199
+ POSTGRES_REPLICA_DATABASE_NAME_SSM_NAME,
2200
+ POSTGRES_REPLICA_SECRET_ARN_SSM_NAME,
2201
+ PostAuthenticationLambda,
1831
2202
  PreTokenGenerationLambda,
1832
2203
  REST_API_BASE_URL_SSM_NAME,
1833
2204
  RootGraphqlApi,
@@ -1837,6 +2208,7 @@ var OpenHiGraphqlService = _OpenHiGraphqlService;
1837
2208
  STATIC_HOSTING_SERVICE_TYPE,
1838
2209
  StaticHosting,
1839
2210
  buildFhirCurrentResourceChangeDetail,
1840
- getDynamoDbDataStoreTableName
2211
+ getDynamoDbDataStoreTableName,
2212
+ getPostgresReplicaSchemaName
1841
2213
  });
1842
2214
  //# sourceMappingURL=index.js.map