import {z} from 'zod' export type GetApiV1VideosIdClipsClipIdLayoutsArgs = {id: string, clipId: string}; export type GetApiV1VideosIdClipsClipIdLayoutsOptions = {baseUrl?: string | undefined, BearerAuth?: string | undefined, fetch?: typeof fetch | undefined}; export const clipLayoutCropOutput = z.object({bottom: z.number().gte(0), left: z.number().gte(0), right: z.number().gte(0), top: z.number().gte(0)}); export const customLayoutDimensions = z.object({height: z.number().gt(0), width: z.number().gt(0)}); export const customLayoutPoint = z.object({x: z.number(), y: z.number()}); export const customLayoutSlot = z.object({corners: z.enum(["none", "regular", "squircle"]).optional(), dimensions: customLayoutDimensions.optional(), hidden: z.boolean().optional(), order: z.number().int().gte(-9007199254740991).lte(9007199254740991).optional(), point: customLayoutPoint.optional(), shape: z.enum(["none", "circle", "square", "portrait", "cutout", "blob", "blob-outline"]).optional()}); export const clipLayoutShape = z.discriminatedUnion("kind", [z.object({kind: z.literal("fullscreen"), screenFit: z.enum(["cover", "letterbox"]).optional(), style: z.enum(["regular", "stretch"]).optional()}), z.object({kind: z.literal("middle"), shape: z.enum(["circle", "square", "landscape", "portrait"]).optional()}), z.object({kind: z.literal("side-by-side"), position: z.enum(["left", "right", "top", "bottom"]), size: z.enum(["S", "M", "L"]).optional(), style: z.enum(["regular", "even", "overlap", "perspective"])}), z.object({kind: z.literal("tv-presenter"), position: z.enum(["left", "right"]), style: z.enum(["regular", "full", "overlap"])}), z.object({kind: z.literal("cut-out"), position: z.enum(["left", "right"]).optional(), style: z.enum(["regular", "perspective"]).optional()}), z.object({kind: z.literal("camera-bubble"), position: z.enum(["left", "right", "top", "bottom", "top-left", "top-right", "bottom-left", "bottom-right", "middle"]), screenFit: z.enum(["cover", "letterbox"]).optional(), shape: z.enum(["circle", "square", "landscape", "portrait"]).optional(), size: z.enum(["S", "M", "L"]), style: z.enum(["regular", "full"]).optional()}), z.object({kind: z.literal("camera-only"), punchIn: z.boolean().optional(), shape: z.enum(["circle", "square", "landscape", "portrait"]).optional(), style: z.enum(["fullscreen", "middle"])}), z.object({kind: z.literal("screen-only"), screenFit: z.enum(["cover", "letterbox"]).optional(), style: z.enum(["fullscreen", "middle"])}), z.object({kind: z.literal("custom"), presentation: customLayoutSlot.optional(), subject: customLayoutSlot.optional()})]); export const clipMediaItem = z.object({documentId: z.string().optional(), height: z.number().int().gte(-9007199254740991).lte(9007199254740991).nullable().optional(), imageUrl: z.string().nullable().optional(), muted: z.boolean().nullable().optional(), slot: z.enum(["screen", "camera"]).optional(), sourceId: z.string().nullable().optional(), startTimeMs: z.number().nullable().optional(), type: z.enum(["image", "video", "motion"]), width: z.number().int().gte(-9007199254740991).lte(9007199254740991).nullable().optional()}); export const clipPopOut = z.object({amount: z.number().gte(0).lte(0.5).optional(), background: z.enum(["original", "color"]).optional(), color: z.string().optional(), outlineColor: z.string().optional(), outlineWidth: z.number().gte(0).lte(0.05).optional()}); export const layoutTransitionStyle = z.enum(["spring", "hardCut"]); export const clipLayout = z.object({cameraStyle: z.enum(["none", "circle", "square", "portrait", "cutout", "blob", "blob-outline"]).optional(), crop: clipLayoutCropOutput.nullable().optional(), durationMs: z.number().gte(0).nullable().optional(), followsBase: z.boolean().optional(), id: z.string(), layout: clipLayoutShape.nullable().optional(), media: z.array(clipMediaItem), popOut: clipPopOut.nullable().optional(), startTimeMs: z.number().gte(0).nullable().optional(), transitionStyle: layoutTransitionStyle.nullable().optional()}); export const listClipLayoutsResponse = z.object({layouts: z.array(clipLayout)}); export const validateResponse = async ( schema: { readonly '~standard': { readonly validate: (value: unknown) => ({ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }) | Promise<{ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }> } }, value: unknown ): Promise => { const result = await schema['~standard'].validate(value) if (result.issues !== undefined) { const detail = result.issues .map(({ message, path }) => path?.length ? `${path.map((segment) => String(typeof segment === 'object' ? segment.key : segment)).join('.')}: ${message}` : message ) .join('; ') throw new Error(`Response does not match the schema: ${detail}`, { cause: { issues: result.issues } }) } return result.value }; /** * List layouts on a clip * * GET /v1/videos/{id}/clips/{clipId}/layouts */ export const getApiV1VideosIdClipsClipIdLayouts = async (args: GetApiV1VideosIdClipsClipIdLayoutsArgs, options?: GetApiV1VideosIdClipsClipIdLayoutsOptions) => { const {baseUrl = "https://api.tella.com", fetch: fetchFn = fetch, BearerAuth} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('accept', "application/json") if (BearerAuth !== undefined) headers.set('authorization', `Bearer ${BearerAuth}`) const url = `${baseUrl.replace(/\/+$/, '')}/v1/videos/${encodeURIComponent(String(args.id))}/clips/${encodeURIComponent(String(args.clipId))}/layouts${query.size > 0 ? `?${query}` : ''}` const res = await fetchFn(url, {method: "GET", headers}) if (!res.ok) throw new Error(`Request failed with status ${res.status}`, {cause: {status: res.status, body: await res.text()}}) return validateResponse(listClipLayoutsResponse, await res.json()) };