@openhi/constructs 0.0.1 → 0.0.2

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
@@ -278,37 +278,7 @@ import {
278
278
  } from "@codedrifters/utils";
279
279
  import { RemovalPolicy, Stack, Tags } from "aws-cdk-lib";
280
280
  import { paramCase } from "change-case";
281
- var OPEN_HI_SERVICE_TYPE = {
282
- /**
283
- * Authentication service.
284
- * *
285
- * Only one instance of the auth service should exist per environment.
286
- */
287
- AUTH: "auth",
288
- /**
289
- * Root shared core services.
290
- *
291
- * Only one instance of the core service should exist per environment.
292
- */
293
- CORE: "core",
294
- /**
295
- * Rest API service.
296
- */
297
- REST_API: "rest-api",
298
- /**
299
- * Global Infrastructure stack (Route53, ACM).
300
- */
301
- GLOBAL: "global",
302
- /**
303
- * Data service (DynamoDB, S3, persistence).
304
- */
305
- DATA: "data"
306
- };
307
281
  var OpenHiService = class extends Stack {
308
- /**
309
- * Core construct containing shared infrastructure.
310
- */
311
- // public core: Core;
312
282
  /**
313
283
  * Creates a new OpenHI service stack.
314
284
  *
@@ -354,16 +324,6 @@ var OpenHiService = class extends Stack {
354
324
  const removalPolicy = props.removalPolicy ?? (ohEnv.ohStage.stageType === import_config3.OPEN_HI_STAGE.PROD ? RemovalPolicy.RETAIN : RemovalPolicy.DESTROY);
355
325
  Object.assign(props, { removalPolicy });
356
326
  const description = `OpenHi Service: ${id} [${branchName}] - ${branchHash}`;
357
- const hostedZoneId = ohEnv.props.config.hostedZoneId;
358
- const zoneName = ohEnv.props.config.zoneName;
359
- if (hostedZoneId && zoneName) {
360
- props = {
361
- ...props,
362
- coreProps: {
363
- ...props.coreProps
364
- }
365
- };
366
- }
367
327
  super(ohEnv, [branchHash, id, account, region].join("-"), {
368
328
  ...props,
369
329
  description
@@ -373,7 +333,6 @@ var OpenHiService = class extends Stack {
373
333
  this.serviceId = id;
374
334
  this.removalPolicy = removalPolicy;
375
335
  this.config = props.config ?? ohEnv.props.config;
376
- this.serviceType = props.serviceType ?? id;
377
336
  this.deploymentTargetRole = ohEnv.deploymentTargetRole;
378
337
  this.repoName = repoName;
379
338
  this.appName = appName;
@@ -384,26 +343,12 @@ var OpenHiService = class extends Stack {
384
343
  this.stackHash = stackHash;
385
344
  Tags.of(this).add(`${appName}:repo-name`, repoName.slice(0, 255));
386
345
  Tags.of(this).add(`${appName}:branch-name`, branchName.slice(0, 255));
387
- Tags.of(this).add(
388
- `${appName}:service-type`,
389
- this.serviceType.slice(0, 255)
390
- );
346
+ Tags.of(this).add(`${appName}:service-type`, id.slice(0, 255));
391
347
  Tags.of(this).add(
392
348
  `${appName}:stage-type`,
393
349
  ohEnv.ohStage.stageType.slice(0, 255)
394
350
  );
395
351
  }
396
- /**
397
- * Creates or returns the core construct for shared infrastructure.
398
- */
399
- /*
400
- protected createCore(props: OpenHiServiceProps = {}): Core {
401
- if (!this.core) {
402
- return new Core(this, props.coreProps);
403
- }
404
- return this.core;
405
- }
406
- */
407
352
  /**
408
353
  * DNS prefix for this branche's child zone.
409
354
  */
@@ -412,12 +357,68 @@ var OpenHiService = class extends Stack {
412
357
  }
413
358
  };
414
359
 
360
+ // src/components/acm/root-wildcard-certificate.ts
361
+ import {
362
+ Certificate
363
+ } from "aws-cdk-lib/aws-certificatemanager";
364
+ import { StringParameter } from "aws-cdk-lib/aws-ssm";
365
+ var _RootWildcardCertificate = class _RootWildcardCertificate extends Certificate {
366
+ /**
367
+ * Using a special name here since this will be shared and used among many
368
+ * stacks and services. Use with OpenHiGlobalService.rootWildcardCertificateFromConstruct.
369
+ */
370
+ static ssmParameterName() {
371
+ return "/" + ["GLOBAL", _RootWildcardCertificate.SSM_PARAM_NAME].join("/").toUpperCase();
372
+ }
373
+ constructor(scope, props) {
374
+ super(scope, "root-wildcard-certificate", { ...props });
375
+ new StringParameter(this, "wildcard-cert-param", {
376
+ parameterName: _RootWildcardCertificate.ssmParameterName(),
377
+ stringValue: this.certificateArn
378
+ });
379
+ }
380
+ };
381
+ /**
382
+ * Used when storing the Certificate ARN in SSM.
383
+ */
384
+ _RootWildcardCertificate.SSM_PARAM_NAME = "ROOT_WILDCARD_CERT_ARN";
385
+ var RootWildcardCertificate = _RootWildcardCertificate;
386
+
387
+ // src/components/api-gateway/root-http-api.ts
388
+ import { HttpApi } from "aws-cdk-lib/aws-apigatewayv2";
389
+ var RootHttpApi = class extends HttpApi {
390
+ constructor(scope, props = {}) {
391
+ const stack = OpenHiService.of(scope);
392
+ super(scope, "http-api", {
393
+ /**
394
+ * User provided props
395
+ */
396
+ ...props,
397
+ /**
398
+ * Required
399
+ */
400
+ apiName: ["root", "http", "api", stack.branchHash].join("-")
401
+ });
402
+ }
403
+ };
404
+ /**
405
+ * Used when storing the API ID in SSM.
406
+ */
407
+ RootHttpApi.SSM_PARAM_NAME = "ROOT_HTTP_API";
408
+
409
+ // src/components/app-sync/root-graphql-api.ts
410
+ import {
411
+ Definition,
412
+ GraphqlApi
413
+ } from "aws-cdk-lib/aws-appsync";
414
+ import { CodeFirstSchema, GraphqlType, ObjectType } from "awscdk-appsync-utils";
415
+
415
416
  // src/components/ssm/discoverable-string-parameter.ts
416
417
  import { Tags as Tags2 } from "aws-cdk-lib";
417
418
  import {
418
- StringParameter
419
+ StringParameter as StringParameter2
419
420
  } from "aws-cdk-lib/aws-ssm";
