@openhi/constructs 0.0.91 → 0.0.92

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.js CHANGED
@@ -121,6 +121,7 @@ __export(src_exports, {
121
121
  POSTGRES_REPLICA_DATABASE_NAME_SSM_NAME: () => POSTGRES_REPLICA_DATABASE_NAME_SSM_NAME,
122
122
  POSTGRES_REPLICA_SECRET_ARN_SSM_NAME: () => POSTGRES_REPLICA_SECRET_ARN_SSM_NAME,
123
123
  PostAuthenticationLambda: () => PostAuthenticationLambda,
124
+ PostConfirmationLambda: () => PostConfirmationLambda,
124
125
  PreTokenGenerationLambda: () => PreTokenGenerationLambda,
125
126
  REST_API_BASE_URL_SSM_NAME: () => REST_API_BASE_URL_SSM_NAME,
126
127
  RootGraphqlApi: () => RootGraphqlApi,
@@ -749,13 +750,13 @@ var PostAuthenticationLambda = class extends import_constructs.Construct {
749
750
  }
750
751
  };
751
752
 
752
- // src/components/cognito/pre-token-generation-lambda.ts
753
+ // src/components/cognito/post-confirmation-lambda.ts
753
754
  var import_node_fs2 = __toESM(require("fs"));
754
755
  var import_node_path2 = __toESM(require("path"));
755
756
  var import_aws_lambda2 = require("aws-cdk-lib/aws-lambda");
756
757
  var import_aws_lambda_nodejs2 = require("aws-cdk-lib/aws-lambda-nodejs");
757
758
  var import_constructs2 = require("constructs");
758
- var HANDLER_NAME2 = "pre-token-generation.handler.js";
759
+ var HANDLER_NAME2 = "post-confirmation.handler.js";
759
760
  function resolveHandlerEntry2(dirname) {
760
761
  const sameDir = import_node_path2.default.join(dirname, HANDLER_NAME2);
761
762
  if (import_node_fs2.default.existsSync(sameDir)) {
@@ -764,12 +765,41 @@ function resolveHandlerEntry2(dirname) {
764
765
  const fromLib = import_node_path2.default.join(dirname, "..", "..", "..", "lib", HANDLER_NAME2);
765
766
  return fromLib;
766
767
  }
767
- var PreTokenGenerationLambda = class extends import_constructs2.Construct {
768
- constructor(scope) {
769
- super(scope, "pre-token-generation-lambda");
768
+ var PostConfirmationLambda = class extends import_constructs2.Construct {
769
+ constructor(scope, props) {
770
+ super(scope, "post-confirmation-lambda");
770
771
  this.lambda = new import_aws_lambda_nodejs2.NodejsFunction(this, "handler", {
771
772
  entry: resolveHandlerEntry2(__dirname),
772
773
  runtime: import_aws_lambda2.Runtime.NODEJS_LATEST,
774
+ memorySize: 1024,
775
+ environment: {
776
+ DYNAMO_TABLE_NAME: props.dynamoTableName
777
+ }
778
+ });
779
+ }
780
+ };
781
+
782
+ // src/components/cognito/pre-token-generation-lambda.ts
783
+ var import_node_fs3 = __toESM(require("fs"));
784
+ var import_node_path3 = __toESM(require("path"));
785
+ var import_aws_lambda3 = require("aws-cdk-lib/aws-lambda");
786
+ var import_aws_lambda_nodejs3 = require("aws-cdk-lib/aws-lambda-nodejs");
787
+ var import_constructs3 = require("constructs");
788
+ var HANDLER_NAME3 = "pre-token-generation.handler.js";
789
+ function resolveHandlerEntry3(dirname) {
790
+ const sameDir = import_node_path3.default.join(dirname, HANDLER_NAME3);
791
+ if (import_node_fs3.default.existsSync(sameDir)) {
792
+ return sameDir;
793
+ }
794
+ const fromLib = import_node_path3.default.join(dirname, "..", "..", "..", "lib", HANDLER_NAME3);
795
+ return fromLib;
796
+ }
797
+ var PreTokenGenerationLambda = class extends import_constructs3.Construct {
798
+ constructor(scope) {
799
+ super(scope, "pre-token-generation-lambda");
800
+ this.lambda = new import_aws_lambda_nodejs3.NodejsFunction(this, "handler", {
801
+ entry: resolveHandlerEntry3(__dirname),
802
+ runtime: import_aws_lambda3.Runtime.NODEJS_LATEST,
773
803
  memorySize: 1024
774
804
  });
775
805
  }
@@ -897,23 +927,23 @@ function buildFhirCurrentResourceChangeDetail(record, keys) {
897
927
  }
898
928
 
899
929
  // src/components/dynamodb/data-store-historical-archive.ts
900
- var import_node_fs3 = __toESM(require("fs"));
901
- var import_node_path3 = __toESM(require("path"));
930
+ var import_node_fs4 = __toESM(require("fs"));
931
+ var import_node_path4 = __toESM(require("path"));
902
932
  var import_aws_cdk_lib7 = require("aws-cdk-lib");
903
933
  var kinesisfirehose = __toESM(require("aws-cdk-lib/aws-kinesisfirehose"));
904
- var import_aws_lambda3 = require("aws-cdk-lib/aws-lambda");
905
- var import_aws_lambda_nodejs3 = require("aws-cdk-lib/aws-lambda-nodejs");
934
+ var import_aws_lambda4 = require("aws-cdk-lib/aws-lambda");
935
+ var import_aws_lambda_nodejs4 = require("aws-cdk-lib/aws-lambda-nodejs");
906
936
  var s3 = __toESM(require("aws-cdk-lib/aws-s3"));
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)) {
937
+ var import_constructs4 = require("constructs");
938
+ var HANDLER_NAME4 = "firehose-archive-transform.handler.js";
939
+ function resolveHandlerEntry4(dirname) {
940
+ const sameDir = import_node_path4.default.join(dirname, HANDLER_NAME4);
941
+ if (import_node_fs4.default.existsSync(sameDir)) {
912
942
  return sameDir;
913
943
  }
914
- return import_node_path3.default.join(dirname, "..", "..", "..", "lib", HANDLER_NAME3);
944
+ return import_node_path4.default.join(dirname, "..", "..", "..", "lib", HANDLER_NAME4);
915
945
  }
916
- var DataStoreHistoricalArchive = class extends import_constructs3.Construct {
946
+ var DataStoreHistoricalArchive = class extends import_constructs4.Construct {
917
947
  constructor(scope, id, props) {
918
948
  super(scope, id);
919
949
  this.archiveBucket = new s3.Bucket(this, "ArchiveBucket", {
@@ -933,9 +963,9 @@ var DataStoreHistoricalArchive = class extends import_constructs3.Construct {
933
963
  versioned: false
934
964
  }) : void 0;
935
965
  this.putEventsFailureDlqBucket = putEventsFailureDlqBucket;
936
- this.transformFunction = new import_aws_lambda_nodejs3.NodejsFunction(this, "FirehoseTransform", {
937
- entry: resolveHandlerEntry3(__dirname),
938
- runtime: import_aws_lambda3.Runtime.NODEJS_LATEST,
966
+ this.transformFunction = new import_aws_lambda_nodejs4.NodejsFunction(this, "FirehoseTransform", {
967
+ entry: resolveHandlerEntry4(__dirname),
968
+ runtime: import_aws_lambda4.Runtime.NODEJS_LATEST,
939
969
  memorySize: 512,
940
970
  timeout: import_aws_cdk_lib7.Duration.minutes(1),
941
971
  description: "Firehose transform: filter CURRENT resource rows, S3 keys, EventBridge PutEvents",
@@ -1113,27 +1143,27 @@ var OpsEventBus = class _OpsEventBus extends import_aws_events2.EventBus {
1113
1143
  };
1114
1144
 
1115
1145
  // src/components/postgres/data-store-postgres-replica.ts
1116
- var import_node_fs4 = __toESM(require("fs"));
1117
- var import_node_path4 = __toESM(require("path"));
1146
+ var import_node_fs5 = __toESM(require("fs"));
1147
+ var import_node_path5 = __toESM(require("path"));
1118
1148
  var import_aws_cdk_lib8 = require("aws-cdk-lib");
1119
1149
  var ec2 = __toESM(require("aws-cdk-lib/aws-ec2"));
1120
- var import_aws_lambda4 = require("aws-cdk-lib/aws-lambda");
1150
+ var import_aws_lambda5 = require("aws-cdk-lib/aws-lambda");
1121
1151
  var import_aws_lambda_event_sources = require("aws-cdk-lib/aws-lambda-event-sources");
1122
- var import_aws_lambda_nodejs4 = require("aws-cdk-lib/aws-lambda-nodejs");
1152
+ var import_aws_lambda_nodejs5 = require("aws-cdk-lib/aws-lambda-nodejs");
1123
1153
  var rds = __toESM(require("aws-cdk-lib/aws-rds"));
1124
- var import_constructs4 = require("constructs");
1125
- var HANDLER_NAME4 = "data-store-postgres-replication.handler.js";
1154
+ var import_constructs5 = require("constructs");
1155
+ var HANDLER_NAME5 = "data-store-postgres-replication.handler.js";
1126
1156
  var DEFAULT_DATABASE_NAME = "openhi";
1127
1157
  var SCHEMA_NAME_PATTERN = /^[a-z_][a-z0-9_]{0,62}$/;
1128
1158
  var POSTGRES_REPLICA_CLUSTER_ARN_SSM_NAME = "POSTGRES_REPLICA_CLUSTER_ARN";
1129
1159
  var POSTGRES_REPLICA_SECRET_ARN_SSM_NAME = "POSTGRES_REPLICA_SECRET_ARN";
1130
1160
  var POSTGRES_REPLICA_DATABASE_NAME_SSM_NAME = "POSTGRES_REPLICA_DATABASE_NAME";
1131
- function resolveHandlerEntry4(dirname) {
1132
- const sameDir = import_node_path4.default.join(dirname, HANDLER_NAME4);
1133
- if (import_node_fs4.default.existsSync(sameDir)) {
1161
+ function resolveHandlerEntry5(dirname) {
1162
+ const sameDir = import_node_path5.default.join(dirname, HANDLER_NAME5);
1163
+ if (import_node_fs5.default.existsSync(sameDir)) {
1134
1164
  return sameDir;
1135
1165
  }
1136
- return import_node_path4.default.join(dirname, "..", "..", "..", "lib", HANDLER_NAME4);
1166
+ return import_node_path5.default.join(dirname, "..", "..", "..", "lib", HANDLER_NAME5);
1137
1167
  }
1138
1168
  function getPostgresReplicaSchemaName(branchHash) {
1139
1169
  const candidate = `b_${branchHash.toLowerCase()}`;
@@ -1144,7 +1174,7 @@ function getPostgresReplicaSchemaName(branchHash) {
1144
1174
  }
1145
1175
  return candidate;
1146
1176
  }
1147
- var DataStorePostgresReplica = class extends import_constructs4.Construct {
1177
+ var DataStorePostgresReplica = class extends import_constructs5.Construct {
1148
1178
  /**
1149
1179
  * Resolve the cluster ARN published by an upstream {@link DataStorePostgresReplica}.
1150
1180
  * Use from any stack that needs to grant `rds-data:ExecuteStatement` against
@@ -1213,9 +1243,9 @@ var DataStorePostgresReplica = class extends import_constructs4.Construct {
1213
1243
  enableDataApi: true
1214
1244
  });
1215
1245
  this.publishCoordinatesToSsm();
1216
- this.replicationFunction = new import_aws_lambda_nodejs4.NodejsFunction(this, "ReplicationFunction", {
1217
- entry: resolveHandlerEntry4(__dirname),
1218
- runtime: import_aws_lambda4.Runtime.NODEJS_LATEST,
1246
+ this.replicationFunction = new import_aws_lambda_nodejs5.NodejsFunction(this, "ReplicationFunction", {
1247
+ entry: resolveHandlerEntry5(__dirname),
1248
+ runtime: import_aws_lambda5.Runtime.NODEJS_LATEST,
1219
1249
  memorySize: 512,
1220
1250
  timeout: import_aws_cdk_lib8.Duration.minutes(1),
1221
1251
  vpc: this.vpc,
@@ -1242,7 +1272,7 @@ var DataStorePostgresReplica = class extends import_constructs4.Construct {
1242
1272
  this.cluster.connections.allowDefaultPortFrom(this.replicationFunction);
1243
1273
  this.replicationFunction.addEventSource(
1244
1274
  new import_aws_lambda_event_sources.KinesisEventSource(props.kinesisStream, {
1245
- startingPosition: import_aws_lambda4.StartingPosition.LATEST,
1275
+ startingPosition: import_aws_lambda5.StartingPosition.LATEST,
1246
1276
  batchSize: 100,
1247
1277
  maxBatchingWindow: import_aws_cdk_lib8.Duration.seconds(5),
1248
1278
  retryAttempts: 10,
@@ -1296,8 +1326,8 @@ var ChildHostedZone = class extends import_aws_route53.HostedZone {
1296
1326
  ChildHostedZone.SSM_PARAM_NAME = "CHILDHOSTEDZONE";
1297
1327
 
1298
1328
  // src/components/route-53/root-hosted-zone.ts
1299
- var import_constructs5 = require("constructs");
1300
- var RootHostedZone = class extends import_constructs5.Construct {
1329
+ var import_constructs6 = require("constructs");
1330
+ var RootHostedZone = class extends import_constructs6.Construct {
1301
1331
  };
1302
1332
 
1303
1333
  // src/components/static-hosting/static-hosting.ts
@@ -1305,9 +1335,9 @@ var import_aws_cloudfront = require("aws-cdk-lib/aws-cloudfront");
1305
1335
  var import_aws_cloudfront_origins = require("aws-cdk-lib/aws-cloudfront-origins");
1306
1336
  var import_aws_s3 = require("aws-cdk-lib/aws-s3");
1307
1337
  var import_core = require("aws-cdk-lib/core");
1308
- var import_constructs6 = require("constructs");
1338
+ var import_constructs7 = require("constructs");
1309
1339
  var STATIC_HOSTING_SERVICE_TYPE = "website";
1310
- var _StaticHosting = class _StaticHosting extends import_constructs6.Construct {
1340
+ var _StaticHosting = class _StaticHosting extends import_constructs7.Construct {
1311
1341
  constructor(scope, id, props = {}) {
1312
1342
  super(scope, id);
1313
1343
  const stack = OpenHiService.of(scope);
@@ -1364,7 +1394,131 @@ var import_aws_cognito5 = require("aws-cdk-lib/aws-cognito");
1364
1394
  var import_aws_iam = require("aws-cdk-lib/aws-iam");
1365
1395
  var import_aws_kms2 = require("aws-cdk-lib/aws-kms");
1366
1396
  var import_core2 = require("aws-cdk-lib/core");
1397
+
1398
+ // src/services/open-hi-data-service.ts
1399
+ var import_aws_dynamodb2 = require("aws-cdk-lib/aws-dynamodb");
1400
+ var import_aws_events3 = require("aws-cdk-lib/aws-events");
1401
+ var kinesis = __toESM(require("aws-cdk-lib/aws-kinesis"));
1402
+ var _OpenHiDataService = class _OpenHiDataService extends OpenHiService {
1403
+ /**
1404
+ * Returns the data event bus by name (deterministic per branch). Use from other stacks to obtain an IEventBus reference.
1405
+ */
1406
+ static dataEventBusFromConstruct(scope) {
1407
+ return import_aws_events3.EventBus.fromEventBusName(
1408
+ scope,
1409
+ "data-event-bus",
1410
+ DataEventBus.getEventBusName(scope)
1411
+ );
1412
+ }
1413
+ /**
1414
+ * Returns the ops event bus by name (deterministic per branch). Use from other stacks to obtain an IEventBus reference.
1415
+ */
1416
+ static opsEventBusFromConstruct(scope) {
1417
+ return import_aws_events3.EventBus.fromEventBusName(
1418
+ scope,
1419
+ "ops-event-bus",
1420
+ OpsEventBus.getEventBusName(scope)
1421
+ );
1422
+ }
1423
+ /**
1424
+ * Returns the data store table by name. Use from other stacks (e.g. REST API Lambda) to obtain an ITable reference.
1425
+ */
1426
+ static dynamoDbDataStoreFromConstruct(scope, id = "dynamo-db-data-store") {
1427
+ return import_aws_dynamodb2.Table.fromTableName(scope, id, getDynamoDbDataStoreTableName(scope));
1428
+ }
1429
+ get serviceType() {
1430
+ return _OpenHiDataService.SERVICE_TYPE;
1431
+ }
1432
+ constructor(ohEnv, props = {}) {
1433
+ super(ohEnv, _OpenHiDataService.SERVICE_TYPE, props);
1434
+ this.props = props;
1435
+ this.dataEventBus = this.createDataEventBus();
1436
+ this.opsEventBus = this.createOpsEventBus();
1437
+ this.dataStoreChangeStream = new kinesis.Stream(
1438
+ this,
1439
+ "data-store-change-stream",
1440
+ {
1441
+ streamName: `openhi-dstore-cdc-${this.branchHash}`,
1442
+ streamMode: kinesis.StreamMode.ON_DEMAND,
1443
+ // CDK default for kinesis.Stream is RETAIN, which strands the stream
1444
+ // when a non-prod stack is destroyed. Use the service's policy so
1445
+ // non-prod tears down cleanly while prod retains.
1446
+ removalPolicy: this.removalPolicy
1447
+ }
1448
+ );
1449
+ this.dataStore = this.createDataStore();
1450
+ this.dataStoreHistoricalArchive = new DataStoreHistoricalArchive(
1451
+ this,
1452
+ "data-store-historical-archive",
1453
+ {
1454
+ kinesisStream: this.dataStoreChangeStream,
1455
+ removalPolicy: this.removalPolicy,
1456
+ stackHash: this.stackHash,
1457
+ dataEventBus: this.dataEventBus
1458
+ }
1459
+ );
1460
+ this.dataStorePostgresReplica = new DataStorePostgresReplica(
1461
+ this,
1462
+ "data-store-postgres-replica",
1463
+ {
1464
+ kinesisStream: this.dataStoreChangeStream,
1465
+ removalPolicy: this.removalPolicy,
1466
+ stackHash: this.stackHash,
1467
+ branchHash: this.branchHash
1468
+ }
1469
+ );
1470
+ }
1471
+ /**
1472
+ * Creates the data event bus.
1473
+ * Override to customize.
1474
+ */
1475
+ createDataEventBus() {
1476
+ return new DataEventBus(this);
1477
+ }
1478
+ /**
1479
+ * Creates the ops event bus.
1480
+ * Override to customize.
1481
+ */
1482
+ createOpsEventBus() {
1483
+ return new OpsEventBus(this);
1484
+ }
1485
+ /**
1486
+ * Creates the single-table DynamoDB data store.
1487
+ * Override to customize.
1488
+ */
1489
+ createDataStore() {
1490
+ return new DynamoDbDataStore(this, "dynamo-db-data-store", {
1491
+ kinesisStream: this.dataStoreChangeStream,
1492
+ stream: import_aws_dynamodb2.StreamViewType.NEW_AND_OLD_IMAGES
1493
+ });
1494
+ }
1495
+ };
1496
+ _OpenHiDataService.SERVICE_TYPE = "data";
1497
+ var OpenHiDataService = _OpenHiDataService;
1498
+
1499
+ // src/services/open-hi-auth-service.ts
1367
1500
  var _OpenHiAuthService = class _OpenHiAuthService extends OpenHiService {
1501
+ constructor(ohEnv, props = {}) {
1502
+ super(ohEnv, _OpenHiAuthService.SERVICE_TYPE, props);
1503
+ /**
1504
+ * Cross-stack reference to the data store table. Cached so repeated
1505
+ * lookups share a single CDK construct id ("dynamo-db-data-store") in
1506
+ * this stack — a second `Table.fromTableName` call under the same scope
1507
+ * would collide.
1508
+ */
1509
+ this._dataStoreTable = null;
1510
+ this.props = props;
1511
+ this.userPoolKmsKey = this.createUserPoolKmsKey();
1512
+ this.preTokenGenerationLambda = this.createPreTokenGenerationLambda();
1513
+ this.postAuthenticationLambda = this.createPostAuthenticationLambda();
1514
+ this.postConfirmationLambda = this.createPostConfirmationLambda();
1515
+ this.userPool = this.createUserPool();
1516
+ this.grantPostAuthenticationPermissions();
1517
+ this.grantPostConfirmationPermissions();
1518
+ this.userPoolClient = this.createUserPoolClient();
1519
+ this.userPoolDomain = this.createUserPoolDomain();
1520
+ this.fixtureSeederClient = this.createFixtureSeederClient();
1521
+ }
1368
1522
  /**
1369
1523
  * Returns an IUserPool by looking up the Auth stack's User Pool ID from SSM.
1370
1524
  */
@@ -1436,18 +1590,6 @@ var _OpenHiAuthService = class _OpenHiAuthService extends OpenHiService {
1436
1590
  get serviceType() {
1437
1591
  return _OpenHiAuthService.SERVICE_TYPE;
1438
1592
  }
1439
- constructor(ohEnv, props = {}) {
1440
- super(ohEnv, _OpenHiAuthService.SERVICE_TYPE, props);
1441
- this.props = props;
1442
- this.userPoolKmsKey = this.createUserPoolKmsKey();
1443
- this.preTokenGenerationLambda = this.createPreTokenGenerationLambda();
1444
- this.postAuthenticationLambda = this.createPostAuthenticationLambda();
1445
- this.userPool = this.createUserPool();
1446
- this.grantPostAuthenticationPermissions();
1447
- this.userPoolClient = this.createUserPoolClient();
1448
- this.userPoolDomain = this.createUserPoolDomain();
1449
- this.fixtureSeederClient = this.createFixtureSeederClient();
1450
- }
1451
1593
  /**
1452
1594
  * Creates the KMS key for the Cognito User Pool and exports its ARN to SSM.
1453
1595
  * Look up via {@link OpenHiAuthService.userPoolKmsKeyFromConstruct}.
@@ -1479,6 +1621,25 @@ var _OpenHiAuthService = class _OpenHiAuthService extends OpenHiService {
1479
1621
  const construct = new PostAuthenticationLambda(this);
1480
1622
  return construct.lambda;
1481
1623
  }
1624
+ /**
1625
+ * Creates the Post Confirmation Lambda (Cognito trigger). On sign-up
1626
+ * confirmation, writes the new user's default Tenant, Workspace,
1627
+ * Memberships, and `tenant-user` RoleAssignment, plus a User record
1628
+ * carrying the Cognito `sub` and current tenant/workspace pointers
1629
+ * (ADR 2026-03-17-01 invariants).
1630
+ */
1631
+ createPostConfirmationLambda() {
1632
+ const construct = new PostConfirmationLambda(this, {
1633
+ dynamoTableName: this.dataStoreTable().tableName
1634
+ });
1635
+ return construct.lambda;
1636
+ }
1637
+ dataStoreTable() {
1638
+ if (this._dataStoreTable === null) {
1639
+ this._dataStoreTable = OpenHiDataService.dynamoDbDataStoreFromConstruct(this);
1640
+ }
1641
+ return this._dataStoreTable;
1642
+ }
1482
1643
  /**
1483
1644
  * Creates the Cognito User Pool and exports its ID to SSM.
1484
1645
  * Look up via {@link OpenHiAuthService.userPoolFromConstruct}.
@@ -1498,6 +1659,10 @@ var _OpenHiAuthService = class _OpenHiAuthService extends OpenHiService {
1498
1659
  import_aws_cognito5.UserPoolOperation.POST_AUTHENTICATION,
1499
1660
  this.postAuthenticationLambda
1500
1661
  );
1662
+ userPool.addTrigger(
1663
+ import_aws_cognito5.UserPoolOperation.POST_CONFIRMATION,
1664
+ this.postConfirmationLambda
1665
+ );
1501
1666
  new DiscoverableStringParameter(this, "user-pool-param", {
1502
1667
  ssmParamName: CognitoUserPool.SSM_PARAM_NAME,
1503
1668
  stringValue: userPool.userPoolId,
@@ -1532,6 +1697,28 @@ var _OpenHiAuthService = class _OpenHiAuthService extends OpenHiService {
1532
1697
  })
1533
1698
  );
1534
1699
  }
1700
+ /**
1701
+ * Grants the Post Confirmation Lambda write access to the data store
1702
+ * table (and its GSIs) so it can seed the new user's Tenant, Workspace,
1703
+ * Memberships, RoleAssignment, and User records on sign-up confirmation.
1704
+ */
1705
+ grantPostConfirmationPermissions() {
1706
+ const dataStoreTable = this.dataStoreTable();
1707
+ const dynamoActions = [
1708
+ "dynamodb:PutItem",
1709
+ "dynamodb:UpdateItem",
1710
+ "dynamodb:BatchWriteItem",
1711
+ "dynamodb:DescribeTable"
1712
+ ];
1713
+ dataStoreTable.grant(this.postConfirmationLambda, ...dynamoActions);
1714
+ this.postConfirmationLambda.addToRolePolicy(
1715
+ new import_aws_iam.PolicyStatement({
1716
+ effect: import_aws_iam.Effect.ALLOW,
1717
+ actions: [...dynamoActions],
1718
+ resources: [`${dataStoreTable.tableArn}/index/*`]
1719
+ })
1720
+ );
1721
+ }
1535
1722
  /**
1536
1723
  * Creates the User Pool Client and exports its ID to SSM (AUTH service type).
1537
1724
  * Look up via {@link OpenHiAuthService.userPoolClientFromConstruct}.
@@ -1708,154 +1895,53 @@ var import_aws_route533 = require("aws-cdk-lib/aws-route53");
1708
1895
  var import_aws_route53_targets = require("aws-cdk-lib/aws-route53-targets");
1709
1896
  var import_core3 = require("aws-cdk-lib/core");
1710
1897
 
1711
- // src/services/open-hi-data-service.ts
1712
- var import_aws_dynamodb2 = require("aws-cdk-lib/aws-dynamodb");
1713
- var import_aws_events3 = require("aws-cdk-lib/aws-events");
1714
- var kinesis = __toESM(require("aws-cdk-lib/aws-kinesis"));
1715
- var _OpenHiDataService = class _OpenHiDataService extends OpenHiService {
1716
- /**
1717
- * Returns the data event bus by name (deterministic per branch). Use from other stacks to obtain an IEventBus reference.
1718
- */
1719
- static dataEventBusFromConstruct(scope) {
1720
- return import_aws_events3.EventBus.fromEventBusName(
1721
- scope,
1722
- "data-event-bus",
1723
- DataEventBus.getEventBusName(scope)
1724
- );
1725
- }
1726
- /**
1727
- * Returns the ops event bus by name (deterministic per branch). Use from other stacks to obtain an IEventBus reference.
1728
- */
1729
- static opsEventBusFromConstruct(scope) {
1730
- return import_aws_events3.EventBus.fromEventBusName(
1731
- scope,
1732
- "ops-event-bus",
1733
- OpsEventBus.getEventBusName(scope)
1734
- );
1735
- }
1736
- /**
1737
- * Returns the data store table by name. Use from other stacks (e.g. REST API Lambda) to obtain an ITable reference.
1738
- */
1739
- static dynamoDbDataStoreFromConstruct(scope, id = "dynamo-db-data-store") {
1740
- return import_aws_dynamodb2.Table.fromTableName(scope, id, getDynamoDbDataStoreTableName(scope));
1741
- }
1742
- get serviceType() {
1743
- return _OpenHiDataService.SERVICE_TYPE;
1744
- }
1745
- constructor(ohEnv, props = {}) {
1746
- super(ohEnv, _OpenHiDataService.SERVICE_TYPE, props);
1747
- this.props = props;
1748
- this.dataEventBus = this.createDataEventBus();
1749
- this.opsEventBus = this.createOpsEventBus();
1750
- this.dataStoreChangeStream = new kinesis.Stream(
1751
- this,
1752
- "data-store-change-stream",
1753
- {
1754
- streamName: `openhi-dstore-cdc-${this.branchHash}`,
1755
- streamMode: kinesis.StreamMode.ON_DEMAND,
1756
- // CDK default for kinesis.Stream is RETAIN, which strands the stream
1757
- // when a non-prod stack is destroyed. Use the service's policy so
1758
- // non-prod tears down cleanly while prod retains.
1759
- removalPolicy: this.removalPolicy
1760
- }
1761
- );
1762
- this.dataStore = this.createDataStore();
1763
- this.dataStoreHistoricalArchive = new DataStoreHistoricalArchive(
1764
- this,
1765
- "data-store-historical-archive",
1766
- {
1767
- kinesisStream: this.dataStoreChangeStream,
1768
- removalPolicy: this.removalPolicy,
1769
- stackHash: this.stackHash,
1770
- dataEventBus: this.dataEventBus
1771
- }
1772
- );
1773
- this.dataStorePostgresReplica = new DataStorePostgresReplica(
1774
- this,
1775
- "data-store-postgres-replica",
1776
- {
1777
- kinesisStream: this.dataStoreChangeStream,
1778
- removalPolicy: this.removalPolicy,
1779
- stackHash: this.stackHash,
1780
- branchHash: this.branchHash
1781
- }
1782
- );
1783
- }
1784
- /**
1785
- * Creates the data event bus.
1786
- * Override to customize.
1787
- */
1788
- createDataEventBus() {
1789
- return new DataEventBus(this);
1790
- }
1791
- /**
1792
- * Creates the ops event bus.
1793
- * Override to customize.
1794
- */
1795
- createOpsEventBus() {
1796
- return new OpsEventBus(this);
1797
- }
1798
- /**
1799
- * Creates the single-table DynamoDB data store.
1800
- * Override to customize.
1801
- */
1802
- createDataStore() {
1803
- return new DynamoDbDataStore(this, "dynamo-db-data-store", {
1804
- kinesisStream: this.dataStoreChangeStream,
1805
- stream: import_aws_dynamodb2.StreamViewType.NEW_AND_OLD_IMAGES
1806
- });
1807
- }
1808
- };
1809
- _OpenHiDataService.SERVICE_TYPE = "data";
1810
- var OpenHiDataService = _OpenHiDataService;
1811
-
1812
1898
  // src/data/lambda/cors-options-lambda.ts
1813
- var import_node_fs5 = __toESM(require("fs"));
1814
- var import_node_path5 = __toESM(require("path"));
1815
- var import_aws_lambda5 = require("aws-cdk-lib/aws-lambda");
1816
- var import_aws_lambda_nodejs5 = require("aws-cdk-lib/aws-lambda-nodejs");
1817
- var import_constructs7 = require("constructs");
1818
- var HANDLER_NAME5 = "cors-options-lambda.handler.js";
1819
- function resolveHandlerEntry5(dirname) {
1820
- const sameDir = import_node_path5.default.join(dirname, HANDLER_NAME5);
1821
- if (import_node_fs5.default.existsSync(sameDir)) {
1899
+ var import_node_fs6 = __toESM(require("fs"));
1900
+ var import_node_path6 = __toESM(require("path"));
1901
+ var import_aws_lambda6 = require("aws-cdk-lib/aws-lambda");
1902
+ var import_aws_lambda_nodejs6 = require("aws-cdk-lib/aws-lambda-nodejs");
1903
+ var import_constructs8 = require("constructs");
1904
+ var HANDLER_NAME6 = "cors-options-lambda.handler.js";
1905
+ function resolveHandlerEntry6(dirname) {
1906
+ const sameDir = import_node_path6.default.join(dirname, HANDLER_NAME6);
1907
+ if (import_node_fs6.default.existsSync(sameDir)) {
1822
1908
  return sameDir;
1823
1909
  }
1824
- const fromLib = import_node_path5.default.join(dirname, "..", "..", "..", "lib", HANDLER_NAME5);
1910
+ const fromLib = import_node_path6.default.join(dirname, "..", "..", "..", "lib", HANDLER_NAME6);
1825
1911
  return fromLib;
1826
1912
  }
1827
- var CorsOptionsLambda = class extends import_constructs7.Construct {
1913
+ var CorsOptionsLambda = class extends import_constructs8.Construct {
1828
1914
  constructor(scope, id = "cors-options-lambda") {
1829
1915
  super(scope, id);
1830
- this.lambda = new import_aws_lambda_nodejs5.NodejsFunction(this, "handler", {
1831
- entry: resolveHandlerEntry5(__dirname),
1832
- runtime: import_aws_lambda5.Runtime.NODEJS_LATEST,
1916
+ this.lambda = new import_aws_lambda_nodejs6.NodejsFunction(this, "handler", {
1917
+ entry: resolveHandlerEntry6(__dirname),
1918
+ runtime: import_aws_lambda6.Runtime.NODEJS_LATEST,
1833
1919
  memorySize: 128
1834
1920
  });
1835
1921
  }
1836
1922
  };
1837
1923
 
1838
1924
  // src/data/lambda/rest-api-lambda.ts
1839
- var import_node_fs6 = __toESM(require("fs"));
1840
- var import_node_path6 = __toESM(require("path"));
1841
- var import_aws_lambda6 = require("aws-cdk-lib/aws-lambda");
1842
- var import_aws_lambda_nodejs6 = require("aws-cdk-lib/aws-lambda-nodejs");
1843
- var import_constructs8 = require("constructs");
1844
- var HANDLER_NAME6 = "rest-api-lambda.handler.js";
1845
- function resolveHandlerEntry6(dirname) {
1846
- const sameDir = import_node_path6.default.join(dirname, HANDLER_NAME6);
1847
- if (import_node_fs6.default.existsSync(sameDir)) {
1925
+ var import_node_fs7 = __toESM(require("fs"));
1926
+ var import_node_path7 = __toESM(require("path"));
1927
+ var import_aws_lambda7 = require("aws-cdk-lib/aws-lambda");
1928
+ var import_aws_lambda_nodejs7 = require("aws-cdk-lib/aws-lambda-nodejs");
1929
+ var import_constructs9 = require("constructs");
1930
+ var HANDLER_NAME7 = "rest-api-lambda.handler.js";
1931
+ function resolveHandlerEntry7(dirname) {
1932
+ const sameDir = import_node_path7.default.join(dirname, HANDLER_NAME7);
1933
+ if (import_node_fs7.default.existsSync(sameDir)) {
1848
1934
  return sameDir;
1849
1935
  }
1850
- const fromLib = import_node_path6.default.join(dirname, "..", "..", "..", "lib", HANDLER_NAME6);
1936
+ const fromLib = import_node_path7.default.join(dirname, "..", "..", "..", "lib", HANDLER_NAME7);
1851
1937
  return fromLib;
1852
1938
  }
1853
- var RestApiLambda = class extends import_constructs8.Construct {
1939
+ var RestApiLambda = class extends import_constructs9.Construct {
1854
1940
  constructor(scope, props) {
1855
1941
  super(scope, "rest-api-lambda");
1856
- this.lambda = new import_aws_lambda_nodejs6.NodejsFunction(this, "handler", {
1857
- entry: resolveHandlerEntry6(__dirname),
1858
- runtime: import_aws_lambda6.Runtime.NODEJS_LATEST,
1942
+ this.lambda = new import_aws_lambda_nodejs7.NodejsFunction(this, "handler", {
1943
+ entry: resolveHandlerEntry7(__dirname),
1944
+ runtime: import_aws_lambda7.Runtime.NODEJS_LATEST,
1859
1945
  memorySize: 1024,
1860
1946
  environment: {
1861
1947
  DYNAMO_TABLE_NAME: props.dynamoTableName,
@@ -2211,6 +2297,7 @@ var OpenHiGraphqlService = _OpenHiGraphqlService;
2211
2297
  POSTGRES_REPLICA_DATABASE_NAME_SSM_NAME,
2212
2298
  POSTGRES_REPLICA_SECRET_ARN_SSM_NAME,
2213
2299
  PostAuthenticationLambda,
2300
+ PostConfirmationLambda,
2214
2301
  PreTokenGenerationLambda,
2215
2302
  REST_API_BASE_URL_SSM_NAME,
2216
2303
  RootGraphqlApi,