@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.
- package/lib/{chunk-SWSN6GDD.mjs → chunk-CEOAGPYY.mjs} +1 -5
- package/lib/chunk-CEOAGPYY.mjs.map +1 -0
- package/lib/chunk-X5MHU7DA.mjs +298 -0
- package/lib/chunk-X5MHU7DA.mjs.map +1 -0
- package/lib/data-store-postgres-replication.handler.d.mts +55 -0
- package/lib/data-store-postgres-replication.handler.d.ts +55 -0
- package/lib/data-store-postgres-replication.handler.js +448 -0
- package/lib/data-store-postgres-replication.handler.js.map +1 -0
- package/lib/data-store-postgres-replication.handler.mjs +313 -0
- package/lib/data-store-postgres-replication.handler.mjs.map +1 -0
- package/lib/firehose-archive-transform.handler.js +0 -4
- package/lib/firehose-archive-transform.handler.js.map +1 -1
- package/lib/firehose-archive-transform.handler.mjs +5 -290
- package/lib/firehose-archive-transform.handler.mjs.map +1 -1
- package/lib/index.d.mts +230 -5
- package/lib/index.d.ts +231 -6
- package/lib/index.js +489 -117
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +468 -97
- package/lib/index.mjs.map +1 -1
- package/lib/post-authentication.handler.d.mts +5 -0
- package/lib/post-authentication.handler.d.ts +5 -0
- package/lib/post-authentication.handler.js +45 -0
- package/lib/post-authentication.handler.js.map +1 -0
- package/lib/post-authentication.handler.mjs +25 -0
- package/lib/post-authentication.handler.mjs.map +1 -0
- package/lib/rest-api-lambda.handler.js +636 -153
- package/lib/rest-api-lambda.handler.js.map +1 -1
- package/lib/rest-api-lambda.handler.mjs +639 -153
- package/lib/rest-api-lambda.handler.mjs.map +1 -1
- package/package.json +20 -11
- package/scripts/generate-operations.js +2 -2
- package/scripts/generate-routes.js +1 -1
- 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-
|
|
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
|
|
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:
|
|
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
|
|
618
|
-
var CognitoUserPoolClient = class extends
|
|
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
|
|
646
|
-
var CognitoUserPoolDomain = class extends
|
|
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/
|
|
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 = "
|
|
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
|
|
741
|
+
var PostAuthenticationLambda = class extends import_constructs.Construct {
|
|
693
742
|
constructor(scope) {
|
|
694
|
-
super(scope, "
|
|
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
|
|
830
|
-
var
|
|
831
|
-
var
|
|
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
|
|
834
|
-
var
|
|
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
|
|
837
|
-
var
|
|
838
|
-
function
|
|
839
|
-
const sameDir =
|
|
840
|
-
if (
|
|
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
|
|
914
|
+
return import_node_path3.default.join(dirname, "..", "..", "..", "lib", HANDLER_NAME3);
|
|
844
915
|
}
|
|
845
|
-
var DataStoreHistoricalArchive = class extends
|
|
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 ===
|
|
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 ===
|
|
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
|
|
866
|
-
entry:
|
|
867
|
-
runtime:
|
|
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:
|
|
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:
|
|
886
|
-
bufferSize:
|
|
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:
|
|
963
|
+
bufferingInterval: import_aws_cdk_lib7.Duration.seconds(300),
|
|
893
964
|
// Firehose requires SizeInMBs ≥ 64 when dynamic partitioning is enabled.
|
|
894
|
-
bufferingSize:
|
|
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: [
|
|
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: [
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
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
|
|
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:
|
|
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
|
|
1065
|
-
var RootHostedZone = class extends
|
|
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
|
|
1296
|
+
var import_constructs6 = require("constructs");
|
|
1074
1297
|
var STATIC_HOSTING_SERVICE_TYPE = "website";
|
|
1075
|
-
var _StaticHosting = class _StaticHosting extends
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
1481
|
+
import_aws_cognito5.UserPoolOperation.PRE_TOKEN_GENERATION_CONFIG,
|
|
1223
1482
|
this.preTokenGenerationLambda,
|
|
1224
|
-
|
|
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
|
|
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
|
|
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
|
|
1472
|
-
var
|
|
1473
|
-
var
|
|
1474
|
-
var
|
|
1475
|
-
var
|
|
1476
|
-
var
|
|
1477
|
-
function
|
|
1478
|
-
const sameDir =
|
|
1479
|
-
if (
|
|
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 =
|
|
1812
|
+
const fromLib = import_node_path5.default.join(dirname, "..", "..", "..", "lib", HANDLER_NAME5);
|
|
1483
1813
|
return fromLib;
|
|
1484
1814
|
}
|
|
1485
|
-
var CorsOptionsLambda = class extends
|
|
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
|
|
1489
|
-
entry:
|
|
1490
|
-
runtime:
|
|
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
|
|
1498
|
-
var
|
|
1499
|
-
var
|
|
1500
|
-
var
|
|
1501
|
-
var
|
|
1502
|
-
var
|
|
1503
|
-
function
|
|
1504
|
-
const sameDir =
|
|
1505
|
-
if (
|
|
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 =
|
|
1838
|
+
const fromLib = import_node_path6.default.join(dirname, "..", "..", "..", "lib", HANDLER_NAME6);
|
|
1509
1839
|
return fromLib;
|
|
1510
1840
|
}
|
|
1511
|
-
var RestApiLambda = class extends
|
|
1841
|
+
var RestApiLambda = class extends import_constructs8.Construct {
|
|
1512
1842
|
constructor(scope, props) {
|
|
1513
1843
|
super(scope, "rest-api-lambda");
|
|
1514
|
-
this.lambda = new
|
|
1515
|
-
entry:
|
|
1516
|
-
runtime:
|
|
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
|
|
1659
|
-
effect:
|
|
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
|
|
1666
|
-
effect:
|
|
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
|
|
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 ??
|
|
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
|