@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.mjs CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  DATA_STORE_CHANGE_DETAIL_TYPE,
4
4
  DATA_STORE_CHANGE_EVENT_SOURCE,
5
5
  buildFhirCurrentResourceChangeDetail
6
- } from "./chunk-SWSN6GDD.mjs";
6
+ } from "./chunk-CEOAGPYY.mjs";
7
7
  import {
8
8
  __commonJS,
9
9
  __toESM
@@ -347,6 +347,10 @@ var OpenHiService = class extends Stack {
347
347
  this.environmentHash = environmentHash;
348
348
  this.branchHash = branchHash;
349
349
  this.stackHash = stackHash;
350
+ this.node.setContext(
351
+ `availability-zones:account=${account}:region=${region}`,
352
+ [`${region}a`, `${region}b`, `${region}c`]
353
+ );
350
354
  Tags.of(this).add(`${appName}:repo-name`, repoName.slice(0, 255));
351
355
  Tags.of(this).add(`${appName}:branch-name`, branchName.slice(0, 255));
352
356
  Tags.of(this).add(`${appName}:service-type`, id.slice(0, 255));
@@ -530,6 +534,46 @@ var _RootGraphqlApi = class _RootGraphqlApi extends GraphqlApi {
530
534
  _RootGraphqlApi.SSM_PARAM_NAME = "ROOT_GRAPHQL_API";
531
535
  var RootGraphqlApi = _RootGraphqlApi;
532
536
 
537
+ // src/components/cognito/cognito-fixture-seeder-client.ts
538
+ import { Duration } from "aws-cdk-lib";
539
+ import {
540
+ UserPoolClient
541
+ } from "aws-cdk-lib/aws-cognito";
542
+ var CognitoFixtureSeederClient = class extends UserPoolClient {
543
+ constructor(scope, props) {
544
+ const { userPool, ...rest } = props;
545
+ super(scope, "fixture-seeder-client", {
546
+ userPool,
547
+ generateSecret: false,
548
+ authFlows: {
549
+ userPassword: true
550
+ },
551
+ // No OAuth flows — the seeder calls Cognito's `InitiateAuth`
552
+ // directly with USER_PASSWORD_AUTH, not through the hosted-UI
553
+ // OAuth grant flows the SPA client uses. `disableOAuth: true`
554
+ // causes CDK to omit `AllowedOAuthFlowsUserPoolClient` entirely;
555
+ // passing an empty `oAuth` block instead still flips that flag on
556
+ // and Cognito rejects the create call for missing flows/scopes.
557
+ disableOAuth: true,
558
+ // Short-lived tokens: a seeder run takes seconds, not hours.
559
+ // 1h access-token validity is the minimum Cognito permits and is
560
+ // plenty for a fixture run.
561
+ accessTokenValidity: Duration.hours(1),
562
+ idTokenValidity: Duration.hours(1),
563
+ refreshTokenValidity: Duration.days(1),
564
+ preventUserExistenceErrors: true,
565
+ ...rest
566
+ });
567
+ }
568
+ };
569
+ /**
570
+ * SSM parameter name suffix used to publish this client's ID for
571
+ * cross-stack lookups. Built into a full parameter name via
572
+ * `buildParameterName` with `serviceType` AUTH (since the auth stack
573
+ * owns this resource).
574
+ */
575
+ CognitoFixtureSeederClient.SSM_PARAM_NAME = "COGNITO_FIXTURE_SEEDER_CLIENT";
576
+
533
577
  // src/components/cognito/cognito-user-pool.ts
534
578
  import {
535
579
  UserPool,
@@ -569,8 +613,8 @@ var CognitoUserPool = class extends UserPool {
569
613
  CognitoUserPool.SSM_PARAM_NAME = "COGNITO_USER_POOL";
570
614
 
571
615
  // src/components/cognito/cognito-user-pool-client.ts
572
- import { UserPoolClient } from "aws-cdk-lib/aws-cognito";
573
- var CognitoUserPoolClient = class extends UserPoolClient {
616
+ import { UserPoolClient as UserPoolClient2 } from "aws-cdk-lib/aws-cognito";
617
+ var CognitoUserPoolClient = class extends UserPoolClient2 {
574
618
  constructor(scope, props) {
575
619
  super(scope, "user-pool-client", {
576
620
  /**
@@ -629,13 +673,13 @@ var CognitoUserPoolKmsKey = class extends Key {
629
673
  */
630
674
  CognitoUserPoolKmsKey.SSM_PARAM_NAME = "COGNITO_USER_POOL_KMS_KEY";
631
675
 
632
- // src/components/cognito/pre-token-generation-lambda.ts
676
+ // src/components/cognito/post-authentication-lambda.ts
633
677
  import fs from "fs";
634
678
  import path from "path";
635
679
  import { Runtime } from "aws-cdk-lib/aws-lambda";
636
680
  import { NodejsFunction } from "aws-cdk-lib/aws-lambda-nodejs";
637
681
  import { Construct } from "constructs";
638
- var HANDLER_NAME = "pre-token-generation.handler.js";
682
+ var HANDLER_NAME = "post-authentication.handler.js";
639
683
  function resolveHandlerEntry(dirname) {
640
684
  const sameDir = path.join(dirname, HANDLER_NAME);
641
685
  if (fs.existsSync(sameDir)) {
@@ -644,9 +688,9 @@ function resolveHandlerEntry(dirname) {
644
688
  const fromLib = path.join(dirname, "..", "..", "..", "lib", HANDLER_NAME);
645
689
  return fromLib;
646
690
  }
647
- var PreTokenGenerationLambda = class extends Construct {
691
+ var PostAuthenticationLambda = class extends Construct {
648
692
  constructor(scope) {
649
- super(scope, "pre-token-generation-lambda");
693
+ super(scope, "post-authentication-lambda");
650
694
  this.lambda = new NodejsFunction(this, "handler", {
651
695
  entry: resolveHandlerEntry(__dirname),
652
696
  runtime: Runtime.NODEJS_LATEST,
@@ -655,24 +699,50 @@ var PreTokenGenerationLambda = class extends Construct {
655
699
  }
656
700
  };
657
701
 
658
- // src/components/dynamodb/data-store-historical-archive.ts
702
+ // src/components/cognito/pre-token-generation-lambda.ts
659
703
  import fs2 from "fs";
660
704
  import path2 from "path";
661
- import { Duration, RemovalPolicy as RemovalPolicy2, Size } from "aws-cdk-lib";
662
- import * as kinesisfirehose from "aws-cdk-lib/aws-kinesisfirehose";
663
705
  import { Runtime as Runtime2 } from "aws-cdk-lib/aws-lambda";
664
706
  import { NodejsFunction as NodejsFunction2 } from "aws-cdk-lib/aws-lambda-nodejs";
665
- import * as s3 from "aws-cdk-lib/aws-s3";
666
707
  import { Construct as Construct2 } from "constructs";
667
- var HANDLER_NAME2 = "firehose-archive-transform.handler.js";
708
+ var HANDLER_NAME2 = "pre-token-generation.handler.js";
668
709
  function resolveHandlerEntry2(dirname) {
669
710
  const sameDir = path2.join(dirname, HANDLER_NAME2);
670
711
  if (fs2.existsSync(sameDir)) {
671
712
  return sameDir;
672
713
  }
673
- return path2.join(dirname, "..", "..", "..", "lib", HANDLER_NAME2);
714
+ const fromLib = path2.join(dirname, "..", "..", "..", "lib", HANDLER_NAME2);
715
+ return fromLib;
674
716
  }
675
- 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 {
676
746
  constructor(scope, id, props) {
677
747
  super(scope, id);
678
748
  this.archiveBucket = new s3.Bucket(this, "ArchiveBucket", {
@@ -692,11 +762,11 @@ var DataStoreHistoricalArchive = class extends Construct2 {
692
762
  versioned: false
693
763
  }) : void 0;
694
764
  this.putEventsFailureDlqBucket = putEventsFailureDlqBucket;
695
- this.transformFunction = new NodejsFunction2(this, "FirehoseTransform", {
696
- entry: resolveHandlerEntry2(__dirname),
697
- runtime: Runtime2.NODEJS_LATEST,
765
+ this.transformFunction = new NodejsFunction3(this, "FirehoseTransform", {
766
+ entry: resolveHandlerEntry3(__dirname),
767
+ runtime: Runtime3.NODEJS_LATEST,
698
768
  memorySize: 512,
699
- timeout: Duration.minutes(1),
769
+ timeout: Duration2.minutes(1),
700
770
  description: "Firehose transform: filter CURRENT resource rows, S3 keys, EventBridge PutEvents",
701
771
  environment: props.dataEventBus && putEventsFailureDlqBucket ? {
702
772
  DATA_EVENT_BUS_NAME: props.dataEventBus.eventBusName,
@@ -712,14 +782,14 @@ var DataStoreHistoricalArchive = class extends Construct2 {
712
782
  const processor = new kinesisfirehose.LambdaFunctionProcessor(
713
783
  this.transformFunction,
714
784
  {
715
- bufferInterval: Duration.seconds(60),
785
+ bufferInterval: Duration2.seconds(60),
716
786
  bufferSize: Size.mebibytes(3),
717
787
  retries: 3
718
788
  }
719
789
  );
720
790
  const destination = new kinesisfirehose.S3Bucket(this.archiveBucket, {
721
791
  compression: kinesisfirehose.Compression.GZIP,
722
- bufferingInterval: Duration.seconds(300),
792
+ bufferingInterval: Duration2.seconds(300),
723
793
  // Firehose requires SizeInMBs ≥ 64 when dynamic partitioning is enabled.
724
794
  bufferingSize: Size.mebibytes(64),
725
795
  processors: [processor],
@@ -789,7 +859,15 @@ var DynamoDbDataStore = class extends Table {
789
859
  type: AttributeType.STRING
790
860
  },
791
861
  projectionType: ProjectionType.INCLUDE,
792
- nonKeyAttributes: ["srcType", "srcId", "path", "srcPk", "srcSk", "ts"]
862
+ nonKeyAttributes: [
863
+ "summary",
864
+ "vid",
865
+ "lastUpdated",
866
+ "createdDate",
867
+ "modifiedDate",
868
+ "createdById",
869
+ "modifiedById"
870
+ ]
793
871
  });
794
872
  this.addGlobalSecondaryIndex({
795
873
  indexName: "GSI2",
@@ -802,32 +880,12 @@ var DynamoDbDataStore = class extends Table {
802
880
  type: AttributeType.STRING
803
881
  },
804
882
  projectionType: ProjectionType.INCLUDE,
805
- nonKeyAttributes: ["resourcePk", "resourceSk", "display", "status"]
806
- });
807
- this.addGlobalSecondaryIndex({
808
- indexName: "GSI3",
809
- partitionKey: {
810
- name: "GSI3PK",
811
- type: AttributeType.STRING
812
- },
813
- sortKey: {
814
- name: "GSI3SK",
815
- type: AttributeType.STRING
816
- },
817
- projectionType: ProjectionType.INCLUDE,
818
- nonKeyAttributes: ["resourcePk", "resourceSk"]
819
- });
820
- this.addGlobalSecondaryIndex({
821
- indexName: "GSI4",
822
- partitionKey: {
823
- name: "GSI4PK",
824
- type: AttributeType.STRING
825
- },
826
- sortKey: {
827
- name: "GSI4SK",
828
- type: AttributeType.STRING
829
- },
830
- projectionType: ProjectionType.ALL
883
+ nonKeyAttributes: [
884
+ "id",
885
+ "currentTenant",
886
+ "currentWorkspace",
887
+ "displayName"
888
+ ]
831
889
  });
832
890
  }
833
891
  };
@@ -876,8 +934,172 @@ var OpsEventBus = class _OpsEventBus extends EventBus2 {
876
934
  }
877
935
  };
878
936
 
937
+ // src/components/postgres/data-store-postgres-replica.ts
938
+ import fs4 from "fs";
939
+ import path4 from "path";
940
+ import { Duration as Duration3, Stack as Stack2 } from "aws-cdk-lib";
941
+ import * as ec2 from "aws-cdk-lib/aws-ec2";
942
+ import { Runtime as Runtime4, StartingPosition } from "aws-cdk-lib/aws-lambda";
943
+ import { KinesisEventSource } from "aws-cdk-lib/aws-lambda-event-sources";
944
+ import { NodejsFunction as NodejsFunction4 } from "aws-cdk-lib/aws-lambda-nodejs";
945
+ import * as rds from "aws-cdk-lib/aws-rds";
946
+ import { Construct as Construct4 } from "constructs";
947
+ var HANDLER_NAME4 = "data-store-postgres-replication.handler.js";
948
+ var DEFAULT_DATABASE_NAME = "openhi";
949
+ var SCHEMA_NAME_PATTERN = /^[a-z_][a-z0-9_]{0,62}$/;
950
+ var POSTGRES_REPLICA_CLUSTER_ARN_SSM_NAME = "POSTGRES_REPLICA_CLUSTER_ARN";
951
+ var POSTGRES_REPLICA_SECRET_ARN_SSM_NAME = "POSTGRES_REPLICA_SECRET_ARN";
952
+ var POSTGRES_REPLICA_DATABASE_NAME_SSM_NAME = "POSTGRES_REPLICA_DATABASE_NAME";
953
+ function resolveHandlerEntry4(dirname) {
954
+ const sameDir = path4.join(dirname, HANDLER_NAME4);
955
+ if (fs4.existsSync(sameDir)) {
956
+ return sameDir;
957
+ }
958
+ return path4.join(dirname, "..", "..", "..", "lib", HANDLER_NAME4);
959
+ }
960
+ function getPostgresReplicaSchemaName(branchHash) {
961
+ const candidate = `b_${branchHash.toLowerCase()}`;
962
+ if (!SCHEMA_NAME_PATTERN.test(candidate)) {
963
+ throw new Error(
964
+ `Branch hash ${JSON.stringify(branchHash)} produces an invalid Postgres schema name ${JSON.stringify(candidate)}; expected /[a-z_][a-z0-9_]{0,62}/.`
965
+ );
966
+ }
967
+ return candidate;
968
+ }
969
+ var DataStorePostgresReplica = class extends Construct4 {
970
+ /**
971
+ * Resolve the cluster ARN published by an upstream {@link DataStorePostgresReplica}.
972
+ * Use from any stack that needs to grant `rds-data:ExecuteStatement` against
973
+ * the cluster.
974
+ */
975
+ static clusterArnFromConstruct(scope) {
976
+ return DiscoverableStringParameter.valueForLookupName(scope, {
977
+ ssmParamName: POSTGRES_REPLICA_CLUSTER_ARN_SSM_NAME,
978
+ serviceType: "data"
979
+ });
980
+ }
981
+ /**
982
+ * Resolve the credentials secret ARN published by an upstream
983
+ * {@link DataStorePostgresReplica}. Use from any stack that needs to grant
984
+ * `secretsmanager:GetSecretValue` against the secret.
985
+ */
986
+ static secretArnFromConstruct(scope) {
987
+ return DiscoverableStringParameter.valueForLookupName(scope, {
988
+ ssmParamName: POSTGRES_REPLICA_SECRET_ARN_SSM_NAME,
989
+ serviceType: "data"
990
+ });
991
+ }
992
+ /**
993
+ * Resolve the database name published by an upstream
994
+ * {@link DataStorePostgresReplica}.
995
+ */
996
+ static databaseNameFromConstruct(scope) {
997
+ return DiscoverableStringParameter.valueForLookupName(scope, {
998
+ ssmParamName: POSTGRES_REPLICA_DATABASE_NAME_SSM_NAME,
999
+ serviceType: "data"
1000
+ });
1001
+ }
1002
+ constructor(scope, id, props) {
1003
+ super(scope, id);
1004
+ this.databaseName = props.databaseName ?? DEFAULT_DATABASE_NAME;
1005
+ this.schemaName = getPostgresReplicaSchemaName(props.branchHash);
1006
+ const region = Stack2.of(this).region;
1007
+ this.vpc = props.vpc ?? new ec2.Vpc(this, "Vpc", {
1008
+ availabilityZones: [`${region}a`, `${region}b`],
1009
+ natGateways: 0,
1010
+ subnetConfiguration: [
1011
+ {
1012
+ name: "isolated",
1013
+ subnetType: ec2.SubnetType.PRIVATE_ISOLATED,
1014
+ cidrMask: 24
1015
+ }
1016
+ ]
1017
+ });
1018
+ this.cluster = new rds.DatabaseCluster(this, "Cluster", {
1019
+ clusterIdentifier: `openhi-dstore-pg-${props.stackHash}`,
1020
+ engine: rds.DatabaseClusterEngine.auroraPostgres({
1021
+ version: rds.AuroraPostgresEngineVersion.VER_16_4
1022
+ }),
1023
+ vpc: this.vpc,
1024
+ vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED },
1025
+ writer: rds.ClusterInstance.serverlessV2("writer"),
1026
+ serverlessV2MinCapacity: props.minCapacity ?? 1,
1027
+ serverlessV2MaxCapacity: props.maxCapacity ?? 2,
1028
+ defaultDatabaseName: this.databaseName,
1029
+ credentials: rds.Credentials.fromGeneratedSecret("openhi_admin"),
1030
+ storageEncrypted: true,
1031
+ removalPolicy: props.removalPolicy,
1032
+ // Phase 2 of ADR 2026-04-17-01: the REST API Lambda queries Postgres
1033
+ // via the RDS Data API (HTTPS) so it can stay out of the cluster's VPC.
1034
+ // Direct `pg` from the replication Lambda continues to work in parallel.
1035
+ enableDataApi: true
1036
+ });
1037
+ this.publishCoordinatesToSsm();
1038
+ this.replicationFunction = new NodejsFunction4(this, "ReplicationFunction", {
1039
+ entry: resolveHandlerEntry4(__dirname),
1040
+ runtime: Runtime4.NODEJS_LATEST,
1041
+ memorySize: 512,
1042
+ timeout: Duration3.minutes(1),
1043
+ vpc: this.vpc,
1044
+ vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED },
1045
+ description: "Replicates DynamoDB current-resource changes into the Postgres `resources` JSONB table (ADR 2026-04-17-01).",
1046
+ environment: {
1047
+ OPENHI_PG_HOST: this.cluster.clusterEndpoint.hostname,
1048
+ OPENHI_PG_PORT: this.cluster.clusterEndpoint.port.toString(),
1049
+ OPENHI_PG_DATABASE: this.databaseName,
1050
+ OPENHI_PG_SCHEMA: this.schemaName,
1051
+ OPENHI_PG_SECRET_ARN: this.cluster.secret.secretArn,
1052
+ OPENHI_PG_SSL: "true"
1053
+ },
1054
+ bundling: {
1055
+ minify: true,
1056
+ sourceMap: false,
1057
+ // pg has conditional/optional deps (pg-native, pg-cloudflare) that
1058
+ // historically misbehave when bundled by esbuild; keep it as a real
1059
+ // node_module in the Lambda zip instead.
1060
+ nodeModules: ["pg"]
1061
+ }
1062
+ });
1063
+ this.cluster.secret.grantRead(this.replicationFunction);
1064
+ this.cluster.connections.allowDefaultPortFrom(this.replicationFunction);
1065
+ this.replicationFunction.addEventSource(
1066
+ new KinesisEventSource(props.kinesisStream, {
1067
+ startingPosition: StartingPosition.LATEST,
1068
+ batchSize: 100,
1069
+ maxBatchingWindow: Duration3.seconds(5),
1070
+ retryAttempts: 10,
1071
+ bisectBatchOnError: true,
1072
+ parallelizationFactor: 2,
1073
+ reportBatchItemFailures: true
1074
+ })
1075
+ );
1076
+ }
1077
+ /**
1078
+ * Publishes the cluster ARN, secret ARN, and database name as discoverable
1079
+ * SSM parameters so the REST API stack (and any future read-side consumer)
1080
+ * can wire RDS Data API access without a direct CDK cross-stack reference.
1081
+ */
1082
+ publishCoordinatesToSsm() {
1083
+ new DiscoverableStringParameter(this, "cluster-arn-param", {
1084
+ ssmParamName: POSTGRES_REPLICA_CLUSTER_ARN_SSM_NAME,
1085
+ stringValue: this.cluster.clusterArn,
1086
+ description: "ARN of the Aurora Serverless v2 cluster backing the Postgres replication tier (ADR 2026-04-17-01)."
1087
+ });
1088
+ new DiscoverableStringParameter(this, "secret-arn-param", {
1089
+ ssmParamName: POSTGRES_REPLICA_SECRET_ARN_SSM_NAME,
1090
+ stringValue: this.cluster.secret.secretArn,
1091
+ description: "ARN of the Secrets Manager secret with credentials for the Postgres replication tier."
1092
+ });
1093
+ new DiscoverableStringParameter(this, "database-name-param", {
1094
+ ssmParamName: POSTGRES_REPLICA_DATABASE_NAME_SSM_NAME,
1095
+ stringValue: this.databaseName,
1096
+ description: "Database name within the Postgres replication cluster."
1097
+ });
1098
+ }
1099
+ };
1100
+
879
1101
  // src/components/route-53/child-hosted-zone.ts
880
- import { Duration as Duration2 } from "aws-cdk-lib";
1102
+ import { Duration as Duration4 } from "aws-cdk-lib";
881
1103
  import {
882
1104
  HostedZone,
883
1105
  NsRecord
@@ -889,7 +1111,7 @@ var ChildHostedZone = class extends HostedZone {
889
1111
  zone: props.parentHostedZone,
890
1112
  recordName: this.zoneName,
891
1113
  values: this.hostedZoneNameServers || [],
892
- ttl: Duration2.minutes(5)
1114
+ ttl: Duration4.minutes(5)
893
1115
  });
894
1116
  }
895
1117
  };
@@ -899,8 +1121,8 @@ var ChildHostedZone = class extends HostedZone {
899
1121
  ChildHostedZone.SSM_PARAM_NAME = "CHILDHOSTEDZONE";
900
1122
 
901
1123
  // src/components/route-53/root-hosted-zone.ts
902
- import { Construct as Construct3 } from "constructs";
903
- var RootHostedZone = class extends Construct3 {
1124
+ import { Construct as Construct5 } from "constructs";
1125
+ var RootHostedZone = class extends Construct5 {
904
1126
  };
905
1127
 
906
1128
  // src/components/static-hosting/static-hosting.ts
@@ -910,10 +1132,10 @@ import {
910
1132
  } from "aws-cdk-lib/aws-cloudfront";
911
1133
  import { S3BucketOrigin } from "aws-cdk-lib/aws-cloudfront-origins";
912
1134
  import { Bucket as Bucket2 } from "aws-cdk-lib/aws-s3";
913
- import { Duration as Duration3 } from "aws-cdk-lib/core";
914
- import { Construct as Construct4 } from "constructs";
1135
+ import { Duration as Duration5 } from "aws-cdk-lib/core";
1136
+ import { Construct as Construct6 } from "constructs";
915
1137
  var STATIC_HOSTING_SERVICE_TYPE = "website";
916
- var _StaticHosting = class _StaticHosting extends Construct4 {
1138
+ var _StaticHosting = class _StaticHosting extends Construct6 {
917
1139
  constructor(scope, id, props = {}) {
918
1140
  super(scope, id);
919
1141
  const stack = OpenHiService.of(scope);
@@ -931,9 +1153,9 @@ var _StaticHosting = class _StaticHosting extends Construct4 {
931
1153
  const cachePolicy = new CachePolicy(this, "cache-policy", {
932
1154
  cachePolicyName: `static-hosting-10s-${stack.branchHash}`,
933
1155
  comment: "Low TTL (10s) for static hosting; no invalidation",
934
- defaultTtl: Duration3.seconds(10),
935
- minTtl: Duration3.seconds(0),
936
- maxTtl: Duration3.seconds(10)
1156
+ defaultTtl: Duration5.seconds(10),
1157
+ minTtl: Duration5.seconds(0),
1158
+ maxTtl: Duration5.seconds(10)
937
1159
  });
938
1160
  this.distribution = new Distribution(this, "distribution", {
939
1161
  defaultBehavior: {
@@ -965,14 +1187,17 @@ _StaticHosting.SSM_PARAM_NAME_DISTRIBUTION_ARN = "STATIC_HOSTING_DISTRIBUTION_AR
965
1187
  var StaticHosting = _StaticHosting;
966
1188
 
967
1189
  // src/services/open-hi-auth-service.ts
1190
+ var import_config4 = __toESM(require_lib());
968
1191
  import {
969
1192
  LambdaVersion,
970
1193
  UserPool as UserPool2,
971
- UserPoolClient as UserPoolClient2,
1194
+ UserPoolClient as UserPoolClient3,
972
1195
  UserPoolDomain as UserPoolDomain2,
973
1196
  UserPoolOperation
974
1197
  } from "aws-cdk-lib/aws-cognito";
1198
+ import { PolicyStatement } from "aws-cdk-lib/aws-iam";
975
1199
  import { Key as Key2 } from "aws-cdk-lib/aws-kms";
1200
+ import { Stack as Stack3 } from "aws-cdk-lib/core";
976
1201
  var _OpenHiAuthService = class _OpenHiAuthService extends OpenHiService {
977
1202
  /**
978
1203
  * Returns an IUserPool by looking up the Auth stack's User Pool ID from SSM.
@@ -995,12 +1220,33 @@ var _OpenHiAuthService = class _OpenHiAuthService extends OpenHiService {
995
1220
  serviceType: _OpenHiAuthService.SERVICE_TYPE
996
1221
  }
997
1222
  );
998
- return UserPoolClient2.fromUserPoolClientId(
1223
+ return UserPoolClient3.fromUserPoolClientId(
999
1224
  scope,
1000
1225
  "user-pool-client",
1001
1226
  userPoolClientId
1002
1227
  );
1003
1228
  }
1229
+ /**
1230
+ * Returns the dedicated fixture-seeder IUserPoolClient by looking up
1231
+ * its ID from SSM. Only non-prod auth stacks publish this parameter
1232
+ * (per the conditional in {@link createFixtureSeederClient}); calling
1233
+ * this against a prod-deployed stack will fail at lookup time.
1234
+ *
1235
+ * Consumed by `OpenHiRestApiService` (in non-prod) so the authorizer
1236
+ * accepts tokens issued by this client, and by the seed-fixtures CLI
1237
+ * to drive USER_PASSWORD_AUTH against this client's ID.
1238
+ */
1239
+ static fixtureSeederClientFromConstruct(scope) {
1240
+ const clientId = DiscoverableStringParameter.valueForLookupName(scope, {
1241
+ ssmParamName: CognitoFixtureSeederClient.SSM_PARAM_NAME,
1242
+ serviceType: _OpenHiAuthService.SERVICE_TYPE
1243
+ });
1244
+ return UserPoolClient3.fromUserPoolClientId(
1245
+ scope,
1246
+ "fixture-seeder-client",
1247
+ clientId
1248
+ );
1249
+ }
1004
1250
  /**
1005
1251
  * Returns an IUserPoolDomain by looking up the Auth stack's User Pool Domain from SSM.
1006
1252
  */
@@ -1029,9 +1275,12 @@ var _OpenHiAuthService = class _OpenHiAuthService extends OpenHiService {
1029
1275
  this.props = props;
1030
1276
  this.userPoolKmsKey = this.createUserPoolKmsKey();
1031
1277
  this.preTokenGenerationLambda = this.createPreTokenGenerationLambda();
1278
+ this.postAuthenticationLambda = this.createPostAuthenticationLambda();
1032
1279
  this.userPool = this.createUserPool();
1280
+ this.grantPostAuthenticationPermissions();
1033
1281
  this.userPoolClient = this.createUserPoolClient();
1034
1282
  this.userPoolDomain = this.createUserPoolDomain();
1283
+ this.fixtureSeederClient = this.createFixtureSeederClient();
1035
1284
  }
1036
1285
  /**
1037
1286
  * Creates the KMS key for the Cognito User Pool and exports its ARN to SSM.
@@ -1055,6 +1304,15 @@ var _OpenHiAuthService = class _OpenHiAuthService extends OpenHiService {
1055
1304
  const construct = new PreTokenGenerationLambda(this);
1056
1305
  return construct.lambda;
1057
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
+ }
1058
1316
  /**
1059
1317
  * Creates the Cognito User Pool and exports its ID to SSM.
1060
1318
  * Look up via {@link OpenHiAuthService.userPoolFromConstruct}.
@@ -1070,6 +1328,10 @@ var _OpenHiAuthService = class _OpenHiAuthService extends OpenHiService {
1070
1328
  this.preTokenGenerationLambda,
1071
1329
  LambdaVersion.V2_0
1072
1330
  );
1331
+ userPool.addTrigger(
1332
+ UserPoolOperation.POST_AUTHENTICATION,
1333
+ this.postAuthenticationLambda
1334
+ );
1073
1335
  new DiscoverableStringParameter(this, "user-pool-param", {
1074
1336
  ssmParamName: CognitoUserPool.SSM_PARAM_NAME,
1075
1337
  stringValue: userPool.userPoolId,
@@ -1077,6 +1339,33 @@ var _OpenHiAuthService = class _OpenHiAuthService extends OpenHiService {
1077
1339
  });
1078
1340
  return userPool;
1079
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
+ }
1080
1369
  /**
1081
1370
  * Creates the User Pool Client and exports its ID to SSM (AUTH service type).
1082
1371
  * Look up via {@link OpenHiAuthService.userPoolClientFromConstruct}.
@@ -1093,6 +1382,31 @@ var _OpenHiAuthService = class _OpenHiAuthService extends OpenHiService {
1093
1382
  });
1094
1383
  return client;
1095
1384
  }
1385
+ /**
1386
+ * Creates the dedicated USER_PASSWORD_AUTH app client for the
1387
+ * `@openhi/seed-fixtures` CLI, **only** in non-prod environments.
1388
+ * Returns `undefined` when this stack is being deployed to a prod
1389
+ * stage so the prod auth stack carries no fixture-seeder code path.
1390
+ *
1391
+ * Operator post-deploy: create a `fixture-seeder` Cognito user with
1392
+ * a service password (manually via console or scripted with
1393
+ * `aws cognito-idp admin-create-user`); the CLI consumes those creds
1394
+ * via env vars to drive `InitiateAuth`.
1395
+ */
1396
+ createFixtureSeederClient() {
1397
+ if (this.ohEnv.ohStage.stageType === import_config4.OPEN_HI_STAGE.PROD) {
1398
+ return void 0;
1399
+ }
1400
+ const client = new CognitoFixtureSeederClient(this, {
1401
+ userPool: this.userPool
1402
+ });
1403
+ new DiscoverableStringParameter(this, "fixture-seeder-client-param", {
1404
+ ssmParamName: CognitoFixtureSeederClient.SSM_PARAM_NAME,
1405
+ stringValue: client.userPoolClientId,
1406
+ description: "Cognito User Pool Client ID for the OpenHI fixture-seeder CLI (USER_PASSWORD_AUTH; non-prod only); cross-stack reference"
1407
+ });
1408
+ return client;
1409
+ }
1096
1410
  /**
1097
1411
  * Creates the User Pool Domain (Cognito hosted UI) and exports domain name to SSM.
1098
1412
  * Look up via {@link OpenHiAuthService.userPoolDomainFromConstruct}.
@@ -1224,6 +1538,7 @@ _OpenHiGlobalService.SERVICE_TYPE = "global";
1224
1538
  var OpenHiGlobalService = _OpenHiGlobalService;
1225
1539
 
1226
1540
  // src/services/open-hi-rest-api-service.ts
1541
+ var import_config5 = __toESM(require_lib());
1227
1542
  import {
1228
1543
  CorsHttpMethod,
1229
1544
  DomainName,
@@ -1235,14 +1550,14 @@ import {
1235
1550
  } from "aws-cdk-lib/aws-apigatewayv2";
1236
1551
  import { HttpUserPoolAuthorizer } from "aws-cdk-lib/aws-apigatewayv2-authorizers";
1237
1552
  import { HttpLambdaIntegration } from "aws-cdk-lib/aws-apigatewayv2-integrations";
1238
- import { Effect, PolicyStatement } from "aws-cdk-lib/aws-iam";
1553
+ import { Effect, PolicyStatement as PolicyStatement2 } from "aws-cdk-lib/aws-iam";
1239
1554
  import {
1240
1555
  ARecord,
1241
1556
  HostedZone as HostedZone3,
1242
1557
  RecordTarget
1243
1558
  } from "aws-cdk-lib/aws-route53";
1244
1559
  import { ApiGatewayv2DomainProperties } from "aws-cdk-lib/aws-route53-targets";
1245
- import { Duration as Duration4 } from "aws-cdk-lib/core";
1560
+ import { Duration as Duration6 } from "aws-cdk-lib/core";
1246
1561
 
1247
1562
  // src/services/open-hi-data-service.ts
1248
1563
  import { StreamViewType, Table as Table2 } from "aws-cdk-lib/aws-dynamodb";
@@ -1288,7 +1603,11 @@ var _OpenHiDataService = class _OpenHiDataService extends OpenHiService {
1288
1603
  "data-store-change-stream",
1289
1604
  {
1290
1605
  streamName: `openhi-dstore-cdc-${this.branchHash}`,
1291
- streamMode: kinesis.StreamMode.ON_DEMAND
1606
+ streamMode: kinesis.StreamMode.ON_DEMAND,
1607
+ // CDK default for kinesis.Stream is RETAIN, which strands the stream
1608
+ // when a non-prod stack is destroyed. Use the service's policy so
1609
+ // non-prod tears down cleanly while prod retains.
1610
+ removalPolicy: this.removalPolicy
1292
1611
  }
1293
1612
  );
1294
1613
  this.dataStore = this.createDataStore();
@@ -1302,6 +1621,16 @@ var _OpenHiDataService = class _OpenHiDataService extends OpenHiService {
1302
1621
  dataEventBus: this.dataEventBus
1303
1622
  }
1304
1623
  );
1624
+ this.dataStorePostgresReplica = new DataStorePostgresReplica(
1625
+ this,
1626
+ "data-store-postgres-replica",
1627
+ {
1628
+ kinesisStream: this.dataStoreChangeStream,
1629
+ removalPolicy: this.removalPolicy,
1630
+ stackHash: this.stackHash,
1631
+ branchHash: this.branchHash
1632
+ }
1633
+ );
1305
1634
  }
1306
1635
  /**
1307
1636
  * Creates the data event bus.
@@ -1332,57 +1661,61 @@ _OpenHiDataService.SERVICE_TYPE = "data";
1332
1661
  var OpenHiDataService = _OpenHiDataService;
1333
1662
 
1334
1663
  // src/data/lambda/cors-options-lambda.ts
1335
- import fs3 from "fs";
1336
- import path3 from "path";
1337
- import { Runtime as Runtime3 } from "aws-cdk-lib/aws-lambda";
1338
- import { NodejsFunction as NodejsFunction3 } from "aws-cdk-lib/aws-lambda-nodejs";
1339
- import { Construct as Construct5 } from "constructs";
1340
- var HANDLER_NAME3 = "cors-options-lambda.handler.js";
1341
- function resolveHandlerEntry3(dirname) {
1342
- const sameDir = path3.join(dirname, HANDLER_NAME3);
1343
- if (fs3.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)) {
1344
1673
  return sameDir;
1345
1674
  }
1346
- const fromLib = path3.join(dirname, "..", "..", "..", "lib", HANDLER_NAME3);
1675
+ const fromLib = path5.join(dirname, "..", "..", "..", "lib", HANDLER_NAME5);
1347
1676
  return fromLib;
1348
1677
  }
1349
- var CorsOptionsLambda = class extends Construct5 {
1678
+ var CorsOptionsLambda = class extends Construct7 {
1350
1679
  constructor(scope, id = "cors-options-lambda") {
1351
1680
  super(scope, id);
1352
- this.lambda = new NodejsFunction3(this, "handler", {
1353
- entry: resolveHandlerEntry3(__dirname),
1354
- runtime: Runtime3.NODEJS_LATEST,
1681
+ this.lambda = new NodejsFunction5(this, "handler", {
1682
+ entry: resolveHandlerEntry5(__dirname),
1683
+ runtime: Runtime5.NODEJS_LATEST,
1355
1684
  memorySize: 128
1356
1685
  });
1357
1686
  }
1358
1687
  };
1359
1688
 
1360
1689
  // src/data/lambda/rest-api-lambda.ts
1361
- import fs4 from "fs";
1362
- import path4 from "path";
1363
- import { Runtime as Runtime4 } from "aws-cdk-lib/aws-lambda";
1364
- import { NodejsFunction as NodejsFunction4 } from "aws-cdk-lib/aws-lambda-nodejs";
1365
- import { Construct as Construct6 } from "constructs";
1366
- var HANDLER_NAME4 = "rest-api-lambda.handler.js";
1367
- function resolveHandlerEntry4(dirname) {
1368
- const sameDir = path4.join(dirname, HANDLER_NAME4);
1369
- if (fs4.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)) {
1370
1699
  return sameDir;
1371
1700
  }
1372
- const fromLib = path4.join(dirname, "..", "..", "..", "lib", HANDLER_NAME4);
1701
+ const fromLib = path6.join(dirname, "..", "..", "..", "lib", HANDLER_NAME6);
1373
1702
  return fromLib;
1374
1703
  }
1375
- var RestApiLambda = class extends Construct6 {
1704
+ var RestApiLambda = class extends Construct8 {
1376
1705
  constructor(scope, props) {
1377
1706
  super(scope, "rest-api-lambda");
1378
- this.lambda = new NodejsFunction4(this, "handler", {
1379
- entry: resolveHandlerEntry4(__dirname),
1380
- runtime: Runtime4.NODEJS_LATEST,
1707
+ this.lambda = new NodejsFunction6(this, "handler", {
1708
+ entry: resolveHandlerEntry6(__dirname),
1709
+ runtime: Runtime6.NODEJS_LATEST,
1381
1710
  memorySize: 1024,
1382
1711
  environment: {
1383
1712
  DYNAMO_TABLE_NAME: props.dynamoTableName,
1384
1713
  BRANCH_TAG_VALUE: props.branchTagValue,
1385
- HTTP_API_TAG_VALUE: props.httpApiTagValue
1714
+ HTTP_API_TAG_VALUE: props.httpApiTagValue,
1715
+ OPENHI_PG_CLUSTER_ARN: props.postgresClusterArn,
1716
+ OPENHI_PG_SECRET_ARN: props.postgresSecretArn,
1717
+ OPENHI_PG_DATABASE: props.postgresDatabase,
1718
+ OPENHI_PG_SCHEMA: props.postgresSchema
1386
1719
  },
1387
1720
  bundling: {
1388
1721
  minify: true,
@@ -1501,11 +1834,36 @@ var _OpenHiRestApiService = class _OpenHiRestApiService extends OpenHiService {
1501
1834
  */
1502
1835
  createRestApiLambdaAndRoutes(hostedZone, domainName) {
1503
1836
  const dataStoreTable = OpenHiDataService.dynamoDbDataStoreFromConstruct(this);
1837
+ const postgresClusterArn = DataStorePostgresReplica.clusterArnFromConstruct(this);
1838
+ const postgresSecretArn = DataStorePostgresReplica.secretArnFromConstruct(this);
1839
+ const postgresDatabase = DataStorePostgresReplica.databaseNameFromConstruct(this);
1840
+ const postgresSchema = getPostgresReplicaSchemaName(this.branchHash);
1504
1841
  const { lambda } = new RestApiLambda(this, {
1505
1842
  dynamoTableName: dataStoreTable.tableName,
1506
1843
  branchTagValue: this.branchName,
1507
- httpApiTagValue: RootHttpApi.SSM_PARAM_NAME
1844
+ httpApiTagValue: RootHttpApi.SSM_PARAM_NAME,
1845
+ postgresClusterArn,
1846
+ postgresSecretArn,
1847
+ postgresDatabase,
1848
+ postgresSchema
1508
1849
  });
1850
+ lambda.addToRolePolicy(
1851
+ new PolicyStatement2({
1852
+ effect: Effect.ALLOW,
1853
+ actions: [
1854
+ "rds-data:ExecuteStatement",
1855
+ "rds-data:BatchExecuteStatement"
1856
+ ],
1857
+ resources: [postgresClusterArn]
1858
+ })
1859
+ );
1860
+ lambda.addToRolePolicy(
1861
+ new PolicyStatement2({
1862
+ effect: Effect.ALLOW,
1863
+ actions: ["secretsmanager:GetSecretValue"],
1864
+ resources: [postgresSecretArn]
1865
+ })
1866
+ );
1509
1867
  const dynamoActions = [
1510
1868
  "dynamodb:GetItem",
1511
1869
  "dynamodb:Query",
@@ -1519,14 +1877,14 @@ var _OpenHiRestApiService = class _OpenHiRestApiService extends OpenHiService {
1519
1877
  ];
1520
1878
  dataStoreTable.grant(lambda, ...dynamoActions);
1521
1879
  lambda.addToRolePolicy(
1522
- new PolicyStatement({
1880
+ new PolicyStatement2({
1523
1881
  effect: Effect.ALLOW,
1524
1882
  actions: [...dynamoActions],
1525
1883
  resources: [`${dataStoreTable.tableArn}/index/*`]
1526
1884
  })
1527
1885
  );
1528
1886
  lambda.addToRolePolicy(
1529
- new PolicyStatement({
1887
+ new PolicyStatement2({
1530
1888
  effect: Effect.ALLOW,
1531
1889
  actions: [
1532
1890
  "ssm:GetParameter",
@@ -1585,10 +1943,16 @@ var _OpenHiRestApiService = class _OpenHiRestApiService extends OpenHiService {
1585
1943
  createRootHttpApi(domainName) {
1586
1944
  const userPool = OpenHiAuthService.userPoolFromConstruct(this);
1587
1945
  const userPoolClient = OpenHiAuthService.userPoolClientFromConstruct(this);
1946
+ const userPoolClients = [userPoolClient];
1947
+ if (this.ohEnv.ohStage.stageType !== import_config5.OPEN_HI_STAGE.PROD) {
1948
+ userPoolClients.push(
1949
+ OpenHiAuthService.fixtureSeederClientFromConstruct(this)
1950
+ );
1951
+ }
1588
1952
  const cognitoAuthorizer = new HttpUserPoolAuthorizer(
1589
1953
  "cognito-authorizer",
1590
1954
  userPool,
1591
- { userPoolClients: [userPoolClient] }
1955
+ { userPoolClients }
1592
1956
  );
1593
1957
  const { corsPreflight: cors, ...restRootHttpApiProps } = this.props.rootHttpApiProps ?? {};
1594
1958
  const corsPreflight = cors !== void 0 ? {
@@ -1607,7 +1971,7 @@ var _OpenHiRestApiService = class _OpenHiRestApiService extends OpenHiService {
1607
1971
  "Authorization"
1608
1972
  ],
1609
1973
  allowCredentials: cors.allowCredentials ?? true,
1610
- maxAge: cors.maxAge ?? Duration4.days(1),
1974
+ maxAge: cors.maxAge ?? Duration6.days(1),
1611
1975
  ...cors.exposeHeaders !== void 0 && {
1612
1976
  exposeHeaders: cors.exposeHeaders
1613
1977
  }
@@ -1673,6 +2037,7 @@ _OpenHiGraphqlService.SERVICE_TYPE = "graphql-api";
1673
2037
  var OpenHiGraphqlService = _OpenHiGraphqlService;
1674
2038
  export {
1675
2039
  ChildHostedZone,
2040
+ CognitoFixtureSeederClient,
1676
2041
  CognitoUserPool,
1677
2042
  CognitoUserPoolClient,
1678
2043
  CognitoUserPoolDomain,
@@ -1682,6 +2047,7 @@ export {
1682
2047
  DATA_STORE_CHANGE_EVENT_SOURCE,
1683
2048
  DataEventBus,
1684
2049
  DataStoreHistoricalArchive,
2050
+ DataStorePostgresReplica,
1685
2051
  DiscoverableStringParameter,
1686
2052
  DynamoDbDataStore,
1687
2053
  OpenHiApp,
@@ -1694,6 +2060,10 @@ export {
1694
2060
  OpenHiService,
1695
2061
  OpenHiStage,
1696
2062
  OpsEventBus,
2063
+ POSTGRES_REPLICA_CLUSTER_ARN_SSM_NAME,
2064
+ POSTGRES_REPLICA_DATABASE_NAME_SSM_NAME,
2065
+ POSTGRES_REPLICA_SECRET_ARN_SSM_NAME,
2066
+ PostAuthenticationLambda,
1697
2067
  PreTokenGenerationLambda,
1698
2068
  REST_API_BASE_URL_SSM_NAME,
1699
2069
  RootGraphqlApi,
@@ -1703,6 +2073,7 @@ export {
1703
2073
  STATIC_HOSTING_SERVICE_TYPE,
1704
2074
  StaticHosting,
1705
2075
  buildFhirCurrentResourceChangeDetail,
1706
- getDynamoDbDataStoreTableName
2076
+ getDynamoDbDataStoreTableName,
2077
+ getPostgresReplicaSchemaName
1707
2078
  };
1708
2079
  //# sourceMappingURL=index.mjs.map