Skip to main content

API Client Layer

The web dashboard communicates with the NestJS backend API through a server-side API client layer in src/lib/api/. This layer runs exclusively on the server (using import 'server-only') and provides typed functions for every API endpoint. Server actions call these client functions, never making API calls directly.

File Organization

src/lib/api/
index.ts # Re-exports all API modules
server-api.ts # Core fetch utilities (serverFetch, serverMutation)
auth.ts # Authentication endpoints
work.ts # Work CRUD, import, schedule, settings
items-generator.ts # Item generation, submission, extraction
ai-conversation.ts # AI chat streaming endpoint
website.ts # Website repository management
health.ts # Health check endpoint
members.ts # Work member management
notifications.ts # Notification endpoints
plugins.ts # Plugin management and settings
settings.ts # User settings endpoints
enums.ts # Shared enum definitions
types.ts # Shared type definitions
types-only.ts # Re-exported types (no runtime code)
plugins-capabilities/ # Plugin capability-specific APIs
screenshot.ts # Screenshot plugin API
deploy.ts # Deployment plugin API
git-providers.ts # Git provider plugin API
oauth.ts # OAuth plugin API

Core Utilities

serverFetch

File: src/lib/api/server-api.ts

The foundation for all API calls. Handles authentication, error parsing, and response processing.

async function serverFetch<T>(endpoint: string, options?: ServerFetchOptions): Promise<T>;

Request Pipeline:

  1. Reads the auth access token from cookies via getAuthAccessCookie()
  2. Determines the frontend URL from request headers (x-forwarded-host, host) for the X-Frontend-URL header
  3. Constructs headers: Content-Type: application/json, Authorization: Bearer {token}, X-Frontend-URL
  4. Sends the request to ${API_URL}${endpoint} with cache: 'no-store' and revalidate: 0
  5. If rawResponse: true, returns the raw Response object (used for streaming)
  6. Parses the JSON response, or falls back to text

Error Handling:

StatusBehavior
401Throws with t('unauthorizedLogin') or API error message
403Throws with t('forbidden') or API error message
Other 4xx/5xxParses error from message, error.message, or error field in response body

Error messages are extracted from multiple response formats to handle different API error shapes:

// Format 1: { message: "..." } or { message: ["err1", "err2"] }
// Format 2: { error: { message: "..." } }
// Format 3: { error: "..." }
// Format 4: { message: "...", errors: ["detail1", "detail2"] }

serverMutation

A convenience wrapper for write operations:

async function serverMutation<T>({
endpoint: string,
data: any,
method: 'POST' | 'PUT' | 'PATCH' | 'DELETE',
wrapInData: boolean,
headers?: Record<string, string>,
}): Promise<T>

When wrapInData is true, the data is wrapped as { data: ... } in the request body.

handleServerError

A utility for re-throwing errors with translated messages:

async function handleServerError(error: unknown): Promise<never>;

Items Generator API

File: src/lib/api/items-generator.ts

Provides the client for all generation-related endpoints.

MethodEndpointHTTPDescription
generate/works/{id}/generatePOSTStarts item generation
update/works/{id}/updatePOSTStarts item update generation
submitItem/works/{id}/submit-itemPOSTSubmits a new item
removeItem/works/{id}/remove-itemPOSTRemoves an item
updateItem/works/{id}/update-itemPOSTUpdates item metadata
extractItemDetails/extract-item-detailsPOSTAI-extracts details from URL
regenerateMarkdown/works/{id}/regenerate-markdownPOSTRegenerates all markdown
getFormSchema/works/{id}/generator-formGETGets work form schema
getFormSchemaGlobal/generator-formGETGets global form schema

Type Re-exports: The file re-exports key types from @ever-works/plugin and @ever-works/contracts/api:

export type {
PluginIcon,
ProviderOption,
GeneratorFormSchema,
FormSchemaProvidersType,
ProviderSelectionState,
SelectableProviderCategory,
ProviderCategoryKey
} from '@ever-works/plugin';

