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,55 @@
import { createLogger } from '@sim/logger'
import { getErrorMessage } from '@sim/utils/errors'
import { generateId } from '@sim/utils/id'
import { type NextRequest, NextResponse } from 'next/server'
import { awsSecretsManagerCreateSecretContract } from '@/lib/api/contracts/tools/aws/secrets-manager-create-secret'
import { parseToolRequest } from '@/lib/api/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import { createSecret, createSecretsManagerClient } from '../utils'
const logger = createLogger('SecretsManagerCreateSecretAPI')
export const POST = withRouteHandler(async (request: NextRequest) => {
const requestId = generateId().slice(0, 8)
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const parsed = await parseToolRequest(awsSecretsManagerCreateSecretContract, request, {
errorFormat: 'details',
logger,
})
if (!parsed.success) return parsed.response
const params = parsed.data.body
logger.info(`[${requestId}] Creating secret ${params.name}`)
const client = createSecretsManagerClient({
region: params.region,
accessKeyId: params.accessKeyId,
secretAccessKey: params.secretAccessKey,
})
try {
const result = await createSecret(client, params.name, params.secretValue, params.description)
logger.info(`[${requestId}] Secret created: ${result.name}`)
return NextResponse.json({
message: `Secret "${result.name}" created successfully`,
...result,
})
} finally {
client.destroy()
}
} catch (error) {
const errorMessage = getErrorMessage(error, 'Unknown error occurred')
logger.error(`[${requestId}] Failed to create secret:`, error)
return NextResponse.json({ error: `Failed to create secret: ${errorMessage}` }, { status: 500 })
}
})
@@ -0,0 +1,61 @@
import { createLogger } from '@sim/logger'
import { getErrorMessage } from '@sim/utils/errors'
import { generateId } from '@sim/utils/id'
import { type NextRequest, NextResponse } from 'next/server'
import { awsSecretsManagerDeleteSecretContract } from '@/lib/api/contracts/tools/aws/secrets-manager-delete-secret'
import { parseToolRequest } from '@/lib/api/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import { createSecretsManagerClient, deleteSecret } from '../utils'
const logger = createLogger('SecretsManagerDeleteSecretAPI')
export const POST = withRouteHandler(async (request: NextRequest) => {
const requestId = generateId().slice(0, 8)
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const parsed = await parseToolRequest(awsSecretsManagerDeleteSecretContract, request, {
errorFormat: 'details',
logger,
})
if (!parsed.success) return parsed.response
const params = parsed.data.body
logger.info(`[${requestId}] Deleting secret ${params.secretId}`)
const client = createSecretsManagerClient({
region: params.region,
accessKeyId: params.accessKeyId,
secretAccessKey: params.secretAccessKey,
})
try {
const result = await deleteSecret(
client,
params.secretId,
params.recoveryWindowInDays,
params.forceDelete
)
const action = params.forceDelete ? 'permanently deleted' : 'scheduled for deletion'
logger.info(`[${requestId}] Secret ${action}: ${result.name}`)
return NextResponse.json({
message: `Secret "${result.name}" ${action}`,
...result,
})
} finally {
client.destroy()
}
} catch (error) {
const errorMessage = getErrorMessage(error, 'Unknown error occurred')
logger.error(`[${requestId}] Failed to delete secret:`, error)
return NextResponse.json({ error: `Failed to delete secret: ${errorMessage}` }, { status: 500 })
}
})
@@ -0,0 +1,55 @@
import { createLogger } from '@sim/logger'
import { getErrorMessage } from '@sim/utils/errors'
import { generateId } from '@sim/utils/id'
import { type NextRequest, NextResponse } from 'next/server'
import { awsSecretsManagerDescribeSecretContract } from '@/lib/api/contracts/tools/aws/secrets-manager-describe-secret'
import { parseToolRequest } from '@/lib/api/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import { createSecretsManagerClient, describeSecret } from '../utils'
const logger = createLogger('SecretsManagerDescribeSecretAPI')
export const POST = withRouteHandler(async (request: NextRequest) => {
const requestId = generateId().slice(0, 8)
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const parsed = await parseToolRequest(awsSecretsManagerDescribeSecretContract, request, {
errorFormat: 'details',
logger,
})
if (!parsed.success) return parsed.response
const params = parsed.data.body
logger.info(`[${requestId}] Describing secret ${params.secretId}`)
const client = createSecretsManagerClient({
region: params.region,
accessKeyId: params.accessKeyId,
secretAccessKey: params.secretAccessKey,
})
try {
const result = await describeSecret(client, params.secretId)
logger.info(`[${requestId}] Described secret: ${result.name}`)
return NextResponse.json(result)
} finally {
client.destroy()
}
} catch (error) {
const errorMessage = getErrorMessage(error, 'Unknown error occurred')
logger.error(`[${requestId}] Failed to describe secret:`, error)
return NextResponse.json(
{ error: `Failed to describe secret: ${errorMessage}` },
{ status: 500 }
)
}
})
@@ -0,0 +1,60 @@
import { createLogger } from '@sim/logger'
import { getErrorMessage } from '@sim/utils/errors'
import { generateId } from '@sim/utils/id'
import { type NextRequest, NextResponse } from 'next/server'
import { awsSecretsManagerGetSecretContract } from '@/lib/api/contracts/tools/aws/secrets-manager-get-secret'
import { parseToolRequest } from '@/lib/api/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import { createSecretsManagerClient, getSecretValue } from '../utils'
const logger = createLogger('SecretsManagerGetSecretAPI')
export const POST = withRouteHandler(async (request: NextRequest) => {
const requestId = generateId().slice(0, 8)
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const parsed = await parseToolRequest(awsSecretsManagerGetSecretContract, request, {
errorFormat: 'details',
logger,
})
if (!parsed.success) return parsed.response
const params = parsed.data.body
logger.info(`[${requestId}] Retrieving secret ${params.secretId}`)
const client = createSecretsManagerClient({
region: params.region,
accessKeyId: params.accessKeyId,
secretAccessKey: params.secretAccessKey,
})
try {
const result = await getSecretValue(
client,
params.secretId,
params.versionId,
params.versionStage
)
logger.info(`[${requestId}] Secret retrieved successfully`)
return NextResponse.json(result)
} finally {
client.destroy()
}
} catch (error) {
const errorMessage = getErrorMessage(error, 'Unknown error occurred')
logger.error(`[${requestId}] Failed to retrieve secret:`, error)
return NextResponse.json(
{ error: `Failed to retrieve secret: ${errorMessage}` },
{ status: 500 }
)
}
})
@@ -0,0 +1,52 @@
import { createLogger } from '@sim/logger'
import { getErrorMessage } from '@sim/utils/errors'
import { generateId } from '@sim/utils/id'
import { type NextRequest, NextResponse } from 'next/server'
import { awsSecretsManagerListSecretsContract } from '@/lib/api/contracts/tools/aws/secrets-manager-list-secrets'
import { parseToolRequest } from '@/lib/api/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import { createSecretsManagerClient, listSecrets } from '../utils'
const logger = createLogger('SecretsManagerListSecretsAPI')
export const POST = withRouteHandler(async (request: NextRequest) => {
const requestId = generateId().slice(0, 8)
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const parsed = await parseToolRequest(awsSecretsManagerListSecretsContract, request, {
errorFormat: 'details',
logger,
})
if (!parsed.success) return parsed.response
const params = parsed.data.body
logger.info(`[${requestId}] Listing secrets`)
const client = createSecretsManagerClient({
region: params.region,
accessKeyId: params.accessKeyId,
secretAccessKey: params.secretAccessKey,
})
try {
const result = await listSecrets(client, params.maxResults, params.nextToken)
logger.info(`[${requestId}] Listed ${result.count} secrets`)
return NextResponse.json(result)
} finally {
client.destroy()
}
} catch (error) {
const errorMessage = getErrorMessage(error, 'Unknown error occurred')
logger.error(`[${requestId}] Failed to list secrets:`, error)
return NextResponse.json({ error: `Failed to list secrets: ${errorMessage}` }, { status: 500 })
}
})
@@ -0,0 +1,58 @@
import { createLogger } from '@sim/logger'
import { getErrorMessage } from '@sim/utils/errors'
import { generateId } from '@sim/utils/id'
import { type NextRequest, NextResponse } from 'next/server'
import { awsSecretsManagerRestoreSecretContract } from '@/lib/api/contracts/tools/aws/secrets-manager-restore-secret'
import { parseToolRequest } from '@/lib/api/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import { createSecretsManagerClient, restoreSecret } from '../utils'
const logger = createLogger('SecretsManagerRestoreSecretAPI')
export const POST = withRouteHandler(async (request: NextRequest) => {
const requestId = generateId().slice(0, 8)
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const parsed = await parseToolRequest(awsSecretsManagerRestoreSecretContract, request, {
errorFormat: 'details',
logger,
})
if (!parsed.success) return parsed.response
const params = parsed.data.body
logger.info(`[${requestId}] Restoring secret ${params.secretId}`)
const client = createSecretsManagerClient({
region: params.region,
accessKeyId: params.accessKeyId,
secretAccessKey: params.secretAccessKey,
})
try {
const result = await restoreSecret(client, params.secretId)
logger.info(`[${requestId}] Restored secret: ${result.name}`)
return NextResponse.json({
message: `Secret "${result.name}" restored successfully`,
...result,
})
} finally {
client.destroy()
}
} catch (error) {
const errorMessage = getErrorMessage(error, 'Unknown error occurred')
logger.error(`[${requestId}] Failed to restore secret:`, error)
return NextResponse.json(
{ error: `Failed to restore secret: ${errorMessage}` },
{ status: 500 }
)
}
})
@@ -0,0 +1,66 @@
import { createLogger } from '@sim/logger'
import { getErrorMessage } from '@sim/utils/errors'
import { generateId } from '@sim/utils/id'
import { type NextRequest, NextResponse } from 'next/server'
import { awsSecretsManagerRotateSecretContract } from '@/lib/api/contracts/tools/aws/secrets-manager-rotate-secret'
import { parseToolRequest } from '@/lib/api/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import { createSecretsManagerClient, rotateSecret } from '../utils'
const logger = createLogger('SecretsManagerRotateSecretAPI')
export const POST = withRouteHandler(async (request: NextRequest) => {
const requestId = generateId().slice(0, 8)
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const parsed = await parseToolRequest(awsSecretsManagerRotateSecretContract, request, {
errorFormat: 'details',
logger,
})
if (!parsed.success) return parsed.response
const params = parsed.data.body
logger.info(`[${requestId}] Rotating secret ${params.secretId}`)
const client = createSecretsManagerClient({
region: params.region,
accessKeyId: params.accessKeyId,
secretAccessKey: params.secretAccessKey,
})
try {
const result = await rotateSecret(
client,
params.secretId,
params.clientRequestToken,
params.rotationLambdaARN,
{
automaticallyAfterDays: params.automaticallyAfterDays,
duration: params.duration,
scheduleExpression: params.scheduleExpression,
},
params.rotateImmediately
)
logger.info(`[${requestId}] Rotation started for secret: ${result.name}`)
return NextResponse.json({
message: `Rotation started for secret "${result.name}"`,
...result,
})
} finally {
client.destroy()
}
} catch (error) {
const errorMessage = getErrorMessage(error, 'Unknown error occurred')
logger.error(`[${requestId}] Failed to rotate secret:`, error)
return NextResponse.json({ error: `Failed to rotate secret: ${errorMessage}` }, { status: 500 })
}
})
@@ -0,0 +1,59 @@
import { createLogger } from '@sim/logger'
import { getErrorMessage } from '@sim/utils/errors'
import { generateId } from '@sim/utils/id'
import { type NextRequest, NextResponse } from 'next/server'
import { awsSecretsManagerTagResourceContract } from '@/lib/api/contracts/tools/aws/secrets-manager-tag-resource'
import { parseToolRequest } from '@/lib/api/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import { createSecretsManagerClient, tagResource } from '../utils'
const logger = createLogger('SecretsManagerTagResourceAPI')
export const POST = withRouteHandler(async (request: NextRequest) => {
const requestId = generateId().slice(0, 8)
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const parsed = await parseToolRequest(awsSecretsManagerTagResourceContract, request, {
errorFormat: 'details',
logger,
})
if (!parsed.success) return parsed.response
const params = parsed.data.body
logger.info(`[${requestId}] Tagging secret ${params.secretId}`)
const client = createSecretsManagerClient({
region: params.region,
accessKeyId: params.accessKeyId,
secretAccessKey: params.secretAccessKey,
})
try {
const result = await tagResource(
client,
params.secretId,
params.tags.map((t) => ({ Key: t.key, Value: t.value }))
)
logger.info(`[${requestId}] Tagged secret: ${result.name}`)
return NextResponse.json({
message: `Secret "${result.name}" tagged successfully`,
...result,
})
} finally {
client.destroy()
}
} catch (error) {
const errorMessage = getErrorMessage(error, 'Unknown error occurred')
logger.error(`[${requestId}] Failed to tag secret:`, error)
return NextResponse.json({ error: `Failed to tag secret: ${errorMessage}` }, { status: 500 })
}
})
@@ -0,0 +1,55 @@
import { createLogger } from '@sim/logger'
import { getErrorMessage } from '@sim/utils/errors'
import { generateId } from '@sim/utils/id'
import { type NextRequest, NextResponse } from 'next/server'
import { awsSecretsManagerUntagResourceContract } from '@/lib/api/contracts/tools/aws/secrets-manager-untag-resource'
import { parseToolRequest } from '@/lib/api/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import { createSecretsManagerClient, untagResource } from '../utils'
const logger = createLogger('SecretsManagerUntagResourceAPI')
export const POST = withRouteHandler(async (request: NextRequest) => {
const requestId = generateId().slice(0, 8)
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const parsed = await parseToolRequest(awsSecretsManagerUntagResourceContract, request, {
errorFormat: 'details',
logger,
})
if (!parsed.success) return parsed.response
const params = parsed.data.body
logger.info(`[${requestId}] Untagging secret ${params.secretId}`)
const client = createSecretsManagerClient({
region: params.region,
accessKeyId: params.accessKeyId,
secretAccessKey: params.secretAccessKey,
})
try {
const result = await untagResource(client, params.secretId, params.tagKeys)
logger.info(`[${requestId}] Untagged secret: ${result.name}`)
return NextResponse.json({
message: `Secret "${result.name}" untagged successfully`,
...result,
})
} finally {
client.destroy()
}
} catch (error) {
const errorMessage = getErrorMessage(error, 'Unknown error occurred')
logger.error(`[${requestId}] Failed to untag secret:`, error)
return NextResponse.json({ error: `Failed to untag secret: ${errorMessage}` }, { status: 500 })
}
})
@@ -0,0 +1,60 @@
import { createLogger } from '@sim/logger'
import { getErrorMessage } from '@sim/utils/errors'
import { generateId } from '@sim/utils/id'
import { type NextRequest, NextResponse } from 'next/server'
import { awsSecretsManagerUpdateSecretContract } from '@/lib/api/contracts/tools/aws/secrets-manager-update-secret'
import { parseToolRequest } from '@/lib/api/server'
import { checkInternalAuth } from '@/lib/auth/hybrid'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import { createSecretsManagerClient, updateSecretValue } from '../utils'
const logger = createLogger('SecretsManagerUpdateSecretAPI')
export const POST = withRouteHandler(async (request: NextRequest) => {
const requestId = generateId().slice(0, 8)
const auth = await checkInternalAuth(request)
if (!auth.success || !auth.userId) {
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
}
try {
const parsed = await parseToolRequest(awsSecretsManagerUpdateSecretContract, request, {
errorFormat: 'details',
logger,
})
if (!parsed.success) return parsed.response
const params = parsed.data.body
logger.info(`[${requestId}] Updating secret ${params.secretId}`)
const client = createSecretsManagerClient({
region: params.region,
accessKeyId: params.accessKeyId,
secretAccessKey: params.secretAccessKey,
})
try {
const result = await updateSecretValue(
client,
params.secretId,
params.secretValue,
params.description
)
logger.info(`[${requestId}] Secret updated: ${result.name}`)
return NextResponse.json({
message: `Secret "${result.name}" updated successfully`,
...result,
})
} finally {
client.destroy()
}
} catch (error) {
const errorMessage = getErrorMessage(error, 'Unknown error occurred')
logger.error(`[${requestId}] Failed to update secret:`, error)
return NextResponse.json({ error: `Failed to update secret: ${errorMessage}` }, { status: 500 })
}
})
@@ -0,0 +1,266 @@
import type { RotationRulesType, SecretListEntry, Tag } from '@aws-sdk/client-secrets-manager'
import {
CreateSecretCommand,
DeleteSecretCommand,
DescribeSecretCommand,
GetSecretValueCommand,
ListSecretsCommand,
RestoreSecretCommand,
RotateSecretCommand,
SecretsManagerClient,
TagResourceCommand,
UntagResourceCommand,
UpdateSecretCommand,
} from '@aws-sdk/client-secrets-manager'
import type { SecretsManagerConnectionConfig } from '@/tools/secrets_manager/types'
function mapRotationRules(rules: RotationRulesType | undefined) {
if (!rules) return null
return {
automaticallyAfterDays: rules.AutomaticallyAfterDays ?? null,
duration: rules.Duration ?? null,
scheduleExpression: rules.ScheduleExpression ?? null,
}
}
export function createSecretsManagerClient(
config: SecretsManagerConnectionConfig
): SecretsManagerClient {
return new SecretsManagerClient({
region: config.region,
credentials: {
accessKeyId: config.accessKeyId,
secretAccessKey: config.secretAccessKey,
},
})
}
export async function getSecretValue(
client: SecretsManagerClient,
secretId: string,
versionId?: string | null,
versionStage?: string | null
) {
const command = new GetSecretValueCommand({
SecretId: secretId,
...(versionId ? { VersionId: versionId } : {}),
...(versionStage ? { VersionStage: versionStage } : {}),
})
const response = await client.send(command)
if (!response.SecretString && response.SecretBinary) {
throw new Error(
'Secret is stored as binary (SecretBinary). This integration only supports string secrets.'
)
}
return {
name: response.Name ?? '',
secretValue: response.SecretString ?? '',
arn: response.ARN ?? '',
versionId: response.VersionId ?? '',
versionStages: response.VersionStages ?? [],
createdDate: response.CreatedDate?.toISOString() ?? null,
}
}
export async function listSecrets(
client: SecretsManagerClient,
maxResults?: number | null,
nextToken?: string | null
) {
const command = new ListSecretsCommand({
...(maxResults ? { MaxResults: maxResults } : {}),
...(nextToken ? { NextToken: nextToken } : {}),
})
const response = await client.send(command)
const secrets = (response.SecretList ?? []).map((secret: SecretListEntry) => ({
name: secret.Name ?? '',
arn: secret.ARN ?? '',
description: secret.Description ?? null,
createdDate: secret.CreatedDate?.toISOString() ?? null,
lastChangedDate: secret.LastChangedDate?.toISOString() ?? null,
lastAccessedDate: secret.LastAccessedDate?.toISOString() ?? null,
rotationEnabled: secret.RotationEnabled ?? false,
tags: secret.Tags?.map((t: Tag) => ({ key: t.Key ?? '', value: t.Value ?? '' })) ?? [],
rotationRules: mapRotationRules(secret.RotationRules),
lastRotatedDate: secret.LastRotatedDate?.toISOString() ?? null,
nextRotationDate: secret.NextRotationDate?.toISOString() ?? null,
deletedDate: secret.DeletedDate?.toISOString() ?? null,
secretVersionsToStages: secret.SecretVersionsToStages ?? null,
}))
return {
secrets,
nextToken: response.NextToken ?? null,
count: secrets.length,
}
}
export async function createSecret(
client: SecretsManagerClient,
name: string,
secretValue: string,
description?: string | null
) {
const command = new CreateSecretCommand({
Name: name,
SecretString: secretValue,
...(description ? { Description: description } : {}),
})
const response = await client.send(command)
return {
name: response.Name ?? '',
arn: response.ARN ?? '',
versionId: response.VersionId ?? '',
}
}
export async function updateSecretValue(
client: SecretsManagerClient,
secretId: string,
secretValue: string,
description?: string | null
) {
const command = new UpdateSecretCommand({
SecretId: secretId,
SecretString: secretValue,
...(description ? { Description: description } : {}),
})
const response = await client.send(command)
return {
name: response.Name ?? '',
arn: response.ARN ?? '',
versionId: response.VersionId ?? '',
}
}
export async function deleteSecret(
client: SecretsManagerClient,
secretId: string,
recoveryWindowInDays?: number | null,
forceDelete?: boolean | null
) {
const command = new DeleteSecretCommand({
SecretId: secretId,
...(forceDelete ? { ForceDeleteWithoutRecovery: true } : {}),
...(!forceDelete && recoveryWindowInDays ? { RecoveryWindowInDays: recoveryWindowInDays } : {}),
})
const response = await client.send(command)
return {
name: response.Name ?? '',
arn: response.ARN ?? '',
deletionDate: response.DeletionDate?.toISOString() ?? null,
}
}
export async function describeSecret(client: SecretsManagerClient, secretId: string) {
const command = new DescribeSecretCommand({ SecretId: secretId })
const response = await client.send(command)
return {
name: response.Name ?? '',
arn: response.ARN ?? '',
description: response.Description ?? null,
kmsKeyId: response.KmsKeyId ?? null,
rotationEnabled: response.RotationEnabled ?? false,
rotationLambdaARN: response.RotationLambdaARN ?? null,
rotationRules: mapRotationRules(response.RotationRules),
lastRotatedDate: response.LastRotatedDate?.toISOString() ?? null,
lastChangedDate: response.LastChangedDate?.toISOString() ?? null,
lastAccessedDate: response.LastAccessedDate?.toISOString() ?? null,
deletedDate: response.DeletedDate?.toISOString() ?? null,
nextRotationDate: response.NextRotationDate?.toISOString() ?? null,
tags: response.Tags?.map((t: Tag) => ({ key: t.Key ?? '', value: t.Value ?? '' })) ?? [],
versionIdsToStages: response.VersionIdsToStages ?? null,
owningService: response.OwningService ?? null,
createdDate: response.CreatedDate?.toISOString() ?? null,
primaryRegion: response.PrimaryRegion ?? null,
replicationStatus:
response.ReplicationStatus?.map((r) => ({
region: r.Region ?? '',
kmsKeyId: r.KmsKeyId ?? null,
status: r.Status ?? null,
statusMessage: r.StatusMessage ?? null,
lastAccessedDate: r.LastAccessedDate?.toISOString() ?? null,
})) ?? [],
}
}
export async function tagResource(client: SecretsManagerClient, secretId: string, tags: Tag[]) {
const command = new TagResourceCommand({ SecretId: secretId, Tags: tags })
await client.send(command)
return { name: secretId }
}
export async function untagResource(
client: SecretsManagerClient,
secretId: string,
tagKeys: string[]
) {
const command = new UntagResourceCommand({ SecretId: secretId, TagKeys: tagKeys })
await client.send(command)
return { name: secretId }
}
export async function restoreSecret(client: SecretsManagerClient, secretId: string) {
const command = new RestoreSecretCommand({ SecretId: secretId })
const response = await client.send(command)
return {
name: response.Name ?? '',
arn: response.ARN ?? '',
}
}
export async function rotateSecret(
client: SecretsManagerClient,
secretId: string,
clientRequestToken?: string | null,
rotationLambdaARN?: string | null,
rotationRules?: {
automaticallyAfterDays?: number | null
duration?: string | null
scheduleExpression?: string | null
} | null,
rotateImmediately?: boolean | null
) {
const hasRotationRules = Boolean(
rotationRules?.automaticallyAfterDays ||
rotationRules?.duration ||
rotationRules?.scheduleExpression
)
const command = new RotateSecretCommand({
SecretId: secretId,
...(clientRequestToken ? { ClientRequestToken: clientRequestToken } : {}),
...(rotationLambdaARN ? { RotationLambdaARN: rotationLambdaARN } : {}),
...(hasRotationRules
? {
RotationRules: {
...(rotationRules?.automaticallyAfterDays
? { AutomaticallyAfterDays: rotationRules.automaticallyAfterDays }
: {}),
...(rotationRules?.duration ? { Duration: rotationRules.duration } : {}),
...(rotationRules?.scheduleExpression
? { ScheduleExpression: rotationRules.scheduleExpression }
: {}),
},
}
: {}),
...(rotateImmediately === undefined || rotateImmediately === null
? {}
: { RotateImmediately: rotateImmediately }),
})
const response = await client.send(command)
return {
name: response.Name ?? '',
arn: response.ARN ?? '',
versionId: response.VersionId ?? '',
}
}