Skip to main content

Overview

Connection server actions handle database connection management, including deletion, schema retrieval, validation, and introspection.

deleteConnection

Deletes a specific database connection from a project.
export async function deleteConnection(
  connectionId: string,
  userId: string
): Promise<DeleteConnectionResponse>

Parameters

connectionId
string
required
ID of the connection to delete
userId
string
required
ID of the user requesting deletion (must own the parent project)

Validation

The connection ID is validated using the ConnectionDeleteSchema:
const ConnectionDeleteSchema = z.object({
  id: z.string().min(1, "Connection ID is required")
})

Response

success
boolean
required
Indicates if deletion was successful
message
string
Success message with connection and project details
error
string
Error message (only when success is false)Possible errors:
  • "Invalid connection ID"
  • "Connection not found or you don't have permission to delete it"
  • "Failed to delete connection"

Behavior

  • Ownership verification: Only the project owner can delete connections
  • Cascade impact: Deleting a connection may affect widgets using that schema
  • Revalidation: Automatically revalidates /projects and /projects/:id paths

Example

import { deleteConnection } from '@/app/actions/project/connections'

const result = await deleteConnection('conn_123', 'clx1234567')

if (result.success) {
  console.log(result.message)
  // "Connection deleted from project 'Analytics Dashboard'"
} else {
  console.error(result.error)
}
Deleting a connection is irreversible and may break widgets that depend on its schema.

getProjectSchema

Retrieves the stored database schema for a project from the first available connection with an introspected schema.
export async function getProjectSchema(
  projectId: string
): Promise<GetSchemaResponse>

Parameters

projectId
string
required
ID of the project to retrieve schema for

Response

success
boolean
required
Indicates if schema retrieval was successful
schema
DbSchema
The database schema object (only when success is true)
schema.tables
Table[]
Array of table definitions
tables[].name
string
Table name
tables[].columns
Column[]
Array of column definitions
columns[].name
string
Column name
columns[].type
string
Column data type (e.g., “integer”, “varchar”, “timestamp”)
columns[].nullable
boolean
Whether the column accepts NULL values
columns[].defaultValue
string | null
Default value for the column
lastIntrospectionAt
Date | null
Timestamp of the last schema introspection
error
string
Error message (only when success is false)Possible errors:
  • "Valid project ID is required"
  • "Project not found"
  • "No schema found for this project"
  • "Invalid schema format"
  • "Failed to fetch project schema"

Behavior

  • Returns schema from the first connection with a non-null dbSchema field
  • Handles both JSON string and object formats for stored schemas
  • Includes timestamp of last introspection

Example

import { getProjectSchema } from '@/app/actions/project/connections'

const result = await getProjectSchema('clx7890abc')

if (result.success && result.schema) {
  console.log('Tables:', result.schema.tables.length)
  console.log('Last introspection:', result.lastIntrospectionAt)
  
  result.schema.tables.forEach(table => {
    console.log(`Table: ${table.name} (${table.columns.length} columns)`)
  })
}
Schemas are automatically introspected when connections are created or validated. Use regenerateProjectSchemas to refresh.

validateProjectConnections

Validates all database connections in a project by testing connectivity.
export async function validateProjectConnections(
  projectId: string,
  userId: string
): Promise<ValidationResponse>

Parameters

projectId
string
required
ID of the project to validate connections for
userId
string
required
ID of the user requesting validation (must own the project)

Response

success
boolean
required
Indicates if validation process completed successfully
validConnections
number
Number of valid connections
totalConnections
number
Total number of connections tested
connectionStatuses
ConnectionStatus[]
Detailed status for each connection
connectionStatuses[].id
string
Connection ID
connectionStatuses[].isValid
boolean
Whether the connection is valid
connectionStatuses[].error
string | undefined
Error message (if connection failed)
error
string
Error message (only when success is false)

Behavior

  • Parallel validation: Tests all connections concurrently using Promise.allSettled
  • Connection test: Makes HTTP request to /api/testdbconnection for each connection
  • No persistence: Results are returned but NOT saved to the database
  • Read-only: Does not modify connection status in the database

Example

import { validateProjectConnections } from '@/app/actions/project/validation'

const result = await validateProjectConnections('clx7890abc', 'clx1234567')

if (result.success) {
  console.log(`Valid: ${result.validConnections}/${result.totalConnections}`)
  
  result.connectionStatuses?.forEach(status => {
    if (!status.isValid) {
      console.error(`Connection ${status.id} failed: ${status.error}`)
    }
  })
}

validateConnectionsQuietly

Validates connections and updates their status in the database without triggering UI updates.
export async function validateConnectionsQuietly(
  projectId: string,
  userId: string
): Promise<ValidationResponse>

Parameters

