cdk-factory 0.7.29__tar.gz → 0.7.31__tar.gz

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.

Potentially problematic release.


This version of cdk-factory might be problematic. Click here for more details.

Files changed (133) hide show
  1. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/PKG-INFO +1 -1
  2. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/pyproject.toml +1 -1
  3. cdk_factory-0.7.31/src/cdk_factory/configurations/resources/rum.py +135 -0
  4. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/constructs/cloudfront/cloudfront_distribution_construct.py +113 -1
  5. cdk_factory-0.7.31/src/cdk_factory/stack_library/rum/__init__.py +7 -0
  6. cdk_factory-0.7.31/src/cdk_factory/stack_library/rum/rum_stack.py +332 -0
  7. cdk_factory-0.7.31/src/cdk_factory/version.py +1 -0
  8. cdk_factory-0.7.29/src/cdk_factory/version.py +0 -1
  9. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/.gitignore +0 -0
  10. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/LICENSE +0 -0
  11. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/README.md +0 -0
  12. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/archive/README.md +0 -0
  13. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/archive/migrate_to_enhanced_ssm.py +0 -0
  14. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/mypy.ini +0 -0
  15. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/publish_to_pypi.py +0 -0
  16. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/publish_to_pypi.sh +0 -0
  17. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/pysetup.py +0 -0
  18. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/pysetup.sh +0 -0
  19. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/requirements.dev.txt +0 -0
  20. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/requirements.tests.txt +0 -0
  21. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/requirements.txt +0 -0
  22. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/run-checks.sh +0 -0
  23. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/run-tests.sh +0 -0
  24. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/__init__.py +0 -0
  25. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/app.py +0 -0
  26. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/builds/README.md +0 -0
  27. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/cdk.json +0 -0
  28. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/commands/command_loader.py +0 -0
  29. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/configurations/base_config.py +0 -0
  30. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/configurations/cdk_config.py +0 -0
  31. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/configurations/deployment.py +0 -0
  32. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/configurations/deployment_wave.py +0 -0
  33. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/configurations/devops.py +0 -0
  34. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/configurations/enhanced_base_config.py +0 -0
  35. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/configurations/enhanced_ssm_config.py +0 -0
  36. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/configurations/management.py +0 -0
  37. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/configurations/pipeline.py +0 -0
  38. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/configurations/pipeline_stage.py +0 -0
  39. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/configurations/resources/_resources.py +0 -0
  40. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/configurations/resources/api_gateway.py +0 -0
  41. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/configurations/resources/apigateway_route_config.py +0 -0
  42. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/configurations/resources/auto_scaling.py +0 -0
  43. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/configurations/resources/cloudfront.py +0 -0
  44. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/configurations/resources/cloudwatch_widget.py +0 -0
  45. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/configurations/resources/code_artifact.py +0 -0
  46. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/configurations/resources/code_artifact_login.py +0 -0
  47. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/configurations/resources/code_repository.py +0 -0
  48. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/configurations/resources/cognito.py +0 -0
  49. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/configurations/resources/docker.py +0 -0
  50. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/configurations/resources/dynamodb.py +0 -0
  51. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/configurations/resources/ecr.py +0 -0
  52. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/configurations/resources/exisiting.py +0 -0
  53. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/configurations/resources/lambda_function.py +0 -0
  54. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/configurations/resources/lambda_layers.py +0 -0
  55. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/configurations/resources/lambda_triggers.py +0 -0
  56. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/configurations/resources/load_balancer.py +0 -0
  57. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/configurations/resources/rds.py +0 -0
  58. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/configurations/resources/resource_mapping.py +0 -0
  59. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/configurations/resources/resource_naming.py +0 -0
  60. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/configurations/resources/resource_types.py +0 -0
  61. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/configurations/resources/route53.py +0 -0
  62. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/configurations/resources/route53_hosted_zone.py +0 -0
  63. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/configurations/resources/s3.py +0 -0
  64. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/configurations/resources/security_group.py +0 -0
  65. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/configurations/resources/security_group_full_stack.py +0 -0
  66. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/configurations/resources/sqs.py +0 -0
  67. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/configurations/resources/vpc.py +0 -0
  68. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/configurations/stack.py +0 -0
  69. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/configurations/workload.py +0 -0
  70. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/constructs/ecr/ecr_construct.py +0 -0
  71. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/constructs/lambdas/lambda_function_construct.py +0 -0
  72. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/constructs/lambdas/lambda_function_docker_construct.py +0 -0
  73. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/constructs/lambdas/lambda_function_role_construct.py +0 -0
  74. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/constructs/lambdas/policies/policy_docs.py +0 -0
  75. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/constructs/lambdas/policies/policy_statements.py +0 -0
  76. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/constructs/s3_buckets/s3_bucket_construct.py +0 -0
  77. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/constructs/s3_buckets/s3_bucket_replication_destination_construct.py +0 -0
  78. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/constructs/s3_buckets/s3_bucket_replication_source_construct.py +0 -0
  79. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/constructs/sqs/policies/sqs_policies.py +0 -0
  80. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/interfaces/enhanced_ssm_parameter_mixin.py +0 -0
  81. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/interfaces/istack.py +0 -0
  82. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/interfaces/live_ssm_resolver.py +0 -0
  83. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/interfaces/ssm_parameter_mixin.py +0 -0
  84. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/lambdas/health_handler.py +0 -0
  85. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/pipeline/pipeline_factory.py +0 -0
  86. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/pipeline/security/policies.py +0 -0
  87. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/pipeline/security/roles.py +0 -0
  88. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/pipeline/stage.py +0 -0
  89. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/stack/istack.py +0 -0
  90. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/stack/stack_factory.py +0 -0
  91. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/stack/stack_module_loader.py +0 -0
  92. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/stack/stack_module_registry.py +0 -0
  93. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/stack/stack_modules.py +0 -0
  94. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/stack_library/__init__.py +0 -0
  95. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/stack_library/api_gateway/api_gateway_stack.py +0 -0
  96. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/stack_library/auto_scaling/__init__.py +0 -0
  97. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/stack_library/auto_scaling/auto_scaling_stack.py +0 -0
  98. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/stack_library/aws_lambdas/lambda_stack.py +0 -0
  99. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/stack_library/buckets/README.md +0 -0
  100. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/stack_library/buckets/bucket_stack.py +0 -0
  101. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/stack_library/code_artifact/code_artifact_stack.py +0 -0
  102. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/stack_library/cognito/cognito_stack.py +0 -0
  103. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/stack_library/dynamodb/dynamodb_stack.py +0 -0
  104. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/stack_library/ecr/README.md +0 -0
  105. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/stack_library/ecr/ecr_stack.py +0 -0
  106. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/stack_library/load_balancer/__init__.py +0 -0
  107. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/stack_library/load_balancer/load_balancer_stack.py +0 -0
  108. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/stack_library/rds/__init__.py +0 -0
  109. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/stack_library/rds/rds_stack.py +0 -0
  110. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/stack_library/route53/__init__.py +0 -0
  111. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/stack_library/route53/route53_stack.py +0 -0
  112. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/stack_library/security_group/__init__.py +0 -0
  113. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/stack_library/security_group/security_group_full_stack.py +0 -0
  114. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/stack_library/security_group/security_group_stack.py +0 -0
  115. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/stack_library/simple_queue_service/sqs_stack.py +0 -0
  116. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/stack_library/stack_base.py +0 -0
  117. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/stack_library/vpc/__init__.py +0 -0
  118. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/stack_library/vpc/vpc_stack.py +0 -0
  119. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/stack_library/websites/static_website_stack.py +0 -0
  120. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/stages/websites/static_website_stage.py +0 -0
  121. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/utilities/api_gateway_integration_utility.py +0 -0
  122. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/utilities/commandline_args.py +0 -0
  123. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/utilities/configuration_loader.py +0 -0
  124. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/utilities/docker_utilities.py +0 -0
  125. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/utilities/environment_services.py +0 -0
  126. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/utilities/file_operations.py +0 -0
  127. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/utilities/git_utilities.py +0 -0
  128. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/utilities/json_loading_utility.py +0 -0
  129. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/utilities/lambda_function_utilities.py +0 -0
  130. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/utilities/os_execute.py +0 -0
  131. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/utils/api_gateway_utilities.py +0 -0
  132. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/cdk_factory/workload/workload_factory.py +0 -0
  133. {cdk_factory-0.7.29 → cdk_factory-0.7.31}/src/handlers/test/handler.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cdk_factory
