import {z} from 'zod' export type CtaSettings = {label: string, url: string}; export type ActorSettings = {backgroundColor: unknown, horizontalAlign?: ('left' | 'center' | 'right' | 'null' | null) | undefined, scale?: (number | null) | undefined, style: 'circular' | 'rectangular' | 'voiceOnly', voice?: (string | null) | undefined, seamless?: boolean | undefined}; export type InputBackgroundPosition = {x: number, y: number}; export type InputBackgroundTrim = {startTime: number, endTime: number}; export type InputVideoBackgroundSettings = {trim?: (InputBackgroundTrim | null) | undefined, shortBackgroundContentMatchMode?: ('freeze' | 'loop' | 'slow_down') | undefined, longBackgroundContentMatchMode?: ('extend_content' | 'trim' | 'speed_up') | undefined, volume?: (number | null) | undefined}; export type InputBackgroundSettings = {position?: (InputBackgroundPosition | null) | undefined, scale?: number | undefined, videoSettings?: (InputVideoBackgroundSettings | null) | undefined}; export type InputSoundSettings = {soundtrackVolume?: (number | null) | undefined}; export type Input = {avatar: string, avatarSettings?: ActorSettings | undefined, background: string, backgroundSettings?: InputBackgroundSettings | undefined, scriptAudio?: string | undefined, scriptLanguage?: ('MISSING' | 'af' | 'af-001' | 'sq-AL' | 'sq-001' | 'am' | 'am-001' | 'ar-DZ' | 'ar-BH' | 'ar-EG' | 'ar-IQ' | 'ar-JO' | 'ar-KW' | 'ar-LY' | 'ar-MA' | 'ar-QA' | 'ar-SA' | 'ar-SY' | 'ar-TN' | 'ar-AE' | 'ar-YE' | 'ar-001' | 'as-IN' | 'as-001' | 'hy-AM' | 'hy-001' | 'az-AZ' | 'az-001' | 'eu-ES' | 'eu-001' | 'bs-BA' | 'bs-001' | 'bg' | 'bg-001' | 'bn-BD' | 'bn-IN' | 'bn-001' | 'my' | 'my-001' | 'yue-CN' | 'ca' | 'ca-001' | 'zh-CN' | 'zh-HK' | 'zh-TW' | 'zh-001' | 'hr' | 'hr-001' | 'cs' | 'cs-001' | 'da' | 'da-001' | 'nl-NL' | 'nl-001' | 'nl-BE' | 'ka-GE' | 'ka-001' | 'en-AU' | 'en-CA' | 'en-GB' | 'en-HK' | 'en-IE' | 'en-IN' | 'en-KE' | 'en-MX' | 'en-NG' | 'en-NZ' | 'en-PH' | 'en-US' | 'en-SG' | 'en-ZA' | 'en-TZ' | 'en-001' | 'et' | 'et-001' | 'fil' | 'fil-001' | 'fi' | 'fi-001' | 'fr-BE' | 'fr-CA' | 'fr-CH' | 'fr-FR' | 'fr-001' | 'gl' | 'gl-001' | 'de-AT' | 'de-DE' | 'de-CH' | 'de-001' | 'el' | 'el-001' | 'gu' | 'gu-001' | 'iw' | 'iw-001' | 'hi' | 'hi-001' | 'ht-HT' | 'hu' | 'hu-001' | 'is' | 'is-001' | 'id' | 'id-001' | 'ga' | 'ga-001' | 'it' | 'it-001' | 'ja' | 'ja-001' | 'jv' | 'jv-001' | 'kn' | 'kn-001' | 'kk-KZ' | 'kk-001' | 'km' | 'km-001' | 'ko' | 'ko-001' | 'lt' | 'lt-001' | 'lv' | 'lv-001' | 'lo-LA' | 'lo-001' | 'mi-NZ' | 'mk-MK' | 'mk-001' | 'ms' | 'ms-001' | 'ml' | 'ml-001' | 'mt' | 'mt-001' | 'mr' | 'mr-001' | 'mn-MN' | 'mn-001' | 'ne-NP' | 'ne-001' | 'nb' | 'nb-001' | 'or-IN' | 'or-001' | 'ps-AF' | 'ps-001' | 'fa' | 'fa-001' | 'pl' | 'pl-001' | 'pt-BR' | 'pt-PT' | 'pt-001' | 'pa-IN' | 'pa-001' | 'ro' | 'ro-001' | 'ru' | 'ru-001' | 'sr' | 'sr-001' | 'si-LK' | 'si-001' | 'sk' | 'sk-001' | 'sl' | 'sl-001' | 'so' | 'so-001' | 'es-AR' | 'es-BO' | 'es-CL' | 'es-CO' | 'es-CR' | 'es-CU' | 'es-DO' | 'es-EC' | 'es-SV' | 'es-GQ' | 'es-GT' | 'es-HN' | 'es-LA' | 'es-MX' | 'es-NI' | 'es-PA' | 'es-PY' | 'es-PE' | 'es-PR' | 'es-ES' | 'es-US' | 'es-UY' | 'es-VE' | 'es-001' | 'su' | 'su-001' | 'sv' | 'sv-001' | 'sw-KE' | 'sw-TZ' | 'sw-001' | 'vi' | 'vi-001' | 'ta-IN' | 'ta-SG' | 'ta-LK' | 'ta-001' | 'te' | 'te-001' | 'tr' | 'tr-001' | 'th' | 'th-001' | 'uk' | 'uk-001' | 'ur-IN' | 'ur-PK' | 'ur-001' | 'uz' | 'uz-001' | 'cy' | 'cy-001' | 'wuu-CN' | 'zu' | 'zu-001') | undefined, scriptText?: string | undefined, soundSettings?: InputSoundSettings | undefined, transition?: (string | null) | undefined}; export type ParentSoundtrackRegion = {soundtrack: string, slideRange: string, fadeInSeconds?: number | undefined, fadeOutSeconds?: number | undefined}; export type ParentSoundSettings = {defaultSoundtrackVolume?: number | undefined, soundtracks?: Array | undefined}; export type CreateVideoRequest = {folderId?: (string | null) | undefined, aspectRatio?: ('16:9' | '9:16' | '1:1' | '4:5' | '5:4') | undefined, ctaSettings?: CtaSettings | undefined, callbackId?: string | undefined, description?: string | undefined, input: Array, soundtrack?: ('corporate' | 'inspirational' | 'modern' | 'urban') | undefined, soundSettings?: ParentSoundSettings | undefined, test?: boolean | undefined, title?: string | undefined, visibility?: ('private' | 'public') | undefined}; export type CreateApiV2VideosArgs = {body: CreateVideoRequest}; export type CreateApiV2VideosOptions = {baseUrl?: string | undefined, apiKey?: string | undefined, fetch?: typeof fetch | undefined}; export const ctaSettings = z.object({label: z.string(), url: z.string()}); export const videoThumbnailTypesResponse = z.object({image: z.string().nullable().optional(), gif: z.string().nullable().optional()}); export const videoResponse = z.object({callbackId: z.string().optional(), createdAt: z.number().int().optional(), ctaSettings: ctaSettings.optional(), description: z.string().optional(), test: z.boolean().optional(), download: z.string().optional(), duration: z.string().optional(), id: z.string().optional(), lastUpdatedAt: z.number().int().optional(), status: z.enum(["complete", "deleted", "error", "in_progress", "rejected", "approved"]).optional(), thumbnail: videoThumbnailTypesResponse.nullable().optional(), title: z.string().optional(), visibility: z.enum(["private", "public"]).optional()}); 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 }; /** * Create a video * * POST /v2/videos */ export const createApiV2Videos = async (args: CreateApiV2VideosArgs, options?: CreateApiV2VideosOptions) => { const {baseUrl = "https://api.synthesia.io", fetch: fetchFn = fetch, apiKey} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('content-type', "application/json") headers.set('accept', "application/json") if (apiKey !== undefined) headers.set("Authorization", apiKey) const url = `${baseUrl.replace(/\/+$/, '')}/v2/videos${query.size > 0 ? `?${query}` : ''}` const res = await fetchFn(url, {method: "POST", headers, body: JSON.stringify(args.body)}) if (!res.ok) throw new Error(`Request failed with status ${res.status}`, {cause: {status: res.status, body: await res.text()}}) return validateResponse(videoResponse, await res.json()) };