projectId
string
required
ID of the project to validate connections for
userId
string
required
ID of the user requesting validation (must own the project)

Response

success
boolean
required
Indicates if validation completed successfully
validConnections
number
Number of valid connections
totalConnections
number
Total number of connections tested
connectionStatuses
ConnectionStatus[]
Detailed status for each connection
error
string
Error message (only when success is false)

Behavior

  • Database persistence: Updates each connection’s isValid, validationError, and lastIntrospectionAt fields
  • Parallel validation: Tests all connections concurrently
  • Background operation: Designed for silent validation after create/update operations
  • No revalidation: Does not trigger Next.js path revalidation
  • Empty project handling: Returns success with 0 connections if project has no connections

Example

import { validateConnectionsQuietly } from '@/app/actions/project/validation'

// Called automatically after project creation/update
const result = await validateConnectionsQuietly('clx7890abc', 'clx1234567')

if (result.success) {
  console.log(`Validated ${result.validConnections} connections silently`)
}
This action is automatically called after createProjectWithConnections and updateProject. You rarely need to call it directly.

CreateDbSchema

Introspects a database connection to extract and store its schema (tables, columns, types).
export default async function CreateDbSchema(
  connectionId: string
): Promise<CreateSchemaResponse>

Parameters

connectionId
string
required
ID of the database connection to introspect

Response

Returns the introspected schema data or throws an error.
tables
Table[]
Array of table definitions extracted from the database

Behavior

  • API call: Makes HTTP POST request to /api/createschema
  • Database update: Stores schema in the connection’s dbSchema field
  • Timestamp update: Updates lastIntrospectionAt timestamp
  • Error handling: Throws detailed error messages on failure

Errors

Throws Error with descriptive messages:
  • "Invalid connection ID provided"
  • "API call failed with status {statusCode}"
  • "Failed to create database schema: {errorMessage}"

Example

import CreateDbSchema from '@/app/actions/project/database'

try {
  const schema = await CreateDbSchema('conn_123')
  console.log('Introspected tables:', schema.tables)
} catch (error) {
  console.error('Schema introspection failed:', error.message)
}
Schema introspection is automatically triggered when connections are created or updated. Manual calls are only needed for schema refresh.

Type Definitions

interface DeleteConnectionResponse {
  success: boolean
  message?: string
  error?: string
}

interface GetSchemaResponse {
  success: boolean
  schema?: DbSchema
  lastIntrospectionAt?: Date | null
  error?: string
}

interface DbSchema {
  tables: Table[]
}

interface Table {
  name: string
  columns: Column[]
}

interface Column {
  name: string
  type: string           // e.g., "integer", "varchar", "timestamp"
  nullable: boolean
  defaultValue: string | null
}

interface ValidationResponse {
  success: boolean
  validConnections?: number
  totalConnections?: number
  connectionStatuses?: ConnectionStatus[]
  error?: string
}

interface ConnectionStatus {
  id: string
  isValid: boolean
  error?: string
}

interface CreateSchemaResponse {
  tables: Table[]
}

Validation Schemas

Connection-related Zod schemas from @/lib/projects/schemas:
// Connection title (1-50 characters)
const ConnectionTitleSchema = z.string()
  .min(1, "Connection title is required")
  .max(50, "Connection title cannot exceed 50 characters")

// Database host (IP, localhost, or hostname)
const DatabaseHostSchema = z.string()
  .min(1, "Host is required")
  .refine((value) => {
    // Validates IPv4, IPv6, localhost, or valid hostname
  })

// Database port (1-65535)
const DatabasePortSchema = z.number()
  .min(1, "Port is required")
  .max(65535, "Port must be between 1 and 65535")

// Database name (1-60 chars, alphanumeric + hyphens/underscores)
const DatabaseNameSchema = z.string()
  .min(1, "Database name is required")
  .max(60, "Database name cannot exceed 60 characters")
  .regex(/^[a-zA-Z0-9_-]+$/, "Only letters, numbers, hyphens, and underscores allowed")

// Database user (1-50 characters)
const DatabaseUserSchema = z.string()
  .min(1, "Username is required")
  .max(50, "Username cannot exceed 50 characters")

// Database password (min 1 character)
const DatabasePasswordSchema = z.string()
  .min(1, "Password is required")

// Complete connection configuration
const DatabaseConfigSchema = z.object({
  title: ConnectionTitleSchema,
  host: DatabaseHostSchema,
  port: DatabasePortSchema,
  database: DatabaseNameSchema,
  user: DatabaseUserSchema,
  password: DatabasePasswordSchema,
})

// Connection deletion
const ConnectionDeleteSchema = z.object({
  id: z.string().min(1, "Connection ID is required")
})

Build docs developers (and LLMs) love