3
- Version: 0.7.29
3
+ Version: 0.7.31
4
4
  Summary: CDK Factory. A QuickStarter and best practices setup for CDK projects
5
5
  Author-email: Eric Wilson <eric.wilson@geekcafe.com>
6
6
  License: MIT License
@@ -33,7 +33,7 @@ markers = [
33
33
  [project]
34
34
 
35
35
  name = "cdk_factory"
36
- version = "0.7.29"
36
+ version = "0.7.31"
37
37
  authors = [
38
38
  { name="Eric Wilson", email="eric.wilson@geekcafe.com" }
39
39
  ]
@@ -0,0 +1,135 @@
1
+ """
2
+ Geek Cafe, LLC
3
+ Maintainers: Eric Wilson
4
+ MIT License. See Project Root for the license information.
5
+ """
6
+
7
+ from typing import Dict, Any, List, Optional
8
+ from cdk_factory.configurations.enhanced_base_config import EnhancedBaseConfig
9
+
10
+
11
+ class RumConfig(EnhancedBaseConfig):
12
+ """
13
+ RUM (Real User Monitoring) Configuration - supports CloudWatch RUM app monitor settings.
14
+ Each property reads from the config dict and provides sensible defaults.
15
+ """
16
+
17
+ def __init__(self, config: dict = None) -> None:
18
+ super().__init__(config or {}, resource_type="rum", resource_name=config.get("name", "rum") if config else "rum")
19
+ self.__config = config or {}
20
+
21
+ @property
22
+ def name(self) -> str:
23
+ """Name for the RUM app monitor"""
24
+ return self.__config.get("name", "app-monitor")
25
+
26
+ @property
27
+ def domain(self) -> Optional[str]:
28
+ """The top-level internet domain name for which your application has administrative authority"""
29
+ return self.__config.get("domain")
30
+
31
+ @property
32
+ def domain_list(self) -> Optional[List[str]]:
33
+ """A list of top-level internet domain names for which your application has administrative authority"""
34
+ return self.__config.get("domain_list")
35
+
36
+ @property
37
+ def cw_log_enabled(self) -> bool:
38
+ """Whether to send telemetry data to CloudWatch Logs (default: False)"""
39
+ return bool(self.__config.get("cw_log_enabled", False))
40
+
41
+ @property
42
+ def custom_events_enabled(self) -> bool:
43
+ """Whether custom events are enabled (default: False)"""
44
+ return bool(self.__config.get("custom_events_enabled", False))
45
+
46
+ # App Monitor Configuration Properties
47
+ @property
48
+ def allow_cookies(self) -> bool:
49
+ """Whether to allow cookies for user tracking (default: True)"""
50
+ return bool(self.__config.get("allow_cookies", True))
51
+
52
+ @property
53
+ def enable_xray(self) -> bool:
54
+ """Whether to enable X-Ray tracing (default: False)"""
55
+ return bool(self.__config.get("enable_xray", False))
56
+
57
+ @property
58
+ def excluded_pages(self) -> Optional[List[str]]:
59
+ """List of URLs to exclude from RUM data collection"""
60
+ return self.__config.get("excluded_pages")
61
+
62
+ @property
63
+ def included_pages(self) -> Optional[List[str]]:
64
+ """List of URLs to include in RUM data collection"""
65
+ return self.__config.get("included_pages")
66
+
67
+ @property
68
+ def favorite_pages(self) -> Optional[List[str]]:
69
+ """List of pages to mark as favorites in the RUM console"""
70
+ return self.__config.get("favorite_pages")
71
+
72
+ @property
73
+ def session_sample_rate(self) -> float:
74
+ """Portion of user sessions to sample (0.0 to 1.0, default: 0.1)"""
75
+ rate = self.__config.get("session_sample_rate", 0.1)
76
+ return float(rate) if rate is not None else 0.1
77
+
78
+ @property
79
+ def telemetries(self) -> List[str]:
80
+ """Types of telemetry data to collect (default: ['errors', 'performance', 'http'])"""
81
+ return self.__config.get("telemetries", ["errors", "performance", "http"])
82
+
83
+ # Cognito Integration Properties
84
+ @property
85
+ def cognito_identity_pool_id(self) -> Optional[str]:
86
+ """Existing Cognito Identity Pool ID to use for authorization"""
87
+ return self.__config.get("cognito_identity_pool_id")
88
+
89
+ @property
90
+ def cognito_user_pool_id(self) -> Optional[str]:
91
+ """Existing Cognito User Pool ID to reference"""
92
+ return self.__config.get("cognito_user_pool_id")
93
+
94
+ @property
95
+ def create_cognito_identity_pool(self) -> bool:
96
+ """Whether to create a new Cognito Identity Pool if none provided (default: True)"""
97
+ return bool(self.__config.get("create_cognito_identity_pool", True))
98
+
99
+ @property
100
+ def cognito_identity_pool_name(self) -> str:
101
+ """Name for the Cognito Identity Pool if creating one"""
102
+ return self.__config.get("cognito_identity_pool_name", f"{self.name}_identity_pool")
103
+
104
+ @property
105
+ def cognito_user_pool_name(self) -> str:
106
+ """Name for the Cognito User Pool if creating one"""
107
+ return self.__config.get("cognito_user_pool_name", f"{self.name}_user_pool")
108
+
109
+ @property
110
+ def create_cognito_user_pool(self) -> bool:
111
+ """Whether to create a new Cognito User Pool if none provided (default: True)"""
112
+ return bool(self.__config.get("create_cognito_user_pool", True))
113
+
114
+ # Metric Destinations
115
+ @property
116
+ def metric_destinations(self) -> Optional[List[Dict[str, Any]]]:
117
+ """List of metric destinations for extended metrics"""
118
+ return self.__config.get("metric_destinations")
119
+
120
+ # Tags
121
+ @property
122
+ def tags(self) -> Dict[str, str]:
123
+ """Tags to apply to the RUM app monitor"""
124
+ return self.__config.get("tags", {})
125
+
126
+ # SSM Integration
127
+ @property
128
+ def ssm_exports(self) -> Dict[str, str]:
129
+ """SSM parameter paths for exporting RUM resources"""
130
+ return self.__config.get("ssm_exports", {})
131
+
132
+ @property
133
+ def ssm_imports(self) -> Dict[str, str]:
134
+ """SSM parameter paths for importing external resources"""
135
+ return self.__config.get("ssm_imports", {})
@@ -184,7 +184,29 @@ class CloudFrontDistributionConstruct(Construct):
184
184
  """
185
185
  function_associations = []
186
186
 
187
- if self.restrict_to_known_hosts and self.aliases:
187
+ # Check if URL rewrite is enabled for SPA/static site routing
188
+ enable_url_rewrite = False
189
+ if self.stack_config and isinstance(self.stack_config, StackConfig):
190
+ cloudfront_config = self.stack_config.dictionary.get("cloudfront", {})
191
+ enable_url_rewrite = cloudfront_config.get("enable_url_rewrite", False)
192
+
193
+ # CloudFront only allows ONE function per event type
194
+ # If both URL rewrite and host restrictions are needed, combine them
195
+ if enable_url_rewrite and self.restrict_to_known_hosts and self.aliases:
196
+ function_associations.append(
197
+ cloudfront.FunctionAssociation(
198
+ function=self.__get_combined_function(hosts=self.aliases),
199
+ event_type=cloudfront.FunctionEventType.VIEWER_REQUEST,
200
+ )
201
+ )
202
+ elif enable_url_rewrite:
203
+ function_associations.append(
204
+ cloudfront.FunctionAssociation(
205
+ function=self.__get_url_rewrite_function(),
206
+ event_type=cloudfront.FunctionEventType.VIEWER_REQUEST,
207
+ )
208
+ )
209
+ elif self.restrict_to_known_hosts and self.aliases:
188
210
  function_associations.append(
189
211
  cloudfront.FunctionAssociation(
190
212
  function=self.__get_cloudfront_host_restrictions(
@@ -196,6 +218,96 @@ class CloudFrontDistributionConstruct(Construct):
196
218
 
197
219
  return function_associations
198
220
 
221
+ def __get_combined_function(self, hosts: List[str]) -> cloudfront.Function:
222
+ """
223
+ Creates a combined CloudFront function that does both URL rewriting and host restrictions.
224
+ This is necessary because CloudFront only allows one function per event type.
225
+
226
+ Args:
227
+ hosts: List of allowed hostnames
228
+
229
+ Returns:
230
+ cloudfront.Function: Combined function
231
+ """
232
+ allowed_hosts = "[" + ", ".join(f"'{host}'" for host in hosts) + "]"
233
+
234
+ function_code = f"""
235
+ function handler(event) {{
236
+ var request = event.request;
237
+ var allowedHosts = {allowed_hosts};
238
+ var hostHeader = request.headers.host.value;
239
+
240
+ // Check host restrictions first
241
+ if (allowedHosts.indexOf(hostHeader) === -1) {{
242
+ return {{ statusCode: 403, statusDescription: 'Forbidden' }};
243
+ }}
244
+
245
+ // Then do URL rewrite
246
+ var uri = request.uri;
247
+
248
+ // If URI doesn't have a file extension and doesn't end with /
249
+ if (!uri.includes('.') && !uri.endsWith('/')) {{
250
+ request.uri = uri + '/index.html';
251
+ }}
252
+ // If URI ends with / but not index.html
253
+ else if (uri.endsWith('/') && !uri.endsWith('index.html')) {{
254
+ request.uri = uri + 'index.html';
255
+ }}
256
+ // If URI is exactly /
257
+ else if (uri === '/') {{
258
+ request.uri = '/index.html';
259
+ }}
260
+
261
+ return request;
262
+ }}
263
+ """
264
+
265
+ combined_function = cloudfront.Function(
266
+ self,
267
+ "CombinedFunction",
268
+ comment="Combined URL rewrite and host restrictions for static site routing",
269
+ code=cloudfront.FunctionCode.from_inline(function_code),
270
+ )
271
+ return combined_function
272
+
273
+ def __get_url_rewrite_function(self) -> cloudfront.Function:
274
+ """
275
+ Creates a CloudFront function that rewrites URLs for SPA/static site routing.
276
+ This enables clean URLs by routing /about to /about/index.html
277
+
278
+ Returns:
279
+ cloudfront.Function: URL rewrite function for static site routing
280
+ """
281
+ function_code = """
282
+ function handler(event) {
283
+ var request = event.request;
284
+ var uri = request.uri;
285
+
286
+ // If URI doesn't have a file extension and doesn't end with /
287
+ if (!uri.includes('.') && !uri.endsWith('/')) {
288
+ request.uri = uri + '/index.html';
289
+ }
290
+ // If URI ends with / but not index.html
291
+ else if (uri.endsWith('/') && !uri.endsWith('index.html')) {
292
+ request.uri = uri + 'index.html';
293
+ }
294
+ // If URI is exactly /
295
+ else if (uri === '/') {
296
+ request.uri = '/index.html';
297
+ }
298
+
299
+ return request;
300
+ }
301
+ """
302
+
303
+ url_rewrite_function = cloudfront.Function(
304
+ self,
305
+ "UrlRewriteFunction",
306
+ comment="Rewrites clean URLs to /folder/index.html for static site routing",
307
+ code=cloudfront.FunctionCode.from_inline(function_code),
308
+ )
309
+ return url_rewrite_function
310
+
199
311
  def __get_cloudfront_host_restrictions(
200
312
  self, hosts: List[str]
201
313
  ) -> cloudfront.Function:
@@ -0,0 +1,7 @@
1
+ """
2
+ RUM Stack Library Module
3
+ """
4
+
5
+ from .rum_stack import RumStack
6
+
7
+ __all__ = ["RumStack"]
@@ -0,0 +1,332 @@
1
+ """
2
+ Geek Cafe, LLC
3
+ Maintainers: Eric Wilson
4
+ MIT License. See Project Root for the license information.
5
+ """
6
+
7
+ import aws_cdk as cdk
8
+ from aws_cdk import aws_rum as rum
9
+ from aws_cdk import aws_cognito as cognito
10
+ from aws_cdk import aws_iam as iam
11
+ from constructs import Construct
12
+ from aws_lambda_powertools import Logger
13
+ from typing import Optional
14
+
15
+ from cdk_factory.configurations.deployment import DeploymentConfig
16
+ from cdk_factory.configurations.resources.rum import RumConfig
17
+ from cdk_factory.configurations.stack import StackConfig
18
+ from cdk_factory.interfaces.istack import IStack
19
+ from cdk_factory.interfaces.enhanced_ssm_parameter_mixin import EnhancedSsmParameterMixin
20
+ from cdk_factory.stack.stack_module_registry import register_stack
21
+ from cdk_factory.workload.workload_factory import WorkloadConfig
22
+
23
+ logger = Logger(__name__)
24
+
25
+
26
+ @register_stack("rum_library_module")
27
+ @register_stack("rum_stack")
28
+ class RumStack(IStack, EnhancedSsmParameterMixin):
29
+ """
30
+ RUM Stack - Creates a CloudWatch RUM app monitor with optional Cognito integration.
31
+ Can either use existing Cognito resources or create new ones if not provided.
32
+ """
33
+
34
+ def __init__(self, scope: Construct, id: str, **kwargs) -> None:
35
+ super().__init__(scope, id, **kwargs)
36
+ self.id = id
37
+ self.stack_config: Optional[StackConfig] = None
38
+ self.deployment: Optional[DeploymentConfig] = None
39
+ self.rum_config: Optional[RumConfig] = None
40
+ self.app_monitor: Optional[rum.CfnAppMonitor] = None
41
+ self.identity_pool: Optional[cognito.CfnIdentityPool] = None
42
+ self.user_pool: Optional[cognito.UserPool] = None
43
+
44
+ def build(
45
+ self,
46
+ stack_config: StackConfig,
47
+ deployment: DeploymentConfig,
48
+ workload: WorkloadConfig,
49
+ ) -> None:
50
+ """Build the RUM stack"""
51
+ self.stack_config = stack_config
52
+ self.deployment = deployment
53
+ self.rum_config = RumConfig(stack_config.dictionary.get("rum", {}))
54
+
55
+ logger.info(f"Building RUM stack: {self.rum_config.name}")
56
+
57
+ # Setup enhanced SSM integration
58
+ self.setup_enhanced_ssm_integration(
59
+ scope=self,
60
+ config=stack_config.dictionary.get("rum", {}),
61
+ resource_type="rum",
62
+ resource_name=self.rum_config.name
63
+ )
64
+
65
+ # Import or create Cognito resources
66
+ identity_pool_id, guest_role_arn = self._setup_cognito_integration()
67
+
68
+ # Create the RUM app monitor
69
+ self._create_app_monitor(identity_pool_id, guest_role_arn)
70
+
71
+ # Export resources to SSM
72
+ self._export_ssm_parameters()
73
+
74
+ def _setup_cognito_integration(self) -> tuple[str, str]:
75
+ """
76
+ Setup Cognito integration - either import existing resources or create new ones.
77
+ Returns (identity_pool_id, guest_role_arn)
78
+ """
79
+ identity_pool_id = None
80
+ guest_role_arn = None
81
+
82
+ # Try to import existing Cognito Identity Pool ID from SSM or config
83
+ if self.rum_config.cognito_identity_pool_id:
84
+ identity_pool_id = self.rum_config.cognito_identity_pool_id
85
+ logger.info(f"Using existing Cognito Identity Pool: {identity_pool_id}")
86
+ else:
87
+ # Try to import from SSM using enhanced SSM pattern
88
+ imported_values = self.auto_import_resources({
89
+ "cognito_identity_pool_id": "auto"
90
+ })
91
+
92
+ if imported_values.get("cognito_identity_pool_id"):
93
+ identity_pool_id = imported_values["cognito_identity_pool_id"]
94
+ logger.info(f"Imported Cognito Identity Pool from SSM: {identity_pool_id}")
95
+
96
+ # If no existing identity pool found, create new Cognito resources
97
+ if not identity_pool_id and self.rum_config.create_cognito_identity_pool:
98
+ identity_pool_id, guest_role_arn = self._create_cognito_resources()
99
+
100
+ # If we still don't have an identity pool, create a minimal one
101
+ if not identity_pool_id:
102
+ identity_pool_id, guest_role_arn = self._create_minimal_identity_pool()
103
+
104
+ return identity_pool_id, guest_role_arn
105
+
106
+ def _create_cognito_resources(self) -> tuple[str, str]:
107
+ """Create new Cognito User Pool and Identity Pool for RUM"""
108
+ logger.info("Creating new Cognito resources for RUM")
109
+
110
+ # Create User Pool if needed
111
+ user_pool_id = self.rum_config.cognito_user_pool_id
112
+ if not user_pool_id and self.rum_config.create_cognito_user_pool:
113
+ self.user_pool = cognito.UserPool(
114
+ self,
115
+ id=self.deployment.build_resource_name(f"{self.rum_config.name}-user-pool"),
116
+ user_pool_name=self.rum_config.cognito_user_pool_name,
117
+ self_sign_up_enabled=True,
118
+ sign_in_aliases=cognito.SignInAliases(email=True),
119
+ auto_verify=cognito.AutoVerifiedAttrs(email=True),
120
+ removal_policy=cdk.RemovalPolicy.DESTROY
121
+ )
122
+ user_pool_id = self.user_pool.user_pool_id
123
+ logger.info(f"Created Cognito User Pool: {user_pool_id}")
124
+
125
+ # Create Identity Pool
126
+ identity_pool_providers = []
127
+ if user_pool_id and self.user_pool:
128
+ # Create User Pool Client for Identity Pool integration
129
+ user_pool_client = cognito.UserPoolClient(
130
+ self,
131
+ id=self.deployment.build_resource_name(f"{self.rum_config.name}-user-pool-client"),
132
+ user_pool=self.user_pool,
133
+ generate_secret=False,
134
+ auth_flows=cognito.AuthFlow(
135
+ user_srp=True,
136
+ user_password=True
137
+ )
138
+ )
139
+
140
+ identity_pool_providers.append({
141
+ "providerName": f"cognito-idp.{self.region}.amazonaws.com/{user_pool_id}",
142
+ "providerType": "COGNITO_USER_POOLS",
143
+ "clientId": user_pool_client.user_pool_client_id
144
+ })
145
+
146
+ self.identity_pool = cognito.CfnIdentityPool(
147
+ self,
148
+ id=self.deployment.build_resource_name(f"{self.rum_config.name}-identity-pool"),
149
+ identity_pool_name=self.rum_config.cognito_identity_pool_name,
150
+ allow_unauthenticated_identities=True,
151
+ cognito_identity_providers=identity_pool_providers if identity_pool_providers else None
152
+ )
153
+
154
+ # Create IAM role for unauthenticated users (guest role)
155
+ guest_role = iam.Role(
156
+ self,
157
+ id=self.deployment.build_resource_name(f"{self.rum_config.name}-guest-role"),
158
+ assumed_by=iam.FederatedPrincipal(
159
+ "cognito-identity.amazonaws.com",
160
+ conditions={
161
+ "StringEquals": {
162
+ "cognito-identity.amazonaws.com:aud": self.identity_pool.ref
163
+ },
164
+ "ForAnyValue:StringLike": {
165
+ "cognito-identity.amazonaws.com:amr": "unauthenticated"
166
+ }
167
+ }
168
+ ),
169
+ inline_policies={
170
+ "RUMPolicy": iam.PolicyDocument(
171
+ statements=[
172
+ iam.PolicyStatement(
173
+ effect=iam.Effect.ALLOW,
174
+ actions=[
175
+ "rum:PutRumEvents"
176
+ ],
177
+ resources=[f"arn:aws:rum:{self.region}:{self.account}:appmonitor/{self.rum_config.name}"]
178
+ )
179
+ ]
180
+ )
181
+ }
182
+ )
183
+
184
+ # Attach the role to the identity pool
185
+ cognito.CfnIdentityPoolRoleAttachment(
186
+ self,
187
+ id=self.deployment.build_resource_name(f"{self.rum_config.name}-role-attachment"),
188
+ identity_pool_id=self.identity_pool.ref,
189
+ roles={
190
+ "unauthenticated": guest_role.role_arn
191
+ }
192
+ )
193
+
194
+ logger.info(f"Created Cognito Identity Pool: {self.identity_pool.ref}")
195
+ return self.identity_pool.ref, guest_role.role_arn
196
+
197
+ def _create_minimal_identity_pool(self) -> tuple[str, str]:
198
+ """Create a minimal identity pool for RUM when no Cognito resources are provided"""
199
+ logger.info("Creating minimal Cognito Identity Pool for RUM")
200
+
201
+ self.identity_pool = cognito.CfnIdentityPool(
202
+ self,
203
+ id=self.deployment.build_resource_name(f"{self.rum_config.name}-minimal-identity-pool"),
204
+ identity_pool_name=f"{self.rum_config.name}_minimal_identity_pool",
205
+ allow_unauthenticated_identities=True
206
+ )
207
+
208
+ # Create minimal IAM role for unauthenticated users
209
+ guest_role = iam.Role(
210
+ self,
211
+ id=self.deployment.build_resource_name(f"{self.rum_config.name}-minimal-guest-role"),
212
+ assumed_by=iam.FederatedPrincipal(
213
+ "cognito-identity.amazonaws.com",
214
+ conditions={
215
+ "StringEquals": {
216
+ "cognito-identity.amazonaws.com:aud": self.identity_pool.ref
217
+ },
218
+ "ForAnyValue:StringLike": {
219
+ "cognito-identity.amazonaws.com:amr": "unauthenticated"
220
+ }
221
+ }
222
+ ),
223
+ inline_policies={
224
+ "RUMPolicy": iam.PolicyDocument(
225
+ statements=[
226
+ iam.PolicyStatement(
227
+ effect=iam.Effect.ALLOW,
228
+ actions=[
229
+ "rum:PutRumEvents"
230
+ ],
231
+ resources=[f"arn:aws:rum:{self.region}:{self.account}:appmonitor/{self.rum_config.name}"]
232
+ )
233
+ ]
234
+ )
235
+ }
236
+ )
237
+
238
+ # Attach the role to the identity pool
239
+ cognito.CfnIdentityPoolRoleAttachment(
240
+ self,
241
+ id=self.deployment.build_resource_name(f"{self.rum_config.name}-minimal-role-attachment"),
242
+ identity_pool_id=self.identity_pool.ref,
243
+ roles={
244
+ "unauthenticated": guest_role.role_arn
245
+ }
246
+ )
247
+
248
+ return self.identity_pool.ref, guest_role.role_arn
249
+
250
+ def _create_app_monitor(self, identity_pool_id: str, guest_role_arn: Optional[str]) -> None:
251
+ """Create the CloudWatch RUM app monitor"""
252
+ logger.info(f"Creating RUM app monitor: {self.rum_config.name}")
253
+
254
+ # Build app monitor configuration
255
+ app_monitor_config = rum.CfnAppMonitor.AppMonitorConfigurationProperty(
256
+ identity_pool_id=identity_pool_id,
257
+ guest_role_arn=guest_role_arn,
258
+ allow_cookies=self.rum_config.allow_cookies,
259
+ enable_x_ray=self.rum_config.enable_xray,
260
+ session_sample_rate=self.rum_config.session_sample_rate,
261
+ telemetries=self.rum_config.telemetries
262
+ )
263
+
264
+ # Add optional properties
265
+ if self.rum_config.excluded_pages:
266
+ app_monitor_config.excluded_pages = self.rum_config.excluded_pages
267
+
268
+ if self.rum_config.included_pages:
269
+ app_monitor_config.included_pages = self.rum_config.included_pages
270
+
271
+ if self.rum_config.favorite_pages:
272
+ app_monitor_config.favorite_pages = self.rum_config.favorite_pages
273
+
274
+ if self.rum_config.metric_destinations:
275
+ app_monitor_config.metric_destinations = [
276
+ rum.CfnAppMonitor.MetricDestinationProperty(**dest)
277
+ for dest in self.rum_config.metric_destinations
278
+ ]
279
+
280
+ # Create custom events configuration if enabled
281
+ custom_events = None
282
+ if self.rum_config.custom_events_enabled:
283
+ custom_events = rum.CfnAppMonitor.CustomEventsProperty(
284
+ status="ENABLED"
285
+ )
286
+
287
+ # Create the app monitor
288
+ self.app_monitor = rum.CfnAppMonitor(
289
+ self,
290
+ id=self.deployment.build_resource_name(f"{self.rum_config.name}-app-monitor"),
291
+ name=self.rum_config.name,
292
+ app_monitor_configuration=app_monitor_config,
293
+ domain=self.rum_config.domain,
294
+ domain_list=self.rum_config.domain_list,
295
+ cw_log_enabled=self.rum_config.cw_log_enabled,
296
+ custom_events=custom_events
297
+ )
298
+
299
+ # Add tags if specified
300
+ if self.rum_config.tags:
301
+ for key, value in self.rum_config.tags.items():
302
+ cdk.Tags.of(self.app_monitor).add(key, value)
303
+
304
+ logger.info(f"Created RUM app monitor: {self.app_monitor.name}")
305
+
306
+ def _export_ssm_parameters(self) -> None:
307
+ """Export RUM resources to SSM using enhanced SSM parameter mixin"""
308
+ if not self.app_monitor:
309
+ logger.warning("No app monitor to export")
310
+ return
311
+
312
+ # Prepare resource values for export
313
+ resource_values = {
314
+ "app_monitor_name": self.app_monitor.name,
315
+ "app_monitor_id": self.app_monitor.ref,
316
+ }
317
+
318
+ # Add identity pool info if available
319
+ if self.identity_pool:
320
+ resource_values["identity_pool_id"] = self.identity_pool.ref
321
+
322
+ # Add user pool info if available
323
+ if self.user_pool:
324
+ resource_values["user_pool_id"] = self.user_pool.user_pool_id
325
+
326
+ # Use enhanced SSM parameter export
327
+ exported_params = self.auto_export_resources(resource_values)
328
+
329
+ if exported_params:
330
+ logger.info(f"Exported {len(exported_params)} RUM parameters to SSM")
331
+ else:
332
+ logger.info("No SSM parameters configured for export")
@@ -0,0 +1 @@
1
+ __version__ = "0.7.31"
@@ -1 +0,0 @@
1
- __version__ = "0.7.29"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes