├── .docs ├── cloudwatch-dashboard-monitoring-account-manage.png ├── cloudwatch-dashboard-monitoring-account.png ├── cloudwatch-dashboard-source-account-manage.png ├── cloudwatch-dashboard-source-account.png ├── monitoring-ap-southeast-2.png ├── monitoring-log-insights.png ├── monitoring-us-east-1.png └── oam.png ├── .gitignore ├── .vscode └── settings.json ├── README.md ├── infra ├── _env.tf ├── ap_southeast_2.tf └── us_east_1.tf ├── package.json └── pnpm-lock.yaml /.docs/cloudwatch-dashboard-monitoring-account-manage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awsfundamentals-hq/cloudwatch-observability-access-manager/87bccc831d22cbd3ee6115627b83d171258da525/.docs/cloudwatch-dashboard-monitoring-account-manage.png -------------------------------------------------------------------------------- /.docs/cloudwatch-dashboard-monitoring-account.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awsfundamentals-hq/cloudwatch-observability-access-manager/87bccc831d22cbd3ee6115627b83d171258da525/.docs/cloudwatch-dashboard-monitoring-account.png -------------------------------------------------------------------------------- /.docs/cloudwatch-dashboard-source-account-manage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awsfundamentals-hq/cloudwatch-observability-access-manager/87bccc831d22cbd3ee6115627b83d171258da525/.docs/cloudwatch-dashboard-source-account-manage.png -------------------------------------------------------------------------------- /.docs/cloudwatch-dashboard-source-account.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awsfundamentals-hq/cloudwatch-observability-access-manager/87bccc831d22cbd3ee6115627b83d171258da525/.docs/cloudwatch-dashboard-source-account.png -------------------------------------------------------------------------------- /.docs/monitoring-ap-southeast-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awsfundamentals-hq/cloudwatch-observability-access-manager/87bccc831d22cbd3ee6115627b83d171258da525/.docs/monitoring-ap-southeast-2.png -------------------------------------------------------------------------------- /.docs/monitoring-log-insights.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awsfundamentals-hq/cloudwatch-observability-access-manager/87bccc831d22cbd3ee6115627b83d171258da525/.docs/monitoring-log-insights.png -------------------------------------------------------------------------------- /.docs/monitoring-us-east-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awsfundamentals-hq/cloudwatch-observability-access-manager/87bccc831d22cbd3ee6115627b83d171258da525/.docs/monitoring-us-east-1.png -------------------------------------------------------------------------------- /.docs/oam.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awsfundamentals-hq/cloudwatch-observability-access-manager/87bccc831d22cbd3ee6115627b83d171258da525/.docs/oam.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.lock.hcl 2 | 3 | # Created by https://www.toptal.com/developers/gitignore/api/macos,node,terraform 4 | # Edit at https://www.toptal.com/developers/gitignore?templates=macos,node,terraform 5 | 6 | ### macOS ### 7 | # General 8 | .DS_Store 9 | .AppleDouble 10 | .LSOverride 11 | 12 | # Icon must end with two \r 13 | Icon 14 | 15 | 16 | # Thumbnails 17 | ._* 18 | 19 | # Files that might appear in the root of a volume 20 | .DocumentRevisions-V100 21 | .fseventsd 22 | .Spotlight-V100 23 | .TemporaryItems 24 | .Trashes 25 | .VolumeIcon.icns 26 | .com.apple.timemachine.donotpresent 27 | 28 | # Directories potentially created on remote AFP share 29 | .AppleDB 30 | .AppleDesktop 31 | Network Trash Folder 32 | Temporary Items 33 | .apdisk 34 | 35 | ### macOS Patch ### 36 | # iCloud generated files 37 | *.icloud 38 | 39 | ### Node ### 40 | # Logs 41 | logs 42 | *.log 43 | npm-debug.log* 44 | yarn-debug.log* 45 | yarn-error.log* 46 | lerna-debug.log* 47 | .pnpm-debug.log* 48 | 49 | # Diagnostic reports (https://nodejs.org/api/report.html) 50 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 51 | 52 | # Runtime data 53 | pids 54 | *.pid 55 | *.seed 56 | *.pid.lock 57 | 58 | # Directory for instrumented libs generated by jscoverage/JSCover 59 | lib-cov 60 | 61 | # Coverage directory used by tools like istanbul 62 | coverage 63 | *.lcov 64 | 65 | # nyc test coverage 66 | .nyc_output 67 | 68 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 69 | .grunt 70 | 71 | # Bower dependency directory (https://bower.io/) 72 | bower_components 73 | 74 | # node-waf configuration 75 | .lock-wscript 76 | 77 | # Compiled binary addons (https://nodejs.org/api/addons.html) 78 | build/Release 79 | 80 | # Dependency directories 81 | node_modules/ 82 | jspm_packages/ 83 | 84 | # Snowpack dependency directory (https://snowpack.dev/) 85 | web_modules/ 86 | 87 | # TypeScript cache 88 | *.tsbuildinfo 89 | 90 | # Optional npm cache directory 91 | .npm 92 | 93 | # Optional eslint cache 94 | .eslintcache 95 | 96 | # Optional stylelint cache 97 | .stylelintcache 98 | 99 | # Microbundle cache 100 | .rpt2_cache/ 101 | .rts2_cache_cjs/ 102 | .rts2_cache_es/ 103 | .rts2_cache_umd/ 104 | 105 | # Optional REPL history 106 | .node_repl_history 107 | 108 | # Output of 'npm pack' 109 | *.tgz 110 | 111 | # Yarn Integrity file 112 | .yarn-integrity 113 | 114 | # dotenv environment variable files 115 | .env 116 | .env.development.local 117 | .env.test.local 118 | .env.production.local 119 | .env.local 120 | 121 | # parcel-bundler cache (https://parceljs.org/) 122 | .cache 123 | .parcel-cache 124 | 125 | # Next.js build output 126 | .next 127 | out 128 | 129 | # Nuxt.js build / generate output 130 | .nuxt 131 | dist 132 | 133 | # Gatsby files 134 | .cache/ 135 | # Comment in the public line in if your project uses Gatsby and not Next.js 136 | # https://nextjs.org/blog/next-9-1#public-directory-support 137 | # public 138 | 139 | # vuepress build output 140 | .vuepress/dist 141 | 142 | # vuepress v2.x temp and cache directory 143 | .temp 144 | 145 | # Docusaurus cache and generated files 146 | .docusaurus 147 | 148 | # Serverless directories 149 | .serverless/ 150 | 151 | # FuseBox cache 152 | .fusebox/ 153 | 154 | # DynamoDB Local files 155 | .dynamodb/ 156 | 157 | # TernJS port file 158 | .tern-port 159 | 160 | # Stores VSCode versions used for testing VSCode extensions 161 | .vscode-test 162 | 163 | # yarn v2 164 | .yarn/cache 165 | .yarn/unplugged 166 | .yarn/build-state.yml 167 | .yarn/install-state.gz 168 | .pnp.* 169 | 170 | ### Node Patch ### 171 | # Serverless Webpack directories 172 | .webpack/ 173 | 174 | # Optional stylelint cache 175 | 176 | # SvelteKit build / generate output 177 | .svelte-kit 178 | 179 | ### Terraform ### 180 | # Local .terraform directories 181 | **/.terraform/* 182 | 183 | # .tfstate files 184 | *.tfstate 185 | *.tfstate.* 186 | 187 | # Crash log files 188 | crash.log 189 | crash.*.log 190 | 191 | # Exclude all .tfvars files, which are likely to contain sensitive data, such as 192 | # password, private keys, and other secrets. These should not be part of version 193 | # control as they are data points which are potentially sensitive and subject 194 | # to change depending on the environment. 195 | *.tfvars 196 | *.tfvars.json 197 | 198 | # Ignore override files as they are usually used to override resources locally and so 199 | # are not checked in 200 | override.tf 201 | override.tf.json 202 | *_override.tf 203 | *_override.tf.json 204 | 205 | # Include override files you do wish to add to version control using negated pattern 206 | # !example_override.tf 207 | 208 | # Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan 209 | # example: *tfplan* 210 | 211 | # Ignore CLI configuration files 212 | .terraformrc 213 | terraform.rc 214 | 215 | # End of https://www.toptal.com/developers/gitignore/api/macos,node,terraform 216 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": true 3 | } 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # How to configure CloudWatch Observability Access Manager (OAM) 2 | 3 | CloudWatch OAM empowers you to centralize and connect a region in multiple accounts (named Source accounts) into the same region in a destination account (named Monitoring account). 4 | 5 | For example: 6 | 7 | - Source account A us-east-1 => Monitoring account us-east-1 8 | - Source account B us-east-1 => Monitoring account us-east-1 9 | 10 | Using the CloudWatch dashboard in Monitoring account us-east-1, you can see logs, metrics, trances and insights from Source accounts A and B. 11 | 12 | - Source account A ap-southeast-2 => Monitoring account ap-southeast-2 13 | - Source account B ap-southeast-2 => Monitoring account ap-southeast-2 14 | 15 | Using the CloudWatch dashboard in Monitoring account ap-southeast-2, you can see logs, metrics, trances and insights from Source accounts A and B. 16 | 17 | ## CloudWatch OAM Constructs 18 | 19 | You work with 3 (three) components when configuring CloudWatch OAM: 20 | 21 | - **Sink**: A Sink represents a destination point where AWS accounts running workloads (named Source accounts) will send their logs, metrics, trace and insights to. You create Sinks in the Monitoring account. You can create a single Sink per region in the Monitoring account. A Monitoring account can be connected to as many as 100,000 Source accounts. 22 | 23 | - **Link**: A Link represents the connection between the Source account (AWS accounts running workloads) and the Monitoring account (the destination point). You create a Link in the AWS accounts running workloads where logs, metrics trace and insights are created. You can create multiple Links per region in the Source account, they must point and connect to a different Sink ARN. A Source account can be paired with up to 5 (five) monitoring accounts concurrently. 24 | 25 | - **Sink Policy**: A Sink Policy is similar to [Resource-based Policies](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_identity-vs-resource.html). A Sink Policy grants permissions to Source accounts to connect their Links to the Monitoring account Sink. When you create a Sink Policy, you can grant permissions to all accounts in an AWS Organizations or to individual accounts via AWS Account Id. You can also use the Sink Policy to limit the types of data that is shared. The 4 (four) types that you can allow or deny are: 26 | - **Metrics**: Links in Source accounts can send [CloudWatch Metrics](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/working_with_metrics.html) to the Sink in the Monitoring account, enable it by adding the **AWS::CloudWatch::Metric** type to your Sink Policy. 27 | - **Log Groups**: Links in Source accounts can send [CloudWatch Logs](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/WhatIsCloudWatchLogs.html) to the Sink in the Monitoring account, enable it by adding the **AWS::Logs::LogGroup** type to your Sink Policy. 28 | - **Traces**: Links in Source accounts can send [AWS X-Ray Traces](https://docs.aws.amazon.com/xray/latest/devguide/aws-xray.html) to the Sink in the Monitoring account, enable it by adding the **AWS::XRay::Trace** type to your Sink Policy. 29 | - **Application Insights - Applications**: - Links in Source accounts can send [CloudWatch Application Insights](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/cloudwatch-application-insights.html) to the Sink in the Monitoring account, enable it by adding the **AWS::ApplicationInsights::Application** type to your Sink Policy. 30 | 31 | ## The example in this repository 32 | 33 | This repository shows how to configure [CloudWatch Observability Access Manager (OAM)](https://docs.aws.amazon.com/OAM/latest/APIReference/Welcome.html) for multi-account logs, metrics, traces and insights. 34 | 35 | We'll use the example described in the introduction above for our technical implementation. We are going to connect two regions from two Source accounts into the Monitoring account. 36 | 37 | ![Diagram showing CloudWatch OAM constructs, Sinks and Links, distributed between two Source accounts and the Monitoring account.](.docs/oam.png) 38 | 39 | ## Final results 40 | 41 | After deploying this example, you can generate logs, metrics, traces and insights in the Source accounts and they will be available for analysis and visualization in the Monitoring account. 42 | 43 | In the Monitoring account CloudWatch Logs dashboard in us-east-1, I can see logs from both Source accounts: 44 | 45 | ![Screenshot of CloudWatch Logs dashboard in us-east-1 in Monitoring account.](.docs/monitoring-us-east-1.png) 46 | 47 | In the Monitoring account CloudWatch Logs dashboard in ap-southeast-2, I can see logs from both Source accounts: 48 | 49 | ![Screenshot of CloudWatch Logs dashboard in ap-southeast-2 in Monitoring account.](.docs/monitoring-ap-southeast-2.png) 50 | 51 | In the Monitoring account CloudWatch Logs dashboard in us-east-1, I can use Log Insights to query log groups from both Source accounts and inspect my log events: 52 | 53 | ![Screenshot of CloudWatch Logs dashboard in us-east-1 in Monitoring account using Log Insights to query log groups from both Source accounts](.docs/monitoring-log-insights.png) 54 | 55 | ## How to find OAM Sink and Link in CloudWatch dashboard? 56 | 57 | You can find OAM Sink and Link configuration by clicking on "Settings" in the sidebar on the CloudWatch regional dashboard: 58 | 59 | - Link to us-east-1 regional dashboard: https://console.aws.amazon.com/cloudwatch/home?region=us-east-1 60 | - Link to ap-southeast-2 regional dashboard: https://console.aws.amazon.com/cloudwatch/home?region=us-east-1 61 | 62 | In the Monitoring account, you will see the "Monitoring account enabled" enable status and buttons to inspect the configuration of the Sink, connected Links and manual steps to connect Links (which we didn't used! We are using Terraform for the configuration). 63 | 64 | ![Screenshot showing CloudWatch regional dashboard for ap-southeast-2 in the Monitoring account](.docs/cloudwatch-dashboard-monitoring-account.png) 65 | 66 | ![Screenshot showing CloudWatch regional dashboard for ap-southeast-2 in the Monitoring account in the manage OAM Sink tab](.docs/cloudwatch-dashboard-monitoring-account-manage.png) 67 | 68 | However, in the Source account, you will see the "Linked" enable status and buttons to view the linked monitoring accounts and to connect manually to one (which we didn't used! We are using Terraform for the configuration). 69 | 70 | ![Screenshot showing CloudWatch regional dashboard for ap-southeast-2 in the Source account](.docs/cloudwatch-dashboard-source-account.png) 71 | 72 | ![Screenshot showing CloudWatch regional dashboard for ap-southeast-2 in the Source account in the manage OAM Link tab](.docs/cloudwatch-dashboard-source-account-manage.png) -------------------------------------------------------------------------------- /infra/_env.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = "1.7.5" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = "5.43.0" 8 | } 9 | } 10 | } 11 | 12 | variable "source_a_aws_account_id" { 13 | type = string 14 | description = "The AWS Account ID for Source A" 15 | } 16 | 17 | variable "source_b_aws_account_id" { 18 | type = string 19 | description = "The AWS Account ID for Source B" 20 | } 21 | 22 | locals { 23 | aws_region_ap_southeast_2 = "ap-southeast-2" 24 | aws_region_us_east_1 = "us-east-1" 25 | 26 | source_a_aws_account_id = var.source_a_aws_account_id 27 | source_a_role_name = "OrganizationAccountAccessRole" 28 | source_a_role_arn = "arn:aws:iam::${local.source_a_aws_account_id}:role/${local.source_a_role_name}" 29 | 30 | source_b_aws_account_id = var.source_b_aws_account_id 31 | source_b_role_name = "OrganizationAccountAccessRole" 32 | source_b_role_arn = "arn:aws:iam::${local.source_b_aws_account_id}:role/${local.source_b_role_name}" 33 | 34 | link_label_template = "$AccountName" 35 | 36 | oam_resource_types = [ 37 | "AWS::ApplicationInsights::Application", 38 | "AWS::CloudWatch::Metric", 39 | "AWS::Logs::LogGroup", 40 | "AWS::XRay::Trace", 41 | ] 42 | 43 | sink_policy = jsonencode({ 44 | Version = "2012-10-17", 45 | Statement = [ 46 | { 47 | Action = ["oam:CreateLink", "oam:UpdateLink"], 48 | Effect = "Allow", 49 | Resource = "*", 50 | Principal = { 51 | AWS = [local.source_a_role_arn, local.source_b_role_arn], 52 | }, 53 | Condition = { 54 | "ForAllValues:StringEquals" = { 55 | "oam:ResourceTypes" = local.oam_resource_types, 56 | }, 57 | }, 58 | }, 59 | ], 60 | }) 61 | } 62 | -------------------------------------------------------------------------------- /infra/ap_southeast_2.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | alias = "monitoring_ap_southeast_2" 3 | region = local.aws_region_ap_southeast_2 4 | } 5 | 6 | resource "aws_oam_sink" "monitoring_sink_ap_southeast_2" { 7 | name = "monitoring_sink_ap_southeast_2" 8 | 9 | provider = aws.monitoring_ap_southeast_2 10 | } 11 | 12 | resource "aws_oam_sink_policy" "monitoring_sink_policy_ap_southeast_2" { 13 | sink_identifier = aws_oam_sink.monitoring_sink_ap_southeast_2.arn 14 | policy = local.sink_policy 15 | 16 | provider = aws.monitoring_ap_southeast_2 17 | } 18 | 19 | provider "aws" { 20 | alias = "source_a_ap_southeast_2" 21 | region = local.aws_region_ap_southeast_2 22 | assume_role { 23 | role_arn = local.source_a_role_arn 24 | } 25 | } 26 | 27 | resource "aws_oam_link" "source_a_link_ap_southeast_2" { 28 | sink_identifier = aws_oam_sink.monitoring_sink_ap_southeast_2.arn 29 | label_template = local.link_label_template 30 | resource_types = local.oam_resource_types 31 | 32 | depends_on = [aws_oam_sink_policy.monitoring_sink_policy_ap_southeast_2] 33 | 34 | provider = aws.source_a_ap_southeast_2 35 | } 36 | 37 | provider "aws" { 38 | alias = "source_b_ap_southeast_2" 39 | region = local.aws_region_ap_southeast_2 40 | 41 | assume_role { 42 | role_arn = local.source_b_role_arn 43 | } 44 | } 45 | 46 | resource "aws_oam_link" "source_b_link_ap_southeast_2" { 47 | sink_identifier = aws_oam_sink.monitoring_sink_ap_southeast_2.arn 48 | label_template = local.link_label_template 49 | resource_types = local.oam_resource_types 50 | 51 | depends_on = [aws_oam_sink_policy.monitoring_sink_policy_ap_southeast_2] 52 | 53 | provider = aws.source_b_ap_southeast_2 54 | } 55 | -------------------------------------------------------------------------------- /infra/us_east_1.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | alias = "monitoring_us_east_1" 3 | region = local.aws_region_us_east_1 4 | } 5 | 6 | resource "aws_oam_sink" "monitoring_sink_us_east_1" { 7 | name = "monitoring_sink_us_east_1" 8 | 9 | provider = aws.monitoring_us_east_1 10 | } 11 | 12 | resource "aws_oam_sink_policy" "monitoring_sink_policy_us_east_1" { 13 | sink_identifier = aws_oam_sink.monitoring_sink_us_east_1.arn 14 | policy = local.sink_policy 15 | 16 | provider = aws.monitoring_us_east_1 17 | } 18 | 19 | provider "aws" { 20 | alias = "source_a_us_east_1" 21 | region = local.aws_region_us_east_1 22 | assume_role { 23 | role_arn = local.source_a_role_arn 24 | } 25 | } 26 | 27 | resource "aws_oam_link" "source_a_link_us_east_1" { 28 | sink_identifier = aws_oam_sink.monitoring_sink_us_east_1.arn 29 | label_template = local.link_label_template 30 | resource_types = local.oam_resource_types 31 | 32 | depends_on = [aws_oam_sink_policy.monitoring_sink_policy_us_east_1] 33 | 34 | provider = aws.source_a_us_east_1 35 | } 36 | 37 | provider "aws" { 38 | alias = "source_b_us_east_1" 39 | region = local.aws_region_us_east_1 40 | 41 | assume_role { 42 | role_arn = local.source_b_role_arn 43 | } 44 | } 45 | 46 | resource "aws_oam_link" "source_b_link_us_east_1" { 47 | sink_identifier = aws_oam_sink.monitoring_sink_us_east_1.arn 48 | label_template = local.link_label_template 49 | resource_types = local.oam_resource_types 50 | 51 | depends_on = [aws_oam_sink_policy.monitoring_sink_policy_us_east_1] 52 | 53 | provider = aws.source_b_us_east_1 54 | } 55 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cloudwatch-observability-access-manager", 3 | "packageManager": "pnpm@9.0.0-beta.1+sha256.fba2e63d591308988fa66645c4f77d67aea9490c2a6c05f14b2b1154d207761e", 4 | "devDependencies": { 5 | "@trivago/prettier-plugin-sort-imports": "^4.3.0", 6 | "prettier": "^3.2.5" 7 | }, 8 | "prettier": { 9 | "importOrder": [ 10 | "^[./]" 11 | ], 12 | "importOrderSeparation": true, 13 | "importOrderSortSpecifiers": true, 14 | "plugins": [ 15 | "@trivago/prettier-plugin-sort-imports" 16 | ], 17 | "printWidth": 125, 18 | "semi": true, 19 | "singleQuote": true, 20 | "tabWidth": 4, 21 | "trailingComma": "all", 22 | "useTabs": false 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '7.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | importers: 8 | 9 | .: 10 | devDependencies: 11 | '@trivago/prettier-plugin-sort-imports': 12 | specifier: ^4.3.0 13 | version: 4.3.0(prettier@3.2.5) 14 | prettier: 15 | specifier: ^3.2.5 16 | version: 3.2.5 17 | 18 | packages: 19 | 20 | '@babel/code-frame@7.24.2': 21 | resolution: {integrity: sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==} 22 | engines: {node: '>=6.9.0'} 23 | 24 | '@babel/generator@7.17.7': 25 | resolution: {integrity: sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w==} 26 | engines: {node: '>=6.9.0'} 27 | 28 | '@babel/generator@7.24.1': 29 | resolution: {integrity: sha512-DfCRfZsBcrPEHUfuBMgbJ1Ut01Y/itOs+hY2nFLgqsqXd52/iSiVq5TITtUasIUgm+IIKdY2/1I7auiQOEeC9A==} 30 | engines: {node: '>=6.9.0'} 31 | 32 | '@babel/helper-environment-visitor@7.22.20': 33 | resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==} 34 | engines: {node: '>=6.9.0'} 35 | 36 | '@babel/helper-function-name@7.23.0': 37 | resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==} 38 | engines: {node: '>=6.9.0'} 39 | 40 | '@babel/helper-hoist-variables@7.22.5': 41 | resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} 42 | engines: {node: '>=6.9.0'} 43 | 44 | '@babel/helper-split-export-declaration@7.22.6': 45 | resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} 46 | engines: {node: '>=6.9.0'} 47 | 48 | '@babel/helper-string-parser@7.24.1': 49 | resolution: {integrity: sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==} 50 | engines: {node: '>=6.9.0'} 51 | 52 | '@babel/helper-validator-identifier@7.22.20': 53 | resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} 54 | engines: {node: '>=6.9.0'} 55 | 56 | '@babel/highlight@7.24.2': 57 | resolution: {integrity: sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==} 58 | engines: {node: '>=6.9.0'} 59 | 60 | '@babel/parser@7.24.1': 61 | resolution: {integrity: sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg==} 62 | engines: {node: '>=6.0.0'} 63 | hasBin: true 64 | 65 | '@babel/template@7.24.0': 66 | resolution: {integrity: sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==} 67 | engines: {node: '>=6.9.0'} 68 | 69 | '@babel/traverse@7.23.2': 70 | resolution: {integrity: sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==} 71 | engines: {node: '>=6.9.0'} 72 | 73 | '@babel/types@7.17.0': 74 | resolution: {integrity: sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==} 75 | engines: {node: '>=6.9.0'} 76 | 77 | '@babel/types@7.24.0': 78 | resolution: {integrity: sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==} 79 | engines: {node: '>=6.9.0'} 80 | 81 | '@jridgewell/gen-mapping@0.3.5': 82 | resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} 83 | engines: {node: '>=6.0.0'} 84 | 85 | '@jridgewell/resolve-uri@3.1.2': 86 | resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} 87 | engines: {node: '>=6.0.0'} 88 | 89 | '@jridgewell/set-array@1.2.1': 90 | resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} 91 | engines: {node: '>=6.0.0'} 92 | 93 | '@jridgewell/sourcemap-codec@1.4.15': 94 | resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} 95 | 96 | '@jridgewell/trace-mapping@0.3.25': 97 | resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} 98 | 99 | '@trivago/prettier-plugin-sort-imports@4.3.0': 100 | resolution: {integrity: sha512-r3n0onD3BTOVUNPhR4lhVK4/pABGpbA7bW3eumZnYdKaHkf1qEC+Mag6DPbGNuuh0eG8AaYj+YqmVHSiGslaTQ==} 101 | peerDependencies: 102 | '@vue/compiler-sfc': 3.x 103 | prettier: 2.x - 3.x 104 | peerDependenciesMeta: 105 | '@vue/compiler-sfc': 106 | optional: true 107 | 108 | ansi-styles@3.2.1: 109 | resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} 110 | engines: {node: '>=4'} 111 | 112 | chalk@2.4.2: 113 | resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} 114 | engines: {node: '>=4'} 115 | 116 | color-convert@1.9.3: 117 | resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} 118 | 119 | color-name@1.1.3: 120 | resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} 121 | 122 | debug@4.3.4: 123 | resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} 124 | engines: {node: '>=6.0'} 125 | peerDependencies: 126 | supports-color: '*' 127 | peerDependenciesMeta: 128 | supports-color: 129 | optional: true 130 | 131 | escape-string-regexp@1.0.5: 132 | resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} 133 | engines: {node: '>=0.8.0'} 134 | 135 | globals@11.12.0: 136 | resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} 137 | engines: {node: '>=4'} 138 | 139 | has-flag@3.0.0: 140 | resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} 141 | engines: {node: '>=4'} 142 | 143 | javascript-natural-sort@0.7.1: 144 | resolution: {integrity: sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==} 145 | 146 | js-tokens@4.0.0: 147 | resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} 148 | 149 | jsesc@2.5.2: 150 | resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} 151 | engines: {node: '>=4'} 152 | hasBin: true 153 | 154 | lodash@4.17.21: 155 | resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} 156 | 157 | ms@2.1.2: 158 | resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} 159 | 160 | picocolors@1.0.0: 161 | resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} 162 | 163 | prettier@3.2.5: 164 | resolution: {integrity: sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==} 165 | engines: {node: '>=14'} 166 | hasBin: true 167 | 168 | source-map@0.5.7: 169 | resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} 170 | engines: {node: '>=0.10.0'} 171 | 172 | supports-color@5.5.0: 173 | resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} 174 | engines: {node: '>=4'} 175 | 176 | to-fast-properties@2.0.0: 177 | resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} 178 | engines: {node: '>=4'} 179 | 180 | snapshots: 181 | 182 | '@babel/code-frame@7.24.2': 183 | dependencies: 184 | '@babel/highlight': 7.24.2 185 | picocolors: 1.0.0 186 | 187 | '@babel/generator@7.17.7': 188 | dependencies: 189 | '@babel/types': 7.17.0 190 | jsesc: 2.5.2 191 | source-map: 0.5.7 192 | 193 | '@babel/generator@7.24.1': 194 | dependencies: 195 | '@babel/types': 7.24.0 196 | '@jridgewell/gen-mapping': 0.3.5 197 | '@jridgewell/trace-mapping': 0.3.25 198 | jsesc: 2.5.2 199 | 200 | '@babel/helper-environment-visitor@7.22.20': {} 201 | 202 | '@babel/helper-function-name@7.23.0': 203 | dependencies: 204 | '@babel/template': 7.24.0 205 | '@babel/types': 7.24.0 206 | 207 | '@babel/helper-hoist-variables@7.22.5': 208 | dependencies: 209 | '@babel/types': 7.24.0 210 | 211 | '@babel/helper-split-export-declaration@7.22.6': 212 | dependencies: 213 | '@babel/types': 7.24.0 214 | 215 | '@babel/helper-string-parser@7.24.1': {} 216 | 217 | '@babel/helper-validator-identifier@7.22.20': {} 218 | 219 | '@babel/highlight@7.24.2': 220 | dependencies: 221 | '@babel/helper-validator-identifier': 7.22.20 222 | chalk: 2.4.2 223 | js-tokens: 4.0.0 224 | picocolors: 1.0.0 225 | 226 | '@babel/parser@7.24.1': 227 | dependencies: 228 | '@babel/types': 7.17.0 229 | 230 | '@babel/template@7.24.0': 231 | dependencies: 232 | '@babel/code-frame': 7.24.2 233 | '@babel/parser': 7.24.1 234 | '@babel/types': 7.24.0 235 | 236 | '@babel/traverse@7.23.2': 237 | dependencies: 238 | '@babel/code-frame': 7.24.2 239 | '@babel/generator': 7.24.1 240 | '@babel/helper-environment-visitor': 7.22.20 241 | '@babel/helper-function-name': 7.23.0 242 | '@babel/helper-hoist-variables': 7.22.5 243 | '@babel/helper-split-export-declaration': 7.22.6 244 | '@babel/parser': 7.24.1 245 | '@babel/types': 7.24.0 246 | debug: 4.3.4 247 | globals: 11.12.0 248 | transitivePeerDependencies: 249 | - supports-color 250 | 251 | '@babel/types@7.17.0': 252 | dependencies: 253 | '@babel/helper-validator-identifier': 7.22.20 254 | to-fast-properties: 2.0.0 255 | 256 | '@babel/types@7.24.0': 257 | dependencies: 258 | '@babel/helper-string-parser': 7.24.1 259 | '@babel/helper-validator-identifier': 7.22.20 260 | to-fast-properties: 2.0.0 261 | 262 | '@jridgewell/gen-mapping@0.3.5': 263 | dependencies: 264 | '@jridgewell/set-array': 1.2.1 265 | '@jridgewell/sourcemap-codec': 1.4.15 266 | '@jridgewell/trace-mapping': 0.3.25 267 | 268 | '@jridgewell/resolve-uri@3.1.2': {} 269 | 270 | '@jridgewell/set-array@1.2.1': {} 271 | 272 | '@jridgewell/sourcemap-codec@1.4.15': {} 273 | 274 | '@jridgewell/trace-mapping@0.3.25': 275 | dependencies: 276 | '@jridgewell/resolve-uri': 3.1.2 277 | '@jridgewell/sourcemap-codec': 1.4.15 278 | 279 | '@trivago/prettier-plugin-sort-imports@4.3.0(prettier@3.2.5)': 280 | dependencies: 281 | '@babel/generator': 7.17.7 282 | '@babel/parser': 7.24.1 283 | '@babel/traverse': 7.23.2 284 | '@babel/types': 7.17.0 285 | javascript-natural-sort: 0.7.1 286 | lodash: 4.17.21 287 | prettier: 3.2.5 288 | transitivePeerDependencies: 289 | - supports-color 290 | 291 | ansi-styles@3.2.1: 292 | dependencies: 293 | color-convert: 1.9.3 294 | 295 | chalk@2.4.2: 296 | dependencies: 297 | ansi-styles: 3.2.1 298 | escape-string-regexp: 1.0.5 299 | supports-color: 5.5.0 300 | 301 | color-convert@1.9.3: 302 | dependencies: 303 | color-name: 1.1.3 304 | 305 | color-name@1.1.3: {} 306 | 307 | debug@4.3.4: 308 | dependencies: 309 | ms: 2.1.2 310 | 311 | escape-string-regexp@1.0.5: {} 312 | 313 | globals@11.12.0: {} 314 | 315 | has-flag@3.0.0: {} 316 | 317 | javascript-natural-sort@0.7.1: {} 318 | 319 | js-tokens@4.0.0: {} 320 | 321 | jsesc@2.5.2: {} 322 | 323 | lodash@4.17.21: {} 324 | 325 | ms@2.1.2: {} 326 | 327 | picocolors@1.0.0: {} 328 | 329 | prettier@3.2.5: {} 330 | 331 | source-map@0.5.7: {} 332 | 333 | supports-color@5.5.0: 334 | dependencies: 335 | has-flag: 3.0.0 336 | 337 | to-fast-properties@2.0.0: {} 338 | --------------------------------------------------------------------------------