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,70 @@
import { createLogger } from '@sim/logger'
import { assertWorkflowMutable, WorkflowLockedError } from '@sim/platform-authz/workflow'
import type { NextRequest } from 'next/server'
import { workflowDeploymentVersionParamSchema } from '@/lib/api/contracts/workflows'
import { generateRequestId } from '@/lib/core/utils/request'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import { performRevertToVersion } from '@/lib/workflows/orchestration'
import { validateWorkflowPermissions } from '@/lib/workflows/utils'
import { createErrorResponse, createSuccessResponse } from '@/app/api/workflows/utils'
const logger = createLogger('RevertToDeploymentVersionAPI')
export const dynamic = 'force-dynamic'
export const runtime = 'nodejs'
export const POST = withRouteHandler(
async (
request: NextRequest,
{ params }: { params: Promise<{ id: string; version: string }> }
) => {
const requestId = generateRequestId()
const { id, version } = await params
try {
const {
error,
session,
workflow: workflowRecord,
} = await validateWorkflowPermissions(id, requestId, 'admin')
if (error) {
return createErrorResponse(error.message, error.status)
}
await assertWorkflowMutable(id)
const versionValidation = workflowDeploymentVersionParamSchema.safeParse(version)
if (!versionValidation.success) {
return createErrorResponse('Invalid version', 400)
}
const result = await performRevertToVersion({
workflowId: id,
version: versionValidation.data,
userId: session!.user.id,
workflow: (workflowRecord ?? {}) as Record<string, unknown>,
request,
actorName: session!.user.name ?? undefined,
actorEmail: session!.user.email ?? undefined,
})
if (!result.success) {
return createErrorResponse(
result.error || 'Failed to revert',
result.errorCode === 'not_found' ? 404 : 500
)
}
return createSuccessResponse({
message: 'Reverted to deployment version',
lastSaved: result.lastSaved,
})
} catch (error: any) {
if (error instanceof WorkflowLockedError) {
return createErrorResponse(error.message, error.status)
}
logger.error('Error reverting to deployment version', error)
return createErrorResponse(error.message || 'Failed to revert', 500)
}
}
)
@@ -0,0 +1,188 @@
import { db, workflowDeploymentVersion } from '@sim/db'
import { createLogger } from '@sim/logger'
import { and, eq } from 'drizzle-orm'
import type { NextRequest } from 'next/server'
import { updateDeploymentVersionMetadataContract } from '@/lib/api/contracts/deployments'
import { getValidationErrorMessage, parseRequest } from '@/lib/api/server'
import { generateRequestId } from '@/lib/core/utils/request'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import { captureServerEvent } from '@/lib/posthog/server'
import { performActivateVersion } from '@/lib/workflows/orchestration'
import { statusForOrchestrationError } from '@/lib/workflows/orchestration/types'
import {
getWorkflowDeploymentVersion,
updateDeploymentVersionMetadata,
} from '@/lib/workflows/persistence/utils'
import { validateWorkflowPermissions } from '@/lib/workflows/utils'
import { createErrorResponse, createSuccessResponse } from '@/app/api/workflows/utils'
const logger = createLogger('WorkflowDeploymentVersionAPI')
export const dynamic = 'force-dynamic'
export const runtime = 'nodejs'
export const maxDuration = 120
export const GET = withRouteHandler(
async (
request: NextRequest,
{ params }: { params: Promise<{ id: string; version: string }> }
) => {
const requestId = generateRequestId()
const { id, version } = await params
try {
const { error } = await validateWorkflowPermissions(id, requestId, 'read')
if (error) {
return createErrorResponse(error.message, error.status)
}
const versionNum = Number(version)
if (!Number.isFinite(versionNum)) {
return createErrorResponse('Invalid version', 400)
}
const row = await getWorkflowDeploymentVersion(id, versionNum)
if (!row?.state) {
return createErrorResponse('Deployment version not found', 404)
}
return createSuccessResponse({ deployedState: row.state })
} catch (error: any) {
logger.error(
`[${requestId}] Error fetching deployment version ${version} for workflow ${id}`,
error
)
return createErrorResponse(error.message || 'Failed to fetch deployment version', 500)
}
}
)
export const PATCH = withRouteHandler(
async (request: NextRequest, context: { params: Promise<{ id: string; version: string }> }) => {
const requestId = generateRequestId()
try {
const parsed = await parseRequest(updateDeploymentVersionMetadataContract, request, context, {
validationErrorResponse: (error) =>
createErrorResponse(getValidationErrorMessage(error, 'Invalid request body'), 400),
})
if (!parsed.success) return parsed.response
const { id, version } = parsed.data.params
const { name, description, isActive } = parsed.data.body
// Activation requires admin permission, other updates require write
const requiredPermission = isActive ? 'admin' : 'write'
const {
error,
session,
workflow: workflowData,
} = await validateWorkflowPermissions(id, requestId, requiredPermission)
if (error) {
return createErrorResponse(error.message, error.status)
}
const versionNum = version
// Handle activation
if (isActive) {
const actorUserId = session?.user?.id
if (!actorUserId) {
logger.warn(
`[${requestId}] Unable to resolve actor user for deployment activation: ${id}`
)
return createErrorResponse('Unable to determine activating user', 400)
}
const activateResult = await performActivateVersion({
workflowId: id,
version: versionNum,
userId: actorUserId,
workflow: workflowData as Record<string, unknown>,
requestId,
request,
})
if (!activateResult.success) {
return createErrorResponse(
activateResult.error || 'Failed to activate deployment',
statusForOrchestrationError(activateResult.errorCode)
)
}
let updatedName: string | null | undefined
let updatedDescription: string | null | undefined
if (name !== undefined || description !== undefined) {
const activationUpdateData: { name?: string; description?: string | null } = {}
if (name !== undefined) {
activationUpdateData.name = name
}
if (description !== undefined) {
activationUpdateData.description = description
}
const [updated] = await db
.update(workflowDeploymentVersion)
.set(activationUpdateData)
.where(
and(
eq(workflowDeploymentVersion.workflowId, id),
eq(workflowDeploymentVersion.version, versionNum)
)
)
.returning({
name: workflowDeploymentVersion.name,
description: workflowDeploymentVersion.description,
})
if (updated) {
updatedName = updated.name
updatedDescription = updated.description
logger.info(
`[${requestId}] Updated deployment version ${version} metadata during activation`,
{ name: activationUpdateData.name, description: activationUpdateData.description }
)
}
}
const wsId = (workflowData as { workspaceId?: string } | null)?.workspaceId
captureServerEvent(
actorUserId,
'deployment_version_activated',
{ workflow_id: id, workspace_id: wsId ?? '', version: versionNum },
wsId ? { groups: { workspace: wsId } } : undefined
)
return createSuccessResponse({
success: true,
deployedAt: activateResult.deployedAt,
warnings: activateResult.warnings,
...(updatedName !== undefined && { name: updatedName }),
...(updatedDescription !== undefined && { description: updatedDescription }),
})
}
// Handle name/description updates (shared with the update_deployment_version copilot tool)
const updated = await updateDeploymentVersionMetadata({
workflowId: id,
version: versionNum,
name,
description,
})
if (!updated) {
return createErrorResponse('Deployment version not found', 404)
}
logger.info(`[${requestId}] Updated deployment version ${version} for workflow ${id}`, {
name,
description,
})
return createSuccessResponse({ name: updated.name, description: updated.description })
} catch (error: any) {
logger.error(`[${requestId}] Error updating deployment version`, error)
return createErrorResponse(error.message || 'Failed to update deployment version', 500)
}
}
)
@@ -0,0 +1,41 @@
import { createLogger } from '@sim/logger'
import type { NextRequest } from 'next/server'
import { listDeploymentVersionsContract } from '@/lib/api/contracts/deployments'
import { parseRequest } from '@/lib/api/server'
import { generateRequestId } from '@/lib/core/utils/request'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import { listWorkflowVersions } from '@/lib/workflows/persistence/utils'
import { validateWorkflowPermissions } from '@/lib/workflows/utils'
import { createErrorResponse, createSuccessResponse } from '@/app/api/workflows/utils'
const logger = createLogger('WorkflowDeploymentsListAPI')
export const dynamic = 'force-dynamic'
export const runtime = 'nodejs'
export const GET = withRouteHandler(
async (request: NextRequest, context: { params: Promise<{ id: string }> }) => {
const requestId = generateRequestId()
const parsed = await parseRequest(listDeploymentVersionsContract, request, context)
if (!parsed.success) return parsed.response
const { id } = parsed.data.params
try {
const { error } = await validateWorkflowPermissions(id, requestId, 'read')
if (error) {
return createErrorResponse(error.message, error.status)
}
const { versions: rows } = await listWorkflowVersions(id)
const versions = rows.map(({ deployedByName, ...version }) => ({
...version,
deployedBy: deployedByName,
}))
return createSuccessResponse({ versions })
} catch (error: any) {
logger.error(`[${requestId}] Error listing deployments for workflow: ${id}`, error)
return createErrorResponse(error.message || 'Failed to list deployments', 500)
}
}
)