Files
flatrender/src/lib/render-quality.ts
T
soroush.asadi 896ce3dfa9
CI/CD / CI · Web (tsc) (push) Successful in 1m8s
CI/CD / Deploy · full stack (push) Successful in 3m8s
feat(render): plan-gate quality tiers — free=360p watermarked, paid=all
Monetization gate for the template render flow:
- render-quality.ts: single source of truth (free -> 360p only +
  watermark; pro/business -> 540p..4K, no watermark).
- /api/render: server-authoritative gate — rejects >360p for free
  users with 403 quality_locked; passes a watermark flag through
  createRenderJob -> /v1/renders (render-svc passthrough, wired later).
- /api/render/limits: GET endpoint exposing the user's allowed tiers
  and watermark state to the studio.
- render page: locks higher tiers for free users (dashed + lock badge,
  click routes to /pricing), clamps the selected resolution down,
  shows the "free = 360p + watermark, upgrade" notice, and handles the
  403 quality_locked response.

AI-video "no free preview" rule is a future hook (no AI gen yet).
Watermark rendering (ffmpeg drawtext on the node) is a follow-up.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 15:17:25 +03:30

32 lines
1.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Render quality policy (monetization gate).
*
* Free plan → 360p only, watermarked preview.
* Pro/Business → every resolution (540p4K), no watermark.
*
* (AI-generated videos will have NO free preview at all — pay/credits before the
* result is shown. That rule belongs in the AI-video feature when it's built;
* this module covers the normal template render flow.)
*/
import type { PlanId } from "@/lib/plans";
import type { RenderSettings } from "@/lib/render-schemas";
export type Resolution = RenderSettings["resolution"]; // "360p" | "540p" | "720p" | "1080p" | "4K"
export const FREE_RESOLUTION: Resolution = "360p";
export const ALL_RESOLUTIONS: Resolution[] = ["360p", "540p", "720p", "1080p", "4K"];
/** Resolutions a plan may render at. Free = 360p only; any paid plan = all. */
export function allowedResolutions(plan: PlanId): Resolution[] {
return plan === "free" ? [FREE_RESOLUTION] : ALL_RESOLUTIONS;
}
export function isResolutionAllowed(plan: PlanId, res: Resolution): boolean {
return allowedResolutions(plan).includes(res);
}
/** Free renders get a watermarked preview; paid plans get clean output. */
export function isWatermarked(plan: PlanId): boolean {
return plan === "free";
}