import {z} from 'zod' export type CreateApiSunoV1StemsArgs = {body: {isStorage?: boolean | undefined, hookUrl?: string | undefined, music_id: string, stem_type?: ('lead_vocal' | 'drum_kit' | 'bass' | 'backing_vocals' | 'piano' | 'electric_guitar' | 'percussion' | 'string_section' | 'synth' | 'acoustic_guitar' | 'sound_effects' | 'synth_pad' | 'synth_bass' | 'guitar' | 'brass_section' | 'organ' | 'electronic_drum_kit' | 'lead_electric_guitar' | 'synth_keys' | 'rhythm_electric_guitar' | 'electric_piano' | 'upright_bass' | 'keyboards' | 'distorted_electric_guitar' | 'kick' | 'snare' | 'risers' | 'synth_strings' | 'synth_lead' | 'woodwinds' | 'flute' | 'harp' | 'tambourine' | 'trumpet' | 'arpeggiator' | 'accordion' | 'fiddle' | 'pedal_steel_guitar' | 'synth_voice' | 'violin' | 'digital_piano' | 'synth_brass' | 'mandolin' | 'choir' | 'banjo' | 'bells' | 'clarinet' | 'tenor_saxophone' | 'trombone' | 'shaker' | 'french_horn' | 'glockenspiel' | 'electric_bass' | 'cello' | 'timpani' | 'harmonica' | 'marimba' | 'vibraphone' | 'lap_steel_guitar' | 'saxophone' | 'orchestra' | 'horns' | 'cymbals' | 'hand_clap' | 'oboe' | 'celesta' | 'congas' | 'drone' | 'alto_saxophone' | 'double_bass' | 'ukulele' | 'harpsichord' | 'baritone_saxophone' | 'xylophone' | 'tuba' | 'bass_guitar' | 'whistle' | 'lead_guitar' | 'rhodes' | '808' | 'bongos' | 'bassoon' | 'cowbell' | 'viola' | 'sitar' | 'steel_drums' | 'piccolo' | 'theremin' | 'bagpipes' | 'hi_hat' | 'music_box' | 'melodica' | 'tabla' | 'koto' | 'djembe' | 'taiko' | 'didgeridoo') | undefined}}; export type CreateApiSunoV1StemsOptions = {baseUrl?: string | undefined, CustomApiKey?: string | undefined, fetch?: typeof fetch | undefined}; export const createApiSunoV1StemsResponse = z.object({status: z.string(), message: z.string(), data: z.object({})}); 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 }; /** * POST /suno/v1/stems */ export const createApiSunoV1Stems = async (args: CreateApiSunoV1StemsArgs, options?: CreateApiSunoV1StemsOptions) => { const {baseUrl = "https://api.ttapi.io", fetch: fetchFn = fetch, CustomApiKey} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('content-type', "application/json") headers.set('accept', "application/json") if (CustomApiKey !== undefined) headers.set("TT-API-KEY", CustomApiKey) const url = `${baseUrl.replace(/\/+$/, '')}/suno/v1/stems${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(createApiSunoV1StemsResponse, await res.json()) };