@openhi/constructs 0.0.115 → 0.0.117

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
@@ -1176,7 +1176,9 @@ var WorkflowDedupConsumerNameInvalidError = class extends Error {
1176
1176
  };
1177
1177
 
1178
1178
  // src/components/event-bridge/data-event-bus.ts
1179
- import { EventBus } from "aws-cdk-lib/aws-events";
1179
+ import { Duration as Duration2, Stack as Stack2 } from "aws-cdk-lib";
1180
+ import { Archive, EventBus } from "aws-cdk-lib/aws-events";
1181
+ var DEFAULT_ARCHIVE_RETENTION = Duration2.days(7);
1180
1182
  var DataEventBus = class _DataEventBus extends EventBus {
1181
1183
  /*****************************************************************************
1182
1184
  *
@@ -1189,11 +1191,19 @@ var DataEventBus = class _DataEventBus extends EventBus {
1189
1191
  const stack = OpenHiService.of(scope);
1190
1192
  return `datav1${stack.branchHash}`;
1191
1193
  }
1192
- constructor(scope, props) {
1194
+ constructor(scope, props = void 0) {
1195
+ const { archiveRetention, ...busProps } = props ?? {};
1193
1196
  super(scope, "data-event-bus-v1", {
1194
- ...props,
1197
+ ...busProps,
1195
1198
  eventBusName: _DataEventBus.getEventBusName(scope)
1196
1199
  });
1200
+ this.replayArchive = new Archive(this, "Archive", {
1201
+ sourceEventBus: this,
1202
+ archiveName: `${_DataEventBus.getEventBusName(scope)}-archive`,
1203
+ description: "Replay archive for the OpenHI data event bus (data-store change notifications).",
1204
+ eventPattern: { account: [Stack2.of(this).account] },
1205
+ retention: archiveRetention ?? DEFAULT_ARCHIVE_RETENTION
1206
+ });
1197
1207
  }
1198
1208
  };
1199
1209
 
@@ -1244,7 +1254,7 @@ var ControlEventBus = class _ControlEventBus extends EventBus3 {
1244
1254
  // src/components/postgres/data-store-postgres-replica.ts
1245
1255
  import fs5 from "fs";
1246
1256
  import path5 from "path";
1247
- import { Duration as Duration2, Stack as Stack2 } from "aws-cdk-lib";
1257
+ import { Duration as Duration3, Stack as Stack3 } from "aws-cdk-lib";
1248
1258
  import * as ec2 from "aws-cdk-lib/aws-ec2";
1249
1259
  import { Runtime as Runtime5, StartingPosition } from "aws-cdk-lib/aws-lambda";
1250
1260
  import { KinesisEventSource } from "aws-cdk-lib/aws-lambda-event-sources";
@@ -1310,7 +1320,7 @@ var DataStorePostgresReplica = class extends Construct6 {
1310
1320
  super(scope, id);
1311
1321
  this.databaseName = props.databaseName ?? DEFAULT_DATABASE_NAME;
1312
1322
  this.schemaName = getPostgresReplicaSchemaName(props.branchHash);
1313
- const region = Stack2.of(this).region;
1323
+ const region = Stack3.of(this).region;
1314
1324
  this.vpc = props.vpc ?? new ec2.Vpc(this, "Vpc", {
1315
1325
  availabilityZones: [`${region}a`, `${region}b`],
1316
1326
  natGateways: 0,
@@ -1346,7 +1356,7 @@ var DataStorePostgresReplica = class extends Construct6 {
1346
1356
  entry: resolveHandlerEntry5(__dirname),
1347
1357
  runtime: Runtime5.NODEJS_LATEST,
1348
1358
  memorySize: 512,
1349
- timeout: Duration2.minutes(1),
1359
+ timeout: Duration3.minutes(1),
1350
1360
  vpc: this.vpc,
1351
1361
  vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED },
1352
1362
  description: "Replicates DynamoDB current-resource changes into the Postgres `resources` JSONB table (ADR 2026-04-17-01).",
@@ -1373,7 +1383,7 @@ var DataStorePostgresReplica = class extends Construct6 {
1373
1383
  new KinesisEventSource(props.kinesisStream, {
1374
1384
  startingPosition: StartingPosition.LATEST,
1375
1385
  batchSize: 100,
1376
- maxBatchingWindow: Duration2.seconds(5),
1386
+ maxBatchingWindow: Duration3.seconds(5),
1377
1387
  retryAttempts: 10,
1378
1388
  bisectBatchOnError: true,
1379
1389
  parallelizationFactor: 2,
@@ -1406,7 +1416,7 @@ var DataStorePostgresReplica = class extends Construct6 {
1406
1416
  };
1407
1417
 
1408
1418
  // src/components/route-53/child-hosted-zone.ts
1409
- import { Duration as Duration3 } from "aws-cdk-lib";
1419
+ import { Duration as Duration4 } from "aws-cdk-lib";
1410
1420
  import {
1411
1421
  HostedZone,
1412
1422
  NsRecord
@@ -1418,7 +1428,7 @@ var ChildHostedZone = class extends HostedZone {
1418
1428
  zone: props.parentHostedZone,
1419
1429
  recordName: this.zoneName,
1420
1430
  values: this.hostedZoneNameServers || [],
1421
- ttl: Duration3.minutes(5)
1431
+ ttl: Duration4.minutes(5)
1422
1432
  });
1423
1433
  }
1424
1434
  };
@@ -1432,14 +1442,39 @@ import { Construct as Construct7 } from "constructs";
1432
1442
  var RootHostedZone = class extends Construct7 {
1433
1443
  };
1434
1444
 
1445
+ // src/components/static-hosting/static-content.ts
1446
+ import { Bucket as Bucket3 } from "aws-cdk-lib/aws-s3";
1447
+ import { BucketDeployment, Source } from "aws-cdk-lib/aws-s3-deployment";
1448
+ import { paramCase as paramCase2 } from "change-case";
1449
+ import { Construct as Construct9 } from "constructs";
1450
+
1435
1451
  // src/components/static-hosting/static-hosting.ts
1452
+ import * as fs6 from "fs";
1453
+ import * as path6 from "path";
1454
+ import { Duration as Duration5 } from "aws-cdk-lib";
1436
1455
  import {
1456
+ AccessLevel,
1457
+ AllowedMethods,
1458
+ CacheCookieBehavior,
1459
+ CacheHeaderBehavior,
1437
1460
  CachePolicy,
1438
- Distribution
1461
+ CacheQueryStringBehavior,
1462
+ Distribution,
1463
+ LambdaEdgeEventType,
1464
+ S3OriginAccessControl,
1465
+ Signing,
1466
+ ViewerProtocolPolicy
1439
1467
  } from "aws-cdk-lib/aws-cloudfront";
1440
1468
  import { S3BucketOrigin } from "aws-cdk-lib/aws-cloudfront-origins";
1469
+ import { Runtime as Runtime6 } from "aws-cdk-lib/aws-lambda";
1470
+ import { NodejsFunction as NodejsFunction6 } from "aws-cdk-lib/aws-lambda-nodejs";
1471
+ import { LogGroup, RetentionDays } from "aws-cdk-lib/aws-logs";
1472
+ import {
1473
+ ARecord,
1474
+ RecordTarget
1475
+ } from "aws-cdk-lib/aws-route53";
1476
+ import { CloudFrontTarget } from "aws-cdk-lib/aws-route53-targets";
1441
1477
  import { Bucket as Bucket2 } from "aws-cdk-lib/aws-s3";
1442
- import { Duration as Duration4 } from "aws-cdk-lib/core";
1443
1478
  import { Construct as Construct8 } from "constructs";
1444
1479
  var STATIC_HOSTING_SERVICE_TYPE = "website";
1445
1480
  var _StaticHosting = class _StaticHosting extends Construct8 {
@@ -1447,6 +1482,7 @@ var _StaticHosting = class _StaticHosting extends Construct8 {
1447
1482
  super(scope, id);
1448
1483
  const stack = OpenHiService.of(scope);
1449
1484
  const serviceType = props.serviceType ?? STATIC_HOSTING_SERVICE_TYPE;
1485
+ const hostingMode = props.hostingMode ?? "spa";
1450
1486
  this.bucket = new Bucket2(this, "bucket", {
1451
1487
  blockPublicAccess: {
1452
1488
  blockPublicAcls: true,
@@ -1456,30 +1492,105 @@ var _StaticHosting = class _StaticHosting extends Construct8 {
1456
1492
  },
1457
1493
  ...props.bucketProps
1458
1494
  });
1459
- const origin = S3BucketOrigin.withOriginAccessControl(this.bucket);
1495
+ const handlerJs = path6.join(
1496
+ __dirname,
1497
+ "static-hosting.viewer-request-handler.js"
1498
+ );
1499
+ const handlerTs = path6.join(
1500
+ __dirname,
1501
+ "static-hosting.viewer-request-handler.ts"
1502
+ );
1503
+ const handlerEntry = fs6.existsSync(handlerJs) ? handlerJs : handlerTs;
1504
+ this.viewerRequestHandler = new NodejsFunction6(
1505
+ this,
1506
+ "viewer-request-handler",
1507
+ {
1508
+ entry: handlerEntry,
1509
+ handler: hostingMode === "static" ? "staticHandler" : "spaHandler",
1510
+ memorySize: 128,
1511
+ runtime: Runtime6.NODEJS_LATEST,
1512
+ logGroup: new LogGroup(this, "viewer-request-handler-log-group", {
1513
+ retention: RetentionDays.ONE_MONTH
1514
+ })
1515
+ }
1516
+ );
1460
1517
  const cachePolicy = new CachePolicy(this, "cache-policy", {
1461
- cachePolicyName: `static-hosting-10s-${stack.branchHash}`,
1462
- comment: "Low TTL (10s) for static hosting; no invalidation",
1463
- defaultTtl: Duration4.seconds(10),
1464
- minTtl: Duration4.seconds(0),
1465
- maxTtl: Duration4.seconds(10)
1466
- });
1518
+ cachePolicyName: `static-hosting-${stack.branchHash}`,
1519
+ comment: "Static hosting default: 60s default / 300s max, gzip+brotli.",
1520
+ defaultTtl: Duration5.seconds(60),
1521
+ minTtl: Duration5.seconds(0),
1522
+ maxTtl: Duration5.seconds(300),
1523
+ headerBehavior: CacheHeaderBehavior.none(),
1524
+ queryStringBehavior: CacheQueryStringBehavior.none(),
1525
+ cookieBehavior: CacheCookieBehavior.none(),
1526
+ enableAcceptEncodingGzip: true,
1527
+ enableAcceptEncodingBrotli: true,
1528
+ ...props.cachePolicyProps
1529
+ });
1530
+ const oac = new S3OriginAccessControl(this, "origin-access-control", {
1531
+ signing: Signing.SIGV4_NO_OVERRIDE
1532
+ });
1533
+ const origin = S3BucketOrigin.withOriginAccessControl(this.bucket, {
1534
+ originAccessControl: oac,
1535
+ originAccessLevels: [AccessLevel.READ]
1536
+ });
1537
+ const hasCustomDomain = props.certificate !== void 0 && props.hostedZone !== void 0 && props.domainNames !== void 0 && props.domainNames.length > 0;
1467
1538
  this.distribution = new Distribution(this, "distribution", {
1539
+ comment: `Static hosting distribution for ${props.description ?? id}`,
1540
+ ...hasCustomDomain ? {
1541
+ certificate: props.certificate,
1542
+ domainNames: [...props.domainNames]
1543
+ } : {},
1544
+ defaultRootObject: "index.html",
1468
1545
  defaultBehavior: {
1469
1546
  origin,
1470
- cachePolicy
1547
+ viewerProtocolPolicy: ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
1548
+ cachePolicy,
1549
+ allowedMethods: AllowedMethods.ALLOW_GET_HEAD_OPTIONS,
1550
+ edgeLambdas: [
1551
+ {
1552
+ functionVersion: this.viewerRequestHandler.currentVersion,
1553
+ eventType: LambdaEdgeEventType.VIEWER_REQUEST,
1554
+ includeBody: false
1555
+ }
1556
+ ]
1471
1557
  },
1472
1558
  ...props.distributionProps
1473
1559
  });
1560
+ if (hasCustomDomain) {
1561
+ props.domainNames.forEach((domainName, index) => {
1562
+ new ARecord(this, `dns-record-${index}`, {
1563
+ zone: props.hostedZone,
1564
+ recordName: domainName,
1565
+ target: RecordTarget.fromAlias(
1566
+ new CloudFrontTarget(this.distribution)
1567
+ )
1568
+ });
1569
+ });
1570
+ }
1474
1571
  new DiscoverableStringParameter(this, "bucket-arn-param", {
1475
1572
  ssmParamName: _StaticHosting.SSM_PARAM_NAME_BUCKET_ARN,
1476
1573
  serviceType,
1477
- stringValue: this.bucket.bucketArn
1574
+ stringValue: this.bucket.bucketArn,
1575
+ description: `Static hosting bucket ARN (${props.description ?? id})`
1478
1576
  });
1479
1577
  new DiscoverableStringParameter(this, "distribution-arn-param", {
1480
1578
  ssmParamName: _StaticHosting.SSM_PARAM_NAME_DISTRIBUTION_ARN,
1481
1579
  serviceType,
1482
- stringValue: this.distribution.distributionArn
1580
+ stringValue: this.distribution.distributionArn,
1581
+ description: `Static hosting distribution ARN (${props.description ?? id})`
1582
+ });
1583
+ new DiscoverableStringParameter(this, "distribution-domain-param", {
1584
+ ssmParamName: _StaticHosting.SSM_PARAM_NAME_DISTRIBUTION_DOMAIN,
1585
+ serviceType,
1586
+ stringValue: this.distribution.domainName,
1587
+ description: `Static hosting distribution domain (${props.description ?? id})`
1588
+ });
1589
+ new DiscoverableStringParameter(this, "distribution-id-param", {
1590
+ ssmParamName: _StaticHosting.SSM_PARAM_NAME_DISTRIBUTION_ID,
1591
+ serviceType,
1592
+ stringValue: this.distribution.distributionId,
1593
+ description: `Static hosting distribution ID (${props.description ?? id})`
1483
1594
  });
1484
1595
  }
1485
1596
  };
@@ -1491,8 +1602,46 @@ _StaticHosting.SSM_PARAM_NAME_BUCKET_ARN = "STATIC_HOSTING_BUCKET_ARN";
1491
1602
  * SSM parameter name for the CloudFront distribution ARN.
1492
1603
  */
1493
1604
  _StaticHosting.SSM_PARAM_NAME_DISTRIBUTION_ARN = "STATIC_HOSTING_DISTRIBUTION_ARN";
1605
+ /**
1606
+ * SSM parameter name for the CloudFront distribution domain
1607
+ * (e.g. dXXXXX.cloudfront.net).
1608
+ */
1609
+ _StaticHosting.SSM_PARAM_NAME_DISTRIBUTION_DOMAIN = "STATIC_HOSTING_DISTRIBUTION_DOMAIN";
1610
+ /**
1611
+ * SSM parameter name for the CloudFront distribution ID.
1612
+ */
1613
+ _StaticHosting.SSM_PARAM_NAME_DISTRIBUTION_ID = "STATIC_HOSTING_DISTRIBUTION_ID";
1494
1614
  var StaticHosting = _StaticHosting;
1495
1615
 
1616
+ // src/components/static-hosting/static-content.ts
1617
+ var StaticContent = class extends Construct9 {
1618
+ constructor(scope, id, props) {
1619
+ super(scope, id);
1620
+ const stack = OpenHiService.of(scope);
1621
+ const {
1622
+ contentSourceDirectory,
1623
+ contentDestinationDirectory = "/",
1624
+ subDomain = stack.branchName,
1625
+ fullDomain,
1626
+ serviceType = STATIC_HOSTING_SERVICE_TYPE
1627
+ } = props;
1628
+ const keyPrefix = [paramCase2(subDomain), fullDomain].join(".");
1629
+ const bucketArn = DiscoverableStringParameter.valueForLookupName(this, {
1630
+ ssmParamName: StaticHosting.SSM_PARAM_NAME_BUCKET_ARN,
1631
+ serviceType
1632
+ });
1633
+ const bucket = Bucket3.fromBucketArn(this, "bucket", bucketArn);
1634
+ const isTestEnv = process.env.JEST_WORKER_ID !== void 0;
1635
+ const sources = isTestEnv ? [] : [Source.asset(contentSourceDirectory)];
1636
+ new BucketDeployment(this, "deploy", {
1637
+ sources,
1638
+ destinationBucket: bucket,
1639
+ retainOnDelete: false,
1640
+ destinationKeyPrefix: `${keyPrefix}${contentDestinationDirectory}`
1641
+ });
1642
+ }
1643
+ };
1644
+
1496
1645
  // src/services/open-hi-auth-service.ts
1497
1646
  import {
1498
1647
  LambdaVersion,
@@ -1503,7 +1652,7 @@ import {
1503
1652
  } from "aws-cdk-lib/aws-cognito";
1504
1653
  import { Effect as Effect6, PolicyStatement as PolicyStatement6 } from "aws-cdk-lib/aws-iam";
1505
1654
  import { Key as Key2 } from "aws-cdk-lib/aws-kms";
1506
- import { Stack as Stack6 } from "aws-cdk-lib/core";
1655
+ import { Stack as Stack7 } from "aws-cdk-lib/core";
1507
1656
 
1508
1657
  // src/services/open-hi-data-service.ts
1509
1658
  var import_config4 = __toESM(require_lib2());
@@ -1522,27 +1671,27 @@ import {
1522
1671
  import { StringParameter as StringParameter3 } from "aws-cdk-lib/aws-ssm";
1523
1672
 
1524
1673
  // src/workflows/control-plane/platform-deploy-bridge/platform-deploy-bridge.ts
1525
- import { Construct as Construct10 } from "constructs";
1674
+ import { Construct as Construct11 } from "constructs";
1526
1675
 
1527
1676
  // src/workflows/control-plane/platform-deploy-bridge/platform-deploy-bridge-lambda.ts
1528
- import fs6 from "fs";
1529
- import path6 from "path";
1530
- import { Duration as Duration5, Stack as Stack3 } from "aws-cdk-lib";
1677
+ import fs7 from "fs";
1678
+ import path7 from "path";
1679
+ import { Duration as Duration6, Stack as Stack4 } from "aws-cdk-lib";
1531
1680
  import { Rule } from "aws-cdk-lib/aws-events";
1532
1681
  import { LambdaFunction } from "aws-cdk-lib/aws-events-targets";
1533
1682
  import { Effect as Effect2, PolicyStatement as PolicyStatement2 } from "aws-cdk-lib/aws-iam";
1534
- import { Runtime as Runtime6 } from "aws-cdk-lib/aws-lambda";
1535
- import { NodejsFunction as NodejsFunction6 } from "aws-cdk-lib/aws-lambda-nodejs";
1536
- import { Construct as Construct9 } from "constructs";
1683
+ import { Runtime as Runtime7 } from "aws-cdk-lib/aws-lambda";
1684
+ import { NodejsFunction as NodejsFunction7 } from "aws-cdk-lib/aws-lambda-nodejs";
1685
+ import { Construct as Construct10 } from "constructs";
1537
1686
  var HANDLER_NAME6 = "platform-deploy-bridge.handler.js";
1538
1687
  function resolveHandlerEntry6(dirname) {
1539
- const sameDir = path6.join(dirname, HANDLER_NAME6);
1540
- if (fs6.existsSync(sameDir)) {
1688
+ const sameDir = path7.join(dirname, HANDLER_NAME6);
1689
+ if (fs7.existsSync(sameDir)) {
1541
1690
  return sameDir;
1542
1691
  }
1543
- return path6.join(dirname, "..", "..", "..", "..", "lib", HANDLER_NAME6);
1692
+ return path7.join(dirname, "..", "..", "..", "..", "lib", HANDLER_NAME6);
1544
1693
  }
1545
- var PlatformDeployBridgeLambda = class extends Construct9 {
1694
+ var PlatformDeployBridgeLambda = class extends Construct10 {
1546
1695
  constructor(scope, props) {
1547
1696
  super(scope, "platform-deploy-bridge-lambda");
1548
1697
  const service = OpenHiService.of(this);
@@ -1551,15 +1700,15 @@ var PlatformDeployBridgeLambda = class extends Construct9 {
1551
1700
  OPENHI_TAG_SUFFIX_REPO_NAME
1552
1701
  );
1553
1702
  const tagKeyPrefix = `${service.appName}:`;
1554
- const ownStackName = Stack3.of(this).stackName;
1555
- const ownSuffix = `-${service.serviceId}-${Stack3.of(this).account}-${Stack3.of(this).region}`;
1703
+ const ownStackName = Stack4.of(this).stackName;
1704
+ const ownSuffix = `-${service.serviceId}-${Stack4.of(this).account}-${Stack4.of(this).region}`;
1556
1705
  const sharedPrefix = ownStackName.endsWith(ownSuffix) ? ownStackName.slice(0, -ownSuffix.length) : service.branchHash;
1557
- const stackIdPrefix = `arn:aws:cloudformation:${Stack3.of(this).region}:${Stack3.of(this).account}:stack/${sharedPrefix}-`;
1558
- this.lambda = new NodejsFunction6(this, "handler", {
1706
+ const stackIdPrefix = `arn:aws:cloudformation:${Stack4.of(this).region}:${Stack4.of(this).account}:stack/${sharedPrefix}-`;
1707
+ this.lambda = new NodejsFunction7(this, "handler", {
1559
1708
  entry: resolveHandlerEntry6(__dirname),
1560
- runtime: Runtime6.NODEJS_LATEST,
1709
+ runtime: Runtime7.NODEJS_LATEST,
1561
1710
  memorySize: 256,
1562
- timeout: Duration5.seconds(30),
1711
+ timeout: Duration6.seconds(30),
1563
1712
  environment: {
1564
1713
  [CONTROL_EVENT_BUS_NAME_ENV_VAR]: props.controlEventBus.eventBusName,
1565
1714
  [OPENHI_REPO_TAG_KEY_ENV_VAR]: repoTagKey,
@@ -1571,7 +1720,7 @@ var PlatformDeployBridgeLambda = class extends Construct9 {
1571
1720
  effect: Effect2.ALLOW,
1572
1721
  actions: ["cloudformation:DescribeStacks"],
1573
1722
  resources: [
1574
- `arn:aws:cloudformation:${Stack3.of(this).region}:${Stack3.of(this).account}:stack/*`
1723
+ `arn:aws:cloudformation:${Stack4.of(this).region}:${Stack4.of(this).account}:stack/*`
1575
1724
  ]
1576
1725
  })
1577
1726
  );
@@ -1590,7 +1739,7 @@ var PlatformDeployBridgeLambda = class extends Construct9 {
1590
1739
  targets: [
1591
1740
  new LambdaFunction(this.lambda, {
1592
1741
  retryAttempts: 2,
1593
- maxEventAge: Duration5.hours(2)
1742
+ maxEventAge: Duration6.hours(2)
1594
1743
  })
1595
1744
  ]
1596
1745
  });
@@ -1598,7 +1747,7 @@ var PlatformDeployBridgeLambda = class extends Construct9 {
1598
1747
  };
1599
1748
 
1600
1749
  // src/workflows/control-plane/platform-deploy-bridge/platform-deploy-bridge.ts
1601
- var PlatformDeployBridge = class extends Construct10 {
1750
+ var PlatformDeployBridge = class extends Construct11 {
1602
1751
  constructor(scope, props) {
1603
1752
  super(scope, "platform-deploy-bridge");
1604
1753
  this.bridgeLambda = new PlatformDeployBridgeLambda(this, {
@@ -1791,31 +1940,31 @@ _OpenHiGlobalService.SERVICE_TYPE = "global";
1791
1940
  var OpenHiGlobalService = _OpenHiGlobalService;
1792
1941
 
1793
1942
  // src/workflows/control-plane/seed-demo-data/seed-demo-data-lambda.ts
1794
- import fs7 from "fs";
1795
- import path7 from "path";
1796
- import { Duration as Duration6, Stack as Stack4 } from "aws-cdk-lib";
1943
+ import fs8 from "fs";
1944
+ import path8 from "path";
1945
+ import { Duration as Duration7, Stack as Stack5 } from "aws-cdk-lib";
1797
1946
  import { Rule as Rule2 } from "aws-cdk-lib/aws-events";
1798
1947
  import { LambdaFunction as LambdaFunction2 } from "aws-cdk-lib/aws-events-targets";
1799
1948
  import { Effect as Effect3, PolicyStatement as PolicyStatement3 } from "aws-cdk-lib/aws-iam";
1800
- import { Runtime as Runtime7 } from "aws-cdk-lib/aws-lambda";
1801
- import { NodejsFunction as NodejsFunction7 } from "aws-cdk-lib/aws-lambda-nodejs";
1802
- import { Construct as Construct11 } from "constructs";
1949
+ import { Runtime as Runtime8 } from "aws-cdk-lib/aws-lambda";
1950
+ import { NodejsFunction as NodejsFunction8 } from "aws-cdk-lib/aws-lambda-nodejs";
1951
+ import { Construct as Construct12 } from "constructs";
1803
1952
  var HANDLER_NAME7 = "seed-demo-data.handler.js";
1804
1953
  function resolveHandlerEntry7(dirname) {
1805
- const sameDir = path7.join(dirname, HANDLER_NAME7);
1806
- if (fs7.existsSync(sameDir)) {
1954
+ const sameDir = path8.join(dirname, HANDLER_NAME7);
1955
+ if (fs8.existsSync(sameDir)) {
1807
1956
  return sameDir;
1808
1957
  }
1809
- return path7.join(dirname, "..", "..", "..", "..", "lib", HANDLER_NAME7);
1958
+ return path8.join(dirname, "..", "..", "..", "..", "lib", HANDLER_NAME7);
1810
1959
  }
1811
- var SeedDemoDataLambda = class extends Construct11 {
1960
+ var SeedDemoDataLambda = class extends Construct12 {
1812
1961
  constructor(scope, props) {
1813
1962
  super(scope, "seed-demo-data-lambda");
1814
- this.lambda = new NodejsFunction7(this, "handler", {
1963
+ this.lambda = new NodejsFunction8(this, "handler", {
1815
1964
  entry: resolveHandlerEntry7(__dirname),
1816
- runtime: Runtime7.NODEJS_LATEST,
1965
+ runtime: Runtime8.NODEJS_LATEST,
1817
1966
  memorySize: 512,
1818
- timeout: Duration6.minutes(2),
1967
+ timeout: Duration7.minutes(2),
1819
1968
  environment: {
1820
1969
  DYNAMO_TABLE_NAME: props.dataStoreTable.tableName,
1821
1970
  [SEED_DEMO_DATA_USER_POOL_ID_ENV_VAR]: props.userPool.userPoolId
@@ -1844,7 +1993,7 @@ var SeedDemoDataLambda = class extends Construct11 {
1844
1993
  "cognito-idp:AdminSetUserPassword"
1845
1994
  ],
1846
1995
  resources: [
1847
- Stack4.of(this).formatArn({
1996
+ Stack5.of(this).formatArn({
1848
1997
  service: "cognito-idp",
1849
1998
  resource: "userpool",
1850
1999
  resourceName: props.userPool.userPoolId
@@ -1861,7 +2010,7 @@ var SeedDemoDataLambda = class extends Construct11 {
1861
2010
  targets: [
1862
2011
  new LambdaFunction2(this.lambda, {
1863
2012
  retryAttempts: 2,
1864
- maxEventAge: Duration6.hours(2)
2013
+ maxEventAge: Duration7.hours(2)
1865
2014
  })
1866
2015
  ]
1867
2016
  });
@@ -1869,8 +2018,8 @@ var SeedDemoDataLambda = class extends Construct11 {
1869
2018
  };
1870
2019
 
1871
2020
  // src/workflows/control-plane/seed-demo-data/seed-demo-data-workflow.ts
1872
- import { Construct as Construct12 } from "constructs";
1873
- var SeedDemoDataWorkflow = class extends Construct12 {
2021
+ import { Construct as Construct13 } from "constructs";
2022
+ var SeedDemoDataWorkflow = class extends Construct13 {
1874
2023
  constructor(scope, props) {
1875
2024
  super(scope, "seed-demo-data-workflow");
1876
2025
  this.seedDemoData = new SeedDemoDataLambda(this, {
@@ -1887,32 +2036,32 @@ var SeedDemoDataWorkflow = class extends Construct12 {
1887
2036
  };
1888
2037
 
1889
2038
  // src/workflows/control-plane/seed-system-data/seed-system-data-lambda.ts
1890
- import fs8 from "fs";
1891
- import path8 from "path";
2039
+ import fs9 from "fs";
2040
+ import path9 from "path";
1892
2041
  import { PLATFORM_ROLE_IDS } from "@openhi/types";
1893
- import { Duration as Duration7, Stack as Stack5 } from "aws-cdk-lib";
2042
+ import { Duration as Duration8, Stack as Stack6 } from "aws-cdk-lib";
1894
2043
  import { Rule as Rule3 } from "aws-cdk-lib/aws-events";
1895
2044
  import { LambdaFunction as LambdaFunction3 } from "aws-cdk-lib/aws-events-targets";
1896
2045
  import { Effect as Effect4, PolicyStatement as PolicyStatement4 } from "aws-cdk-lib/aws-iam";
1897
- import { Runtime as Runtime8 } from "aws-cdk-lib/aws-lambda";
1898
- import { NodejsFunction as NodejsFunction8 } from "aws-cdk-lib/aws-lambda-nodejs";
1899
- import { Construct as Construct13 } from "constructs";
2046
+ import { Runtime as Runtime9 } from "aws-cdk-lib/aws-lambda";
2047
+ import { NodejsFunction as NodejsFunction9 } from "aws-cdk-lib/aws-lambda-nodejs";
2048
+ import { Construct as Construct14 } from "constructs";
1900
2049
  var HANDLER_NAME8 = "seed-system-data.handler.js";
1901
2050
  function resolveHandlerEntry8(dirname) {
1902
- const sameDir = path8.join(dirname, HANDLER_NAME8);
1903
- if (fs8.existsSync(sameDir)) {
2051
+ const sameDir = path9.join(dirname, HANDLER_NAME8);
2052
+ if (fs9.existsSync(sameDir)) {
1904
2053
  return sameDir;
1905
2054
  }
1906
- return path8.join(dirname, "..", "..", "..", "..", "lib", HANDLER_NAME8);
2055
+ return path9.join(dirname, "..", "..", "..", "..", "lib", HANDLER_NAME8);
1907
2056
  }
1908
- var SeedSystemDataLambda = class extends Construct13 {
2057
+ var SeedSystemDataLambda = class extends Construct14 {
1909
2058
  constructor(scope, props) {
1910
2059
  super(scope, "seed-system-data-lambda");
1911
- this.lambda = new NodejsFunction8(this, "handler", {
2060
+ this.lambda = new NodejsFunction9(this, "handler", {
1912
2061
  entry: resolveHandlerEntry8(__dirname),
1913
- runtime: Runtime8.NODEJS_LATEST,
2062
+ runtime: Runtime9.NODEJS_LATEST,
1914
2063
  memorySize: 512,
1915
- timeout: Duration7.minutes(1),
2064
+ timeout: Duration8.minutes(1),
1916
2065
  environment: {
1917
2066
  DYNAMO_TABLE_NAME: props.dataStoreTable.tableName,
1918
2067
  [SEED_SYSTEM_DATA_CONTROL_BUS_ENV_VAR]: props.controlEventBus.eventBusName
@@ -1934,7 +2083,7 @@ var SeedSystemDataLambda = class extends Construct13 {
1934
2083
  })
1935
2084
  );
1936
2085
  props.controlEventBus.grantPutEventsTo(this.lambda);
1937
- const hostStackName = Stack5.of(this).stackName;
2086
+ const hostStackName = Stack6.of(this).stackName;
1938
2087
  this.rule = new Rule3(this, "rule", {
1939
2088
  eventBus: props.controlEventBus,
1940
2089
  eventPattern: {
@@ -1949,7 +2098,7 @@ var SeedSystemDataLambda = class extends Construct13 {
1949
2098
  targets: [
1950
2099
  new LambdaFunction3(this.lambda, {
1951
2100
  retryAttempts: 2,
1952
- maxEventAge: Duration7.hours(2)
2101
+ maxEventAge: Duration8.hours(2)
1953
2102
  })
1954
2103
  ]
1955
2104
  });
@@ -1957,8 +2106,8 @@ var SeedSystemDataLambda = class extends Construct13 {
1957
2106
  };
1958
2107
 
1959
2108
  // src/workflows/control-plane/seed-system-data/seed-system-data-workflow.ts
1960
- import { Construct as Construct14 } from "constructs";
1961
- var SeedSystemDataWorkflow = class extends Construct14 {
2109
+ import { Construct as Construct15 } from "constructs";
2110
+ var SeedSystemDataWorkflow = class extends Construct15 {
1962
2111
  constructor(scope, props) {
1963
2112
  super(scope, "seed-system-data-workflow");
1964
2113
  this.seedSystemData = new SeedSystemDataLambda(this, {
@@ -2084,29 +2233,29 @@ _OpenHiDataService.SERVICE_TYPE = "data";
2084
2233
  var OpenHiDataService = _OpenHiDataService;
2085
2234
 
2086
2235
  // src/workflows/control-plane/user-onboarding/provision-default-workspace-lambda.ts
2087
- import fs9 from "fs";
2088
- import path9 from "path";
2089
- import { Duration as Duration8 } from "aws-cdk-lib";
2236
+ import fs10 from "fs";
2237
+ import path10 from "path";
2238
+ import { Duration as Duration9 } from "aws-cdk-lib";
2090
2239
  import { Rule as Rule4 } from "aws-cdk-lib/aws-events";
2091
2240
  import { LambdaFunction as LambdaFunction4 } from "aws-cdk-lib/aws-events-targets";
2092
2241
  import { Effect as Effect5, PolicyStatement as PolicyStatement5 } from "aws-cdk-lib/aws-iam";
2093
- import { Runtime as Runtime9 } from "aws-cdk-lib/aws-lambda";
2094
- import { NodejsFunction as NodejsFunction9 } from "aws-cdk-lib/aws-lambda-nodejs";
2095
- import { Construct as Construct15 } from "constructs";
2242
+ import { Runtime as Runtime10 } from "aws-cdk-lib/aws-lambda";
2243
+ import { NodejsFunction as NodejsFunction10 } from "aws-cdk-lib/aws-lambda-nodejs";
2244
+ import { Construct as Construct16 } from "constructs";
2096
2245
  var HANDLER_NAME9 = "provision-default-workspace.handler.js";
2097
2246
  function resolveHandlerEntry9(dirname) {
2098
- const sameDir = path9.join(dirname, HANDLER_NAME9);
2099
- if (fs9.existsSync(sameDir)) {
2247
+ const sameDir = path10.join(dirname, HANDLER_NAME9);
2248
+ if (fs10.existsSync(sameDir)) {
2100
2249
  return sameDir;
2101
2250
  }
2102
- return path9.join(dirname, "..", "..", "..", "..", "lib", HANDLER_NAME9);
2251
+ return path10.join(dirname, "..", "..", "..", "..", "lib", HANDLER_NAME9);
2103
2252
  }
2104
- var ProvisionDefaultWorkspaceLambda = class extends Construct15 {
2253
+ var ProvisionDefaultWorkspaceLambda = class extends Construct16 {
2105
2254
  constructor(scope, props) {
2106
2255
  super(scope, "provision-default-workspace-lambda");
2107
- this.lambda = new NodejsFunction9(this, "handler", {
2256
+ this.lambda = new NodejsFunction10(this, "handler", {
2108
2257
  entry: resolveHandlerEntry9(__dirname),
2109
- runtime: Runtime9.NODEJS_LATEST,
2258
+ runtime: Runtime10.NODEJS_LATEST,
2110
2259
  memorySize: 1024,
2111
2260
  environment: {
2112
2261
  DYNAMO_TABLE_NAME: props.dataStoreTable.tableName
@@ -2133,7 +2282,7 @@ var ProvisionDefaultWorkspaceLambda = class extends Construct15 {
2133
2282
  targets: [
2134
2283
  new LambdaFunction4(this.lambda, {
2135
2284
  retryAttempts: 2,
2136
- maxEventAge: Duration8.hours(2)
2285
+ maxEventAge: Duration9.hours(2)
2137
2286
  })
2138
2287
  ]
2139
2288
  });
@@ -2141,8 +2290,8 @@ var ProvisionDefaultWorkspaceLambda = class extends Construct15 {
2141
2290
  };
2142
2291
 
2143
2292
  // src/workflows/control-plane/user-onboarding/user-onboarding-workflow.ts
2144
- import { Construct as Construct16 } from "constructs";
2145
- var UserOnboardingWorkflow = class extends Construct16 {
2293
+ import { Construct as Construct17 } from "constructs";
2294
+ var UserOnboardingWorkflow = class extends Construct17 {
2146
2295
  constructor(scope, props) {
2147
2296
  super(scope, "user-onboarding-workflow");
2148
2297
  this.provisionDefaultWorkspace = new ProvisionDefaultWorkspaceLambda(this, {
@@ -2360,7 +2509,7 @@ var _OpenHiAuthService = class _OpenHiAuthService extends OpenHiService {
2360
2509
  new PolicyStatement6({
2361
2510
  actions: ["cognito-idp:AdminUserGlobalSignOut"],
2362
2511
  resources: [
2363
- Stack6.of(this).formatArn({
2512
+ Stack7.of(this).formatArn({
2364
2513
  service: "cognito-idp",
2365
2514
  resource: "userpool",
2366
2515
  resourceName: "*"
@@ -2429,60 +2578,60 @@ import { HttpUserPoolAuthorizer } from "aws-cdk-lib/aws-apigatewayv2-authorizers
2429
2578
  import { HttpLambdaIntegration } from "aws-cdk-lib/aws-apigatewayv2-integrations";
2430
2579
  import { Effect as Effect7, PolicyStatement as PolicyStatement7 } from "aws-cdk-lib/aws-iam";
2431
2580
  import {
2432
- ARecord,
2581
+ ARecord as ARecord2,
2433
2582
  HostedZone as HostedZone3,
2434
- RecordTarget
2583
+ RecordTarget as RecordTarget2
2435
2584
  } from "aws-cdk-lib/aws-route53";
2436
2585
  import { ApiGatewayv2DomainProperties } from "aws-cdk-lib/aws-route53-targets";
2437
- import { Duration as Duration9 } from "aws-cdk-lib/core";
2586
+ import { Duration as Duration10 } from "aws-cdk-lib/core";
2438
2587
 
2439
2588
  // src/data/lambda/cors-options-lambda.ts
2440
- import fs10 from "fs";
2441
- import path10 from "path";
2442
- import { Runtime as Runtime10 } from "aws-cdk-lib/aws-lambda";
2443
- import { NodejsFunction as NodejsFunction10 } from "aws-cdk-lib/aws-lambda-nodejs";
2444
- import { Construct as Construct17 } from "constructs";
2589
+ import fs11 from "fs";
2590
+ import path11 from "path";
2591
+ import { Runtime as Runtime11 } from "aws-cdk-lib/aws-lambda";
2592
+ import { NodejsFunction as NodejsFunction11 } from "aws-cdk-lib/aws-lambda-nodejs";
2593
+ import { Construct as Construct18 } from "constructs";
2445
2594
  var HANDLER_NAME10 = "cors-options-lambda.handler.js";
2446
2595
  function resolveHandlerEntry10(dirname) {
2447
- const sameDir = path10.join(dirname, HANDLER_NAME10);
2448
- if (fs10.existsSync(sameDir)) {
2596
+ const sameDir = path11.join(dirname, HANDLER_NAME10);
2597
+ if (fs11.existsSync(sameDir)) {
2449
2598
  return sameDir;
2450
2599
  }
2451
- const fromLib = path10.join(dirname, "..", "..", "..", "lib", HANDLER_NAME10);
2600
+ const fromLib = path11.join(dirname, "..", "..", "..", "lib", HANDLER_NAME10);
2452
2601
  return fromLib;
2453
2602
  }
2454
- var CorsOptionsLambda = class extends Construct17 {
2603
+ var CorsOptionsLambda = class extends Construct18 {
2455
2604
  constructor(scope, id = "cors-options-lambda") {
2456
2605
  super(scope, id);
2457
- this.lambda = new NodejsFunction10(this, "handler", {
2606
+ this.lambda = new NodejsFunction11(this, "handler", {
2458
2607
  entry: resolveHandlerEntry10(__dirname),
2459
- runtime: Runtime10.NODEJS_LATEST,
2608
+ runtime: Runtime11.NODEJS_LATEST,
2460
2609
  memorySize: 128
2461
2610
  });
2462
2611
  }
2463
2612
  };
2464
2613
 
2465
2614
  // src/data/lambda/rest-api-lambda.ts
2466
- import fs11 from "fs";
2467
- import path11 from "path";
2468
- import { Runtime as Runtime11 } from "aws-cdk-lib/aws-lambda";
2469
- import { NodejsFunction as NodejsFunction11 } from "aws-cdk-lib/aws-lambda-nodejs";
2470
- import { Construct as Construct18 } from "constructs";
2615
+ import fs12 from "fs";
2616
+ import path12 from "path";
2617
+ import { Runtime as Runtime12 } from "aws-cdk-lib/aws-lambda";
2618
+ import { NodejsFunction as NodejsFunction12 } from "aws-cdk-lib/aws-lambda-nodejs";
2619
+ import { Construct as Construct19 } from "constructs";
2471
2620
  var HANDLER_NAME11 = "rest-api-lambda.handler.js";
2472
2621
  function resolveHandlerEntry11(dirname) {
2473
- const sameDir = path11.join(dirname, HANDLER_NAME11);
2474
- if (fs11.existsSync(sameDir)) {
2622
+ const sameDir = path12.join(dirname, HANDLER_NAME11);
2623
+ if (fs12.existsSync(sameDir)) {
2475
2624
  return sameDir;
2476
2625
  }
2477
- const fromLib = path11.join(dirname, "..", "..", "..", "lib", HANDLER_NAME11);
2626
+ const fromLib = path12.join(dirname, "..", "..", "..", "lib", HANDLER_NAME11);
2478
2627
  return fromLib;
2479
2628
  }
2480
- var RestApiLambda = class extends Construct18 {
2629
+ var RestApiLambda = class extends Construct19 {
2481
2630
  constructor(scope, props) {
2482
2631
  super(scope, "rest-api-lambda");
2483
- this.lambda = new NodejsFunction11(this, "handler", {
2632
+ this.lambda = new NodejsFunction12(this, "handler", {
2484
2633
  entry: resolveHandlerEntry11(__dirname),
2485
- runtime: Runtime11.NODEJS_LATEST,
2634
+ runtime: Runtime12.NODEJS_LATEST,
2486
2635
  memorySize: 1024,
2487
2636
  environment: {
2488
2637
  DYNAMO_TABLE_NAME: props.dynamoTableName,
@@ -2700,10 +2849,10 @@ var _OpenHiRestApiService = class _OpenHiRestApiService extends OpenHiService {
2700
2849
  integration
2701
2850
  });
2702
2851
  const apiPrefix = this.branchName === "main" ? `api` : `api-${this.childZonePrefix}`;
2703
- new ARecord(this, "api-a-record", {
2852
+ new ARecord2(this, "api-a-record", {
2704
2853
  zone: hostedZone,
2705
2854
  recordName: apiPrefix,
2706
- target: RecordTarget.fromAlias(
2855
+ target: RecordTarget2.fromAlias(
2707
2856
  new ApiGatewayv2DomainProperties(
2708
2857
  domainName.regionalDomainName,
2709
2858
  domainName.regionalHostedZoneId
@@ -2741,7 +2890,7 @@ var _OpenHiRestApiService = class _OpenHiRestApiService extends OpenHiService {
2741
2890
  "Authorization"
2742
2891
  ],
2743
2892
  allowCredentials: cors.allowCredentials ?? true,
2744
- maxAge: cors.maxAge ?? Duration9.days(1),
2893
+ maxAge: cors.maxAge ?? Duration10.days(1),
2745
2894
  ...cors.exposeHeaders !== void 0 && {
2746
2895
  exposeHeaders: cors.exposeHeaders
2747
2896
  }
@@ -2806,34 +2955,186 @@ var _OpenHiGraphqlService = class _OpenHiGraphqlService extends OpenHiService {
2806
2955
  _OpenHiGraphqlService.SERVICE_TYPE = "graphql-api";
2807
2956
  var OpenHiGraphqlService = _OpenHiGraphqlService;
2808
2957
 
2958
+ // src/services/open-hi-website-service.ts
2959
+ var SSM_PARAM_NAME_FULL_DOMAIN = "WEBSITE_FULL_DOMAIN";
2960
+ var _OpenHiWebsiteService = class _OpenHiWebsiteService extends OpenHiService {
2961
+ /**
2962
+ * Looks up the static-hosting bucket ARN published by the release-branch
2963
+ * deploy of this service.
2964
+ */
2965
+ static bucketArnFromConstruct(scope) {
2966
+ return DiscoverableStringParameter.valueForLookupName(scope, {
2967
+ ssmParamName: StaticHosting.SSM_PARAM_NAME_BUCKET_ARN,
2968
+ serviceType: _OpenHiWebsiteService.SERVICE_TYPE
2969
+ });
2970
+ }
2971
+ /**
2972
+ * Looks up the CloudFront distribution ARN published by the release-branch
2973
+ * deploy of this service.
2974
+ */
2975
+ static distributionArnFromConstruct(scope) {
2976
+ return DiscoverableStringParameter.valueForLookupName(scope, {
2977
+ ssmParamName: StaticHosting.SSM_PARAM_NAME_DISTRIBUTION_ARN,
2978
+ serviceType: _OpenHiWebsiteService.SERVICE_TYPE
2979
+ });
2980
+ }
2981
+ /**
2982
+ * Looks up the CloudFront distribution domain
2983
+ * (e.g. dXXXXX.cloudfront.net) published by the release-branch deploy.
2984
+ */
2985
+ static distributionDomainFromConstruct(scope) {
2986
+ return DiscoverableStringParameter.valueForLookupName(scope, {
2987
+ ssmParamName: StaticHosting.SSM_PARAM_NAME_DISTRIBUTION_DOMAIN,
2988
+ serviceType: _OpenHiWebsiteService.SERVICE_TYPE
2989
+ });
2990
+ }
2991
+ /**
2992
+ * Looks up the CloudFront distribution ID published by the release-branch
2993
+ * deploy of this service.
2994
+ */
2995
+ static distributionIdFromConstruct(scope) {
2996
+ return DiscoverableStringParameter.valueForLookupName(scope, {
2997
+ ssmParamName: StaticHosting.SSM_PARAM_NAME_DISTRIBUTION_ID,
2998
+ serviceType: _OpenHiWebsiteService.SERVICE_TYPE
2999
+ });
3000
+ }
3001
+ /**
3002
+ * Looks up the website's full domain (e.g. www.example.com) published by
3003
+ * the release-branch deploy of this service.
3004
+ */
3005
+ static fullDomainFromConstruct(scope) {
3006
+ return DiscoverableStringParameter.valueForLookupName(scope, {
3007
+ ssmParamName: SSM_PARAM_NAME_FULL_DOMAIN,
3008
+ serviceType: _OpenHiWebsiteService.SERVICE_TYPE
3009
+ });
3010
+ }
3011
+ get serviceType() {
3012
+ return _OpenHiWebsiteService.SERVICE_TYPE;
3013
+ }
3014
+ constructor(ohEnv, props) {
3015
+ super(ohEnv, _OpenHiWebsiteService.SERVICE_TYPE, props);
3016
+ this.props = props;
3017
+ this.validateConfig(props);
3018
+ const hostedZone = this.createHostedZone();
3019
+ this.fullDomain = this.computeFullDomain(hostedZone);
3020
+ const shouldCreateHostingInfra = props.createHostingInfrastructure ?? this.branchName === this.defaultReleaseBranch;
3021
+ if (shouldCreateHostingInfra) {
3022
+ const certificate = this.createCertificate();
3023
+ this.staticHosting = this.createStaticHosting({
3024
+ certificate,
3025
+ hostedZone
3026
+ });
3027
+ this.createFullDomainParameter();
3028
+ }
3029
+ this.staticContent = this.createStaticContent();
3030
+ }
3031
+ /**
3032
+ * Validates that config required for the website stack is present.
3033
+ */
3034
+ validateConfig(props) {
3035
+ const { config } = props;
3036
+ if (!config) {
3037
+ throw new Error("Config is required");
3038
+ }
3039
+ if (!config.zoneName) {
3040
+ throw new Error("Zone name is required");
3041
+ }
3042
+ }
3043
+ /**
3044
+ * Looks up the child hosted zone published by the Global service.
3045
+ * Override to customize.
3046
+ */
3047
+ createHostedZone() {
3048
+ return OpenHiGlobalService.childHostedZoneFromConstruct(this, {
3049
+ zoneName: this.config.zoneName
3050
+ });
3051
+ }
3052
+ /**
3053
+ * Returns the wildcard certificate looked up from the Global service.
3054
+ * Override to customize.
3055
+ */
3056
+ createCertificate() {
3057
+ return OpenHiGlobalService.rootWildcardCertificateFromConstruct(this);
3058
+ }
3059
+ /**
3060
+ * Computes the full website domain from `domainPrefix` and the child
3061
+ * zone name.
3062
+ */
3063
+ computeFullDomain(hostedZone) {
3064
+ const prefix = this.props.domainPrefix ?? "www";
3065
+ return [prefix, hostedZone.zoneName].join(".");
3066
+ }
3067
+ /**
3068
+ * Creates the StaticHosting infrastructure (bucket + distribution +
3069
+ * Lambda@Edge + 4 SSM params + DNS).
3070
+ */
3071
+ createStaticHosting(deps) {
3072
+ return new StaticHosting(this, "static-hosting", {
3073
+ serviceType: _OpenHiWebsiteService.SERVICE_TYPE,
3074
+ certificate: deps.certificate,
3075
+ hostedZone: deps.hostedZone,
3076
+ domainNames: [this.fullDomain],
3077
+ description: `OpenHI website (${this.fullDomain})`
3078
+ });
3079
+ }
3080
+ /**
3081
+ * Creates the SSM parameter that publishes the website's full domain.
3082
+ * Look up via {@link OpenHiWebsiteService.fullDomainFromConstruct}.
3083
+ */
3084
+ createFullDomainParameter() {
3085
+ new DiscoverableStringParameter(this, "full-domain-param", {
3086
+ ssmParamName: SSM_PARAM_NAME_FULL_DOMAIN,
3087
+ serviceType: _OpenHiWebsiteService.SERVICE_TYPE,
3088
+ stringValue: this.fullDomain,
3089
+ description: "Full website domain (e.g. www.example.com)"
3090
+ });
3091
+ }
3092
+ /**
3093
+ * Creates the StaticContent uploader. Always created so feature-branch
3094
+ * deploys can publish content to their own sub-domain folder against the
3095
+ * release-branch bucket.
3096
+ */
3097
+ createStaticContent() {
3098
+ const { contentSourceDirectory, contentDestinationDirectory } = this.props;
3099
+ return new StaticContent(this, "static-content", {
3100
+ contentSourceDirectory,
3101
+ contentDestinationDirectory,
3102
+ fullDomain: this.fullDomain,
3103
+ serviceType: _OpenHiWebsiteService.SERVICE_TYPE
3104
+ });
3105
+ }
3106
+ };
3107
+ _OpenHiWebsiteService.SERVICE_TYPE = "website";
3108
+ var OpenHiWebsiteService = _OpenHiWebsiteService;
3109
+
2809
3110
  // src/workflows/control-plane/owning-delete-cascade/owning-delete-cascade-lambdas.ts
2810
- import fs12 from "fs";
2811
- import path12 from "path";
2812
- import { Duration as Duration10 } from "aws-cdk-lib";
3111
+ import fs13 from "fs";
3112
+ import path13 from "path";
3113
+ import { Duration as Duration11 } from "aws-cdk-lib";
2813
3114
  import { Effect as Effect8, PolicyStatement as PolicyStatement8 } from "aws-cdk-lib/aws-iam";
2814
- import { Runtime as Runtime12 } from "aws-cdk-lib/aws-lambda";
2815
- import { NodejsFunction as NodejsFunction12 } from "aws-cdk-lib/aws-lambda-nodejs";
2816
- import { Construct as Construct19 } from "constructs";
3115
+ import { Runtime as Runtime13 } from "aws-cdk-lib/aws-lambda";
3116
+ import { NodejsFunction as NodejsFunction13 } from "aws-cdk-lib/aws-lambda-nodejs";
3117
+ import { Construct as Construct20 } from "constructs";
2817
3118
  function resolveHandlerEntry12(dirname, handlerName) {
2818
- const sameDir = path12.join(dirname, handlerName);
2819
- if (fs12.existsSync(sameDir)) {
3119
+ const sameDir = path13.join(dirname, handlerName);
3120
+ if (fs13.existsSync(sameDir)) {
2820
3121
  return { entry: sameDir, handler: "handler" };
2821
3122
  }
2822
- const libDir = path12.join(dirname, "..", "..", "..", "..", "lib", handlerName);
3123
+ const libDir = path13.join(dirname, "..", "..", "..", "..", "lib", handlerName);
2823
3124
  return { entry: libDir, handler: "handler" };
2824
3125
  }
2825
- var OwningDeleteCascadeLambdas = class extends Construct19 {
3126
+ var OwningDeleteCascadeLambdas = class extends Construct20 {
2826
3127
  constructor(scope, props) {
2827
3128
  super(scope, "owning-delete-cascade-lambdas");
2828
3129
  const listResolved = resolveHandlerEntry12(
2829
3130
  __dirname,
2830
3131
  "list-chunks.handler.js"
2831
3132
  );
2832
- this.listChunks = new NodejsFunction12(this, "list-chunks-handler", {
3133
+ this.listChunks = new NodejsFunction13(this, "list-chunks-handler", {
2833
3134
  entry: listResolved.entry,
2834
- runtime: Runtime12.NODEJS_LATEST,
3135
+ runtime: Runtime13.NODEJS_LATEST,
2835
3136
  memorySize: 512,
2836
- timeout: Duration10.minutes(1),
3137
+ timeout: Duration11.minutes(1),
2837
3138
  environment: {
2838
3139
  DYNAMO_TABLE_NAME: props.dataStoreTable.tableName
2839
3140
  }
@@ -2843,11 +3144,11 @@ var OwningDeleteCascadeLambdas = class extends Construct19 {
2843
3144
  __dirname,
2844
3145
  "delete-chunk.handler.js"
2845
3146
  );
2846
- this.deleteChunk = new NodejsFunction12(this, "delete-chunk-handler", {
3147
+ this.deleteChunk = new NodejsFunction13(this, "delete-chunk-handler", {
2847
3148
  entry: deleteResolved.entry,
2848
- runtime: Runtime12.NODEJS_LATEST,
3149
+ runtime: Runtime13.NODEJS_LATEST,
2849
3150
  memorySize: 512,
2850
- timeout: Duration10.minutes(1),
3151
+ timeout: Duration11.minutes(1),
2851
3152
  environment: {
2852
3153
  DYNAMO_TABLE_NAME: props.dataStoreTable.tableName
2853
3154
  }
@@ -2862,11 +3163,11 @@ var OwningDeleteCascadeLambdas = class extends Construct19 {
2862
3163
  __dirname,
2863
3164
  "finalize.handler.js"
2864
3165
  );
2865
- this.finalize = new NodejsFunction12(this, "finalize-handler", {
3166
+ this.finalize = new NodejsFunction13(this, "finalize-handler", {
2866
3167
  entry: finalizeResolved.entry,
2867
- runtime: Runtime12.NODEJS_LATEST,
3168
+ runtime: Runtime13.NODEJS_LATEST,
2868
3169
  memorySize: 512,
2869
- timeout: Duration10.minutes(1),
3170
+ timeout: Duration11.minutes(1),
2870
3171
  environment: {
2871
3172
  DYNAMO_TABLE_NAME: props.dataStoreTable.tableName,
2872
3173
  [OWNING_DELETE_OPS_EVENT_BUS_ENV_VAR]: props.opsEventBus.eventBusName
@@ -2884,7 +3185,7 @@ var OwningDeleteCascadeLambdas = class extends Construct19 {
2884
3185
  };
2885
3186
 
2886
3187
  // src/workflows/control-plane/owning-delete-cascade/owning-delete-cascade-workflow.ts
2887
- import { Duration as Duration11 } from "aws-cdk-lib";
3188
+ import { Duration as Duration12 } from "aws-cdk-lib";
2888
3189
  import { Rule as Rule5 } from "aws-cdk-lib/aws-events";
2889
3190
  import { SfnStateMachine } from "aws-cdk-lib/aws-events-targets";
2890
3191
  import {
@@ -2900,8 +3201,8 @@ import {
2900
3201
  WaitTime
2901
3202
  } from "aws-cdk-lib/aws-stepfunctions";
2902
3203
  import { LambdaInvoke } from "aws-cdk-lib/aws-stepfunctions-tasks";
2903
- import { Construct as Construct20 } from "constructs";
2904
- var OwningDeleteCascadeWorkflow = class extends Construct20 {
3204
+ import { Construct as Construct21 } from "constructs";
3205
+ var OwningDeleteCascadeWorkflow = class extends Construct21 {
2905
3206
  constructor(scope, props) {
2906
3207
  super(scope, "owning-delete-cascade-workflow");
2907
3208
  this.lambdas = new OwningDeleteCascadeLambdas(this, {
@@ -3010,7 +3311,7 @@ var OwningDeleteCascadeWorkflow = class extends Construct20 {
3010
3311
  }
3011
3312
  });
3012
3313
  const interPageWait = new Wait(this, "inter-page-wait", {
3013
- time: WaitTime.duration(Duration11.seconds(0))
3314
+ time: WaitTime.duration(Duration12.seconds(0))
3014
3315
  });
3015
3316
  const isExhausted = new Choice(this, "is-exhausted");
3016
3317
  const finalize = new LambdaInvoke(this, "finalize", {
@@ -3041,7 +3342,7 @@ var OwningDeleteCascadeWorkflow = class extends Construct20 {
3041
3342
  // Long timeout because real-world cascades can run minutes when
3042
3343
  // a workspace has thousands of members. The stuck-cascade alarm
3043
3344
  // fires at 15 minutes; the state machine itself does not abort.
3044
- timeout: Duration11.hours(2)
3345
+ timeout: Duration12.hours(2)
3045
3346
  });
3046
3347
  this.rule = new Rule5(this, "rule", {
3047
3348
  eventBus: props.dataEventBus,
@@ -3052,7 +3353,7 @@ var OwningDeleteCascadeWorkflow = class extends Construct20 {
3052
3353
  targets: [
3053
3354
  new SfnStateMachine(this.stateMachine, {
3054
3355
  retryAttempts: 2,
3055
- maxEventAge: Duration11.hours(2)
3356
+ maxEventAge: Duration12.hours(2)
3056
3357
  })
3057
3358
  ]
3058
3359
  });
@@ -3060,33 +3361,33 @@ var OwningDeleteCascadeWorkflow = class extends Construct20 {
3060
3361
  };
3061
3362
 
3062
3363
  // src/workflows/control-plane/rename-cascade/rename-cascade-lambdas.ts
3063
- import fs13 from "fs";
3064
- import path13 from "path";
3065
- import { Duration as Duration12 } from "aws-cdk-lib";
3364
+ import fs14 from "fs";
3365
+ import path14 from "path";
3366
+ import { Duration as Duration13 } from "aws-cdk-lib";
3066
3367
  import { Effect as Effect9, PolicyStatement as PolicyStatement9 } from "aws-cdk-lib/aws-iam";
3067
- import { Runtime as Runtime13 } from "aws-cdk-lib/aws-lambda";
3068
- import { NodejsFunction as NodejsFunction13 } from "aws-cdk-lib/aws-lambda-nodejs";
3069
- import { Construct as Construct21 } from "constructs";
3368
+ import { Runtime as Runtime14 } from "aws-cdk-lib/aws-lambda";
3369
+ import { NodejsFunction as NodejsFunction14 } from "aws-cdk-lib/aws-lambda-nodejs";
3370
+ import { Construct as Construct22 } from "constructs";
3070
3371
  function resolveHandlerEntry13(dirname, handlerName) {
3071
- const sameDir = path13.join(dirname, handlerName);
3072
- if (fs13.existsSync(sameDir)) {
3372
+ const sameDir = path14.join(dirname, handlerName);
3373
+ if (fs14.existsSync(sameDir)) {
3073
3374
  return { entry: sameDir, handler: "handler" };
3074
3375
  }
3075
- const libDir = path13.join(dirname, "..", "..", "..", "..", "lib", handlerName);
3376
+ const libDir = path14.join(dirname, "..", "..", "..", "..", "lib", handlerName);
3076
3377
  return { entry: libDir, handler: "handler" };
3077
3378
  }
3078
- var RenameCascadeLambdas = class extends Construct21 {
3379
+ var RenameCascadeLambdas = class extends Construct22 {
3079
3380
  constructor(scope, props) {
3080
3381
  super(scope, "rename-cascade-lambdas");
3081
3382
  const listResolved = resolveHandlerEntry13(
3082
3383
  __dirname,
3083
3384
  "rename-list-targets.handler.js"
3084
3385
  );
3085
- this.listTargets = new NodejsFunction13(this, "list-targets-handler", {
3386
+ this.listTargets = new NodejsFunction14(this, "list-targets-handler", {
3086
3387
  entry: listResolved.entry,
3087
- runtime: Runtime13.NODEJS_LATEST,
3388
+ runtime: Runtime14.NODEJS_LATEST,
3088
3389
  memorySize: 512,
3089
- timeout: Duration12.minutes(1),
3390
+ timeout: Duration13.minutes(1),
3090
3391
  environment: {
3091
3392
  DYNAMO_TABLE_NAME: props.dataStoreTable.tableName
3092
3393
  }
@@ -3096,11 +3397,11 @@ var RenameCascadeLambdas = class extends Construct21 {
3096
3397
  __dirname,
3097
3398
  "rename-rewrite-chunk.handler.js"
3098
3399
  );
3099
- this.rewriteChunk = new NodejsFunction13(this, "rewrite-chunk-handler", {
3400
+ this.rewriteChunk = new NodejsFunction14(this, "rewrite-chunk-handler", {
3100
3401
  entry: rewriteResolved.entry,
3101
- runtime: Runtime13.NODEJS_LATEST,
3402
+ runtime: Runtime14.NODEJS_LATEST,
3102
3403
  memorySize: 512,
3103
- timeout: Duration12.minutes(1),
3404
+ timeout: Duration13.minutes(1),
3104
3405
  environment: {
3105
3406
  DYNAMO_TABLE_NAME: props.dataStoreTable.tableName
3106
3407
  }
@@ -3115,11 +3416,11 @@ var RenameCascadeLambdas = class extends Construct21 {
3115
3416
  __dirname,
3116
3417
  "rename-finalize.handler.js"
3117
3418
  );
3118
- this.finalize = new NodejsFunction13(this, "finalize-handler", {
3419
+ this.finalize = new NodejsFunction14(this, "finalize-handler", {
3119
3420
  entry: finalizeResolved.entry,
3120
- runtime: Runtime13.NODEJS_LATEST,
3421
+ runtime: Runtime14.NODEJS_LATEST,
3121
3422
  memorySize: 512,
3122
- timeout: Duration12.minutes(1),
3423
+ timeout: Duration13.minutes(1),
3123
3424
  environment: {
3124
3425
  [RENAME_CASCADE_OPS_EVENT_BUS_ENV_VAR]: props.opsEventBus.eventBusName
3125
3426
  }
@@ -3135,7 +3436,7 @@ var RenameCascadeLambdas = class extends Construct21 {
3135
3436
  };
3136
3437
 
3137
3438
  // src/workflows/control-plane/rename-cascade/rename-cascade-workflow.ts
3138
- import { Duration as Duration13 } from "aws-cdk-lib";
3439
+ import { Duration as Duration14 } from "aws-cdk-lib";
3139
3440
  import { Rule as Rule6 } from "aws-cdk-lib/aws-events";
3140
3441
  import { SfnStateMachine as SfnStateMachine2 } from "aws-cdk-lib/aws-events-targets";
3141
3442
  import {
@@ -3149,8 +3450,8 @@ import {
3149
3450
  TaskInput as TaskInput2
3150
3451
  } from "aws-cdk-lib/aws-stepfunctions";
3151
3452
  import { LambdaInvoke as LambdaInvoke2 } from "aws-cdk-lib/aws-stepfunctions-tasks";
3152
- import { Construct as Construct22 } from "constructs";
3153
- var RenameCascadeWorkflow = class extends Construct22 {
3453
+ import { Construct as Construct23 } from "constructs";
3454
+ var RenameCascadeWorkflow = class extends Construct23 {
3154
3455
  constructor(scope, props) {
3155
3456
  super(scope, "rename-cascade-workflow");
3156
3457
  this.lambdas = new RenameCascadeLambdas(this, {
@@ -3294,7 +3595,7 @@ var RenameCascadeWorkflow = class extends Construct22 {
3294
3595
  // Long timeout — large renames may rewrite thousands of rows;
3295
3596
  // the `CascadeSlow` alarm fires at 300s p99 but the state
3296
3597
  // machine itself does not abort.
3297
- timeout: Duration13.hours(2)
3598
+ timeout: Duration14.hours(2)
3298
3599
  });
3299
3600
  this.rule = new Rule6(this, "rule", {
3300
3601
  eventBus: props.dataEventBus,
@@ -3305,7 +3606,7 @@ var RenameCascadeWorkflow = class extends Construct22 {
3305
3606
  targets: [
3306
3607
  new SfnStateMachine2(this.stateMachine, {
3307
3608
  retryAttempts: 2,
3308
- maxEventAge: Duration13.hours(2)
3609
+ maxEventAge: Duration14.hours(2)
3309
3610
  })
3310
3611
  ]
3311
3612
  });
@@ -3371,6 +3672,7 @@ export {
3371
3672
  OpenHiRestApiService,
3372
3673
  OpenHiService,
3373
3674
  OpenHiStage,
3675
+ OpenHiWebsiteService,
3374
3676
  OpsEventBus,
3375
3677
  OwningDeleteCascadeLambdas,
3376
3678
  OwningDeleteCascadeWorkflow,
@@ -3406,11 +3708,13 @@ export {
3406
3708
  SEED_SYSTEM_DATA_ACTOR_SYSTEM,
3407
3709
  SEED_SYSTEM_DATA_CONSUMER_NAME,
3408
3710
  SEED_SYSTEM_DATA_CONTROL_BUS_ENV_VAR,
3711
+ SSM_PARAM_NAME_FULL_DOMAIN,
3409
3712
  STATIC_HOSTING_SERVICE_TYPE,
3410
3713
  SeedDemoDataLambda,
3411
3714
  SeedDemoDataWorkflow,
3412
3715
  SeedSystemDataLambda,
3413
3716
  SeedSystemDataWorkflow,
3717
+ StaticContent,
3414
3718
  StaticHosting,
3415
3719
  USER_ONBOARDING_EVENT_SOURCE,
3416
3720
  UserOnboardingWorkflow,