export type {
ProvidersDto,
CreateItemsGeneratorDto,
UpdateItemsGeneratorDto,
SubmitItemDto,
RemoveItemDto,
UpdateItemDto,
ExtractItemDetailsDto
} from '@ever-works/contracts/api';

Response Types:

interface ItemsGeneratorResponse {
id: string;
slug: string;
status: string;
message?: string;
}

interface ItemResponse {
status: 'success' | 'error' | 'pending';
slug: string;
item_name: string;
item_slug?: string;
message: string;
pr_number?: number;
pr_url?: string;
auto_merged?: boolean;
item?: ItemData;
}

Enums

File: src/lib/api/enums.ts

Centralizes enum definitions, re-exporting from @ever-works/contracts/api and defining web-specific enums:

// From @ever-works/contracts/api
export { GenerationMethod, WebsiteRepositoryCreationMethod } from '@ever-works/contracts/api';
export {
GenerateStatusType,
WorkScheduleCadence,
WorkScheduleStatus,
WorkScheduleBillingMode
} from '@ever-works/contracts/api';

// Web-specific
export enum OAuthProvider {
GITHUB = 'github',
GOOGLE = 'google'
}

export enum WorkMemberRole {
OWNER = 'owner', // Reserved for creator, not assignable
MANAGER = 'manager', // Can edit work and manage members
EDITOR = 'editor', // Can edit content, cannot manage members
VIEWER = 'viewer' // Read-only access
}

export const ASSIGNABLE_MEMBER_ROLES = [WorkMemberRole.MANAGER, WorkMemberRole.EDITOR, WorkMemberRole.VIEWER] as const;

Plugin Capabilities APIs

The plugins-capabilities/ work contains API clients for plugin-specific features:

Screenshot API (screenshot.ts)

MethodDescription
checkAvailability()Checks if any screenshot plugin is configured
getScreenshotUrl(options)Gets a screenshot URL for a given website URL

Deploy API (deploy.ts)

MethodDescription
deploy(workId, options)Triggers a deployment
getDeploymentTeams()Lists deployment provider teams
getTeamsForWork(workId)Lists teams using work's plugin token
lookupExistingDeployment(workId)Checks for existing deployments

Git Providers API (git-providers.ts)

MethodDescription
checkConnection(providerId)Checks if a git provider is connected
getOrganizations(providerId)Lists user's organizations on the provider

OAuth API (oauth.ts)

MethodDescription
getConnectUrl(providerId, callbackUrl, state, forceConsent?)Gets OAuth authorization URL
disconnect(providerId)Disconnects an OAuth provider

Request/Response Patterns

Standard API Response

Most API responses follow this structure:

interface APIResponse<T = unknown> {
status: 'success' | 'error';
message?: string;
data?: T;
}

Authentication Flow

Every request includes the JWT access token from the cookie:

Authorization: Bearer <access_token>

The token is read from cookies using getAuthAccessCookie() which runs in the server context. If no token exists, the request proceeds without authentication (for public endpoints).

Caching Strategy

All API requests use cache: 'no-store' and revalidate: 0 to ensure fresh data. Cache invalidation is handled at the page level via revalidatePath() in server actions rather than at the API fetch level.

Error Propagation

Errors flow through three layers:

API Response (4xx/5xx)
-> serverFetch throws Error with parsed message
-> Server Action catches, returns { success: false, error: message }
-> Client component reads result and shows toast/inline error

This pattern ensures errors never bubble up as unhandled exceptions in the client, and all error messages are user-friendly (translated via next-intl where possible).

Index Re-exports

File: src/lib/api/index.ts

The index file provides a single import point for all API modules:

export * from './auth';
export * from './work';
export * from './items-generator';
export * from './website';
export * from './server-api';
export * from './ai-conversation';
export * from './settings';
export * from './health';
export * from './members';
export * from './plugins';
export * from './plugins-capabilities/screenshot';
export * from './plugins-capabilities/deploy';
export * from './plugins-capabilities/git-providers';
export * from './plugins-capabilities/oauth';
export * from './types';

Server actions import from this index: import { workAPI, itemsGeneratorAPI } from '@/lib/api'.