chore: import upstream snapshot with attribution
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
Publish CLI Package / publish-npm (push) Has been cancelled
Publish Python SDK / publish-pypi (push) Has been cancelled
Publish TypeScript SDK / publish-npm (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:20:55 +08:00
commit d25d482dc2
13754 changed files with 4996608 additions and 0 deletions
@@ -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 CreateApplicationSchema = 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'),
name: z.string().min(1, 'Application name is required').max(64),
description: z.string().max(1024).nullish(),
})
const CreateApplicationResponseSchema = z.object({
message: z.string(),
id: z.string(),
name: z.string(),
description: z.string().nullable(),
})
export const awsAppConfigCreateApplicationContract = defineRouteContract({
method: 'POST',
path: '/api/tools/appconfig/create-application',
body: CreateApplicationSchema,
response: { mode: 'json', schema: CreateApplicationResponseSchema },
})
export type AwsAppConfigCreateApplicationRequest = ContractBodyInput<
typeof awsAppConfigCreateApplicationContract
>
export type AwsAppConfigCreateApplicationBody = ContractBody<
typeof awsAppConfigCreateApplicationContract
>
export type AwsAppConfigCreateApplicationResponse = ContractJsonResponse<
typeof awsAppConfigCreateApplicationContract
>
@@ -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
>
@@ -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
>
@@ -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
>
@@ -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
>
@@ -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
>
@@ -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
>
@@ -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
>
@@ -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<typeof awsAppConfigGetApplicationContract>
export type AwsAppConfigGetApplicationResponse = ContractJsonResponse<
typeof awsAppConfigGetApplicationContract
>
@@ -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
>
@@ -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
>
@@ -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<typeof awsAppConfigGetDeploymentContract>
export type AwsAppConfigGetDeploymentResponse = ContractJsonResponse<
typeof awsAppConfigGetDeploymentContract
>
@@ -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<typeof awsAppConfigGetEnvironmentContract>
export type AwsAppConfigGetEnvironmentResponse = ContractJsonResponse<
typeof awsAppConfigGetEnvironmentContract
>
@@ -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
>
@@ -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
>
@@ -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
>
@@ -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
>
@@ -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
>
@@ -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
>
@@ -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
>
@@ -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
>
@@ -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<typeof awsAppConfigStopDeploymentContract>
export type AwsAppConfigStopDeploymentResponse = ContractJsonResponse<
typeof awsAppConfigStopDeploymentContract
>
@@ -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
>
@@ -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
>
@@ -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
>
@@ -0,0 +1,72 @@
import { z } from 'zod'
import type {
ContractBody,
ContractBodyInput,
ContractJsonResponse,
} from '@/lib/api/contracts/types'
import { defineRouteContract } from '@/lib/api/contracts/types'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const BatchGetQueryExecutionSchema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
queryExecutionIds: z
.array(z.string().trim().min(1))
.min(1, 'At least one query execution ID is required')
.max(50, 'A maximum of 50 query execution IDs can be requested at once'),
})
const BatchGetQueryExecutionResponseSchema = z.object({
success: z.literal(true),
output: z.object({
queryExecutions: z.array(
z.object({
queryExecutionId: z.string(),
query: z.string().nullable(),
state: z.string().nullable(),
stateChangeReason: z.string().nullable(),
statementType: z.string().nullable(),
database: z.string().nullable(),
catalog: z.string().nullable(),
workGroup: z.string().nullable(),
submissionDateTime: z.number().nullable(),
completionDateTime: z.number().nullable(),
dataScannedInBytes: z.number().nullable(),
engineExecutionTimeInMillis: z.number().nullable(),
queryPlanningTimeInMillis: z.number().nullable(),
queryQueueTimeInMillis: z.number().nullable(),
totalExecutionTimeInMillis: z.number().nullable(),
outputLocation: z.string().nullable(),
})
),
unprocessedQueryExecutionIds: z.array(
z.object({
queryExecutionId: z.string().nullable(),
errorCode: z.string().nullable(),
errorMessage: z.string().nullable(),
})
),
}),
})
export const awsAthenaBatchGetQueryExecutionContract = defineRouteContract({
method: 'POST',
path: '/api/tools/athena/batch-get-query-execution',
body: BatchGetQueryExecutionSchema,
response: { mode: 'json', schema: BatchGetQueryExecutionResponseSchema },
})
export type AwsAthenaBatchGetQueryExecutionRequest = ContractBodyInput<
typeof awsAthenaBatchGetQueryExecutionContract
>
export type AwsAthenaBatchGetQueryExecutionBody = ContractBody<
typeof awsAthenaBatchGetQueryExecutionContract
>
export type AwsAthenaBatchGetQueryExecutionResponse = ContractJsonResponse<
typeof awsAthenaBatchGetQueryExecutionContract
>
@@ -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 CreateNamedQuerySchema = 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'),
name: z.string().min(1, 'Query name is required'),
database: z.string().min(1, 'Database is required'),
queryString: z.string().min(1, 'Query string is required'),
description: z.string().optional(),
workGroup: z.string().optional(),
})
const CreateNamedQueryResponseSchema = z.object({
success: z.literal(true),
output: z.object({
namedQueryId: z.string(),
}),
})
export const awsAthenaCreateNamedQueryContract = defineRouteContract({
method: 'POST',
path: '/api/tools/athena/create-named-query',
body: CreateNamedQuerySchema,
response: { mode: 'json', schema: CreateNamedQueryResponseSchema },
})
export type AwsAthenaCreateNamedQueryRequest = ContractBodyInput<
typeof awsAthenaCreateNamedQueryContract
>
export type AwsAthenaCreateNamedQueryBody = ContractBody<typeof awsAthenaCreateNamedQueryContract>
export type AwsAthenaCreateNamedQueryResponse = ContractJsonResponse<
typeof awsAthenaCreateNamedQueryContract
>
@@ -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'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const DeleteNamedQuerySchema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
namedQueryId: z.string().trim().min(1, 'Named query ID is required'),
})
const DeleteNamedQueryResponseSchema = z.object({
success: z.literal(true),
output: z.object({
success: z.literal(true),
}),
})
export const awsAthenaDeleteNamedQueryContract = defineRouteContract({
method: 'POST',
path: '/api/tools/athena/delete-named-query',
body: DeleteNamedQuerySchema,
response: { mode: 'json', schema: DeleteNamedQueryResponseSchema },
})
export type AwsAthenaDeleteNamedQueryRequest = ContractBodyInput<
typeof awsAthenaDeleteNamedQueryContract
>
export type AwsAthenaDeleteNamedQueryBody = ContractBody<typeof awsAthenaDeleteNamedQueryContract>
export type AwsAthenaDeleteNamedQueryResponse = ContractJsonResponse<
typeof awsAthenaDeleteNamedQueryContract
>
@@ -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 GetNamedQuerySchema = 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'),
namedQueryId: z.string().trim().min(1, 'Named query ID is required'),
})
const GetNamedQueryResponseSchema = z.object({
success: z.literal(true),
output: z.object({
namedQueryId: z.string(),
name: z.string(),
description: z.string().nullable(),
database: z.string(),
queryString: z.string(),
workGroup: z.string().nullable(),
}),
})
export const awsAthenaGetNamedQueryContract = defineRouteContract({
method: 'POST',
path: '/api/tools/athena/get-named-query',
body: GetNamedQuerySchema,
response: { mode: 'json', schema: GetNamedQueryResponseSchema },
})
export type AwsAthenaGetNamedQueryRequest = ContractBodyInput<typeof awsAthenaGetNamedQueryContract>
export type AwsAthenaGetNamedQueryBody = ContractBody<typeof awsAthenaGetNamedQueryContract>
export type AwsAthenaGetNamedQueryResponse = ContractJsonResponse<
typeof awsAthenaGetNamedQueryContract
>
@@ -0,0 +1,50 @@
import { z } from 'zod'
import type {
ContractBody,
ContractBodyInput,
ContractJsonResponse,
} from '@/lib/api/contracts/types'
import { defineRouteContract } from '@/lib/api/contracts/types'
const GetQueryExecutionSchema = 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'),
queryExecutionId: z.string().trim().min(1, 'Query execution ID is required'),
})
const GetQueryExecutionResponseSchema = z.object({
success: z.literal(true),
output: z.object({
queryExecutionId: z.string(),
query: z.string(),
state: z.string(),
stateChangeReason: z.string().nullable(),
statementType: z.string().nullable(),
database: z.string().nullable(),
catalog: z.string().nullable(),
workGroup: z.string().nullable(),
submissionDateTime: z.number().nullable(),
completionDateTime: z.number().nullable(),
dataScannedInBytes: z.number().nullable(),
engineExecutionTimeInMillis: z.number().nullable(),
queryPlanningTimeInMillis: z.number().nullable(),
queryQueueTimeInMillis: z.number().nullable(),
totalExecutionTimeInMillis: z.number().nullable(),
outputLocation: z.string().nullable(),
}),
})
export const awsAthenaGetQueryExecutionContract = defineRouteContract({
method: 'POST',
path: '/api/tools/athena/get-query-execution',
body: GetQueryExecutionSchema,
response: { mode: 'json', schema: GetQueryExecutionResponseSchema },
})
export type AwsAthenaGetQueryExecutionRequest = ContractBodyInput<
typeof awsAthenaGetQueryExecutionContract
>
export type AwsAthenaGetQueryExecutionBody = ContractBody<typeof awsAthenaGetQueryExecutionContract>
export type AwsAthenaGetQueryExecutionResponse = ContractJsonResponse<
typeof awsAthenaGetQueryExecutionContract
>
@@ -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 GetQueryResultsSchema = 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'),
queryExecutionId: z.string().trim().min(1, 'Query execution ID is required'),
maxResults: z.preprocess(
(v) => (v === '' || v === undefined || v === null ? undefined : v),
z.coerce.number().int().positive().max(999).optional()
),
nextToken: z.string().optional(),
})
const GetQueryResultsResponseSchema = z.object({
success: z.literal(true),
output: z.object({
columns: z.array(
z.object({
name: z.string(),
type: z.string(),
})
),
rows: z.array(z.record(z.string(), z.string())),
nextToken: z.string().nullable(),
updateCount: z.number().nullable(),
}),
})
export const awsAthenaGetQueryResultsContract = defineRouteContract({
method: 'POST',
path: '/api/tools/athena/get-query-results',
body: GetQueryResultsSchema,
response: { mode: 'json', schema: GetQueryResultsResponseSchema },
})
export type AwsAthenaGetQueryResultsRequest = ContractBodyInput<
typeof awsAthenaGetQueryResultsContract
>
export type AwsAthenaGetQueryResultsBody = ContractBody<typeof awsAthenaGetQueryResultsContract>
export type AwsAthenaGetQueryResultsResponse = ContractJsonResponse<
typeof awsAthenaGetQueryResultsContract
>
@@ -0,0 +1,51 @@
import { z } from 'zod'
import type {
ContractBody,
ContractBodyInput,
ContractJsonResponse,
} from '@/lib/api/contracts/types'
import { defineRouteContract } from '@/lib/api/contracts/types'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const ListDatabasesSchema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
catalogName: z.string().trim().min(1, 'Data catalog name is required'),
workGroup: z.string().optional(),
maxResults: z.preprocess(
(v) => (v === '' || v === undefined || v === null ? undefined : v),
z.coerce.number().int().min(1).max(50).optional()
),
nextToken: z.string().optional(),
})
const ListDatabasesResponseSchema = z.object({
success: z.literal(true),
output: z.object({
databases: z.array(
z.object({
name: z.string(),
description: z.string().nullable(),
})
),
nextToken: z.string().nullable(),
}),
})
export const awsAthenaListDatabasesContract = defineRouteContract({
method: 'POST',
path: '/api/tools/athena/list-databases',
body: ListDatabasesSchema,
response: { mode: 'json', schema: ListDatabasesResponseSchema },
})
export type AwsAthenaListDatabasesRequest = ContractBodyInput<typeof awsAthenaListDatabasesContract>
export type AwsAthenaListDatabasesBody = ContractBody<typeof awsAthenaListDatabasesContract>
export type AwsAthenaListDatabasesResponse = ContractJsonResponse<
typeof awsAthenaListDatabasesContract
>
@@ -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 ListNamedQueriesSchema = 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'),
workGroup: z.string().optional(),
maxResults: z.preprocess(
(v) => (v === '' || v === undefined || v === null ? undefined : v),
z.coerce.number().int().min(0).max(50).optional()
),
nextToken: z.string().optional(),
})
const ListNamedQueriesResponseSchema = z.object({
success: z.literal(true),
output: z.object({
namedQueryIds: z.array(z.string()),
nextToken: z.string().nullable(),
}),
})
export const awsAthenaListNamedQueriesContract = defineRouteContract({
method: 'POST',
path: '/api/tools/athena/list-named-queries',
body: ListNamedQueriesSchema,
response: { mode: 'json', schema: ListNamedQueriesResponseSchema },
})
export type AwsAthenaListNamedQueriesRequest = ContractBodyInput<
typeof awsAthenaListNamedQueriesContract
>
export type AwsAthenaListNamedQueriesBody = ContractBody<typeof awsAthenaListNamedQueriesContract>
export type AwsAthenaListNamedQueriesResponse = ContractJsonResponse<
typeof awsAthenaListNamedQueriesContract
>
@@ -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 ListQueryExecutionsSchema = 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'),
workGroup: z.string().optional(),
maxResults: z.preprocess(
(v) => (v === '' || v === undefined || v === null ? undefined : v),
z.coerce.number().int().min(0).max(50).optional()
),
nextToken: z.string().optional(),
})
const ListQueryExecutionsResponseSchema = z.object({
success: z.literal(true),
output: z.object({
queryExecutionIds: z.array(z.string()),
nextToken: z.string().nullable(),
}),
})
export const awsAthenaListQueryExecutionsContract = defineRouteContract({
method: 'POST',
path: '/api/tools/athena/list-query-executions',
body: ListQueryExecutionsSchema,
response: { mode: 'json', schema: ListQueryExecutionsResponseSchema },
})
export type AwsAthenaListQueryExecutionsRequest = ContractBodyInput<
typeof awsAthenaListQueryExecutionsContract
>
export type AwsAthenaListQueryExecutionsBody = ContractBody<
typeof awsAthenaListQueryExecutionsContract
>
export type AwsAthenaListQueryExecutionsResponse = ContractJsonResponse<
typeof awsAthenaListQueryExecutionsContract
>
@@ -0,0 +1,65 @@
import { z } from 'zod'
import type {
ContractBody,
ContractBodyInput,
ContractJsonResponse,
} from '@/lib/api/contracts/types'
import { defineRouteContract } from '@/lib/api/contracts/types'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const ColumnSchema = z.object({
name: z.string(),
type: z.string().nullable(),
comment: z.string().nullable(),
})
const ListTableMetadataSchema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
catalogName: z.string().trim().min(1, 'Data catalog name is required'),
databaseName: z.string().trim().min(1, 'Database name is required'),
expression: z.string().optional(),
workGroup: z.string().optional(),
maxResults: z.preprocess(
(v) => (v === '' || v === undefined || v === null ? undefined : v),
z.coerce.number().int().min(1).max(50).optional()
),
nextToken: z.string().optional(),
})
const ListTableMetadataResponseSchema = z.object({
success: z.literal(true),
output: z.object({
tables: z.array(
z.object({
name: z.string(),
tableType: z.string().nullable(),
createTime: z.number().nullable(),
lastAccessTime: z.number().nullable(),
columns: z.array(ColumnSchema),
partitionKeys: z.array(ColumnSchema),
})
),
nextToken: z.string().nullable(),
}),
})
export const awsAthenaListTableMetadataContract = defineRouteContract({
method: 'POST',
path: '/api/tools/athena/list-table-metadata',
body: ListTableMetadataSchema,
response: { mode: 'json', schema: ListTableMetadataResponseSchema },
})
export type AwsAthenaListTableMetadataRequest = ContractBodyInput<
typeof awsAthenaListTableMetadataContract
>
export type AwsAthenaListTableMetadataBody = ContractBody<typeof awsAthenaListTableMetadataContract>
export type AwsAthenaListTableMetadataResponse = ContractJsonResponse<
typeof awsAthenaListTableMetadataContract
>
@@ -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 StartQuerySchema = 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'),
queryString: z.string().min(1, 'Query string is required'),
database: z.string().optional(),
catalog: z.string().optional(),
outputLocation: z.string().optional(),
workGroup: z.string().optional(),
})
const StartQueryResponseSchema = z.object({
success: z.literal(true),
output: z.object({
queryExecutionId: z.string(),
}),
})
export const awsAthenaStartQueryContract = defineRouteContract({
method: 'POST',
path: '/api/tools/athena/start-query',
body: StartQuerySchema,
response: { mode: 'json', schema: StartQueryResponseSchema },
})
export type AwsAthenaStartQueryRequest = ContractBodyInput<typeof awsAthenaStartQueryContract>
export type AwsAthenaStartQueryBody = ContractBody<typeof awsAthenaStartQueryContract>
export type AwsAthenaStartQueryResponse = ContractJsonResponse<typeof awsAthenaStartQueryContract>
@@ -0,0 +1,31 @@
import { z } from 'zod'
import type {
ContractBody,
ContractBodyInput,
ContractJsonResponse,
} from '@/lib/api/contracts/types'
import { defineRouteContract } from '@/lib/api/contracts/types'
const StopQuerySchema = 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'),
queryExecutionId: z.string().trim().min(1, 'Query execution ID is required'),
})
const StopQueryResponseSchema = z.object({
success: z.literal(true),
output: z.object({
success: z.literal(true),
}),
})
export const awsAthenaStopQueryContract = defineRouteContract({
method: 'POST',
path: '/api/tools/athena/stop-query',
body: StopQuerySchema,
response: { mode: 'json', schema: StopQueryResponseSchema },
})
export type AwsAthenaStopQueryRequest = ContractBodyInput<typeof awsAthenaStopQueryContract>
export type AwsAthenaStopQueryBody = ContractBody<typeof awsAthenaStopQueryContract>
export type AwsAthenaStopQueryResponse = ContractJsonResponse<typeof awsAthenaStopQueryContract>
@@ -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'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const CancelUpdateStackSchema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
stackName: z.string().min(1, 'Stack name is required'),
})
const CancelUpdateStackResponseSchema = z.object({
success: z.literal(true),
output: z.object({
message: z.string(),
}),
})
export const awsCloudformationCancelUpdateStackContract = defineRouteContract({
method: 'POST',
path: '/api/tools/cloudformation/cancel-update-stack',
body: CancelUpdateStackSchema,
response: { mode: 'json', schema: CancelUpdateStackResponseSchema },
})
export type AwsCloudformationCancelUpdateStackRequest = ContractBodyInput<
typeof awsCloudformationCancelUpdateStackContract
>
export type AwsCloudformationCancelUpdateStackBody = ContractBody<
typeof awsCloudformationCancelUpdateStackContract
>
export type AwsCloudformationCancelUpdateStackResponse = ContractJsonResponse<
typeof awsCloudformationCancelUpdateStackContract
>
@@ -0,0 +1,86 @@
import { z } from 'zod'
import type {
ContractBody,
ContractBodyInput,
ContractJsonResponse,
} from '@/lib/api/contracts/types'
import { defineRouteContract } from '@/lib/api/contracts/types'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const CreateChangeSetSchema = z
.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
stackName: z.string().min(1, 'Stack name is required'),
changeSetName: z.string().min(1, 'Change set name is required'),
templateBody: z.string().optional(),
usePreviousTemplate: z.boolean().optional(),
parameters: z
.array(
z.object({
parameterKey: z.string().min(1, 'Parameter key is required'),
parameterValue: z.string().optional(),
usePreviousValue: z.boolean().optional(),
})
)
.optional(),
capabilities: z
.string()
.optional()
.refine(
(v) =>
!v ||
v
.split(',')
.map((c) => c.trim())
.filter(Boolean)
.every((c) =>
['CAPABILITY_IAM', 'CAPABILITY_NAMED_IAM', 'CAPABILITY_AUTO_EXPAND'].includes(c)
),
{
message:
'capabilities must be a comma-separated list of CAPABILITY_IAM, CAPABILITY_NAMED_IAM, CAPABILITY_AUTO_EXPAND',
}
),
changeSetType: z.enum(['CREATE', 'UPDATE', 'IMPORT']).optional(),
description: z.string().max(1024, 'Description must be at most 1024 characters').optional(),
})
.superRefine((data, ctx) => {
if (!data.templateBody && !data.usePreviousTemplate) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: 'Either templateBody must be provided or usePreviousTemplate must be true',
path: ['templateBody'],
})
}
})
const CreateChangeSetResponseSchema = z.object({
success: z.literal(true),
output: z.object({
changeSetId: z.string(),
stackId: z.string(),
}),
})
export const awsCloudformationCreateChangeSetContract = defineRouteContract({
method: 'POST',
path: '/api/tools/cloudformation/create-change-set',
body: CreateChangeSetSchema,
response: { mode: 'json', schema: CreateChangeSetResponseSchema },
})
export type AwsCloudformationCreateChangeSetRequest = ContractBodyInput<
typeof awsCloudformationCreateChangeSetContract
>
export type AwsCloudformationCreateChangeSetBody = ContractBody<
typeof awsCloudformationCreateChangeSetContract
>
export type AwsCloudformationCreateChangeSetResponse = ContractJsonResponse<
typeof awsCloudformationCreateChangeSetContract
>
@@ -0,0 +1,84 @@
import { z } from 'zod'
import type {
ContractBody,
ContractBodyInput,
ContractJsonResponse,
} from '@/lib/api/contracts/types'
import { defineRouteContract } from '@/lib/api/contracts/types'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const CreateStackSchema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
stackName: z.string().min(1, 'Stack name is required'),
templateBody: z.string().min(1, 'Template body is required'),
parameters: z
.array(
z.object({
parameterKey: z.string().min(1, 'Parameter key is required'),
parameterValue: z.string().optional(),
usePreviousValue: z.boolean().optional(),
})
)
.optional(),
capabilities: z
.string()
.optional()
.refine(
(v) =>
!v ||
v
.split(',')
.map((c) => c.trim())
.filter(Boolean)
.every((c) =>
['CAPABILITY_IAM', 'CAPABILITY_NAMED_IAM', 'CAPABILITY_AUTO_EXPAND'].includes(c)
),
{
message:
'capabilities must be a comma-separated list of CAPABILITY_IAM, CAPABILITY_NAMED_IAM, CAPABILITY_AUTO_EXPAND',
}
),
tags: z
.array(
z.object({
key: z
.string()
.min(1, 'Tag key is required')
.max(128, 'Tag key must be at most 128 characters'),
value: z.string().max(256, 'Tag value must be at most 256 characters'),
})
)
.optional(),
onFailure: z.enum(['ROLLBACK', 'DELETE', 'DO_NOTHING']).optional(),
timeoutInMinutes: z.coerce.number().int().positive().optional(),
})
const CreateStackResponseSchema = z.object({
success: z.literal(true),
output: z.object({
stackId: z.string(),
}),
})
export const awsCloudformationCreateStackContract = defineRouteContract({
method: 'POST',
path: '/api/tools/cloudformation/create-stack',
body: CreateStackSchema,
response: { mode: 'json', schema: CreateStackResponseSchema },
})
export type AwsCloudformationCreateStackRequest = ContractBodyInput<
typeof awsCloudformationCreateStackContract
>
export type AwsCloudformationCreateStackBody = ContractBody<
typeof awsCloudformationCreateStackContract
>
export type AwsCloudformationCreateStackResponse = ContractJsonResponse<
typeof awsCloudformationCreateStackContract
>
@@ -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'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const DeleteStackSchema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
stackName: z.string().min(1, 'Stack name is required'),
retainResources: z.string().optional(),
})
const DeleteStackResponseSchema = z.object({
success: z.literal(true),
output: z.object({
message: z.string(),
}),
})
export const awsCloudformationDeleteStackContract = defineRouteContract({
method: 'POST',
path: '/api/tools/cloudformation/delete-stack',
body: DeleteStackSchema,
response: { mode: 'json', schema: DeleteStackResponseSchema },
})
export type AwsCloudformationDeleteStackRequest = ContractBodyInput<
typeof awsCloudformationDeleteStackContract
>
export type AwsCloudformationDeleteStackBody = ContractBody<
typeof awsCloudformationDeleteStackContract
>
export type AwsCloudformationDeleteStackResponse = ContractJsonResponse<
typeof awsCloudformationDeleteStackContract
>
@@ -0,0 +1,62 @@
import { z } from 'zod'
import type {
ContractBody,
ContractBodyInput,
ContractJsonResponse,
} from '@/lib/api/contracts/types'
import { defineRouteContract } from '@/lib/api/contracts/types'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const DescribeChangeSetSchema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
changeSetName: z.string().min(1, 'Change set name is required'),
stackName: z.string().optional(),
})
const DescribeChangeSetResponseSchema = z.object({
success: z.literal(true),
output: z.object({
changeSetName: z.string().optional(),
changeSetId: z.string().optional(),
stackId: z.string().optional(),
stackName: z.string().optional(),
description: z.string().optional(),
executionStatus: z.string().optional(),
status: z.string().optional(),
statusReason: z.string().optional(),
creationTime: z.number().optional(),
capabilities: z.array(z.string()),
changes: z.array(
z.object({
action: z.string().optional(),
logicalResourceId: z.string().optional(),
physicalResourceId: z.string().optional(),
resourceType: z.string().optional(),
replacement: z.string().optional(),
})
),
}),
})
export const awsCloudformationDescribeChangeSetContract = defineRouteContract({
method: 'POST',
path: '/api/tools/cloudformation/describe-change-set',
body: DescribeChangeSetSchema,
response: { mode: 'json', schema: DescribeChangeSetResponseSchema },
})
export type AwsCloudformationDescribeChangeSetRequest = ContractBodyInput<
typeof awsCloudformationDescribeChangeSetContract
>
export type AwsCloudformationDescribeChangeSetBody = ContractBody<
typeof awsCloudformationDescribeChangeSetContract
>
export type AwsCloudformationDescribeChangeSetResponse = ContractJsonResponse<
typeof awsCloudformationDescribeChangeSetContract
>
@@ -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 DescribeStackDriftDetectionStatusSchema = 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'),
stackDriftDetectionId: z.string().min(1, 'Stack drift detection ID is required'),
})
const DescribeStackDriftDetectionStatusResponseSchema = z.object({
success: z.literal(true),
output: z.object({
stackId: z.string(),
stackDriftDetectionId: z.string(),
stackDriftStatus: z.string().optional(),
detectionStatus: z.string(),
detectionStatusReason: z.string().optional(),
driftedStackResourceCount: z.number().optional(),
timestamp: z.number().optional(),
}),
})
export const awsCloudformationDescribeStackDriftDetectionStatusContract = defineRouteContract({
method: 'POST',
path: '/api/tools/cloudformation/describe-stack-drift-detection-status',
body: DescribeStackDriftDetectionStatusSchema,
response: { mode: 'json', schema: DescribeStackDriftDetectionStatusResponseSchema },
})
export type AwsCloudformationDescribeStackDriftDetectionStatusRequest = ContractBodyInput<
typeof awsCloudformationDescribeStackDriftDetectionStatusContract
>
export type AwsCloudformationDescribeStackDriftDetectionStatusBody = ContractBody<
typeof awsCloudformationDescribeStackDriftDetectionStatusContract
>
export type AwsCloudformationDescribeStackDriftDetectionStatusResponse = ContractJsonResponse<
typeof awsCloudformationDescribeStackDriftDetectionStatusContract
>
@@ -0,0 +1,53 @@
import { z } from 'zod'
import type {
ContractBody,
ContractBodyInput,
ContractJsonResponse,
} from '@/lib/api/contracts/types'
import { defineRouteContract } from '@/lib/api/contracts/types'
const DescribeStackEventsSchema = 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'),
stackName: z.string().min(1, 'Stack name is required'),
limit: z.preprocess(
(v) => (v === '' || v === undefined || v === null ? undefined : v),
z.coerce.number().int().positive().optional()
),
})
const DescribeStackEventsResponseSchema = z.object({
success: z.literal(true),
output: z.object({
events: z.array(
z.object({
stackId: z.string(),
eventId: z.string(),
stackName: z.string(),
logicalResourceId: z.string().optional(),
physicalResourceId: z.string().optional(),
resourceType: z.string().optional(),
resourceStatus: z.string().optional(),
resourceStatusReason: z.string().optional(),
timestamp: z.number().optional(),
})
),
}),
})
export const awsCloudformationDescribeStackEventsContract = defineRouteContract({
method: 'POST',
path: '/api/tools/cloudformation/describe-stack-events',
body: DescribeStackEventsSchema,
response: { mode: 'json', schema: DescribeStackEventsResponseSchema },
})
export type AwsCloudformationDescribeStackEventsRequest = ContractBodyInput<
typeof awsCloudformationDescribeStackEventsContract
>
export type AwsCloudformationDescribeStackEventsBody = ContractBody<
typeof awsCloudformationDescribeStackEventsContract
>
export type AwsCloudformationDescribeStackEventsResponse = ContractJsonResponse<
typeof awsCloudformationDescribeStackEventsContract
>
@@ -0,0 +1,67 @@
import { z } from 'zod'
import type {
ContractBody,
ContractBodyInput,
ContractJsonResponse,
} from '@/lib/api/contracts/types'
import { defineRouteContract } from '@/lib/api/contracts/types'
const DescribeStacksSchema = 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'),
stackName: z.string().optional(),
})
const DescribeStacksResponseSchema = z.object({
success: z.literal(true),
output: z.object({
stacks: z.array(
z.object({
stackName: z.string(),
stackId: z.string(),
stackStatus: z.string(),
stackStatusReason: z.string().optional(),
creationTime: z.number().optional(),
lastUpdatedTime: z.number().optional(),
description: z.string().optional(),
enableTerminationProtection: z.boolean().optional(),
driftInformation: z
.object({
stackDriftStatus: z.string().optional(),
lastCheckTimestamp: z.number().optional(),
})
.nullable(),
outputs: z.array(
z.object({
outputKey: z.string(),
outputValue: z.string(),
description: z.string().optional(),
})
),
tags: z.array(
z.object({
key: z.string(),
value: z.string(),
})
),
})
),
}),
})
export const awsCloudformationDescribeStacksContract = defineRouteContract({
method: 'POST',
path: '/api/tools/cloudformation/describe-stacks',
body: DescribeStacksSchema,
response: { mode: 'json', schema: DescribeStacksResponseSchema },
})
export type AwsCloudformationDescribeStacksRequest = ContractBodyInput<
typeof awsCloudformationDescribeStacksContract
>
export type AwsCloudformationDescribeStacksBody = ContractBody<
typeof awsCloudformationDescribeStacksContract
>
export type AwsCloudformationDescribeStacksResponse = ContractJsonResponse<
typeof awsCloudformationDescribeStacksContract
>
@@ -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 DetectStackDriftSchema = 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'),
stackName: z.string().min(1, 'Stack name is required'),
})
const DetectStackDriftResponseSchema = z.object({
success: z.literal(true),
output: z.object({
stackDriftDetectionId: z.string(),
}),
})
export const awsCloudformationDetectStackDriftContract = defineRouteContract({
method: 'POST',
path: '/api/tools/cloudformation/detect-stack-drift',
body: DetectStackDriftSchema,
response: { mode: 'json', schema: DetectStackDriftResponseSchema },
})
export type AwsCloudformationDetectStackDriftRequest = ContractBodyInput<
typeof awsCloudformationDetectStackDriftContract
>
export type AwsCloudformationDetectStackDriftBody = ContractBody<
typeof awsCloudformationDetectStackDriftContract
>
export type AwsCloudformationDetectStackDriftResponse = ContractJsonResponse<
typeof awsCloudformationDetectStackDriftContract
>
@@ -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'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const ExecuteChangeSetSchema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
changeSetName: z.string().min(1, 'Change set name is required'),
stackName: z.string().optional(),
})
const ExecuteChangeSetResponseSchema = z.object({
success: z.literal(true),
output: z.object({
message: z.string(),
}),
})
export const awsCloudformationExecuteChangeSetContract = defineRouteContract({
method: 'POST',
path: '/api/tools/cloudformation/execute-change-set',
body: ExecuteChangeSetSchema,
response: { mode: 'json', schema: ExecuteChangeSetResponseSchema },
})
export type AwsCloudformationExecuteChangeSetRequest = ContractBodyInput<
typeof awsCloudformationExecuteChangeSetContract
>
export type AwsCloudformationExecuteChangeSetBody = ContractBody<
typeof awsCloudformationExecuteChangeSetContract
>
export type AwsCloudformationExecuteChangeSetResponse = ContractJsonResponse<
typeof awsCloudformationExecuteChangeSetContract
>
@@ -0,0 +1,68 @@
import { z } from 'zod'
import type {
ContractBody,
ContractBodyInput,
ContractJsonResponse,
} from '@/lib/api/contracts/types'
import { defineRouteContract } from '@/lib/api/contracts/types'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const GetTemplateSummarySchema = z
.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
templateBody: z.string().optional(),
stackName: z.string().optional(),
})
.superRefine((data, ctx) => {
if (!data.templateBody && !data.stackName) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: 'Either templateBody or stackName is required',
path: ['templateBody'],
})
}
})
const GetTemplateSummaryResponseSchema = z.object({
success: z.literal(true),
output: z.object({
description: z.string().optional(),
parameters: z.array(
z.object({
parameterKey: z.string().optional(),
defaultValue: z.string().optional(),
parameterType: z.string().optional(),
noEcho: z.boolean().optional(),
description: z.string().optional(),
})
),
capabilities: z.array(z.string()),
capabilitiesReason: z.string().optional(),
resourceTypes: z.array(z.string()),
version: z.string().optional(),
declaredTransforms: z.array(z.string()),
}),
})
export const awsCloudformationGetTemplateSummaryContract = defineRouteContract({
method: 'POST',
path: '/api/tools/cloudformation/get-template-summary',
body: GetTemplateSummarySchema,
response: { mode: 'json', schema: GetTemplateSummaryResponseSchema },
})
export type AwsCloudformationGetTemplateSummaryRequest = ContractBodyInput<
typeof awsCloudformationGetTemplateSummaryContract
>
export type AwsCloudformationGetTemplateSummaryBody = ContractBody<
typeof awsCloudformationGetTemplateSummaryContract
>
export type AwsCloudformationGetTemplateSummaryResponse = ContractJsonResponse<
typeof awsCloudformationGetTemplateSummaryContract
>
@@ -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 GetTemplateSchema = 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'),
stackName: z.string().min(1, 'Stack name is required'),
templateStage: z.enum(['Original', 'Processed']).optional(),
})
const GetTemplateResponseSchema = z.object({
success: z.literal(true),
output: z.object({
templateBody: z.string(),
stagesAvailable: z.array(z.string()),
}),
})
export const awsCloudformationGetTemplateContract = defineRouteContract({
method: 'POST',
path: '/api/tools/cloudformation/get-template',
body: GetTemplateSchema,
response: { mode: 'json', schema: GetTemplateResponseSchema },
})
export type AwsCloudformationGetTemplateRequest = ContractBodyInput<
typeof awsCloudformationGetTemplateContract
>
export type AwsCloudformationGetTemplateBody = ContractBody<
typeof awsCloudformationGetTemplateContract
>
export type AwsCloudformationGetTemplateResponse = ContractJsonResponse<
typeof awsCloudformationGetTemplateContract
>
@@ -0,0 +1,52 @@
import { z } from 'zod'
import type {
ContractBody,
ContractBodyInput,
ContractJsonResponse,
} from '@/lib/api/contracts/types'
import { defineRouteContract } from '@/lib/api/contracts/types'
const ListStackResourcesSchema = 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'),
stackName: z.string().min(1, 'Stack name is required'),
})
const ListStackResourcesResponseSchema = z.object({
success: z.literal(true),
output: z.object({
resources: z.array(
z.object({
logicalResourceId: z.string(),
physicalResourceId: z.string().optional(),
resourceType: z.string(),
resourceStatus: z.string(),
resourceStatusReason: z.string().optional(),
lastUpdatedTimestamp: z.number().optional(),
driftInformation: z
.object({
stackResourceDriftStatus: z.string().optional(),
lastCheckTimestamp: z.number().optional(),
})
.nullable(),
})
),
}),
})
export const awsCloudformationListStackResourcesContract = defineRouteContract({
method: 'POST',
path: '/api/tools/cloudformation/list-stack-resources',
body: ListStackResourcesSchema,
response: { mode: 'json', schema: ListStackResourcesResponseSchema },
})
export type AwsCloudformationListStackResourcesRequest = ContractBodyInput<
typeof awsCloudformationListStackResourcesContract
>
export type AwsCloudformationListStackResourcesBody = ContractBody<
typeof awsCloudformationListStackResourcesContract
>
export type AwsCloudformationListStackResourcesResponse = ContractJsonResponse<
typeof awsCloudformationListStackResourcesContract
>
@@ -0,0 +1,93 @@
import { z } from 'zod'
import type {
ContractBody,
ContractBodyInput,
ContractJsonResponse,
} from '@/lib/api/contracts/types'
import { defineRouteContract } from '@/lib/api/contracts/types'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const UpdateStackSchema = z
.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
stackName: z.string().min(1, 'Stack name is required'),
templateBody: z.string().optional(),
usePreviousTemplate: z.boolean().optional(),
parameters: z
.array(
z.object({
parameterKey: z.string().min(1, 'Parameter key is required'),
parameterValue: z.string().optional(),
usePreviousValue: z.boolean().optional(),
})
)
.optional(),
capabilities: z
.string()
.optional()
.refine(
(v) =>
!v ||
v
.split(',')
.map((c) => c.trim())
.filter(Boolean)
.every((c) =>
['CAPABILITY_IAM', 'CAPABILITY_NAMED_IAM', 'CAPABILITY_AUTO_EXPAND'].includes(c)
),
{
message:
'capabilities must be a comma-separated list of CAPABILITY_IAM, CAPABILITY_NAMED_IAM, CAPABILITY_AUTO_EXPAND',
}
),
tags: z
.array(
z.object({
key: z
.string()
.min(1, 'Tag key is required')
.max(128, 'Tag key must be at most 128 characters'),
value: z.string().max(256, 'Tag value must be at most 256 characters'),
})
)
.optional(),
})
.superRefine((data, ctx) => {
if (!data.templateBody && !data.usePreviousTemplate) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: 'Either templateBody must be provided or usePreviousTemplate must be true',
path: ['templateBody'],
})
}
})
const UpdateStackResponseSchema = z.object({
success: z.literal(true),
output: z.object({
stackId: z.string(),
}),
})
export const awsCloudformationUpdateStackContract = defineRouteContract({
method: 'POST',
path: '/api/tools/cloudformation/update-stack',
body: UpdateStackSchema,
response: { mode: 'json', schema: UpdateStackResponseSchema },
})
export type AwsCloudformationUpdateStackRequest = ContractBodyInput<
typeof awsCloudformationUpdateStackContract
>
export type AwsCloudformationUpdateStackBody = ContractBody<
typeof awsCloudformationUpdateStackContract
>
export type AwsCloudformationUpdateStackResponse = ContractJsonResponse<
typeof awsCloudformationUpdateStackContract
>
@@ -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 ValidateTemplateSchema = 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'),
templateBody: z.string().min(1, 'Template body is required'),
})
const ValidateTemplateResponseSchema = z.object({
success: z.literal(true),
output: z.object({
description: z.string().optional(),
parameters: z.array(
z.object({
parameterKey: z.string().optional(),
defaultValue: z.string().optional(),
noEcho: z.boolean().optional(),
description: z.string().optional(),
})
),
capabilities: z.array(z.string()),
capabilitiesReason: z.string().optional(),
declaredTransforms: z.array(z.string()),
}),
})
export const awsCloudformationValidateTemplateContract = defineRouteContract({
method: 'POST',
path: '/api/tools/cloudformation/validate-template',
body: ValidateTemplateSchema,
response: { mode: 'json', schema: ValidateTemplateResponseSchema },
})
export type AwsCloudformationValidateTemplateRequest = ContractBodyInput<
typeof awsCloudformationValidateTemplateContract
>
export type AwsCloudformationValidateTemplateBody = ContractBody<
typeof awsCloudformationValidateTemplateContract
>
export type AwsCloudformationValidateTemplateResponse = ContractJsonResponse<
typeof awsCloudformationValidateTemplateContract
>
@@ -0,0 +1,73 @@
import { z } from 'zod'
import type {
ContractBody,
ContractBodyInput,
ContractJsonResponse,
} from '@/lib/api/contracts/types'
import { defineRouteContract } from '@/lib/api/contracts/types'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const DescribeAlarmHistorySchema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
alarmName: z.string().optional(),
historyItemType: z.preprocess(
(v) => (v === '' ? undefined : v),
z
.enum([
'ConfigurationUpdate',
'StateUpdate',
'Action',
'AlarmContributorStateUpdate',
'AlarmContributorAction',
])
.optional()
),
startDate: z.coerce.number().int().optional(),
endDate: z.coerce.number().int().optional(),
scanBy: z.preprocess(
(v) => (v === '' ? undefined : v),
z.enum(['TimestampDescending', 'TimestampAscending']).optional()
),
limit: z.preprocess(
(v) => (v === '' || v === undefined || v === null ? undefined : v),
z.coerce.number().int().positive().optional()
),
})
const DescribeAlarmHistoryResponseSchema = z.object({
success: z.literal(true),
output: z.object({
alarmHistoryItems: z.array(
z.object({
alarmName: z.string().optional(),
alarmType: z.string().optional(),
timestamp: z.number().optional(),
historyItemType: z.string().optional(),
historySummary: z.string().optional(),
})
),
}),
})
export const awsCloudwatchDescribeAlarmHistoryContract = defineRouteContract({
method: 'POST',
path: '/api/tools/cloudwatch/describe-alarm-history',
body: DescribeAlarmHistorySchema,
response: { mode: 'json', schema: DescribeAlarmHistoryResponseSchema },
})
export type AwsCloudwatchDescribeAlarmHistoryRequest = ContractBodyInput<
typeof awsCloudwatchDescribeAlarmHistoryContract
>
export type AwsCloudwatchDescribeAlarmHistoryBody = ContractBody<
typeof awsCloudwatchDescribeAlarmHistoryContract
>
export type AwsCloudwatchDescribeAlarmHistoryResponse = ContractJsonResponse<
typeof awsCloudwatchDescribeAlarmHistoryContract
>
@@ -0,0 +1,73 @@
import { z } from 'zod'
import type {
ContractBody,
ContractBodyInput,
ContractJsonResponse,
} from '@/lib/api/contracts/types'
import { defineRouteContract } from '@/lib/api/contracts/types'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const DescribeAlarmsSchema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
alarmNamePrefix: z.string().optional(),
stateValue: z.preprocess(
(v) => (v === '' ? undefined : v),
z.enum(['OK', 'ALARM', 'INSUFFICIENT_DATA']).optional()
),
alarmType: z.preprocess(
(v) => (v === '' ? undefined : v),
z.enum(['MetricAlarm', 'CompositeAlarm']).optional()
),
limit: z.preprocess(
(v) => (v === '' || v === undefined || v === null ? undefined : v),
z.coerce
.number()
.int()
.positive()
.max(100, 'limit must be at most 100 (CloudWatch DescribeAlarms limit)')
.optional()
),
})
const DescribeAlarmsResponseSchema = z.object({
success: z.literal(true),
output: z.object({
alarms: z.array(
z.object({
alarmName: z.string(),
alarmArn: z.string(),
stateValue: z.string(),
stateReason: z.string(),
metricName: z.string().optional(),
namespace: z.string().optional(),
comparisonOperator: z.string().optional(),
threshold: z.number().optional(),
evaluationPeriods: z.number().optional(),
stateUpdatedTimestamp: z.number().optional(),
})
),
}),
})
export const awsCloudwatchDescribeAlarmsContract = defineRouteContract({
method: 'POST',
path: '/api/tools/cloudwatch/describe-alarms',
body: DescribeAlarmsSchema,
response: { mode: 'json', schema: DescribeAlarmsResponseSchema },
})
export type AwsCloudwatchDescribeAlarmsRequest = ContractBodyInput<
typeof awsCloudwatchDescribeAlarmsContract
>
export type AwsCloudwatchDescribeAlarmsBody = ContractBody<
typeof awsCloudwatchDescribeAlarmsContract
>
export type AwsCloudwatchDescribeAlarmsResponse = ContractJsonResponse<
typeof awsCloudwatchDescribeAlarmsContract
>
@@ -0,0 +1,59 @@
import { z } from 'zod'
import type {
ContractBody,
ContractBodyInput,
ContractJsonResponse,
} from '@/lib/api/contracts/types'
import { defineRouteContract } from '@/lib/api/contracts/types'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const FilterLogEventsSchema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
logGroupName: z.string().min(1, 'Log group name is required'),
filterPattern: z.string().max(1024).optional(),
logStreamNamePrefix: z.string().optional(),
startTime: z.coerce.number().int().optional(),
endTime: z.coerce.number().int().optional(),
startFromHead: z.boolean().optional(),
limit: z.preprocess(
(v) => (v === '' || v === undefined || v === null ? undefined : v),
z.coerce.number().int().positive().optional()
),
})
const FilterLogEventsResponseSchema = z.object({
success: z.literal(true),
output: z.object({
events: z.array(
z.object({
logStreamName: z.string().optional(),
timestamp: z.number().optional(),
message: z.string().optional(),
ingestionTime: z.number().optional(),
})
),
}),
})
export const awsCloudwatchFilterLogEventsContract = defineRouteContract({
method: 'POST',
path: '/api/tools/cloudwatch/filter-log-events',
body: FilterLogEventsSchema,
response: { mode: 'json', schema: FilterLogEventsResponseSchema },
})
export type AwsCloudwatchFilterLogEventsRequest = ContractBodyInput<
typeof awsCloudwatchFilterLogEventsContract
>
export type AwsCloudwatchFilterLogEventsBody = ContractBody<
typeof awsCloudwatchFilterLogEventsContract
>
export type AwsCloudwatchFilterLogEventsResponse = ContractJsonResponse<
typeof awsCloudwatchFilterLogEventsContract
>
@@ -0,0 +1,59 @@
import { z } from 'zod'
import type {
ContractBody,
ContractBodyInput,
ContractJsonResponse,
} from '@/lib/api/contracts/types'
import { defineRouteContract } from '@/lib/api/contracts/types'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const GetLogEventsSchema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
logGroupName: z.string().min(1, 'Log group name is required'),
logStreamName: z.string().min(1, 'Log stream name is required'),
startTime: z.coerce.number().int().optional(),
endTime: z.coerce.number().int().optional(),
limit: z.preprocess(
(v) => (v === '' || v === undefined || v === null ? undefined : v),
z.coerce
.number()
.int()
.positive()
.max(10000, 'limit must be at most 10000 (CloudWatch Logs GetLogEvents limit)')
.optional()
),
})
const GetLogEventsResponseSchema = z.object({
success: z.literal(true),
output: z.object({
events: z.array(
z.object({
timestamp: z.number().optional(),
message: z.string().optional(),
ingestionTime: z.number().optional(),
})
),
}),
})
export const awsCloudwatchGetLogEventsContract = defineRouteContract({
method: 'POST',
path: '/api/tools/cloudwatch/get-log-events',
body: GetLogEventsSchema,
response: { mode: 'json', schema: GetLogEventsResponseSchema },
})
export type AwsCloudwatchGetLogEventsRequest = ContractBodyInput<
typeof awsCloudwatchGetLogEventsContract
>
export type AwsCloudwatchGetLogEventsBody = ContractBody<typeof awsCloudwatchGetLogEventsContract>
export type AwsCloudwatchGetLogEventsResponse = ContractJsonResponse<
typeof awsCloudwatchGetLogEventsContract
>
@@ -0,0 +1,63 @@
import { z } from 'zod'
import type {
ContractBody,
ContractBodyInput,
ContractJsonResponse,
} from '@/lib/api/contracts/types'
import { defineRouteContract } from '@/lib/api/contracts/types'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const GetMetricStatisticsSchema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
namespace: z.string().min(1, 'Namespace is required'),
metricName: z.string().min(1, 'Metric name is required'),
startTime: z.coerce.number().int(),
endTime: z.coerce.number().int(),
period: z.coerce.number().int().min(1),
statistics: z
.array(z.enum(['Average', 'Sum', 'Minimum', 'Maximum', 'SampleCount']))
.min(1, 'At least one statistic is required')
.max(5, 'At most 5 statistics are allowed per GetMetricStatistics call'),
dimensions: z.string().optional(),
})
const GetMetricStatisticsResponseSchema = z.object({
success: z.literal(true),
output: z.object({
label: z.string(),
datapoints: z.array(
z.object({
timestamp: z.number(),
average: z.number().optional(),
sum: z.number().optional(),
minimum: z.number().optional(),
maximum: z.number().optional(),
sampleCount: z.number().optional(),
unit: z.string().optional(),
})
),
}),
})
export const awsCloudwatchGetMetricStatisticsContract = defineRouteContract({
method: 'POST',
path: '/api/tools/cloudwatch/get-metric-statistics',
body: GetMetricStatisticsSchema,
response: { mode: 'json', schema: GetMetricStatisticsResponseSchema },
})
export type AwsCloudwatchGetMetricStatisticsRequest = ContractBodyInput<
typeof awsCloudwatchGetMetricStatisticsContract
>
export type AwsCloudwatchGetMetricStatisticsBody = ContractBody<
typeof awsCloudwatchGetMetricStatisticsContract
>
export type AwsCloudwatchGetMetricStatisticsResponse = ContractJsonResponse<
typeof awsCloudwatchGetMetricStatisticsContract
>
@@ -0,0 +1,58 @@
import { z } from 'zod'
import type {
ContractBody,
ContractBodyInput,
ContractJsonResponse,
} from '@/lib/api/contracts/types'
import { defineRouteContract } from '@/lib/api/contracts/types'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const ListMetricsSchema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
namespace: z.string().optional(),
metricName: z.string().optional(),
recentlyActive: z.boolean().optional(),
limit: z.preprocess(
(v) => (v === '' || v === undefined || v === null ? undefined : v),
z.coerce.number().int().positive().optional()
),
})
const ListMetricsResponseSchema = z.object({
success: z.literal(true),
output: z.object({
metrics: z.array(
z.object({
namespace: z.string(),
metricName: z.string(),
dimensions: z.array(
z.object({
name: z.string(),
value: z.string(),
})
),
})
),
}),
})
export const awsCloudwatchListMetricsContract = defineRouteContract({
method: 'POST',
path: '/api/tools/cloudwatch/list-metrics',
body: ListMetricsSchema,
response: { mode: 'json', schema: ListMetricsResponseSchema },
})
export type AwsCloudwatchListMetricsRequest = ContractBodyInput<
typeof awsCloudwatchListMetricsContract
>
export type AwsCloudwatchListMetricsBody = ContractBody<typeof awsCloudwatchListMetricsContract>
export type AwsCloudwatchListMetricsResponse = ContractJsonResponse<
typeof awsCloudwatchListMetricsContract
>
@@ -0,0 +1,75 @@
import { z } from 'zod'
import type {
ContractBody,
ContractBodyInput,
ContractJsonResponse,
} from '@/lib/api/contracts/types'
import { defineRouteContract } from '@/lib/api/contracts/types'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const MAX_MUTE_MINUTES = 15 * 24 * 60
const MuteAlarmSchema = z
.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
muteRuleName: z
.string()
.min(1, 'muteRuleName cannot be empty')
.max(255, 'muteRuleName must be at most 255 characters'),
alarmNames: z
.array(z.string().min(1, 'Alarm name cannot be empty').max(255))
.min(1, 'At least one alarm name is required')
.max(100, 'At most 100 alarm names are allowed per mute rule'),
durationValue: z
.number()
.int('durationValue must be an integer')
.min(1, 'durationValue must be at least 1'),
durationUnit: z.enum(['minutes', 'hours', 'days']),
description: z.string().max(1024).optional(),
startDate: z
.number()
.int('startDate must be an integer')
.min(0, 'startDate must be a non-negative Unix epoch in seconds')
.optional(),
})
.superRefine((data, ctx) => {
const minutesPerUnit = { minutes: 1, hours: 60, days: 1440 } as const
const totalMinutes = data.durationValue * minutesPerUnit[data.durationUnit]
if (totalMinutes > MAX_MUTE_MINUTES) {
ctx.addIssue({
code: 'custom',
message: 'duration must be at most 15 days (CloudWatch mute rule limit)',
path: ['durationValue'],
})
}
})
const MuteAlarmResponseSchema = z.object({
success: z.literal(true),
output: z.object({
success: z.literal(true),
muteRuleName: z.string(),
alarmNames: z.array(z.string()),
expression: z.string(),
duration: z.string(),
}),
})
export const awsCloudwatchMuteAlarmContract = defineRouteContract({
method: 'POST',
path: '/api/tools/cloudwatch/mute-alarm',
body: MuteAlarmSchema,
response: { mode: 'json', schema: MuteAlarmResponseSchema },
})
export type AwsCloudwatchMuteAlarmRequest = ContractBodyInput<typeof awsCloudwatchMuteAlarmContract>
export type AwsCloudwatchMuteAlarmBody = ContractBody<typeof awsCloudwatchMuteAlarmContract>
export type AwsCloudwatchMuteAlarmResponse = ContractJsonResponse<
typeof awsCloudwatchMuteAlarmContract
>
@@ -0,0 +1,60 @@
import { z } from 'zod'
import type {
ContractBody,
ContractBodyInput,
ContractJsonResponse,
} from '@/lib/api/contracts/types'
import { defineRouteContract } from '@/lib/api/contracts/types'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
/** Only these values are accepted by CloudWatch Logs PutRetentionPolicy. */
const VALID_RETENTION_DAYS = [
1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1096, 1827, 2192, 2557, 2922, 3288,
3653,
] as const
const PutLogGroupRetentionSchema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
logGroupName: z.string().min(1, 'Log group name is required'),
retentionInDays: z.preprocess(
(v) => (v === '' || v === undefined || v === null ? undefined : v),
z.coerce
.number()
.refine((v) => (VALID_RETENTION_DAYS as readonly number[]).includes(v), {
message: `retentionInDays must be one of ${VALID_RETENTION_DAYS.join(', ')}`,
})
.optional()
),
})
const PutLogGroupRetentionResponseSchema = z.object({
success: z.literal(true),
output: z.object({
success: z.literal(true),
logGroupName: z.string(),
retentionInDays: z.number().nullable(),
}),
})
export const awsCloudwatchPutLogGroupRetentionContract = defineRouteContract({
method: 'POST',
path: '/api/tools/cloudwatch/put-log-group-retention',
body: PutLogGroupRetentionSchema,
response: { mode: 'json', schema: PutLogGroupRetentionResponseSchema },
})
export type AwsCloudwatchPutLogGroupRetentionRequest = ContractBodyInput<
typeof awsCloudwatchPutLogGroupRetentionContract
>
export type AwsCloudwatchPutLogGroupRetentionBody = ContractBody<
typeof awsCloudwatchPutLogGroupRetentionContract
>
export type AwsCloudwatchPutLogGroupRetentionResponse = ContractJsonResponse<
typeof awsCloudwatchPutLogGroupRetentionContract
>
@@ -0,0 +1,97 @@
import { isRecordLike } from '@sim/utils/object'
import { z } from 'zod'
import type {
ContractBody,
ContractBodyInput,
ContractJsonResponse,
} from '@/lib/api/contracts/types'
import { defineRouteContract } from '@/lib/api/contracts/types'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const VALID_UNITS = [
'Seconds',
'Microseconds',
'Milliseconds',
'Bytes',
'Kilobytes',
'Megabytes',
'Gigabytes',
'Terabytes',
'Bits',
'Kilobits',
'Megabits',
'Gigabits',
'Terabits',
'Percent',
'Count',
'Bytes/Second',
'Kilobytes/Second',
'Megabytes/Second',
'Gigabytes/Second',
'Terabytes/Second',
'Bits/Second',
'Kilobits/Second',
'Megabits/Second',
'Gigabits/Second',
'Terabits/Second',
'Count/Second',
'None',
] as const
const PutMetricDataSchema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
namespace: z.string().min(1, 'Namespace is required'),
metricName: z.string().min(1, 'Metric name is required'),
value: z.coerce.number().refine((v) => Number.isFinite(v), {
message: 'Metric value must be a finite number',
}),
unit: z.enum(VALID_UNITS).optional(),
dimensions: z
.string()
.optional()
.refine(
(val) => {
if (!val) return true
try {
const parsed = JSON.parse(val)
return isRecordLike(parsed)
} catch {
return false
}
},
{ message: 'dimensions must be a valid JSON object string' }
),
})
const PutMetricDataResponseSchema = z.object({
success: z.literal(true),
output: z.object({
success: z.literal(true),
namespace: z.string(),
metricName: z.string(),
value: z.number(),
unit: z.string(),
timestamp: z.string(),
}),
})
export const awsCloudwatchPutMetricDataContract = defineRouteContract({
method: 'POST',
path: '/api/tools/cloudwatch/put-metric-data',
body: PutMetricDataSchema,
response: { mode: 'json', schema: PutMetricDataResponseSchema },
})
export type AwsCloudwatchPutMetricDataRequest = ContractBodyInput<
typeof awsCloudwatchPutMetricDataContract
>
export type AwsCloudwatchPutMetricDataBody = ContractBody<typeof awsCloudwatchPutMetricDataContract>
export type AwsCloudwatchPutMetricDataResponse = ContractJsonResponse<
typeof awsCloudwatchPutMetricDataContract
>
@@ -0,0 +1,52 @@
import { z } from 'zod'
import type {
ContractBody,
ContractBodyInput,
ContractJsonResponse,
} from '@/lib/api/contracts/types'
import { defineRouteContract } from '@/lib/api/contracts/types'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const QueryLogsSchema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
logGroupNames: z.array(z.string().min(1)).min(1, 'At least one log group name is required'),
queryString: z.string().min(1, 'Query string is required'),
startTime: z.coerce.number().int(),
endTime: z.coerce.number().int(),
limit: z.preprocess(
(v) => (v === '' || v === undefined || v === null ? undefined : v),
z.coerce.number().int().positive().optional()
),
})
const QueryLogsResponseSchema = z.object({
success: z.literal(true),
output: z.object({
results: z.array(z.record(z.string(), z.string())),
statistics: z.object({
bytesScanned: z.number(),
recordsMatched: z.number(),
recordsScanned: z.number(),
}),
status: z.string(),
}),
})
export const awsCloudwatchQueryLogsContract = defineRouteContract({
method: 'POST',
path: '/api/tools/cloudwatch/query-logs',
body: QueryLogsSchema,
response: { mode: 'json', schema: QueryLogsResponseSchema },
})
export type AwsCloudwatchQueryLogsRequest = ContractBodyInput<typeof awsCloudwatchQueryLogsContract>
export type AwsCloudwatchQueryLogsBody = ContractBody<typeof awsCloudwatchQueryLogsContract>
export type AwsCloudwatchQueryLogsResponse = ContractJsonResponse<
typeof awsCloudwatchQueryLogsContract
>
@@ -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'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const UnmuteAlarmSchema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
muteRuleName: z
.string()
.min(1, 'muteRuleName cannot be empty')
.max(255, 'muteRuleName must be at most 255 characters'),
})
const UnmuteAlarmResponseSchema = z.object({
success: z.literal(true),
output: z.object({
success: z.literal(true),
muteRuleName: z.string(),
}),
})
export const awsCloudwatchUnmuteAlarmContract = defineRouteContract({
method: 'POST',
path: '/api/tools/cloudwatch/unmute-alarm',
body: UnmuteAlarmSchema,
response: { mode: 'json', schema: UnmuteAlarmResponseSchema },
})
export type AwsCloudwatchUnmuteAlarmRequest = ContractBodyInput<
typeof awsCloudwatchUnmuteAlarmContract
>
export type AwsCloudwatchUnmuteAlarmBody = ContractBody<typeof awsCloudwatchUnmuteAlarmContract>
export type AwsCloudwatchUnmuteAlarmResponse = ContractJsonResponse<
typeof awsCloudwatchUnmuteAlarmContract
>
@@ -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'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const DisableStageTransitionSchema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
pipelineName: z
.string()
.min(1, 'Pipeline name is required')
.max(100, 'Pipeline name must be at most 100 characters'),
stageName: z
.string()
.min(1, 'Stage name is required')
.max(100, 'Stage name must be at most 100 characters'),
transitionType: z.enum(['Inbound', 'Outbound']),
reason: z.string().min(1, 'Reason is required').max(300, 'Reason must be at most 300 characters'),
})
const DisableStageTransitionResponseSchema = z.object({
success: z.literal(true),
output: z.object({
pipelineName: z.string(),
stageName: z.string(),
transitionType: z.enum(['Inbound', 'Outbound']),
}),
})
export const awsCodepipelineDisableStageTransitionContract = defineRouteContract({
method: 'POST',
path: '/api/tools/codepipeline/disable-stage-transition',
body: DisableStageTransitionSchema,
response: { mode: 'json', schema: DisableStageTransitionResponseSchema },
})
export type AwsCodepipelineDisableStageTransitionRequest = ContractBodyInput<
typeof awsCodepipelineDisableStageTransitionContract
>
export type AwsCodepipelineDisableStageTransitionBody = ContractBody<
typeof awsCodepipelineDisableStageTransitionContract
>
export type AwsCodepipelineDisableStageTransitionResponse = ContractJsonResponse<
typeof awsCodepipelineDisableStageTransitionContract
>
@@ -0,0 +1,53 @@
import { z } from 'zod'
import type {
ContractBody,
ContractBodyInput,
ContractJsonResponse,
} from '@/lib/api/contracts/types'
import { defineRouteContract } from '@/lib/api/contracts/types'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const EnableStageTransitionSchema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
pipelineName: z
.string()
.min(1, 'Pipeline name is required')
.max(100, 'Pipeline name must be at most 100 characters'),
stageName: z
.string()
.min(1, 'Stage name is required')
.max(100, 'Stage name must be at most 100 characters'),
transitionType: z.enum(['Inbound', 'Outbound']),
})
const EnableStageTransitionResponseSchema = z.object({
success: z.literal(true),
output: z.object({
pipelineName: z.string(),
stageName: z.string(),
transitionType: z.enum(['Inbound', 'Outbound']),
}),
})
export const awsCodepipelineEnableStageTransitionContract = defineRouteContract({
method: 'POST',
path: '/api/tools/codepipeline/enable-stage-transition',
body: EnableStageTransitionSchema,
response: { mode: 'json', schema: EnableStageTransitionResponseSchema },
})
export type AwsCodepipelineEnableStageTransitionRequest = ContractBodyInput<
typeof awsCodepipelineEnableStageTransitionContract
>
export type AwsCodepipelineEnableStageTransitionBody = ContractBody<
typeof awsCodepipelineEnableStageTransitionContract
>
export type AwsCodepipelineEnableStageTransitionResponse = ContractJsonResponse<
typeof awsCodepipelineEnableStageTransitionContract
>
@@ -0,0 +1,70 @@
import { z } from 'zod'
import type {
ContractBody,
ContractBodyInput,
ContractJsonResponse,
} from '@/lib/api/contracts/types'
import { defineRouteContract } from '@/lib/api/contracts/types'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const GetPipelineExecutionSchema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
pipelineName: z
.string()
.min(1, 'Pipeline name is required')
.max(100, 'Pipeline name must be at most 100 characters'),
pipelineExecutionId: z.string().min(1, 'Pipeline execution ID is required'),
})
const GetPipelineExecutionResponseSchema = z.object({
success: z.literal(true),
output: z.object({
pipelineExecutionId: z.string(),
pipelineName: z.string(),
pipelineVersion: z.number().optional(),
status: z.string(),
statusSummary: z.string().optional(),
executionMode: z.string().optional(),
executionType: z.string().optional(),
triggerType: z.string().optional(),
triggerDetail: z.string().optional(),
artifactRevisions: z.array(
z.object({
name: z.string(),
revisionId: z.string().optional(),
revisionSummary: z.string().optional(),
revisionUrl: z.string().optional(),
created: z.number().optional(),
})
),
variables: z.array(
z.object({
name: z.string(),
resolvedValue: z.string(),
})
),
}),
})
export const awsCodepipelineGetPipelineExecutionContract = defineRouteContract({
method: 'POST',
path: '/api/tools/codepipeline/get-pipeline-execution',
body: GetPipelineExecutionSchema,
response: { mode: 'json', schema: GetPipelineExecutionResponseSchema },
})
export type AwsCodepipelineGetPipelineExecutionRequest = ContractBodyInput<
typeof awsCodepipelineGetPipelineExecutionContract
>
export type AwsCodepipelineGetPipelineExecutionBody = ContractBody<
typeof awsCodepipelineGetPipelineExecutionContract
>
export type AwsCodepipelineGetPipelineExecutionResponse = ContractJsonResponse<
typeof awsCodepipelineGetPipelineExecutionContract
>
@@ -0,0 +1,73 @@
import { z } from 'zod'
import type {
ContractBody,
ContractBodyInput,
ContractJsonResponse,
} from '@/lib/api/contracts/types'
import { defineRouteContract } from '@/lib/api/contracts/types'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const GetPipelineStateSchema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
pipelineName: z
.string()
.min(1, 'Pipeline name is required')
.max(100, 'Pipeline name must be at most 100 characters'),
})
const ActionStateSchema = z.object({
actionName: z.string(),
status: z.string().optional(),
summary: z.string().optional(),
lastStatusChange: z.number().optional(),
externalExecutionId: z.string().optional(),
externalExecutionUrl: z.string().optional(),
errorCode: z.string().optional(),
errorMessage: z.string().optional(),
percentComplete: z.number().optional(),
token: z.string().optional(),
revisionId: z.string().optional(),
entityUrl: z.string().optional(),
})
const StageStateSchema = z.object({
stageName: z.string(),
status: z.string().optional(),
pipelineExecutionId: z.string().optional(),
inboundTransitionEnabled: z.boolean().optional(),
actionStates: z.array(ActionStateSchema),
})
const GetPipelineStateResponseSchema = z.object({
success: z.literal(true),
output: z.object({
pipelineName: z.string(),
pipelineVersion: z.number().optional(),
created: z.number().optional(),
updated: z.number().optional(),
stageStates: z.array(StageStateSchema),
}),
})
export const awsCodepipelineGetPipelineStateContract = defineRouteContract({
method: 'POST',
path: '/api/tools/codepipeline/get-pipeline-state',
body: GetPipelineStateSchema,
response: { mode: 'json', schema: GetPipelineStateResponseSchema },
})
export type AwsCodepipelineGetPipelineStateRequest = ContractBodyInput<
typeof awsCodepipelineGetPipelineStateContract
>
export type AwsCodepipelineGetPipelineStateBody = ContractBody<
typeof awsCodepipelineGetPipelineStateContract
>
export type AwsCodepipelineGetPipelineStateResponse = ContractJsonResponse<
typeof awsCodepipelineGetPipelineStateContract
>
@@ -0,0 +1,82 @@
import { z } from 'zod'
import type {
ContractBody,
ContractBodyInput,
ContractJsonResponse,
} from '@/lib/api/contracts/types'
import { defineRouteContract } from '@/lib/api/contracts/types'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const GetPipelineSchema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
pipelineName: z
.string()
.min(1, 'Pipeline name is required')
.max(100, 'Pipeline name must be at most 100 characters'),
version: z.preprocess(
(v) => (v === '' || v === undefined || v === null ? undefined : v),
z.coerce.number().int().min(1).optional()
),
})
const ActionDeclarationSchema = z.object({
name: z.string(),
category: z.string(),
owner: z.string(),
provider: z.string(),
version: z.string(),
runOrder: z.number().optional(),
configuration: z.record(z.string(), z.string()),
inputArtifacts: z.array(z.string()),
outputArtifacts: z.array(z.string()),
})
const StageDeclarationSchema = z.object({
stageName: z.string(),
actions: z.array(ActionDeclarationSchema),
})
const GetPipelineResponseSchema = z.object({
success: z.literal(true),
output: z.object({
pipelineName: z.string(),
pipelineArn: z.string().optional(),
roleArn: z.string(),
version: z.number().optional(),
pipelineType: z.string().optional(),
executionMode: z.string().optional(),
artifactStoreType: z.string().optional(),
artifactStoreLocation: z.string().optional(),
stages: z.array(StageDeclarationSchema),
variables: z.array(
z.object({
name: z.string(),
defaultValue: z.string().optional(),
description: z.string().optional(),
})
),
created: z.number().optional(),
updated: z.number().optional(),
}),
})
export const awsCodepipelineGetPipelineContract = defineRouteContract({
method: 'POST',
path: '/api/tools/codepipeline/get-pipeline',
body: GetPipelineSchema,
response: { mode: 'json', schema: GetPipelineResponseSchema },
})
export type AwsCodepipelineGetPipelineRequest = ContractBodyInput<
typeof awsCodepipelineGetPipelineContract
>
export type AwsCodepipelineGetPipelineBody = ContractBody<typeof awsCodepipelineGetPipelineContract>
export type AwsCodepipelineGetPipelineResponse = ContractJsonResponse<
typeof awsCodepipelineGetPipelineContract
>
@@ -0,0 +1,70 @@
import { z } from 'zod'
import type {
ContractBody,
ContractBodyInput,
ContractJsonResponse,
} from '@/lib/api/contracts/types'
import { defineRouteContract } from '@/lib/api/contracts/types'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const ListActionExecutionsSchema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
pipelineName: z
.string()
.min(1, 'Pipeline name is required')
.max(100, 'Pipeline name must be at most 100 characters'),
pipelineExecutionId: z.string().min(1).optional(),
maxResults: z.preprocess(
(v) => (v === '' || v === undefined || v === null ? undefined : v),
z.coerce.number().int().min(1).max(100).optional()
),
nextToken: z.string().min(1).max(2048).optional(),
})
const ActionExecutionDetailSchema = z.object({
pipelineExecutionId: z.string().optional(),
actionExecutionId: z.string().optional(),
pipelineVersion: z.number().optional(),
stageName: z.string().optional(),
actionName: z.string().optional(),
startTime: z.number().optional(),
lastUpdateTime: z.number().optional(),
updatedBy: z.string().optional(),
status: z.string().optional(),
externalExecutionId: z.string().optional(),
externalExecutionSummary: z.string().optional(),
externalExecutionUrl: z.string().optional(),
errorCode: z.string().optional(),
errorMessage: z.string().optional(),
})
const ListActionExecutionsResponseSchema = z.object({
success: z.literal(true),
output: z.object({
actionExecutionDetails: z.array(ActionExecutionDetailSchema),
nextToken: z.string().optional(),
}),
})
export const awsCodepipelineListActionExecutionsContract = defineRouteContract({
method: 'POST',
path: '/api/tools/codepipeline/list-action-executions',
body: ListActionExecutionsSchema,
response: { mode: 'json', schema: ListActionExecutionsResponseSchema },
})
export type AwsCodepipelineListActionExecutionsRequest = ContractBodyInput<
typeof awsCodepipelineListActionExecutionsContract
>
export type AwsCodepipelineListActionExecutionsBody = ContractBody<
typeof awsCodepipelineListActionExecutionsContract
>
export type AwsCodepipelineListActionExecutionsResponse = ContractJsonResponse<
typeof awsCodepipelineListActionExecutionsContract
>
@@ -0,0 +1,75 @@
import { z } from 'zod'
import type {
ContractBody,
ContractBodyInput,
ContractJsonResponse,
} from '@/lib/api/contracts/types'
import { defineRouteContract } from '@/lib/api/contracts/types'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const ListPipelineExecutionsSchema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
pipelineName: z
.string()
.min(1, 'Pipeline name is required')
.max(100, 'Pipeline name must be at most 100 characters'),
maxResults: z.preprocess(
(v) => (v === '' || v === undefined || v === null ? undefined : v),
z.coerce.number().int().min(1).max(100).optional()
),
nextToken: z.string().min(1).max(2048).optional(),
succeededInStage: z.string().min(1).max(100).optional(),
})
const PipelineExecutionSummarySchema = z.object({
pipelineExecutionId: z.string(),
status: z.string(),
statusSummary: z.string().optional(),
startTime: z.number().optional(),
lastUpdateTime: z.number().optional(),
executionMode: z.string().optional(),
executionType: z.string().optional(),
stopTriggerReason: z.string().optional(),
triggerType: z.string().optional(),
triggerDetail: z.string().optional(),
rollbackTargetPipelineExecutionId: z.string().optional(),
sourceRevisions: z.array(
z.object({
actionName: z.string(),
revisionId: z.string().optional(),
revisionSummary: z.string().optional(),
revisionUrl: z.string().optional(),
})
),
})
const ListPipelineExecutionsResponseSchema = z.object({
success: z.literal(true),
output: z.object({
executions: z.array(PipelineExecutionSummarySchema),
nextToken: z.string().optional(),
}),
})
export const awsCodepipelineListPipelineExecutionsContract = defineRouteContract({
method: 'POST',
path: '/api/tools/codepipeline/list-pipeline-executions',
body: ListPipelineExecutionsSchema,
response: { mode: 'json', schema: ListPipelineExecutionsResponseSchema },
})
export type AwsCodepipelineListPipelineExecutionsRequest = ContractBodyInput<
typeof awsCodepipelineListPipelineExecutionsContract
>
export type AwsCodepipelineListPipelineExecutionsBody = ContractBody<
typeof awsCodepipelineListPipelineExecutionsContract
>
export type AwsCodepipelineListPipelineExecutionsResponse = ContractJsonResponse<
typeof awsCodepipelineListPipelineExecutionsContract
>
@@ -0,0 +1,57 @@
import { z } from 'zod'
import type {
ContractBody,
ContractBodyInput,
ContractJsonResponse,
} from '@/lib/api/contracts/types'
import { defineRouteContract } from '@/lib/api/contracts/types'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const ListPipelinesSchema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
maxResults: z.preprocess(
(v) => (v === '' || v === undefined || v === null ? undefined : v),
z.coerce.number().int().min(1).max(1000).optional()
),
nextToken: z.string().min(1).max(2048).optional(),
})
const ListPipelinesResponseSchema = z.object({
success: z.literal(true),
output: z.object({
pipelines: z.array(
z.object({
name: z.string(),
version: z.number().optional(),
pipelineType: z.string().optional(),
executionMode: z.string().optional(),
created: z.number().optional(),
updated: z.number().optional(),
})
),
nextToken: z.string().optional(),
}),
})
export const awsCodepipelineListPipelinesContract = defineRouteContract({
method: 'POST',
path: '/api/tools/codepipeline/list-pipelines',
body: ListPipelinesSchema,
response: { mode: 'json', schema: ListPipelinesResponseSchema },
})
export type AwsCodepipelineListPipelinesRequest = ContractBodyInput<
typeof awsCodepipelineListPipelinesContract
>
export type AwsCodepipelineListPipelinesBody = ContractBody<
typeof awsCodepipelineListPipelinesContract
>
export type AwsCodepipelineListPipelinesResponse = ContractJsonResponse<
typeof awsCodepipelineListPipelinesContract
>
@@ -0,0 +1,61 @@
import { z } from 'zod'
import type {
ContractBody,
ContractBodyInput,
ContractJsonResponse,
} from '@/lib/api/contracts/types'
import { defineRouteContract } from '@/lib/api/contracts/types'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const PutApprovalResultSchema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
pipelineName: z
.string()
.min(1, 'Pipeline name is required')
.max(100, 'Pipeline name must be at most 100 characters'),
stageName: z
.string()
.min(1, 'Stage name is required')
.max(100, 'Stage name must be at most 100 characters'),
actionName: z
.string()
.min(1, 'Action name is required')
.max(100, 'Action name must be at most 100 characters'),
token: z.string().min(1, 'Approval token is required'),
status: z.enum(['Approved', 'Rejected']),
summary: z
.string()
.min(1, 'Approval summary is required')
.max(512, 'Approval summary must be at most 512 characters'),
})
const PutApprovalResultResponseSchema = z.object({
success: z.literal(true),
output: z.object({
approvedAt: z.number().optional(),
status: z.string(),
}),
})
export const awsCodepipelinePutApprovalResultContract = defineRouteContract({
method: 'POST',
path: '/api/tools/codepipeline/put-approval-result',
body: PutApprovalResultSchema,
response: { mode: 'json', schema: PutApprovalResultResponseSchema },
})
export type AwsCodepipelinePutApprovalResultRequest = ContractBodyInput<
typeof awsCodepipelinePutApprovalResultContract
>
export type AwsCodepipelinePutApprovalResultBody = ContractBody<
typeof awsCodepipelinePutApprovalResultContract
>
export type AwsCodepipelinePutApprovalResultResponse = ContractJsonResponse<
typeof awsCodepipelinePutApprovalResultContract
>
@@ -0,0 +1,52 @@
import { z } from 'zod'
import type {
ContractBody,
ContractBodyInput,
ContractJsonResponse,
} from '@/lib/api/contracts/types'
import { defineRouteContract } from '@/lib/api/contracts/types'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const RetryStageExecutionSchema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
pipelineName: z
.string()
.min(1, 'Pipeline name is required')
.max(100, 'Pipeline name must be at most 100 characters'),
stageName: z
.string()
.min(1, 'Stage name is required')
.max(100, 'Stage name must be at most 100 characters'),
pipelineExecutionId: z.string().min(1, 'Pipeline execution ID is required'),
retryMode: z.enum(['FAILED_ACTIONS', 'ALL_ACTIONS']),
})
const RetryStageExecutionResponseSchema = z.object({
success: z.literal(true),
output: z.object({
pipelineExecutionId: z.string(),
}),
})
export const awsCodepipelineRetryStageExecutionContract = defineRouteContract({
method: 'POST',
path: '/api/tools/codepipeline/retry-stage-execution',
body: RetryStageExecutionSchema,
response: { mode: 'json', schema: RetryStageExecutionResponseSchema },
})
export type AwsCodepipelineRetryStageExecutionRequest = ContractBodyInput<
typeof awsCodepipelineRetryStageExecutionContract
>
export type AwsCodepipelineRetryStageExecutionBody = ContractBody<
typeof awsCodepipelineRetryStageExecutionContract
>
export type AwsCodepipelineRetryStageExecutionResponse = ContractJsonResponse<
typeof awsCodepipelineRetryStageExecutionContract
>
@@ -0,0 +1,62 @@
import { z } from 'zod'
import type {
ContractBody,
ContractBodyInput,
ContractJsonResponse,
} from '@/lib/api/contracts/types'
import { defineRouteContract } from '@/lib/api/contracts/types'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const StartExecutionSchema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
pipelineName: z
.string()
.min(1, 'Pipeline name is required')
.max(100, 'Pipeline name must be at most 100 characters'),
clientRequestToken: z
.string()
.min(1)
.max(128)
.regex(/^[a-zA-Z0-9-]+$/, 'Client request token may only contain letters, digits, and hyphens')
.optional(),
variables: z
.array(
z.object({
name: z.string().min(1, 'Variable name is required'),
value: z.string().min(1, 'Variable value cannot be empty'),
})
)
.min(1)
.max(50)
.optional(),
})
const StartExecutionResponseSchema = z.object({
success: z.literal(true),
output: z.object({
pipelineExecutionId: z.string(),
}),
})
export const awsCodepipelineStartExecutionContract = defineRouteContract({
method: 'POST',
path: '/api/tools/codepipeline/start-execution',
body: StartExecutionSchema,
response: { mode: 'json', schema: StartExecutionResponseSchema },
})
export type AwsCodepipelineStartExecutionRequest = ContractBodyInput<
typeof awsCodepipelineStartExecutionContract
>
export type AwsCodepipelineStartExecutionBody = ContractBody<
typeof awsCodepipelineStartExecutionContract
>
export type AwsCodepipelineStartExecutionResponse = ContractJsonResponse<
typeof awsCodepipelineStartExecutionContract
>
@@ -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'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const StopExecutionSchema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
pipelineName: z
.string()
.min(1, 'Pipeline name is required')
.max(100, 'Pipeline name must be at most 100 characters'),
pipelineExecutionId: z.string().min(1, 'Pipeline execution ID is required'),
abandon: z.boolean().optional(),
reason: z.string().max(200, 'Stop reason must be at most 200 characters').optional(),
})
const StopExecutionResponseSchema = z.object({
success: z.literal(true),
output: z.object({
pipelineExecutionId: z.string(),
}),
})
export const awsCodepipelineStopExecutionContract = defineRouteContract({
method: 'POST',
path: '/api/tools/codepipeline/stop-execution',
body: StopExecutionSchema,
response: { mode: 'json', schema: StopExecutionResponseSchema },
})
export type AwsCodepipelineStopExecutionRequest = ContractBodyInput<
typeof awsCodepipelineStopExecutionContract
>
export type AwsCodepipelineStopExecutionBody = ContractBody<
typeof awsCodepipelineStopExecutionContract
>
export type AwsCodepipelineStopExecutionResponse = ContractJsonResponse<
typeof awsCodepipelineStopExecutionContract
>
@@ -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'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const DeleteSchema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
tableName: z.string().min(1, 'Table name is required'),
key: z.record(z.string(), z.unknown()).refine((val) => Object.keys(val).length > 0, {
message: 'Key is required',
}),
conditionExpression: z.string().optional(),
expressionAttributeNames: z.record(z.string(), z.string()).optional(),
expressionAttributeValues: z.record(z.string(), z.unknown()).optional(),
})
const DeleteResponseSchema = z.object({
message: z.string(),
})
export const awsDynamodbDeleteContract = defineRouteContract({
method: 'POST',
path: '/api/tools/dynamodb/delete',
body: DeleteSchema,
response: { mode: 'json', schema: DeleteResponseSchema },
})
export type AwsDynamodbDeleteRequest = ContractBodyInput<typeof awsDynamodbDeleteContract>
export type AwsDynamodbDeleteBody = ContractBody<typeof awsDynamodbDeleteContract>
export type AwsDynamodbDeleteResponse = ContractJsonResponse<typeof awsDynamodbDeleteContract>
@@ -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'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const GetSchema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
tableName: z.string().min(1, 'Table name is required'),
key: z.record(z.string(), z.unknown()).refine((val) => Object.keys(val).length > 0, {
message: 'Key is required',
}),
consistentRead: z
.union([z.boolean(), z.string()])
.optional()
.transform((val) => {
if (val === true || val === 'true') return true
return undefined
}),
})
const GetResponseSchema = z.object({
message: z.string(),
// untyped-response: DynamoDB Item is an arbitrary user attribute-value record
item: z.record(z.string(), z.unknown()).nullable(),
})
export const awsDynamodbGetContract = defineRouteContract({
method: 'POST',
path: '/api/tools/dynamodb/get',
body: GetSchema,
response: { mode: 'json', schema: GetResponseSchema },
})
export type AwsDynamodbGetRequest = ContractBodyInput<typeof awsDynamodbGetContract>
export type AwsDynamodbGetBody = ContractBody<typeof awsDynamodbGetContract>
export type AwsDynamodbGetResponse = ContractJsonResponse<typeof awsDynamodbGetContract>
@@ -0,0 +1,67 @@
import { z } from 'zod'
import type {
ContractBody,
ContractBodyInput,
ContractJsonResponse,
} from '@/lib/api/contracts/types'
import { defineRouteContract } from '@/lib/api/contracts/types'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const IntrospectSchema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
tableName: z.string().optional(),
})
const KeySchemaEntrySchema = z.object({
attributeName: z.string(),
keyType: z.enum(['HASH', 'RANGE']),
})
const SecondaryIndexSchema = z.object({
indexName: z.string(),
keySchema: z.array(KeySchemaEntrySchema),
projectionType: z.string(),
indexStatus: z.string(),
})
const TableDetailsSchema = z.object({
tableName: z.string(),
tableStatus: z.string(),
keySchema: z.array(KeySchemaEntrySchema),
attributeDefinitions: z.array(
z.object({
attributeName: z.string(),
attributeType: z.enum(['S', 'N', 'B']),
})
),
globalSecondaryIndexes: z.array(SecondaryIndexSchema),
localSecondaryIndexes: z.array(SecondaryIndexSchema),
itemCount: z.number(),
tableSizeBytes: z.number(),
billingMode: z.string(),
})
const IntrospectResponseSchema = z.object({
message: z.string(),
tables: z.array(z.string()),
tableDetails: TableDetailsSchema.optional(),
})
export const awsDynamodbIntrospectContract = defineRouteContract({
method: 'POST',
path: '/api/tools/dynamodb/introspect',
body: IntrospectSchema,
response: { mode: 'json', schema: IntrospectResponseSchema },
})
export type AwsDynamodbIntrospectRequest = ContractBodyInput<typeof awsDynamodbIntrospectContract>
export type AwsDynamodbIntrospectBody = ContractBody<typeof awsDynamodbIntrospectContract>
export type AwsDynamodbIntrospectResponse = ContractJsonResponse<
typeof awsDynamodbIntrospectContract
>
@@ -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'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const PutSchema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
tableName: z.string().min(1, 'Table name is required'),
item: z.record(z.string(), z.unknown()).refine((val) => Object.keys(val).length > 0, {
message: 'Item is required',
}),
conditionExpression: z.string().optional(),
expressionAttributeNames: z.record(z.string(), z.string()).optional(),
expressionAttributeValues: z.record(z.string(), z.unknown()).optional(),
})
const PutResponseSchema = z.object({
message: z.string(),
// untyped-response: DynamoDB Item is an arbitrary user attribute-value record
item: z.record(z.string(), z.unknown()),
})
export const awsDynamodbPutContract = defineRouteContract({
method: 'POST',
path: '/api/tools/dynamodb/put',
body: PutSchema,
response: { mode: 'json', schema: PutResponseSchema },
})
export type AwsDynamodbPutRequest = ContractBodyInput<typeof awsDynamodbPutContract>
export type AwsDynamodbPutBody = ContractBody<typeof awsDynamodbPutContract>
export type AwsDynamodbPutResponse = ContractJsonResponse<typeof awsDynamodbPutContract>
@@ -0,0 +1,47 @@
import { z } from 'zod'
import type {
ContractBody,
ContractBodyInput,
ContractJsonResponse,
} from '@/lib/api/contracts/types'
import { defineRouteContract } from '@/lib/api/contracts/types'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const QuerySchema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
tableName: z.string().min(1, 'Table name is required'),
keyConditionExpression: z.string().min(1, 'Key condition expression is required'),
filterExpression: z.string().optional(),
expressionAttributeNames: z.record(z.string(), z.string()).optional(),
expressionAttributeValues: z.record(z.string(), z.unknown()).optional(),
indexName: z.string().optional(),
limit: z.number().positive().optional(),
exclusiveStartKey: z.record(z.string(), z.unknown()).optional(),
scanIndexForward: z.boolean().optional(),
})
const QueryResponseSchema = z.object({
message: z.string(),
// untyped-response: DynamoDB Items are arbitrary user attribute-value records
items: z.array(z.record(z.string(), z.unknown())),
count: z.number(),
// untyped-response: DynamoDB LastEvaluatedKey mirrors the table's primary key shape
lastEvaluatedKey: z.record(z.string(), z.unknown()).optional(),
})
export const awsDynamodbQueryContract = defineRouteContract({
method: 'POST',
path: '/api/tools/dynamodb/query',
body: QuerySchema,
response: { mode: 'json', schema: QueryResponseSchema },
})
export type AwsDynamodbQueryRequest = ContractBodyInput<typeof awsDynamodbQueryContract>
export type AwsDynamodbQueryBody = ContractBody<typeof awsDynamodbQueryContract>
export type AwsDynamodbQueryResponse = ContractJsonResponse<typeof awsDynamodbQueryContract>
@@ -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'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const ScanSchema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
tableName: z.string().min(1, 'Table name is required'),
filterExpression: z.string().optional(),
projectionExpression: z.string().optional(),
expressionAttributeNames: z.record(z.string(), z.string()).optional(),
expressionAttributeValues: z.record(z.string(), z.unknown()).optional(),
limit: z.number().positive().optional(),
exclusiveStartKey: z.record(z.string(), z.unknown()).optional(),
})
const ScanResponseSchema = z.object({
message: z.string(),
// untyped-response: DynamoDB Items are arbitrary user attribute-value records
items: z.array(z.record(z.string(), z.unknown())),
count: z.number(),
// untyped-response: DynamoDB LastEvaluatedKey mirrors the table's primary key shape
lastEvaluatedKey: z.record(z.string(), z.unknown()).optional(),
})
export const awsDynamodbScanContract = defineRouteContract({
method: 'POST',
path: '/api/tools/dynamodb/scan',
body: ScanSchema,
response: { mode: 'json', schema: ScanResponseSchema },
})
export type AwsDynamodbScanRequest = ContractBodyInput<typeof awsDynamodbScanContract>
export type AwsDynamodbScanBody = ContractBody<typeof awsDynamodbScanContract>
export type AwsDynamodbScanResponse = ContractJsonResponse<typeof awsDynamodbScanContract>
@@ -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'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const UpdateSchema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
tableName: z.string().min(1, 'Table name is required'),
key: z.record(z.string(), z.unknown()).refine((val) => Object.keys(val).length > 0, {
message: 'Key is required',
}),
updateExpression: z.string().min(1, 'Update expression is required'),
expressionAttributeNames: z.record(z.string(), z.string()).optional(),
expressionAttributeValues: z.record(z.string(), z.unknown()).optional(),
conditionExpression: z.string().optional(),
})
const UpdateResponseSchema = z.object({
message: z.string(),
// untyped-response: DynamoDB UpdateItem Attributes is an arbitrary user attribute-value record
item: z.record(z.string(), z.unknown()).nullable(),
})
export const awsDynamodbUpdateContract = defineRouteContract({
method: 'POST',
path: '/api/tools/dynamodb/update',
body: UpdateSchema,
response: { mode: 'json', schema: UpdateResponseSchema },
})
export type AwsDynamodbUpdateRequest = ContractBodyInput<typeof awsDynamodbUpdateContract>
export type AwsDynamodbUpdateBody = ContractBody<typeof awsDynamodbUpdateContract>
export type AwsDynamodbUpdateResponse = ContractJsonResponse<typeof awsDynamodbUpdateContract>
@@ -0,0 +1,31 @@
import { z } from 'zod'
import type {
ContractBody,
ContractBodyInput,
ContractJsonResponse,
} from '@/lib/api/contracts/types'
import { defineRouteContract } from '@/lib/api/contracts/types'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const Schema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
userName: z.string().min(1, 'User name is required'),
groupName: z.string().min(1, 'Group name is required'),
})
export const awsIamAddUserToGroupContract = defineRouteContract({
method: 'POST',
path: '/api/tools/iam/add-user-to-group',
body: Schema,
response: { mode: 'json', schema: z.object({ message: z.string() }) },
})
export type AwsIamAddUserToGroupRequest = ContractBodyInput<typeof awsIamAddUserToGroupContract>
export type AwsIamAddUserToGroupBody = ContractBody<typeof awsIamAddUserToGroupContract>
export type AwsIamAddUserToGroupResponse = ContractJsonResponse<typeof awsIamAddUserToGroupContract>
@@ -0,0 +1,33 @@
import { z } from 'zod'
import type {
ContractBody,
ContractBodyInput,
ContractJsonResponse,
} from '@/lib/api/contracts/types'
import { defineRouteContract } from '@/lib/api/contracts/types'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const Schema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
roleName: z.string().min(1, 'Role name is required'),
policyArn: z.string().min(1, 'Policy ARN is required'),
})
export const awsIamAttachRolePolicyContract = defineRouteContract({
method: 'POST',
path: '/api/tools/iam/attach-role-policy',
body: Schema,
response: { mode: 'json', schema: z.object({ message: z.string() }) },
})
export type AwsIamAttachRolePolicyRequest = ContractBodyInput<typeof awsIamAttachRolePolicyContract>
export type AwsIamAttachRolePolicyBody = ContractBody<typeof awsIamAttachRolePolicyContract>
export type AwsIamAttachRolePolicyResponse = ContractJsonResponse<
typeof awsIamAttachRolePolicyContract
>
@@ -0,0 +1,33 @@
import { z } from 'zod'
import type {
ContractBody,
ContractBodyInput,
ContractJsonResponse,
} from '@/lib/api/contracts/types'
import { defineRouteContract } from '@/lib/api/contracts/types'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const Schema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
userName: z.string().min(1, 'User name is required'),
policyArn: z.string().min(1, 'Policy ARN is required'),
})
export const awsIamAttachUserPolicyContract = defineRouteContract({
method: 'POST',
path: '/api/tools/iam/attach-user-policy',
body: Schema,
response: { mode: 'json', schema: z.object({ message: z.string() }) },
})
export type AwsIamAttachUserPolicyRequest = ContractBodyInput<typeof awsIamAttachUserPolicyContract>
export type AwsIamAttachUserPolicyBody = ContractBody<typeof awsIamAttachUserPolicyContract>
export type AwsIamAttachUserPolicyResponse = ContractJsonResponse<
typeof awsIamAttachUserPolicyContract
>
@@ -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'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const Schema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
userName: z.string().optional().nullable(),
})
const CreateAccessKeyResponseSchema = z.object({
message: z.string(),
accessKeyId: z.string(),
secretAccessKey: z.string(),
userName: z.string(),
status: z.string(),
createDate: z.string().nullable(),
})
export const awsIamCreateAccessKeyContract = defineRouteContract({
method: 'POST',
path: '/api/tools/iam/create-access-key',
body: Schema,
response: { mode: 'json', schema: CreateAccessKeyResponseSchema },
})
export type AwsIamCreateAccessKeyRequest = ContractBodyInput<typeof awsIamCreateAccessKeyContract>
export type AwsIamCreateAccessKeyBody = ContractBody<typeof awsIamCreateAccessKeyContract>
export type AwsIamCreateAccessKeyResponse = ContractJsonResponse<
typeof awsIamCreateAccessKeyContract
>
@@ -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'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const Schema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
roleName: z.string().min(1, 'Role name is required'),
assumeRolePolicyDocument: z.string().min(1, 'Assume role policy document is required'),
description: z.string().optional().nullable(),
path: z.string().optional().nullable(),
maxSessionDuration: z.number().int().min(3600).max(43200).optional().nullable(),
})
const CreateRoleResponseSchema = z.object({
message: z.string(),
roleName: z.string(),
roleId: z.string(),
arn: z.string(),
path: z.string(),
createDate: z.string().nullable(),
})
export const awsIamCreateRoleContract = defineRouteContract({
method: 'POST',
path: '/api/tools/iam/create-role',
body: Schema,
response: { mode: 'json', schema: CreateRoleResponseSchema },
})
export type AwsIamCreateRoleRequest = ContractBodyInput<typeof awsIamCreateRoleContract>
export type AwsIamCreateRoleBody = ContractBody<typeof awsIamCreateRoleContract>
export type AwsIamCreateRoleResponse = ContractJsonResponse<typeof awsIamCreateRoleContract>
@@ -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'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const Schema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
userName: z.string().min(1, 'User name is required'),
path: z.string().optional().nullable(),
})
const CreateUserResponseSchema = z.object({
message: z.string(),
userName: z.string(),
userId: z.string(),
arn: z.string(),
path: z.string(),
createDate: z.string().nullable(),
})
export const awsIamCreateUserContract = defineRouteContract({
method: 'POST',
path: '/api/tools/iam/create-user',
body: Schema,
response: { mode: 'json', schema: CreateUserResponseSchema },
})
export type AwsIamCreateUserRequest = ContractBodyInput<typeof awsIamCreateUserContract>
export type AwsIamCreateUserBody = ContractBody<typeof awsIamCreateUserContract>
export type AwsIamCreateUserResponse = ContractJsonResponse<typeof awsIamCreateUserContract>
@@ -0,0 +1,33 @@
import { z } from 'zod'
import type {
ContractBody,
ContractBodyInput,
ContractJsonResponse,
} from '@/lib/api/contracts/types'
import { defineRouteContract } from '@/lib/api/contracts/types'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const Schema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
accessKeyIdToDelete: z.string().min(1, 'Access key ID to delete is required'),
userName: z.string().optional().nullable(),
})
export const awsIamDeleteAccessKeyContract = defineRouteContract({
method: 'POST',
path: '/api/tools/iam/delete-access-key',
body: Schema,
response: { mode: 'json', schema: z.object({ message: z.string() }) },
})
export type AwsIamDeleteAccessKeyRequest = ContractBodyInput<typeof awsIamDeleteAccessKeyContract>
export type AwsIamDeleteAccessKeyBody = ContractBody<typeof awsIamDeleteAccessKeyContract>
export type AwsIamDeleteAccessKeyResponse = ContractJsonResponse<
typeof awsIamDeleteAccessKeyContract
>
@@ -0,0 +1,30 @@
import { z } from 'zod'
import type {
ContractBody,
ContractBodyInput,
ContractJsonResponse,
} from '@/lib/api/contracts/types'
import { defineRouteContract } from '@/lib/api/contracts/types'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const Schema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
roleName: z.string().min(1, 'Role name is required'),
})
export const awsIamDeleteRoleContract = defineRouteContract({
method: 'POST',
path: '/api/tools/iam/delete-role',
body: Schema,
response: { mode: 'json', schema: z.object({ message: z.string() }) },
})
export type AwsIamDeleteRoleRequest = ContractBodyInput<typeof awsIamDeleteRoleContract>
export type AwsIamDeleteRoleBody = ContractBody<typeof awsIamDeleteRoleContract>
export type AwsIamDeleteRoleResponse = ContractJsonResponse<typeof awsIamDeleteRoleContract>
@@ -0,0 +1,30 @@
import { z } from 'zod'
import type {
ContractBody,
ContractBodyInput,
ContractJsonResponse,
} from '@/lib/api/contracts/types'
import { defineRouteContract } from '@/lib/api/contracts/types'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const Schema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
userName: z.string().min(1, 'User name is required'),
})
export const awsIamDeleteUserContract = defineRouteContract({
method: 'POST',
path: '/api/tools/iam/delete-user',
body: Schema,
response: { mode: 'json', schema: z.object({ message: z.string() }) },
})
export type AwsIamDeleteUserRequest = ContractBodyInput<typeof awsIamDeleteUserContract>
export type AwsIamDeleteUserBody = ContractBody<typeof awsIamDeleteUserContract>
export type AwsIamDeleteUserResponse = ContractJsonResponse<typeof awsIamDeleteUserContract>
@@ -0,0 +1,33 @@
import { z } from 'zod'
import type {
ContractBody,
ContractBodyInput,
ContractJsonResponse,
} from '@/lib/api/contracts/types'
import { defineRouteContract } from '@/lib/api/contracts/types'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const Schema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
roleName: z.string().min(1, 'Role name is required'),
policyArn: z.string().min(1, 'Policy ARN is required'),
})
export const awsIamDetachRolePolicyContract = defineRouteContract({
method: 'POST',
path: '/api/tools/iam/detach-role-policy',
body: Schema,
response: { mode: 'json', schema: z.object({ message: z.string() }) },
})
export type AwsIamDetachRolePolicyRequest = ContractBodyInput<typeof awsIamDetachRolePolicyContract>
export type AwsIamDetachRolePolicyBody = ContractBody<typeof awsIamDetachRolePolicyContract>
export type AwsIamDetachRolePolicyResponse = ContractJsonResponse<
typeof awsIamDetachRolePolicyContract
>
@@ -0,0 +1,33 @@
import { z } from 'zod'
import type {
ContractBody,
ContractBodyInput,
ContractJsonResponse,
} from '@/lib/api/contracts/types'
import { defineRouteContract } from '@/lib/api/contracts/types'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const Schema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
userName: z.string().min(1, 'User name is required'),
policyArn: z.string().min(1, 'Policy ARN is required'),
})
export const awsIamDetachUserPolicyContract = defineRouteContract({
method: 'POST',
path: '/api/tools/iam/detach-user-policy',
body: Schema,
response: { mode: 'json', schema: z.object({ message: z.string() }) },
})
export type AwsIamDetachUserPolicyRequest = ContractBodyInput<typeof awsIamDetachUserPolicyContract>
export type AwsIamDetachUserPolicyBody = ContractBody<typeof awsIamDetachUserPolicyContract>
export type AwsIamDetachUserPolicyResponse = ContractJsonResponse<
typeof awsIamDetachUserPolicyContract
>
@@ -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'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const Schema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
roleName: z.string().min(1, 'Role name is required'),
})
const GetRoleResponseSchema = z.object({
roleName: z.string(),
roleId: z.string(),
arn: z.string(),
path: z.string(),
createDate: z.string().nullable(),
description: z.string().nullable(),
maxSessionDuration: z.number().nullable(),
assumeRolePolicyDocument: z.string().nullable(),
roleLastUsedDate: z.string().nullable(),
roleLastUsedRegion: z.string().nullable(),
})
export const awsIamGetRoleContract = defineRouteContract({
method: 'POST',
path: '/api/tools/iam/get-role',
body: Schema,
response: { mode: 'json', schema: GetRoleResponseSchema },
})
export type AwsIamGetRoleRequest = ContractBodyInput<typeof awsIamGetRoleContract>
export type AwsIamGetRoleBody = ContractBody<typeof awsIamGetRoleContract>
export type AwsIamGetRoleResponse = ContractJsonResponse<typeof awsIamGetRoleContract>
@@ -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'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const Schema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
userName: z.string().min(1).optional().nullable(),
})
const GetUserResponseSchema = z.object({
userName: z.string(),
userId: z.string(),
arn: z.string(),
path: z.string(),
createDate: z.string().nullable(),
passwordLastUsed: z.string().nullable(),
permissionsBoundaryArn: z.string().nullable(),
tags: z.array(
z.object({
key: z.string(),
value: z.string(),
})
),
})
export const awsIamGetUserContract = defineRouteContract({
method: 'POST',
path: '/api/tools/iam/get-user',
body: Schema,
response: { mode: 'json', schema: GetUserResponseSchema },
})
export type AwsIamGetUserRequest = ContractBodyInput<typeof awsIamGetUserContract>
export type AwsIamGetUserBody = ContractBody<typeof awsIamGetUserContract>
export type AwsIamGetUserResponse = ContractJsonResponse<typeof awsIamGetUserContract>
@@ -0,0 +1,51 @@
import { z } from 'zod'
import type {
ContractBody,
ContractBodyInput,
ContractJsonResponse,
} from '@/lib/api/contracts/types'
import { defineRouteContract } from '@/lib/api/contracts/types'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const Schema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
roleName: z.string().min(1, 'Role name is required'),
pathPrefix: z.string().optional().nullable(),
maxItems: z.number().int().min(1).max(1000).optional().nullable(),
marker: z.string().optional().nullable(),
})
const ListAttachedRolePoliciesResponseSchema = z.object({
attachedPolicies: z.array(
z.object({
policyName: z.string(),
policyArn: z.string(),
})
),
isTruncated: z.boolean(),
marker: z.string().nullable(),
count: z.number(),
})
export const awsIamListAttachedRolePoliciesContract = defineRouteContract({
method: 'POST',
path: '/api/tools/iam/list-attached-role-policies',
body: Schema,
response: { mode: 'json', schema: ListAttachedRolePoliciesResponseSchema },
})
export type AwsIamListAttachedRolePoliciesRequest = ContractBodyInput<
typeof awsIamListAttachedRolePoliciesContract
>
export type AwsIamListAttachedRolePoliciesBody = ContractBody<
typeof awsIamListAttachedRolePoliciesContract
>
export type AwsIamListAttachedRolePoliciesResponse = ContractJsonResponse<
typeof awsIamListAttachedRolePoliciesContract
>
@@ -0,0 +1,51 @@
import { z } from 'zod'
import type {
ContractBody,
ContractBodyInput,
ContractJsonResponse,
} from '@/lib/api/contracts/types'
import { defineRouteContract } from '@/lib/api/contracts/types'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const Schema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
userName: z.string().min(1, 'User name is required'),
pathPrefix: z.string().optional().nullable(),
maxItems: z.number().int().min(1).max(1000).optional().nullable(),
marker: z.string().optional().nullable(),
})
const ListAttachedUserPoliciesResponseSchema = z.object({
attachedPolicies: z.array(
z.object({
policyName: z.string(),
policyArn: z.string(),
})
),
isTruncated: z.boolean(),
marker: z.string().nullable(),
count: z.number(),
})
export const awsIamListAttachedUserPoliciesContract = defineRouteContract({
method: 'POST',
path: '/api/tools/iam/list-attached-user-policies',
body: Schema,
response: { mode: 'json', schema: ListAttachedUserPoliciesResponseSchema },
})
export type AwsIamListAttachedUserPoliciesRequest = ContractBodyInput<
typeof awsIamListAttachedUserPoliciesContract
>
export type AwsIamListAttachedUserPoliciesBody = ContractBody<
typeof awsIamListAttachedUserPoliciesContract
>
export type AwsIamListAttachedUserPoliciesResponse = ContractJsonResponse<
typeof awsIamListAttachedUserPoliciesContract
>
@@ -0,0 +1,47 @@
import { z } from 'zod'
import type {
ContractBody,
ContractBodyInput,
ContractJsonResponse,
} from '@/lib/api/contracts/types'
import { defineRouteContract } from '@/lib/api/contracts/types'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const Schema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
pathPrefix: z.string().optional().nullable(),
maxItems: z.number().int().min(1).max(1000).optional().nullable(),
marker: z.string().optional().nullable(),
})
const ListGroupsResponseSchema = z.object({
groups: z.array(
z.object({
groupName: z.string(),
groupId: z.string(),
arn: z.string(),
path: z.string(),
createDate: z.string().nullable(),
})
),
isTruncated: z.boolean(),
marker: z.string().nullable(),
count: z.number(),
})
export const awsIamListGroupsContract = defineRouteContract({
method: 'POST',
path: '/api/tools/iam/list-groups',
body: Schema,
response: { mode: 'json', schema: ListGroupsResponseSchema },
})
export type AwsIamListGroupsRequest = ContractBodyInput<typeof awsIamListGroupsContract>
export type AwsIamListGroupsBody = ContractBody<typeof awsIamListGroupsContract>
export type AwsIamListGroupsResponse = ContractJsonResponse<typeof awsIamListGroupsContract>
@@ -0,0 +1,55 @@
import { z } from 'zod'
import type {
ContractBody,
ContractBodyInput,
ContractJsonResponse,
} from '@/lib/api/contracts/types'
import { defineRouteContract } from '@/lib/api/contracts/types'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const Schema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
scope: z.string().optional().nullable(),
onlyAttached: z.boolean().optional().nullable(),
pathPrefix: z.string().optional().nullable(),
maxItems: z.number().int().min(1).max(1000).optional().nullable(),
marker: z.string().optional().nullable(),
})
const ListPoliciesResponseSchema = z.object({
policies: z.array(
z.object({
policyName: z.string(),
policyId: z.string(),
arn: z.string(),
path: z.string(),
attachmentCount: z.number(),
isAttachable: z.boolean(),
createDate: z.string().nullable(),
updateDate: z.string().nullable(),
description: z.string().nullable(),
defaultVersionId: z.string().nullable(),
permissionsBoundaryUsageCount: z.number(),
})
),
isTruncated: z.boolean(),
marker: z.string().nullable(),
count: z.number(),
})
export const awsIamListPoliciesContract = defineRouteContract({
method: 'POST',
path: '/api/tools/iam/list-policies',
body: Schema,
response: { mode: 'json', schema: ListPoliciesResponseSchema },
})
export type AwsIamListPoliciesRequest = ContractBodyInput<typeof awsIamListPoliciesContract>
export type AwsIamListPoliciesBody = ContractBody<typeof awsIamListPoliciesContract>
export type AwsIamListPoliciesResponse = ContractJsonResponse<typeof awsIamListPoliciesContract>
@@ -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'
import { validateAwsRegion } from '@/lib/core/security/input-validation'
const Schema = z.object({
region: z
.string()
.min(1, 'AWS region is required')
.refine((v) => validateAwsRegion(v).isValid, {
message: 'Invalid AWS region format (e.g., us-east-1, eu-west-2)',
}),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
pathPrefix: z.string().optional().nullable(),
maxItems: z.number().int().min(1).max(1000).optional().nullable(),
marker: z.string().optional().nullable(),
})
const ListRolesResponseSchema = z.object({
roles: z.array(
z.object({
roleName: z.string(),
roleId: z.string(),
arn: z.string(),
path: z.string(),
createDate: z.string().nullable(),
description: z.string().nullable(),
maxSessionDuration: z.number().nullable(),
})
),
isTruncated: z.boolean(),
marker: z.string().nullable(),
count: z.number(),
})
export const awsIamListRolesContract = defineRouteContract({
method: 'POST',
path: '/api/tools/iam/list-roles',
body: Schema,
response: { mode: 'json', schema: ListRolesResponseSchema },
})
export type AwsIamListRolesRequest = ContractBodyInput<typeof awsIamListRolesContract>
export type AwsIamListRolesBody = ContractBody<typeof awsIamListRolesContract>
export type AwsIamListRolesResponse = ContractJsonResponse<typeof awsIamListRolesContract>

Some files were not shown because too many files have changed in this diff Show More