Advertisement

← vibesdk

worker/api/controllers/apps/publicAppDto.ts

3.0 KB Download file
/**
 * Public response projections for app endpoints.
 *
 * The persistence model (schema.apps / EnhancedAppData) intentionally carries
 * sensitive and operational data (original prompts, deployment IDs, anonymous
 * session tokens, internal user IDs). These helpers are the single source of
 * truth for what may leave the worker on the public app endpoints. Any new
 * public field must be added here explicitly.
 */

import type {
    EnhancedAppData,
    PublicAppListData,
    PublicAppDetailData,
} from '../../../database/types';

/**
 * GitHub repository fields are only safe to expose for public repositories.
 * For private repos (or non-owner viewers) both fields are nulled.
 */
function publicGithubFields(
    app: Pick<EnhancedAppData, 'githubRepositoryUrl' | 'githubRepositoryVisibility'>,
): Pick<PublicAppListData, 'githubRepositoryUrl' | 'githubRepositoryVisibility'> {
    const isPublicRepo = app.githubRepositoryVisibility === 'public';
    return {
        githubRepositoryUrl: isPublicRepo ? app.githubRepositoryUrl : null,
        githubRepositoryVisibility: isPublicRepo ? app.githubRepositoryVisibility : null,
    };
}

/**
 * Whitelist an enhanced app row for the public listing response. Drops every
 * sensitive/operational column; exposes GitHub fields only for public repos.
 */
export function toPublicAppListItem(app: EnhancedAppData): PublicAppListData {
    return {
        id: app.id,
        title: app.title,
        description: app.description,
        iconUrl: app.iconUrl,
        framework: app.framework,
        visibility: app.visibility,
        status: app.status,
        isFeatured: app.isFeatured,
        screenshotUrl: app.screenshotUrl,
        createdAt: app.createdAt,
        updatedAt: app.updatedAt,
        lastDeployedAt: app.lastDeployedAt,
        ...publicGithubFields(app),
        userName: app.userName,
        userAvatar: app.userAvatar,
        starCount: app.starCount,
        viewCount: app.viewCount,
        forkCount: app.forkCount,
        likeCount: app.likeCount,
        userStarred: app.userStarred,
        userFavorited: app.userFavorited,
    };
}

/**
 * Whitelist an enhanced app row for the detail response.
 *
 * The original prompt and generated code are intended to be visible on public
 * apps, so `originalPrompt` is always included. Operational fields (`userId`,
 * `deploymentId`) and private-repo GitHub URLs are only exposed to the owner.
 */
export function toPublicAppDetail(
    app: EnhancedAppData,
    isOwner: boolean,
): PublicAppDetailData {
    const base = toPublicAppListItem(app);
    const github = isOwner
        ? {
              githubRepositoryUrl: app.githubRepositoryUrl,
              githubRepositoryVisibility: app.githubRepositoryVisibility,
          }
        : {};

    return {
        ...base,
        ...github,
        originalPrompt: app.originalPrompt,
        userId: isOwner ? app.userId : undefined,
        deploymentId: isOwner ? app.deploymentId : undefined,
    };
}