From 70c274a594d8022f23237b953bcd41a809dbeec0 Mon Sep 17 00:00:00 2001 From: waleed Date: Tue, 9 Jun 2026 11:23:57 -0700 Subject: [PATCH 1/6] feat(integrations): add AWS AppConfig integration with tools, block, and docs --- apps/docs/components/icons.tsx | 19 + apps/docs/components/ui/icon-mapping.ts | 2 + apps/docs/content/docs/en/tools/appconfig.mdx | 421 +++++++++++++ apps/docs/content/docs/en/tools/meta.json | 1 + .../appconfig/create-application/route.ts | 52 ++ .../create-configuration-profile/route.ts | 60 ++ .../appconfig/create-environment/route.ts | 57 ++ .../route.ts | 64 ++ .../appconfig/get-configuration/route.ts | 59 ++ .../tools/appconfig/get-deployment/route.ts | 59 ++ .../get-hosted-configuration-version/route.ts | 60 ++ .../appconfig/list-applications/route.ts | 52 ++ .../list-configuration-profiles/route.ts | 59 ++ .../list-deployment-strategies/route.ts | 52 ++ .../tools/appconfig/list-deployments/route.ts | 58 ++ .../appconfig/list-environments/route.ts | 57 ++ .../tools/appconfig/start-deployment/route.ts | 60 ++ .../tools/appconfig/stop-deployment/route.ts | 59 ++ apps/sim/app/api/tools/appconfig/utils.ts | 439 +++++++++++++ apps/sim/blocks/blocks/appconfig.ts | 579 ++++++++++++++++++ apps/sim/blocks/registry.ts | 3 + apps/sim/components/icons.tsx | 19 + .../tools/aws/appconfig-create-application.ts | 38 ++ .../appconfig-create-configuration-profile.ts | 44 ++ .../tools/aws/appconfig-create-environment.ts | 40 ++ ...fig-create-hosted-configuration-version.ts | 45 ++ .../tools/aws/appconfig-get-configuration.ts | 38 ++ .../tools/aws/appconfig-get-deployment.ts | 45 ++ ...config-get-hosted-configuration-version.ts | 42 ++ .../tools/aws/appconfig-list-applications.ts | 43 ++ .../appconfig-list-configuration-profiles.ts | 49 ++ .../appconfig-list-deployment-strategies.ts | 48 ++ .../tools/aws/appconfig-list-deployments.ts | 54 ++ .../tools/aws/appconfig-list-environments.ts | 46 ++ .../tools/aws/appconfig-start-deployment.ts | 42 ++ .../tools/aws/appconfig-stop-deployment.ts | 36 ++ apps/sim/lib/integrations/icon-mapping.ts | 2 + apps/sim/lib/integrations/integrations.json | 75 +++ .../sim/tools/appconfig/create_application.ts | 90 +++ .../appconfig/create_configuration_profile.ts | 120 ++++ .../sim/tools/appconfig/create_environment.ts | 95 +++ .../create_hosted_configuration_version.ts | 137 +++++ apps/sim/tools/appconfig/get_configuration.ts | 100 +++ apps/sim/tools/appconfig/get_deployment.ts | 109 ++++ .../get_hosted_configuration_version.ts | 107 ++++ apps/sim/tools/appconfig/index.ts | 29 + apps/sim/tools/appconfig/list_applications.ts | 99 +++ .../appconfig/list_configuration_profiles.ts | 117 ++++ .../appconfig/list_deployment_strategies.ts | 120 ++++ apps/sim/tools/appconfig/list_deployments.ts | 138 +++++ apps/sim/tools/appconfig/list_environments.ts | 108 ++++ apps/sim/tools/appconfig/start_deployment.ts | 122 ++++ apps/sim/tools/appconfig/stop_deployment.ts | 91 +++ apps/sim/tools/appconfig/types.ts | 301 +++++++++ apps/sim/tools/registry.ts | 30 + bun.lock | 5 + package.json | 5 +- scripts/check-api-validation-contracts.ts | 4 +- 58 files changed, 4902 insertions(+), 3 deletions(-) create mode 100644 apps/docs/content/docs/en/tools/appconfig.mdx create mode 100644 apps/sim/app/api/tools/appconfig/create-application/route.ts create mode 100644 apps/sim/app/api/tools/appconfig/create-configuration-profile/route.ts create mode 100644 apps/sim/app/api/tools/appconfig/create-environment/route.ts create mode 100644 apps/sim/app/api/tools/appconfig/create-hosted-configuration-version/route.ts create mode 100644 apps/sim/app/api/tools/appconfig/get-configuration/route.ts create mode 100644 apps/sim/app/api/tools/appconfig/get-deployment/route.ts create mode 100644 apps/sim/app/api/tools/appconfig/get-hosted-configuration-version/route.ts create mode 100644 apps/sim/app/api/tools/appconfig/list-applications/route.ts create mode 100644 apps/sim/app/api/tools/appconfig/list-configuration-profiles/route.ts create mode 100644 apps/sim/app/api/tools/appconfig/list-deployment-strategies/route.ts create mode 100644 apps/sim/app/api/tools/appconfig/list-deployments/route.ts create mode 100644 apps/sim/app/api/tools/appconfig/list-environments/route.ts create mode 100644 apps/sim/app/api/tools/appconfig/start-deployment/route.ts create mode 100644 apps/sim/app/api/tools/appconfig/stop-deployment/route.ts create mode 100644 apps/sim/app/api/tools/appconfig/utils.ts create mode 100644 apps/sim/blocks/blocks/appconfig.ts create mode 100644 apps/sim/lib/api/contracts/tools/aws/appconfig-create-application.ts create mode 100644 apps/sim/lib/api/contracts/tools/aws/appconfig-create-configuration-profile.ts create mode 100644 apps/sim/lib/api/contracts/tools/aws/appconfig-create-environment.ts create mode 100644 apps/sim/lib/api/contracts/tools/aws/appconfig-create-hosted-configuration-version.ts create mode 100644 apps/sim/lib/api/contracts/tools/aws/appconfig-get-configuration.ts create mode 100644 apps/sim/lib/api/contracts/tools/aws/appconfig-get-deployment.ts create mode 100644 apps/sim/lib/api/contracts/tools/aws/appconfig-get-hosted-configuration-version.ts create mode 100644 apps/sim/lib/api/contracts/tools/aws/appconfig-list-applications.ts create mode 100644 apps/sim/lib/api/contracts/tools/aws/appconfig-list-configuration-profiles.ts create mode 100644 apps/sim/lib/api/contracts/tools/aws/appconfig-list-deployment-strategies.ts create mode 100644 apps/sim/lib/api/contracts/tools/aws/appconfig-list-deployments.ts create mode 100644 apps/sim/lib/api/contracts/tools/aws/appconfig-list-environments.ts create mode 100644 apps/sim/lib/api/contracts/tools/aws/appconfig-start-deployment.ts create mode 100644 apps/sim/lib/api/contracts/tools/aws/appconfig-stop-deployment.ts create mode 100644 apps/sim/tools/appconfig/create_application.ts create mode 100644 apps/sim/tools/appconfig/create_configuration_profile.ts create mode 100644 apps/sim/tools/appconfig/create_environment.ts create mode 100644 apps/sim/tools/appconfig/create_hosted_configuration_version.ts create mode 100644 apps/sim/tools/appconfig/get_configuration.ts create mode 100644 apps/sim/tools/appconfig/get_deployment.ts create mode 100644 apps/sim/tools/appconfig/get_hosted_configuration_version.ts create mode 100644 apps/sim/tools/appconfig/index.ts create mode 100644 apps/sim/tools/appconfig/list_applications.ts create mode 100644 apps/sim/tools/appconfig/list_configuration_profiles.ts create mode 100644 apps/sim/tools/appconfig/list_deployment_strategies.ts create mode 100644 apps/sim/tools/appconfig/list_deployments.ts create mode 100644 apps/sim/tools/appconfig/list_environments.ts create mode 100644 apps/sim/tools/appconfig/start_deployment.ts create mode 100644 apps/sim/tools/appconfig/stop_deployment.ts create mode 100644 apps/sim/tools/appconfig/types.ts diff --git a/apps/docs/components/icons.tsx b/apps/docs/components/icons.tsx index 12aeb36697b..5e18d3adc93 100644 --- a/apps/docs/components/icons.tsx +++ b/apps/docs/components/icons.tsx @@ -4672,6 +4672,25 @@ export function ServiceNowIcon(props: SVGProps) { ) } +export function AppConfigIcon(props: SVGProps) { + const id = useId() + return ( + + + + + + + + + + + ) +} + export function ApolloIcon(props: SVGProps) { return ( = { amplitude: AmplitudeIcon, apify: ApifyIcon, apollo: ApolloIcon, + appconfig: AppConfigIcon, arxiv: ArxivIcon, asana: AsanaIcon, ashby: AshbyIcon, diff --git a/apps/docs/content/docs/en/tools/appconfig.mdx b/apps/docs/content/docs/en/tools/appconfig.mdx new file mode 100644 index 00000000000..4f5907e7958 --- /dev/null +++ b/apps/docs/content/docs/en/tools/appconfig.mdx @@ -0,0 +1,421 @@ +--- +title: AWS AppConfig +description: Manage and retrieve configuration with AWS AppConfig +--- + +import { BlockInfoCard } from "@/components/ui/block-info-card" + + + +{/* MANUAL-CONTENT-START:intro */} +[AWS AppConfig](https://docs.aws.amazon.com/appconfig/) is a capability of AWS Systems Manager that lets you create, manage, and deploy application configuration and feature flags independently of your code. You organize configuration into applications, environments, and configuration profiles, store versioned configuration data, and roll it out gradually with deployment strategies that can monitor and automatically roll back on errors. + +With the AppConfig integration, you can: + +- **Get Configuration**: Retrieve the latest deployed configuration for an application, environment, and profile at runtime, using the AppConfig Data plane to drive feature flags and dynamic settings in your workflows +- **Manage Applications**: List existing applications or create a new one to group related configuration +- **Manage Environments**: List or create the environments (such as `development`, `staging`, and `production`) that configuration is deployed to +- **Manage Configuration Profiles**: List or create the profiles that describe where configuration is stored — AppConfig-hosted, SSM, or S3 — and whether it is freeform or a feature-flag profile +- **Version Hosted Configuration**: Create a new hosted configuration version from a JSON, YAML, or text document, or read back a specific version's content +- **Run Deployments**: Start a deployment of a configuration version to an environment with a chosen deployment strategy, inspect deployment status and history, and stop an in-progress deployment + +In Sim, the AppConfig integration lets your agents read live configuration to branch behavior, publish new configuration versions, and orchestrate safe, gradual rollouts. This pairs naturally with CloudWatch for monitoring deployment health and Slack for approval gates and rollout alerts, enabling end-to-end configuration and feature-flag automation. + +Authentication uses an AWS access key ID and secret access key. The associated IAM principal needs the relevant `appconfig:*` permissions (for example `appconfig:GetLatestConfiguration` and `appconfig:StartConfigurationSession` for retrieval, and `appconfig:StartDeployment` for rollouts). +{/* MANUAL-CONTENT-END */} + +## Usage Instructions + +Integrate AWS AppConfig into workflows. Manage applications, environments, and configuration profiles, create and read hosted configuration versions, run and inspect deployments, and retrieve the latest deployed configuration at runtime. Requires AWS access key and secret access key. + + + +## Tools + +### `appconfig_get_configuration` + +Retrieve the latest deployed configuration for an AppConfig application, environment, and profile + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `region` | string | Yes | AWS region \(e.g., us-east-1\) | +| `accessKeyId` | string | Yes | AWS access key ID | +| `secretAccessKey` | string | Yes | AWS secret access key | +| `applicationId` | string | Yes | The application ID or name to retrieve configuration for | +| `environmentId` | string | Yes | The environment ID or name to retrieve configuration for | +| `configurationProfileId` | string | Yes | The configuration profile ID or name to retrieve | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `configuration` | string | The deployed configuration content | +| `contentType` | string | Content type of the configuration | +| `versionLabel` | string | Label of the retrieved configuration version | + +### `appconfig_list_applications` + +List applications in AWS AppConfig + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `region` | string | Yes | AWS region \(e.g., us-east-1\) | +| `accessKeyId` | string | Yes | AWS access key ID | +| `secretAccessKey` | string | Yes | AWS secret access key | +| `maxResults` | number | No | Maximum number of applications to return \(1-50\) | +| `nextToken` | string | No | Pagination token from a previous response | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `applications` | array | List of AppConfig applications | +| ↳ `id` | string | Application ID | +| ↳ `name` | string | Application name | +| ↳ `description` | string | Application description | +| `nextToken` | string | Pagination token for the next page | +| `count` | number | Number of applications returned | + +### `appconfig_create_application` + +Create an application in AWS AppConfig + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `region` | string | Yes | AWS region \(e.g., us-east-1\) | +| `accessKeyId` | string | Yes | AWS access key ID | +| `secretAccessKey` | string | Yes | AWS secret access key | +| `name` | string | Yes | Name of the application to create | +| `description` | string | No | Description of the application | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `message` | string | Operation status message | +| `id` | string | ID of the created application | +| `name` | string | Name of the created application | +| `description` | string | Description of the created application | + +### `appconfig_list_environments` + +List environments for an AWS AppConfig application + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `region` | string | Yes | AWS region \(e.g., us-east-1\) | +| `accessKeyId` | string | Yes | AWS access key ID | +| `secretAccessKey` | string | Yes | AWS secret access key | +| `applicationId` | string | Yes | The application ID that owns the environments | +| `maxResults` | number | No | Maximum number of environments to return \(1-50\) | +| `nextToken` | string | No | Pagination token from a previous response | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `environments` | array | List of AppConfig environments | +| ↳ `applicationId` | string | Owning application ID | +| ↳ `id` | string | Environment ID | +| ↳ `name` | string | Environment name | +| ↳ `description` | string | Environment description | +| ↳ `state` | string | Environment state | +| `nextToken` | string | Pagination token for the next page | +| `count` | number | Number of environments returned | + +### `appconfig_create_environment` + +Create an environment for an AWS AppConfig application + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `region` | string | Yes | AWS region \(e.g., us-east-1\) | +| `accessKeyId` | string | Yes | AWS access key ID | +| `secretAccessKey` | string | Yes | AWS secret access key | +| `applicationId` | string | Yes | The application ID to create the environment in | +| `name` | string | Yes | Name of the environment to create | +| `description` | string | No | Description of the environment | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `message` | string | Operation status message | +| `applicationId` | string | Owning application ID | +| `id` | string | ID of the created environment | +| `name` | string | Name of the created environment | +| `state` | string | State of the created environment | + +### `appconfig_list_configuration_profiles` + +List configuration profiles for an AWS AppConfig application + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `region` | string | Yes | AWS region \(e.g., us-east-1\) | +| `accessKeyId` | string | Yes | AWS access key ID | +| `secretAccessKey` | string | Yes | AWS secret access key | +| `applicationId` | string | Yes | The application ID that owns the configuration profiles | +| `maxResults` | number | No | Maximum number of configuration profiles to return \(1-50\) | +| `nextToken` | string | No | Pagination token from a previous response | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `configurationProfiles` | array | List of AppConfig configuration profiles | +| ↳ `applicationId` | string | Owning application ID | +| ↳ `id` | string | Configuration profile ID | +| ↳ `name` | string | Configuration profile name | +| ↳ `locationUri` | string | Location URI of the config | +| ↳ `type` | string | Profile type \(e.g., AWS.Freeform\) | +| ↳ `validatorTypes` | array | Validator types configured | +| `nextToken` | string | Pagination token for the next page | +| `count` | number | Number of configuration profiles returned | + +### `appconfig_create_configuration_profile` + +Create a configuration profile in an AWS AppConfig application + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `region` | string | Yes | AWS region \(e.g., us-east-1\) | +| `accessKeyId` | string | Yes | AWS access key ID | +| `secretAccessKey` | string | Yes | AWS secret access key | +| `applicationId` | string | Yes | The application ID to create the configuration profile in | +| `name` | string | Yes | Name of the configuration profile | +| `locationUri` | string | Yes | Where the configuration is stored. Use "hosted" for AppConfig-hosted configurations, or an SSM/S3 URI | +| `description` | string | No | Description of the configuration profile | +| `retrievalRoleArn` | string | No | ARN of an IAM role to retrieve the configuration \(required for non-hosted URIs\) | +| `type` | string | No | Profile type: AWS.Freeform \(default\) or AWS.AppConfig.FeatureFlags | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `message` | string | Operation status message | +| `applicationId` | string | Owning application ID | +| `id` | string | ID of the created configuration profile | +| `name` | string | Name of the created configuration profile | +| `locationUri` | string | Location URI of the config | +| `type` | string | Profile type | + +### `appconfig_create_hosted_configuration_version` + +Create a new hosted configuration version for an AppConfig configuration profile + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `region` | string | Yes | AWS region \(e.g., us-east-1\) | +| `accessKeyId` | string | Yes | AWS access key ID | +| `secretAccessKey` | string | Yes | AWS secret access key | +| `applicationId` | string | Yes | The application ID that owns the configuration profile | +| `configurationProfileId` | string | Yes | The configuration profile ID to add the version to | +| `content` | string | Yes | The configuration content \(e.g., a JSON or YAML document\) | +| `contentType` | string | Yes | Content type of the configuration \(e.g., application/json, text/plain\) | +| `description` | string | No | Description of the configuration version | +| `latestVersionNumber` | number | No | The version number of the latest version, used for optimistic concurrency | +| `versionLabel` | string | No | A user-defined label for the configuration version | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `message` | string | Operation status message | +| `applicationId` | string | Owning application ID | +| `configurationProfileId` | string | Owning configuration profile ID | +| `versionNumber` | number | Version number of the created configuration | +| `contentType` | string | Content type of the configuration | +| `versionLabel` | string | Label of the configuration version | + +### `appconfig_get_hosted_configuration_version` + +Retrieve a specific hosted configuration version from an AppConfig profile + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `region` | string | Yes | AWS region \(e.g., us-east-1\) | +| `accessKeyId` | string | Yes | AWS access key ID | +| `secretAccessKey` | string | Yes | AWS secret access key | +| `applicationId` | string | Yes | The application ID that owns the configuration profile | +| `configurationProfileId` | string | Yes | The configuration profile ID to read the version from | +| `versionNumber` | number | Yes | The version number to retrieve | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `applicationId` | string | Owning application ID | +| `configurationProfileId` | string | Owning configuration profile ID | +| `versionNumber` | number | Version number | +| `description` | string | Description of the version | +| `content` | string | The configuration content | +| `contentType` | string | Content type of the configuration | +| `versionLabel` | string | Label of the configuration version | + +### `appconfig_list_deployment_strategies` + +List deployment strategies available in AWS AppConfig + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `region` | string | Yes | AWS region \(e.g., us-east-1\) | +| `accessKeyId` | string | Yes | AWS access key ID | +| `secretAccessKey` | string | Yes | AWS secret access key | +| `maxResults` | number | No | Maximum number of deployment strategies to return \(1-50\) | +| `nextToken` | string | No | Pagination token from a previous response | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `deploymentStrategies` | array | List of AppConfig deployment strategies | +| ↳ `id` | string | Deployment strategy ID | +| ↳ `name` | string | Deployment strategy name | +| ↳ `description` | string | Strategy description | +| ↳ `deploymentDurationInMinutes` | number | Total deployment duration in minutes | +| ↳ `growthType` | string | Growth type \(LINEAR or EXPONENTIAL\) | +| ↳ `growthFactor` | number | Growth factor percentage | +| ↳ `finalBakeTimeInMinutes` | number | Final bake time in minutes | +| ↳ `replicateTo` | string | Where the strategy is replicated | +| `nextToken` | string | Pagination token for the next page | +| `count` | number | Number of deployment strategies returned | + +### `appconfig_start_deployment` + +Start deploying a configuration version to an AWS AppConfig environment + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `region` | string | Yes | AWS region \(e.g., us-east-1\) | +| `accessKeyId` | string | Yes | AWS access key ID | +| `secretAccessKey` | string | Yes | AWS secret access key | +| `applicationId` | string | Yes | The application ID to deploy in | +| `environmentId` | string | Yes | The environment ID to deploy to | +| `deploymentStrategyId` | string | Yes | The deployment strategy ID to use | +| `configurationProfileId` | string | Yes | The configuration profile ID to deploy | +| `configurationVersion` | string | Yes | The configuration version to deploy | +| `description` | string | No | Description of the deployment | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `message` | string | Operation status message | +| `deploymentNumber` | number | Sequence number of the deployment | +| `state` | string | Current deployment state | +| `percentageComplete` | number | Percentage of the deployment that has completed | + +### `appconfig_get_deployment` + +Get details about a specific AWS AppConfig deployment + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `region` | string | Yes | AWS region \(e.g., us-east-1\) | +| `accessKeyId` | string | Yes | AWS access key ID | +| `secretAccessKey` | string | Yes | AWS secret access key | +| `applicationId` | string | Yes | The application ID of the deployment | +| `environmentId` | string | Yes | The environment ID of the deployment | +| `deploymentNumber` | number | Yes | The sequence number of the deployment | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `applicationId` | string | Application ID | +| `environmentId` | string | Environment ID | +| `deploymentStrategyId` | string | Deployment strategy ID | +| `configurationProfileId` | string | Configuration profile ID | +| `deploymentNumber` | number | Deployment sequence number | +| `configurationName` | string | Configuration name | +| `configurationVersion` | string | Configuration version | +| `description` | string | Deployment description | +| `state` | string | Current deployment state | +| `percentageComplete` | number | Percentage completed | +| `startedAt` | string | When the deployment started | +| `completedAt` | string | When the deployment completed | + +### `appconfig_list_deployments` + +List deployments for an AWS AppConfig environment + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `region` | string | Yes | AWS region \(e.g., us-east-1\) | +| `accessKeyId` | string | Yes | AWS access key ID | +| `secretAccessKey` | string | Yes | AWS secret access key | +| `applicationId` | string | Yes | The application ID of the deployments | +| `environmentId` | string | Yes | The environment ID of the deployments | +| `maxResults` | number | No | Maximum number of deployments to return \(1-50\) | +| `nextToken` | string | No | Pagination token from a previous response | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `deployments` | array | List of AppConfig deployments | +| ↳ `deploymentNumber` | number | Deployment sequence number | +| ↳ `configurationName` | string | Configuration name | +| ↳ `configurationVersion` | string | Configuration version | +| ↳ `state` | string | Current deployment state | +| ↳ `percentageComplete` | number | Percentage completed | +| ↳ `startedAt` | string | When the deployment started | +| ↳ `completedAt` | string | When the deployment completed | +| ↳ `versionLabel` | string | Configuration version label | +| `nextToken` | string | Pagination token for the next page | +| `count` | number | Number of deployments returned | + +### `appconfig_stop_deployment` + +Stop an in-progress AWS AppConfig deployment + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `region` | string | Yes | AWS region \(e.g., us-east-1\) | +| `accessKeyId` | string | Yes | AWS access key ID | +| `secretAccessKey` | string | Yes | AWS secret access key | +| `applicationId` | string | Yes | The application ID of the deployment | +| `environmentId` | string | Yes | The environment ID of the deployment | +| `deploymentNumber` | number | Yes | The sequence number of the deployment to stop | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `message` | string | Operation status message | +| `deploymentNumber` | number | Deployment sequence number | +| `state` | string | Deployment state after stopping | + + diff --git a/apps/docs/content/docs/en/tools/meta.json b/apps/docs/content/docs/en/tools/meta.json index c1e0a1d2081..c2edcceb166 100644 --- a/apps/docs/content/docs/en/tools/meta.json +++ b/apps/docs/content/docs/en/tools/meta.json @@ -11,6 +11,7 @@ "amplitude", "apify", "apollo", + "appconfig", "arxiv", "asana", "ashby", diff --git a/apps/sim/app/api/tools/appconfig/create-application/route.ts b/apps/sim/app/api/tools/appconfig/create-application/route.ts new file mode 100644 index 00000000000..f539bb43897 --- /dev/null +++ b/apps/sim/app/api/tools/appconfig/create-application/route.ts @@ -0,0 +1,52 @@ +import { createLogger } from '@sim/logger' +import { getErrorMessage } from '@sim/utils/errors' +import { generateId } from '@sim/utils/id' +import { type NextRequest, NextResponse } from 'next/server' +import { awsAppConfigCreateApplicationContract } from '@/lib/api/contracts/tools/aws/appconfig-create-application' +import { parseToolRequest } from '@/lib/api/server' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { withRouteHandler } from '@/lib/core/utils/with-route-handler' +import { createAppConfigClient, createApplication } from '../utils' + +const logger = createLogger('AppConfigCreateApplicationAPI') + +export const POST = withRouteHandler(async (request: NextRequest) => { + const requestId = generateId().slice(0, 8) + + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + try { + const parsed = await parseToolRequest(awsAppConfigCreateApplicationContract, request, { + errorFormat: 'details', + logger, + }) + if (!parsed.success) return parsed.response + const params = parsed.data.body + + logger.info(`[${requestId}] Creating AppConfig application ${params.name}`) + + const client = createAppConfigClient({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + }) + + try { + const result = await createApplication(client, params.name, params.description) + logger.info(`[${requestId}] Created application ${result.id}`) + return NextResponse.json(result) + } finally { + client.destroy() + } + } catch (error) { + const errorMessage = getErrorMessage(error, 'Unknown error occurred') + logger.error(`[${requestId}] Failed to create application:`, error) + return NextResponse.json( + { error: `Failed to create application: ${errorMessage}` }, + { status: 500 } + ) + } +}) diff --git a/apps/sim/app/api/tools/appconfig/create-configuration-profile/route.ts b/apps/sim/app/api/tools/appconfig/create-configuration-profile/route.ts new file mode 100644 index 00000000000..cf61b1f79fa --- /dev/null +++ b/apps/sim/app/api/tools/appconfig/create-configuration-profile/route.ts @@ -0,0 +1,60 @@ +import { createLogger } from '@sim/logger' +import { getErrorMessage } from '@sim/utils/errors' +import { generateId } from '@sim/utils/id' +import { type NextRequest, NextResponse } from 'next/server' +import { awsAppConfigCreateConfigurationProfileContract } from '@/lib/api/contracts/tools/aws/appconfig-create-configuration-profile' +import { parseToolRequest } from '@/lib/api/server' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { withRouteHandler } from '@/lib/core/utils/with-route-handler' +import { createAppConfigClient, createConfigurationProfile } from '../utils' + +const logger = createLogger('AppConfigCreateConfigurationProfileAPI') + +export const POST = withRouteHandler(async (request: NextRequest) => { + const requestId = generateId().slice(0, 8) + + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + try { + const parsed = await parseToolRequest(awsAppConfigCreateConfigurationProfileContract, request, { + errorFormat: 'details', + logger, + }) + if (!parsed.success) return parsed.response + const params = parsed.data.body + + logger.info(`[${requestId}] Creating AppConfig configuration profile ${params.name}`) + + const client = createAppConfigClient({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + }) + + try { + const result = await createConfigurationProfile( + client, + params.applicationId, + params.name, + params.locationUri, + params.description, + params.retrievalRoleArn, + params.type + ) + logger.info(`[${requestId}] Created configuration profile ${result.id}`) + return NextResponse.json(result) + } finally { + client.destroy() + } + } catch (error) { + const errorMessage = getErrorMessage(error, 'Unknown error occurred') + logger.error(`[${requestId}] Failed to create configuration profile:`, error) + return NextResponse.json( + { error: `Failed to create configuration profile: ${errorMessage}` }, + { status: 500 } + ) + } +}) diff --git a/apps/sim/app/api/tools/appconfig/create-environment/route.ts b/apps/sim/app/api/tools/appconfig/create-environment/route.ts new file mode 100644 index 00000000000..dff11740c9b --- /dev/null +++ b/apps/sim/app/api/tools/appconfig/create-environment/route.ts @@ -0,0 +1,57 @@ +import { createLogger } from '@sim/logger' +import { getErrorMessage } from '@sim/utils/errors' +import { generateId } from '@sim/utils/id' +import { type NextRequest, NextResponse } from 'next/server' +import { awsAppConfigCreateEnvironmentContract } from '@/lib/api/contracts/tools/aws/appconfig-create-environment' +import { parseToolRequest } from '@/lib/api/server' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { withRouteHandler } from '@/lib/core/utils/with-route-handler' +import { createAppConfigClient, createEnvironment } from '../utils' + +const logger = createLogger('AppConfigCreateEnvironmentAPI') + +export const POST = withRouteHandler(async (request: NextRequest) => { + const requestId = generateId().slice(0, 8) + + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + try { + const parsed = await parseToolRequest(awsAppConfigCreateEnvironmentContract, request, { + errorFormat: 'details', + logger, + }) + if (!parsed.success) return parsed.response + const params = parsed.data.body + + logger.info(`[${requestId}] Creating AppConfig environment ${params.name}`) + + const client = createAppConfigClient({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + }) + + try { + const result = await createEnvironment( + client, + params.applicationId, + params.name, + params.description + ) + logger.info(`[${requestId}] Created environment ${result.id}`) + return NextResponse.json(result) + } finally { + client.destroy() + } + } catch (error) { + const errorMessage = getErrorMessage(error, 'Unknown error occurred') + logger.error(`[${requestId}] Failed to create environment:`, error) + return NextResponse.json( + { error: `Failed to create environment: ${errorMessage}` }, + { status: 500 } + ) + } +}) diff --git a/apps/sim/app/api/tools/appconfig/create-hosted-configuration-version/route.ts b/apps/sim/app/api/tools/appconfig/create-hosted-configuration-version/route.ts new file mode 100644 index 00000000000..dbce4d4966f --- /dev/null +++ b/apps/sim/app/api/tools/appconfig/create-hosted-configuration-version/route.ts @@ -0,0 +1,64 @@ +import { createLogger } from '@sim/logger' +import { getErrorMessage } from '@sim/utils/errors' +import { generateId } from '@sim/utils/id' +import { type NextRequest, NextResponse } from 'next/server' +import { awsAppConfigCreateHostedConfigurationVersionContract } from '@/lib/api/contracts/tools/aws/appconfig-create-hosted-configuration-version' +import { parseToolRequest } from '@/lib/api/server' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { withRouteHandler } from '@/lib/core/utils/with-route-handler' +import { createAppConfigClient, createHostedConfigurationVersion } from '../utils' + +const logger = createLogger('AppConfigCreateHostedConfigurationVersionAPI') + +export const POST = withRouteHandler(async (request: NextRequest) => { + const requestId = generateId().slice(0, 8) + + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + try { + const parsed = await parseToolRequest( + awsAppConfigCreateHostedConfigurationVersionContract, + request, + { errorFormat: 'details', logger } + ) + if (!parsed.success) return parsed.response + const params = parsed.data.body + + logger.info( + `[${requestId}] Creating hosted configuration version for profile ${params.configurationProfileId}` + ) + + const client = createAppConfigClient({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + }) + + try { + const result = await createHostedConfigurationVersion( + client, + params.applicationId, + params.configurationProfileId, + params.content, + params.contentType, + params.description, + params.latestVersionNumber, + params.versionLabel + ) + logger.info(`[${requestId}] Created hosted configuration version ${result.versionNumber}`) + return NextResponse.json(result) + } finally { + client.destroy() + } + } catch (error) { + const errorMessage = getErrorMessage(error, 'Unknown error occurred') + logger.error(`[${requestId}] Failed to create hosted configuration version:`, error) + return NextResponse.json( + { error: `Failed to create hosted configuration version: ${errorMessage}` }, + { status: 500 } + ) + } +}) diff --git a/apps/sim/app/api/tools/appconfig/get-configuration/route.ts b/apps/sim/app/api/tools/appconfig/get-configuration/route.ts new file mode 100644 index 00000000000..32387a4505f --- /dev/null +++ b/apps/sim/app/api/tools/appconfig/get-configuration/route.ts @@ -0,0 +1,59 @@ +import { createLogger } from '@sim/logger' +import { getErrorMessage } from '@sim/utils/errors' +import { generateId } from '@sim/utils/id' +import { type NextRequest, NextResponse } from 'next/server' +import { awsAppConfigGetConfigurationContract } from '@/lib/api/contracts/tools/aws/appconfig-get-configuration' +import { parseToolRequest } from '@/lib/api/server' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { withRouteHandler } from '@/lib/core/utils/with-route-handler' +import { createAppConfigDataClient, getConfiguration } from '../utils' + +const logger = createLogger('AppConfigGetConfigurationAPI') + +export const POST = withRouteHandler(async (request: NextRequest) => { + const requestId = generateId().slice(0, 8) + + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + try { + const parsed = await parseToolRequest(awsAppConfigGetConfigurationContract, request, { + errorFormat: 'details', + logger, + }) + if (!parsed.success) return parsed.response + const params = parsed.data.body + + logger.info( + `[${requestId}] Retrieving AppConfig configuration for ${params.applicationId}/${params.environmentId}/${params.configurationProfileId}` + ) + + const client = createAppConfigDataClient({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + }) + + try { + const result = await getConfiguration( + client, + params.applicationId, + params.environmentId, + params.configurationProfileId + ) + logger.info(`[${requestId}] Retrieved configuration`) + return NextResponse.json(result) + } finally { + client.destroy() + } + } catch (error) { + const errorMessage = getErrorMessage(error, 'Unknown error occurred') + logger.error(`[${requestId}] Failed to retrieve configuration:`, error) + return NextResponse.json( + { error: `Failed to retrieve configuration: ${errorMessage}` }, + { status: 500 } + ) + } +}) diff --git a/apps/sim/app/api/tools/appconfig/get-deployment/route.ts b/apps/sim/app/api/tools/appconfig/get-deployment/route.ts new file mode 100644 index 00000000000..4e4313dfb24 --- /dev/null +++ b/apps/sim/app/api/tools/appconfig/get-deployment/route.ts @@ -0,0 +1,59 @@ +import { createLogger } from '@sim/logger' +import { getErrorMessage } from '@sim/utils/errors' +import { generateId } from '@sim/utils/id' +import { type NextRequest, NextResponse } from 'next/server' +import { awsAppConfigGetDeploymentContract } from '@/lib/api/contracts/tools/aws/appconfig-get-deployment' +import { parseToolRequest } from '@/lib/api/server' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { withRouteHandler } from '@/lib/core/utils/with-route-handler' +import { createAppConfigClient, getDeployment } from '../utils' + +const logger = createLogger('AppConfigGetDeploymentAPI') + +export const POST = withRouteHandler(async (request: NextRequest) => { + const requestId = generateId().slice(0, 8) + + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + try { + const parsed = await parseToolRequest(awsAppConfigGetDeploymentContract, request, { + errorFormat: 'details', + logger, + }) + if (!parsed.success) return parsed.response + const params = parsed.data.body + + logger.info( + `[${requestId}] Getting AppConfig deployment ${params.deploymentNumber} in env ${params.environmentId}` + ) + + const client = createAppConfigClient({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + }) + + try { + const result = await getDeployment( + client, + params.applicationId, + params.environmentId, + params.deploymentNumber + ) + logger.info(`[${requestId}] Retrieved deployment`) + return NextResponse.json(result) + } finally { + client.destroy() + } + } catch (error) { + const errorMessage = getErrorMessage(error, 'Unknown error occurred') + logger.error(`[${requestId}] Failed to get deployment:`, error) + return NextResponse.json( + { error: `Failed to get deployment: ${errorMessage}` }, + { status: 500 } + ) + } +}) diff --git a/apps/sim/app/api/tools/appconfig/get-hosted-configuration-version/route.ts b/apps/sim/app/api/tools/appconfig/get-hosted-configuration-version/route.ts new file mode 100644 index 00000000000..74011556eeb --- /dev/null +++ b/apps/sim/app/api/tools/appconfig/get-hosted-configuration-version/route.ts @@ -0,0 +1,60 @@ +import { createLogger } from '@sim/logger' +import { getErrorMessage } from '@sim/utils/errors' +import { generateId } from '@sim/utils/id' +import { type NextRequest, NextResponse } from 'next/server' +import { awsAppConfigGetHostedConfigurationVersionContract } from '@/lib/api/contracts/tools/aws/appconfig-get-hosted-configuration-version' +import { parseToolRequest } from '@/lib/api/server' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { withRouteHandler } from '@/lib/core/utils/with-route-handler' +import { createAppConfigClient, getHostedConfigurationVersion } from '../utils' + +const logger = createLogger('AppConfigGetHostedConfigurationVersionAPI') + +export const POST = withRouteHandler(async (request: NextRequest) => { + const requestId = generateId().slice(0, 8) + + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + try { + const parsed = await parseToolRequest( + awsAppConfigGetHostedConfigurationVersionContract, + request, + { errorFormat: 'details', logger } + ) + if (!parsed.success) return parsed.response + const params = parsed.data.body + + logger.info( + `[${requestId}] Getting hosted configuration version ${params.versionNumber} for profile ${params.configurationProfileId}` + ) + + const client = createAppConfigClient({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + }) + + try { + const result = await getHostedConfigurationVersion( + client, + params.applicationId, + params.configurationProfileId, + params.versionNumber + ) + logger.info(`[${requestId}] Retrieved hosted configuration version`) + return NextResponse.json(result) + } finally { + client.destroy() + } + } catch (error) { + const errorMessage = getErrorMessage(error, 'Unknown error occurred') + logger.error(`[${requestId}] Failed to get hosted configuration version:`, error) + return NextResponse.json( + { error: `Failed to get hosted configuration version: ${errorMessage}` }, + { status: 500 } + ) + } +}) diff --git a/apps/sim/app/api/tools/appconfig/list-applications/route.ts b/apps/sim/app/api/tools/appconfig/list-applications/route.ts new file mode 100644 index 00000000000..5cd42681bc4 --- /dev/null +++ b/apps/sim/app/api/tools/appconfig/list-applications/route.ts @@ -0,0 +1,52 @@ +import { createLogger } from '@sim/logger' +import { getErrorMessage } from '@sim/utils/errors' +import { generateId } from '@sim/utils/id' +import { type NextRequest, NextResponse } from 'next/server' +import { awsAppConfigListApplicationsContract } from '@/lib/api/contracts/tools/aws/appconfig-list-applications' +import { parseToolRequest } from '@/lib/api/server' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { withRouteHandler } from '@/lib/core/utils/with-route-handler' +import { createAppConfigClient, listApplications } from '../utils' + +const logger = createLogger('AppConfigListApplicationsAPI') + +export const POST = withRouteHandler(async (request: NextRequest) => { + const requestId = generateId().slice(0, 8) + + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + try { + const parsed = await parseToolRequest(awsAppConfigListApplicationsContract, request, { + errorFormat: 'details', + logger, + }) + if (!parsed.success) return parsed.response + const params = parsed.data.body + + logger.info(`[${requestId}] Listing AppConfig applications`) + + const client = createAppConfigClient({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + }) + + try { + const result = await listApplications(client, params.maxResults, params.nextToken) + logger.info(`[${requestId}] Listed ${result.count} applications`) + return NextResponse.json(result) + } finally { + client.destroy() + } + } catch (error) { + const errorMessage = getErrorMessage(error, 'Unknown error occurred') + logger.error(`[${requestId}] Failed to list applications:`, error) + return NextResponse.json( + { error: `Failed to list applications: ${errorMessage}` }, + { status: 500 } + ) + } +}) diff --git a/apps/sim/app/api/tools/appconfig/list-configuration-profiles/route.ts b/apps/sim/app/api/tools/appconfig/list-configuration-profiles/route.ts new file mode 100644 index 00000000000..d46d6f147b9 --- /dev/null +++ b/apps/sim/app/api/tools/appconfig/list-configuration-profiles/route.ts @@ -0,0 +1,59 @@ +import { createLogger } from '@sim/logger' +import { getErrorMessage } from '@sim/utils/errors' +import { generateId } from '@sim/utils/id' +import { type NextRequest, NextResponse } from 'next/server' +import { awsAppConfigListConfigurationProfilesContract } from '@/lib/api/contracts/tools/aws/appconfig-list-configuration-profiles' +import { parseToolRequest } from '@/lib/api/server' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { withRouteHandler } from '@/lib/core/utils/with-route-handler' +import { createAppConfigClient, listConfigurationProfiles } from '../utils' + +const logger = createLogger('AppConfigListConfigurationProfilesAPI') + +export const POST = withRouteHandler(async (request: NextRequest) => { + const requestId = generateId().slice(0, 8) + + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + try { + const parsed = await parseToolRequest(awsAppConfigListConfigurationProfilesContract, request, { + errorFormat: 'details', + logger, + }) + if (!parsed.success) return parsed.response + const params = parsed.data.body + + logger.info( + `[${requestId}] Listing AppConfig configuration profiles for ${params.applicationId}` + ) + + const client = createAppConfigClient({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + }) + + try { + const result = await listConfigurationProfiles( + client, + params.applicationId, + params.maxResults, + params.nextToken + ) + logger.info(`[${requestId}] Listed ${result.count} configuration profiles`) + return NextResponse.json(result) + } finally { + client.destroy() + } + } catch (error) { + const errorMessage = getErrorMessage(error, 'Unknown error occurred') + logger.error(`[${requestId}] Failed to list configuration profiles:`, error) + return NextResponse.json( + { error: `Failed to list configuration profiles: ${errorMessage}` }, + { status: 500 } + ) + } +}) diff --git a/apps/sim/app/api/tools/appconfig/list-deployment-strategies/route.ts b/apps/sim/app/api/tools/appconfig/list-deployment-strategies/route.ts new file mode 100644 index 00000000000..6aa05d4b31a --- /dev/null +++ b/apps/sim/app/api/tools/appconfig/list-deployment-strategies/route.ts @@ -0,0 +1,52 @@ +import { createLogger } from '@sim/logger' +import { getErrorMessage } from '@sim/utils/errors' +import { generateId } from '@sim/utils/id' +import { type NextRequest, NextResponse } from 'next/server' +import { awsAppConfigListDeploymentStrategiesContract } from '@/lib/api/contracts/tools/aws/appconfig-list-deployment-strategies' +import { parseToolRequest } from '@/lib/api/server' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { withRouteHandler } from '@/lib/core/utils/with-route-handler' +import { createAppConfigClient, listDeploymentStrategies } from '../utils' + +const logger = createLogger('AppConfigListDeploymentStrategiesAPI') + +export const POST = withRouteHandler(async (request: NextRequest) => { + const requestId = generateId().slice(0, 8) + + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + try { + const parsed = await parseToolRequest(awsAppConfigListDeploymentStrategiesContract, request, { + errorFormat: 'details', + logger, + }) + if (!parsed.success) return parsed.response + const params = parsed.data.body + + logger.info(`[${requestId}] Listing AppConfig deployment strategies`) + + const client = createAppConfigClient({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + }) + + try { + const result = await listDeploymentStrategies(client, params.maxResults, params.nextToken) + logger.info(`[${requestId}] Listed ${result.count} deployment strategies`) + return NextResponse.json(result) + } finally { + client.destroy() + } + } catch (error) { + const errorMessage = getErrorMessage(error, 'Unknown error occurred') + logger.error(`[${requestId}] Failed to list deployment strategies:`, error) + return NextResponse.json( + { error: `Failed to list deployment strategies: ${errorMessage}` }, + { status: 500 } + ) + } +}) diff --git a/apps/sim/app/api/tools/appconfig/list-deployments/route.ts b/apps/sim/app/api/tools/appconfig/list-deployments/route.ts new file mode 100644 index 00000000000..0eb3eac0a9a --- /dev/null +++ b/apps/sim/app/api/tools/appconfig/list-deployments/route.ts @@ -0,0 +1,58 @@ +import { createLogger } from '@sim/logger' +import { getErrorMessage } from '@sim/utils/errors' +import { generateId } from '@sim/utils/id' +import { type NextRequest, NextResponse } from 'next/server' +import { awsAppConfigListDeploymentsContract } from '@/lib/api/contracts/tools/aws/appconfig-list-deployments' +import { parseToolRequest } from '@/lib/api/server' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { withRouteHandler } from '@/lib/core/utils/with-route-handler' +import { createAppConfigClient, listDeployments } from '../utils' + +const logger = createLogger('AppConfigListDeploymentsAPI') + +export const POST = withRouteHandler(async (request: NextRequest) => { + const requestId = generateId().slice(0, 8) + + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + try { + const parsed = await parseToolRequest(awsAppConfigListDeploymentsContract, request, { + errorFormat: 'details', + logger, + }) + if (!parsed.success) return parsed.response + const params = parsed.data.body + + logger.info(`[${requestId}] Listing AppConfig deployments in env ${params.environmentId}`) + + const client = createAppConfigClient({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + }) + + try { + const result = await listDeployments( + client, + params.applicationId, + params.environmentId, + params.maxResults, + params.nextToken + ) + logger.info(`[${requestId}] Listed ${result.count} deployments`) + return NextResponse.json(result) + } finally { + client.destroy() + } + } catch (error) { + const errorMessage = getErrorMessage(error, 'Unknown error occurred') + logger.error(`[${requestId}] Failed to list deployments:`, error) + return NextResponse.json( + { error: `Failed to list deployments: ${errorMessage}` }, + { status: 500 } + ) + } +}) diff --git a/apps/sim/app/api/tools/appconfig/list-environments/route.ts b/apps/sim/app/api/tools/appconfig/list-environments/route.ts new file mode 100644 index 00000000000..8daae842e47 --- /dev/null +++ b/apps/sim/app/api/tools/appconfig/list-environments/route.ts @@ -0,0 +1,57 @@ +import { createLogger } from '@sim/logger' +import { getErrorMessage } from '@sim/utils/errors' +import { generateId } from '@sim/utils/id' +import { type NextRequest, NextResponse } from 'next/server' +import { awsAppConfigListEnvironmentsContract } from '@/lib/api/contracts/tools/aws/appconfig-list-environments' +import { parseToolRequest } from '@/lib/api/server' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { withRouteHandler } from '@/lib/core/utils/with-route-handler' +import { createAppConfigClient, listEnvironments } from '../utils' + +const logger = createLogger('AppConfigListEnvironmentsAPI') + +export const POST = withRouteHandler(async (request: NextRequest) => { + const requestId = generateId().slice(0, 8) + + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + try { + const parsed = await parseToolRequest(awsAppConfigListEnvironmentsContract, request, { + errorFormat: 'details', + logger, + }) + if (!parsed.success) return parsed.response + const params = parsed.data.body + + logger.info(`[${requestId}] Listing AppConfig environments for ${params.applicationId}`) + + const client = createAppConfigClient({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + }) + + try { + const result = await listEnvironments( + client, + params.applicationId, + params.maxResults, + params.nextToken + ) + logger.info(`[${requestId}] Listed ${result.count} environments`) + return NextResponse.json(result) + } finally { + client.destroy() + } + } catch (error) { + const errorMessage = getErrorMessage(error, 'Unknown error occurred') + logger.error(`[${requestId}] Failed to list environments:`, error) + return NextResponse.json( + { error: `Failed to list environments: ${errorMessage}` }, + { status: 500 } + ) + } +}) diff --git a/apps/sim/app/api/tools/appconfig/start-deployment/route.ts b/apps/sim/app/api/tools/appconfig/start-deployment/route.ts new file mode 100644 index 00000000000..743f1ae330a --- /dev/null +++ b/apps/sim/app/api/tools/appconfig/start-deployment/route.ts @@ -0,0 +1,60 @@ +import { createLogger } from '@sim/logger' +import { getErrorMessage } from '@sim/utils/errors' +import { generateId } from '@sim/utils/id' +import { type NextRequest, NextResponse } from 'next/server' +import { awsAppConfigStartDeploymentContract } from '@/lib/api/contracts/tools/aws/appconfig-start-deployment' +import { parseToolRequest } from '@/lib/api/server' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { withRouteHandler } from '@/lib/core/utils/with-route-handler' +import { createAppConfigClient, startDeployment } from '../utils' + +const logger = createLogger('AppConfigStartDeploymentAPI') + +export const POST = withRouteHandler(async (request: NextRequest) => { + const requestId = generateId().slice(0, 8) + + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + try { + const parsed = await parseToolRequest(awsAppConfigStartDeploymentContract, request, { + errorFormat: 'details', + logger, + }) + if (!parsed.success) return parsed.response + const params = parsed.data.body + + logger.info(`[${requestId}] Starting AppConfig deployment in env ${params.environmentId}`) + + const client = createAppConfigClient({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + }) + + try { + const result = await startDeployment( + client, + params.applicationId, + params.environmentId, + params.deploymentStrategyId, + params.configurationProfileId, + params.configurationVersion, + params.description + ) + logger.info(`[${requestId}] Started deployment ${result.deploymentNumber}`) + return NextResponse.json(result) + } finally { + client.destroy() + } + } catch (error) { + const errorMessage = getErrorMessage(error, 'Unknown error occurred') + logger.error(`[${requestId}] Failed to start deployment:`, error) + return NextResponse.json( + { error: `Failed to start deployment: ${errorMessage}` }, + { status: 500 } + ) + } +}) diff --git a/apps/sim/app/api/tools/appconfig/stop-deployment/route.ts b/apps/sim/app/api/tools/appconfig/stop-deployment/route.ts new file mode 100644 index 00000000000..dcbdf7db88a --- /dev/null +++ b/apps/sim/app/api/tools/appconfig/stop-deployment/route.ts @@ -0,0 +1,59 @@ +import { createLogger } from '@sim/logger' +import { getErrorMessage } from '@sim/utils/errors' +import { generateId } from '@sim/utils/id' +import { type NextRequest, NextResponse } from 'next/server' +import { awsAppConfigStopDeploymentContract } from '@/lib/api/contracts/tools/aws/appconfig-stop-deployment' +import { parseToolRequest } from '@/lib/api/server' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { withRouteHandler } from '@/lib/core/utils/with-route-handler' +import { createAppConfigClient, stopDeployment } from '../utils' + +const logger = createLogger('AppConfigStopDeploymentAPI') + +export const POST = withRouteHandler(async (request: NextRequest) => { + const requestId = generateId().slice(0, 8) + + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + try { + const parsed = await parseToolRequest(awsAppConfigStopDeploymentContract, request, { + errorFormat: 'details', + logger, + }) + if (!parsed.success) return parsed.response + const params = parsed.data.body + + logger.info( + `[${requestId}] Stopping AppConfig deployment ${params.deploymentNumber} in env ${params.environmentId}` + ) + + const client = createAppConfigClient({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + }) + + try { + const result = await stopDeployment( + client, + params.applicationId, + params.environmentId, + params.deploymentNumber + ) + logger.info(`[${requestId}] Stopped deployment ${result.deploymentNumber}`) + return NextResponse.json(result) + } finally { + client.destroy() + } + } catch (error) { + const errorMessage = getErrorMessage(error, 'Unknown error occurred') + logger.error(`[${requestId}] Failed to stop deployment:`, error) + return NextResponse.json( + { error: `Failed to stop deployment: ${errorMessage}` }, + { status: 500 } + ) + } +}) diff --git a/apps/sim/app/api/tools/appconfig/utils.ts b/apps/sim/app/api/tools/appconfig/utils.ts new file mode 100644 index 00000000000..454b064b04b --- /dev/null +++ b/apps/sim/app/api/tools/appconfig/utils.ts @@ -0,0 +1,439 @@ +import { + AppConfigClient, + CreateApplicationCommand, + CreateConfigurationProfileCommand, + CreateEnvironmentCommand, + CreateHostedConfigurationVersionCommand, + GetDeploymentCommand, + GetHostedConfigurationVersionCommand, + ListApplicationsCommand, + ListConfigurationProfilesCommand, + ListDeploymentStrategiesCommand, + ListDeploymentsCommand, + ListEnvironmentsCommand, + StartDeploymentCommand, + StopDeploymentCommand, +} from '@aws-sdk/client-appconfig' +import { + AppConfigDataClient, + GetLatestConfigurationCommand, + StartConfigurationSessionCommand, +} from '@aws-sdk/client-appconfigdata' +import type { AppConfigConnectionConfig } from '@/tools/appconfig/types' + +export function createAppConfigClient(config: AppConfigConnectionConfig): AppConfigClient { + return new AppConfigClient({ + region: config.region, + credentials: { + accessKeyId: config.accessKeyId, + secretAccessKey: config.secretAccessKey, + }, + }) +} + +export function createAppConfigDataClient(config: AppConfigConnectionConfig): AppConfigDataClient { + return new AppConfigDataClient({ + region: config.region, + credentials: { + accessKeyId: config.accessKeyId, + secretAccessKey: config.secretAccessKey, + }, + }) +} + +const textDecoder = new TextDecoder() + +function decodeContent(content?: Uint8Array): string { + if (!content || content.length === 0) return '' + return textDecoder.decode(content) +} + +export async function listApplications( + client: AppConfigClient, + maxResults?: number | null, + nextToken?: string | null +) { + const response = await client.send( + new ListApplicationsCommand({ + ...(maxResults ? { MaxResults: maxResults } : {}), + ...(nextToken ? { NextToken: nextToken } : {}), + }) + ) + + const applications = (response.Items ?? []).map((item) => ({ + id: item.Id ?? '', + name: item.Name ?? '', + description: item.Description ?? null, + })) + + return { + applications, + nextToken: response.NextToken ?? null, + count: applications.length, + } +} + +export async function createApplication( + client: AppConfigClient, + name: string, + description?: string | null +) { + const response = await client.send( + new CreateApplicationCommand({ + Name: name, + ...(description ? { Description: description } : {}), + }) + ) + + return { + message: `Application "${response.Name ?? name}" created`, + id: response.Id ?? '', + name: response.Name ?? '', + description: response.Description ?? null, + } +} + +export async function listEnvironments( + client: AppConfigClient, + applicationId: string, + maxResults?: number | null, + nextToken?: string | null +) { + const response = await client.send( + new ListEnvironmentsCommand({ + ApplicationId: applicationId, + ...(maxResults ? { MaxResults: maxResults } : {}), + ...(nextToken ? { NextToken: nextToken } : {}), + }) + ) + + const environments = (response.Items ?? []).map((item) => ({ + applicationId: item.ApplicationId ?? '', + id: item.Id ?? '', + name: item.Name ?? '', + description: item.Description ?? null, + state: item.State ?? null, + })) + + return { + environments, + nextToken: response.NextToken ?? null, + count: environments.length, + } +} + +export async function createEnvironment( + client: AppConfigClient, + applicationId: string, + name: string, + description?: string | null +) { + const response = await client.send( + new CreateEnvironmentCommand({ + ApplicationId: applicationId, + Name: name, + ...(description ? { Description: description } : {}), + }) + ) + + return { + message: `Environment "${response.Name ?? name}" created`, + applicationId: response.ApplicationId ?? applicationId, + id: response.Id ?? '', + name: response.Name ?? '', + state: response.State ?? null, + } +} + +export async function listConfigurationProfiles( + client: AppConfigClient, + applicationId: string, + maxResults?: number | null, + nextToken?: string | null +) { + const response = await client.send( + new ListConfigurationProfilesCommand({ + ApplicationId: applicationId, + ...(maxResults ? { MaxResults: maxResults } : {}), + ...(nextToken ? { NextToken: nextToken } : {}), + }) + ) + + const configurationProfiles = (response.Items ?? []).map((item) => ({ + applicationId: item.ApplicationId ?? '', + id: item.Id ?? '', + name: item.Name ?? '', + description: null, + locationUri: item.LocationUri ?? null, + retrievalRoleArn: null, + type: item.Type ?? null, + validatorTypes: item.ValidatorTypes ?? [], + })) + + return { + configurationProfiles, + nextToken: response.NextToken ?? null, + count: configurationProfiles.length, + } +} + +export async function createConfigurationProfile( + client: AppConfigClient, + applicationId: string, + name: string, + locationUri: string, + description?: string | null, + retrievalRoleArn?: string | null, + type?: string | null +) { + const response = await client.send( + new CreateConfigurationProfileCommand({ + ApplicationId: applicationId, + Name: name, + LocationUri: locationUri, + ...(description ? { Description: description } : {}), + ...(retrievalRoleArn ? { RetrievalRoleArn: retrievalRoleArn } : {}), + ...(type ? { Type: type } : {}), + }) + ) + + return { + message: `Configuration profile "${response.Name ?? name}" created`, + applicationId: response.ApplicationId ?? applicationId, + id: response.Id ?? '', + name: response.Name ?? '', + locationUri: response.LocationUri ?? null, + type: response.Type ?? null, + } +} + +export async function createHostedConfigurationVersion( + client: AppConfigClient, + applicationId: string, + configurationProfileId: string, + content: string, + contentType: string, + description?: string | null, + latestVersionNumber?: number | null, + versionLabel?: string | null +) { + const response = await client.send( + new CreateHostedConfigurationVersionCommand({ + ApplicationId: applicationId, + ConfigurationProfileId: configurationProfileId, + Content: new TextEncoder().encode(content), + ContentType: contentType, + ...(description ? { Description: description } : {}), + ...(latestVersionNumber ? { LatestVersionNumber: latestVersionNumber } : {}), + ...(versionLabel ? { VersionLabel: versionLabel } : {}), + }) + ) + + return { + message: `Hosted configuration version ${response.VersionNumber ?? ''} created`, + applicationId: response.ApplicationId ?? applicationId, + configurationProfileId: response.ConfigurationProfileId ?? configurationProfileId, + versionNumber: response.VersionNumber ?? null, + contentType: response.ContentType ?? null, + versionLabel: response.VersionLabel ?? null, + } +} + +export async function getHostedConfigurationVersion( + client: AppConfigClient, + applicationId: string, + configurationProfileId: string, + versionNumber: number +) { + const response = await client.send( + new GetHostedConfigurationVersionCommand({ + ApplicationId: applicationId, + ConfigurationProfileId: configurationProfileId, + VersionNumber: versionNumber, + }) + ) + + return { + applicationId: response.ApplicationId ?? applicationId, + configurationProfileId: response.ConfigurationProfileId ?? configurationProfileId, + versionNumber: response.VersionNumber ?? null, + description: response.Description ?? null, + content: decodeContent(response.Content), + contentType: response.ContentType ?? null, + versionLabel: response.VersionLabel ?? null, + } +} + +export async function listDeploymentStrategies( + client: AppConfigClient, + maxResults?: number | null, + nextToken?: string | null +) { + const response = await client.send( + new ListDeploymentStrategiesCommand({ + ...(maxResults ? { MaxResults: maxResults } : {}), + ...(nextToken ? { NextToken: nextToken } : {}), + }) + ) + + const deploymentStrategies = (response.Items ?? []).map((item) => ({ + id: item.Id ?? '', + name: item.Name ?? '', + description: item.Description ?? null, + deploymentDurationInMinutes: item.DeploymentDurationInMinutes ?? null, + growthType: item.GrowthType ?? null, + growthFactor: item.GrowthFactor ?? null, + finalBakeTimeInMinutes: item.FinalBakeTimeInMinutes ?? null, + replicateTo: item.ReplicateTo ?? null, + })) + + return { + deploymentStrategies, + nextToken: response.NextToken ?? null, + count: deploymentStrategies.length, + } +} + +export async function startDeployment( + client: AppConfigClient, + applicationId: string, + environmentId: string, + deploymentStrategyId: string, + configurationProfileId: string, + configurationVersion: string, + description?: string | null +) { + const response = await client.send( + new StartDeploymentCommand({ + ApplicationId: applicationId, + EnvironmentId: environmentId, + DeploymentStrategyId: deploymentStrategyId, + ConfigurationProfileId: configurationProfileId, + ConfigurationVersion: configurationVersion, + ...(description ? { Description: description } : {}), + }) + ) + + return { + message: `Deployment ${response.DeploymentNumber ?? ''} started`, + deploymentNumber: response.DeploymentNumber ?? null, + state: response.State ?? null, + percentageComplete: response.PercentageComplete ?? null, + } +} + +export async function getDeployment( + client: AppConfigClient, + applicationId: string, + environmentId: string, + deploymentNumber: number +) { + const response = await client.send( + new GetDeploymentCommand({ + ApplicationId: applicationId, + EnvironmentId: environmentId, + DeploymentNumber: deploymentNumber, + }) + ) + + return { + applicationId: response.ApplicationId ?? applicationId, + environmentId: response.EnvironmentId ?? environmentId, + deploymentStrategyId: response.DeploymentStrategyId ?? '', + configurationProfileId: response.ConfigurationProfileId ?? '', + deploymentNumber: response.DeploymentNumber ?? null, + configurationName: response.ConfigurationName ?? null, + configurationVersion: response.ConfigurationVersion ?? null, + description: response.Description ?? null, + state: response.State ?? null, + percentageComplete: response.PercentageComplete ?? null, + startedAt: response.StartedAt?.toISOString() ?? null, + completedAt: response.CompletedAt?.toISOString() ?? null, + } +} + +export async function listDeployments( + client: AppConfigClient, + applicationId: string, + environmentId: string, + maxResults?: number | null, + nextToken?: string | null +) { + const response = await client.send( + new ListDeploymentsCommand({ + ApplicationId: applicationId, + EnvironmentId: environmentId, + ...(maxResults ? { MaxResults: maxResults } : {}), + ...(nextToken ? { NextToken: nextToken } : {}), + }) + ) + + const deployments = (response.Items ?? []).map((item) => ({ + deploymentNumber: item.DeploymentNumber ?? null, + configurationName: item.ConfigurationName ?? null, + configurationVersion: item.ConfigurationVersion ?? null, + deploymentDurationInMinutes: item.DeploymentDurationInMinutes ?? null, + growthType: item.GrowthType ?? null, + growthFactor: item.GrowthFactor ?? null, + finalBakeTimeInMinutes: item.FinalBakeTimeInMinutes ?? null, + state: item.State ?? null, + percentageComplete: item.PercentageComplete ?? null, + startedAt: item.StartedAt?.toISOString() ?? null, + completedAt: item.CompletedAt?.toISOString() ?? null, + versionLabel: item.VersionLabel ?? null, + })) + + return { + deployments, + nextToken: response.NextToken ?? null, + count: deployments.length, + } +} + +export async function stopDeployment( + client: AppConfigClient, + applicationId: string, + environmentId: string, + deploymentNumber: number +) { + const response = await client.send( + new StopDeploymentCommand({ + ApplicationId: applicationId, + EnvironmentId: environmentId, + DeploymentNumber: deploymentNumber, + }) + ) + + return { + message: `Deployment ${response.DeploymentNumber ?? deploymentNumber} stopped`, + deploymentNumber: response.DeploymentNumber ?? null, + state: response.State ?? null, + } +} + +export async function getConfiguration( + client: AppConfigDataClient, + applicationId: string, + environmentId: string, + configurationProfileId: string +) { + const session = await client.send( + new StartConfigurationSessionCommand({ + ApplicationIdentifier: applicationId, + EnvironmentIdentifier: environmentId, + ConfigurationProfileIdentifier: configurationProfileId, + }) + ) + + const response = await client.send( + new GetLatestConfigurationCommand({ + ConfigurationToken: session.InitialConfigurationToken, + }) + ) + + return { + configuration: decodeContent(response.Configuration), + contentType: response.ContentType ?? null, + versionLabel: response.VersionLabel ?? null, + } +} diff --git a/apps/sim/blocks/blocks/appconfig.ts b/apps/sim/blocks/blocks/appconfig.ts new file mode 100644 index 00000000000..f3dc3fc0ca9 --- /dev/null +++ b/apps/sim/blocks/blocks/appconfig.ts @@ -0,0 +1,579 @@ +import { AppConfigIcon } from '@/components/icons' +import type { BlockConfig, BlockMeta } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' +import type { + AppConfigGetConfigurationResponse, + AppConfigListApplicationsResponse, +} from '@/tools/appconfig/types' + +export const AppConfigBlock: BlockConfig< + AppConfigListApplicationsResponse | AppConfigGetConfigurationResponse +> = { + type: 'appconfig', + name: 'AWS AppConfig', + description: 'Manage and retrieve configuration with AWS AppConfig', + longDescription: + 'Integrate AWS AppConfig into workflows. Manage applications, environments, and configuration profiles, create and read hosted configuration versions, run and inspect deployments, and retrieve the latest deployed configuration at runtime. Requires AWS access key and secret access key.', + docsLink: 'https://docs.sim.ai/tools/appconfig', + category: 'tools', + integrationType: IntegrationType.DevOps, + bgColor: 'linear-gradient(45deg, #B0084D 0%, #FF4F8B 100%)', + icon: AppConfigIcon, + authMode: AuthMode.ApiKey, + subBlocks: [ + { + id: 'operation', + title: 'Operation', + type: 'dropdown', + options: [ + { label: 'Get Configuration', id: 'get_configuration' }, + { label: 'List Applications', id: 'list_applications' }, + { label: 'Create Application', id: 'create_application' }, + { label: 'List Environments', id: 'list_environments' }, + { label: 'Create Environment', id: 'create_environment' }, + { label: 'List Configuration Profiles', id: 'list_configuration_profiles' }, + { label: 'Create Configuration Profile', id: 'create_configuration_profile' }, + { + label: 'Create Hosted Configuration Version', + id: 'create_hosted_configuration_version', + }, + { label: 'Get Hosted Configuration Version', id: 'get_hosted_configuration_version' }, + { label: 'List Deployment Strategies', id: 'list_deployment_strategies' }, + { label: 'Start Deployment', id: 'start_deployment' }, + { label: 'Get Deployment', id: 'get_deployment' }, + { label: 'List Deployments', id: 'list_deployments' }, + { label: 'Stop Deployment', id: 'stop_deployment' }, + ], + value: () => 'get_configuration', + }, + { + id: 'region', + title: 'AWS Region', + type: 'short-input', + placeholder: 'us-east-1', + required: true, + }, + { + id: 'accessKeyId', + title: 'AWS Access Key ID', + type: 'short-input', + placeholder: 'AKIA...', + password: true, + required: true, + }, + { + id: 'secretAccessKey', + title: 'AWS Secret Access Key', + type: 'short-input', + placeholder: 'Your secret access key', + password: true, + required: true, + }, + { + id: 'applicationId', + title: 'Application ID', + type: 'short-input', + placeholder: 'Application ID (or name for Get Configuration)', + condition: { + field: 'operation', + value: [ + 'list_environments', + 'create_environment', + 'list_configuration_profiles', + 'create_configuration_profile', + 'create_hosted_configuration_version', + 'get_hosted_configuration_version', + 'start_deployment', + 'get_deployment', + 'list_deployments', + 'stop_deployment', + 'get_configuration', + ], + }, + required: { + field: 'operation', + value: [ + 'list_environments', + 'create_environment', + 'list_configuration_profiles', + 'create_configuration_profile', + 'create_hosted_configuration_version', + 'get_hosted_configuration_version', + 'start_deployment', + 'get_deployment', + 'list_deployments', + 'stop_deployment', + 'get_configuration', + ], + }, + }, + { + id: 'environmentId', + title: 'Environment ID', + type: 'short-input', + placeholder: 'Environment ID (or name for Get Configuration)', + condition: { + field: 'operation', + value: [ + 'start_deployment', + 'get_deployment', + 'list_deployments', + 'stop_deployment', + 'get_configuration', + ], + }, + required: { + field: 'operation', + value: [ + 'start_deployment', + 'get_deployment', + 'list_deployments', + 'stop_deployment', + 'get_configuration', + ], + }, + }, + { + id: 'configurationProfileId', + title: 'Configuration Profile ID', + type: 'short-input', + placeholder: 'Configuration profile ID (or name for Get Configuration)', + condition: { + field: 'operation', + value: [ + 'create_hosted_configuration_version', + 'get_hosted_configuration_version', + 'start_deployment', + 'get_configuration', + ], + }, + required: { + field: 'operation', + value: [ + 'create_hosted_configuration_version', + 'get_hosted_configuration_version', + 'start_deployment', + 'get_configuration', + ], + }, + }, + { + id: 'name', + title: 'Name', + type: 'short-input', + placeholder: 'Resource name', + condition: { + field: 'operation', + value: ['create_application', 'create_environment', 'create_configuration_profile'], + }, + required: { + field: 'operation', + value: ['create_application', 'create_environment', 'create_configuration_profile'], + }, + }, + { + id: 'locationUri', + title: 'Location URI', + type: 'short-input', + placeholder: 'hosted', + condition: { field: 'operation', value: 'create_configuration_profile' }, + required: { field: 'operation', value: 'create_configuration_profile' }, + }, + { + id: 'type', + title: 'Profile Type', + type: 'dropdown', + options: [ + { label: 'Freeform (AWS.Freeform)', id: 'AWS.Freeform' }, + { label: 'Feature Flags (AWS.AppConfig.FeatureFlags)', id: 'AWS.AppConfig.FeatureFlags' }, + ], + value: () => 'AWS.Freeform', + condition: { field: 'operation', value: 'create_configuration_profile' }, + required: false, + mode: 'advanced', + }, + { + id: 'retrievalRoleArn', + title: 'Retrieval Role ARN', + type: 'short-input', + placeholder: 'arn:aws:iam::123456789012:role/AppConfigRetrieval', + condition: { field: 'operation', value: 'create_configuration_profile' }, + required: false, + mode: 'advanced', + }, + { + id: 'content', + title: 'Configuration Content', + type: 'code', + placeholder: '{"featureX": {"enabled": true}}', + condition: { field: 'operation', value: 'create_hosted_configuration_version' }, + required: { field: 'operation', value: 'create_hosted_configuration_version' }, + }, + { + id: 'contentType', + title: 'Content Type', + type: 'short-input', + placeholder: 'application/json', + condition: { field: 'operation', value: 'create_hosted_configuration_version' }, + required: { field: 'operation', value: 'create_hosted_configuration_version' }, + }, + { + id: 'latestVersionNumber', + title: 'Latest Version Number', + type: 'short-input', + placeholder: 'For optimistic concurrency', + condition: { field: 'operation', value: 'create_hosted_configuration_version' }, + required: false, + mode: 'advanced', + }, + { + id: 'versionLabel', + title: 'Version Label', + type: 'short-input', + placeholder: 'v1.0.0', + condition: { field: 'operation', value: 'create_hosted_configuration_version' }, + required: false, + mode: 'advanced', + }, + { + id: 'versionNumber', + title: 'Version Number', + type: 'short-input', + placeholder: '1', + condition: { field: 'operation', value: 'get_hosted_configuration_version' }, + required: { field: 'operation', value: 'get_hosted_configuration_version' }, + }, + { + id: 'deploymentStrategyId', + title: 'Deployment Strategy ID', + type: 'short-input', + placeholder: 'AppConfig.AllAtOnce', + condition: { field: 'operation', value: 'start_deployment' }, + required: { field: 'operation', value: 'start_deployment' }, + }, + { + id: 'configurationVersion', + title: 'Configuration Version', + type: 'short-input', + placeholder: '1', + condition: { field: 'operation', value: 'start_deployment' }, + required: { field: 'operation', value: 'start_deployment' }, + }, + { + id: 'deploymentNumber', + title: 'Deployment Number', + type: 'short-input', + placeholder: '1', + condition: { field: 'operation', value: ['get_deployment', 'stop_deployment'] }, + required: { field: 'operation', value: ['get_deployment', 'stop_deployment'] }, + }, + { + id: 'description', + title: 'Description', + type: 'short-input', + placeholder: 'Optional description', + condition: { + field: 'operation', + value: [ + 'create_application', + 'create_environment', + 'create_configuration_profile', + 'create_hosted_configuration_version', + 'start_deployment', + ], + }, + required: false, + mode: 'advanced', + }, + { + id: 'maxResults', + title: 'Max Results', + type: 'short-input', + placeholder: '50', + condition: { + field: 'operation', + value: [ + 'list_applications', + 'list_environments', + 'list_configuration_profiles', + 'list_deployment_strategies', + 'list_deployments', + ], + }, + required: false, + mode: 'advanced', + }, + { + id: 'nextToken', + title: 'Next Token', + type: 'short-input', + placeholder: 'Pagination token', + condition: { + field: 'operation', + value: [ + 'list_applications', + 'list_environments', + 'list_configuration_profiles', + 'list_deployment_strategies', + 'list_deployments', + ], + }, + required: false, + mode: 'advanced', + }, + ], + tools: { + access: [ + 'appconfig_get_configuration', + 'appconfig_list_applications', + 'appconfig_create_application', + 'appconfig_list_environments', + 'appconfig_create_environment', + 'appconfig_list_configuration_profiles', + 'appconfig_create_configuration_profile', + 'appconfig_create_hosted_configuration_version', + 'appconfig_get_hosted_configuration_version', + 'appconfig_list_deployment_strategies', + 'appconfig_start_deployment', + 'appconfig_get_deployment', + 'appconfig_list_deployments', + 'appconfig_stop_deployment', + ], + config: { + tool: (params) => { + switch (params.operation) { + case 'get_configuration': + return 'appconfig_get_configuration' + case 'list_applications': + return 'appconfig_list_applications' + case 'create_application': + return 'appconfig_create_application' + case 'list_environments': + return 'appconfig_list_environments' + case 'create_environment': + return 'appconfig_create_environment' + case 'list_configuration_profiles': + return 'appconfig_list_configuration_profiles' + case 'create_configuration_profile': + return 'appconfig_create_configuration_profile' + case 'create_hosted_configuration_version': + return 'appconfig_create_hosted_configuration_version' + case 'get_hosted_configuration_version': + return 'appconfig_get_hosted_configuration_version' + case 'list_deployment_strategies': + return 'appconfig_list_deployment_strategies' + case 'start_deployment': + return 'appconfig_start_deployment' + case 'get_deployment': + return 'appconfig_get_deployment' + case 'list_deployments': + return 'appconfig_list_deployments' + case 'stop_deployment': + return 'appconfig_stop_deployment' + default: + throw new Error(`Invalid AppConfig operation: ${params.operation}`) + } + }, + params: (params) => { + const { + operation, + maxResults, + versionNumber, + deploymentNumber, + latestVersionNumber, + ...rest + } = params + + const result: Record = { ...rest } + + const toInt = (value: unknown): number | undefined => { + if (value === undefined || value === null || value === '') return undefined + const parsed = Number.parseInt(String(value), 10) + return Number.isNaN(parsed) ? undefined : parsed + } + + const maxResultsInt = toInt(maxResults) + if (maxResultsInt !== undefined) result.maxResults = maxResultsInt + + const versionNumberInt = toInt(versionNumber) + if (versionNumberInt !== undefined) result.versionNumber = versionNumberInt + + const deploymentNumberInt = toInt(deploymentNumber) + if (deploymentNumberInt !== undefined) result.deploymentNumber = deploymentNumberInt + + const latestVersionNumberInt = toInt(latestVersionNumber) + if (latestVersionNumberInt !== undefined) + result.latestVersionNumber = latestVersionNumberInt + + return result + }, + }, + }, + inputs: { + operation: { type: 'string', description: 'AppConfig operation to perform' }, + region: { type: 'string', description: 'AWS region' }, + accessKeyId: { type: 'string', description: 'AWS access key ID' }, + secretAccessKey: { type: 'string', description: 'AWS secret access key' }, + applicationId: { type: 'string', description: 'Application ID or name' }, + environmentId: { type: 'string', description: 'Environment ID or name' }, + configurationProfileId: { type: 'string', description: 'Configuration profile ID or name' }, + name: { type: 'string', description: 'Name for a new resource' }, + locationUri: { type: 'string', description: 'Where the configuration is stored' }, + type: { type: 'string', description: 'Configuration profile type' }, + retrievalRoleArn: { type: 'string', description: 'IAM role ARN to retrieve configuration' }, + content: { type: 'string', description: 'Configuration content' }, + contentType: { type: 'string', description: 'Content type of the configuration' }, + latestVersionNumber: { type: 'number', description: 'Latest version number for concurrency' }, + versionLabel: { type: 'string', description: 'Label for the configuration version' }, + versionNumber: { type: 'number', description: 'Hosted configuration version number' }, + deploymentStrategyId: { type: 'string', description: 'Deployment strategy ID' }, + configurationVersion: { type: 'string', description: 'Configuration version to deploy' }, + deploymentNumber: { type: 'number', description: 'Deployment sequence number' }, + description: { type: 'string', description: 'Optional description' }, + maxResults: { type: 'number', description: 'Maximum number of results to return' }, + nextToken: { type: 'string', description: 'Pagination token' }, + }, + outputs: { + configuration: { type: 'string', description: 'The deployed configuration content' }, + contentType: { type: 'string', description: 'Content type of the configuration' }, + versionLabel: { type: 'string', description: 'Configuration version label' }, + message: { type: 'string', description: 'Operation status message' }, + id: { type: 'string', description: 'ID of the created or affected resource' }, + name: { type: 'string', description: 'Name of the resource' }, + description: { type: 'string', description: 'Description of the resource' }, + applicationId: { type: 'string', description: 'Application ID' }, + environmentId: { type: 'string', description: 'Environment ID' }, + configurationProfileId: { type: 'string', description: 'Configuration profile ID' }, + locationUri: { type: 'string', description: 'Location URI of the configuration' }, + type: { type: 'string', description: 'Configuration profile type' }, + state: { type: 'string', description: 'State of the resource or deployment' }, + deploymentStrategyId: { type: 'string', description: 'Deployment strategy ID' }, + deploymentNumber: { type: 'number', description: 'Deployment sequence number' }, + configurationName: { type: 'string', description: 'Configuration name' }, + configurationVersion: { type: 'string', description: 'Configuration version' }, + percentageComplete: { type: 'number', description: 'Deployment completion percentage' }, + startedAt: { type: 'string', description: 'When the deployment started' }, + completedAt: { type: 'string', description: 'When the deployment completed' }, + versionNumber: { type: 'number', description: 'Hosted configuration version number' }, + content: { type: 'string', description: 'Hosted configuration content' }, + applications: { type: 'json', description: 'List of applications' }, + environments: { type: 'json', description: 'List of environments' }, + configurationProfiles: { type: 'json', description: 'List of configuration profiles' }, + deploymentStrategies: { type: 'json', description: 'List of deployment strategies' }, + deployments: { type: 'json', description: 'List of deployments' }, + nextToken: { type: 'string', description: 'Pagination token for the next page' }, + count: { type: 'number', description: 'Number of items returned' }, + }, +} + +export const AppConfigBlockMeta = { + tags: ['cloud', 'configuration', 'feature-flags'], + templates: [ + { + icon: AppConfigIcon, + title: 'AppConfig runtime config loader', + prompt: + 'Build a workflow that retrieves the latest deployed AWS AppConfig configuration for a given application, environment, and profile, parses the JSON, and uses the feature flags to branch downstream agent behavior.', + modules: ['agent', 'workflows'], + category: 'engineering', + tags: ['devops', 'feature-flags', 'automation'], + }, + { + icon: AppConfigIcon, + title: 'AppConfig feature-flag publisher', + prompt: + 'Create a workflow that takes a JSON feature-flag document, creates a new hosted configuration version in an AWS AppConfig configuration profile, and starts a deployment to the target environment using a chosen deployment strategy.', + modules: ['agent', 'workflows'], + category: 'engineering', + tags: ['devops', 'feature-flags', 'automation'], + }, + { + icon: AppConfigIcon, + title: 'AppConfig deployment monitor', + prompt: + 'Build a scheduled workflow that lists in-progress AWS AppConfig deployments for an environment, gets each deployment status, and posts a Slack alert when a deployment is rolling back or has stalled.', + modules: ['scheduled', 'agent', 'workflows'], + category: 'engineering', + tags: ['devops', 'monitoring'], + alsoIntegrations: ['slack'], + }, + { + icon: AppConfigIcon, + title: 'AppConfig config inventory', + prompt: + 'Create a scheduled workflow that lists every AWS AppConfig application, its environments, and its configuration profiles, and writes a unified inventory into a tracking table so the platform team has a single source of truth.', + modules: ['scheduled', 'tables', 'agent', 'workflows'], + category: 'engineering', + tags: ['devops', 'enterprise', 'reporting'], + }, + { + icon: AppConfigIcon, + title: 'AppConfig change auditor', + prompt: + 'Build a scheduled workflow that lists recent AWS AppConfig deployments across environments, summarizes which configuration versions were deployed when, and writes an audit report file for compliance review.', + modules: ['scheduled', 'agent', 'files', 'workflows'], + category: 'engineering', + tags: ['devops', 'reporting', 'enterprise'], + }, + { + icon: AppConfigIcon, + title: 'AppConfig drift checker', + prompt: + 'Create a scheduled workflow that retrieves the live AWS AppConfig configuration and compares it against an expected baseline stored in a table, alerting Slack when the deployed configuration drifts from the approved version.', + modules: ['scheduled', 'tables', 'agent', 'workflows'], + category: 'engineering', + tags: ['devops', 'monitoring', 'automation'], + alsoIntegrations: ['slack'], + }, + { + icon: AppConfigIcon, + title: 'AppConfig bootstrap from GitHub', + prompt: + 'Build a workflow triggered when a config file changes in a GitHub pull request that creates a new hosted AWS AppConfig configuration version from the file contents and deploys it to a staging environment for validation.', + modules: ['agent', 'workflows'], + category: 'engineering', + tags: ['devops', 'automation', 'engineering'], + alsoIntegrations: ['github'], + }, + { + icon: AppConfigIcon, + title: 'AppConfig gated rollout', + prompt: + 'Create a workflow that gates an AWS AppConfig deployment behind a Slack approval: it creates the configuration version, waits for sign-off, starts the deployment with a linear strategy, and monitors completion before reporting back.', + modules: ['agent', 'workflows'], + category: 'operations', + tags: ['devops', 'enterprise', 'automation'], + alsoIntegrations: ['slack'], + }, + ], + skills: [ + { + name: 'read-feature-flags', + description: + 'Retrieve the latest deployed AWS AppConfig configuration for an application, environment, and profile and use the values to drive feature flags or dynamic settings.', + content: + '# Read AppConfig Feature Flags\n\nLoad live configuration to branch workflow behavior.\n\n## Steps\n1. Identify the target application, environment, and configuration profile (IDs or names).\n2. Get the latest deployed configuration for that combination.\n3. Parse the returned content (usually JSON) into a structured object.\n4. Use the flag or setting values to decide which downstream path to take.\n\n## Output\nThe resolved configuration values and the decision they drive. Do not hardcode flag values — always read them fresh from AppConfig.', + }, + { + name: 'publish-and-deploy-config', + description: + 'Create a new hosted AWS AppConfig configuration version from a document and deploy it to an environment with a chosen deployment strategy.', + content: + '# Publish and Deploy Config\n\nShip a new configuration version safely.\n\n## Steps\n1. Assemble the configuration content (JSON, YAML, or text) and confirm the target application and configuration profile.\n2. Create a new hosted configuration version with the correct content type.\n3. Start a deployment of that version to the target environment using an appropriate deployment strategy.\n4. Record the returned deployment number for follow-up monitoring.\n\n## Output\nThe new version number and the started deployment number, plus the deployment state.', + }, + { + name: 'monitor-deployment-rollback', + description: + 'Watch in-progress AWS AppConfig deployments for an environment and surface rollbacks or stalled rollouts so they can be acted on.', + content: + '# Monitor Deployment Rollback\n\nKeep an eye on configuration rollouts.\n\n## Steps\n1. List deployments for the target environment and find in-progress ones.\n2. Get the status of each active deployment, capturing state and percentage complete.\n3. Flag deployments that are rolling back or have stopped making progress.\n4. Optionally stop a deployment that needs to be halted.\n\n## Output\nA per-deployment status summary with any rollbacks or stalls called out for action.', + }, + { + name: 'inventory-appconfig', + description: + 'List AWS AppConfig applications, environments, and configuration profiles to build a single inventory of what configuration exists across the account.', + content: + '# Inventory AppConfig\n\nBuild a unified view of all AppConfig resources.\n\n## Steps\n1. List every application and capture its ID, name, and description.\n2. For each application, list its environments and configuration profiles.\n3. Note the profile type (freeform vs feature flags) and where each profile is stored.\n4. Assemble the results into a single structured inventory.\n\n## Output\nAn inventory of applications with their environments and configuration profiles, suitable for writing to a tracking table.', + }, + ], +} as const satisfies BlockMeta diff --git a/apps/sim/blocks/registry.ts b/apps/sim/blocks/registry.ts index f9ba05533b9..4d0d5bf1443 100644 --- a/apps/sim/blocks/registry.ts +++ b/apps/sim/blocks/registry.ts @@ -13,6 +13,7 @@ import { ApiBlock } from '@/blocks/blocks/api' import { ApiTriggerBlock } from '@/blocks/blocks/api_trigger' import { ApifyBlock, ApifyBlockMeta } from '@/blocks/blocks/apify' import { ApolloBlock, ApolloBlockMeta } from '@/blocks/blocks/apollo' +import { AppConfigBlock, AppConfigBlockMeta } from '@/blocks/blocks/appconfig' import { ArxivBlock, ArxivBlockMeta } from '@/blocks/blocks/arxiv' import { AsanaBlock, AsanaBlockMeta } from '@/blocks/blocks/asana' import { AshbyBlock, AshbyBlockMeta } from '@/blocks/blocks/ashby' @@ -328,6 +329,7 @@ const BLOCK_REGISTRY: Record = { api: ApiBlock, api_trigger: ApiTriggerBlock, apify: ApifyBlock, + appconfig: AppConfigBlock, apollo: ApolloBlock, arxiv: ArxivBlock, asana: AsanaBlock, @@ -615,6 +617,7 @@ const BLOCK_META_REGISTRY: Record = { algolia: AlgoliaBlockMeta, amplitude: AmplitudeBlockMeta, apify: ApifyBlockMeta, + appconfig: AppConfigBlockMeta, apollo: ApolloBlockMeta, arxiv: ArxivBlockMeta, asana: AsanaBlockMeta, diff --git a/apps/sim/components/icons.tsx b/apps/sim/components/icons.tsx index 12aeb36697b..5e18d3adc93 100644 --- a/apps/sim/components/icons.tsx +++ b/apps/sim/components/icons.tsx @@ -4672,6 +4672,25 @@ export function ServiceNowIcon(props: SVGProps) { ) } +export function AppConfigIcon(props: SVGProps) { + const id = useId() + return ( + + + + + + + + + + + ) +} + export function ApolloIcon(props: SVGProps) { return ( +export type AwsAppConfigCreateApplicationBody = ContractBody< + typeof awsAppConfigCreateApplicationContract +> +export type AwsAppConfigCreateApplicationResponse = ContractJsonResponse< + typeof awsAppConfigCreateApplicationContract +> diff --git a/apps/sim/lib/api/contracts/tools/aws/appconfig-create-configuration-profile.ts b/apps/sim/lib/api/contracts/tools/aws/appconfig-create-configuration-profile.ts new file mode 100644 index 00000000000..19d4e86e43b --- /dev/null +++ b/apps/sim/lib/api/contracts/tools/aws/appconfig-create-configuration-profile.ts @@ -0,0 +1,44 @@ +import { z } from 'zod' +import type { + ContractBody, + ContractBodyInput, + ContractJsonResponse, +} from '@/lib/api/contracts/types' +import { defineRouteContract } from '@/lib/api/contracts/types' + +const CreateConfigurationProfileSchema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + applicationId: z.string().min(1, 'Application ID is required'), + name: z.string().min(1, 'Configuration profile name is required').max(128), + locationUri: z.string().min(1, 'Location URI is required').max(2048), + description: z.string().max(1024).nullish(), + retrievalRoleArn: z.string().nullish(), + type: z.string().nullish(), +}) + +const CreateConfigurationProfileResponseSchema = z.object({ + message: z.string(), + applicationId: z.string(), + id: z.string(), + name: z.string(), + locationUri: z.string().nullable(), + type: z.string().nullable(), +}) + +export const awsAppConfigCreateConfigurationProfileContract = defineRouteContract({ + method: 'POST', + path: '/api/tools/appconfig/create-configuration-profile', + body: CreateConfigurationProfileSchema, + response: { mode: 'json', schema: CreateConfigurationProfileResponseSchema }, +}) +export type AwsAppConfigCreateConfigurationProfileRequest = ContractBodyInput< + typeof awsAppConfigCreateConfigurationProfileContract +> +export type AwsAppConfigCreateConfigurationProfileBody = ContractBody< + typeof awsAppConfigCreateConfigurationProfileContract +> +export type AwsAppConfigCreateConfigurationProfileResponse = ContractJsonResponse< + typeof awsAppConfigCreateConfigurationProfileContract +> diff --git a/apps/sim/lib/api/contracts/tools/aws/appconfig-create-environment.ts b/apps/sim/lib/api/contracts/tools/aws/appconfig-create-environment.ts new file mode 100644 index 00000000000..c8208422d0e --- /dev/null +++ b/apps/sim/lib/api/contracts/tools/aws/appconfig-create-environment.ts @@ -0,0 +1,40 @@ +import { z } from 'zod' +import type { + ContractBody, + ContractBodyInput, + ContractJsonResponse, +} from '@/lib/api/contracts/types' +import { defineRouteContract } from '@/lib/api/contracts/types' + +const CreateEnvironmentSchema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + applicationId: z.string().min(1, 'Application ID is required'), + name: z.string().min(1, 'Environment name is required').max(64), + description: z.string().max(1024).nullish(), +}) + +const CreateEnvironmentResponseSchema = z.object({ + message: z.string(), + applicationId: z.string(), + id: z.string(), + name: z.string(), + state: z.string().nullable(), +}) + +export const awsAppConfigCreateEnvironmentContract = defineRouteContract({ + method: 'POST', + path: '/api/tools/appconfig/create-environment', + body: CreateEnvironmentSchema, + response: { mode: 'json', schema: CreateEnvironmentResponseSchema }, +}) +export type AwsAppConfigCreateEnvironmentRequest = ContractBodyInput< + typeof awsAppConfigCreateEnvironmentContract +> +export type AwsAppConfigCreateEnvironmentBody = ContractBody< + typeof awsAppConfigCreateEnvironmentContract +> +export type AwsAppConfigCreateEnvironmentResponse = ContractJsonResponse< + typeof awsAppConfigCreateEnvironmentContract +> diff --git a/apps/sim/lib/api/contracts/tools/aws/appconfig-create-hosted-configuration-version.ts b/apps/sim/lib/api/contracts/tools/aws/appconfig-create-hosted-configuration-version.ts new file mode 100644 index 00000000000..636803d6651 --- /dev/null +++ b/apps/sim/lib/api/contracts/tools/aws/appconfig-create-hosted-configuration-version.ts @@ -0,0 +1,45 @@ +import { z } from 'zod' +import type { + ContractBody, + ContractBodyInput, + ContractJsonResponse, +} from '@/lib/api/contracts/types' +import { defineRouteContract } from '@/lib/api/contracts/types' + +const CreateHostedConfigurationVersionSchema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + applicationId: z.string().min(1, 'Application ID is required'), + configurationProfileId: z.string().min(1, 'Configuration profile ID is required'), + content: z.string().min(1, 'Content is required'), + contentType: z.string().min(1, 'Content type is required').max(255), + description: z.string().max(1024).nullish(), + latestVersionNumber: z.number().int().min(0).nullish(), + versionLabel: z.string().max(64).nullish(), +}) + +const CreateHostedConfigurationVersionResponseSchema = z.object({ + message: z.string(), + applicationId: z.string(), + configurationProfileId: z.string(), + versionNumber: z.number().nullable(), + contentType: z.string().nullable(), + versionLabel: z.string().nullable(), +}) + +export const awsAppConfigCreateHostedConfigurationVersionContract = defineRouteContract({ + method: 'POST', + path: '/api/tools/appconfig/create-hosted-configuration-version', + body: CreateHostedConfigurationVersionSchema, + response: { mode: 'json', schema: CreateHostedConfigurationVersionResponseSchema }, +}) +export type AwsAppConfigCreateHostedConfigurationVersionRequest = ContractBodyInput< + typeof awsAppConfigCreateHostedConfigurationVersionContract +> +export type AwsAppConfigCreateHostedConfigurationVersionBody = ContractBody< + typeof awsAppConfigCreateHostedConfigurationVersionContract +> +export type AwsAppConfigCreateHostedConfigurationVersionResponse = ContractJsonResponse< + typeof awsAppConfigCreateHostedConfigurationVersionContract +> diff --git a/apps/sim/lib/api/contracts/tools/aws/appconfig-get-configuration.ts b/apps/sim/lib/api/contracts/tools/aws/appconfig-get-configuration.ts new file mode 100644 index 00000000000..f8caadd3922 --- /dev/null +++ b/apps/sim/lib/api/contracts/tools/aws/appconfig-get-configuration.ts @@ -0,0 +1,38 @@ +import { z } from 'zod' +import type { + ContractBody, + ContractBodyInput, + ContractJsonResponse, +} from '@/lib/api/contracts/types' +import { defineRouteContract } from '@/lib/api/contracts/types' + +const GetConfigurationSchema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + applicationId: z.string().min(1, 'Application ID or name is required'), + environmentId: z.string().min(1, 'Environment ID or name is required'), + configurationProfileId: z.string().min(1, 'Configuration profile ID or name is required'), +}) + +const GetConfigurationResponseSchema = z.object({ + configuration: z.string(), + contentType: z.string().nullable(), + versionLabel: z.string().nullable(), +}) + +export const awsAppConfigGetConfigurationContract = defineRouteContract({ + method: 'POST', + path: '/api/tools/appconfig/get-configuration', + body: GetConfigurationSchema, + response: { mode: 'json', schema: GetConfigurationResponseSchema }, +}) +export type AwsAppConfigGetConfigurationRequest = ContractBodyInput< + typeof awsAppConfigGetConfigurationContract +> +export type AwsAppConfigGetConfigurationBody = ContractBody< + typeof awsAppConfigGetConfigurationContract +> +export type AwsAppConfigGetConfigurationResponse = ContractJsonResponse< + typeof awsAppConfigGetConfigurationContract +> diff --git a/apps/sim/lib/api/contracts/tools/aws/appconfig-get-deployment.ts b/apps/sim/lib/api/contracts/tools/aws/appconfig-get-deployment.ts new file mode 100644 index 00000000000..282a5dabf3a --- /dev/null +++ b/apps/sim/lib/api/contracts/tools/aws/appconfig-get-deployment.ts @@ -0,0 +1,45 @@ +import { z } from 'zod' +import type { + ContractBody, + ContractBodyInput, + ContractJsonResponse, +} from '@/lib/api/contracts/types' +import { defineRouteContract } from '@/lib/api/contracts/types' + +const GetDeploymentSchema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + applicationId: z.string().min(1, 'Application ID is required'), + environmentId: z.string().min(1, 'Environment ID is required'), + deploymentNumber: z.number().int().min(1, 'Deployment number is required'), +}) + +const GetDeploymentResponseSchema = z.object({ + applicationId: z.string(), + environmentId: z.string(), + deploymentStrategyId: z.string(), + configurationProfileId: z.string(), + deploymentNumber: z.number().nullable(), + configurationName: z.string().nullable(), + configurationVersion: z.string().nullable(), + description: z.string().nullable(), + state: z.string().nullable(), + percentageComplete: z.number().nullable(), + startedAt: z.string().nullable(), + completedAt: z.string().nullable(), +}) + +export const awsAppConfigGetDeploymentContract = defineRouteContract({ + method: 'POST', + path: '/api/tools/appconfig/get-deployment', + body: GetDeploymentSchema, + response: { mode: 'json', schema: GetDeploymentResponseSchema }, +}) +export type AwsAppConfigGetDeploymentRequest = ContractBodyInput< + typeof awsAppConfigGetDeploymentContract +> +export type AwsAppConfigGetDeploymentBody = ContractBody +export type AwsAppConfigGetDeploymentResponse = ContractJsonResponse< + typeof awsAppConfigGetDeploymentContract +> diff --git a/apps/sim/lib/api/contracts/tools/aws/appconfig-get-hosted-configuration-version.ts b/apps/sim/lib/api/contracts/tools/aws/appconfig-get-hosted-configuration-version.ts new file mode 100644 index 00000000000..1cd80b4fc89 --- /dev/null +++ b/apps/sim/lib/api/contracts/tools/aws/appconfig-get-hosted-configuration-version.ts @@ -0,0 +1,42 @@ +import { z } from 'zod' +import type { + ContractBody, + ContractBodyInput, + ContractJsonResponse, +} from '@/lib/api/contracts/types' +import { defineRouteContract } from '@/lib/api/contracts/types' + +const GetHostedConfigurationVersionSchema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + applicationId: z.string().min(1, 'Application ID is required'), + configurationProfileId: z.string().min(1, 'Configuration profile ID is required'), + versionNumber: z.number().int().min(1, 'Version number is required'), +}) + +const GetHostedConfigurationVersionResponseSchema = z.object({ + applicationId: z.string(), + configurationProfileId: z.string(), + versionNumber: z.number().nullable(), + description: z.string().nullable(), + content: z.string(), + contentType: z.string().nullable(), + versionLabel: z.string().nullable(), +}) + +export const awsAppConfigGetHostedConfigurationVersionContract = defineRouteContract({ + method: 'POST', + path: '/api/tools/appconfig/get-hosted-configuration-version', + body: GetHostedConfigurationVersionSchema, + response: { mode: 'json', schema: GetHostedConfigurationVersionResponseSchema }, +}) +export type AwsAppConfigGetHostedConfigurationVersionRequest = ContractBodyInput< + typeof awsAppConfigGetHostedConfigurationVersionContract +> +export type AwsAppConfigGetHostedConfigurationVersionBody = ContractBody< + typeof awsAppConfigGetHostedConfigurationVersionContract +> +export type AwsAppConfigGetHostedConfigurationVersionResponse = ContractJsonResponse< + typeof awsAppConfigGetHostedConfigurationVersionContract +> diff --git a/apps/sim/lib/api/contracts/tools/aws/appconfig-list-applications.ts b/apps/sim/lib/api/contracts/tools/aws/appconfig-list-applications.ts new file mode 100644 index 00000000000..e56e68696f5 --- /dev/null +++ b/apps/sim/lib/api/contracts/tools/aws/appconfig-list-applications.ts @@ -0,0 +1,43 @@ +import { z } from 'zod' +import type { + ContractBody, + ContractBodyInput, + ContractJsonResponse, +} from '@/lib/api/contracts/types' +import { defineRouteContract } from '@/lib/api/contracts/types' + +const ListApplicationsSchema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + maxResults: z.number().int().min(1).max(50).nullish(), + nextToken: z.string().nullish(), +}) + +const ApplicationSchema = z.object({ + id: z.string(), + name: z.string(), + description: z.string().nullable(), +}) + +const ListApplicationsResponseSchema = z.object({ + applications: z.array(ApplicationSchema), + nextToken: z.string().nullable(), + count: z.number(), +}) + +export const awsAppConfigListApplicationsContract = defineRouteContract({ + method: 'POST', + path: '/api/tools/appconfig/list-applications', + body: ListApplicationsSchema, + response: { mode: 'json', schema: ListApplicationsResponseSchema }, +}) +export type AwsAppConfigListApplicationsRequest = ContractBodyInput< + typeof awsAppConfigListApplicationsContract +> +export type AwsAppConfigListApplicationsBody = ContractBody< + typeof awsAppConfigListApplicationsContract +> +export type AwsAppConfigListApplicationsResponse = ContractJsonResponse< + typeof awsAppConfigListApplicationsContract +> diff --git a/apps/sim/lib/api/contracts/tools/aws/appconfig-list-configuration-profiles.ts b/apps/sim/lib/api/contracts/tools/aws/appconfig-list-configuration-profiles.ts new file mode 100644 index 00000000000..e2a22943a14 --- /dev/null +++ b/apps/sim/lib/api/contracts/tools/aws/appconfig-list-configuration-profiles.ts @@ -0,0 +1,49 @@ +import { z } from 'zod' +import type { + ContractBody, + ContractBodyInput, + ContractJsonResponse, +} from '@/lib/api/contracts/types' +import { defineRouteContract } from '@/lib/api/contracts/types' + +const ListConfigurationProfilesSchema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + applicationId: z.string().min(1, 'Application ID is required'), + maxResults: z.number().int().min(1).max(50).nullish(), + nextToken: z.string().nullish(), +}) + +const ConfigurationProfileSchema = z.object({ + applicationId: z.string(), + id: z.string(), + name: z.string(), + description: z.string().nullable(), + locationUri: z.string().nullable(), + retrievalRoleArn: z.string().nullable(), + type: z.string().nullable(), + validatorTypes: z.array(z.string()), +}) + +const ListConfigurationProfilesResponseSchema = z.object({ + configurationProfiles: z.array(ConfigurationProfileSchema), + nextToken: z.string().nullable(), + count: z.number(), +}) + +export const awsAppConfigListConfigurationProfilesContract = defineRouteContract({ + method: 'POST', + path: '/api/tools/appconfig/list-configuration-profiles', + body: ListConfigurationProfilesSchema, + response: { mode: 'json', schema: ListConfigurationProfilesResponseSchema }, +}) +export type AwsAppConfigListConfigurationProfilesRequest = ContractBodyInput< + typeof awsAppConfigListConfigurationProfilesContract +> +export type AwsAppConfigListConfigurationProfilesBody = ContractBody< + typeof awsAppConfigListConfigurationProfilesContract +> +export type AwsAppConfigListConfigurationProfilesResponse = ContractJsonResponse< + typeof awsAppConfigListConfigurationProfilesContract +> diff --git a/apps/sim/lib/api/contracts/tools/aws/appconfig-list-deployment-strategies.ts b/apps/sim/lib/api/contracts/tools/aws/appconfig-list-deployment-strategies.ts new file mode 100644 index 00000000000..cace62a1c4a --- /dev/null +++ b/apps/sim/lib/api/contracts/tools/aws/appconfig-list-deployment-strategies.ts @@ -0,0 +1,48 @@ +import { z } from 'zod' +import type { + ContractBody, + ContractBodyInput, + ContractJsonResponse, +} from '@/lib/api/contracts/types' +import { defineRouteContract } from '@/lib/api/contracts/types' + +const ListDeploymentStrategiesSchema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + maxResults: z.number().int().min(1).max(50).nullish(), + nextToken: z.string().nullish(), +}) + +const DeploymentStrategySchema = z.object({ + id: z.string(), + name: z.string(), + description: z.string().nullable(), + deploymentDurationInMinutes: z.number().nullable(), + growthType: z.string().nullable(), + growthFactor: z.number().nullable(), + finalBakeTimeInMinutes: z.number().nullable(), + replicateTo: z.string().nullable(), +}) + +const ListDeploymentStrategiesResponseSchema = z.object({ + deploymentStrategies: z.array(DeploymentStrategySchema), + nextToken: z.string().nullable(), + count: z.number(), +}) + +export const awsAppConfigListDeploymentStrategiesContract = defineRouteContract({ + method: 'POST', + path: '/api/tools/appconfig/list-deployment-strategies', + body: ListDeploymentStrategiesSchema, + response: { mode: 'json', schema: ListDeploymentStrategiesResponseSchema }, +}) +export type AwsAppConfigListDeploymentStrategiesRequest = ContractBodyInput< + typeof awsAppConfigListDeploymentStrategiesContract +> +export type AwsAppConfigListDeploymentStrategiesBody = ContractBody< + typeof awsAppConfigListDeploymentStrategiesContract +> +export type AwsAppConfigListDeploymentStrategiesResponse = ContractJsonResponse< + typeof awsAppConfigListDeploymentStrategiesContract +> diff --git a/apps/sim/lib/api/contracts/tools/aws/appconfig-list-deployments.ts b/apps/sim/lib/api/contracts/tools/aws/appconfig-list-deployments.ts new file mode 100644 index 00000000000..9ab6b102850 --- /dev/null +++ b/apps/sim/lib/api/contracts/tools/aws/appconfig-list-deployments.ts @@ -0,0 +1,54 @@ +import { z } from 'zod' +import type { + ContractBody, + ContractBodyInput, + ContractJsonResponse, +} from '@/lib/api/contracts/types' +import { defineRouteContract } from '@/lib/api/contracts/types' + +const ListDeploymentsSchema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + applicationId: z.string().min(1, 'Application ID is required'), + environmentId: z.string().min(1, 'Environment ID is required'), + maxResults: z.number().int().min(1).max(50).nullish(), + nextToken: z.string().nullish(), +}) + +const DeploymentSummarySchema = z.object({ + deploymentNumber: z.number().nullable(), + configurationName: z.string().nullable(), + configurationVersion: z.string().nullable(), + deploymentDurationInMinutes: z.number().nullable(), + growthType: z.string().nullable(), + growthFactor: z.number().nullable(), + finalBakeTimeInMinutes: z.number().nullable(), + state: z.string().nullable(), + percentageComplete: z.number().nullable(), + startedAt: z.string().nullable(), + completedAt: z.string().nullable(), + versionLabel: z.string().nullable(), +}) + +const ListDeploymentsResponseSchema = z.object({ + deployments: z.array(DeploymentSummarySchema), + nextToken: z.string().nullable(), + count: z.number(), +}) + +export const awsAppConfigListDeploymentsContract = defineRouteContract({ + method: 'POST', + path: '/api/tools/appconfig/list-deployments', + body: ListDeploymentsSchema, + response: { mode: 'json', schema: ListDeploymentsResponseSchema }, +}) +export type AwsAppConfigListDeploymentsRequest = ContractBodyInput< + typeof awsAppConfigListDeploymentsContract +> +export type AwsAppConfigListDeploymentsBody = ContractBody< + typeof awsAppConfigListDeploymentsContract +> +export type AwsAppConfigListDeploymentsResponse = ContractJsonResponse< + typeof awsAppConfigListDeploymentsContract +> diff --git a/apps/sim/lib/api/contracts/tools/aws/appconfig-list-environments.ts b/apps/sim/lib/api/contracts/tools/aws/appconfig-list-environments.ts new file mode 100644 index 00000000000..f385c78fe1f --- /dev/null +++ b/apps/sim/lib/api/contracts/tools/aws/appconfig-list-environments.ts @@ -0,0 +1,46 @@ +import { z } from 'zod' +import type { + ContractBody, + ContractBodyInput, + ContractJsonResponse, +} from '@/lib/api/contracts/types' +import { defineRouteContract } from '@/lib/api/contracts/types' + +const ListEnvironmentsSchema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + applicationId: z.string().min(1, 'Application ID is required'), + maxResults: z.number().int().min(1).max(50).nullish(), + nextToken: z.string().nullish(), +}) + +const EnvironmentSchema = z.object({ + applicationId: z.string(), + id: z.string(), + name: z.string(), + description: z.string().nullable(), + state: z.string().nullable(), +}) + +const ListEnvironmentsResponseSchema = z.object({ + environments: z.array(EnvironmentSchema), + nextToken: z.string().nullable(), + count: z.number(), +}) + +export const awsAppConfigListEnvironmentsContract = defineRouteContract({ + method: 'POST', + path: '/api/tools/appconfig/list-environments', + body: ListEnvironmentsSchema, + response: { mode: 'json', schema: ListEnvironmentsResponseSchema }, +}) +export type AwsAppConfigListEnvironmentsRequest = ContractBodyInput< + typeof awsAppConfigListEnvironmentsContract +> +export type AwsAppConfigListEnvironmentsBody = ContractBody< + typeof awsAppConfigListEnvironmentsContract +> +export type AwsAppConfigListEnvironmentsResponse = ContractJsonResponse< + typeof awsAppConfigListEnvironmentsContract +> diff --git a/apps/sim/lib/api/contracts/tools/aws/appconfig-start-deployment.ts b/apps/sim/lib/api/contracts/tools/aws/appconfig-start-deployment.ts new file mode 100644 index 00000000000..9e0e7ec4802 --- /dev/null +++ b/apps/sim/lib/api/contracts/tools/aws/appconfig-start-deployment.ts @@ -0,0 +1,42 @@ +import { z } from 'zod' +import type { + ContractBody, + ContractBodyInput, + ContractJsonResponse, +} from '@/lib/api/contracts/types' +import { defineRouteContract } from '@/lib/api/contracts/types' + +const StartDeploymentSchema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + applicationId: z.string().min(1, 'Application ID is required'), + environmentId: z.string().min(1, 'Environment ID is required'), + deploymentStrategyId: z.string().min(1, 'Deployment strategy ID is required'), + configurationProfileId: z.string().min(1, 'Configuration profile ID is required'), + configurationVersion: z.string().min(1, 'Configuration version is required'), + description: z.string().max(1024).nullish(), +}) + +const StartDeploymentResponseSchema = z.object({ + message: z.string(), + deploymentNumber: z.number().nullable(), + state: z.string().nullable(), + percentageComplete: z.number().nullable(), +}) + +export const awsAppConfigStartDeploymentContract = defineRouteContract({ + method: 'POST', + path: '/api/tools/appconfig/start-deployment', + body: StartDeploymentSchema, + response: { mode: 'json', schema: StartDeploymentResponseSchema }, +}) +export type AwsAppConfigStartDeploymentRequest = ContractBodyInput< + typeof awsAppConfigStartDeploymentContract +> +export type AwsAppConfigStartDeploymentBody = ContractBody< + typeof awsAppConfigStartDeploymentContract +> +export type AwsAppConfigStartDeploymentResponse = ContractJsonResponse< + typeof awsAppConfigStartDeploymentContract +> diff --git a/apps/sim/lib/api/contracts/tools/aws/appconfig-stop-deployment.ts b/apps/sim/lib/api/contracts/tools/aws/appconfig-stop-deployment.ts new file mode 100644 index 00000000000..7bdf735891c --- /dev/null +++ b/apps/sim/lib/api/contracts/tools/aws/appconfig-stop-deployment.ts @@ -0,0 +1,36 @@ +import { z } from 'zod' +import type { + ContractBody, + ContractBodyInput, + ContractJsonResponse, +} from '@/lib/api/contracts/types' +import { defineRouteContract } from '@/lib/api/contracts/types' + +const StopDeploymentSchema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + applicationId: z.string().min(1, 'Application ID is required'), + environmentId: z.string().min(1, 'Environment ID is required'), + deploymentNumber: z.number().int().min(1, 'Deployment number is required'), +}) + +const StopDeploymentResponseSchema = z.object({ + message: z.string(), + deploymentNumber: z.number().nullable(), + state: z.string().nullable(), +}) + +export const awsAppConfigStopDeploymentContract = defineRouteContract({ + method: 'POST', + path: '/api/tools/appconfig/stop-deployment', + body: StopDeploymentSchema, + response: { mode: 'json', schema: StopDeploymentResponseSchema }, +}) +export type AwsAppConfigStopDeploymentRequest = ContractBodyInput< + typeof awsAppConfigStopDeploymentContract +> +export type AwsAppConfigStopDeploymentBody = ContractBody +export type AwsAppConfigStopDeploymentResponse = ContractJsonResponse< + typeof awsAppConfigStopDeploymentContract +> diff --git a/apps/sim/lib/integrations/icon-mapping.ts b/apps/sim/lib/integrations/icon-mapping.ts index c4163e094b9..a0a17f222c3 100644 --- a/apps/sim/lib/integrations/icon-mapping.ts +++ b/apps/sim/lib/integrations/icon-mapping.ts @@ -14,6 +14,7 @@ import { AmplitudeIcon, ApifyIcon, ApolloIcon, + AppConfigIcon, ArxivIcon, AsanaIcon, AshbyIcon, @@ -220,6 +221,7 @@ export const blockTypeToIconMap: Record = { amplitude: AmplitudeIcon, apify: ApifyIcon, apollo: ApolloIcon, + appconfig: AppConfigIcon, arxiv: ArxivIcon, asana: AsanaIcon, ashby: AshbyIcon, diff --git a/apps/sim/lib/integrations/integrations.json b/apps/sim/lib/integrations/integrations.json index 313c8091f15..c0b36749225 100644 --- a/apps/sim/lib/integrations/integrations.json +++ b/apps/sim/lib/integrations/integrations.json @@ -1455,6 +1455,81 @@ "integrationType": "sales", "tags": ["sales-engagement", "enrichment"] }, + { + "type": "appconfig", + "slug": "aws-appconfig", + "name": "AWS AppConfig", + "description": "Manage and retrieve configuration with AWS AppConfig", + "longDescription": "Integrate AWS AppConfig into workflows. Manage applications, environments, and configuration profiles, create and read hosted configuration versions, run and inspect deployments, and retrieve the latest deployed configuration at runtime. Requires AWS access key and secret access key.", + "bgColor": "linear-gradient(45deg, #B0084D 0%, #FF4F8B 100%)", + "iconName": "AppConfigIcon", + "docsUrl": "https://docs.sim.ai/tools/appconfig", + "operations": [ + { + "name": "Get Configuration", + "description": "Retrieve the latest deployed configuration for an AppConfig application, environment, and profile" + }, + { + "name": "List Applications", + "description": "List applications in AWS AppConfig" + }, + { + "name": "Create Application", + "description": "Create an application in AWS AppConfig" + }, + { + "name": "List Environments", + "description": "List environments for an AWS AppConfig application" + }, + { + "name": "Create Environment", + "description": "Create an environment for an AWS AppConfig application" + }, + { + "name": "List Configuration Profiles", + "description": "List configuration profiles for an AWS AppConfig application" + }, + { + "name": "Create Configuration Profile", + "description": "Create a configuration profile in an AWS AppConfig application" + }, + { + "name": "Create Hosted Configuration Version", + "description": "Create a new hosted configuration version for an AppConfig configuration profile" + }, + { + "name": "Get Hosted Configuration Version", + "description": "Retrieve a specific hosted configuration version from an AppConfig profile" + }, + { + "name": "List Deployment Strategies", + "description": "List deployment strategies available in AWS AppConfig" + }, + { + "name": "Start Deployment", + "description": "Start deploying a configuration version to an AWS AppConfig environment" + }, + { + "name": "Get Deployment", + "description": "Get details about a specific AWS AppConfig deployment" + }, + { + "name": "List Deployments", + "description": "List deployments for an AWS AppConfig environment" + }, + { + "name": "Stop Deployment", + "description": "Stop an in-progress AWS AppConfig deployment" + } + ], + "operationCount": 14, + "triggers": [], + "triggerCount": 0, + "authType": "api-key", + "category": "tools", + "integrationType": "devops", + "tags": ["cloud", "configuration", "feature-flags"] + }, { "type": "iam", "slug": "aws-iam", diff --git a/apps/sim/tools/appconfig/create_application.ts b/apps/sim/tools/appconfig/create_application.ts new file mode 100644 index 00000000000..f881de3051b --- /dev/null +++ b/apps/sim/tools/appconfig/create_application.ts @@ -0,0 +1,90 @@ +import type { + AppConfigCreateApplicationParams, + AppConfigCreateApplicationResponse, +} from '@/tools/appconfig/types' +import type { ToolConfig } from '@/tools/types' + +export const createApplicationTool: ToolConfig< + AppConfigCreateApplicationParams, + AppConfigCreateApplicationResponse +> = { + id: 'appconfig_create_application', + name: 'AppConfig Create Application', + description: 'Create an application in AWS AppConfig', + version: '1.0', + + params: { + region: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + accessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + secretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + name: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Name of the application to create', + }, + description: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Description of the application', + }, + }, + + request: { + url: '/api/tools/appconfig/create-application', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + name: params.name, + description: params.description, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || 'Failed to create AppConfig application') + } + + return { + success: true, + output: { + message: data.message ?? '', + id: data.id ?? '', + name: data.name ?? '', + description: data.description ?? null, + }, + } + }, + + outputs: { + message: { type: 'string', description: 'Operation status message' }, + id: { type: 'string', description: 'ID of the created application' }, + name: { type: 'string', description: 'Name of the created application' }, + description: { + type: 'string', + description: 'Description of the created application', + optional: true, + }, + }, +} diff --git a/apps/sim/tools/appconfig/create_configuration_profile.ts b/apps/sim/tools/appconfig/create_configuration_profile.ts new file mode 100644 index 00000000000..658afbb2de5 --- /dev/null +++ b/apps/sim/tools/appconfig/create_configuration_profile.ts @@ -0,0 +1,120 @@ +import type { + AppConfigCreateConfigurationProfileParams, + AppConfigCreateConfigurationProfileResponse, +} from '@/tools/appconfig/types' +import type { ToolConfig } from '@/tools/types' + +export const createConfigurationProfileTool: ToolConfig< + AppConfigCreateConfigurationProfileParams, + AppConfigCreateConfigurationProfileResponse +> = { + id: 'appconfig_create_configuration_profile', + name: 'AppConfig Create Configuration Profile', + description: 'Create a configuration profile in an AWS AppConfig application', + version: '1.0', + + params: { + region: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + accessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + secretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + applicationId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The application ID to create the configuration profile in', + }, + name: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Name of the configuration profile', + }, + locationUri: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: + 'Where the configuration is stored. Use "hosted" for AppConfig-hosted configurations, or an SSM/S3 URI', + }, + description: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Description of the configuration profile', + }, + retrievalRoleArn: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: + 'ARN of an IAM role to retrieve the configuration (required for non-hosted URIs)', + }, + type: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Profile type: AWS.Freeform (default) or AWS.AppConfig.FeatureFlags', + }, + }, + + request: { + url: '/api/tools/appconfig/create-configuration-profile', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + applicationId: params.applicationId, + name: params.name, + locationUri: params.locationUri, + description: params.description, + retrievalRoleArn: params.retrievalRoleArn, + type: params.type, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || 'Failed to create AppConfig configuration profile') + } + + return { + success: true, + output: { + message: data.message ?? '', + applicationId: data.applicationId ?? '', + id: data.id ?? '', + name: data.name ?? '', + locationUri: data.locationUri ?? null, + type: data.type ?? null, + }, + } + }, + + outputs: { + message: { type: 'string', description: 'Operation status message' }, + applicationId: { type: 'string', description: 'Owning application ID' }, + id: { type: 'string', description: 'ID of the created configuration profile' }, + name: { type: 'string', description: 'Name of the created configuration profile' }, + locationUri: { type: 'string', description: 'Location URI of the config', optional: true }, + type: { type: 'string', description: 'Profile type', optional: true }, + }, +} diff --git a/apps/sim/tools/appconfig/create_environment.ts b/apps/sim/tools/appconfig/create_environment.ts new file mode 100644 index 00000000000..8389116c144 --- /dev/null +++ b/apps/sim/tools/appconfig/create_environment.ts @@ -0,0 +1,95 @@ +import type { + AppConfigCreateEnvironmentParams, + AppConfigCreateEnvironmentResponse, +} from '@/tools/appconfig/types' +import type { ToolConfig } from '@/tools/types' + +export const createEnvironmentTool: ToolConfig< + AppConfigCreateEnvironmentParams, + AppConfigCreateEnvironmentResponse +> = { + id: 'appconfig_create_environment', + name: 'AppConfig Create Environment', + description: 'Create an environment for an AWS AppConfig application', + version: '1.0', + + params: { + region: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + accessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + secretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + applicationId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The application ID to create the environment in', + }, + name: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Name of the environment to create', + }, + description: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Description of the environment', + }, + }, + + request: { + url: '/api/tools/appconfig/create-environment', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + applicationId: params.applicationId, + name: params.name, + description: params.description, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || 'Failed to create AppConfig environment') + } + + return { + success: true, + output: { + message: data.message ?? '', + applicationId: data.applicationId ?? '', + id: data.id ?? '', + name: data.name ?? '', + state: data.state ?? null, + }, + } + }, + + outputs: { + message: { type: 'string', description: 'Operation status message' }, + applicationId: { type: 'string', description: 'Owning application ID' }, + id: { type: 'string', description: 'ID of the created environment' }, + name: { type: 'string', description: 'Name of the created environment' }, + state: { type: 'string', description: 'State of the created environment', optional: true }, + }, +} diff --git a/apps/sim/tools/appconfig/create_hosted_configuration_version.ts b/apps/sim/tools/appconfig/create_hosted_configuration_version.ts new file mode 100644 index 00000000000..4cecaa199c1 --- /dev/null +++ b/apps/sim/tools/appconfig/create_hosted_configuration_version.ts @@ -0,0 +1,137 @@ +import type { + AppConfigCreateHostedConfigurationVersionParams, + AppConfigCreateHostedConfigurationVersionResponse, +} from '@/tools/appconfig/types' +import type { ToolConfig } from '@/tools/types' + +export const createHostedConfigurationVersionTool: ToolConfig< + AppConfigCreateHostedConfigurationVersionParams, + AppConfigCreateHostedConfigurationVersionResponse +> = { + id: 'appconfig_create_hosted_configuration_version', + name: 'AppConfig Create Hosted Configuration Version', + description: 'Create a new hosted configuration version for an AppConfig configuration profile', + version: '1.0', + + params: { + region: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + accessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + secretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + applicationId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The application ID that owns the configuration profile', + }, + configurationProfileId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The configuration profile ID to add the version to', + }, + content: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The configuration content (e.g., a JSON or YAML document)', + }, + contentType: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Content type of the configuration (e.g., application/json, text/plain)', + }, + description: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Description of the configuration version', + }, + latestVersionNumber: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'The version number of the latest version, used for optimistic concurrency', + }, + versionLabel: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'A user-defined label for the configuration version', + }, + }, + + request: { + url: '/api/tools/appconfig/create-hosted-configuration-version', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + applicationId: params.applicationId, + configurationProfileId: params.configurationProfileId, + content: params.content, + contentType: params.contentType, + description: params.description, + latestVersionNumber: params.latestVersionNumber, + versionLabel: params.versionLabel, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || 'Failed to create AppConfig hosted configuration version') + } + + return { + success: true, + output: { + message: data.message ?? '', + applicationId: data.applicationId ?? '', + configurationProfileId: data.configurationProfileId ?? '', + versionNumber: data.versionNumber ?? null, + contentType: data.contentType ?? null, + versionLabel: data.versionLabel ?? null, + }, + } + }, + + outputs: { + message: { type: 'string', description: 'Operation status message' }, + applicationId: { type: 'string', description: 'Owning application ID' }, + configurationProfileId: { type: 'string', description: 'Owning configuration profile ID' }, + versionNumber: { + type: 'number', + description: 'Version number of the created configuration', + optional: true, + }, + contentType: { + type: 'string', + description: 'Content type of the configuration', + optional: true, + }, + versionLabel: { + type: 'string', + description: 'Label of the configuration version', + optional: true, + }, + }, +} diff --git a/apps/sim/tools/appconfig/get_configuration.ts b/apps/sim/tools/appconfig/get_configuration.ts new file mode 100644 index 00000000000..9605f551dcf --- /dev/null +++ b/apps/sim/tools/appconfig/get_configuration.ts @@ -0,0 +1,100 @@ +import type { + AppConfigGetConfigurationParams, + AppConfigGetConfigurationResponse, +} from '@/tools/appconfig/types' +import type { ToolConfig } from '@/tools/types' + +export const getConfigurationTool: ToolConfig< + AppConfigGetConfigurationParams, + AppConfigGetConfigurationResponse +> = { + id: 'appconfig_get_configuration', + name: 'AppConfig Get Configuration', + description: + 'Retrieve the latest deployed configuration for an AppConfig application, environment, and profile', + version: '1.0', + + params: { + region: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + accessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + secretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + applicationId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The application ID or name to retrieve configuration for', + }, + environmentId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The environment ID or name to retrieve configuration for', + }, + configurationProfileId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The configuration profile ID or name to retrieve', + }, + }, + + request: { + url: '/api/tools/appconfig/get-configuration', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + applicationId: params.applicationId, + environmentId: params.environmentId, + configurationProfileId: params.configurationProfileId, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || 'Failed to retrieve AppConfig configuration') + } + + return { + success: true, + output: { + configuration: data.configuration ?? '', + contentType: data.contentType ?? null, + versionLabel: data.versionLabel ?? null, + }, + } + }, + + outputs: { + configuration: { type: 'string', description: 'The deployed configuration content' }, + contentType: { + type: 'string', + description: 'Content type of the configuration', + optional: true, + }, + versionLabel: { + type: 'string', + description: 'Label of the retrieved configuration version', + optional: true, + }, + }, +} diff --git a/apps/sim/tools/appconfig/get_deployment.ts b/apps/sim/tools/appconfig/get_deployment.ts new file mode 100644 index 00000000000..983c5a783dc --- /dev/null +++ b/apps/sim/tools/appconfig/get_deployment.ts @@ -0,0 +1,109 @@ +import type { + AppConfigGetDeploymentParams, + AppConfigGetDeploymentResponse, +} from '@/tools/appconfig/types' +import type { ToolConfig } from '@/tools/types' + +export const getDeploymentTool: ToolConfig< + AppConfigGetDeploymentParams, + AppConfigGetDeploymentResponse +> = { + id: 'appconfig_get_deployment', + name: 'AppConfig Get Deployment', + description: 'Get details about a specific AWS AppConfig deployment', + version: '1.0', + + params: { + region: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + accessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + secretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + applicationId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The application ID of the deployment', + }, + environmentId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The environment ID of the deployment', + }, + deploymentNumber: { + type: 'number', + required: true, + visibility: 'user-or-llm', + description: 'The sequence number of the deployment', + }, + }, + + request: { + url: '/api/tools/appconfig/get-deployment', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + applicationId: params.applicationId, + environmentId: params.environmentId, + deploymentNumber: params.deploymentNumber, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || 'Failed to get AppConfig deployment') + } + + return { + success: true, + output: { + applicationId: data.applicationId ?? '', + environmentId: data.environmentId ?? '', + deploymentStrategyId: data.deploymentStrategyId ?? '', + configurationProfileId: data.configurationProfileId ?? '', + deploymentNumber: data.deploymentNumber ?? null, + configurationName: data.configurationName ?? null, + configurationVersion: data.configurationVersion ?? null, + description: data.description ?? null, + state: data.state ?? null, + percentageComplete: data.percentageComplete ?? null, + startedAt: data.startedAt ?? null, + completedAt: data.completedAt ?? null, + }, + } + }, + + outputs: { + applicationId: { type: 'string', description: 'Application ID' }, + environmentId: { type: 'string', description: 'Environment ID' }, + deploymentStrategyId: { type: 'string', description: 'Deployment strategy ID' }, + configurationProfileId: { type: 'string', description: 'Configuration profile ID' }, + deploymentNumber: { type: 'number', description: 'Deployment sequence number', optional: true }, + configurationName: { type: 'string', description: 'Configuration name', optional: true }, + configurationVersion: { type: 'string', description: 'Configuration version', optional: true }, + description: { type: 'string', description: 'Deployment description', optional: true }, + state: { type: 'string', description: 'Current deployment state', optional: true }, + percentageComplete: { type: 'number', description: 'Percentage completed', optional: true }, + startedAt: { type: 'string', description: 'When the deployment started', optional: true }, + completedAt: { type: 'string', description: 'When the deployment completed', optional: true }, + }, +} diff --git a/apps/sim/tools/appconfig/get_hosted_configuration_version.ts b/apps/sim/tools/appconfig/get_hosted_configuration_version.ts new file mode 100644 index 00000000000..99a7683a230 --- /dev/null +++ b/apps/sim/tools/appconfig/get_hosted_configuration_version.ts @@ -0,0 +1,107 @@ +import type { + AppConfigGetHostedConfigurationVersionParams, + AppConfigGetHostedConfigurationVersionResponse, +} from '@/tools/appconfig/types' +import type { ToolConfig } from '@/tools/types' + +export const getHostedConfigurationVersionTool: ToolConfig< + AppConfigGetHostedConfigurationVersionParams, + AppConfigGetHostedConfigurationVersionResponse +> = { + id: 'appconfig_get_hosted_configuration_version', + name: 'AppConfig Get Hosted Configuration Version', + description: 'Retrieve a specific hosted configuration version from an AppConfig profile', + version: '1.0', + + params: { + region: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + accessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + secretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + applicationId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The application ID that owns the configuration profile', + }, + configurationProfileId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The configuration profile ID to read the version from', + }, + versionNumber: { + type: 'number', + required: true, + visibility: 'user-or-llm', + description: 'The version number to retrieve', + }, + }, + + request: { + url: '/api/tools/appconfig/get-hosted-configuration-version', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + applicationId: params.applicationId, + configurationProfileId: params.configurationProfileId, + versionNumber: params.versionNumber, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || 'Failed to get AppConfig hosted configuration version') + } + + return { + success: true, + output: { + applicationId: data.applicationId ?? '', + configurationProfileId: data.configurationProfileId ?? '', + versionNumber: data.versionNumber ?? null, + description: data.description ?? null, + content: data.content ?? '', + contentType: data.contentType ?? null, + versionLabel: data.versionLabel ?? null, + }, + } + }, + + outputs: { + applicationId: { type: 'string', description: 'Owning application ID' }, + configurationProfileId: { type: 'string', description: 'Owning configuration profile ID' }, + versionNumber: { type: 'number', description: 'Version number', optional: true }, + description: { type: 'string', description: 'Description of the version', optional: true }, + content: { type: 'string', description: 'The configuration content' }, + contentType: { + type: 'string', + description: 'Content type of the configuration', + optional: true, + }, + versionLabel: { + type: 'string', + description: 'Label of the configuration version', + optional: true, + }, + }, +} diff --git a/apps/sim/tools/appconfig/index.ts b/apps/sim/tools/appconfig/index.ts new file mode 100644 index 00000000000..7ec5c39b9d5 --- /dev/null +++ b/apps/sim/tools/appconfig/index.ts @@ -0,0 +1,29 @@ +import { createApplicationTool } from './create_application' +import { createConfigurationProfileTool } from './create_configuration_profile' +import { createEnvironmentTool } from './create_environment' +import { createHostedConfigurationVersionTool } from './create_hosted_configuration_version' +import { getConfigurationTool } from './get_configuration' +import { getDeploymentTool } from './get_deployment' +import { getHostedConfigurationVersionTool } from './get_hosted_configuration_version' +import { listApplicationsTool } from './list_applications' +import { listConfigurationProfilesTool } from './list_configuration_profiles' +import { listDeploymentStrategiesTool } from './list_deployment_strategies' +import { listDeploymentsTool } from './list_deployments' +import { listEnvironmentsTool } from './list_environments' +import { startDeploymentTool } from './start_deployment' +import { stopDeploymentTool } from './stop_deployment' + +export const appConfigListApplicationsTool = listApplicationsTool +export const appConfigCreateApplicationTool = createApplicationTool +export const appConfigListEnvironmentsTool = listEnvironmentsTool +export const appConfigCreateEnvironmentTool = createEnvironmentTool +export const appConfigListConfigurationProfilesTool = listConfigurationProfilesTool +export const appConfigCreateConfigurationProfileTool = createConfigurationProfileTool +export const appConfigCreateHostedConfigurationVersionTool = createHostedConfigurationVersionTool +export const appConfigGetHostedConfigurationVersionTool = getHostedConfigurationVersionTool +export const appConfigListDeploymentStrategiesTool = listDeploymentStrategiesTool +export const appConfigStartDeploymentTool = startDeploymentTool +export const appConfigGetDeploymentTool = getDeploymentTool +export const appConfigListDeploymentsTool = listDeploymentsTool +export const appConfigStopDeploymentTool = stopDeploymentTool +export const appConfigGetConfigurationTool = getConfigurationTool diff --git a/apps/sim/tools/appconfig/list_applications.ts b/apps/sim/tools/appconfig/list_applications.ts new file mode 100644 index 00000000000..b54f1fcf289 --- /dev/null +++ b/apps/sim/tools/appconfig/list_applications.ts @@ -0,0 +1,99 @@ +import type { + AppConfigListApplicationsParams, + AppConfigListApplicationsResponse, +} from '@/tools/appconfig/types' +import type { ToolConfig } from '@/tools/types' + +export const listApplicationsTool: ToolConfig< + AppConfigListApplicationsParams, + AppConfigListApplicationsResponse +> = { + id: 'appconfig_list_applications', + name: 'AppConfig List Applications', + description: 'List applications in AWS AppConfig', + version: '1.0', + + params: { + region: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + accessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + secretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + maxResults: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Maximum number of applications to return (1-50)', + }, + nextToken: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Pagination token from a previous response', + }, + }, + + request: { + url: '/api/tools/appconfig/list-applications', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + maxResults: params.maxResults, + nextToken: params.nextToken, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || 'Failed to list AppConfig applications') + } + + return { + success: true, + output: { + applications: data.applications ?? [], + nextToken: data.nextToken ?? null, + count: data.count ?? 0, + }, + } + }, + + outputs: { + applications: { + type: 'array', + description: 'List of AppConfig applications', + items: { + type: 'object', + properties: { + id: { type: 'string', description: 'Application ID' }, + name: { type: 'string', description: 'Application name' }, + description: { type: 'string', description: 'Application description', optional: true }, + }, + }, + }, + nextToken: { + type: 'string', + description: 'Pagination token for the next page', + optional: true, + }, + count: { type: 'number', description: 'Number of applications returned' }, + }, +} diff --git a/apps/sim/tools/appconfig/list_configuration_profiles.ts b/apps/sim/tools/appconfig/list_configuration_profiles.ts new file mode 100644 index 00000000000..337d0575201 --- /dev/null +++ b/apps/sim/tools/appconfig/list_configuration_profiles.ts @@ -0,0 +1,117 @@ +import type { + AppConfigListConfigurationProfilesParams, + AppConfigListConfigurationProfilesResponse, +} from '@/tools/appconfig/types' +import type { ToolConfig } from '@/tools/types' + +export const listConfigurationProfilesTool: ToolConfig< + AppConfigListConfigurationProfilesParams, + AppConfigListConfigurationProfilesResponse +> = { + id: 'appconfig_list_configuration_profiles', + name: 'AppConfig List Configuration Profiles', + description: 'List configuration profiles for an AWS AppConfig application', + version: '1.0', + + params: { + region: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + accessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + secretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + applicationId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The application ID that owns the configuration profiles', + }, + maxResults: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Maximum number of configuration profiles to return (1-50)', + }, + nextToken: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Pagination token from a previous response', + }, + }, + + request: { + url: '/api/tools/appconfig/list-configuration-profiles', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + applicationId: params.applicationId, + maxResults: params.maxResults, + nextToken: params.nextToken, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || 'Failed to list AppConfig configuration profiles') + } + + return { + success: true, + output: { + configurationProfiles: data.configurationProfiles ?? [], + nextToken: data.nextToken ?? null, + count: data.count ?? 0, + }, + } + }, + + outputs: { + configurationProfiles: { + type: 'array', + description: 'List of AppConfig configuration profiles', + items: { + type: 'object', + properties: { + applicationId: { type: 'string', description: 'Owning application ID' }, + id: { type: 'string', description: 'Configuration profile ID' }, + name: { type: 'string', description: 'Configuration profile name' }, + locationUri: { + type: 'string', + description: 'Location URI of the config', + optional: true, + }, + type: { + type: 'string', + description: 'Profile type (e.g., AWS.Freeform)', + optional: true, + }, + validatorTypes: { type: 'array', description: 'Validator types configured' }, + }, + }, + }, + nextToken: { + type: 'string', + description: 'Pagination token for the next page', + optional: true, + }, + count: { type: 'number', description: 'Number of configuration profiles returned' }, + }, +} diff --git a/apps/sim/tools/appconfig/list_deployment_strategies.ts b/apps/sim/tools/appconfig/list_deployment_strategies.ts new file mode 100644 index 00000000000..13f1e1f3578 --- /dev/null +++ b/apps/sim/tools/appconfig/list_deployment_strategies.ts @@ -0,0 +1,120 @@ +import type { + AppConfigListDeploymentStrategiesParams, + AppConfigListDeploymentStrategiesResponse, +} from '@/tools/appconfig/types' +import type { ToolConfig } from '@/tools/types' + +export const listDeploymentStrategiesTool: ToolConfig< + AppConfigListDeploymentStrategiesParams, + AppConfigListDeploymentStrategiesResponse +> = { + id: 'appconfig_list_deployment_strategies', + name: 'AppConfig List Deployment Strategies', + description: 'List deployment strategies available in AWS AppConfig', + version: '1.0', + + params: { + region: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + accessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + secretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + maxResults: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Maximum number of deployment strategies to return (1-50)', + }, + nextToken: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Pagination token from a previous response', + }, + }, + + request: { + url: '/api/tools/appconfig/list-deployment-strategies', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + maxResults: params.maxResults, + nextToken: params.nextToken, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || 'Failed to list AppConfig deployment strategies') + } + + return { + success: true, + output: { + deploymentStrategies: data.deploymentStrategies ?? [], + nextToken: data.nextToken ?? null, + count: data.count ?? 0, + }, + } + }, + + outputs: { + deploymentStrategies: { + type: 'array', + description: 'List of AppConfig deployment strategies', + items: { + type: 'object', + properties: { + id: { type: 'string', description: 'Deployment strategy ID' }, + name: { type: 'string', description: 'Deployment strategy name' }, + description: { type: 'string', description: 'Strategy description', optional: true }, + deploymentDurationInMinutes: { + type: 'number', + description: 'Total deployment duration in minutes', + optional: true, + }, + growthType: { + type: 'string', + description: 'Growth type (LINEAR or EXPONENTIAL)', + optional: true, + }, + growthFactor: { type: 'number', description: 'Growth factor percentage', optional: true }, + finalBakeTimeInMinutes: { + type: 'number', + description: 'Final bake time in minutes', + optional: true, + }, + replicateTo: { + type: 'string', + description: 'Where the strategy is replicated', + optional: true, + }, + }, + }, + }, + nextToken: { + type: 'string', + description: 'Pagination token for the next page', + optional: true, + }, + count: { type: 'number', description: 'Number of deployment strategies returned' }, + }, +} diff --git a/apps/sim/tools/appconfig/list_deployments.ts b/apps/sim/tools/appconfig/list_deployments.ts new file mode 100644 index 00000000000..682e193bce9 --- /dev/null +++ b/apps/sim/tools/appconfig/list_deployments.ts @@ -0,0 +1,138 @@ +import type { + AppConfigListDeploymentsParams, + AppConfigListDeploymentsResponse, +} from '@/tools/appconfig/types' +import type { ToolConfig } from '@/tools/types' + +export const listDeploymentsTool: ToolConfig< + AppConfigListDeploymentsParams, + AppConfigListDeploymentsResponse +> = { + id: 'appconfig_list_deployments', + name: 'AppConfig List Deployments', + description: 'List deployments for an AWS AppConfig environment', + version: '1.0', + + params: { + region: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + accessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + secretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + applicationId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The application ID of the deployments', + }, + environmentId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The environment ID of the deployments', + }, + maxResults: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Maximum number of deployments to return (1-50)', + }, + nextToken: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Pagination token from a previous response', + }, + }, + + request: { + url: '/api/tools/appconfig/list-deployments', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + applicationId: params.applicationId, + environmentId: params.environmentId, + maxResults: params.maxResults, + nextToken: params.nextToken, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || 'Failed to list AppConfig deployments') + } + + return { + success: true, + output: { + deployments: data.deployments ?? [], + nextToken: data.nextToken ?? null, + count: data.count ?? 0, + }, + } + }, + + outputs: { + deployments: { + type: 'array', + description: 'List of AppConfig deployments', + items: { + type: 'object', + properties: { + deploymentNumber: { + type: 'number', + description: 'Deployment sequence number', + optional: true, + }, + configurationName: { type: 'string', description: 'Configuration name', optional: true }, + configurationVersion: { + type: 'string', + description: 'Configuration version', + optional: true, + }, + state: { type: 'string', description: 'Current deployment state', optional: true }, + percentageComplete: { + type: 'number', + description: 'Percentage completed', + optional: true, + }, + startedAt: { type: 'string', description: 'When the deployment started', optional: true }, + completedAt: { + type: 'string', + description: 'When the deployment completed', + optional: true, + }, + versionLabel: { + type: 'string', + description: 'Configuration version label', + optional: true, + }, + }, + }, + }, + nextToken: { + type: 'string', + description: 'Pagination token for the next page', + optional: true, + }, + count: { type: 'number', description: 'Number of deployments returned' }, + }, +} diff --git a/apps/sim/tools/appconfig/list_environments.ts b/apps/sim/tools/appconfig/list_environments.ts new file mode 100644 index 00000000000..97bf323dcd2 --- /dev/null +++ b/apps/sim/tools/appconfig/list_environments.ts @@ -0,0 +1,108 @@ +import type { + AppConfigListEnvironmentsParams, + AppConfigListEnvironmentsResponse, +} from '@/tools/appconfig/types' +import type { ToolConfig } from '@/tools/types' + +export const listEnvironmentsTool: ToolConfig< + AppConfigListEnvironmentsParams, + AppConfigListEnvironmentsResponse +> = { + id: 'appconfig_list_environments', + name: 'AppConfig List Environments', + description: 'List environments for an AWS AppConfig application', + version: '1.0', + + params: { + region: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + accessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + secretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + applicationId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The application ID that owns the environments', + }, + maxResults: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Maximum number of environments to return (1-50)', + }, + nextToken: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Pagination token from a previous response', + }, + }, + + request: { + url: '/api/tools/appconfig/list-environments', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + applicationId: params.applicationId, + maxResults: params.maxResults, + nextToken: params.nextToken, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || 'Failed to list AppConfig environments') + } + + return { + success: true, + output: { + environments: data.environments ?? [], + nextToken: data.nextToken ?? null, + count: data.count ?? 0, + }, + } + }, + + outputs: { + environments: { + type: 'array', + description: 'List of AppConfig environments', + items: { + type: 'object', + properties: { + applicationId: { type: 'string', description: 'Owning application ID' }, + id: { type: 'string', description: 'Environment ID' }, + name: { type: 'string', description: 'Environment name' }, + description: { type: 'string', description: 'Environment description', optional: true }, + state: { type: 'string', description: 'Environment state', optional: true }, + }, + }, + }, + nextToken: { + type: 'string', + description: 'Pagination token for the next page', + optional: true, + }, + count: { type: 'number', description: 'Number of environments returned' }, + }, +} diff --git a/apps/sim/tools/appconfig/start_deployment.ts b/apps/sim/tools/appconfig/start_deployment.ts new file mode 100644 index 00000000000..6f22e7f8007 --- /dev/null +++ b/apps/sim/tools/appconfig/start_deployment.ts @@ -0,0 +1,122 @@ +import type { + AppConfigStartDeploymentParams, + AppConfigStartDeploymentResponse, +} from '@/tools/appconfig/types' +import type { ToolConfig } from '@/tools/types' + +export const startDeploymentTool: ToolConfig< + AppConfigStartDeploymentParams, + AppConfigStartDeploymentResponse +> = { + id: 'appconfig_start_deployment', + name: 'AppConfig Start Deployment', + description: 'Start deploying a configuration version to an AWS AppConfig environment', + version: '1.0', + + params: { + region: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + accessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + secretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + applicationId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The application ID to deploy in', + }, + environmentId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The environment ID to deploy to', + }, + deploymentStrategyId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The deployment strategy ID to use', + }, + configurationProfileId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The configuration profile ID to deploy', + }, + configurationVersion: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The configuration version to deploy', + }, + description: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Description of the deployment', + }, + }, + + request: { + url: '/api/tools/appconfig/start-deployment', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + applicationId: params.applicationId, + environmentId: params.environmentId, + deploymentStrategyId: params.deploymentStrategyId, + configurationProfileId: params.configurationProfileId, + configurationVersion: params.configurationVersion, + description: params.description, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || 'Failed to start AppConfig deployment') + } + + return { + success: true, + output: { + message: data.message ?? '', + deploymentNumber: data.deploymentNumber ?? null, + state: data.state ?? null, + percentageComplete: data.percentageComplete ?? null, + }, + } + }, + + outputs: { + message: { type: 'string', description: 'Operation status message' }, + deploymentNumber: { + type: 'number', + description: 'Sequence number of the deployment', + optional: true, + }, + state: { type: 'string', description: 'Current deployment state', optional: true }, + percentageComplete: { + type: 'number', + description: 'Percentage of the deployment that has completed', + optional: true, + }, + }, +} diff --git a/apps/sim/tools/appconfig/stop_deployment.ts b/apps/sim/tools/appconfig/stop_deployment.ts new file mode 100644 index 00000000000..6d081325012 --- /dev/null +++ b/apps/sim/tools/appconfig/stop_deployment.ts @@ -0,0 +1,91 @@ +import type { + AppConfigStopDeploymentParams, + AppConfigStopDeploymentResponse, +} from '@/tools/appconfig/types' +import type { ToolConfig } from '@/tools/types' + +export const stopDeploymentTool: ToolConfig< + AppConfigStopDeploymentParams, + AppConfigStopDeploymentResponse +> = { + id: 'appconfig_stop_deployment', + name: 'AppConfig Stop Deployment', + description: 'Stop an in-progress AWS AppConfig deployment', + version: '1.0', + + params: { + region: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + accessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + secretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + applicationId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The application ID of the deployment', + }, + environmentId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The environment ID of the deployment', + }, + deploymentNumber: { + type: 'number', + required: true, + visibility: 'user-or-llm', + description: 'The sequence number of the deployment to stop', + }, + }, + + request: { + url: '/api/tools/appconfig/stop-deployment', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + applicationId: params.applicationId, + environmentId: params.environmentId, + deploymentNumber: params.deploymentNumber, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || 'Failed to stop AppConfig deployment') + } + + return { + success: true, + output: { + message: data.message ?? '', + deploymentNumber: data.deploymentNumber ?? null, + state: data.state ?? null, + }, + } + }, + + outputs: { + message: { type: 'string', description: 'Operation status message' }, + deploymentNumber: { type: 'number', description: 'Deployment sequence number', optional: true }, + state: { type: 'string', description: 'Deployment state after stopping', optional: true }, + }, +} diff --git a/apps/sim/tools/appconfig/types.ts b/apps/sim/tools/appconfig/types.ts new file mode 100644 index 00000000000..5ede4963a99 --- /dev/null +++ b/apps/sim/tools/appconfig/types.ts @@ -0,0 +1,301 @@ +import type { ToolResponse } from '@/tools/types' + +export interface AppConfigConnectionConfig { + region: string + accessKeyId: string + secretAccessKey: string +} + +export interface AppConfigApplication { + id: string + name: string + description: string | null +} + +export interface AppConfigEnvironment { + applicationId: string + id: string + name: string + description: string | null + state: string | null +} + +export interface AppConfigConfigurationProfile { + applicationId: string + id: string + name: string + description: string | null + locationUri: string | null + retrievalRoleArn: string | null + type: string | null + validatorTypes: string[] +} + +export interface AppConfigDeploymentSummary { + deploymentNumber: number | null + configurationName: string | null + configurationVersion: string | null + deploymentDurationInMinutes: number | null + growthType: string | null + growthFactor: number | null + finalBakeTimeInMinutes: number | null + state: string | null + percentageComplete: number | null + startedAt: string | null + completedAt: string | null + versionLabel: string | null +} + +export interface AppConfigDeploymentDetail { + applicationId: string + environmentId: string + deploymentStrategyId: string + configurationProfileId: string + deploymentNumber: number | null + configurationName: string | null + configurationVersion: string | null + description: string | null + state: string | null + percentageComplete: number | null + startedAt: string | null + completedAt: string | null +} + +export interface AppConfigDeploymentStrategy { + id: string + name: string + description: string | null + deploymentDurationInMinutes: number | null + growthType: string | null + growthFactor: number | null + finalBakeTimeInMinutes: number | null + replicateTo: string | null +} + +export interface AppConfigListApplicationsParams extends AppConfigConnectionConfig { + maxResults?: number | null + nextToken?: string | null +} + +export interface AppConfigCreateApplicationParams extends AppConfigConnectionConfig { + name: string + description?: string | null +} + +export interface AppConfigListEnvironmentsParams extends AppConfigConnectionConfig { + applicationId: string + maxResults?: number | null + nextToken?: string | null +} + +export interface AppConfigCreateEnvironmentParams extends AppConfigConnectionConfig { + applicationId: string + name: string + description?: string | null +} + +export interface AppConfigListConfigurationProfilesParams extends AppConfigConnectionConfig { + applicationId: string + maxResults?: number | null + nextToken?: string | null +} + +export interface AppConfigCreateConfigurationProfileParams extends AppConfigConnectionConfig { + applicationId: string + name: string + locationUri?: string | null + description?: string | null + retrievalRoleArn?: string | null + type?: string | null +} + +export interface AppConfigCreateHostedConfigurationVersionParams extends AppConfigConnectionConfig { + applicationId: string + configurationProfileId: string + content: string + contentType: string + description?: string | null + latestVersionNumber?: number | null + versionLabel?: string | null +} + +export interface AppConfigGetHostedConfigurationVersionParams extends AppConfigConnectionConfig { + applicationId: string + configurationProfileId: string + versionNumber: number +} + +export interface AppConfigListDeploymentStrategiesParams extends AppConfigConnectionConfig { + maxResults?: number | null + nextToken?: string | null +} + +export interface AppConfigStartDeploymentParams extends AppConfigConnectionConfig { + applicationId: string + environmentId: string + deploymentStrategyId: string + configurationProfileId: string + configurationVersion: string + description?: string | null +} + +export interface AppConfigGetDeploymentParams extends AppConfigConnectionConfig { + applicationId: string + environmentId: string + deploymentNumber: number +} + +export interface AppConfigListDeploymentsParams extends AppConfigConnectionConfig { + applicationId: string + environmentId: string + maxResults?: number | null + nextToken?: string | null +} + +export interface AppConfigStopDeploymentParams extends AppConfigConnectionConfig { + applicationId: string + environmentId: string + deploymentNumber: number +} + +export interface AppConfigGetConfigurationParams extends AppConfigConnectionConfig { + applicationId: string + environmentId: string + configurationProfileId: string +} + +export interface AppConfigListApplicationsResponse extends ToolResponse { + output: { + applications: AppConfigApplication[] + nextToken: string | null + count: number + } + error?: string +} + +export interface AppConfigCreateApplicationResponse extends ToolResponse { + output: { + message: string + id: string + name: string + description: string | null + } + error?: string +} + +export interface AppConfigListEnvironmentsResponse extends ToolResponse { + output: { + environments: AppConfigEnvironment[] + nextToken: string | null + count: number + } + error?: string +} + +export interface AppConfigCreateEnvironmentResponse extends ToolResponse { + output: { + message: string + applicationId: string + id: string + name: string + state: string | null + } + error?: string +} + +export interface AppConfigListConfigurationProfilesResponse extends ToolResponse { + output: { + configurationProfiles: AppConfigConfigurationProfile[] + nextToken: string | null + count: number + } + error?: string +} + +export interface AppConfigCreateConfigurationProfileResponse extends ToolResponse { + output: { + message: string + applicationId: string + id: string + name: string + locationUri: string | null + type: string | null + } + error?: string +} + +export interface AppConfigCreateHostedConfigurationVersionResponse extends ToolResponse { + output: { + message: string + applicationId: string + configurationProfileId: string + versionNumber: number | null + contentType: string | null + versionLabel: string | null + } + error?: string +} + +export interface AppConfigGetHostedConfigurationVersionResponse extends ToolResponse { + output: { + applicationId: string + configurationProfileId: string + versionNumber: number | null + description: string | null + content: string + contentType: string | null + versionLabel: string | null + } + error?: string +} + +export interface AppConfigListDeploymentStrategiesResponse extends ToolResponse { + output: { + deploymentStrategies: AppConfigDeploymentStrategy[] + nextToken: string | null + count: number + } + error?: string +} + +export interface AppConfigStartDeploymentResponse extends ToolResponse { + output: { + message: string + deploymentNumber: number | null + state: string | null + percentageComplete: number | null + } + error?: string +} + +export interface AppConfigGetDeploymentResponse extends ToolResponse { + output: AppConfigDeploymentDetail + error?: string +} + +export interface AppConfigListDeploymentsResponse extends ToolResponse { + output: { + deployments: AppConfigDeploymentSummary[] + nextToken: string | null + count: number + } + error?: string +} + +export interface AppConfigStopDeploymentResponse extends ToolResponse { + output: { + message: string + deploymentNumber: number | null + state: string | null + } + error?: string +} + +export interface AppConfigGetConfigurationResponse extends ToolResponse { + output: { + configuration: string + contentType: string | null + versionLabel: string | null + } + error?: string +} diff --git a/apps/sim/tools/registry.ts b/apps/sim/tools/registry.ts index 6b1c404ef2b..b2f97ee7dee 100644 --- a/apps/sim/tools/registry.ts +++ b/apps/sim/tools/registry.ts @@ -155,6 +155,22 @@ import { apolloTaskCreateTool, apolloTaskSearchTool, } from '@/tools/apollo' +import { + appConfigCreateApplicationTool, + appConfigCreateConfigurationProfileTool, + appConfigCreateEnvironmentTool, + appConfigCreateHostedConfigurationVersionTool, + appConfigGetConfigurationTool, + appConfigGetDeploymentTool, + appConfigGetHostedConfigurationVersionTool, + appConfigListApplicationsTool, + appConfigListConfigurationProfilesTool, + appConfigListDeploymentStrategiesTool, + appConfigListDeploymentsTool, + appConfigListEnvironmentsTool, + appConfigStartDeploymentTool, + appConfigStopDeploymentTool, +} from '@/tools/appconfig' import { arxivGetAuthorPapersTool, arxivGetPaperTool, arxivSearchTool } from '@/tools/arxiv' import { asanaAddCommentTool, @@ -5235,6 +5251,20 @@ export const tools: Record = { apify_run_task: apifyRunTaskTool, apify_get_dataset_items: apifyGetDatasetItemsTool, apify_get_run: apifyGetRunTool, + appconfig_get_configuration: appConfigGetConfigurationTool, + appconfig_list_applications: appConfigListApplicationsTool, + appconfig_create_application: appConfigCreateApplicationTool, + appconfig_list_environments: appConfigListEnvironmentsTool, + appconfig_create_environment: appConfigCreateEnvironmentTool, + appconfig_list_configuration_profiles: appConfigListConfigurationProfilesTool, + appconfig_create_configuration_profile: appConfigCreateConfigurationProfileTool, + appconfig_create_hosted_configuration_version: appConfigCreateHostedConfigurationVersionTool, + appconfig_get_hosted_configuration_version: appConfigGetHostedConfigurationVersionTool, + appconfig_list_deployment_strategies: appConfigListDeploymentStrategiesTool, + appconfig_start_deployment: appConfigStartDeploymentTool, + appconfig_get_deployment: appConfigGetDeploymentTool, + appconfig_list_deployments: appConfigListDeploymentsTool, + appconfig_stop_deployment: appConfigStopDeploymentTool, apollo_people_search: apolloPeopleSearchTool, apollo_people_enrich: apolloPeopleEnrichTool, apollo_people_bulk_enrich: apolloPeopleBulkEnrichTool, diff --git a/bun.lock b/bun.lock index d5496a63094..42d93b34c8d 100644 --- a/bun.lock +++ b/bun.lock @@ -4,6 +4,9 @@ "workspaces": { "": { "name": "simstudio", + "dependencies": { + "@aws-sdk/client-appconfig": "3.1032.0", + }, "devDependencies": { "@biomejs/biome": "2.0.0-beta.5", "@octokit/rest": "^21.0.0", @@ -561,6 +564,8 @@ "@aws-crypto/util": ["@aws-crypto/util@5.2.0", "", { "dependencies": { "@aws-sdk/types": "^3.222.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ=="], + "@aws-sdk/client-appconfig": ["@aws-sdk/client-appconfig@3.1032.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.974.1", "@aws-sdk/credential-provider-node": "^3.972.32", "@aws-sdk/middleware-host-header": "^3.972.10", "@aws-sdk/middleware-logger": "^3.972.10", "@aws-sdk/middleware-recursion-detection": "^3.972.11", "@aws-sdk/middleware-user-agent": "^3.972.31", "@aws-sdk/region-config-resolver": "^3.972.12", "@aws-sdk/types": "^3.973.8", "@aws-sdk/util-endpoints": "^3.996.7", "@aws-sdk/util-user-agent-browser": "^3.972.10", "@aws-sdk/util-user-agent-node": "^3.973.17", "@smithy/config-resolver": "^4.4.16", "@smithy/core": "^3.23.15", "@smithy/fetch-http-handler": "^5.3.17", "@smithy/hash-node": "^4.2.14", "@smithy/invalid-dependency": "^4.2.14", "@smithy/middleware-content-length": "^4.2.14", "@smithy/middleware-endpoint": "^4.4.30", "@smithy/middleware-retry": "^4.5.3", "@smithy/middleware-serde": "^4.2.18", "@smithy/middleware-stack": "^4.2.14", "@smithy/node-config-provider": "^4.3.14", "@smithy/node-http-handler": "^4.5.3", "@smithy/protocol-http": "^5.3.14", "@smithy/smithy-client": "^4.12.11", "@smithy/types": "^4.14.1", "@smithy/url-parser": "^4.2.14", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-body-length-node": "^4.2.3", "@smithy/util-defaults-mode-browser": "^4.3.47", "@smithy/util-defaults-mode-node": "^4.2.52", "@smithy/util-endpoints": "^3.4.1", "@smithy/util-middleware": "^4.2.14", "@smithy/util-retry": "^4.3.2", "@smithy/util-stream": "^4.5.23", "@smithy/util-utf8": "^4.2.2", "@smithy/util-waiter": "^4.2.16", "tslib": "^2.6.2" } }, "sha512-WcS820syhSamz1PcZUvdUXf7FUm3cpze+hfMvDKzPojrh/zFO5eVopzhBGEkDFXiHFD0qel1ZgE5s5AkmH9fyg=="], + "@aws-sdk/client-appconfigdata": ["@aws-sdk/client-appconfigdata@3.1032.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.974.1", "@aws-sdk/credential-provider-node": "^3.972.32", "@aws-sdk/middleware-host-header": "^3.972.10", "@aws-sdk/middleware-logger": "^3.972.10", "@aws-sdk/middleware-recursion-detection": "^3.972.11", "@aws-sdk/middleware-user-agent": "^3.972.31", "@aws-sdk/region-config-resolver": "^3.972.12", "@aws-sdk/types": "^3.973.8", "@aws-sdk/util-endpoints": "^3.996.7", "@aws-sdk/util-user-agent-browser": "^3.972.10", "@aws-sdk/util-user-agent-node": "^3.973.17", "@smithy/config-resolver": "^4.4.16", "@smithy/core": "^3.23.15", "@smithy/fetch-http-handler": "^5.3.17", "@smithy/hash-node": "^4.2.14", "@smithy/invalid-dependency": "^4.2.14", "@smithy/middleware-content-length": "^4.2.14", "@smithy/middleware-endpoint": "^4.4.30", "@smithy/middleware-retry": "^4.5.3", "@smithy/middleware-serde": "^4.2.18", "@smithy/middleware-stack": "^4.2.14", "@smithy/node-config-provider": "^4.3.14", "@smithy/node-http-handler": "^4.5.3", "@smithy/protocol-http": "^5.3.14", "@smithy/smithy-client": "^4.12.11", "@smithy/types": "^4.14.1", "@smithy/url-parser": "^4.2.14", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-body-length-node": "^4.2.3", "@smithy/util-defaults-mode-browser": "^4.3.47", "@smithy/util-defaults-mode-node": "^4.2.52", "@smithy/util-endpoints": "^3.4.1", "@smithy/util-middleware": "^4.2.14", "@smithy/util-retry": "^4.3.2", "@smithy/util-stream": "^4.5.23", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-gh/cmEFDN97XJBWRLT0usnWnTDEm+cqgOIffTJGP68xCgj28EkSHnN5vtdy2QaZjj7/n/sKOlqIKONZUeonRpA=="], "@aws-sdk/client-athena": ["@aws-sdk/client-athena@3.1032.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.974.1", "@aws-sdk/credential-provider-node": "^3.972.32", "@aws-sdk/middleware-host-header": "^3.972.10", "@aws-sdk/middleware-logger": "^3.972.10", "@aws-sdk/middleware-recursion-detection": "^3.972.11", "@aws-sdk/middleware-user-agent": "^3.972.31", "@aws-sdk/region-config-resolver": "^3.972.12", "@aws-sdk/types": "^3.973.8", "@aws-sdk/util-endpoints": "^3.996.7", "@aws-sdk/util-user-agent-browser": "^3.972.10", "@aws-sdk/util-user-agent-node": "^3.973.17", "@smithy/config-resolver": "^4.4.16", "@smithy/core": "^3.23.15", "@smithy/fetch-http-handler": "^5.3.17", "@smithy/hash-node": "^4.2.14", "@smithy/invalid-dependency": "^4.2.14", "@smithy/middleware-content-length": "^4.2.14", "@smithy/middleware-endpoint": "^4.4.30", "@smithy/middleware-retry": "^4.5.3", "@smithy/middleware-serde": "^4.2.18", "@smithy/middleware-stack": "^4.2.14", "@smithy/node-config-provider": "^4.3.14", "@smithy/node-http-handler": "^4.5.3", "@smithy/protocol-http": "^5.3.14", "@smithy/smithy-client": "^4.12.11", "@smithy/types": "^4.14.1", "@smithy/url-parser": "^4.2.14", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-body-length-node": "^4.2.3", "@smithy/util-defaults-mode-browser": "^4.3.47", "@smithy/util-defaults-mode-node": "^4.2.52", "@smithy/util-endpoints": "^3.4.1", "@smithy/util-middleware": "^4.2.14", "@smithy/util-retry": "^4.3.2", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-/3RrC4J644U1ZlqcGyGCRf2cyCH/xWs2B6PewlKWeyTq2uWSRtY+v5CkEQ51fRm2Y5wfhuxoU9FO1jKIKm9fSA=="], diff --git a/package.json b/package.json index 1b95ca0f8dd..0dcaf676f30 100644 --- a/package.json +++ b/package.json @@ -74,5 +74,8 @@ }, "trustedDependencies": [ "sharp" - ] + ], + "dependencies": { + "@aws-sdk/client-appconfig": "3.1032.0" + } } diff --git a/scripts/check-api-validation-contracts.ts b/scripts/check-api-validation-contracts.ts index 9e188840c6b..2dc563d040b 100644 --- a/scripts/check-api-validation-contracts.ts +++ b/scripts/check-api-validation-contracts.ts @@ -9,8 +9,8 @@ const QUERY_HOOKS_DIR = path.join(ROOT, 'apps/sim/hooks/queries') const SELECTOR_HOOKS_DIR = path.join(ROOT, 'apps/sim/hooks/selectors') const BASELINE = { - totalRoutes: 792, - zodRoutes: 792, + totalRoutes: 793, + zodRoutes: 793, nonZodRoutes: 0, } as const From 05807bbfda08e35219c6c95be8620f3c8f6d6e3b Mon Sep 17 00:00:00 2001 From: waleed Date: Tue, 9 Jun 2026 11:34:25 -0700 Subject: [PATCH 2/6] fix(integrations): preserve latestVersionNumber 0 and tighten locationUri type in AppConfig --- apps/sim/app/api/tools/appconfig/utils.ts | 2 +- apps/sim/tools/appconfig/types.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/sim/app/api/tools/appconfig/utils.ts b/apps/sim/app/api/tools/appconfig/utils.ts index 454b064b04b..7820f4f9eb3 100644 --- a/apps/sim/app/api/tools/appconfig/utils.ts +++ b/apps/sim/app/api/tools/appconfig/utils.ts @@ -224,7 +224,7 @@ export async function createHostedConfigurationVersion( Content: new TextEncoder().encode(content), ContentType: contentType, ...(description ? { Description: description } : {}), - ...(latestVersionNumber ? { LatestVersionNumber: latestVersionNumber } : {}), + ...(latestVersionNumber != null ? { LatestVersionNumber: latestVersionNumber } : {}), ...(versionLabel ? { VersionLabel: versionLabel } : {}), }) ) diff --git a/apps/sim/tools/appconfig/types.ts b/apps/sim/tools/appconfig/types.ts index 5ede4963a99..e176e56a075 100644 --- a/apps/sim/tools/appconfig/types.ts +++ b/apps/sim/tools/appconfig/types.ts @@ -103,7 +103,7 @@ export interface AppConfigListConfigurationProfilesParams extends AppConfigConne export interface AppConfigCreateConfigurationProfileParams extends AppConfigConnectionConfig { applicationId: string name: string - locationUri?: string | null + locationUri: string description?: string | null retrievalRoleArn?: string | null type?: string | null From cd186f8d55087df4f9dc7f3c6ad60723293f5c11 Mon Sep 17 00:00:00 2001 From: waleed Date: Tue, 9 Jun 2026 11:49:47 -0700 Subject: [PATCH 3/6] fix(integrations): use valid IntegrationTag values in AppConfig BlockMeta --- apps/sim/blocks/blocks/appconfig.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/sim/blocks/blocks/appconfig.ts b/apps/sim/blocks/blocks/appconfig.ts index f3dc3fc0ca9..5dce699bd51 100644 --- a/apps/sim/blocks/blocks/appconfig.ts +++ b/apps/sim/blocks/blocks/appconfig.ts @@ -467,7 +467,7 @@ export const AppConfigBlock: BlockConfig< } export const AppConfigBlockMeta = { - tags: ['cloud', 'configuration', 'feature-flags'], + tags: ['cloud', 'feature-flags', 'automation'], templates: [ { icon: AppConfigIcon, From af483504adf346436cb2430e4925d3b4c3e4097e Mon Sep 17 00:00:00 2001 From: Theodore Li Date: Tue, 9 Jun 2026 11:58:40 -0700 Subject: [PATCH 4/6] feat(appconfig): add list_hosted_configuration_versions operation --- apps/docs/content/docs/en/tools/appconfig.mdx | 31 ++++ .../route.ts | 61 ++++++++ apps/sim/app/api/tools/appconfig/utils.ts | 33 +++++ apps/sim/blocks/blocks/appconfig.ts | 14 ++ ...nfig-list-hosted-configuration-versions.ts | 48 +++++++ apps/sim/lib/integrations/integrations.json | 8 +- apps/sim/tools/appconfig/index.ts | 2 + .../list_hosted_configuration_versions.ts | 132 ++++++++++++++++++ apps/sim/tools/appconfig/types.ts | 25 ++++ apps/sim/tools/registry.ts | 2 + scripts/check-api-validation-contracts.ts | 4 +- 11 files changed, 356 insertions(+), 4 deletions(-) create mode 100644 apps/sim/app/api/tools/appconfig/list-hosted-configuration-versions/route.ts create mode 100644 apps/sim/lib/api/contracts/tools/aws/appconfig-list-hosted-configuration-versions.ts create mode 100644 apps/sim/tools/appconfig/list_hosted_configuration_versions.ts diff --git a/apps/docs/content/docs/en/tools/appconfig.mdx b/apps/docs/content/docs/en/tools/appconfig.mdx index 4f5907e7958..4141ef07562 100644 --- a/apps/docs/content/docs/en/tools/appconfig.mdx +++ b/apps/docs/content/docs/en/tools/appconfig.mdx @@ -27,6 +27,7 @@ In Sim, the AppConfig integration lets your agents read live configuration to br Authentication uses an AWS access key ID and secret access key. The associated IAM principal needs the relevant `appconfig:*` permissions (for example `appconfig:GetLatestConfiguration` and `appconfig:StartConfigurationSession` for retrieval, and `appconfig:StartDeployment` for rollouts). {/* MANUAL-CONTENT-END */} + ## Usage Instructions Integrate AWS AppConfig into workflows. Manage applications, environments, and configuration profiles, create and read hosted configuration versions, run and inspect deployments, and retrieve the latest deployed configuration at runtime. Requires AWS access key and secret access key. @@ -274,6 +275,36 @@ Retrieve a specific hosted configuration version from an AppConfig profile | `contentType` | string | Content type of the configuration | | `versionLabel` | string | Label of the configuration version | +### `appconfig_list_hosted_configuration_versions` + +List hosted configuration versions for an AWS AppConfig configuration profile + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `region` | string | Yes | AWS region \(e.g., us-east-1\) | +| `accessKeyId` | string | Yes | AWS access key ID | +| `secretAccessKey` | string | Yes | AWS secret access key | +| `applicationId` | string | Yes | The application ID that owns the configuration profile | +| `configurationProfileId` | string | Yes | The configuration profile ID to list versions for | +| `maxResults` | number | No | Maximum number of versions to return \(1-50\) | +| `nextToken` | string | No | Pagination token from a previous response | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `versions` | array | List of hosted configuration versions | +| ↳ `applicationId` | string | Owning application ID | +| ↳ `configurationProfileId` | string | Owning configuration profile ID | +| ↳ `versionNumber` | number | Version number | +| ↳ `description` | string | Description of the version | +| ↳ `contentType` | string | Content type of the configuration | +| ↳ `versionLabel` | string | Label of the configuration version | +| `nextToken` | string | Pagination token for the next page | +| `count` | number | Number of versions returned | + ### `appconfig_list_deployment_strategies` List deployment strategies available in AWS AppConfig diff --git a/apps/sim/app/api/tools/appconfig/list-hosted-configuration-versions/route.ts b/apps/sim/app/api/tools/appconfig/list-hosted-configuration-versions/route.ts new file mode 100644 index 00000000000..9db3d331902 --- /dev/null +++ b/apps/sim/app/api/tools/appconfig/list-hosted-configuration-versions/route.ts @@ -0,0 +1,61 @@ +import { createLogger } from '@sim/logger' +import { getErrorMessage } from '@sim/utils/errors' +import { generateId } from '@sim/utils/id' +import { type NextRequest, NextResponse } from 'next/server' +import { awsAppConfigListHostedConfigurationVersionsContract } from '@/lib/api/contracts/tools/aws/appconfig-list-hosted-configuration-versions' +import { parseToolRequest } from '@/lib/api/server' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { withRouteHandler } from '@/lib/core/utils/with-route-handler' +import { createAppConfigClient, listHostedConfigurationVersions } from '../utils' + +const logger = createLogger('AppConfigListHostedConfigurationVersionsAPI') + +export const POST = withRouteHandler(async (request: NextRequest) => { + const requestId = generateId().slice(0, 8) + + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + try { + const parsed = await parseToolRequest( + awsAppConfigListHostedConfigurationVersionsContract, + request, + { errorFormat: 'details', logger } + ) + if (!parsed.success) return parsed.response + const params = parsed.data.body + + logger.info( + `[${requestId}] Listing AppConfig hosted configuration versions for profile ${params.configurationProfileId}` + ) + + const client = createAppConfigClient({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + }) + + try { + const result = await listHostedConfigurationVersions( + client, + params.applicationId, + params.configurationProfileId, + params.maxResults, + params.nextToken + ) + logger.info(`[${requestId}] Listed ${result.count} hosted configuration versions`) + return NextResponse.json(result) + } finally { + client.destroy() + } + } catch (error) { + const errorMessage = getErrorMessage(error, 'Unknown error occurred') + logger.error(`[${requestId}] Failed to list hosted configuration versions:`, error) + return NextResponse.json( + { error: `Failed to list hosted configuration versions: ${errorMessage}` }, + { status: 500 } + ) + } +}) diff --git a/apps/sim/app/api/tools/appconfig/utils.ts b/apps/sim/app/api/tools/appconfig/utils.ts index 7820f4f9eb3..dcf4b478ac7 100644 --- a/apps/sim/app/api/tools/appconfig/utils.ts +++ b/apps/sim/app/api/tools/appconfig/utils.ts @@ -11,6 +11,7 @@ import { ListDeploymentStrategiesCommand, ListDeploymentsCommand, ListEnvironmentsCommand, + ListHostedConfigurationVersionsCommand, StartDeploymentCommand, StopDeploymentCommand, } from '@aws-sdk/client-appconfig' @@ -264,6 +265,38 @@ export async function getHostedConfigurationVersion( } } +export async function listHostedConfigurationVersions( + client: AppConfigClient, + applicationId: string, + configurationProfileId: string, + maxResults?: number | null, + nextToken?: string | null +) { + const response = await client.send( + new ListHostedConfigurationVersionsCommand({ + ApplicationId: applicationId, + ConfigurationProfileId: configurationProfileId, + ...(maxResults ? { MaxResults: maxResults } : {}), + ...(nextToken ? { NextToken: nextToken } : {}), + }) + ) + + const versions = (response.Items ?? []).map((item) => ({ + applicationId: item.ApplicationId ?? null, + configurationProfileId: item.ConfigurationProfileId ?? null, + versionNumber: item.VersionNumber ?? null, + description: item.Description ?? null, + contentType: item.ContentType ?? null, + versionLabel: item.VersionLabel ?? null, + })) + + return { + versions, + nextToken: response.NextToken ?? null, + count: versions.length, + } +} + export async function listDeploymentStrategies( client: AppConfigClient, maxResults?: number | null, diff --git a/apps/sim/blocks/blocks/appconfig.ts b/apps/sim/blocks/blocks/appconfig.ts index 5dce699bd51..daa02ef661b 100644 --- a/apps/sim/blocks/blocks/appconfig.ts +++ b/apps/sim/blocks/blocks/appconfig.ts @@ -38,6 +38,10 @@ export const AppConfigBlock: BlockConfig< id: 'create_hosted_configuration_version', }, { label: 'Get Hosted Configuration Version', id: 'get_hosted_configuration_version' }, + { + label: 'List Hosted Configuration Versions', + id: 'list_hosted_configuration_versions', + }, { label: 'List Deployment Strategies', id: 'list_deployment_strategies' }, { label: 'Start Deployment', id: 'start_deployment' }, { label: 'Get Deployment', id: 'get_deployment' }, @@ -83,6 +87,7 @@ export const AppConfigBlock: BlockConfig< 'create_configuration_profile', 'create_hosted_configuration_version', 'get_hosted_configuration_version', + 'list_hosted_configuration_versions', 'start_deployment', 'get_deployment', 'list_deployments', @@ -99,6 +104,7 @@ export const AppConfigBlock: BlockConfig< 'create_configuration_profile', 'create_hosted_configuration_version', 'get_hosted_configuration_version', + 'list_hosted_configuration_versions', 'start_deployment', 'get_deployment', 'list_deployments', @@ -143,6 +149,7 @@ export const AppConfigBlock: BlockConfig< value: [ 'create_hosted_configuration_version', 'get_hosted_configuration_version', + 'list_hosted_configuration_versions', 'start_deployment', 'get_configuration', ], @@ -152,6 +159,7 @@ export const AppConfigBlock: BlockConfig< value: [ 'create_hosted_configuration_version', 'get_hosted_configuration_version', + 'list_hosted_configuration_versions', 'start_deployment', 'get_configuration', ], @@ -298,6 +306,7 @@ export const AppConfigBlock: BlockConfig< 'list_configuration_profiles', 'list_deployment_strategies', 'list_deployments', + 'list_hosted_configuration_versions', ], }, required: false, @@ -316,6 +325,7 @@ export const AppConfigBlock: BlockConfig< 'list_configuration_profiles', 'list_deployment_strategies', 'list_deployments', + 'list_hosted_configuration_versions', ], }, required: false, @@ -333,6 +343,7 @@ export const AppConfigBlock: BlockConfig< 'appconfig_create_configuration_profile', 'appconfig_create_hosted_configuration_version', 'appconfig_get_hosted_configuration_version', + 'appconfig_list_hosted_configuration_versions', 'appconfig_list_deployment_strategies', 'appconfig_start_deployment', 'appconfig_get_deployment', @@ -360,6 +371,8 @@ export const AppConfigBlock: BlockConfig< return 'appconfig_create_hosted_configuration_version' case 'get_hosted_configuration_version': return 'appconfig_get_hosted_configuration_version' + case 'list_hosted_configuration_versions': + return 'appconfig_list_hosted_configuration_versions' case 'list_deployment_strategies': return 'appconfig_list_deployment_strategies' case 'start_deployment': @@ -461,6 +474,7 @@ export const AppConfigBlock: BlockConfig< configurationProfiles: { type: 'json', description: 'List of configuration profiles' }, deploymentStrategies: { type: 'json', description: 'List of deployment strategies' }, deployments: { type: 'json', description: 'List of deployments' }, + versions: { type: 'json', description: 'List of hosted configuration versions' }, nextToken: { type: 'string', description: 'Pagination token for the next page' }, count: { type: 'number', description: 'Number of items returned' }, }, diff --git a/apps/sim/lib/api/contracts/tools/aws/appconfig-list-hosted-configuration-versions.ts b/apps/sim/lib/api/contracts/tools/aws/appconfig-list-hosted-configuration-versions.ts new file mode 100644 index 00000000000..f51b15fcd12 --- /dev/null +++ b/apps/sim/lib/api/contracts/tools/aws/appconfig-list-hosted-configuration-versions.ts @@ -0,0 +1,48 @@ +import { z } from 'zod' +import type { + ContractBody, + ContractBodyInput, + ContractJsonResponse, +} from '@/lib/api/contracts/types' +import { defineRouteContract } from '@/lib/api/contracts/types' + +const ListHostedConfigurationVersionsSchema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + applicationId: z.string().min(1, 'Application ID is required'), + configurationProfileId: z.string().min(1, 'Configuration profile ID is required'), + maxResults: z.number().int().min(1).max(50).nullish(), + nextToken: z.string().nullish(), +}) + +const HostedConfigurationVersionSummarySchema = z.object({ + applicationId: z.string().nullable(), + configurationProfileId: z.string().nullable(), + versionNumber: z.number().nullable(), + description: z.string().nullable(), + contentType: z.string().nullable(), + versionLabel: z.string().nullable(), +}) + +const ListHostedConfigurationVersionsResponseSchema = z.object({ + versions: z.array(HostedConfigurationVersionSummarySchema), + nextToken: z.string().nullable(), + count: z.number(), +}) + +export const awsAppConfigListHostedConfigurationVersionsContract = defineRouteContract({ + method: 'POST', + path: '/api/tools/appconfig/list-hosted-configuration-versions', + body: ListHostedConfigurationVersionsSchema, + response: { mode: 'json', schema: ListHostedConfigurationVersionsResponseSchema }, +}) +export type AwsAppConfigListHostedConfigurationVersionsRequest = ContractBodyInput< + typeof awsAppConfigListHostedConfigurationVersionsContract +> +export type AwsAppConfigListHostedConfigurationVersionsBody = ContractBody< + typeof awsAppConfigListHostedConfigurationVersionsContract +> +export type AwsAppConfigListHostedConfigurationVersionsResponse = ContractJsonResponse< + typeof awsAppConfigListHostedConfigurationVersionsContract +> diff --git a/apps/sim/lib/integrations/integrations.json b/apps/sim/lib/integrations/integrations.json index c0b36749225..339448cfa44 100644 --- a/apps/sim/lib/integrations/integrations.json +++ b/apps/sim/lib/integrations/integrations.json @@ -1501,6 +1501,10 @@ "name": "Get Hosted Configuration Version", "description": "Retrieve a specific hosted configuration version from an AppConfig profile" }, + { + "name": "List Hosted Configuration Versions", + "description": "List hosted configuration versions for an AWS AppConfig configuration profile" + }, { "name": "List Deployment Strategies", "description": "List deployment strategies available in AWS AppConfig" @@ -1522,13 +1526,13 @@ "description": "Stop an in-progress AWS AppConfig deployment" } ], - "operationCount": 14, + "operationCount": 15, "triggers": [], "triggerCount": 0, "authType": "api-key", "category": "tools", "integrationType": "devops", - "tags": ["cloud", "configuration", "feature-flags"] + "tags": ["cloud", "feature-flags", "automation"] }, { "type": "iam", diff --git a/apps/sim/tools/appconfig/index.ts b/apps/sim/tools/appconfig/index.ts index 7ec5c39b9d5..1c6fd7dc4d8 100644 --- a/apps/sim/tools/appconfig/index.ts +++ b/apps/sim/tools/appconfig/index.ts @@ -10,6 +10,7 @@ import { listConfigurationProfilesTool } from './list_configuration_profiles' import { listDeploymentStrategiesTool } from './list_deployment_strategies' import { listDeploymentsTool } from './list_deployments' import { listEnvironmentsTool } from './list_environments' +import { listHostedConfigurationVersionsTool } from './list_hosted_configuration_versions' import { startDeploymentTool } from './start_deployment' import { stopDeploymentTool } from './stop_deployment' @@ -21,6 +22,7 @@ export const appConfigListConfigurationProfilesTool = listConfigurationProfilesT export const appConfigCreateConfigurationProfileTool = createConfigurationProfileTool export const appConfigCreateHostedConfigurationVersionTool = createHostedConfigurationVersionTool export const appConfigGetHostedConfigurationVersionTool = getHostedConfigurationVersionTool +export const appConfigListHostedConfigurationVersionsTool = listHostedConfigurationVersionsTool export const appConfigListDeploymentStrategiesTool = listDeploymentStrategiesTool export const appConfigStartDeploymentTool = startDeploymentTool export const appConfigGetDeploymentTool = getDeploymentTool diff --git a/apps/sim/tools/appconfig/list_hosted_configuration_versions.ts b/apps/sim/tools/appconfig/list_hosted_configuration_versions.ts new file mode 100644 index 00000000000..d94f88c4aa9 --- /dev/null +++ b/apps/sim/tools/appconfig/list_hosted_configuration_versions.ts @@ -0,0 +1,132 @@ +import type { + AppConfigListHostedConfigurationVersionsParams, + AppConfigListHostedConfigurationVersionsResponse, +} from '@/tools/appconfig/types' +import type { ToolConfig } from '@/tools/types' + +export const listHostedConfigurationVersionsTool: ToolConfig< + AppConfigListHostedConfigurationVersionsParams, + AppConfigListHostedConfigurationVersionsResponse +> = { + id: 'appconfig_list_hosted_configuration_versions', + name: 'AppConfig List Hosted Configuration Versions', + description: 'List hosted configuration versions for an AWS AppConfig configuration profile', + version: '1.0', + + params: { + region: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + accessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + secretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + applicationId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The application ID that owns the configuration profile', + }, + configurationProfileId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The configuration profile ID to list versions for', + }, + maxResults: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Maximum number of versions to return (1-50)', + }, + nextToken: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Pagination token from a previous response', + }, + }, + + request: { + url: '/api/tools/appconfig/list-hosted-configuration-versions', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + applicationId: params.applicationId, + configurationProfileId: params.configurationProfileId, + maxResults: params.maxResults, + nextToken: params.nextToken, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || 'Failed to list AppConfig hosted configuration versions') + } + + return { + success: true, + output: { + versions: data.versions ?? [], + nextToken: data.nextToken ?? null, + count: data.count ?? 0, + }, + } + }, + + outputs: { + versions: { + type: 'array', + description: 'List of hosted configuration versions', + items: { + type: 'object', + properties: { + applicationId: { type: 'string', description: 'Owning application ID', optional: true }, + configurationProfileId: { + type: 'string', + description: 'Owning configuration profile ID', + optional: true, + }, + versionNumber: { type: 'number', description: 'Version number', optional: true }, + description: { + type: 'string', + description: 'Description of the version', + optional: true, + }, + contentType: { + type: 'string', + description: 'Content type of the configuration', + optional: true, + }, + versionLabel: { + type: 'string', + description: 'Label of the configuration version', + optional: true, + }, + }, + }, + }, + nextToken: { + type: 'string', + description: 'Pagination token for the next page', + optional: true, + }, + count: { type: 'number', description: 'Number of versions returned' }, + }, +} diff --git a/apps/sim/tools/appconfig/types.ts b/apps/sim/tools/appconfig/types.ts index e176e56a075..ea752b75d8f 100644 --- a/apps/sim/tools/appconfig/types.ts +++ b/apps/sim/tools/appconfig/types.ts @@ -72,6 +72,15 @@ export interface AppConfigDeploymentStrategy { replicateTo: string | null } +export interface AppConfigHostedConfigurationVersionSummary { + applicationId: string | null + configurationProfileId: string | null + versionNumber: number | null + description: string | null + contentType: string | null + versionLabel: string | null +} + export interface AppConfigListApplicationsParams extends AppConfigConnectionConfig { maxResults?: number | null nextToken?: string | null @@ -125,6 +134,13 @@ export interface AppConfigGetHostedConfigurationVersionParams extends AppConfigC versionNumber: number } +export interface AppConfigListHostedConfigurationVersionsParams extends AppConfigConnectionConfig { + applicationId: string + configurationProfileId: string + maxResults?: number | null + nextToken?: string | null +} + export interface AppConfigListDeploymentStrategiesParams extends AppConfigConnectionConfig { maxResults?: number | null nextToken?: string | null @@ -258,6 +274,15 @@ export interface AppConfigListDeploymentStrategiesResponse extends ToolResponse error?: string } +export interface AppConfigListHostedConfigurationVersionsResponse extends ToolResponse { + output: { + versions: AppConfigHostedConfigurationVersionSummary[] + nextToken: string | null + count: number + } + error?: string +} + export interface AppConfigStartDeploymentResponse extends ToolResponse { output: { message: string diff --git a/apps/sim/tools/registry.ts b/apps/sim/tools/registry.ts index b2f97ee7dee..084f78c6007 100644 --- a/apps/sim/tools/registry.ts +++ b/apps/sim/tools/registry.ts @@ -168,6 +168,7 @@ import { appConfigListDeploymentStrategiesTool, appConfigListDeploymentsTool, appConfigListEnvironmentsTool, + appConfigListHostedConfigurationVersionsTool, appConfigStartDeploymentTool, appConfigStopDeploymentTool, } from '@/tools/appconfig' @@ -5260,6 +5261,7 @@ export const tools: Record = { appconfig_create_configuration_profile: appConfigCreateConfigurationProfileTool, appconfig_create_hosted_configuration_version: appConfigCreateHostedConfigurationVersionTool, appconfig_get_hosted_configuration_version: appConfigGetHostedConfigurationVersionTool, + appconfig_list_hosted_configuration_versions: appConfigListHostedConfigurationVersionsTool, appconfig_list_deployment_strategies: appConfigListDeploymentStrategiesTool, appconfig_start_deployment: appConfigStartDeploymentTool, appconfig_get_deployment: appConfigGetDeploymentTool, diff --git a/scripts/check-api-validation-contracts.ts b/scripts/check-api-validation-contracts.ts index 2dc563d040b..ffee3f53c83 100644 --- a/scripts/check-api-validation-contracts.ts +++ b/scripts/check-api-validation-contracts.ts @@ -9,8 +9,8 @@ const QUERY_HOOKS_DIR = path.join(ROOT, 'apps/sim/hooks/queries') const SELECTOR_HOOKS_DIR = path.join(ROOT, 'apps/sim/hooks/selectors') const BASELINE = { - totalRoutes: 793, - zodRoutes: 793, + totalRoutes: 794, + zodRoutes: 794, nonZodRoutes: 0, } as const From 7f5dcf159bd3bd50930421b893dac674b94d1f3d Mon Sep 17 00:00:00 2001 From: Theodore Li Date: Tue, 9 Jun 2026 12:03:45 -0700 Subject: [PATCH 5/6] fix(appconfig): stringify configurationVersion in block params --- apps/sim/blocks/blocks/appconfig.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/sim/blocks/blocks/appconfig.ts b/apps/sim/blocks/blocks/appconfig.ts index daa02ef661b..47ac7cfba28 100644 --- a/apps/sim/blocks/blocks/appconfig.ts +++ b/apps/sim/blocks/blocks/appconfig.ts @@ -394,6 +394,7 @@ export const AppConfigBlock: BlockConfig< versionNumber, deploymentNumber, latestVersionNumber, + configurationVersion, ...rest } = params @@ -405,6 +406,12 @@ export const AppConfigBlock: BlockConfig< return Number.isNaN(parsed) ? undefined : parsed } + // Stringify: a versionNumber piped from an upstream step resolves to a JSON number, + // but AppConfig's ConfigurationVersion (version number or label) must be a string. + if (configurationVersion !== undefined && configurationVersion !== null) { + result.configurationVersion = String(configurationVersion) + } + const maxResultsInt = toInt(maxResults) if (maxResultsInt !== undefined) result.maxResults = maxResultsInt From 34fa181e33e8e819f50841ef4249da4efa5841e1 Mon Sep 17 00:00:00 2001 From: waleed Date: Tue, 9 Jun 2026 12:43:21 -0700 Subject: [PATCH 6/6] feat(appconfig): add full CRUD for applications, environments, and configuration profiles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds get/update/delete for applications, environments, and configuration profiles, plus delete_hosted_configuration_version — 10 tools rounding out the integration to management-grade CRUD completeness. --- apps/docs/content/docs/en/tools/appconfig.mdx | 242 ++++++++++++++++++ .../appconfig/delete-application/route.ts | 52 ++++ .../delete-configuration-profile/route.ts | 58 +++++ .../appconfig/delete-environment/route.ts | 52 ++++ .../route.ts | 60 +++++ .../tools/appconfig/get-application/route.ts | 52 ++++ .../get-configuration-profile/route.ts | 58 +++++ .../tools/appconfig/get-environment/route.ts | 52 ++++ .../appconfig/update-application/route.ts | 57 +++++ .../update-configuration-profile/route.ts | 61 +++++ .../appconfig/update-environment/route.ts | 58 +++++ apps/sim/app/api/tools/appconfig/utils.ts | 209 +++++++++++++++ apps/sim/blocks/blocks/appconfig.ts | 107 +++++++- .../tools/aws/appconfig-delete-application.ts | 35 +++ .../appconfig-delete-configuration-profile.ts | 37 +++ .../tools/aws/appconfig-delete-environment.ts | 37 +++ ...fig-delete-hosted-configuration-version.ts | 39 +++ .../tools/aws/appconfig-get-application.ts | 34 +++ .../appconfig-get-configuration-profile.ts | 42 +++ .../tools/aws/appconfig-get-environment.ts | 43 ++++ .../tools/aws/appconfig-update-application.ts | 39 +++ .../appconfig-update-configuration-profile.ts | 43 ++++ .../tools/aws/appconfig-update-environment.ts | 41 +++ apps/sim/lib/integrations/integrations.json | 42 ++- .../sim/tools/appconfig/delete_application.ts | 75 ++++++ .../appconfig/delete_configuration_profile.ts | 84 ++++++ .../sim/tools/appconfig/delete_environment.ts | 84 ++++++ .../delete_hosted_configuration_version.ts | 93 +++++++ apps/sim/tools/appconfig/get_application.ts | 77 ++++++ .../appconfig/get_configuration_profile.ts | 103 ++++++++ apps/sim/tools/appconfig/get_environment.ts | 104 ++++++++ apps/sim/tools/appconfig/index.ts | 20 ++ apps/sim/tools/appconfig/types.ts | 142 ++++++++++ .../sim/tools/appconfig/update_application.ts | 97 +++++++ .../appconfig/update_configuration_profile.ts | 112 ++++++++ .../sim/tools/appconfig/update_environment.ts | 102 ++++++++ apps/sim/tools/registry.ts | 20 ++ scripts/check-api-validation-contracts.ts | 4 +- 38 files changed, 2660 insertions(+), 7 deletions(-) create mode 100644 apps/sim/app/api/tools/appconfig/delete-application/route.ts create mode 100644 apps/sim/app/api/tools/appconfig/delete-configuration-profile/route.ts create mode 100644 apps/sim/app/api/tools/appconfig/delete-environment/route.ts create mode 100644 apps/sim/app/api/tools/appconfig/delete-hosted-configuration-version/route.ts create mode 100644 apps/sim/app/api/tools/appconfig/get-application/route.ts create mode 100644 apps/sim/app/api/tools/appconfig/get-configuration-profile/route.ts create mode 100644 apps/sim/app/api/tools/appconfig/get-environment/route.ts create mode 100644 apps/sim/app/api/tools/appconfig/update-application/route.ts create mode 100644 apps/sim/app/api/tools/appconfig/update-configuration-profile/route.ts create mode 100644 apps/sim/app/api/tools/appconfig/update-environment/route.ts create mode 100644 apps/sim/lib/api/contracts/tools/aws/appconfig-delete-application.ts create mode 100644 apps/sim/lib/api/contracts/tools/aws/appconfig-delete-configuration-profile.ts create mode 100644 apps/sim/lib/api/contracts/tools/aws/appconfig-delete-environment.ts create mode 100644 apps/sim/lib/api/contracts/tools/aws/appconfig-delete-hosted-configuration-version.ts create mode 100644 apps/sim/lib/api/contracts/tools/aws/appconfig-get-application.ts create mode 100644 apps/sim/lib/api/contracts/tools/aws/appconfig-get-configuration-profile.ts create mode 100644 apps/sim/lib/api/contracts/tools/aws/appconfig-get-environment.ts create mode 100644 apps/sim/lib/api/contracts/tools/aws/appconfig-update-application.ts create mode 100644 apps/sim/lib/api/contracts/tools/aws/appconfig-update-configuration-profile.ts create mode 100644 apps/sim/lib/api/contracts/tools/aws/appconfig-update-environment.ts create mode 100644 apps/sim/tools/appconfig/delete_application.ts create mode 100644 apps/sim/tools/appconfig/delete_configuration_profile.ts create mode 100644 apps/sim/tools/appconfig/delete_environment.ts create mode 100644 apps/sim/tools/appconfig/delete_hosted_configuration_version.ts create mode 100644 apps/sim/tools/appconfig/get_application.ts create mode 100644 apps/sim/tools/appconfig/get_configuration_profile.ts create mode 100644 apps/sim/tools/appconfig/get_environment.ts create mode 100644 apps/sim/tools/appconfig/update_application.ts create mode 100644 apps/sim/tools/appconfig/update_configuration_profile.ts create mode 100644 apps/sim/tools/appconfig/update_environment.ts diff --git a/apps/docs/content/docs/en/tools/appconfig.mdx b/apps/docs/content/docs/en/tools/appconfig.mdx index 4141ef07562..4d0fe57fffe 100644 --- a/apps/docs/content/docs/en/tools/appconfig.mdx +++ b/apps/docs/content/docs/en/tools/appconfig.mdx @@ -107,6 +107,71 @@ Create an application in AWS AppConfig | `name` | string | Name of the created application | | `description` | string | Description of the created application | +### `appconfig_get_application` + +Get details about a single AWS AppConfig application + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `region` | string | Yes | AWS region \(e.g., us-east-1\) | +| `accessKeyId` | string | Yes | AWS access key ID | +| `secretAccessKey` | string | Yes | AWS secret access key | +| `applicationId` | string | Yes | The application ID to retrieve | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `id` | string | Application ID | +| `name` | string | Application name | +| `description` | string | Application description | + +### `appconfig_update_application` + +Update the name or description of an AWS AppConfig application + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `region` | string | Yes | AWS region \(e.g., us-east-1\) | +| `accessKeyId` | string | Yes | AWS access key ID | +| `secretAccessKey` | string | Yes | AWS secret access key | +| `applicationId` | string | Yes | The application ID to update | +| `name` | string | No | New name for the application | +| `description` | string | No | New description for the application | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `message` | string | Operation status message | +| `id` | string | ID of the updated application | +| `name` | string | Name of the updated application | +| `description` | string | Description of the updated application | + +### `appconfig_delete_application` + +Delete an AWS AppConfig application + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `region` | string | Yes | AWS region \(e.g., us-east-1\) | +| `accessKeyId` | string | Yes | AWS access key ID | +| `secretAccessKey` | string | Yes | AWS secret access key | +| `applicationId` | string | Yes | The application ID to delete | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `message` | string | Operation status message | +| `id` | string | ID of the deleted application | + ### `appconfig_list_environments` List environments for an AWS AppConfig application @@ -160,6 +225,81 @@ Create an environment for an AWS AppConfig application | `name` | string | Name of the created environment | | `state` | string | State of the created environment | +### `appconfig_get_environment` + +Get details about a single AWS AppConfig environment + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `region` | string | Yes | AWS region \(e.g., us-east-1\) | +| `accessKeyId` | string | Yes | AWS access key ID | +| `secretAccessKey` | string | Yes | AWS secret access key | +| `applicationId` | string | Yes | The application ID that owns the environment | +| `environmentId` | string | Yes | The environment ID to retrieve | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `applicationId` | string | Owning application ID | +| `id` | string | Environment ID | +| `name` | string | Environment name | +| `description` | string | Environment description | +| `state` | string | Environment state | +| `monitors` | array | CloudWatch alarms monitoring this environment | +| ↳ `alarmArn` | string | CloudWatch alarm ARN | +| ↳ `alarmRoleArn` | string | IAM role ARN for the alarm | + +### `appconfig_update_environment` + +Update the name or description of an AWS AppConfig environment + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `region` | string | Yes | AWS region \(e.g., us-east-1\) | +| `accessKeyId` | string | Yes | AWS access key ID | +| `secretAccessKey` | string | Yes | AWS secret access key | +| `applicationId` | string | Yes | The application ID that owns the environment | +| `environmentId` | string | Yes | The environment ID to update | +| `name` | string | No | New name for the environment | +| `description` | string | No | New description for the environment | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `message` | string | Operation status message | +| `applicationId` | string | Owning application ID | +| `id` | string | ID of the updated environment | +| `name` | string | Name of the updated environment | +| `state` | string | State of the updated environment | + +### `appconfig_delete_environment` + +Delete an AWS AppConfig environment + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `region` | string | Yes | AWS region \(e.g., us-east-1\) | +| `accessKeyId` | string | Yes | AWS access key ID | +| `secretAccessKey` | string | Yes | AWS secret access key | +| `applicationId` | string | Yes | The application ID that owns the environment | +| `environmentId` | string | Yes | The environment ID to delete | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `message` | string | Operation status message | +| `applicationId` | string | Owning application ID | +| `id` | string | ID of the deleted environment | + ### `appconfig_list_configuration_profiles` List configuration profiles for an AWS AppConfig application @@ -218,6 +358,84 @@ Create a configuration profile in an AWS AppConfig application | `locationUri` | string | Location URI of the config | | `type` | string | Profile type | +### `appconfig_get_configuration_profile` + +Get details about a single AWS AppConfig configuration profile + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `region` | string | Yes | AWS region \(e.g., us-east-1\) | +| `accessKeyId` | string | Yes | AWS access key ID | +| `secretAccessKey` | string | Yes | AWS secret access key | +| `applicationId` | string | Yes | The application ID that owns the configuration profile | +| `configurationProfileId` | string | Yes | The configuration profile ID to retrieve | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `applicationId` | string | Owning application ID | +| `id` | string | Configuration profile ID | +| `name` | string | Configuration profile name | +| `description` | string | Profile description | +| `locationUri` | string | Location URI of the config | +| `retrievalRoleArn` | string | IAM retrieval role ARN | +| `type` | string | Profile type \(e.g., AWS.Freeform\) | +| `validators` | array | Validators configured on the profile | +| ↳ `type` | string | Validator type \(JSON_SCHEMA or LAMBDA\) | + +### `appconfig_update_configuration_profile` + +Update the name, description, or retrieval role of an AppConfig configuration profile + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `region` | string | Yes | AWS region \(e.g., us-east-1\) | +| `accessKeyId` | string | Yes | AWS access key ID | +| `secretAccessKey` | string | Yes | AWS secret access key | +| `applicationId` | string | Yes | The application ID that owns the configuration profile | +| `configurationProfileId` | string | Yes | The configuration profile ID to update | +| `name` | string | No | New name for the configuration profile | +| `description` | string | No | New description for the configuration profile | +| `retrievalRoleArn` | string | No | New ARN of the IAM role used to retrieve the configuration | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `message` | string | Operation status message | +| `applicationId` | string | Owning application ID | +| `id` | string | ID of the updated configuration profile | +| `name` | string | Name of the updated configuration profile | +| `description` | string | Description of the profile | +| `type` | string | Profile type | + +### `appconfig_delete_configuration_profile` + +Delete an AWS AppConfig configuration profile + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `region` | string | Yes | AWS region \(e.g., us-east-1\) | +| `accessKeyId` | string | Yes | AWS access key ID | +| `secretAccessKey` | string | Yes | AWS secret access key | +| `applicationId` | string | Yes | The application ID that owns the configuration profile | +| `configurationProfileId` | string | Yes | The configuration profile ID to delete | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `message` | string | Operation status message | +| `applicationId` | string | Owning application ID | +| `id` | string | ID of the deleted configuration profile | + ### `appconfig_create_hosted_configuration_version` Create a new hosted configuration version for an AppConfig configuration profile @@ -305,6 +523,30 @@ List hosted configuration versions for an AWS AppConfig configuration profile | `nextToken` | string | Pagination token for the next page | | `count` | number | Number of versions returned | +### `appconfig_delete_hosted_configuration_version` + +Delete a specific hosted configuration version from an AppConfig profile + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `region` | string | Yes | AWS region \(e.g., us-east-1\) | +| `accessKeyId` | string | Yes | AWS access key ID | +| `secretAccessKey` | string | Yes | AWS secret access key | +| `applicationId` | string | Yes | The application ID that owns the configuration profile | +| `configurationProfileId` | string | Yes | The configuration profile ID that owns the version | +| `versionNumber` | number | Yes | The version number to delete | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `message` | string | Operation status message | +| `applicationId` | string | Owning application ID | +| `configurationProfileId` | string | Owning configuration profile ID | +| `versionNumber` | number | Version number that was deleted | + ### `appconfig_list_deployment_strategies` List deployment strategies available in AWS AppConfig diff --git a/apps/sim/app/api/tools/appconfig/delete-application/route.ts b/apps/sim/app/api/tools/appconfig/delete-application/route.ts new file mode 100644 index 00000000000..3e7c8929d49 --- /dev/null +++ b/apps/sim/app/api/tools/appconfig/delete-application/route.ts @@ -0,0 +1,52 @@ +import { createLogger } from '@sim/logger' +import { getErrorMessage } from '@sim/utils/errors' +import { generateId } from '@sim/utils/id' +import { type NextRequest, NextResponse } from 'next/server' +import { awsAppConfigDeleteApplicationContract } from '@/lib/api/contracts/tools/aws/appconfig-delete-application' +import { parseToolRequest } from '@/lib/api/server' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { withRouteHandler } from '@/lib/core/utils/with-route-handler' +import { createAppConfigClient, deleteApplication } from '../utils' + +const logger = createLogger('AppConfigDeleteApplicationAPI') + +export const POST = withRouteHandler(async (request: NextRequest) => { + const requestId = generateId().slice(0, 8) + + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + try { + const parsed = await parseToolRequest(awsAppConfigDeleteApplicationContract, request, { + errorFormat: 'details', + logger, + }) + if (!parsed.success) return parsed.response + const params = parsed.data.body + + logger.info(`[${requestId}] Deleting AppConfig application ${params.applicationId}`) + + const client = createAppConfigClient({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + }) + + try { + const result = await deleteApplication(client, params.applicationId) + logger.info(`[${requestId}] Deleted application`) + return NextResponse.json(result) + } finally { + client.destroy() + } + } catch (error) { + const errorMessage = getErrorMessage(error, 'Unknown error occurred') + logger.error(`[${requestId}] Failed to delete application:`, error) + return NextResponse.json( + { error: `Failed to delete application: ${errorMessage}` }, + { status: 500 } + ) + } +}) diff --git a/apps/sim/app/api/tools/appconfig/delete-configuration-profile/route.ts b/apps/sim/app/api/tools/appconfig/delete-configuration-profile/route.ts new file mode 100644 index 00000000000..202ca4886cd --- /dev/null +++ b/apps/sim/app/api/tools/appconfig/delete-configuration-profile/route.ts @@ -0,0 +1,58 @@ +import { createLogger } from '@sim/logger' +import { getErrorMessage } from '@sim/utils/errors' +import { generateId } from '@sim/utils/id' +import { type NextRequest, NextResponse } from 'next/server' +import { awsAppConfigDeleteConfigurationProfileContract } from '@/lib/api/contracts/tools/aws/appconfig-delete-configuration-profile' +import { parseToolRequest } from '@/lib/api/server' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { withRouteHandler } from '@/lib/core/utils/with-route-handler' +import { createAppConfigClient, deleteConfigurationProfile } from '../utils' + +const logger = createLogger('AppConfigDeleteConfigurationProfileAPI') + +export const POST = withRouteHandler(async (request: NextRequest) => { + const requestId = generateId().slice(0, 8) + + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + try { + const parsed = await parseToolRequest(awsAppConfigDeleteConfigurationProfileContract, request, { + errorFormat: 'details', + logger, + }) + if (!parsed.success) return parsed.response + const params = parsed.data.body + + logger.info( + `[${requestId}] Deleting AppConfig configuration profile ${params.configurationProfileId}` + ) + + const client = createAppConfigClient({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + }) + + try { + const result = await deleteConfigurationProfile( + client, + params.applicationId, + params.configurationProfileId + ) + logger.info(`[${requestId}] Deleted configuration profile`) + return NextResponse.json(result) + } finally { + client.destroy() + } + } catch (error) { + const errorMessage = getErrorMessage(error, 'Unknown error occurred') + logger.error(`[${requestId}] Failed to delete configuration profile:`, error) + return NextResponse.json( + { error: `Failed to delete configuration profile: ${errorMessage}` }, + { status: 500 } + ) + } +}) diff --git a/apps/sim/app/api/tools/appconfig/delete-environment/route.ts b/apps/sim/app/api/tools/appconfig/delete-environment/route.ts new file mode 100644 index 00000000000..5cbefc817ef --- /dev/null +++ b/apps/sim/app/api/tools/appconfig/delete-environment/route.ts @@ -0,0 +1,52 @@ +import { createLogger } from '@sim/logger' +import { getErrorMessage } from '@sim/utils/errors' +import { generateId } from '@sim/utils/id' +import { type NextRequest, NextResponse } from 'next/server' +import { awsAppConfigDeleteEnvironmentContract } from '@/lib/api/contracts/tools/aws/appconfig-delete-environment' +import { parseToolRequest } from '@/lib/api/server' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { withRouteHandler } from '@/lib/core/utils/with-route-handler' +import { createAppConfigClient, deleteEnvironment } from '../utils' + +const logger = createLogger('AppConfigDeleteEnvironmentAPI') + +export const POST = withRouteHandler(async (request: NextRequest) => { + const requestId = generateId().slice(0, 8) + + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + try { + const parsed = await parseToolRequest(awsAppConfigDeleteEnvironmentContract, request, { + errorFormat: 'details', + logger, + }) + if (!parsed.success) return parsed.response + const params = parsed.data.body + + logger.info(`[${requestId}] Deleting AppConfig environment ${params.environmentId}`) + + const client = createAppConfigClient({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + }) + + try { + const result = await deleteEnvironment(client, params.applicationId, params.environmentId) + logger.info(`[${requestId}] Deleted environment`) + return NextResponse.json(result) + } finally { + client.destroy() + } + } catch (error) { + const errorMessage = getErrorMessage(error, 'Unknown error occurred') + logger.error(`[${requestId}] Failed to delete environment:`, error) + return NextResponse.json( + { error: `Failed to delete environment: ${errorMessage}` }, + { status: 500 } + ) + } +}) diff --git a/apps/sim/app/api/tools/appconfig/delete-hosted-configuration-version/route.ts b/apps/sim/app/api/tools/appconfig/delete-hosted-configuration-version/route.ts new file mode 100644 index 00000000000..94f9d34b4ba --- /dev/null +++ b/apps/sim/app/api/tools/appconfig/delete-hosted-configuration-version/route.ts @@ -0,0 +1,60 @@ +import { createLogger } from '@sim/logger' +import { getErrorMessage } from '@sim/utils/errors' +import { generateId } from '@sim/utils/id' +import { type NextRequest, NextResponse } from 'next/server' +import { awsAppConfigDeleteHostedConfigurationVersionContract } from '@/lib/api/contracts/tools/aws/appconfig-delete-hosted-configuration-version' +import { parseToolRequest } from '@/lib/api/server' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { withRouteHandler } from '@/lib/core/utils/with-route-handler' +import { createAppConfigClient, deleteHostedConfigurationVersion } from '../utils' + +const logger = createLogger('AppConfigDeleteHostedConfigurationVersionAPI') + +export const POST = withRouteHandler(async (request: NextRequest) => { + const requestId = generateId().slice(0, 8) + + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + try { + const parsed = await parseToolRequest( + awsAppConfigDeleteHostedConfigurationVersionContract, + request, + { errorFormat: 'details', logger } + ) + if (!parsed.success) return parsed.response + const params = parsed.data.body + + logger.info( + `[${requestId}] Deleting hosted configuration version ${params.versionNumber} for profile ${params.configurationProfileId}` + ) + + const client = createAppConfigClient({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + }) + + try { + const result = await deleteHostedConfigurationVersion( + client, + params.applicationId, + params.configurationProfileId, + params.versionNumber + ) + logger.info(`[${requestId}] Deleted hosted configuration version`) + return NextResponse.json(result) + } finally { + client.destroy() + } + } catch (error) { + const errorMessage = getErrorMessage(error, 'Unknown error occurred') + logger.error(`[${requestId}] Failed to delete hosted configuration version:`, error) + return NextResponse.json( + { error: `Failed to delete hosted configuration version: ${errorMessage}` }, + { status: 500 } + ) + } +}) diff --git a/apps/sim/app/api/tools/appconfig/get-application/route.ts b/apps/sim/app/api/tools/appconfig/get-application/route.ts new file mode 100644 index 00000000000..ac1c0c86294 --- /dev/null +++ b/apps/sim/app/api/tools/appconfig/get-application/route.ts @@ -0,0 +1,52 @@ +import { createLogger } from '@sim/logger' +import { getErrorMessage } from '@sim/utils/errors' +import { generateId } from '@sim/utils/id' +import { type NextRequest, NextResponse } from 'next/server' +import { awsAppConfigGetApplicationContract } from '@/lib/api/contracts/tools/aws/appconfig-get-application' +import { parseToolRequest } from '@/lib/api/server' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { withRouteHandler } from '@/lib/core/utils/with-route-handler' +import { createAppConfigClient, getApplication } from '../utils' + +const logger = createLogger('AppConfigGetApplicationAPI') + +export const POST = withRouteHandler(async (request: NextRequest) => { + const requestId = generateId().slice(0, 8) + + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + try { + const parsed = await parseToolRequest(awsAppConfigGetApplicationContract, request, { + errorFormat: 'details', + logger, + }) + if (!parsed.success) return parsed.response + const params = parsed.data.body + + logger.info(`[${requestId}] Getting AppConfig application ${params.applicationId}`) + + const client = createAppConfigClient({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + }) + + try { + const result = await getApplication(client, params.applicationId) + logger.info(`[${requestId}] Retrieved application`) + return NextResponse.json(result) + } finally { + client.destroy() + } + } catch (error) { + const errorMessage = getErrorMessage(error, 'Unknown error occurred') + logger.error(`[${requestId}] Failed to get application:`, error) + return NextResponse.json( + { error: `Failed to get application: ${errorMessage}` }, + { status: 500 } + ) + } +}) diff --git a/apps/sim/app/api/tools/appconfig/get-configuration-profile/route.ts b/apps/sim/app/api/tools/appconfig/get-configuration-profile/route.ts new file mode 100644 index 00000000000..61d26098a98 --- /dev/null +++ b/apps/sim/app/api/tools/appconfig/get-configuration-profile/route.ts @@ -0,0 +1,58 @@ +import { createLogger } from '@sim/logger' +import { getErrorMessage } from '@sim/utils/errors' +import { generateId } from '@sim/utils/id' +import { type NextRequest, NextResponse } from 'next/server' +import { awsAppConfigGetConfigurationProfileContract } from '@/lib/api/contracts/tools/aws/appconfig-get-configuration-profile' +import { parseToolRequest } from '@/lib/api/server' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { withRouteHandler } from '@/lib/core/utils/with-route-handler' +import { createAppConfigClient, getConfigurationProfile } from '../utils' + +const logger = createLogger('AppConfigGetConfigurationProfileAPI') + +export const POST = withRouteHandler(async (request: NextRequest) => { + const requestId = generateId().slice(0, 8) + + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + try { + const parsed = await parseToolRequest(awsAppConfigGetConfigurationProfileContract, request, { + errorFormat: 'details', + logger, + }) + if (!parsed.success) return parsed.response + const params = parsed.data.body + + logger.info( + `[${requestId}] Getting AppConfig configuration profile ${params.configurationProfileId}` + ) + + const client = createAppConfigClient({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + }) + + try { + const result = await getConfigurationProfile( + client, + params.applicationId, + params.configurationProfileId + ) + logger.info(`[${requestId}] Retrieved configuration profile`) + return NextResponse.json(result) + } finally { + client.destroy() + } + } catch (error) { + const errorMessage = getErrorMessage(error, 'Unknown error occurred') + logger.error(`[${requestId}] Failed to get configuration profile:`, error) + return NextResponse.json( + { error: `Failed to get configuration profile: ${errorMessage}` }, + { status: 500 } + ) + } +}) diff --git a/apps/sim/app/api/tools/appconfig/get-environment/route.ts b/apps/sim/app/api/tools/appconfig/get-environment/route.ts new file mode 100644 index 00000000000..37a9918f801 --- /dev/null +++ b/apps/sim/app/api/tools/appconfig/get-environment/route.ts @@ -0,0 +1,52 @@ +import { createLogger } from '@sim/logger' +import { getErrorMessage } from '@sim/utils/errors' +import { generateId } from '@sim/utils/id' +import { type NextRequest, NextResponse } from 'next/server' +import { awsAppConfigGetEnvironmentContract } from '@/lib/api/contracts/tools/aws/appconfig-get-environment' +import { parseToolRequest } from '@/lib/api/server' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { withRouteHandler } from '@/lib/core/utils/with-route-handler' +import { createAppConfigClient, getEnvironment } from '../utils' + +const logger = createLogger('AppConfigGetEnvironmentAPI') + +export const POST = withRouteHandler(async (request: NextRequest) => { + const requestId = generateId().slice(0, 8) + + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + try { + const parsed = await parseToolRequest(awsAppConfigGetEnvironmentContract, request, { + errorFormat: 'details', + logger, + }) + if (!parsed.success) return parsed.response + const params = parsed.data.body + + logger.info(`[${requestId}] Getting AppConfig environment ${params.environmentId}`) + + const client = createAppConfigClient({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + }) + + try { + const result = await getEnvironment(client, params.applicationId, params.environmentId) + logger.info(`[${requestId}] Retrieved environment`) + return NextResponse.json(result) + } finally { + client.destroy() + } + } catch (error) { + const errorMessage = getErrorMessage(error, 'Unknown error occurred') + logger.error(`[${requestId}] Failed to get environment:`, error) + return NextResponse.json( + { error: `Failed to get environment: ${errorMessage}` }, + { status: 500 } + ) + } +}) diff --git a/apps/sim/app/api/tools/appconfig/update-application/route.ts b/apps/sim/app/api/tools/appconfig/update-application/route.ts new file mode 100644 index 00000000000..d2c2ac58260 --- /dev/null +++ b/apps/sim/app/api/tools/appconfig/update-application/route.ts @@ -0,0 +1,57 @@ +import { createLogger } from '@sim/logger' +import { getErrorMessage } from '@sim/utils/errors' +import { generateId } from '@sim/utils/id' +import { type NextRequest, NextResponse } from 'next/server' +import { awsAppConfigUpdateApplicationContract } from '@/lib/api/contracts/tools/aws/appconfig-update-application' +import { parseToolRequest } from '@/lib/api/server' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { withRouteHandler } from '@/lib/core/utils/with-route-handler' +import { createAppConfigClient, updateApplication } from '../utils' + +const logger = createLogger('AppConfigUpdateApplicationAPI') + +export const POST = withRouteHandler(async (request: NextRequest) => { + const requestId = generateId().slice(0, 8) + + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + try { + const parsed = await parseToolRequest(awsAppConfigUpdateApplicationContract, request, { + errorFormat: 'details', + logger, + }) + if (!parsed.success) return parsed.response + const params = parsed.data.body + + logger.info(`[${requestId}] Updating AppConfig application ${params.applicationId}`) + + const client = createAppConfigClient({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + }) + + try { + const result = await updateApplication( + client, + params.applicationId, + params.name, + params.description + ) + logger.info(`[${requestId}] Updated application`) + return NextResponse.json(result) + } finally { + client.destroy() + } + } catch (error) { + const errorMessage = getErrorMessage(error, 'Unknown error occurred') + logger.error(`[${requestId}] Failed to update application:`, error) + return NextResponse.json( + { error: `Failed to update application: ${errorMessage}` }, + { status: 500 } + ) + } +}) diff --git a/apps/sim/app/api/tools/appconfig/update-configuration-profile/route.ts b/apps/sim/app/api/tools/appconfig/update-configuration-profile/route.ts new file mode 100644 index 00000000000..002bacdf665 --- /dev/null +++ b/apps/sim/app/api/tools/appconfig/update-configuration-profile/route.ts @@ -0,0 +1,61 @@ +import { createLogger } from '@sim/logger' +import { getErrorMessage } from '@sim/utils/errors' +import { generateId } from '@sim/utils/id' +import { type NextRequest, NextResponse } from 'next/server' +import { awsAppConfigUpdateConfigurationProfileContract } from '@/lib/api/contracts/tools/aws/appconfig-update-configuration-profile' +import { parseToolRequest } from '@/lib/api/server' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { withRouteHandler } from '@/lib/core/utils/with-route-handler' +import { createAppConfigClient, updateConfigurationProfile } from '../utils' + +const logger = createLogger('AppConfigUpdateConfigurationProfileAPI') + +export const POST = withRouteHandler(async (request: NextRequest) => { + const requestId = generateId().slice(0, 8) + + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + try { + const parsed = await parseToolRequest(awsAppConfigUpdateConfigurationProfileContract, request, { + errorFormat: 'details', + logger, + }) + if (!parsed.success) return parsed.response + const params = parsed.data.body + + logger.info( + `[${requestId}] Updating AppConfig configuration profile ${params.configurationProfileId}` + ) + + const client = createAppConfigClient({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + }) + + try { + const result = await updateConfigurationProfile( + client, + params.applicationId, + params.configurationProfileId, + params.name, + params.description, + params.retrievalRoleArn + ) + logger.info(`[${requestId}] Updated configuration profile`) + return NextResponse.json(result) + } finally { + client.destroy() + } + } catch (error) { + const errorMessage = getErrorMessage(error, 'Unknown error occurred') + logger.error(`[${requestId}] Failed to update configuration profile:`, error) + return NextResponse.json( + { error: `Failed to update configuration profile: ${errorMessage}` }, + { status: 500 } + ) + } +}) diff --git a/apps/sim/app/api/tools/appconfig/update-environment/route.ts b/apps/sim/app/api/tools/appconfig/update-environment/route.ts new file mode 100644 index 00000000000..b1f611b8f2f --- /dev/null +++ b/apps/sim/app/api/tools/appconfig/update-environment/route.ts @@ -0,0 +1,58 @@ +import { createLogger } from '@sim/logger' +import { getErrorMessage } from '@sim/utils/errors' +import { generateId } from '@sim/utils/id' +import { type NextRequest, NextResponse } from 'next/server' +import { awsAppConfigUpdateEnvironmentContract } from '@/lib/api/contracts/tools/aws/appconfig-update-environment' +import { parseToolRequest } from '@/lib/api/server' +import { checkInternalAuth } from '@/lib/auth/hybrid' +import { withRouteHandler } from '@/lib/core/utils/with-route-handler' +import { createAppConfigClient, updateEnvironment } from '../utils' + +const logger = createLogger('AppConfigUpdateEnvironmentAPI') + +export const POST = withRouteHandler(async (request: NextRequest) => { + const requestId = generateId().slice(0, 8) + + const auth = await checkInternalAuth(request) + if (!auth.success || !auth.userId) { + return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 }) + } + + try { + const parsed = await parseToolRequest(awsAppConfigUpdateEnvironmentContract, request, { + errorFormat: 'details', + logger, + }) + if (!parsed.success) return parsed.response + const params = parsed.data.body + + logger.info(`[${requestId}] Updating AppConfig environment ${params.environmentId}`) + + const client = createAppConfigClient({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + }) + + try { + const result = await updateEnvironment( + client, + params.applicationId, + params.environmentId, + params.name, + params.description + ) + logger.info(`[${requestId}] Updated environment`) + return NextResponse.json(result) + } finally { + client.destroy() + } + } catch (error) { + const errorMessage = getErrorMessage(error, 'Unknown error occurred') + logger.error(`[${requestId}] Failed to update environment:`, error) + return NextResponse.json( + { error: `Failed to update environment: ${errorMessage}` }, + { status: 500 } + ) + } +}) diff --git a/apps/sim/app/api/tools/appconfig/utils.ts b/apps/sim/app/api/tools/appconfig/utils.ts index dcf4b478ac7..038109be133 100644 --- a/apps/sim/app/api/tools/appconfig/utils.ts +++ b/apps/sim/app/api/tools/appconfig/utils.ts @@ -4,7 +4,14 @@ import { CreateConfigurationProfileCommand, CreateEnvironmentCommand, CreateHostedConfigurationVersionCommand, + DeleteApplicationCommand, + DeleteConfigurationProfileCommand, + DeleteEnvironmentCommand, + DeleteHostedConfigurationVersionCommand, + GetApplicationCommand, + GetConfigurationProfileCommand, GetDeploymentCommand, + GetEnvironmentCommand, GetHostedConfigurationVersionCommand, ListApplicationsCommand, ListConfigurationProfilesCommand, @@ -14,6 +21,9 @@ import { ListHostedConfigurationVersionsCommand, StartDeploymentCommand, StopDeploymentCommand, + UpdateApplicationCommand, + UpdateConfigurationProfileCommand, + UpdateEnvironmentCommand, } from '@aws-sdk/client-appconfig' import { AppConfigDataClient, @@ -470,3 +480,202 @@ export async function getConfiguration( versionLabel: response.VersionLabel ?? null, } } + +export async function getApplication(client: AppConfigClient, applicationId: string) { + const response = await client.send(new GetApplicationCommand({ ApplicationId: applicationId })) + + return { + id: response.Id ?? '', + name: response.Name ?? '', + description: response.Description ?? null, + } +} + +export async function updateApplication( + client: AppConfigClient, + applicationId: string, + name?: string | null, + description?: string | null +) { + const response = await client.send( + new UpdateApplicationCommand({ + ApplicationId: applicationId, + ...(name ? { Name: name } : {}), + ...(description != null ? { Description: description } : {}), + }) + ) + + return { + message: `Application "${response.Name ?? applicationId}" updated`, + id: response.Id ?? '', + name: response.Name ?? '', + description: response.Description ?? null, + } +} + +export async function deleteApplication(client: AppConfigClient, applicationId: string) { + await client.send(new DeleteApplicationCommand({ ApplicationId: applicationId })) + + return { + message: `Application ${applicationId} deleted`, + id: applicationId, + } +} + +export async function getEnvironment( + client: AppConfigClient, + applicationId: string, + environmentId: string +) { + const response = await client.send( + new GetEnvironmentCommand({ ApplicationId: applicationId, EnvironmentId: environmentId }) + ) + + return { + applicationId: response.ApplicationId ?? applicationId, + id: response.Id ?? '', + name: response.Name ?? '', + description: response.Description ?? null, + state: response.State ?? null, + monitors: (response.Monitors ?? []).map((monitor) => ({ + alarmArn: monitor.AlarmArn ?? '', + alarmRoleArn: monitor.AlarmRoleArn ?? null, + })), + } +} + +export async function updateEnvironment( + client: AppConfigClient, + applicationId: string, + environmentId: string, + name?: string | null, + description?: string | null +) { + const response = await client.send( + new UpdateEnvironmentCommand({ + ApplicationId: applicationId, + EnvironmentId: environmentId, + ...(name ? { Name: name } : {}), + ...(description != null ? { Description: description } : {}), + }) + ) + + return { + message: `Environment "${response.Name ?? environmentId}" updated`, + applicationId: response.ApplicationId ?? applicationId, + id: response.Id ?? '', + name: response.Name ?? '', + state: response.State ?? null, + } +} + +export async function deleteEnvironment( + client: AppConfigClient, + applicationId: string, + environmentId: string +) { + await client.send( + new DeleteEnvironmentCommand({ ApplicationId: applicationId, EnvironmentId: environmentId }) + ) + + return { + message: `Environment ${environmentId} deleted`, + applicationId, + id: environmentId, + } +} + +export async function getConfigurationProfile( + client: AppConfigClient, + applicationId: string, + configurationProfileId: string +) { + const response = await client.send( + new GetConfigurationProfileCommand({ + ApplicationId: applicationId, + ConfigurationProfileId: configurationProfileId, + }) + ) + + return { + applicationId: response.ApplicationId ?? applicationId, + id: response.Id ?? '', + name: response.Name ?? '', + description: response.Description ?? null, + locationUri: response.LocationUri ?? null, + retrievalRoleArn: response.RetrievalRoleArn ?? null, + type: response.Type ?? null, + validators: (response.Validators ?? []).map((validator) => ({ + type: validator.Type ?? '', + })), + } +} + +export async function updateConfigurationProfile( + client: AppConfigClient, + applicationId: string, + configurationProfileId: string, + name?: string | null, + description?: string | null, + retrievalRoleArn?: string | null +) { + const response = await client.send( + new UpdateConfigurationProfileCommand({ + ApplicationId: applicationId, + ConfigurationProfileId: configurationProfileId, + ...(name ? { Name: name } : {}), + ...(description != null ? { Description: description } : {}), + ...(retrievalRoleArn != null ? { RetrievalRoleArn: retrievalRoleArn } : {}), + }) + ) + + return { + message: `Configuration profile "${response.Name ?? configurationProfileId}" updated`, + applicationId: response.ApplicationId ?? applicationId, + id: response.Id ?? '', + name: response.Name ?? '', + description: response.Description ?? null, + type: response.Type ?? null, + } +} + +export async function deleteConfigurationProfile( + client: AppConfigClient, + applicationId: string, + configurationProfileId: string +) { + await client.send( + new DeleteConfigurationProfileCommand({ + ApplicationId: applicationId, + ConfigurationProfileId: configurationProfileId, + }) + ) + + return { + message: `Configuration profile ${configurationProfileId} deleted`, + applicationId, + id: configurationProfileId, + } +} + +export async function deleteHostedConfigurationVersion( + client: AppConfigClient, + applicationId: string, + configurationProfileId: string, + versionNumber: number +) { + await client.send( + new DeleteHostedConfigurationVersionCommand({ + ApplicationId: applicationId, + ConfigurationProfileId: configurationProfileId, + VersionNumber: versionNumber, + }) + ) + + return { + message: `Hosted configuration version ${versionNumber} deleted`, + applicationId, + configurationProfileId, + versionNumber, + } +} diff --git a/apps/sim/blocks/blocks/appconfig.ts b/apps/sim/blocks/blocks/appconfig.ts index 47ac7cfba28..d9a6a92b683 100644 --- a/apps/sim/blocks/blocks/appconfig.ts +++ b/apps/sim/blocks/blocks/appconfig.ts @@ -29,10 +29,19 @@ export const AppConfigBlock: BlockConfig< { label: 'Get Configuration', id: 'get_configuration' }, { label: 'List Applications', id: 'list_applications' }, { label: 'Create Application', id: 'create_application' }, + { label: 'Get Application', id: 'get_application' }, + { label: 'Update Application', id: 'update_application' }, + { label: 'Delete Application', id: 'delete_application' }, { label: 'List Environments', id: 'list_environments' }, { label: 'Create Environment', id: 'create_environment' }, + { label: 'Get Environment', id: 'get_environment' }, + { label: 'Update Environment', id: 'update_environment' }, + { label: 'Delete Environment', id: 'delete_environment' }, { label: 'List Configuration Profiles', id: 'list_configuration_profiles' }, { label: 'Create Configuration Profile', id: 'create_configuration_profile' }, + { label: 'Get Configuration Profile', id: 'get_configuration_profile' }, + { label: 'Update Configuration Profile', id: 'update_configuration_profile' }, + { label: 'Delete Configuration Profile', id: 'delete_configuration_profile' }, { label: 'Create Hosted Configuration Version', id: 'create_hosted_configuration_version', @@ -42,6 +51,10 @@ export const AppConfigBlock: BlockConfig< label: 'List Hosted Configuration Versions', id: 'list_hosted_configuration_versions', }, + { + label: 'Delete Hosted Configuration Version', + id: 'delete_hosted_configuration_version', + }, { label: 'List Deployment Strategies', id: 'list_deployment_strategies' }, { label: 'Start Deployment', id: 'start_deployment' }, { label: 'Get Deployment', id: 'get_deployment' }, @@ -81,13 +94,23 @@ export const AppConfigBlock: BlockConfig< condition: { field: 'operation', value: [ + 'get_application', + 'update_application', + 'delete_application', 'list_environments', 'create_environment', + 'get_environment', + 'update_environment', + 'delete_environment', 'list_configuration_profiles', 'create_configuration_profile', + 'get_configuration_profile', + 'update_configuration_profile', + 'delete_configuration_profile', 'create_hosted_configuration_version', 'get_hosted_configuration_version', 'list_hosted_configuration_versions', + 'delete_hosted_configuration_version', 'start_deployment', 'get_deployment', 'list_deployments', @@ -98,13 +121,23 @@ export const AppConfigBlock: BlockConfig< required: { field: 'operation', value: [ + 'get_application', + 'update_application', + 'delete_application', 'list_environments', 'create_environment', + 'get_environment', + 'update_environment', + 'delete_environment', 'list_configuration_profiles', 'create_configuration_profile', + 'get_configuration_profile', + 'update_configuration_profile', + 'delete_configuration_profile', 'create_hosted_configuration_version', 'get_hosted_configuration_version', 'list_hosted_configuration_versions', + 'delete_hosted_configuration_version', 'start_deployment', 'get_deployment', 'list_deployments', @@ -121,6 +154,9 @@ export const AppConfigBlock: BlockConfig< condition: { field: 'operation', value: [ + 'get_environment', + 'update_environment', + 'delete_environment', 'start_deployment', 'get_deployment', 'list_deployments', @@ -131,6 +167,9 @@ export const AppConfigBlock: BlockConfig< required: { field: 'operation', value: [ + 'get_environment', + 'update_environment', + 'delete_environment', 'start_deployment', 'get_deployment', 'list_deployments', @@ -147,9 +186,13 @@ export const AppConfigBlock: BlockConfig< condition: { field: 'operation', value: [ + 'get_configuration_profile', + 'update_configuration_profile', + 'delete_configuration_profile', 'create_hosted_configuration_version', 'get_hosted_configuration_version', 'list_hosted_configuration_versions', + 'delete_hosted_configuration_version', 'start_deployment', 'get_configuration', ], @@ -157,9 +200,13 @@ export const AppConfigBlock: BlockConfig< required: { field: 'operation', value: [ + 'get_configuration_profile', + 'update_configuration_profile', + 'delete_configuration_profile', 'create_hosted_configuration_version', 'get_hosted_configuration_version', 'list_hosted_configuration_versions', + 'delete_hosted_configuration_version', 'start_deployment', 'get_configuration', ], @@ -172,7 +219,14 @@ export const AppConfigBlock: BlockConfig< placeholder: 'Resource name', condition: { field: 'operation', - value: ['create_application', 'create_environment', 'create_configuration_profile'], + value: [ + 'create_application', + 'create_environment', + 'create_configuration_profile', + 'update_application', + 'update_environment', + 'update_configuration_profile', + ], }, required: { field: 'operation', @@ -205,7 +259,10 @@ export const AppConfigBlock: BlockConfig< title: 'Retrieval Role ARN', type: 'short-input', placeholder: 'arn:aws:iam::123456789012:role/AppConfigRetrieval', - condition: { field: 'operation', value: 'create_configuration_profile' }, + condition: { + field: 'operation', + value: ['create_configuration_profile', 'update_configuration_profile'], + }, required: false, mode: 'advanced', }, @@ -248,8 +305,14 @@ export const AppConfigBlock: BlockConfig< title: 'Version Number', type: 'short-input', placeholder: '1', - condition: { field: 'operation', value: 'get_hosted_configuration_version' }, - required: { field: 'operation', value: 'get_hosted_configuration_version' }, + condition: { + field: 'operation', + value: ['get_hosted_configuration_version', 'delete_hosted_configuration_version'], + }, + required: { + field: 'operation', + value: ['get_hosted_configuration_version', 'delete_hosted_configuration_version'], + }, }, { id: 'deploymentStrategyId', @@ -286,6 +349,9 @@ export const AppConfigBlock: BlockConfig< 'create_application', 'create_environment', 'create_configuration_profile', + 'update_application', + 'update_environment', + 'update_configuration_profile', 'create_hosted_configuration_version', 'start_deployment', ], @@ -337,13 +403,23 @@ export const AppConfigBlock: BlockConfig< 'appconfig_get_configuration', 'appconfig_list_applications', 'appconfig_create_application', + 'appconfig_get_application', + 'appconfig_update_application', + 'appconfig_delete_application', 'appconfig_list_environments', 'appconfig_create_environment', + 'appconfig_get_environment', + 'appconfig_update_environment', + 'appconfig_delete_environment', 'appconfig_list_configuration_profiles', 'appconfig_create_configuration_profile', + 'appconfig_get_configuration_profile', + 'appconfig_update_configuration_profile', + 'appconfig_delete_configuration_profile', 'appconfig_create_hosted_configuration_version', 'appconfig_get_hosted_configuration_version', 'appconfig_list_hosted_configuration_versions', + 'appconfig_delete_hosted_configuration_version', 'appconfig_list_deployment_strategies', 'appconfig_start_deployment', 'appconfig_get_deployment', @@ -359,20 +435,40 @@ export const AppConfigBlock: BlockConfig< return 'appconfig_list_applications' case 'create_application': return 'appconfig_create_application' + case 'get_application': + return 'appconfig_get_application' + case 'update_application': + return 'appconfig_update_application' + case 'delete_application': + return 'appconfig_delete_application' case 'list_environments': return 'appconfig_list_environments' case 'create_environment': return 'appconfig_create_environment' + case 'get_environment': + return 'appconfig_get_environment' + case 'update_environment': + return 'appconfig_update_environment' + case 'delete_environment': + return 'appconfig_delete_environment' case 'list_configuration_profiles': return 'appconfig_list_configuration_profiles' case 'create_configuration_profile': return 'appconfig_create_configuration_profile' + case 'get_configuration_profile': + return 'appconfig_get_configuration_profile' + case 'update_configuration_profile': + return 'appconfig_update_configuration_profile' + case 'delete_configuration_profile': + return 'appconfig_delete_configuration_profile' case 'create_hosted_configuration_version': return 'appconfig_create_hosted_configuration_version' case 'get_hosted_configuration_version': return 'appconfig_get_hosted_configuration_version' case 'list_hosted_configuration_versions': return 'appconfig_list_hosted_configuration_versions' + case 'delete_hosted_configuration_version': + return 'appconfig_delete_hosted_configuration_version' case 'list_deployment_strategies': return 'appconfig_list_deployment_strategies' case 'start_deployment': @@ -482,6 +578,9 @@ export const AppConfigBlock: BlockConfig< deploymentStrategies: { type: 'json', description: 'List of deployment strategies' }, deployments: { type: 'json', description: 'List of deployments' }, versions: { type: 'json', description: 'List of hosted configuration versions' }, + monitors: { type: 'json', description: 'CloudWatch alarms monitoring an environment' }, + validators: { type: 'json', description: 'Validators configured on a configuration profile' }, + retrievalRoleArn: { type: 'string', description: 'IAM role ARN to retrieve configuration' }, nextToken: { type: 'string', description: 'Pagination token for the next page' }, count: { type: 'number', description: 'Number of items returned' }, }, diff --git a/apps/sim/lib/api/contracts/tools/aws/appconfig-delete-application.ts b/apps/sim/lib/api/contracts/tools/aws/appconfig-delete-application.ts new file mode 100644 index 00000000000..05c47225ada --- /dev/null +++ b/apps/sim/lib/api/contracts/tools/aws/appconfig-delete-application.ts @@ -0,0 +1,35 @@ +import { z } from 'zod' +import type { + ContractBody, + ContractBodyInput, + ContractJsonResponse, +} from '@/lib/api/contracts/types' +import { defineRouteContract } from '@/lib/api/contracts/types' + +const DeleteApplicationSchema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + applicationId: z.string().min(1, 'Application ID is required'), +}) + +const DeleteApplicationResponseSchema = z.object({ + message: z.string(), + id: z.string(), +}) + +export const awsAppConfigDeleteApplicationContract = defineRouteContract({ + method: 'POST', + path: '/api/tools/appconfig/delete-application', + body: DeleteApplicationSchema, + response: { mode: 'json', schema: DeleteApplicationResponseSchema }, +}) +export type AwsAppConfigDeleteApplicationRequest = ContractBodyInput< + typeof awsAppConfigDeleteApplicationContract +> +export type AwsAppConfigDeleteApplicationBody = ContractBody< + typeof awsAppConfigDeleteApplicationContract +> +export type AwsAppConfigDeleteApplicationResponse = ContractJsonResponse< + typeof awsAppConfigDeleteApplicationContract +> diff --git a/apps/sim/lib/api/contracts/tools/aws/appconfig-delete-configuration-profile.ts b/apps/sim/lib/api/contracts/tools/aws/appconfig-delete-configuration-profile.ts new file mode 100644 index 00000000000..96965acd1da --- /dev/null +++ b/apps/sim/lib/api/contracts/tools/aws/appconfig-delete-configuration-profile.ts @@ -0,0 +1,37 @@ +import { z } from 'zod' +import type { + ContractBody, + ContractBodyInput, + ContractJsonResponse, +} from '@/lib/api/contracts/types' +import { defineRouteContract } from '@/lib/api/contracts/types' + +const DeleteConfigurationProfileSchema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + applicationId: z.string().min(1, 'Application ID is required'), + configurationProfileId: z.string().min(1, 'Configuration profile ID is required'), +}) + +const DeleteConfigurationProfileResponseSchema = z.object({ + message: z.string(), + applicationId: z.string(), + id: z.string(), +}) + +export const awsAppConfigDeleteConfigurationProfileContract = defineRouteContract({ + method: 'POST', + path: '/api/tools/appconfig/delete-configuration-profile', + body: DeleteConfigurationProfileSchema, + response: { mode: 'json', schema: DeleteConfigurationProfileResponseSchema }, +}) +export type AwsAppConfigDeleteConfigurationProfileRequest = ContractBodyInput< + typeof awsAppConfigDeleteConfigurationProfileContract +> +export type AwsAppConfigDeleteConfigurationProfileBody = ContractBody< + typeof awsAppConfigDeleteConfigurationProfileContract +> +export type AwsAppConfigDeleteConfigurationProfileResponse = ContractJsonResponse< + typeof awsAppConfigDeleteConfigurationProfileContract +> diff --git a/apps/sim/lib/api/contracts/tools/aws/appconfig-delete-environment.ts b/apps/sim/lib/api/contracts/tools/aws/appconfig-delete-environment.ts new file mode 100644 index 00000000000..1caea5abf85 --- /dev/null +++ b/apps/sim/lib/api/contracts/tools/aws/appconfig-delete-environment.ts @@ -0,0 +1,37 @@ +import { z } from 'zod' +import type { + ContractBody, + ContractBodyInput, + ContractJsonResponse, +} from '@/lib/api/contracts/types' +import { defineRouteContract } from '@/lib/api/contracts/types' + +const DeleteEnvironmentSchema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + applicationId: z.string().min(1, 'Application ID is required'), + environmentId: z.string().min(1, 'Environment ID is required'), +}) + +const DeleteEnvironmentResponseSchema = z.object({ + message: z.string(), + applicationId: z.string(), + id: z.string(), +}) + +export const awsAppConfigDeleteEnvironmentContract = defineRouteContract({ + method: 'POST', + path: '/api/tools/appconfig/delete-environment', + body: DeleteEnvironmentSchema, + response: { mode: 'json', schema: DeleteEnvironmentResponseSchema }, +}) +export type AwsAppConfigDeleteEnvironmentRequest = ContractBodyInput< + typeof awsAppConfigDeleteEnvironmentContract +> +export type AwsAppConfigDeleteEnvironmentBody = ContractBody< + typeof awsAppConfigDeleteEnvironmentContract +> +export type AwsAppConfigDeleteEnvironmentResponse = ContractJsonResponse< + typeof awsAppConfigDeleteEnvironmentContract +> diff --git a/apps/sim/lib/api/contracts/tools/aws/appconfig-delete-hosted-configuration-version.ts b/apps/sim/lib/api/contracts/tools/aws/appconfig-delete-hosted-configuration-version.ts new file mode 100644 index 00000000000..314a0c6226d --- /dev/null +++ b/apps/sim/lib/api/contracts/tools/aws/appconfig-delete-hosted-configuration-version.ts @@ -0,0 +1,39 @@ +import { z } from 'zod' +import type { + ContractBody, + ContractBodyInput, + ContractJsonResponse, +} from '@/lib/api/contracts/types' +import { defineRouteContract } from '@/lib/api/contracts/types' + +const DeleteHostedConfigurationVersionSchema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + applicationId: z.string().min(1, 'Application ID is required'), + configurationProfileId: z.string().min(1, 'Configuration profile ID is required'), + versionNumber: z.number().int().min(1, 'Version number is required'), +}) + +const DeleteHostedConfigurationVersionResponseSchema = z.object({ + message: z.string(), + applicationId: z.string(), + configurationProfileId: z.string(), + versionNumber: z.number(), +}) + +export const awsAppConfigDeleteHostedConfigurationVersionContract = defineRouteContract({ + method: 'POST', + path: '/api/tools/appconfig/delete-hosted-configuration-version', + body: DeleteHostedConfigurationVersionSchema, + response: { mode: 'json', schema: DeleteHostedConfigurationVersionResponseSchema }, +}) +export type AwsAppConfigDeleteHostedConfigurationVersionRequest = ContractBodyInput< + typeof awsAppConfigDeleteHostedConfigurationVersionContract +> +export type AwsAppConfigDeleteHostedConfigurationVersionBody = ContractBody< + typeof awsAppConfigDeleteHostedConfigurationVersionContract +> +export type AwsAppConfigDeleteHostedConfigurationVersionResponse = ContractJsonResponse< + typeof awsAppConfigDeleteHostedConfigurationVersionContract +> diff --git a/apps/sim/lib/api/contracts/tools/aws/appconfig-get-application.ts b/apps/sim/lib/api/contracts/tools/aws/appconfig-get-application.ts new file mode 100644 index 00000000000..51291fd7f9c --- /dev/null +++ b/apps/sim/lib/api/contracts/tools/aws/appconfig-get-application.ts @@ -0,0 +1,34 @@ +import { z } from 'zod' +import type { + ContractBody, + ContractBodyInput, + ContractJsonResponse, +} from '@/lib/api/contracts/types' +import { defineRouteContract } from '@/lib/api/contracts/types' + +const GetApplicationSchema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + applicationId: z.string().min(1, 'Application ID is required'), +}) + +const GetApplicationResponseSchema = z.object({ + id: z.string(), + name: z.string(), + description: z.string().nullable(), +}) + +export const awsAppConfigGetApplicationContract = defineRouteContract({ + method: 'POST', + path: '/api/tools/appconfig/get-application', + body: GetApplicationSchema, + response: { mode: 'json', schema: GetApplicationResponseSchema }, +}) +export type AwsAppConfigGetApplicationRequest = ContractBodyInput< + typeof awsAppConfigGetApplicationContract +> +export type AwsAppConfigGetApplicationBody = ContractBody +export type AwsAppConfigGetApplicationResponse = ContractJsonResponse< + typeof awsAppConfigGetApplicationContract +> diff --git a/apps/sim/lib/api/contracts/tools/aws/appconfig-get-configuration-profile.ts b/apps/sim/lib/api/contracts/tools/aws/appconfig-get-configuration-profile.ts new file mode 100644 index 00000000000..7b7c0e8f183 --- /dev/null +++ b/apps/sim/lib/api/contracts/tools/aws/appconfig-get-configuration-profile.ts @@ -0,0 +1,42 @@ +import { z } from 'zod' +import type { + ContractBody, + ContractBodyInput, + ContractJsonResponse, +} from '@/lib/api/contracts/types' +import { defineRouteContract } from '@/lib/api/contracts/types' + +const GetConfigurationProfileSchema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + applicationId: z.string().min(1, 'Application ID is required'), + configurationProfileId: z.string().min(1, 'Configuration profile ID is required'), +}) + +const GetConfigurationProfileResponseSchema = z.object({ + applicationId: z.string(), + id: z.string(), + name: z.string(), + description: z.string().nullable(), + locationUri: z.string().nullable(), + retrievalRoleArn: z.string().nullable(), + type: z.string().nullable(), + validators: z.array(z.object({ type: z.string() })), +}) + +export const awsAppConfigGetConfigurationProfileContract = defineRouteContract({ + method: 'POST', + path: '/api/tools/appconfig/get-configuration-profile', + body: GetConfigurationProfileSchema, + response: { mode: 'json', schema: GetConfigurationProfileResponseSchema }, +}) +export type AwsAppConfigGetConfigurationProfileRequest = ContractBodyInput< + typeof awsAppConfigGetConfigurationProfileContract +> +export type AwsAppConfigGetConfigurationProfileBody = ContractBody< + typeof awsAppConfigGetConfigurationProfileContract +> +export type AwsAppConfigGetConfigurationProfileResponse = ContractJsonResponse< + typeof awsAppConfigGetConfigurationProfileContract +> diff --git a/apps/sim/lib/api/contracts/tools/aws/appconfig-get-environment.ts b/apps/sim/lib/api/contracts/tools/aws/appconfig-get-environment.ts new file mode 100644 index 00000000000..2e9bb2effb9 --- /dev/null +++ b/apps/sim/lib/api/contracts/tools/aws/appconfig-get-environment.ts @@ -0,0 +1,43 @@ +import { z } from 'zod' +import type { + ContractBody, + ContractBodyInput, + ContractJsonResponse, +} from '@/lib/api/contracts/types' +import { defineRouteContract } from '@/lib/api/contracts/types' + +const GetEnvironmentSchema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + applicationId: z.string().min(1, 'Application ID is required'), + environmentId: z.string().min(1, 'Environment ID is required'), +}) + +const GetEnvironmentResponseSchema = z.object({ + applicationId: z.string(), + id: z.string(), + name: z.string(), + description: z.string().nullable(), + state: z.string().nullable(), + monitors: z.array( + z.object({ + alarmArn: z.string(), + alarmRoleArn: z.string().nullable(), + }) + ), +}) + +export const awsAppConfigGetEnvironmentContract = defineRouteContract({ + method: 'POST', + path: '/api/tools/appconfig/get-environment', + body: GetEnvironmentSchema, + response: { mode: 'json', schema: GetEnvironmentResponseSchema }, +}) +export type AwsAppConfigGetEnvironmentRequest = ContractBodyInput< + typeof awsAppConfigGetEnvironmentContract +> +export type AwsAppConfigGetEnvironmentBody = ContractBody +export type AwsAppConfigGetEnvironmentResponse = ContractJsonResponse< + typeof awsAppConfigGetEnvironmentContract +> diff --git a/apps/sim/lib/api/contracts/tools/aws/appconfig-update-application.ts b/apps/sim/lib/api/contracts/tools/aws/appconfig-update-application.ts new file mode 100644 index 00000000000..2d4c6cb2830 --- /dev/null +++ b/apps/sim/lib/api/contracts/tools/aws/appconfig-update-application.ts @@ -0,0 +1,39 @@ +import { z } from 'zod' +import type { + ContractBody, + ContractBodyInput, + ContractJsonResponse, +} from '@/lib/api/contracts/types' +import { defineRouteContract } from '@/lib/api/contracts/types' + +const UpdateApplicationSchema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + applicationId: z.string().min(1, 'Application ID is required'), + name: z.string().min(1).max(64).nullish(), + description: z.string().max(1024).nullish(), +}) + +const UpdateApplicationResponseSchema = z.object({ + message: z.string(), + id: z.string(), + name: z.string(), + description: z.string().nullable(), +}) + +export const awsAppConfigUpdateApplicationContract = defineRouteContract({ + method: 'POST', + path: '/api/tools/appconfig/update-application', + body: UpdateApplicationSchema, + response: { mode: 'json', schema: UpdateApplicationResponseSchema }, +}) +export type AwsAppConfigUpdateApplicationRequest = ContractBodyInput< + typeof awsAppConfigUpdateApplicationContract +> +export type AwsAppConfigUpdateApplicationBody = ContractBody< + typeof awsAppConfigUpdateApplicationContract +> +export type AwsAppConfigUpdateApplicationResponse = ContractJsonResponse< + typeof awsAppConfigUpdateApplicationContract +> diff --git a/apps/sim/lib/api/contracts/tools/aws/appconfig-update-configuration-profile.ts b/apps/sim/lib/api/contracts/tools/aws/appconfig-update-configuration-profile.ts new file mode 100644 index 00000000000..714259cc0df --- /dev/null +++ b/apps/sim/lib/api/contracts/tools/aws/appconfig-update-configuration-profile.ts @@ -0,0 +1,43 @@ +import { z } from 'zod' +import type { + ContractBody, + ContractBodyInput, + ContractJsonResponse, +} from '@/lib/api/contracts/types' +import { defineRouteContract } from '@/lib/api/contracts/types' + +const UpdateConfigurationProfileSchema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + applicationId: z.string().min(1, 'Application ID is required'), + configurationProfileId: z.string().min(1, 'Configuration profile ID is required'), + name: z.string().min(1).max(128).nullish(), + description: z.string().max(1024).nullish(), + retrievalRoleArn: z.string().nullish(), +}) + +const UpdateConfigurationProfileResponseSchema = z.object({ + message: z.string(), + applicationId: z.string(), + id: z.string(), + name: z.string(), + description: z.string().nullable(), + type: z.string().nullable(), +}) + +export const awsAppConfigUpdateConfigurationProfileContract = defineRouteContract({ + method: 'POST', + path: '/api/tools/appconfig/update-configuration-profile', + body: UpdateConfigurationProfileSchema, + response: { mode: 'json', schema: UpdateConfigurationProfileResponseSchema }, +}) +export type AwsAppConfigUpdateConfigurationProfileRequest = ContractBodyInput< + typeof awsAppConfigUpdateConfigurationProfileContract +> +export type AwsAppConfigUpdateConfigurationProfileBody = ContractBody< + typeof awsAppConfigUpdateConfigurationProfileContract +> +export type AwsAppConfigUpdateConfigurationProfileResponse = ContractJsonResponse< + typeof awsAppConfigUpdateConfigurationProfileContract +> diff --git a/apps/sim/lib/api/contracts/tools/aws/appconfig-update-environment.ts b/apps/sim/lib/api/contracts/tools/aws/appconfig-update-environment.ts new file mode 100644 index 00000000000..34e76af970a --- /dev/null +++ b/apps/sim/lib/api/contracts/tools/aws/appconfig-update-environment.ts @@ -0,0 +1,41 @@ +import { z } from 'zod' +import type { + ContractBody, + ContractBodyInput, + ContractJsonResponse, +} from '@/lib/api/contracts/types' +import { defineRouteContract } from '@/lib/api/contracts/types' + +const UpdateEnvironmentSchema = z.object({ + region: z.string().min(1, 'AWS region is required'), + accessKeyId: z.string().min(1, 'AWS access key ID is required'), + secretAccessKey: z.string().min(1, 'AWS secret access key is required'), + applicationId: z.string().min(1, 'Application ID is required'), + environmentId: z.string().min(1, 'Environment ID is required'), + name: z.string().min(1).max(64).nullish(), + description: z.string().max(1024).nullish(), +}) + +const UpdateEnvironmentResponseSchema = z.object({ + message: z.string(), + applicationId: z.string(), + id: z.string(), + name: z.string(), + state: z.string().nullable(), +}) + +export const awsAppConfigUpdateEnvironmentContract = defineRouteContract({ + method: 'POST', + path: '/api/tools/appconfig/update-environment', + body: UpdateEnvironmentSchema, + response: { mode: 'json', schema: UpdateEnvironmentResponseSchema }, +}) +export type AwsAppConfigUpdateEnvironmentRequest = ContractBodyInput< + typeof awsAppConfigUpdateEnvironmentContract +> +export type AwsAppConfigUpdateEnvironmentBody = ContractBody< + typeof awsAppConfigUpdateEnvironmentContract +> +export type AwsAppConfigUpdateEnvironmentResponse = ContractJsonResponse< + typeof awsAppConfigUpdateEnvironmentContract +> diff --git a/apps/sim/lib/integrations/integrations.json b/apps/sim/lib/integrations/integrations.json index 339448cfa44..324e27d3ea5 100644 --- a/apps/sim/lib/integrations/integrations.json +++ b/apps/sim/lib/integrations/integrations.json @@ -1477,6 +1477,18 @@ "name": "Create Application", "description": "Create an application in AWS AppConfig" }, + { + "name": "Get Application", + "description": "Get details about a single AWS AppConfig application" + }, + { + "name": "Update Application", + "description": "Update the name or description of an AWS AppConfig application" + }, + { + "name": "Delete Application", + "description": "Delete an AWS AppConfig application" + }, { "name": "List Environments", "description": "List environments for an AWS AppConfig application" @@ -1485,6 +1497,18 @@ "name": "Create Environment", "description": "Create an environment for an AWS AppConfig application" }, + { + "name": "Get Environment", + "description": "Get details about a single AWS AppConfig environment" + }, + { + "name": "Update Environment", + "description": "Update the name or description of an AWS AppConfig environment" + }, + { + "name": "Delete Environment", + "description": "Delete an AWS AppConfig environment" + }, { "name": "List Configuration Profiles", "description": "List configuration profiles for an AWS AppConfig application" @@ -1493,6 +1517,18 @@ "name": "Create Configuration Profile", "description": "Create a configuration profile in an AWS AppConfig application" }, + { + "name": "Get Configuration Profile", + "description": "Get details about a single AWS AppConfig configuration profile" + }, + { + "name": "Update Configuration Profile", + "description": "Update the name, description, or retrieval role of an AppConfig configuration profile" + }, + { + "name": "Delete Configuration Profile", + "description": "Delete an AWS AppConfig configuration profile" + }, { "name": "Create Hosted Configuration Version", "description": "Create a new hosted configuration version for an AppConfig configuration profile" @@ -1505,6 +1541,10 @@ "name": "List Hosted Configuration Versions", "description": "List hosted configuration versions for an AWS AppConfig configuration profile" }, + { + "name": "Delete Hosted Configuration Version", + "description": "Delete a specific hosted configuration version from an AppConfig profile" + }, { "name": "List Deployment Strategies", "description": "List deployment strategies available in AWS AppConfig" @@ -1526,7 +1566,7 @@ "description": "Stop an in-progress AWS AppConfig deployment" } ], - "operationCount": 15, + "operationCount": 25, "triggers": [], "triggerCount": 0, "authType": "api-key", diff --git a/apps/sim/tools/appconfig/delete_application.ts b/apps/sim/tools/appconfig/delete_application.ts new file mode 100644 index 00000000000..372c4990dbd --- /dev/null +++ b/apps/sim/tools/appconfig/delete_application.ts @@ -0,0 +1,75 @@ +import type { + AppConfigDeleteApplicationParams, + AppConfigDeleteResourceResponse, +} from '@/tools/appconfig/types' +import type { ToolConfig } from '@/tools/types' + +export const deleteApplicationTool: ToolConfig< + AppConfigDeleteApplicationParams, + AppConfigDeleteResourceResponse +> = { + id: 'appconfig_delete_application', + name: 'AppConfig Delete Application', + description: 'Delete an AWS AppConfig application', + version: '1.0', + + params: { + region: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + accessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + secretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + applicationId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The application ID to delete', + }, + }, + + request: { + url: '/api/tools/appconfig/delete-application', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + applicationId: params.applicationId, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || 'Failed to delete AppConfig application') + } + + return { + success: true, + output: { + message: data.message ?? '', + id: data.id ?? '', + }, + } + }, + + outputs: { + message: { type: 'string', description: 'Operation status message' }, + id: { type: 'string', description: 'ID of the deleted application' }, + }, +} diff --git a/apps/sim/tools/appconfig/delete_configuration_profile.ts b/apps/sim/tools/appconfig/delete_configuration_profile.ts new file mode 100644 index 00000000000..0cb41ae8757 --- /dev/null +++ b/apps/sim/tools/appconfig/delete_configuration_profile.ts @@ -0,0 +1,84 @@ +import type { + AppConfigDeleteConfigurationProfileParams, + AppConfigDeleteResourceResponse, +} from '@/tools/appconfig/types' +import type { ToolConfig } from '@/tools/types' + +export const deleteConfigurationProfileTool: ToolConfig< + AppConfigDeleteConfigurationProfileParams, + AppConfigDeleteResourceResponse +> = { + id: 'appconfig_delete_configuration_profile', + name: 'AppConfig Delete Configuration Profile', + description: 'Delete an AWS AppConfig configuration profile', + version: '1.0', + + params: { + region: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + accessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + secretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + applicationId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The application ID that owns the configuration profile', + }, + configurationProfileId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The configuration profile ID to delete', + }, + }, + + request: { + url: '/api/tools/appconfig/delete-configuration-profile', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + applicationId: params.applicationId, + configurationProfileId: params.configurationProfileId, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || 'Failed to delete AppConfig configuration profile') + } + + return { + success: true, + output: { + message: data.message ?? '', + applicationId: data.applicationId ?? '', + id: data.id ?? '', + }, + } + }, + + outputs: { + message: { type: 'string', description: 'Operation status message' }, + applicationId: { type: 'string', description: 'Owning application ID' }, + id: { type: 'string', description: 'ID of the deleted configuration profile' }, + }, +} diff --git a/apps/sim/tools/appconfig/delete_environment.ts b/apps/sim/tools/appconfig/delete_environment.ts new file mode 100644 index 00000000000..5c079081daa --- /dev/null +++ b/apps/sim/tools/appconfig/delete_environment.ts @@ -0,0 +1,84 @@ +import type { + AppConfigDeleteEnvironmentParams, + AppConfigDeleteResourceResponse, +} from '@/tools/appconfig/types' +import type { ToolConfig } from '@/tools/types' + +export const deleteEnvironmentTool: ToolConfig< + AppConfigDeleteEnvironmentParams, + AppConfigDeleteResourceResponse +> = { + id: 'appconfig_delete_environment', + name: 'AppConfig Delete Environment', + description: 'Delete an AWS AppConfig environment', + version: '1.0', + + params: { + region: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + accessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + secretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + applicationId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The application ID that owns the environment', + }, + environmentId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The environment ID to delete', + }, + }, + + request: { + url: '/api/tools/appconfig/delete-environment', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + applicationId: params.applicationId, + environmentId: params.environmentId, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || 'Failed to delete AppConfig environment') + } + + return { + success: true, + output: { + message: data.message ?? '', + applicationId: data.applicationId ?? '', + id: data.id ?? '', + }, + } + }, + + outputs: { + message: { type: 'string', description: 'Operation status message' }, + applicationId: { type: 'string', description: 'Owning application ID' }, + id: { type: 'string', description: 'ID of the deleted environment' }, + }, +} diff --git a/apps/sim/tools/appconfig/delete_hosted_configuration_version.ts b/apps/sim/tools/appconfig/delete_hosted_configuration_version.ts new file mode 100644 index 00000000000..808f8a523f6 --- /dev/null +++ b/apps/sim/tools/appconfig/delete_hosted_configuration_version.ts @@ -0,0 +1,93 @@ +import type { + AppConfigDeleteHostedConfigurationVersionParams, + AppConfigDeleteHostedConfigurationVersionResponse, +} from '@/tools/appconfig/types' +import type { ToolConfig } from '@/tools/types' + +export const deleteHostedConfigurationVersionTool: ToolConfig< + AppConfigDeleteHostedConfigurationVersionParams, + AppConfigDeleteHostedConfigurationVersionResponse +> = { + id: 'appconfig_delete_hosted_configuration_version', + name: 'AppConfig Delete Hosted Configuration Version', + description: 'Delete a specific hosted configuration version from an AppConfig profile', + version: '1.0', + + params: { + region: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + accessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + secretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + applicationId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The application ID that owns the configuration profile', + }, + configurationProfileId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The configuration profile ID that owns the version', + }, + versionNumber: { + type: 'number', + required: true, + visibility: 'user-or-llm', + description: 'The version number to delete', + }, + }, + + request: { + url: '/api/tools/appconfig/delete-hosted-configuration-version', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + applicationId: params.applicationId, + configurationProfileId: params.configurationProfileId, + versionNumber: params.versionNumber, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || 'Failed to delete AppConfig hosted configuration version') + } + + return { + success: true, + output: { + message: data.message ?? '', + applicationId: data.applicationId ?? '', + configurationProfileId: data.configurationProfileId ?? '', + versionNumber: data.versionNumber ?? 0, + }, + } + }, + + outputs: { + message: { type: 'string', description: 'Operation status message' }, + applicationId: { type: 'string', description: 'Owning application ID' }, + configurationProfileId: { type: 'string', description: 'Owning configuration profile ID' }, + versionNumber: { type: 'number', description: 'Version number that was deleted' }, + }, +} diff --git a/apps/sim/tools/appconfig/get_application.ts b/apps/sim/tools/appconfig/get_application.ts new file mode 100644 index 00000000000..6ea8b8242d5 --- /dev/null +++ b/apps/sim/tools/appconfig/get_application.ts @@ -0,0 +1,77 @@ +import type { + AppConfigGetApplicationParams, + AppConfigGetApplicationResponse, +} from '@/tools/appconfig/types' +import type { ToolConfig } from '@/tools/types' + +export const getApplicationTool: ToolConfig< + AppConfigGetApplicationParams, + AppConfigGetApplicationResponse +> = { + id: 'appconfig_get_application', + name: 'AppConfig Get Application', + description: 'Get details about a single AWS AppConfig application', + version: '1.0', + + params: { + region: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + accessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + secretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + applicationId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The application ID to retrieve', + }, + }, + + request: { + url: '/api/tools/appconfig/get-application', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + applicationId: params.applicationId, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || 'Failed to get AppConfig application') + } + + return { + success: true, + output: { + id: data.id ?? '', + name: data.name ?? '', + description: data.description ?? null, + }, + } + }, + + outputs: { + id: { type: 'string', description: 'Application ID' }, + name: { type: 'string', description: 'Application name' }, + description: { type: 'string', description: 'Application description', optional: true }, + }, +} diff --git a/apps/sim/tools/appconfig/get_configuration_profile.ts b/apps/sim/tools/appconfig/get_configuration_profile.ts new file mode 100644 index 00000000000..ce367994edf --- /dev/null +++ b/apps/sim/tools/appconfig/get_configuration_profile.ts @@ -0,0 +1,103 @@ +import type { + AppConfigGetConfigurationProfileParams, + AppConfigGetConfigurationProfileResponse, +} from '@/tools/appconfig/types' +import type { ToolConfig } from '@/tools/types' + +export const getConfigurationProfileTool: ToolConfig< + AppConfigGetConfigurationProfileParams, + AppConfigGetConfigurationProfileResponse +> = { + id: 'appconfig_get_configuration_profile', + name: 'AppConfig Get Configuration Profile', + description: 'Get details about a single AWS AppConfig configuration profile', + version: '1.0', + + params: { + region: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + accessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + secretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + applicationId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The application ID that owns the configuration profile', + }, + configurationProfileId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The configuration profile ID to retrieve', + }, + }, + + request: { + url: '/api/tools/appconfig/get-configuration-profile', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + applicationId: params.applicationId, + configurationProfileId: params.configurationProfileId, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || 'Failed to get AppConfig configuration profile') + } + + return { + success: true, + output: { + applicationId: data.applicationId ?? '', + id: data.id ?? '', + name: data.name ?? '', + description: data.description ?? null, + locationUri: data.locationUri ?? null, + retrievalRoleArn: data.retrievalRoleArn ?? null, + type: data.type ?? null, + validators: data.validators ?? [], + }, + } + }, + + outputs: { + applicationId: { type: 'string', description: 'Owning application ID' }, + id: { type: 'string', description: 'Configuration profile ID' }, + name: { type: 'string', description: 'Configuration profile name' }, + description: { type: 'string', description: 'Profile description', optional: true }, + locationUri: { type: 'string', description: 'Location URI of the config', optional: true }, + retrievalRoleArn: { type: 'string', description: 'IAM retrieval role ARN', optional: true }, + type: { type: 'string', description: 'Profile type (e.g., AWS.Freeform)', optional: true }, + validators: { + type: 'array', + description: 'Validators configured on the profile', + items: { + type: 'object', + properties: { + type: { type: 'string', description: 'Validator type (JSON_SCHEMA or LAMBDA)' }, + }, + }, + }, + }, +} diff --git a/apps/sim/tools/appconfig/get_environment.ts b/apps/sim/tools/appconfig/get_environment.ts new file mode 100644 index 00000000000..7e09923f47b --- /dev/null +++ b/apps/sim/tools/appconfig/get_environment.ts @@ -0,0 +1,104 @@ +import type { + AppConfigGetEnvironmentParams, + AppConfigGetEnvironmentResponse, +} from '@/tools/appconfig/types' +import type { ToolConfig } from '@/tools/types' + +export const getEnvironmentTool: ToolConfig< + AppConfigGetEnvironmentParams, + AppConfigGetEnvironmentResponse +> = { + id: 'appconfig_get_environment', + name: 'AppConfig Get Environment', + description: 'Get details about a single AWS AppConfig environment', + version: '1.0', + + params: { + region: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + accessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + secretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + applicationId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The application ID that owns the environment', + }, + environmentId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The environment ID to retrieve', + }, + }, + + request: { + url: '/api/tools/appconfig/get-environment', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + applicationId: params.applicationId, + environmentId: params.environmentId, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || 'Failed to get AppConfig environment') + } + + return { + success: true, + output: { + applicationId: data.applicationId ?? '', + id: data.id ?? '', + name: data.name ?? '', + description: data.description ?? null, + state: data.state ?? null, + monitors: data.monitors ?? [], + }, + } + }, + + outputs: { + applicationId: { type: 'string', description: 'Owning application ID' }, + id: { type: 'string', description: 'Environment ID' }, + name: { type: 'string', description: 'Environment name' }, + description: { type: 'string', description: 'Environment description', optional: true }, + state: { type: 'string', description: 'Environment state', optional: true }, + monitors: { + type: 'array', + description: 'CloudWatch alarms monitoring this environment', + items: { + type: 'object', + properties: { + alarmArn: { type: 'string', description: 'CloudWatch alarm ARN' }, + alarmRoleArn: { + type: 'string', + description: 'IAM role ARN for the alarm', + optional: true, + }, + }, + }, + }, + }, +} diff --git a/apps/sim/tools/appconfig/index.ts b/apps/sim/tools/appconfig/index.ts index 1c6fd7dc4d8..315b498304d 100644 --- a/apps/sim/tools/appconfig/index.ts +++ b/apps/sim/tools/appconfig/index.ts @@ -2,8 +2,15 @@ import { createApplicationTool } from './create_application' import { createConfigurationProfileTool } from './create_configuration_profile' import { createEnvironmentTool } from './create_environment' import { createHostedConfigurationVersionTool } from './create_hosted_configuration_version' +import { deleteApplicationTool } from './delete_application' +import { deleteConfigurationProfileTool } from './delete_configuration_profile' +import { deleteEnvironmentTool } from './delete_environment' +import { deleteHostedConfigurationVersionTool } from './delete_hosted_configuration_version' +import { getApplicationTool } from './get_application' import { getConfigurationTool } from './get_configuration' +import { getConfigurationProfileTool } from './get_configuration_profile' import { getDeploymentTool } from './get_deployment' +import { getEnvironmentTool } from './get_environment' import { getHostedConfigurationVersionTool } from './get_hosted_configuration_version' import { listApplicationsTool } from './list_applications' import { listConfigurationProfilesTool } from './list_configuration_profiles' @@ -13,16 +20,29 @@ import { listEnvironmentsTool } from './list_environments' import { listHostedConfigurationVersionsTool } from './list_hosted_configuration_versions' import { startDeploymentTool } from './start_deployment' import { stopDeploymentTool } from './stop_deployment' +import { updateApplicationTool } from './update_application' +import { updateConfigurationProfileTool } from './update_configuration_profile' +import { updateEnvironmentTool } from './update_environment' export const appConfigListApplicationsTool = listApplicationsTool export const appConfigCreateApplicationTool = createApplicationTool +export const appConfigGetApplicationTool = getApplicationTool +export const appConfigUpdateApplicationTool = updateApplicationTool +export const appConfigDeleteApplicationTool = deleteApplicationTool export const appConfigListEnvironmentsTool = listEnvironmentsTool export const appConfigCreateEnvironmentTool = createEnvironmentTool +export const appConfigGetEnvironmentTool = getEnvironmentTool +export const appConfigUpdateEnvironmentTool = updateEnvironmentTool +export const appConfigDeleteEnvironmentTool = deleteEnvironmentTool export const appConfigListConfigurationProfilesTool = listConfigurationProfilesTool export const appConfigCreateConfigurationProfileTool = createConfigurationProfileTool +export const appConfigGetConfigurationProfileTool = getConfigurationProfileTool +export const appConfigUpdateConfigurationProfileTool = updateConfigurationProfileTool +export const appConfigDeleteConfigurationProfileTool = deleteConfigurationProfileTool export const appConfigCreateHostedConfigurationVersionTool = createHostedConfigurationVersionTool export const appConfigGetHostedConfigurationVersionTool = getHostedConfigurationVersionTool export const appConfigListHostedConfigurationVersionsTool = listHostedConfigurationVersionsTool +export const appConfigDeleteHostedConfigurationVersionTool = deleteHostedConfigurationVersionTool export const appConfigListDeploymentStrategiesTool = listDeploymentStrategiesTool export const appConfigStartDeploymentTool = startDeploymentTool export const appConfigGetDeploymentTool = getDeploymentTool diff --git a/apps/sim/tools/appconfig/types.ts b/apps/sim/tools/appconfig/types.ts index ea752b75d8f..79e10dab1dd 100644 --- a/apps/sim/tools/appconfig/types.ts +++ b/apps/sim/tools/appconfig/types.ts @@ -324,3 +324,145 @@ export interface AppConfigGetConfigurationResponse extends ToolResponse { } error?: string } + +export interface AppConfigGetApplicationParams extends AppConfigConnectionConfig { + applicationId: string +} + +export interface AppConfigUpdateApplicationParams extends AppConfigConnectionConfig { + applicationId: string + name?: string | null + description?: string | null +} + +export interface AppConfigDeleteApplicationParams extends AppConfigConnectionConfig { + applicationId: string +} + +export interface AppConfigGetEnvironmentParams extends AppConfigConnectionConfig { + applicationId: string + environmentId: string +} + +export interface AppConfigUpdateEnvironmentParams extends AppConfigConnectionConfig { + applicationId: string + environmentId: string + name?: string | null + description?: string | null +} + +export interface AppConfigDeleteEnvironmentParams extends AppConfigConnectionConfig { + applicationId: string + environmentId: string +} + +export interface AppConfigGetConfigurationProfileParams extends AppConfigConnectionConfig { + applicationId: string + configurationProfileId: string +} + +export interface AppConfigUpdateConfigurationProfileParams extends AppConfigConnectionConfig { + applicationId: string + configurationProfileId: string + name?: string | null + description?: string | null + retrievalRoleArn?: string | null +} + +export interface AppConfigDeleteConfigurationProfileParams extends AppConfigConnectionConfig { + applicationId: string + configurationProfileId: string +} + +export interface AppConfigDeleteHostedConfigurationVersionParams extends AppConfigConnectionConfig { + applicationId: string + configurationProfileId: string + versionNumber: number +} + +export interface AppConfigGetApplicationResponse extends ToolResponse { + output: { + id: string + name: string + description: string | null + } + error?: string +} + +export interface AppConfigUpdateApplicationResponse extends ToolResponse { + output: { + message: string + id: string + name: string + description: string | null + } + error?: string +} + +export interface AppConfigGetEnvironmentResponse extends ToolResponse { + output: { + applicationId: string + id: string + name: string + description: string | null + state: string | null + monitors: Array<{ alarmArn: string; alarmRoleArn: string | null }> + } + error?: string +} + +export interface AppConfigUpdateEnvironmentResponse extends ToolResponse { + output: { + message: string + applicationId: string + id: string + name: string + state: string | null + } + error?: string +} + +export interface AppConfigGetConfigurationProfileResponse extends ToolResponse { + output: { + applicationId: string + id: string + name: string + description: string | null + locationUri: string | null + retrievalRoleArn: string | null + type: string | null + validators: Array<{ type: string }> + } + error?: string +} + +export interface AppConfigUpdateConfigurationProfileResponse extends ToolResponse { + output: { + message: string + applicationId: string + id: string + name: string + description: string | null + type: string | null + } + error?: string +} + +export interface AppConfigDeleteResourceResponse extends ToolResponse { + output: { + message: string + applicationId?: string + id: string + } + error?: string +} + +export interface AppConfigDeleteHostedConfigurationVersionResponse extends ToolResponse { + output: { + message: string + applicationId: string + configurationProfileId: string + versionNumber: number + } + error?: string +} diff --git a/apps/sim/tools/appconfig/update_application.ts b/apps/sim/tools/appconfig/update_application.ts new file mode 100644 index 00000000000..2c4278250a6 --- /dev/null +++ b/apps/sim/tools/appconfig/update_application.ts @@ -0,0 +1,97 @@ +import type { + AppConfigUpdateApplicationParams, + AppConfigUpdateApplicationResponse, +} from '@/tools/appconfig/types' +import type { ToolConfig } from '@/tools/types' + +export const updateApplicationTool: ToolConfig< + AppConfigUpdateApplicationParams, + AppConfigUpdateApplicationResponse +> = { + id: 'appconfig_update_application', + name: 'AppConfig Update Application', + description: 'Update the name or description of an AWS AppConfig application', + version: '1.0', + + params: { + region: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + accessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + secretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + applicationId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The application ID to update', + }, + name: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'New name for the application', + }, + description: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'New description for the application', + }, + }, + + request: { + url: '/api/tools/appconfig/update-application', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + applicationId: params.applicationId, + name: params.name, + description: params.description, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || 'Failed to update AppConfig application') + } + + return { + success: true, + output: { + message: data.message ?? '', + id: data.id ?? '', + name: data.name ?? '', + description: data.description ?? null, + }, + } + }, + + outputs: { + message: { type: 'string', description: 'Operation status message' }, + id: { type: 'string', description: 'ID of the updated application' }, + name: { type: 'string', description: 'Name of the updated application' }, + description: { + type: 'string', + description: 'Description of the updated application', + optional: true, + }, + }, +} diff --git a/apps/sim/tools/appconfig/update_configuration_profile.ts b/apps/sim/tools/appconfig/update_configuration_profile.ts new file mode 100644 index 00000000000..360eff3c954 --- /dev/null +++ b/apps/sim/tools/appconfig/update_configuration_profile.ts @@ -0,0 +1,112 @@ +import type { + AppConfigUpdateConfigurationProfileParams, + AppConfigUpdateConfigurationProfileResponse, +} from '@/tools/appconfig/types' +import type { ToolConfig } from '@/tools/types' + +export const updateConfigurationProfileTool: ToolConfig< + AppConfigUpdateConfigurationProfileParams, + AppConfigUpdateConfigurationProfileResponse +> = { + id: 'appconfig_update_configuration_profile', + name: 'AppConfig Update Configuration Profile', + description: + 'Update the name, description, or retrieval role of an AppConfig configuration profile', + version: '1.0', + + params: { + region: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + accessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + secretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + applicationId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The application ID that owns the configuration profile', + }, + configurationProfileId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The configuration profile ID to update', + }, + name: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'New name for the configuration profile', + }, + description: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'New description for the configuration profile', + }, + retrievalRoleArn: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'New ARN of the IAM role used to retrieve the configuration', + }, + }, + + request: { + url: '/api/tools/appconfig/update-configuration-profile', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + applicationId: params.applicationId, + configurationProfileId: params.configurationProfileId, + name: params.name, + description: params.description, + retrievalRoleArn: params.retrievalRoleArn, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || 'Failed to update AppConfig configuration profile') + } + + return { + success: true, + output: { + message: data.message ?? '', + applicationId: data.applicationId ?? '', + id: data.id ?? '', + name: data.name ?? '', + description: data.description ?? null, + type: data.type ?? null, + }, + } + }, + + outputs: { + message: { type: 'string', description: 'Operation status message' }, + applicationId: { type: 'string', description: 'Owning application ID' }, + id: { type: 'string', description: 'ID of the updated configuration profile' }, + name: { type: 'string', description: 'Name of the updated configuration profile' }, + description: { type: 'string', description: 'Description of the profile', optional: true }, + type: { type: 'string', description: 'Profile type', optional: true }, + }, +} diff --git a/apps/sim/tools/appconfig/update_environment.ts b/apps/sim/tools/appconfig/update_environment.ts new file mode 100644 index 00000000000..06c0e4c9cc1 --- /dev/null +++ b/apps/sim/tools/appconfig/update_environment.ts @@ -0,0 +1,102 @@ +import type { + AppConfigUpdateEnvironmentParams, + AppConfigUpdateEnvironmentResponse, +} from '@/tools/appconfig/types' +import type { ToolConfig } from '@/tools/types' + +export const updateEnvironmentTool: ToolConfig< + AppConfigUpdateEnvironmentParams, + AppConfigUpdateEnvironmentResponse +> = { + id: 'appconfig_update_environment', + name: 'AppConfig Update Environment', + description: 'Update the name or description of an AWS AppConfig environment', + version: '1.0', + + params: { + region: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS region (e.g., us-east-1)', + }, + accessKeyId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS access key ID', + }, + secretAccessKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'AWS secret access key', + }, + applicationId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The application ID that owns the environment', + }, + environmentId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The environment ID to update', + }, + name: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'New name for the environment', + }, + description: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'New description for the environment', + }, + }, + + request: { + url: '/api/tools/appconfig/update-environment', + method: 'POST', + headers: () => ({ 'Content-Type': 'application/json' }), + body: (params) => ({ + region: params.region, + accessKeyId: params.accessKeyId, + secretAccessKey: params.secretAccessKey, + applicationId: params.applicationId, + environmentId: params.environmentId, + name: params.name, + description: params.description, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || 'Failed to update AppConfig environment') + } + + return { + success: true, + output: { + message: data.message ?? '', + applicationId: data.applicationId ?? '', + id: data.id ?? '', + name: data.name ?? '', + state: data.state ?? null, + }, + } + }, + + outputs: { + message: { type: 'string', description: 'Operation status message' }, + applicationId: { type: 'string', description: 'Owning application ID' }, + id: { type: 'string', description: 'ID of the updated environment' }, + name: { type: 'string', description: 'Name of the updated environment' }, + state: { type: 'string', description: 'State of the updated environment', optional: true }, + }, +} diff --git a/apps/sim/tools/registry.ts b/apps/sim/tools/registry.ts index 084f78c6007..b944103dbfe 100644 --- a/apps/sim/tools/registry.ts +++ b/apps/sim/tools/registry.ts @@ -160,8 +160,15 @@ import { appConfigCreateConfigurationProfileTool, appConfigCreateEnvironmentTool, appConfigCreateHostedConfigurationVersionTool, + appConfigDeleteApplicationTool, + appConfigDeleteConfigurationProfileTool, + appConfigDeleteEnvironmentTool, + appConfigDeleteHostedConfigurationVersionTool, + appConfigGetApplicationTool, + appConfigGetConfigurationProfileTool, appConfigGetConfigurationTool, appConfigGetDeploymentTool, + appConfigGetEnvironmentTool, appConfigGetHostedConfigurationVersionTool, appConfigListApplicationsTool, appConfigListConfigurationProfilesTool, @@ -171,6 +178,9 @@ import { appConfigListHostedConfigurationVersionsTool, appConfigStartDeploymentTool, appConfigStopDeploymentTool, + appConfigUpdateApplicationTool, + appConfigUpdateConfigurationProfileTool, + appConfigUpdateEnvironmentTool, } from '@/tools/appconfig' import { arxivGetAuthorPapersTool, arxivGetPaperTool, arxivSearchTool } from '@/tools/arxiv' import { @@ -5255,13 +5265,23 @@ export const tools: Record = { appconfig_get_configuration: appConfigGetConfigurationTool, appconfig_list_applications: appConfigListApplicationsTool, appconfig_create_application: appConfigCreateApplicationTool, + appconfig_get_application: appConfigGetApplicationTool, + appconfig_update_application: appConfigUpdateApplicationTool, + appconfig_delete_application: appConfigDeleteApplicationTool, appconfig_list_environments: appConfigListEnvironmentsTool, appconfig_create_environment: appConfigCreateEnvironmentTool, + appconfig_get_environment: appConfigGetEnvironmentTool, + appconfig_update_environment: appConfigUpdateEnvironmentTool, + appconfig_delete_environment: appConfigDeleteEnvironmentTool, appconfig_list_configuration_profiles: appConfigListConfigurationProfilesTool, appconfig_create_configuration_profile: appConfigCreateConfigurationProfileTool, + appconfig_get_configuration_profile: appConfigGetConfigurationProfileTool, + appconfig_update_configuration_profile: appConfigUpdateConfigurationProfileTool, + appconfig_delete_configuration_profile: appConfigDeleteConfigurationProfileTool, appconfig_create_hosted_configuration_version: appConfigCreateHostedConfigurationVersionTool, appconfig_get_hosted_configuration_version: appConfigGetHostedConfigurationVersionTool, appconfig_list_hosted_configuration_versions: appConfigListHostedConfigurationVersionsTool, + appconfig_delete_hosted_configuration_version: appConfigDeleteHostedConfigurationVersionTool, appconfig_list_deployment_strategies: appConfigListDeploymentStrategiesTool, appconfig_start_deployment: appConfigStartDeploymentTool, appconfig_get_deployment: appConfigGetDeploymentTool, diff --git a/scripts/check-api-validation-contracts.ts b/scripts/check-api-validation-contracts.ts index ffee3f53c83..9921da3ab46 100644 --- a/scripts/check-api-validation-contracts.ts +++ b/scripts/check-api-validation-contracts.ts @@ -9,8 +9,8 @@ const QUERY_HOOKS_DIR = path.join(ROOT, 'apps/sim/hooks/queries') const SELECTOR_HOOKS_DIR = path.join(ROOT, 'apps/sim/hooks/selectors') const BASELINE = { - totalRoutes: 794, - zodRoutes: 794, + totalRoutes: 804, + zodRoutes: 804, nonZodRoutes: 0, } as const