@openhi/constructs 0.0.91 → 0.0.93

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.mjs CHANGED
@@ -699,13 +699,13 @@ var PostAuthenticationLambda = class extends Construct {
699
699
  }
700
700
  };
701
701
 
702
- // src/components/cognito/pre-token-generation-lambda.ts
702
+ // src/components/cognito/post-confirmation-lambda.ts
703
703
  import fs2 from "fs";
704
704
  import path2 from "path";
705
705
  import { Runtime as Runtime2 } from "aws-cdk-lib/aws-lambda";
706
706
  import { NodejsFunction as NodejsFunction2 } from "aws-cdk-lib/aws-lambda-nodejs";
707
707
  import { Construct as Construct2 } from "constructs";
708
- var HANDLER_NAME2 = "pre-token-generation.handler.js";
708
+ var HANDLER_NAME2 = "post-confirmation.handler.js";
709
709
  function resolveHandlerEntry2(dirname) {
710
710
  const sameDir = path2.join(dirname, HANDLER_NAME2);
711
711
  if (fs2.existsSync(sameDir)) {
@@ -714,35 +714,67 @@ function resolveHandlerEntry2(dirname) {
714
714
  const fromLib = path2.join(dirname, "..", "..", "..", "lib", HANDLER_NAME2);
715
715
  return fromLib;
716
716
  }
717
- var PreTokenGenerationLambda = class extends Construct2 {
718
- constructor(scope) {
719
- super(scope, "pre-token-generation-lambda");
717
+ var PostConfirmationLambda = class extends Construct2 {
718
+ constructor(scope, props) {
719
+ super(scope, "post-confirmation-lambda");
720
720
  this.lambda = new NodejsFunction2(this, "handler", {
721
721
  entry: resolveHandlerEntry2(__dirname),
722
722
  runtime: Runtime2.NODEJS_LATEST,
723
- memorySize: 1024
723
+ memorySize: 1024,
724
+ environment: {
725
+ DYNAMO_TABLE_NAME: props.dynamoTableName
726
+ }
724
727
  });
725
728
  }
726
729
  };
727
730
 
728
- // src/components/dynamodb/data-store-historical-archive.ts
731
+ // src/components/cognito/pre-token-generation-lambda.ts
729
732
  import fs3 from "fs";
730
733
  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
734
  import { Runtime as Runtime3 } from "aws-cdk-lib/aws-lambda";
734
735
  import { NodejsFunction as NodejsFunction3 } from "aws-cdk-lib/aws-lambda-nodejs";
735
- import * as s3 from "aws-cdk-lib/aws-s3";
736
736
  import { Construct as Construct3 } from "constructs";
737
- var HANDLER_NAME3 = "firehose-archive-transform.handler.js";
737
+ var HANDLER_NAME3 = "pre-token-generation.handler.js";
738
738
  function resolveHandlerEntry3(dirname) {
739
739
  const sameDir = path3.join(dirname, HANDLER_NAME3);
740
740
  if (fs3.existsSync(sameDir)) {
741
741
  return sameDir;
742
742
  }
743
- return path3.join(dirname, "..", "..", "..", "lib", HANDLER_NAME3);
743
+ const fromLib = path3.join(dirname, "..", "..", "..", "lib", HANDLER_NAME3);
744
+ return fromLib;
745
+ }
746
+ var PreTokenGenerationLambda = class extends Construct3 {
747
+ constructor(scope, props) {
748
+ super(scope, "pre-token-generation-lambda");
749
+ this.lambda = new NodejsFunction3(this, "handler", {
750
+ entry: resolveHandlerEntry3(__dirname),
751
+ runtime: Runtime3.NODEJS_LATEST,
752
+ memorySize: 1024,
753
+ environment: {
754
+ DYNAMO_TABLE_NAME: props.dynamoTableName
755
+ }
756
+ });
757
+ }
758
+ };
759
+
760
+ // src/components/dynamodb/data-store-historical-archive.ts
761
+ import fs4 from "fs";
762
+ import path4 from "path";
763
+ import { Duration as Duration2, RemovalPolicy as RemovalPolicy2, Size } from "aws-cdk-lib";
764
+ import * as kinesisfirehose from "aws-cdk-lib/aws-kinesisfirehose";
765
+ import { Runtime as Runtime4 } from "aws-cdk-lib/aws-lambda";
766
+ import { NodejsFunction as NodejsFunction4 } from "aws-cdk-lib/aws-lambda-nodejs";
767
+ import * as s3 from "aws-cdk-lib/aws-s3";
768
+ import { Construct as Construct4 } from "constructs";
769
+ var HANDLER_NAME4 = "firehose-archive-transform.handler.js";
770
+ function resolveHandlerEntry4(dirname) {
771
+ const sameDir = path4.join(dirname, HANDLER_NAME4);
772
+ if (fs4.existsSync(sameDir)) {
773
+ return sameDir;
774
+ }
775
+ return path4.join(dirname, "..", "..", "..", "lib", HANDLER_NAME4);
744
776
  }
745
- var DataStoreHistoricalArchive = class extends Construct3 {
777
+ var DataStoreHistoricalArchive = class extends Construct4 {
746
778
  constructor(scope, id, props) {
747
779
  super(scope, id);
748
780
  this.archiveBucket = new s3.Bucket(this, "ArchiveBucket", {
@@ -762,9 +794,9 @@ var DataStoreHistoricalArchive = class extends Construct3 {
762
794
  versioned: false
763
795
  }) : void 0;
764
796
  this.putEventsFailureDlqBucket = putEventsFailureDlqBucket;
765
- this.transformFunction = new NodejsFunction3(this, "FirehoseTransform", {
766
- entry: resolveHandlerEntry3(__dirname),
767
- runtime: Runtime3.NODEJS_LATEST,
797
+ this.transformFunction = new NodejsFunction4(this, "FirehoseTransform", {
798
+ entry: resolveHandlerEntry4(__dirname),
799
+ runtime: Runtime4.NODEJS_LATEST,
768
800
  memorySize: 512,
769
801
  timeout: Duration2.minutes(1),
770
802
  description: "Firehose transform: filter CURRENT resource rows, S3 keys, EventBridge PutEvents",
@@ -947,27 +979,27 @@ var OpsEventBus = class _OpsEventBus extends EventBus2 {
947
979
  };
948
980
 
949
981
  // src/components/postgres/data-store-postgres-replica.ts
950
- import fs4 from "fs";
951
- import path4 from "path";
982
+ import fs5 from "fs";
983
+ import path5 from "path";
952
984
  import { Duration as Duration3, Stack as Stack2 } from "aws-cdk-lib";
953
985
  import * as ec2 from "aws-cdk-lib/aws-ec2";
954
- import { Runtime as Runtime4, StartingPosition } from "aws-cdk-lib/aws-lambda";
986
+ import { Runtime as Runtime5, StartingPosition } from "aws-cdk-lib/aws-lambda";
955
987
  import { KinesisEventSource } from "aws-cdk-lib/aws-lambda-event-sources";
956
- import { NodejsFunction as NodejsFunction4 } from "aws-cdk-lib/aws-lambda-nodejs";
988
+ import { NodejsFunction as NodejsFunction5 } from "aws-cdk-lib/aws-lambda-nodejs";
957
989
  import * as rds from "aws-cdk-lib/aws-rds";
958
- import { Construct as Construct4 } from "constructs";
959
- var HANDLER_NAME4 = "data-store-postgres-replication.handler.js";
990
+ import { Construct as Construct5 } from "constructs";
991
+ var HANDLER_NAME5 = "data-store-postgres-replication.handler.js";
960
992
  var DEFAULT_DATABASE_NAME = "openhi";
961
993
  var SCHEMA_NAME_PATTERN = /^[a-z_][a-z0-9_]{0,62}$/;
962
994
  var POSTGRES_REPLICA_CLUSTER_ARN_SSM_NAME = "POSTGRES_REPLICA_CLUSTER_ARN";
963
995
  var POSTGRES_REPLICA_SECRET_ARN_SSM_NAME = "POSTGRES_REPLICA_SECRET_ARN";
964
996
  var POSTGRES_REPLICA_DATABASE_NAME_SSM_NAME = "POSTGRES_REPLICA_DATABASE_NAME";
965
- function resolveHandlerEntry4(dirname) {
966
- const sameDir = path4.join(dirname, HANDLER_NAME4);
967
- if (fs4.existsSync(sameDir)) {
997
+ function resolveHandlerEntry5(dirname) {
998
+ const sameDir = path5.join(dirname, HANDLER_NAME5);
999
+ if (fs5.existsSync(sameDir)) {
968
1000
  return sameDir;
969
1001
  }
970
- return path4.join(dirname, "..", "..", "..", "lib", HANDLER_NAME4);
1002
+ return path5.join(dirname, "..", "..", "..", "lib", HANDLER_NAME5);
971
1003
  }
972
1004
  function getPostgresReplicaSchemaName(branchHash) {
973
1005
  const candidate = `b_${branchHash.toLowerCase()}`;
@@ -978,7 +1010,7 @@ function getPostgresReplicaSchemaName(branchHash) {
978
1010
  }
979
1011
  return candidate;
980
1012
  }
981
- var DataStorePostgresReplica = class extends Construct4 {
1013
+ var DataStorePostgresReplica = class extends Construct5 {
982
1014
  /**
983
1015
  * Resolve the cluster ARN published by an upstream {@link DataStorePostgresReplica}.
984
1016
  * Use from any stack that needs to grant `rds-data:ExecuteStatement` against
@@ -1047,9 +1079,9 @@ var DataStorePostgresReplica = class extends Construct4 {
1047
1079
  enableDataApi: true
1048
1080
  });
1049
1081
  this.publishCoordinatesToSsm();
1050
- this.replicationFunction = new NodejsFunction4(this, "ReplicationFunction", {
1051
- entry: resolveHandlerEntry4(__dirname),
1052
- runtime: Runtime4.NODEJS_LATEST,
1082
+ this.replicationFunction = new NodejsFunction5(this, "ReplicationFunction", {
1083
+ entry: resolveHandlerEntry5(__dirname),
1084
+ runtime: Runtime5.NODEJS_LATEST,
1053
1085
  memorySize: 512,
1054
1086
  timeout: Duration3.minutes(1),
1055
1087
  vpc: this.vpc,
@@ -1133,8 +1165,8 @@ var ChildHostedZone = class extends HostedZone {
1133
1165
  ChildHostedZone.SSM_PARAM_NAME = "CHILDHOSTEDZONE";
1134
1166
 
1135
1167
  // src/components/route-53/root-hosted-zone.ts
1136
- import { Construct as Construct5 } from "constructs";
1137
- var RootHostedZone = class extends Construct5 {
1168
+ import { Construct as Construct6 } from "constructs";
1169
+ var RootHostedZone = class extends Construct6 {
1138
1170
  };
1139
1171
 
1140
1172
  // src/components/static-hosting/static-hosting.ts
@@ -1145,9 +1177,9 @@ import {
1145
1177
  import { S3BucketOrigin } from "aws-cdk-lib/aws-cloudfront-origins";
1146
1178
  import { Bucket as Bucket2 } from "aws-cdk-lib/aws-s3";
1147
1179
  import { Duration as Duration5 } from "aws-cdk-lib/core";
1148
- import { Construct as Construct6 } from "constructs";
1180
+ import { Construct as Construct7 } from "constructs";
1149
1181
  var STATIC_HOSTING_SERVICE_TYPE = "website";
1150
- var _StaticHosting = class _StaticHosting extends Construct6 {
1182
+ var _StaticHosting = class _StaticHosting extends Construct7 {
1151
1183
  constructor(scope, id, props = {}) {
1152
1184
  super(scope, id);
1153
1185
  const stack = OpenHiService.of(scope);
@@ -1207,10 +1239,135 @@ import {
1207
1239
  UserPoolDomain as UserPoolDomain2,
1208
1240
  UserPoolOperation
1209
1241
  } from "aws-cdk-lib/aws-cognito";
1210
- import { PolicyStatement } from "aws-cdk-lib/aws-iam";
1242
+ import { Effect, PolicyStatement } from "aws-cdk-lib/aws-iam";
1211
1243
  import { Key as Key2 } from "aws-cdk-lib/aws-kms";
1212
1244
  import { Stack as Stack3 } from "aws-cdk-lib/core";
1245
+
1246
+ // src/services/open-hi-data-service.ts
1247
+ import { StreamViewType, Table as Table2 } from "aws-cdk-lib/aws-dynamodb";
1248
+ import { EventBus as EventBus3 } from "aws-cdk-lib/aws-events";
1249
+ import * as kinesis from "aws-cdk-lib/aws-kinesis";
1250
+ var _OpenHiDataService = class _OpenHiDataService extends OpenHiService {
1251
+ /**
1252
+ * Returns the data event bus by name (deterministic per branch). Use from other stacks to obtain an IEventBus reference.
1253
+ */
1254
+ static dataEventBusFromConstruct(scope) {
1255
+ return EventBus3.fromEventBusName(
1256
+ scope,
1257
+ "data-event-bus",
1258
+ DataEventBus.getEventBusName(scope)
1259
+ );
1260
+ }
1261
+ /**
1262
+ * Returns the ops event bus by name (deterministic per branch). Use from other stacks to obtain an IEventBus reference.
1263
+ */
1264
+ static opsEventBusFromConstruct(scope) {
1265
+ return EventBus3.fromEventBusName(
1266
+ scope,
1267
+ "ops-event-bus",
1268
+ OpsEventBus.getEventBusName(scope)
1269
+ );
1270
+ }
1271
+ /**
1272
+ * Returns the data store table by name. Use from other stacks (e.g. REST API Lambda) to obtain an ITable reference.
1273
+ */
1274
+ static dynamoDbDataStoreFromConstruct(scope, id = "dynamo-db-data-store") {
1275
+ return Table2.fromTableName(scope, id, getDynamoDbDataStoreTableName(scope));
1276
+ }
1277
+ get serviceType() {
1278
+ return _OpenHiDataService.SERVICE_TYPE;
1279
+ }
1280
+ constructor(ohEnv, props = {}) {
1281
+ super(ohEnv, _OpenHiDataService.SERVICE_TYPE, props);
1282
+ this.props = props;
1283
+ this.dataEventBus = this.createDataEventBus();
1284
+ this.opsEventBus = this.createOpsEventBus();
1285
+ this.dataStoreChangeStream = new kinesis.Stream(
1286
+ this,
1287
+ "data-store-change-stream",
1288
+ {
1289
+ streamName: `openhi-dstore-cdc-${this.branchHash}`,
1290
+ streamMode: kinesis.StreamMode.ON_DEMAND,
1291
+ // CDK default for kinesis.Stream is RETAIN, which strands the stream
1292
+ // when a non-prod stack is destroyed. Use the service's policy so
1293
+ // non-prod tears down cleanly while prod retains.
1294
+ removalPolicy: this.removalPolicy
1295
+ }
1296
+ );
1297
+ this.dataStore = this.createDataStore();
1298
+ this.dataStoreHistoricalArchive = new DataStoreHistoricalArchive(
1299
+ this,
1300
+ "data-store-historical-archive",
1301
+ {
1302
+ kinesisStream: this.dataStoreChangeStream,
1303
+ removalPolicy: this.removalPolicy,
1304
+ stackHash: this.stackHash,
1305
+ dataEventBus: this.dataEventBus
1306
+ }
1307
+ );
1308
+ this.dataStorePostgresReplica = new DataStorePostgresReplica(
1309
+ this,
1310
+ "data-store-postgres-replica",
1311
+ {
1312
+ kinesisStream: this.dataStoreChangeStream,
1313
+ removalPolicy: this.removalPolicy,
1314
+ stackHash: this.stackHash,
1315
+ branchHash: this.branchHash
1316
+ }
1317
+ );
1318
+ }
1319
+ /**
1320
+ * Creates the data event bus.
1321
+ * Override to customize.
1322
+ */
1323
+ createDataEventBus() {
1324
+ return new DataEventBus(this);
1325
+ }
1326
+ /**
1327
+ * Creates the ops event bus.
1328
+ * Override to customize.
1329
+ */
1330
+ createOpsEventBus() {
1331
+ return new OpsEventBus(this);
1332
+ }
1333
+ /**
1334
+ * Creates the single-table DynamoDB data store.
1335
+ * Override to customize.
1336
+ */
1337
+ createDataStore() {
1338
+ return new DynamoDbDataStore(this, "dynamo-db-data-store", {
1339
+ kinesisStream: this.dataStoreChangeStream,
1340
+ stream: StreamViewType.NEW_AND_OLD_IMAGES
1341
+ });
1342
+ }
1343
+ };
1344
+ _OpenHiDataService.SERVICE_TYPE = "data";
1345
+ var OpenHiDataService = _OpenHiDataService;
1346
+
1347
+ // src/services/open-hi-auth-service.ts
1213
1348
  var _OpenHiAuthService = class _OpenHiAuthService extends OpenHiService {
1349
+ constructor(ohEnv, props = {}) {
1350
+ super(ohEnv, _OpenHiAuthService.SERVICE_TYPE, props);
1351
+ /**
1352
+ * Cross-stack reference to the data store table. Cached so repeated
1353
+ * lookups share a single CDK construct id ("dynamo-db-data-store") in
1354
+ * this stack — a second `Table.fromTableName` call under the same scope
1355
+ * would collide.
1356
+ */
1357
+ this._dataStoreTable = null;
1358
+ this.props = props;
1359
+ this.userPoolKmsKey = this.createUserPoolKmsKey();
1360
+ this.preTokenGenerationLambda = this.createPreTokenGenerationLambda();
1361
+ this.postAuthenticationLambda = this.createPostAuthenticationLambda();
1362
+ this.postConfirmationLambda = this.createPostConfirmationLambda();
1363
+ this.userPool = this.createUserPool();
1364
+ this.grantPreTokenGenerationPermissions();
1365
+ this.grantPostAuthenticationPermissions();
1366
+ this.grantPostConfirmationPermissions();
1367
+ this.userPoolClient = this.createUserPoolClient();
1368
+ this.userPoolDomain = this.createUserPoolDomain();
1369
+ this.fixtureSeederClient = this.createFixtureSeederClient();
1370
+ }
1214
1371
  /**
1215
1372
  * Returns an IUserPool by looking up the Auth stack's User Pool ID from SSM.
1216
1373
  */
@@ -1282,18 +1439,6 @@ var _OpenHiAuthService = class _OpenHiAuthService extends OpenHiService {
1282
1439
  get serviceType() {
1283
1440
  return _OpenHiAuthService.SERVICE_TYPE;
1284
1441
  }
1285
- constructor(ohEnv, props = {}) {
1286
- super(ohEnv, _OpenHiAuthService.SERVICE_TYPE, props);
1287
- this.props = props;
1288
- this.userPoolKmsKey = this.createUserPoolKmsKey();
1289
- this.preTokenGenerationLambda = this.createPreTokenGenerationLambda();
1290
- this.postAuthenticationLambda = this.createPostAuthenticationLambda();
1291
- this.userPool = this.createUserPool();
1292
- this.grantPostAuthenticationPermissions();
1293
- this.userPoolClient = this.createUserPoolClient();
1294
- this.userPoolDomain = this.createUserPoolDomain();
1295
- this.fixtureSeederClient = this.createFixtureSeederClient();
1296
- }
1297
1442
  /**
1298
1443
  * Creates the KMS key for the Cognito User Pool and exports its ARN to SSM.
1299
1444
  * Look up via {@link OpenHiAuthService.userPoolKmsKeyFromConstruct}.
@@ -1309,11 +1454,15 @@ var _OpenHiAuthService = class _OpenHiAuthService extends OpenHiService {
1309
1454
  return key;
1310
1455
  }
1311
1456
  /**
1312
- * Creates the Pre Token Generation Lambda (Cognito trigger). Phase 2 will add
1313
- * openhi_* claims to the access token only; trigger version V2_0 may be required.
1457
+ * Creates the Pre Token Generation Lambda (Cognito trigger). On every
1458
+ * sign-in and token refresh the Lambda resolves the User by Cognito `sub`
1459
+ * (GSI2) and injects `ohi_tid`, `ohi_wid`, `ohi_uid`, `ohi_uname` into
1460
+ * both the ID token and the access token (ADR 2026-03-17-01).
1314
1461
  */
1315
1462
  createPreTokenGenerationLambda() {
1316
- const construct = new PreTokenGenerationLambda(this);
1463
+ const construct = new PreTokenGenerationLambda(this, {
1464
+ dynamoTableName: this.dataStoreTable().tableName
1465
+ });
1317
1466
  return construct.lambda;
1318
1467
  }
1319
1468
  /**
@@ -1325,6 +1474,25 @@ var _OpenHiAuthService = class _OpenHiAuthService extends OpenHiService {
1325
1474
  const construct = new PostAuthenticationLambda(this);
1326
1475
  return construct.lambda;
1327
1476
  }
1477
+ /**
1478
+ * Creates the Post Confirmation Lambda (Cognito trigger). On sign-up
1479
+ * confirmation, writes the new user's default Tenant, Workspace,
1480
+ * Memberships, and `tenant-user` RoleAssignment, plus a User record
1481
+ * carrying the Cognito `sub` and current tenant/workspace pointers
1482
+ * (ADR 2026-03-17-01 invariants).
1483
+ */
1484
+ createPostConfirmationLambda() {
1485
+ const construct = new PostConfirmationLambda(this, {
1486
+ dynamoTableName: this.dataStoreTable().tableName
1487
+ });
1488
+ return construct.lambda;
1489
+ }
1490
+ dataStoreTable() {
1491
+ if (this._dataStoreTable === null) {
1492
+ this._dataStoreTable = OpenHiDataService.dynamoDbDataStoreFromConstruct(this);
1493
+ }
1494
+ return this._dataStoreTable;
1495
+ }
1328
1496
  /**
1329
1497
  * Creates the Cognito User Pool and exports its ID to SSM.
1330
1498
  * Look up via {@link OpenHiAuthService.userPoolFromConstruct}.
@@ -1344,6 +1512,10 @@ var _OpenHiAuthService = class _OpenHiAuthService extends OpenHiService {
1344
1512
  UserPoolOperation.POST_AUTHENTICATION,
1345
1513
  this.postAuthenticationLambda
1346
1514
  );
1515
+ userPool.addTrigger(
1516
+ UserPoolOperation.POST_CONFIRMATION,
1517
+ this.postConfirmationLambda
1518
+ );
1347
1519
  new DiscoverableStringParameter(this, "user-pool-param", {
1348
1520
  ssmParamName: CognitoUserPool.SSM_PARAM_NAME,
1349
1521
  stringValue: userPool.userPoolId,
@@ -1351,6 +1523,27 @@ var _OpenHiAuthService = class _OpenHiAuthService extends OpenHiService {
1351
1523
  });
1352
1524
  return userPool;
1353
1525
  }
1526
+ /**
1527
+ * Grants the Pre Token Generation Lambda read-only access on the data
1528
+ * store table and its GSIs. The Lambda only needs:
1529
+ * - `Query` on GSI2 to resolve a User by Cognito `sub`
1530
+ * - `GetItem` on the base table for direct User reads
1531
+ *
1532
+ * No write or scan access: a User missing `currentTenant`/`currentWorkspace`
1533
+ * falls into the absent-claims path; repair belongs in a separate backfill.
1534
+ */
1535
+ grantPreTokenGenerationPermissions() {
1536
+ const dataStoreTable = this.dataStoreTable();
1537
+ const dynamoActions = ["dynamodb:GetItem", "dynamodb:Query"];
1538
+ dataStoreTable.grant(this.preTokenGenerationLambda, ...dynamoActions);
1539
+ this.preTokenGenerationLambda.addToRolePolicy(
1540
+ new PolicyStatement({
1541
+ effect: Effect.ALLOW,
1542
+ actions: [...dynamoActions],
1543
+ resources: [`${dataStoreTable.tableArn}/index/*`]
1544
+ })
1545
+ );
1546
+ }
1354
1547
  /**
1355
1548
  * Grants the Post Authentication Lambda permission to call
1356
1549
  * `cognito-idp:AdminUserGlobalSignOut`.
@@ -1378,6 +1571,28 @@ var _OpenHiAuthService = class _OpenHiAuthService extends OpenHiService {
1378
1571
  })
1379
1572
  );
1380
1573
  }
1574
+ /**
1575
+ * Grants the Post Confirmation Lambda write access to the data store
1576
+ * table (and its GSIs) so it can seed the new user's Tenant, Workspace,
1577
+ * Memberships, RoleAssignment, and User records on sign-up confirmation.
1578
+ */
1579
+ grantPostConfirmationPermissions() {
1580
+ const dataStoreTable = this.dataStoreTable();
1581
+ const dynamoActions = [
1582
+ "dynamodb:PutItem",
1583
+ "dynamodb:UpdateItem",
1584
+ "dynamodb:BatchWriteItem",
1585
+ "dynamodb:DescribeTable"
1586
+ ];
1587
+ dataStoreTable.grant(this.postConfirmationLambda, ...dynamoActions);
1588
+ this.postConfirmationLambda.addToRolePolicy(
1589
+ new PolicyStatement({
1590
+ effect: Effect.ALLOW,
1591
+ actions: [...dynamoActions],
1592
+ resources: [`${dataStoreTable.tableArn}/index/*`]
1593
+ })
1594
+ );
1595
+ }
1381
1596
  /**
1382
1597
  * Creates the User Pool Client and exports its ID to SSM (AUTH service type).
1383
1598
  * Look up via {@link OpenHiAuthService.userPoolClientFromConstruct}.
@@ -1562,7 +1777,7 @@ import {
1562
1777
  } from "aws-cdk-lib/aws-apigatewayv2";
1563
1778
  import { HttpUserPoolAuthorizer } from "aws-cdk-lib/aws-apigatewayv2-authorizers";
1564
1779
  import { HttpLambdaIntegration } from "aws-cdk-lib/aws-apigatewayv2-integrations";
1565
- import { Effect, PolicyStatement as PolicyStatement2 } from "aws-cdk-lib/aws-iam";
1780
+ import { Effect as Effect2, PolicyStatement as PolicyStatement2 } from "aws-cdk-lib/aws-iam";
1566
1781
  import {
1567
1782
  ARecord,
1568
1783
  HostedZone as HostedZone3,
@@ -1571,154 +1786,53 @@ import {
1571
1786
  import { ApiGatewayv2DomainProperties } from "aws-cdk-lib/aws-route53-targets";
1572
1787
  import { Duration as Duration6 } from "aws-cdk-lib/core";
1573
1788
 
1574
- // src/services/open-hi-data-service.ts
1575
- import { StreamViewType, Table as Table2 } from "aws-cdk-lib/aws-dynamodb";
1576
- import { EventBus as EventBus3 } from "aws-cdk-lib/aws-events";
1577
- import * as kinesis from "aws-cdk-lib/aws-kinesis";
1578
- var _OpenHiDataService = class _OpenHiDataService extends OpenHiService {
1579
- /**
1580
- * Returns the data event bus by name (deterministic per branch). Use from other stacks to obtain an IEventBus reference.
1581
- */
1582
- static dataEventBusFromConstruct(scope) {
1583
- return EventBus3.fromEventBusName(
1584
- scope,
1585
- "data-event-bus",
1586
- DataEventBus.getEventBusName(scope)
1587
- );
1588
- }
1589
- /**
1590
- * Returns the ops event bus by name (deterministic per branch). Use from other stacks to obtain an IEventBus reference.
1591
- */
1592
- static opsEventBusFromConstruct(scope) {
1593
- return EventBus3.fromEventBusName(
1594
- scope,
1595
- "ops-event-bus",
1596
- OpsEventBus.getEventBusName(scope)
1597
- );
1598
- }
1599
- /**
1600
- * Returns the data store table by name. Use from other stacks (e.g. REST API Lambda) to obtain an ITable reference.
1601
- */
1602
- static dynamoDbDataStoreFromConstruct(scope, id = "dynamo-db-data-store") {
1603
- return Table2.fromTableName(scope, id, getDynamoDbDataStoreTableName(scope));
1604
- }
1605
- get serviceType() {
1606
- return _OpenHiDataService.SERVICE_TYPE;
1607
- }
1608
- constructor(ohEnv, props = {}) {
1609
- super(ohEnv, _OpenHiDataService.SERVICE_TYPE, props);
1610
- this.props = props;
1611
- this.dataEventBus = this.createDataEventBus();
1612
- this.opsEventBus = this.createOpsEventBus();
1613
- this.dataStoreChangeStream = new kinesis.Stream(
1614
- this,
1615
- "data-store-change-stream",
1616
- {
1617
- streamName: `openhi-dstore-cdc-${this.branchHash}`,
1618
- streamMode: kinesis.StreamMode.ON_DEMAND,
1619
- // CDK default for kinesis.Stream is RETAIN, which strands the stream
1620
- // when a non-prod stack is destroyed. Use the service's policy so
1621
- // non-prod tears down cleanly while prod retains.
1622
- removalPolicy: this.removalPolicy
1623
- }
1624
- );
1625
- this.dataStore = this.createDataStore();
1626
- this.dataStoreHistoricalArchive = new DataStoreHistoricalArchive(
1627
- this,
1628
- "data-store-historical-archive",
1629
- {
1630
- kinesisStream: this.dataStoreChangeStream,
1631
- removalPolicy: this.removalPolicy,
1632
- stackHash: this.stackHash,
1633
- dataEventBus: this.dataEventBus
1634
- }
1635
- );
1636
- this.dataStorePostgresReplica = new DataStorePostgresReplica(
1637
- this,
1638
- "data-store-postgres-replica",
1639
- {
1640
- kinesisStream: this.dataStoreChangeStream,
1641
- removalPolicy: this.removalPolicy,
1642
- stackHash: this.stackHash,
1643
- branchHash: this.branchHash
1644
- }
1645
- );
1646
- }
1647
- /**
1648
- * Creates the data event bus.
1649
- * Override to customize.
1650
- */
1651
- createDataEventBus() {
1652
- return new DataEventBus(this);
1653
- }
1654
- /**
1655
- * Creates the ops event bus.
1656
- * Override to customize.
1657
- */
1658
- createOpsEventBus() {
1659
- return new OpsEventBus(this);
1660
- }
1661
- /**
1662
- * Creates the single-table DynamoDB data store.
1663
- * Override to customize.
1664
- */
1665
- createDataStore() {
1666
- return new DynamoDbDataStore(this, "dynamo-db-data-store", {
1667
- kinesisStream: this.dataStoreChangeStream,
1668
- stream: StreamViewType.NEW_AND_OLD_IMAGES
1669
- });
1670
- }
1671
- };
1672
- _OpenHiDataService.SERVICE_TYPE = "data";
1673
- var OpenHiDataService = _OpenHiDataService;
1674
-
1675
1789
  // src/data/lambda/cors-options-lambda.ts
1676
- import fs5 from "fs";
1677
- import path5 from "path";
1678
- import { Runtime as Runtime5 } from "aws-cdk-lib/aws-lambda";
1679
- import { NodejsFunction as NodejsFunction5 } from "aws-cdk-lib/aws-lambda-nodejs";
1680
- import { Construct as Construct7 } from "constructs";
1681
- var HANDLER_NAME5 = "cors-options-lambda.handler.js";
1682
- function resolveHandlerEntry5(dirname) {
1683
- const sameDir = path5.join(dirname, HANDLER_NAME5);
1684
- if (fs5.existsSync(sameDir)) {
1790
+ import fs6 from "fs";
1791
+ import path6 from "path";
1792
+ import { Runtime as Runtime6 } from "aws-cdk-lib/aws-lambda";
1793
+ import { NodejsFunction as NodejsFunction6 } from "aws-cdk-lib/aws-lambda-nodejs";
1794
+ import { Construct as Construct8 } from "constructs";
1795
+ var HANDLER_NAME6 = "cors-options-lambda.handler.js";
1796
+ function resolveHandlerEntry6(dirname) {
1797
+ const sameDir = path6.join(dirname, HANDLER_NAME6);
1798
+ if (fs6.existsSync(sameDir)) {
1685
1799
  return sameDir;
1686
1800
  }
1687
- const fromLib = path5.join(dirname, "..", "..", "..", "lib", HANDLER_NAME5);
1801
+ const fromLib = path6.join(dirname, "..", "..", "..", "lib", HANDLER_NAME6);
1688
1802
  return fromLib;
1689
1803
  }
1690
- var CorsOptionsLambda = class extends Construct7 {
1804
+ var CorsOptionsLambda = class extends Construct8 {
1691
1805
  constructor(scope, id = "cors-options-lambda") {
1692
1806
  super(scope, id);
1693
- this.lambda = new NodejsFunction5(this, "handler", {
1694
- entry: resolveHandlerEntry5(__dirname),
1695
- runtime: Runtime5.NODEJS_LATEST,
1807
+ this.lambda = new NodejsFunction6(this, "handler", {
1808
+ entry: resolveHandlerEntry6(__dirname),
1809
+ runtime: Runtime6.NODEJS_LATEST,
1696
1810
  memorySize: 128
1697
1811
  });
1698
1812
  }
1699
1813
  };
1700
1814
 
1701
1815
  // src/data/lambda/rest-api-lambda.ts
1702
- import fs6 from "fs";
1703
- import path6 from "path";
1704
- import { Runtime as Runtime6 } from "aws-cdk-lib/aws-lambda";
1705
- import { NodejsFunction as NodejsFunction6 } from "aws-cdk-lib/aws-lambda-nodejs";
1706
- import { Construct as Construct8 } from "constructs";
1707
- var HANDLER_NAME6 = "rest-api-lambda.handler.js";
1708
- function resolveHandlerEntry6(dirname) {
1709
- const sameDir = path6.join(dirname, HANDLER_NAME6);
1710
- if (fs6.existsSync(sameDir)) {
1816
+ import fs7 from "fs";
1817
+ import path7 from "path";
1818
+ import { Runtime as Runtime7 } from "aws-cdk-lib/aws-lambda";
1819
+ import { NodejsFunction as NodejsFunction7 } from "aws-cdk-lib/aws-lambda-nodejs";
1820
+ import { Construct as Construct9 } from "constructs";
1821
+ var HANDLER_NAME7 = "rest-api-lambda.handler.js";
1822
+ function resolveHandlerEntry7(dirname) {
1823
+ const sameDir = path7.join(dirname, HANDLER_NAME7);
1824
+ if (fs7.existsSync(sameDir)) {
1711
1825
  return sameDir;
1712
1826
  }
1713
- const fromLib = path6.join(dirname, "..", "..", "..", "lib", HANDLER_NAME6);
1827
+ const fromLib = path7.join(dirname, "..", "..", "..", "lib", HANDLER_NAME7);
1714
1828
  return fromLib;
1715
1829
  }
1716
- var RestApiLambda = class extends Construct8 {
1830
+ var RestApiLambda = class extends Construct9 {
1717
1831
  constructor(scope, props) {
1718
1832
  super(scope, "rest-api-lambda");
1719
- this.lambda = new NodejsFunction6(this, "handler", {
1720
- entry: resolveHandlerEntry6(__dirname),
1721
- runtime: Runtime6.NODEJS_LATEST,
1833
+ this.lambda = new NodejsFunction7(this, "handler", {
1834
+ entry: resolveHandlerEntry7(__dirname),
1835
+ runtime: Runtime7.NODEJS_LATEST,
1722
1836
  memorySize: 1024,
1723
1837
  environment: {
1724
1838
  DYNAMO_TABLE_NAME: props.dynamoTableName,
@@ -1861,7 +1975,7 @@ var _OpenHiRestApiService = class _OpenHiRestApiService extends OpenHiService {
1861
1975
  });
1862
1976
  lambda.addToRolePolicy(
1863
1977
  new PolicyStatement2({
1864
- effect: Effect.ALLOW,
1978
+ effect: Effect2.ALLOW,
1865
1979
  actions: [
1866
1980
  "rds-data:ExecuteStatement",
1867
1981
  "rds-data:BatchExecuteStatement"
@@ -1871,7 +1985,7 @@ var _OpenHiRestApiService = class _OpenHiRestApiService extends OpenHiService {
1871
1985
  );
1872
1986
  lambda.addToRolePolicy(
1873
1987
  new PolicyStatement2({
1874
- effect: Effect.ALLOW,
1988
+ effect: Effect2.ALLOW,
1875
1989
  actions: ["secretsmanager:GetSecretValue"],
1876
1990
  resources: [postgresSecretArn]
1877
1991
  })
@@ -1890,14 +2004,14 @@ var _OpenHiRestApiService = class _OpenHiRestApiService extends OpenHiService {
1890
2004
  dataStoreTable.grant(lambda, ...dynamoActions);
1891
2005
  lambda.addToRolePolicy(
1892
2006
  new PolicyStatement2({
1893
- effect: Effect.ALLOW,
2007
+ effect: Effect2.ALLOW,
1894
2008
  actions: [...dynamoActions],
1895
2009
  resources: [`${dataStoreTable.tableArn}/index/*`]
1896
2010
  })
1897
2011
  );
1898
2012
  lambda.addToRolePolicy(
1899
2013
  new PolicyStatement2({
1900
- effect: Effect.ALLOW,
2014
+ effect: Effect2.ALLOW,
1901
2015
  actions: [
1902
2016
  "ssm:GetParameter",
1903
2017
  "ssm:GetParameters",
@@ -2076,6 +2190,7 @@ export {
2076
2190
  POSTGRES_REPLICA_DATABASE_NAME_SSM_NAME,
2077
2191
  POSTGRES_REPLICA_SECRET_ARN_SSM_NAME,
2078
2192
  PostAuthenticationLambda,
2193
+ PostConfirmationLambda,
2079
2194
  PreTokenGenerationLambda,
2080
2195
  REST_API_BASE_URL_SSM_NAME,
2081
2196
  RootGraphqlApi,