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