420
- var DiscoverableStringParameter = class _DiscoverableStringParameter extends StringParameter {
421
+ var _DiscoverableStringParameter = class _DiscoverableStringParameter extends StringParameter2 {
421
422
  /**
422
423
  * Build a param name based on predictable attributes found in services and
423
424
  * constructs. Used for storage and retrieval of SSM values across services.
@@ -425,6 +426,7 @@ var DiscoverableStringParameter = class _DiscoverableStringParameter extends Str
425
426
  static buildParameterName(scope, props) {
426
427
  const stack = OpenHiService.of(scope);
427
428
  return "/" + [
429
+ _DiscoverableStringParameter.version,
428
430
  props.branchHash ?? stack.branchHash,
429
431
  props.serviceType ?? stack.serviceType,
430
432
  props.account ?? stack.account,
@@ -441,7 +443,7 @@ var DiscoverableStringParameter = class _DiscoverableStringParameter extends Str
441
443
  scope,
442
444
  props
443
445
  );
444
- return StringParameter.valueForStringParameter(scope, paramName);
446
+ return StringParameter2.valueForStringParameter(scope, paramName);
445
447
  }
446
448
  constructor(scope, id, props) {
447
449
  const { ssmParamName, branchHash, serviceType, account, region, ...rest } = props;
@@ -449,7 +451,7 @@ var DiscoverableStringParameter = class _DiscoverableStringParameter extends Str
449
451
  scope,
450
452
  props
451
453
  );
452
- super(scope, id, {
454
+ super(scope, id + "-" + _DiscoverableStringParameter.version, {
453
455
  ...rest,
454
456
  parameterName
455
457
  });
@@ -457,42 +459,68 @@ var DiscoverableStringParameter = class _DiscoverableStringParameter extends Str
457
459
  Tags2.of(this).add(`${appName}:param-name`, ssmParamName);
458
460
  }
459
461
  };
462
+ /**
463
+ * Version of the parameter name format / discoverability schema.
464
+ * Bump when buildParameterName or tagging semantics change.
465
+ * Also used to drive replacement of parameters during CloudFormation deploys.
466
+ */
467
+ _DiscoverableStringParameter.version = "v1";
468
+ var DiscoverableStringParameter = _DiscoverableStringParameter;
460
469
 
461
- // src/services/open-hi-core-service.ts
462
- import { Code, Function, Runtime } from "aws-cdk-lib/aws-lambda";
463
- var OpenHiCoreService = class extends OpenHiService {
464
- constructor(ohEnv, props = {}) {
465
- props = {
466
- ...props
467
- };
468
- super(ohEnv, OPEN_HI_SERVICE_TYPE.CORE, props);
469
- this.props = props;
470
- new Function(this, "test-fn", {
471
- runtime: Runtime.NODEJS_LATEST,
472
- handler: "index.handler",
473
- code: Code.fromInline(
474
- 'exports.handler = async () => { return {statusCode:200, body:"ok"} }'
475
- )
470
+ // src/components/app-sync/root-graphql-api.ts
471
+ var _RootGraphqlApi = class _RootGraphqlApi extends GraphqlApi {
472
+ static fromConstruct(scope) {
473
+ const graphqlApiId = DiscoverableStringParameter.valueForLookupName(scope, {
474
+ ssmParamName: _RootGraphqlApi.SSM_PARAM_NAME,
475
+ serviceType: "graphql-api"
476
+ });
477
+ return GraphqlApi.fromGraphqlApiAttributes(scope, "root-graphql-api", {
478
+ graphqlApiId
479
+ });
480
+ }
481
+ constructor(scope, props) {
482
+ const stack = OpenHiService.of(scope);
483
+ const schema = new CodeFirstSchema();
484
+ schema.addType(
485
+ new ObjectType("Query", {
486
+ definition: { HelloWorld: GraphqlType.string() }
487
+ })
488
+ );
489
+ super(scope, "root-graphql-api", {
490
+ /**
491
+ * Defaults
492
+ */
493
+ queryDepthLimit: 2,
494
+ resolverCountLimit: 50,
495
+ definition: Definition.fromSchema(schema),
496
+ /**
497
+ * Overrideable props
498
+ */
499
+ ...props,
500
+ /**
501
+ * Required
502
+ */
503
+ name: ["root", "graphql", "api", stack.branchHash].join("-")
504
+ });
505
+ new DiscoverableStringParameter(this, "graphql-api-param", {
506
+ ssmParamName: _RootGraphqlApi.SSM_PARAM_NAME,
507
+ serviceType: "graphql-api",
508
+ stringValue: this.apiId
476
509
  });
477
510
  }
478
511
  };
512
+ /**
513
+ * Used when storing the GraphQl API ID in SSM.
514
+ */
515
+ _RootGraphqlApi.SSM_PARAM_NAME = "ROOT_GRAPHQL_API";
516
+ var RootGraphqlApi = _RootGraphqlApi;
479
517
 
480
- // src/components/auth.ts
481
- import { Construct } from "constructs";
482
-
483
- // src/components/cognito/core-user-pool.ts
518
+ // src/components/cognito/cognito-user-pool.ts
484
519
  import {
485
520
  UserPool,
486
521
  VerificationEmailStyle
487
522
  } from "aws-cdk-lib/aws-cognito";
488
- var _CoreUserPool = class _CoreUserPool extends UserPool {
489
- static fromConstruct(scope) {
490
- const userPoolId = DiscoverableStringParameter.valueForLookupName(scope, {
491
- ssmParamName: _CoreUserPool.SSM_PARAM_NAME,
492
- serviceType: OPEN_HI_SERVICE_TYPE.AUTH
493
- });
494
- return UserPool.fromUserPoolId(scope, "user-pool", userPoolId);
495
- }
523
+ var CognitoUserPool = class extends UserPool {
496
524
  constructor(scope, props = {}) {
497
525
  const service = OpenHiService.of(scope);
498
526
  super(scope, "user-pool", {
@@ -516,39 +544,18 @@ var _CoreUserPool = class _CoreUserPool extends UserPool {
516
544
  /**
517
545
  * Required
518
546
  */
519
- userPoolName: ["core", "user", "pool", service.branchHash].join("-")
520
- });
521
- new DiscoverableStringParameter(this, "user-pool-param", {
522
- ssmParamName: _CoreUserPool.SSM_PARAM_NAME,
523
- stringValue: this.userPoolId
547
+ userPoolName: ["cognito", "user", "pool", service.branchHash].join("-")
524
548
  });
525
549
  }
526
550
  };
527
551
  /**
528
552
  * Used when storing the User Pool ID in SSM.
529
553
  */
530
- _CoreUserPool.SSM_PARAM_NAME = "CORE_USER_POOL";
531
- var CoreUserPool = _CoreUserPool;
554
+ CognitoUserPool.SSM_PARAM_NAME = "COGNITO_USER_POOL";
532
555
 
533
- // src/components/cognito/core-user-pool-client.ts
534
- import {
535
- UserPoolClient
536
- } from "aws-cdk-lib/aws-cognito";
537
- var _CoreUserPoolClient = class _CoreUserPoolClient extends UserPoolClient {
538
- static fromConstruct(scope) {
539
- const userPoolClientId = DiscoverableStringParameter.valueForLookupName(
540
- scope,
541
- {
542
- ssmParamName: _CoreUserPoolClient.SSM_PARAM_NAME,
543
- serviceType: OPEN_HI_SERVICE_TYPE.AUTH
544
- }
545
- );
546
- return UserPoolClient.fromUserPoolClientId(
547
- scope,
548
- "user-pool-client",
549
- userPoolClientId
550
- );
551
- }
556
+ // src/components/cognito/cognito-user-pool-client.ts
557
+ import { UserPoolClient } from "aws-cdk-lib/aws-cognito";
558
+ var CognitoUserPoolClient = class extends UserPoolClient {
552
559
  constructor(scope, props) {
553
560
  super(scope, "user-pool-client", {
554
561
  /**
@@ -567,64 +574,31 @@ var _CoreUserPoolClient = class _CoreUserPoolClient extends UserPoolClient {
567
574
  */
568
575
  ...props
569
576
  });
570
- new DiscoverableStringParameter(this, "user-pool-client-param", {
571
- ssmParamName: _CoreUserPoolClient.SSM_PARAM_NAME,
572
- stringValue: this.userPoolClientId
573
- });
574
577
  }
575
578
  };
576
579
  /**
577
580
  * Used when storing the User Pool Client ID in SSM.
578
581
  */
579
- _CoreUserPoolClient.SSM_PARAM_NAME = "CORE_USER_POOL_CLIENT";
580
- var CoreUserPoolClient = _CoreUserPoolClient;
582
+ CognitoUserPoolClient.SSM_PARAM_NAME = "COGNITO_USER_POOL_CLIENT";
581
583
 
582
- // src/components/cognito/core-user-pool-domain.ts
583
- import {
584
- UserPoolDomain
585
- } from "aws-cdk-lib/aws-cognito";
586
- var _CoreUserPoolDomain = class _CoreUserPoolDomain extends UserPoolDomain {
587
- static fromConstruct(scope) {
588
- const userPoolDomain = DiscoverableStringParameter.valueForLookupName(
589
- scope,
590
- {
591
- ssmParamName: _CoreUserPoolDomain.SSM_PARAM_NAME,
592
- serviceType: OPEN_HI_SERVICE_TYPE.AUTH
593
- }
594
- );
595
- return UserPoolDomain.fromDomainName(
596
- scope,
597
- "user-pool-domain",
598
- userPoolDomain
599
- );
600
- }
584
+ // src/components/cognito/cognito-user-pool-domain.ts
585
+ import { UserPoolDomain } from "aws-cdk-lib/aws-cognito";
586
+ var CognitoUserPoolDomain = class extends UserPoolDomain {
601
587
  constructor(scope, props) {
602
588
  const id = props.cognitoDomain?.domainPrefix ? "cognito-domain" : "custom-domain";
603
589
  super(scope, id, {
604
590
  ...props
605
591
  });
606
- new DiscoverableStringParameter(this, "user-pool-domain-param", {
607
- ssmParamName: _CoreUserPoolDomain.SSM_PARAM_NAME,
608
- stringValue: this.domainName
609
- });
610
592
  }
611
593
  };
612
594
  /**
613
595
  * Used when storing the User Pool Domain in SSM.
614
596
  */
615
- _CoreUserPoolDomain.SSM_PARAM_NAME = "CORE_USER_POOL_DOMAIN";
616
- var CoreUserPoolDomain = _CoreUserPoolDomain;
597
+ CognitoUserPoolDomain.SSM_PARAM_NAME = "COGNITO_USER_POOL_DOMAIN";
617
598
 
618
- // src/components/cognito/core-user-pool-kms-key.ts
599
+ // src/components/cognito/cognito-user-pool-kms-key.ts
619
600
  import { Key } from "aws-cdk-lib/aws-kms";
620
- var _CoreUserPoolKmsKey = class _CoreUserPoolKmsKey extends Key {
621
- static fromConstruct(scope) {
622
- const keyArn = DiscoverableStringParameter.valueForLookupName(scope, {
623
- ssmParamName: _CoreUserPoolKmsKey.SSM_PARAM_NAME,
624
- serviceType: OPEN_HI_SERVICE_TYPE.AUTH
625
- });
626
- return Key.fromKeyArn(scope, "kms-key", keyArn);
627
- }
601
+ var CognitoUserPoolKmsKey = class extends Key {
628
602
  constructor(scope, props = {}) {
629
603
  const service = OpenHiService.of(scope);
630
604
  super(scope, "kms-key", {
@@ -633,142 +607,146 @@ var _CoreUserPoolKmsKey = class _CoreUserPoolKmsKey extends Key {
633
607
  description: `KMS Key for Cognito User Pool - ${service.branchHash}`,
634
608
  removalPolicy: props.removalPolicy ?? service.removalPolicy
635
609
  });
636
- new DiscoverableStringParameter(this, "kms-key-param", {
637
- ssmParamName: _CoreUserPoolKmsKey.SSM_PARAM_NAME,
638
- stringValue: this.keyArn
639
- });
640
610
  }
641
611
  };
642
612
  /**
643
613
  * Used when storing the KMS Key in SSM.
644
614
  */
645
- _CoreUserPoolKmsKey.SSM_PARAM_NAME = "CORE_USER_POOL_KMS_KEY";
646
- var CoreUserPoolKmsKey = _CoreUserPoolKmsKey;
615
+ CognitoUserPoolKmsKey.SSM_PARAM_NAME = "COGNITO_USER_POOL_KMS_KEY";
647
616
 
648
- // src/components/auth.ts
649
- var Auth = class _Auth extends Construct {
650
- /**
651
- * Returns an Auth instance that uses resources imported from AUTH SSM
652
- * parameters. Use this when creating Core or other stacks that consume
653
- * auth resources; the Auth stack must be deployed first.
654
- *
655
- * @param scope - Construct scope (e.g. Core); must be in a stack that has
656
- * access to the same account/region as the deployed Auth stack.
657
- */
658
- static fromConstruct(scope) {
659
- return new _Auth(scope, {});
660
- }
661
- constructor(scope, props = {}) {
662
- super(scope, "auth");
663
- const service = OpenHiService.of(this);
664
- this.isAuthService = service.serviceType === OPEN_HI_SERVICE_TYPE.AUTH;
665
- this.userPoolKmsKey = this.createUserPoolKmsKey();
666
- this.userPool = this.createUserPool({
667
- ...props.userPoolProps,
668
- customSenderKmsKey: this.userPoolKmsKey
617
+ // src/components/dynamodb/dynamo-db-data-store.ts
618
+ import {
619
+ AttributeType,
620
+ BillingMode,
621
+ ProjectionType,
622
+ Table
623
+ } from "aws-cdk-lib/aws-dynamodb";
624
+ function getDynamoDbDataStoreTableName(scope) {
625
+ const stack = OpenHiService.of(scope);
626
+ return `data-store-${stack.branchHash}`;
627
+ }
628
+ var DynamoDbDataStore = class extends Table {
629
+ constructor(scope, id, props = {}) {
630
+ const service = OpenHiService.of(scope);
631
+ super(scope, id, {
632
+ ...props,
633
+ tableName: getDynamoDbDataStoreTableName(scope),
634
+ partitionKey: {
635
+ name: "PK",
636
+ type: AttributeType.STRING
637
+ },
638
+ sortKey: {
639
+ name: "SK",
640
+ type: AttributeType.STRING
641
+ },
642
+ billingMode: BillingMode.PAY_PER_REQUEST,
643
+ removalPolicy: props.removalPolicy ?? service.removalPolicy
669
644
  });
670
- this.userPoolClient = this.createUserPoolClient({
671
- userPool: this.userPool
645
+ this.addGlobalSecondaryIndex({
646
+ indexName: "GSI1",
647
+ partitionKey: {
648
+ name: "GSI1PK",
649
+ type: AttributeType.STRING
650
+ },
651
+ sortKey: {
652
+ name: "GSI1SK",
653
+ type: AttributeType.STRING
654
+ },
655
+ projectionType: ProjectionType.INCLUDE,
656
+ nonKeyAttributes: ["srcType", "srcId", "path", "srcPk", "srcSk", "ts"]
672
657
  });
673
- this.userPoolDomain = this.createUserPoolDomain({
674
- userPool: this.userPool
658
+ this.addGlobalSecondaryIndex({
659
+ indexName: "GSI2",
660
+ partitionKey: {
661
+ name: "GSI2PK",
662
+ type: AttributeType.STRING
663
+ },
664
+ sortKey: {
665
+ name: "GSI2SK",
666
+ type: AttributeType.STRING
667
+ },
668
+ projectionType: ProjectionType.INCLUDE,
669
+ nonKeyAttributes: ["resourcePk", "resourceSk", "display", "status"]
670
+ });
671
+ this.addGlobalSecondaryIndex({
672
+ indexName: "GSI3",
673
+ partitionKey: {
674
+ name: "GSI3PK",
675
+ type: AttributeType.STRING
676
+ },
677
+ sortKey: {
678
+ name: "GSI3SK",
679
+ type: AttributeType.STRING
680
+ },
681
+ projectionType: ProjectionType.INCLUDE,
682
+ nonKeyAttributes: ["resourcePk", "resourceSk"]
683
+ });
684
+ this.addGlobalSecondaryIndex({
685
+ indexName: "GSI4",
686
+ partitionKey: {
687
+ name: "GSI4PK",
688
+ type: AttributeType.STRING
689
+ },
690
+ sortKey: {
691
+ name: "GSI4SK",
692
+ type: AttributeType.STRING
693
+ },
694
+ projectionType: ProjectionType.ALL
675
695
  });
676
696
  }
697
+ };
698
+
699
+ // src/components/event-bridge/data-event-bus.ts
700
+ import { EventBus } from "aws-cdk-lib/aws-events";
701
+ var DataEventBus = class _DataEventBus extends EventBus {
677
702
  /*****************************************************************************
678
703
  *
679
- * Auth Support
704
+ * Return a name for this EventBus based on the stack environment hash. This
705
+ * name is common across all stacks since it's using the environment hash in
706
+ * it's name.
680
707
  *
681
708
  ****************************************************************************/
682
- createUserPoolKmsKey() {
683
- return this.isAuthService ? new CoreUserPoolKmsKey(this) : CoreUserPoolKmsKey.fromConstruct(this);
684
- }
685
- createUserPool(props) {
686
- return this.isAuthService ? new CoreUserPool(this, props) : CoreUserPool.fromConstruct(this);
687
- }
688
- createUserPoolClient(props) {
689
- return this.isAuthService ? new CoreUserPoolClient(this, { userPool: props.userPool }) : CoreUserPoolClient.fromConstruct(this);
709
+ static getEventBusName(scope) {
710
+ const stack = OpenHiService.of(scope);
711
+ return `data${stack.branchHash}`;
690
712
  }
691
- createUserPoolDomain(props) {
692
- const service = OpenHiService.of(this);
693
- return this.isAuthService ? new CoreUserPoolDomain(this, {
694
- userPool: props.userPool,
695
- cognitoDomain: {
696
- domainPrefix: `auth-${service.branchHash}`
697
- }
698
- }) : CoreUserPoolDomain.fromConstruct(this);
713
+ constructor(scope, props) {
714
+ super(scope, "data-event-bus", {
715
+ ...props,
716
+ eventBusName: _DataEventBus.getEventBusName(scope)
717
+ });
699
718
  }
700
719
  };
701
720
 
702
- // src/services/open-hi-auth-service.ts
703
- var OpenHiAuthService = class extends OpenHiService {
704
- constructor(ohEnv, props = {}) {
705
- super(ohEnv, OPEN_HI_SERVICE_TYPE.AUTH, props);
706
- this.props = props;
707
- this.auth = new Auth(this, props.authProps);
721
+ // src/components/event-bridge/ops-event-bus.ts
722
+ import { EventBus as EventBus2 } from "aws-cdk-lib/aws-events";
723
+ var OpsEventBus = class _OpsEventBus extends EventBus2 {
724
+ /*****************************************************************************
725
+ *
726
+ * Return a name for this EventBus based on the stack environment hash. This
727
+ * name is common across all stacks since it's using the environment hash in
728
+ * it's name.
729
+ *
730
+ ****************************************************************************/
731
+ static getEventBusName(scope) {
732
+ const stack = OpenHiService.of(scope);
733
+ return `ops${stack.branchHash}`;
734
+ }
735
+ constructor(scope, props) {
736
+ super(scope, "ops-event-bus", {
737
+ ...props,
738
+ eventBusName: _OpsEventBus.getEventBusName(scope)
739
+ });
708
740
  }
709
741
  };
710
742
 
711
- // src/components/global.ts
712
- import {
713
- CertificateValidation
714
- } from "aws-cdk-lib/aws-certificatemanager";
715
- import { Construct as Construct3 } from "constructs";
716
-
717
- // src/components/acm/root-wildcard-certificate.ts
718
- import {
719
- Certificate
720
- } from "aws-cdk-lib/aws-certificatemanager";
721
- import { StringParameter as StringParameter2 } from "aws-cdk-lib/aws-ssm";
722
- var _RootWildcardCertificate = class _RootWildcardCertificate extends Certificate {
723
- /**
724
- * Using a special name here since this will be shared and used among many
725
- * stacks and services.
726
- */
727
- static ssmParameterName() {
728
- return "/" + ["GLOBAL", _RootWildcardCertificate.SSM_PARAM_NAME].join("/").toUpperCase();
729
- }
730
- static fromConstruct(scope) {
731
- const certificateArn = StringParameter2.valueForStringParameter(
732
- scope,
733
- _RootWildcardCertificate.ssmParameterName()
734
- );
735
- return Certificate.fromCertificateArn(
736
- scope,
737
- "wildcard-certificate",
738
- certificateArn
739
- );
740
- }
741
- constructor(scope, props) {
742
- super(scope, "root-wildcard-certificate", { ...props });
743
- new StringParameter2(this, "wildcard-cert-param", {
744
- parameterName: _RootWildcardCertificate.ssmParameterName(),
745
- stringValue: this.certificateArn
746
- });
747
- }
748
- };
749
- /**
750
- * Used when storing the Certificate ARN in SSM.
751
- */
752
- _RootWildcardCertificate.SSM_PARAM_NAME = "ROOT_WILDCARD_CERT_ARN";
753
- var RootWildcardCertificate = _RootWildcardCertificate;
754
-
755
- // src/components/route-53/child-hosted-zone.ts
756
- import { Duration } from "aws-cdk-lib";
743
+ // src/components/route-53/child-hosted-zone.ts
744
+ import { Duration } from "aws-cdk-lib";
757
745
  import {
758
746
  HostedZone,
759
747
  NsRecord
760
748
  } from "aws-cdk-lib/aws-route53";
761
- var _ChildHostedZone = class _ChildHostedZone extends HostedZone {
762
- static fromConstruct(scope, props) {
763
- const hostedZoneId = DiscoverableStringParameter.valueForLookupName(scope, {
764
- ssmParamName: _ChildHostedZone.SSM_PARAM_NAME,
765
- serviceType: props.serviceType ?? OPEN_HI_SERVICE_TYPE.GLOBAL
766
- });
767
- return HostedZone.fromHostedZoneAttributes(scope, "child-zone", {
768
- hostedZoneId,
769
- zoneName: props.zoneName
770
- });
771
- }
749
+ var ChildHostedZone = class extends HostedZone {
772
750
  constructor(scope, id, props) {
773
751
  super(scope, id, { ...props });
774
752
  new NsRecord(this, "child-ns-record", {
@@ -777,66 +755,211 @@ var _ChildHostedZone = class _ChildHostedZone extends HostedZone {
777
755
  values: this.hostedZoneNameServers || [],
778
756
  ttl: Duration.minutes(5)
779
757
  });
780
- new DiscoverableStringParameter(this, "child-zone-param", {
781
- ssmParamName: _ChildHostedZone.SSM_PARAM_NAME,
782
- stringValue: this.hostedZoneId,
783
- description: "Route53 child hosted zone ID."
784
- });
785
758
  }
786
759
  };
787
760
  /**
788
- * Used when storing the API ID in SSM.
761
+ * Used when storing the child zone ID in SSM. Use {@link OpenHiGlobalService.childHostedZoneFromConstruct} to look up.
789
762
  */
790
- _ChildHostedZone.SSM_PARAM_NAME = "CHILDHOSTEDZONE";
791
- var ChildHostedZone = _ChildHostedZone;
763
+ ChildHostedZone.SSM_PARAM_NAME = "CHILDHOSTEDZONE";
792
764
 
793
765
  // src/components/route-53/root-hosted-zone.ts
794
- import {
795
- HostedZone as HostedZone2
796
- } from "aws-cdk-lib/aws-route53";
797
- import { Construct as Construct2 } from "constructs";
798
- var RootHostedZone = class extends Construct2 {
799
- static fromConstruct(scope, props) {
800
- return HostedZone2.fromHostedZoneAttributes(scope, "root-zone", {
801
- hostedZoneId: props.hostedZoneId,
802
- zoneName: props.zoneName
803
- });
804
- }
766
+ import { Construct } from "constructs";
767
+ var RootHostedZone = class extends Construct {
805
768
  };
806
769
 
807
- // src/components/global.ts
808
- var Global = class extends Construct3 {
809
- constructor(scope, id, props) {
810
- super(scope, id);
770
+ // src/services/open-hi-auth-service.ts
771
+ import {
772
+ UserPool as UserPool2,
773
+ UserPoolClient as UserPoolClient2,
774
+ UserPoolDomain as UserPoolDomain2
775
+ } from "aws-cdk-lib/aws-cognito";
776
+ import { Key as Key2 } from "aws-cdk-lib/aws-kms";
777
+ var _OpenHiAuthService = class _OpenHiAuthService extends OpenHiService {
778
+ constructor(ohEnv, props = {}) {
779
+ super(ohEnv, _OpenHiAuthService.SERVICE_TYPE, props);
811
780
  this.props = props;
812
- const { rootHostedZoneAttributes, childHostedZoneAttributes } = props;
813
- const service = OpenHiService.of(this);
814
- this.rootHostedZone = RootHostedZone.fromConstruct(
815
- this,
816
- rootHostedZoneAttributes
781
+ this.userPoolKmsKey = this.createUserPoolKmsKey();
782
+ this.userPool = this.createUserPool();
783
+ this.userPoolClient = this.createUserPoolClient();
784
+ this.userPoolDomain = this.createUserPoolDomain();
785
+ }
786
+ /**
787
+ * Returns an IUserPool by looking up the Auth stack's User Pool ID from SSM.
788
+ */
789
+ static userPoolFromConstruct(scope) {
790
+ const userPoolId = DiscoverableStringParameter.valueForLookupName(scope, {
791
+ ssmParamName: CognitoUserPool.SSM_PARAM_NAME,
792
+ serviceType: _OpenHiAuthService.SERVICE_TYPE
793
+ });
794
+ return UserPool2.fromUserPoolId(scope, "user-pool", userPoolId);
795
+ }
796
+ /**
797
+ * Returns an IUserPoolClient by looking up the Auth stack's User Pool Client ID from SSM.
798
+ */
799
+ static userPoolClientFromConstruct(scope) {
800
+ const userPoolClientId = DiscoverableStringParameter.valueForLookupName(
801
+ scope,
802
+ {
803
+ ssmParamName: CognitoUserPoolClient.SSM_PARAM_NAME,
804
+ serviceType: _OpenHiAuthService.SERVICE_TYPE
805
+ }
817
806
  );
818
- if (childHostedZoneAttributes) {
819
- this.childHostedZone = new ChildHostedZone(this, "child-zone", {
820
- parentHostedZone: this.rootHostedZone,
821
- zoneName: childHostedZoneAttributes.zoneName
822
- });
823
- }
824
- if (service.branchName === "main") {
825
- this.rootWildcardCertificate = new RootWildcardCertificate(this, {
826
- domainName: `*.${this.rootHostedZone.zoneName}`,
827
- subjectAlternativeNames: [this.rootHostedZone.zoneName],
828
- validation: CertificateValidation.fromDns(this.rootHostedZone)
829
- });
830
- } else {
831
- this.rootWildcardCertificate = RootWildcardCertificate.fromConstruct(this);
832
- }
807
+ return UserPoolClient2.fromUserPoolClientId(
808
+ scope,
809
+ "user-pool-client",
810
+ userPoolClientId
811
+ );
812
+ }
813
+ /**
814
+ * Returns an IUserPoolDomain by looking up the Auth stack's User Pool Domain from SSM.
815
+ */
816
+ static userPoolDomainFromConstruct(scope) {
817
+ const domainName = DiscoverableStringParameter.valueForLookupName(scope, {
818
+ ssmParamName: CognitoUserPoolDomain.SSM_PARAM_NAME,
819
+ serviceType: _OpenHiAuthService.SERVICE_TYPE
820
+ });
821
+ return UserPoolDomain2.fromDomainName(scope, "user-pool-domain", domainName);
822
+ }
823
+ /**
824
+ * Returns an IKey (KMS) by looking up the Auth stack's User Pool KMS Key ARN from SSM.
825
+ */
826
+ static userPoolKmsKeyFromConstruct(scope) {
827
+ const keyArn = DiscoverableStringParameter.valueForLookupName(scope, {
828
+ ssmParamName: CognitoUserPoolKmsKey.SSM_PARAM_NAME,
829
+ serviceType: _OpenHiAuthService.SERVICE_TYPE
830
+ });
831
+ return Key2.fromKeyArn(scope, "kms-key", keyArn);
832
+ }
833
+ get serviceType() {
834
+ return _OpenHiAuthService.SERVICE_TYPE;
835
+ }
836
+ /**
837
+ * Creates the KMS key for the Cognito User Pool and exports its ARN to SSM.
838
+ * Look up via {@link OpenHiAuthService.userPoolKmsKeyFromConstruct}.
839
+ * Override to customize.
840
+ */
841
+ createUserPoolKmsKey() {
842
+ const key = new CognitoUserPoolKmsKey(this);
843
+ new DiscoverableStringParameter(this, "kms-key-param", {
844
+ ssmParamName: CognitoUserPoolKmsKey.SSM_PARAM_NAME,
845
+ stringValue: key.keyArn,
846
+ description: "KMS key ARN for Cognito User Pool (e.g. custom sender); cross-stack reference"
847
+ });
848
+ return key;
849
+ }
850
+ /**
851
+ * Creates the Cognito User Pool and exports its ID to SSM.
852
+ * Look up via {@link OpenHiAuthService.userPoolFromConstruct}.
853
+ * Override to customize.
854
+ */
855
+ createUserPool() {
856
+ const userPool = new CognitoUserPool(this, {
857
+ ...this.props.userPoolProps,
858
+ customSenderKmsKey: this.userPoolKmsKey
859
+ });
860
+ new DiscoverableStringParameter(this, "user-pool-param", {
861
+ ssmParamName: CognitoUserPool.SSM_PARAM_NAME,
862
+ stringValue: userPool.userPoolId,
863
+ description: "Cognito User Pool ID for this Auth stack; cross-stack reference"
864
+ });
865
+ return userPool;
866
+ }
867
+ /**
868
+ * Creates the User Pool Client and exports its ID to SSM (AUTH service type).
869
+ * Look up via {@link OpenHiAuthService.userPoolClientFromConstruct}.
870
+ * Override to customize.
871
+ */
872
+ createUserPoolClient() {
873
+ const client = new CognitoUserPoolClient(this, {
874
+ userPool: this.userPool
875
+ });
876
+ new DiscoverableStringParameter(this, "user-pool-client-param", {
877
+ ssmParamName: CognitoUserPoolClient.SSM_PARAM_NAME,
878
+ stringValue: client.userPoolClientId,
879
+ description: "Cognito User Pool Client ID for this Auth stack; cross-stack reference"
880
+ });
881
+ return client;
882
+ }
883
+ /**
884
+ * Creates the User Pool Domain (Cognito hosted UI) and exports domain name to SSM.
885
+ * Look up via {@link OpenHiAuthService.userPoolDomainFromConstruct}.
886
+ * Override to customize.
887
+ */
888
+ createUserPoolDomain() {
889
+ const domain = new CognitoUserPoolDomain(this, {
890
+ userPool: this.userPool,
891
+ cognitoDomain: {
892
+ domainPrefix: `auth-${this.branchHash}`
893
+ }
894
+ });
895
+ new DiscoverableStringParameter(this, "user-pool-domain-param", {
896
+ ssmParamName: CognitoUserPoolDomain.SSM_PARAM_NAME,
897
+ stringValue: domain.domainName,
898
+ description: "Cognito User Pool Domain (hosted UI) for this Auth stack; cross-stack reference"
899
+ });
900
+ return domain;
833
901
  }
834
902
  };
903
+ _OpenHiAuthService.SERVICE_TYPE = "auth";
904
+ var OpenHiAuthService = _OpenHiAuthService;
835
905
 
836
906
  // src/services/open-hi-global-service.ts
837
- var OpenHiGlobalService = class extends OpenHiService {
907
+ import {
908
+ Certificate as Certificate2,
909
+ CertificateValidation
910
+ } from "aws-cdk-lib/aws-certificatemanager";
911
+ import {
912
+ HostedZone as HostedZone2
913
+ } from "aws-cdk-lib/aws-route53";
914
+ import { StringParameter as StringParameter3 } from "aws-cdk-lib/aws-ssm";
915
+ var _OpenHiGlobalService = class _OpenHiGlobalService extends OpenHiService {
916
+ /**
917
+ * Returns an IHostedZone from the given attributes (no SSM). Use when the zone is imported from config.
918
+ */
919
+ static rootHostedZoneFromConstruct(scope, props) {
920
+ return HostedZone2.fromHostedZoneAttributes(scope, "root-zone", props);
921
+ }
922
+ /**
923
+ * Returns an ICertificate by looking up the Global stack's wildcard cert ARN from SSM.
924
+ */
925
+ static rootWildcardCertificateFromConstruct(scope) {
926
+ const certificateArn = StringParameter3.valueForStringParameter(
927
+ scope,
928
+ RootWildcardCertificate.ssmParameterName()
929
+ );
930
+ return Certificate2.fromCertificateArn(
931
+ scope,
932
+ "wildcard-certificate",
933
+ certificateArn
934
+ );
935
+ }
936
+ /**
937
+ * Returns an IHostedZone by looking up the child hosted zone ID from SSM. Defaults to GLOBAL service type.
938
+ */
939
+ static childHostedZoneFromConstruct(scope, props) {
940
+ const hostedZoneId = DiscoverableStringParameter.valueForLookupName(scope, {
941
+ ssmParamName: ChildHostedZone.SSM_PARAM_NAME,
942
+ serviceType: props.serviceType ?? _OpenHiGlobalService.SERVICE_TYPE
943
+ });
944
+ return HostedZone2.fromHostedZoneAttributes(scope, "child-zone", {
945
+ hostedZoneId,
946
+ zoneName: props.zoneName
947
+ });
948
+ }
949
+ get serviceType() {
950
+ return _OpenHiGlobalService.SERVICE_TYPE;
951
+ }
838
952
  constructor(ohEnv, props = {}) {
839
- super(ohEnv, OPEN_HI_SERVICE_TYPE.GLOBAL, props);
953
+ super(ohEnv, _OpenHiGlobalService.SERVICE_TYPE, props);
954
+ this.validateConfig(props);
955
+ this.rootHostedZone = this.createRootHostedZone();
956
+ this.childHostedZone = this.createChildHostedZone();
957
+ this.rootWildcardCertificate = this.createRootWildcardCertificate();
958
+ }
959
+ /**
960
+ * Validates that config required for the Global stack is present.
961
+ */
962
+ validateConfig(props) {
840
963
  const { config } = props;
841
964
  if (!config) {
842
965
  throw new Error("Config is required");
@@ -847,169 +970,136 @@ var OpenHiGlobalService = class extends OpenHiService {
847
970
  if (!config.hostedZoneId) {
848
971
  throw new Error("Hosted zone ID is required to import the root zone");
849
972
  }
850
- this.global = new Global(this, "global", {
851
- rootHostedZoneAttributes: {
852
- zoneName: config.zoneName,
853
- hostedZoneId: config.hostedZoneId
854
- }
855
- /*
856
- childHostedZoneAttributes: {
857
- zoneName: `${this.childZonePrefix}.${config.zoneName}`,
858
- hostedZoneId: config.hostedZoneId,
859
- },
860
- */
973
+ }
974
+ /**
975
+ * Creates the root hosted zone (imported via attributes from config).
976
+ * Override to customize or create the zone.
977
+ */
978
+ createRootHostedZone() {
979
+ return _OpenHiGlobalService.rootHostedZoneFromConstruct(this, {
980
+ zoneName: this.config.zoneName,
981
+ hostedZoneId: this.config.hostedZoneId
861
982
  });
862
983
  }
984
+ /**
985
+ * Creates the optional child hosted zone (e.g. branch subdomain).
986
+ * Override to create a child zone when config provides childHostedZoneAttributes.
987
+ * If you create a ChildHostedZone, also create a DiscoverableStringParameter
988
+ * with ChildHostedZone.SSM_PARAM_NAME and the zone's hostedZoneId.
989
+ */
990
+ createChildHostedZone() {
991
+ return void 0;
992
+ }
993
+ /**
994
+ * Creates the root wildcard certificate. On main branch, creates a new cert
995
+ * with DNS validation; otherwise imports from SSM.
996
+ * Override to customize certificate creation.
997
+ */
998
+ createRootWildcardCertificate() {
999
+ if (this.branchName === "main") {
1000
+ return new RootWildcardCertificate(this, {
1001
+ domainName: `*.${this.rootHostedZone.zoneName}`,
1002
+ subjectAlternativeNames: [this.rootHostedZone.zoneName],
1003
+ validation: CertificateValidation.fromDns(this.rootHostedZone)
1004
+ });
1005
+ }
1006
+ return _OpenHiGlobalService.rootWildcardCertificateFromConstruct(this);
1007
+ }
863
1008
  };
1009
+ _OpenHiGlobalService.SERVICE_TYPE = "global";
1010
+ var OpenHiGlobalService = _OpenHiGlobalService;
864
1011
 
865
1012
  // src/services/open-hi-rest-api-service.ts
866
1013
  import {
867
1014
  DomainName,
1015
+ HttpApi as HttpApi2,
868
1016
  HttpMethod,
869
1017
  HttpRoute,
870
1018
  HttpRouteKey
871
1019
  } from "aws-cdk-lib/aws-apigatewayv2";
872
1020
  import { HttpLambdaIntegration } from "aws-cdk-lib/aws-apigatewayv2-integrations";
873
- import { ARecord, HostedZone as HostedZone3, RecordTarget } from "aws-cdk-lib/aws-route53";
1021
+ import {
1022
+ ARecord,
1023
+ HostedZone as HostedZone3,
1024
+ RecordTarget
1025
+ } from "aws-cdk-lib/aws-route53";
874
1026
  import { ApiGatewayv2DomainProperties } from "aws-cdk-lib/aws-route53-targets";
875
1027
 
876
- // src/components/api-gateway/core-http-api.ts
877
- import { HttpApi } from "aws-cdk-lib/aws-apigatewayv2";
878
- var _CoreHttpApi = class _CoreHttpApi extends HttpApi {
879
- static fromConstruct(scope) {
880
- const httpApiId = DiscoverableStringParameter.valueForLookupName(scope, {
881
- ssmParamName: _CoreHttpApi.SSM_PARAM_NAME,
882
- serviceType: OPEN_HI_SERVICE_TYPE.REST_API
883
- });
884
- return HttpApi.fromHttpApiAttributes(scope, "http-api", {
885
- httpApiId
886
- });
1028
+ // src/services/open-hi-data-service.ts
1029
+ import { Table as Table2 } from "aws-cdk-lib/aws-dynamodb";
1030
+ import { EventBus as EventBus3 } from "aws-cdk-lib/aws-events";
1031
+ var _OpenHiDataService = class _OpenHiDataService extends OpenHiService {
1032
+ /**
1033
+ * Returns the data event bus by name (deterministic per branch). Use from other stacks to obtain an IEventBus reference.
1034
+ */
1035
+ static dataEventBusFromConstruct(scope) {
1036
+ return EventBus3.fromEventBusName(
1037
+ scope,
1038
+ "data-event-bus",
1039
+ DataEventBus.getEventBusName(scope)
1040
+ );
887
1041
  }
888
- constructor(scope, props = {}) {
889
- const stack = OpenHiService.of(scope);
890
- super(scope, "http-api", {
891
- /**
892
- * User provided props
893
- */
894
- ...props,
895
- /**
896
- * Required
897
- */
898
- apiName: ["core", "http", "api", stack.branchHash].join("-")
899
- });
900
- new DiscoverableStringParameter(this, "http-api-url-param", {
901
- ssmParamName: _CoreHttpApi.SSM_PARAM_NAME,
902
- serviceType: OPEN_HI_SERVICE_TYPE.REST_API,
903
- stringValue: this.httpApiId
904
- });
1042
+ /**
1043
+ * Returns the ops event bus by name (deterministic per branch). Use from other stacks to obtain an IEventBus reference.
1044
+ */
1045
+ static opsEventBusFromConstruct(scope) {
1046
+ return EventBus3.fromEventBusName(
1047
+ scope,
1048
+ "ops-event-bus",
1049
+ OpsEventBus.getEventBusName(scope)
1050
+ );
905
1051
  }
906
- };
907
- /**
908
- * Used when storing the API ID in SSM.
909
- */
910
- _CoreHttpApi.SSM_PARAM_NAME = "CORE_HTTP_API";
911
- var CoreHttpApi = _CoreHttpApi;
912
-
913
- // src/components/dynamodb/dynamo-db-data-store.ts
914
- import {
915
- AttributeType,
916
- BillingMode,
917
- ProjectionType,
918
- Table
919
- } from "aws-cdk-lib/aws-dynamodb";
920
- function getDynamoDbDataStoreTableName(scope) {
921
- const stack = OpenHiService.of(scope);
922
- return `data-store-${stack.branchHash}`;
923
- }
924
- var DynamoDbDataStore = class extends Table {
925
1052
  /**
926
- * Import the data store table by name for use in another stack (e.g. data
927
- * service or Lambda). Uses the same naming as {@link getDynamoDbDataStoreTableName}.
1053
+ * Returns the data store table by name. Use from other stacks (e.g. REST API Lambda) to obtain an ITable reference.
928
1054
  */
929
- static fromConstruct(scope, id = "dynamo-db-data-store") {
930
- return Table.fromTableName(scope, id, getDynamoDbDataStoreTableName(scope));
1055
+ static dynamoDbDataStoreFromConstruct(scope, id = "dynamo-db-data-store") {
1056
+ return Table2.fromTableName(scope, id, getDynamoDbDataStoreTableName(scope));
931
1057
  }
932
- constructor(scope, id, props = {}) {
933
- const service = OpenHiService.of(scope);
934
- super(scope, id, {
935
- ...props,
936
- tableName: getDynamoDbDataStoreTableName(scope),
937
- partitionKey: {
938
- name: "PK",
939
- type: AttributeType.STRING
940
- },
941
- sortKey: {
942
- name: "SK",
943
- type: AttributeType.STRING
944
- },
945
- billingMode: BillingMode.PAY_PER_REQUEST,
946
- removalPolicy: props.removalPolicy ?? service.removalPolicy
947
- });
948
- this.addGlobalSecondaryIndex({
949
- indexName: "GSI1",
950
- partitionKey: {
951
- name: "GSI1PK",
952
- type: AttributeType.STRING
953
- },
954
- sortKey: {
955
- name: "GSI1SK",
956
- type: AttributeType.STRING
957
- },
958
- projectionType: ProjectionType.INCLUDE,
959
- nonKeyAttributes: ["srcType", "srcId", "path", "srcPk", "srcSk", "ts"]
960
- });
961
- this.addGlobalSecondaryIndex({
962
- indexName: "GSI2",
963
- partitionKey: {
964
- name: "GSI2PK",
965
- type: AttributeType.STRING
966
- },
967
- sortKey: {
968
- name: "GSI2SK",
969
- type: AttributeType.STRING
970
- },
971
- projectionType: ProjectionType.INCLUDE,
972
- nonKeyAttributes: ["resourcePk", "resourceSk", "display", "status"]
973
- });
974
- this.addGlobalSecondaryIndex({
975
- indexName: "GSI3",
976
- partitionKey: {
977
- name: "GSI3PK",
978
- type: AttributeType.STRING
979
- },
980
- sortKey: {
981
- name: "GSI3SK",
982
- type: AttributeType.STRING
983
- },
984
- projectionType: ProjectionType.INCLUDE,
985
- nonKeyAttributes: ["resourcePk", "resourceSk"]
986
- });
987
- this.addGlobalSecondaryIndex({
988
- indexName: "GSI4",
989
- partitionKey: {
990
- name: "GSI4PK",
991
- type: AttributeType.STRING
992
- },
993
- sortKey: {
994
- name: "GSI4SK",
995
- type: AttributeType.STRING
996
- },
997
- projectionType: ProjectionType.ALL
998
- });
1058
+ get serviceType() {
1059
+ return _OpenHiDataService.SERVICE_TYPE;
1060
+ }
1061
+ constructor(ohEnv, props = {}) {
1062
+ super(ohEnv, _OpenHiDataService.SERVICE_TYPE, props);
1063
+ this.dataEventBus = this.createDataEventBus();
1064
+ this.opsEventBus = this.createOpsEventBus();
1065
+ this.dataStore = this.createDataStore();
1066
+ }
1067
+ /**
1068
+ * Creates the data event bus.
1069
+ * Override to customize.
1070
+ */
1071
+ createDataEventBus() {
1072
+ return new DataEventBus(this);
1073
+ }
1074
+ /**
1075
+ * Creates the ops event bus.
1076
+ * Override to customize.
1077
+ */
1078
+ createOpsEventBus() {
1079
+ return new OpsEventBus(this);
1080
+ }
1081
+ /**
1082
+ * Creates the single-table DynamoDB data store.
1083
+ * Override to customize.
1084
+ */
1085
+ createDataStore() {
1086
+ return new DynamoDbDataStore(this, "dynamo-db-data-store");
999
1087
  }
1000
1088
  };
1089
+ _OpenHiDataService.SERVICE_TYPE = "data";
1090
+ var OpenHiDataService = _OpenHiDataService;
1001
1091
 
1002
1092
  // src/data/lambda/rest-api-lambda.ts
1003
1093
  import path from "path";
1004
- import { Runtime as Runtime2 } from "aws-cdk-lib/aws-lambda";
1094
+ import { Runtime } from "aws-cdk-lib/aws-lambda";
1005
1095
  import { NodejsFunction } from "aws-cdk-lib/aws-lambda-nodejs";
1006
- import { Construct as Construct4 } from "constructs";
1007
- var RestApiLambda = class extends Construct4 {
1096
+ import { Construct as Construct2 } from "constructs";
1097
+ var RestApiLambda = class extends Construct2 {
1008
1098
  constructor(scope, props) {
1009
1099
  super(scope, "rest-api-lambda");
1010
1100
  this.lambda = new NodejsFunction(this, "handler", {
1011
1101
  entry: path.join(__dirname, "rest-api-lambda.handler.js"),
1012
- runtime: Runtime2.NODEJS_LATEST,
1102
+ runtime: Runtime.NODEJS_LATEST,
1013
1103
  environment: {
1014
1104
  DYNAMO_TABLE_NAME: props.dynamoTableName
1015
1105
  }
@@ -1019,9 +1109,45 @@ var RestApiLambda = class extends Construct4 {
1019
1109
 
1020
1110
  // src/services/open-hi-rest-api-service.ts
1021
1111
  var REST_API_BASE_URL_SSM_NAME = "REST_API_BASE_URL";
1022
- var OpenHiRestApiService = class extends OpenHiService {
1112
+ var _OpenHiRestApiService = class _OpenHiRestApiService extends OpenHiService {
1113
+ /**
1114
+ * Returns an IHttpApi by looking up the REST API stack's HTTP API ID from SSM.
1115
+ */
1116
+ static rootHttpApiFromConstruct(scope) {
1117
+ const httpApiId = DiscoverableStringParameter.valueForLookupName(scope, {
1118
+ ssmParamName: RootHttpApi.SSM_PARAM_NAME,
1119
+ serviceType: _OpenHiRestApiService.SERVICE_TYPE
1120
+ });
1121
+ return HttpApi2.fromHttpApiAttributes(scope, "http-api", { httpApiId });
1122
+ }
1123
+ /**
1124
+ * Returns the REST API base URL (e.g. https://api.example.com) by looking it up from SSM.
1125
+ * Use in other stacks for E2E, scripts, or config.
1126
+ */
1127
+ static restApiBaseUrlFromConstruct(scope) {
1128
+ return DiscoverableStringParameter.valueForLookupName(scope, {
1129
+ ssmParamName: REST_API_BASE_URL_SSM_NAME,
1130
+ serviceType: _OpenHiRestApiService.SERVICE_TYPE
1131
+ });
1132
+ }
1133
+ get serviceType() {
1134
+ return _OpenHiRestApiService.SERVICE_TYPE;
1135
+ }
1023
1136
  constructor(ohEnv, props = {}) {
1024
- super(ohEnv, OPEN_HI_SERVICE_TYPE.REST_API, props);
1137
+ super(ohEnv, _OpenHiRestApiService.SERVICE_TYPE, props);
1138
+ this.validateConfig(props);
1139
+ const hostedZone = this.createHostedZone();
1140
+ const certificate = this.createCertificate();
1141
+ const apiDomainName = this.createApiDomainNameString(hostedZone);
1142
+ this.createRestApiBaseUrlParameter(apiDomainName);
1143
+ const domainName = this.createDomainName(hostedZone, certificate);
1144
+ this.rootHttpApi = this.createRootHttpApi(domainName);
1145
+ this.createRestApiLambdaAndRoutes(hostedZone, domainName);
1146
+ }
1147
+ /**
1148
+ * Validates that config required for the REST API stack is present.
1149
+ */
1150
+ validateConfig(props) {
1025
1151
  const { config } = props;
1026
1152
  if (!config) {
1027
1153
  throw new Error("Config is required");
@@ -1032,31 +1158,63 @@ var OpenHiRestApiService = class extends OpenHiService {
1032
1158
  if (!config.zoneName) {
1033
1159
  throw new Error("Zone name is required");
1034
1160
  }
1035
- const hostedZone = HostedZone3.fromHostedZoneAttributes(this, "root-zone", {
1161
+ }
1162
+ /**
1163
+ * Creates the hosted zone reference (imported from config).
1164
+ * Override to customize.
1165
+ */
1166
+ createHostedZone() {
1167
+ const { config } = this.props;
1168
+ return HostedZone3.fromHostedZoneAttributes(this, "root-zone", {
1036
1169
  hostedZoneId: config.hostedZoneId,
1037
1170
  zoneName: config.zoneName
1038
1171
  });
1039
- const certificate = RootWildcardCertificate.fromConstruct(this);
1172
+ }
1173
+ /**
1174
+ * Creates the wildcard certificate (imported from Global stack via SSM).
1175
+ * Override to customize.
1176
+ */
1177
+ createCertificate() {
1178
+ return OpenHiGlobalService.rootWildcardCertificateFromConstruct(this);
1179
+ }
1180
+ /**
1181
+ * Returns the API domain name string (e.g. api.example.com or api-{prefix}.example.com).
1182
+ * Override to customize.
1183
+ */
1184
+ createApiDomainNameString(hostedZone) {
1040
1185
  const apiPrefix = this.branchName === "main" ? `api` : `api-${this.childZonePrefix}`;
1041
- const apiDomainName = [apiPrefix, hostedZone.zoneName].join(".");
1186
+ return [apiPrefix, hostedZone.zoneName].join(".");
1187
+ }
1188
+ /**
1189
+ * Creates the SSM parameter for the REST API base URL.
1190
+ * Look up via {@link OpenHiRestApiService.restApiBaseUrlFromConstruct}.
1191
+ * Override to customize.
1192
+ */
1193
+ createRestApiBaseUrlParameter(apiDomainName) {
1042
1194
  const restApiBaseUrl = `https://${apiDomainName}`;
1043
1195
  new DiscoverableStringParameter(this, "rest-api-base-url-param", {
1044
1196
  ssmParamName: REST_API_BASE_URL_SSM_NAME,
1045
1197
  stringValue: restApiBaseUrl,
1046
1198
  description: "REST API base URL for this deployment (E2E, scripts)"
1047
1199
  });
1048
- const domainName = new DomainName(this, "domain", {
1200
+ }
1201
+ /**
1202
+ * Creates the API Gateway custom domain name resource.
1203
+ * Override to customize.
1204
+ */
1205
+ createDomainName(_hostedZone, certificate) {
1206
+ const apiDomainName = this.createApiDomainNameString(_hostedZone);
1207
+ return new DomainName(this, "domain", {
1049
1208
  domainName: apiDomainName,
1050
1209
  certificate
1051
1210
  });
1052
- this.coreHttpApi = new CoreHttpApi(this, {
1053
- defaultDomainMapping: {
1054
- domainName,
1055
- mappingKey: void 0
1056
- // serve at root of domain
1057
- }
1058
- });
1059
- const dataStoreTable = DynamoDbDataStore.fromConstruct(this);
1211
+ }
1212
+ /**
1213
+ * Creates the Lambda integration, HTTP routes, and API DNS record.
1214
+ * Override to customize. Uses {@link rootHttpApi} set by the constructor.
1215
+ */
1216
+ createRestApiLambdaAndRoutes(hostedZone, domainName) {
1217
+ const dataStoreTable = OpenHiDataService.dynamoDbDataStoreFromConstruct(this);
1060
1218
  const { lambda } = new RestApiLambda(this, {
1061
1219
  dynamoTableName: dataStoreTable.tableName
1062
1220
  });
@@ -1074,15 +1232,16 @@ var OpenHiRestApiService = class extends OpenHiService {
1074
1232
  );
1075
1233
  const integration = new HttpLambdaIntegration("lambda-integration", lambda);
1076
1234
  new HttpRoute(this, "proxy-route-root", {
1077
- httpApi: this.coreHttpApi,
1235
+ httpApi: this.rootHttpApi,
1078
1236
  routeKey: HttpRouteKey.with("/", HttpMethod.ANY),
1079
1237
  integration
1080
1238
  });
1081
1239
  new HttpRoute(this, "proxy-route", {
1082
- httpApi: this.coreHttpApi,
1240
+ httpApi: this.rootHttpApi,
1083
1241
  routeKey: HttpRouteKey.with("/{proxy+}", HttpMethod.ANY),
1084
1242
  integration
1085
1243
  });
1244
+ const apiPrefix = this.branchName === "main" ? `api` : `api-${this.childZonePrefix}`;
1086
1245
  new ARecord(this, "api-a-record", {
1087
1246
  zone: hostedZone,
1088
1247
  recordName: apiPrefix,
@@ -1094,27 +1253,51 @@ var OpenHiRestApiService = class extends OpenHiService {
1094
1253
  )
1095
1254
  });
1096
1255
  }
1097
- };
1098
-
1099
- // src/services/open-hi-data-service.ts
1100
- var OpenHiDataService = class extends OpenHiService {
1101
- constructor(ohEnv, props = {}) {
1102
- super(ohEnv, OPEN_HI_SERVICE_TYPE.DATA, props);
1103
- this.dataStore = new DynamoDbDataStore(this, "dynamo-db-data-store");
1256
+ /**
1257
+ * Creates the Root HTTP API with default domain mapping and exports API ID to SSM.
1258
+ * Look up via {@link OpenHiRestApiService.rootHttpApiFromConstruct}.
1259
+ * Override to customize.
1260
+ */
1261
+ createRootHttpApi(domainName) {
1262
+ const rootHttpApi = new RootHttpApi(this, {
1263
+ defaultDomainMapping: {
1264
+ domainName,
1265
+ mappingKey: void 0
1266
+ }
1267
+ });
1268
+ new DiscoverableStringParameter(this, "http-api-url-param", {
1269
+ ssmParamName: RootHttpApi.SSM_PARAM_NAME,
1270
+ stringValue: rootHttpApi.httpApiId,
1271
+ description: "API Gateway HTTP API ID for this REST API stack (cross-stack reference)"
1272
+ });
1273
+ return rootHttpApi;
1104
1274
  }
1105
1275
  };
1276
+ _OpenHiRestApiService.SERVICE_TYPE = "rest-api";
1277
+ var OpenHiRestApiService = _OpenHiRestApiService;
1106
1278
  export {
1279
+ ChildHostedZone,
1280
+ CognitoUserPool,
1281
+ CognitoUserPoolClient,
1282
+ CognitoUserPoolDomain,
1283
+ CognitoUserPoolKmsKey,
1284
+ DataEventBus,
1107
1285
  DiscoverableStringParameter,
1108
- OPEN_HI_SERVICE_TYPE,
1286
+ DynamoDbDataStore,
1109
1287
  OpenHiApp,
1110
1288
  OpenHiAuthService,
1111
- OpenHiCoreService,
1112
1289
  OpenHiDataService,
1113
1290
  OpenHiEnvironment,
1114
1291
  OpenHiGlobalService,
1115
1292
  OpenHiRestApiService,
1116
1293
  OpenHiService,
1117
1294
  OpenHiStage,
1118
- REST_API_BASE_URL_SSM_NAME
1295
+ OpsEventBus,
1296
+ REST_API_BASE_URL_SSM_NAME,
1297
+ RootGraphqlApi,
1298
+ RootHostedZone,
1299
+ RootHttpApi,
1300
+ RootWildcardCertificate,
1301
+ getDynamoDbDataStoreTableName
1119
1302
  };
1120
1303
  //# sourceMappingURL=index.mjs.map