ListenHubSDKs & CLI
JavaScript SDK

SDK 方法参考

OpenAPIClient 与 ListenHubClient 的全部方法,按产品分组,附签名、端点和返回值。

这是 @marswave/listenhub-sdk 的完整方法参考,按产品分组。每个条目列出方法签名、一句话说明,以及底层调用的 HTTP 端点。

SDK 提供两个客户端。它们共用同一套响应处理(code 0 时解包 data,否则抛出 ListenHubError,并对 429 自动重试),但面向不同的 API 接口、采用不同的认证方式:

OpenAPIClientListenHubClient
认证API key(Authorization: BearerOAuth 用户访问令牌
Base URLhttps://api.marswave.ai/openapihttps://api.listenhub.ai/api
身份你的账户 / key 所有者已登录用户
适用服务端、脚本、CI面向用户的应用

OpenAPIClient公开的 OpenAPI 产品,也是本参考的重点。ListenHubClient 是第一方应用使用的 OAuth 客户端,其方法列在末尾的 ListenHubClient 方法

生成是异步的。create* 调用会立即返回一个 id;轮询对应的 get* 方法,直到 processStatus(或任务 status)离开 pending / generating。完整循环见 快速开始

下文约定:

  • "端点"路径是相对于客户端 Base URL 的。OpenAPIClient 的 Base URL 为 https://api.marswave.ai/openapi/
  • 方法返回解包后的 data 负载,{ code, message, data } 信封已为你处理。
  • 少数方法返回原始 Response(二进制或流式),文中会明确标注。
  • 不要硬编码积分成本。请改用 estimate*Credits 方法和 getSubscription()

OpenAPIClient 方法

Speakers(声音)

每个声音由其 speakerId 标识。创建任何 episode 前先列出可用声音,并传入需要的 id。

方法端点返回说明
listSpeakers(params?)GET v1/speakers/list{ items: OpenAPISpeaker[] }可用声音

listSpeakers 参数:

参数类型说明
languagestring按语言过滤,如 enzhja
statusnumber可用状态过滤

每个 OpenAPISpeaker 包含 speakerIdnamegenderlanguagedemoAudioUrl,以及可选的 profilepitchspeedtraitsstylesscenesaccentdescription)。

const { items } = await client.listSpeakers({ language: 'en' });
const speakerId = items[0].speakerId;

Podcast(播客)

播客是由 query 和/或 sources 生成的多人对话。创建后轮询 getPodcast,直到 processStatussuccess

方法端点返回
createPodcast(params)POST v1/podcast/episodes{ episodeId }
getPodcast(episodeId)GET v1/podcast/episodes/{episodeId}OpenAPIPodcastDetail
createPodcastTextContent(params)POST v1/podcast/episodes/text-content{ episodeId, message }
generatePodcastAudio(episodeId, params?)POST v1/podcast/episodes/{episodeId}/audio{ success, message, episodeId, status }
getPodcastTextStream(episodeId, event)GET v1/podcast/episodes/{episodeId}/text-stream原始 Response(流)

createPodcast 参数(OpenAPICreatePodcastParams):

参数类型说明
querystringepisode 要讲什么
sourcesArray<{ type: 'text' | 'url'; content: string }>内容素材;原始文本或页面 URL
speakersArray<{ speakerId: string }>必填;每个声音一项
languagestring输出语言
modestring生成深度(如 quickdeep

先文本后音频的两步流程,可让你在付费生成音频前先审阅或修改脚本:createPodcastTextContent 只生成脚本,随后 generatePodcastAudio(episodeId, { scripts }) 用你可选改写的脚本渲染音频。getPodcastTextStream(episodeId, 'script' | 'outline') 返回流式 Response,用于实时获取脚本/大纲 token。

OpenAPIPodcastDetail 包含 processStatustitleoutlinecoveraudioUrlaudioStreamUrlsubtitlesUrlscripts(逐说话人的台词)、credits,失败时还有 failCode

Flow Speech / TTS

Flow speech 把文本或 URL 转成由一个或多个声音朗读的音频。TTS 端点更底层:从明确的脚本合成语音。

Flow speech

方法端点返回
createFlowSpeech(params)POST v1/flow-speech/episodes{ episodeId }
getFlowSpeech(episodeId)GET v1/flow-speech/episodes/{episodeId}OpenAPIFlowSpeechDetail
createFlowSpeechTTS(params)POST v1/flow-speech/episodes/tts{ episodeId }
getFlowSpeechTextStream(episodeId, event)GET v1/flow-speech/episodes/{episodeId}/text-stream原始 Response(流)

createFlowSpeech 参数(OpenAPICreateFlowSpeechParams):

参数类型说明
sourcesArray<{ type: 'text' | 'url'; content?: string; uri?: string }>必填;文本用 content,URL 用 uri
speakersArray<{ speakerId: string }>必填
languagestring输出语言
mode'smart' | 'direct'smart 为朗读改写;direct 原样朗读

createFlowSpeechTTS 接收 scripts: Array<{ content: string; speakerId: string }> 及可选 title,逐字渲染台词。文本流的 event'script' | 'outline'

OpenAPIFlowSpeechDetail 包含 processStatustitleoutlinecoveraudioUrlaudioStreamUrlsubtitlesUrlscriptssourceProcessResult

TTS / speech

方法端点返回
speech(params)POST v1/speechOpenAPISpeechResponse
tts(params)POST v1/tts原始 Response(音频字节)
audioSpeech(params)POST v1/audio/speech原始 Response(音频字节)

speech 接收 scripts: Array<{ content: string; speakerId: string }>,同步返回 { audioUrl, audioDuration, subtitlesUrl?, taskId, credits }

ttsaudioSpeech 是兼容 OpenAI 的单声音合成。它们接收 { input, voice, response_format? }response_formatmp3(默认)、opusaacflacwavpcm,并以原始 Response 返回音频——用 .arrayBuffer() 读取或流式读取 .body

const res = await client.tts({ input: 'Hello world', voice: speakerId, response_format: 'mp3' });
const audio = Buffer.from(await res.arrayBuffer());

Storybook(解说视频 / 幻灯片)

Storybook 产出基于页面的视觉内容——解说视频与幻灯片。mode 选择格式,音频可通过 skipAudio 跳过。

方法端点返回
createStorybook(params)POST v1/storybook/episodes{ episodeId }
getStorybook(episodeId)GET v1/storybook/episodes/{episodeId}OpenAPIStorybookDetail
generateStorybookVideo(episodeId)POST v1/storybook/episodes/{episodeId}/video{ success }

createStorybook 参数(OpenAPICreateStorybookParams):

参数类型说明
sourcesArray<{ type: 'text' | 'url'; content: string }>必填的内容素材
speakersArray<{ speakerId: string }>可选;仅生成音频时需要
mode'info' | 'story' | 'slides'slides 为幻灯片;info / story 为解说
skipAudiobooleantrue 时仅出视觉内容
stylestring视觉风格提示
languagestring输出语言

episode 成功后,generateStorybookVideo(episodeId) 把页面渲染成可下载视频。轮询 getStorybook 并观察 videoStatusnot_generatedpendingsuccess / fail),成功时出现 videoUrl

OpenAPIStorybookDetail 包含 modeprocessStatustitlecoveraudioUrlaudioDurationvideoUrlvideoStatus,以及 pages(每页含 textpageNumberimageUrlaudioTimestamp)。

Image(图片)

单次调用的图片生成。OpenAPIClient 上没有单独的轮询方法——响应即携带结果。

方法端点返回
createImage(params)POST v1/images/generationOpenAPICreateImageResponse

createImage 参数(OpenAPICreateImageParams):

参数类型说明
providerstring必填的图片 provider
modelstringprovider 模型
promptstring必填的文本提示
referenceImagesArray<{ fileData?; inlineData? }>参考图——fileData: { fileUri, mimeType }inlineData: { data, mimeType }(base64)
imageConfig{ imageSize?; aspectRatio? }imageSize1K | 2K | 4KaspectRatio16:9 | 4:3 | 1:1 | 3:4 | 9:16 | 21:9

Video(SeeDance / HappyHorse + PixVerse)

两类视频共用同一套轮询/列表/估算方法,但创建方法和参数不同。SeeDance(doubao-seedance-2-*)与 HappyHorse 使用 content 数组;PixVerse 使用基于 capability 的结构。

SeeDance / HappyHorse

方法端点返回
createVideoGeneration(params)POST v1/video-generation/generate{ taskId, status }
getVideoGenerationTask(taskId)GET v1/video-generation/tasks/{taskId}OpenAPIVideoGenerationTaskDetail
listVideoGenerationTasks(params?)GET v1/video-generation/tasks{ items, page, pageSize, total }
estimateVideoCredits(params)POST v1/video-generation/estimate-credits{ tokens, credits }

createVideoGeneration 参数(OpenAPICreateVideoGenerationParams):

参数类型说明
model'doubao-seedance-2-pro' | 'doubao-seedance-2-fast' | 'happyhorse'默认为某个 SeeDance 模型
contentVideoContentItem[]必填;混合的 文本 / 图片 / 视频 / 音频 项(见下)
resolution'480p' | '720p' | '1080p'1080pdoubao-seedance-2-prohappyhorse480p
ratio'16:9' | '4:3' | '1:1' | '3:4' | '9:16' | '21:9' | '4:5' | '5:4'4:5 / 5:4happyhorse
durationnumber秒;SeeDance 最小 4,HappyHorse 最小 3
generateAudioboolean生成音轨
seednumber复现用种子
inputVideoDurationnumber视频编辑输入;SeeDance [2,15],HappyHorse [3,60]
audioSetting'auto' | 'origin'仅 HappyHorse 视频编辑,且 contentvideo_url 时生效

每个 content 项为以下之一:

  • { type: 'text', text }
  • { type: 'image_url', image_url: { url }, role: 'first_frame' \| 'last_frame' \| 'reference_image' }
  • { type: 'video_url', video_url: { url }, role: 'reference_video' }
  • { type: 'audio_url', audio_url: { url }, role: 'reference_audio' }

HappyHorse 不接受 last_frameaudio_url 内容。estimateVideoCredits 接收 { model, resolution, duration, hasVideoInput?, inputVideoDuration?, ratio? }

const { taskId } = await client.createVideoGeneration({
  model: 'doubao-seedance-2-pro',
  content: [{ type: 'text', text: 'A timelapse of a city at dusk' }],
  resolution: '1080p',
  duration: 5,
});

PixVerse

方法端点返回
createPixVerseVideoGeneration(params)POST v1/video-generation/pixverse/generate{ taskId, episodeId?, status }
estimatePixVerseVideoCredits(params)POST v1/video-generation/pixverse/estimate-credits{ tokens, credits }

PixVerse 任务用上面同样的 getVideoGenerationTask / listVideoGenerationTasks 轮询和列举。

createPixVerseVideoGeneration 参数(OpenAPICreatePixVerseVideoParams):

参数类型说明
capability'text_to_video' | 'image_to_video' | 'transition' | 'multi_transition' | 'fusion' | 'restyle' | 'mimic' | 'lip_sync' | 'agent'必填;选择生成模式
model'pixverse' | 'v6' | 'v5' | 'v4.5'PixVerse 模型版本
language'zh' | 'en'服务区域;en 国际,zh 中国大陆
promptstring文本提示
durationnumber秒(1–60;agent:20/30/60)
aspectRatio'9:16' | '16:9' | '1:1' | '4:3' | '3:4'输出宽高比
quality'360p' | '540p' | '720p' | '1080p'mimic 锁定 720p;agent 需 720p/1080p
sourceTaskIdstring复用此前成功的任务(restyle / lip_sync
images / videos / audiosArray<{ url; duration? }>输入素材
pixverseOpenAPIPixVerseOptionscapability 相关的嵌套选项

嵌套的 pixverse 对象涵盖 agentTypemotionModecameraMovementtemplateIdmultiTransitionimageReferencesttssoundEffect*lipSyncTts*brandStickerintroOutroClip,是否生效取决于 capabilityestimatePixVerseVideoCredits 接收 { capability, model?, language?, duration?, quality?, pixverse? },其中 pixverse 为用于估算的精简结构。

Music(音乐)

音乐端点默认使用 Mureka provider。异步端点返回任务({ taskId, taskType, status }),轮询 getMusicTask。同步端点(recognizeMusicdescribeMusicstemMusic)直接返回结果。

方法端点返回同步?
createMusicGenerate(params)POST v1/music/generateCreateMusicTaskResponse异步
createMusicCover(params)POST v1/music/coverCreateMusicTaskResponse异步(已弃用)
createMusicExtend(params)POST v1/music/extendCreateMusicTaskResponse异步
createMusicRemix(params)POST v1/music/remixCreateMusicTaskResponse异步
createMusicInstrumental(params)POST v1/music/instrumentalCreateMusicTaskResponse异步
createMusicSoundtrack(params)POST v1/music/soundtrackCreateMusicTaskResponse异步
createMusicTrack(params)POST v1/music/trackCreateMusicTaskResponse异步
recognizeMusic(params)POST v1/music/recognizeRecognizeMusicResponse同步
describeMusic(params)POST v1/music/describeDescribeMusicResponse同步
stemMusic(params)POST v1/music/stemStemMusicResponse同步
getMusicTask(taskId)GET v1/music/tasks/{taskId}MusicTaskDetail
listMusicTasks(params?)GET v1/music/tasks{ items, page, pageSize, total }

主要创建参数:

  • createMusicGenerate{ prompt?, lyrics?, model?, style?, title?, instrumental?, vocalId? }modelautomureka-7.6mureka-8mureka-9mureka-o2 之一。
  • createMusicExtend{ uploadUrl, model, continueAt, prompt?, style?, title?, instrumental?, negativeTags?, vocalGender?, styleWeight?, weirdnessConstraint?, audioWeight? }。这里的 model 是 Suno 版本(V4V4_5V4_5PLUSV4_5ALLV5V5_5)。
  • createMusicRemix{ audio?, audioFilename?, audioUrl?, providerSongId?, lyrics, prompt }audio / audioUrl / providerSongId 三者恰传其一。优先于已弃用的 createMusicCover
  • createMusicInstrumental{ prompt?, referenceAudio?, referenceAudioFilename?, model? }promptreferenceAudio 二选一。
  • createMusicSoundtrack{ image?, video?, prompt?, model? }imagevideo 二选一。
  • createMusicTrack{ audio?, providerSongId?, generateType, prompt, lyrics?, vocalGender?, generateStart?, generateEnd? }generateType 选择音轨类型(VocalsInstrumentalDrums…);generateTypeVocals 时必须提供 lyrics

multipart 端点(remixinstrumentalsoundtracktrackrecognizedescribestem)的音频/图片/视频字段接收 Blob/File。在 Node 20+ 中,用 new Blob([buffer]) 包裹 buffer。

const { taskId } = await client.createMusicGenerate({
  prompt: 'lo-fi hip hop, mellow, rainy night',
  model: 'auto',
});
let task = await client.getMusicTask(taskId);
while (task.status === 'pending' || task.status === 'generating') {
  await sleep(10_000);
  task = await client.getMusicTask(taskId);
}
console.log(task.tracks[0]?.audioUrl);

同步结果:recognizeMusic 返回带时间戳的 lyricsSectionsdescribeMusic 返回 { description, tags, genres, instruments }stemMusic 返回 { zipUrl, midiZipUrl, expiresAt }(链接约 24 小时后过期)。

Content Extract(内容抽取)

从 URL 抽取可读内容(正文,可选摘要)。异步:先创建,再轮询。

方法端点返回
createContentExtract(params)POST v1/content/extract{ taskId }
getContentExtract(taskId)GET v1/content/extract/{taskId}OpenAPIContentExtractDetail

createContentExtract 参数(OpenAPICreateContentExtractParams):

参数类型说明
source{ type: 'url'; uri: string }必填;要抽取的页面
options{ summarize?; maxLength?; twitter? }summarize 追加摘要;twitter: { count? } 控制 thread 深度

轮询 getContentExtract,直到 statuscompleted。detail 携带 data.contentdata.metadatadata.referencescredits

Subscription(订阅)

方法端点返回
getSubscription()GET v1/user/subscriptionOpenAPISubscriptionInfo

返回积分余额与套餐信息:totalAvailableCredits、按月/永久/限时积分的明细、resetAtrenewStatuspaidStatussubscriptionPlan。在执行昂贵任务前,用 totalAvailableCredits 检查余额。

Files(文件)

OpenAPIClient 没有专门的文件上传方法。要把本地文件作为输入,请先将其托管到一个公开 URL 并传入该 URL(例如作为 sourceurireferenceImages.fileData.fileUri,或视频的 image_url.url)。预签名上传流程在 ListenHubClient 上——见下文 Files


ListenHubClient 方法

ListenHubClient 使用 OAuth 用户访问令牌认证,面向 https://api.listenhub.ai/api,暴露第一方应用接口。其产品结构与 OpenAPIClient 不同:episode 使用嵌套的 template 对象,创建方法按产品拆分(podcast、TTS、explainer、slides)。仅当每个请求都在某个已登录用户身份下运行时,才使用这个客户端。

Auth & session(认证与会话)

方法端点返回
connectInit(params)POST v1/auth/connect/init{ sessionId, authUrl }
connectToken(params)POST v1/auth/connect/token{ accessToken, refreshToken, expiresIn }
refresh(params)POST v1/auth/token{ accessToken, refreshToken, expiresIn }
revoke(params)POST v1/auth/token/revokevoid

connectInit({ callbackPort }) 启动 device/OAuth 流程并返回待打开的 authUrlconnectToken({ sessionId, code }) 用结果换取令牌。refresh({ refreshToken }) 轮换即将过期的访问令牌;revoke({ refreshToken }) 使其失效。

Speakers(声音)

方法端点返回
listSpeakers(params?)GET v1/settings/speakers{ items: Speaker[] }

参数:{ language?, status? }。注意返回结构与 OpenAPIClient 不同——每个 Speaker 暴露的是 speakerInnerId(而非 speakerId),并附 personalityaccessTypeweight。episode 的 template.speakers 数组期望的正是 speakerInnerId

Podcast(播客)

方法端点返回
createPodcast(params)POST v1/episodes/all-in-one{ episodeId }
listPodcasts(params?)GET v1/episodesproductId=aiPodcastListEpisodesResponse

createPodcast 参数(CreatePodcastParams):

参数类型说明
type'podcast-solo' | 'podcast-duo'单人或双人
querystring主题
sourcesContentSource[]{ type: 'url' | 'text'; uri?; content? }
template{ type: 'podcast'; mode; speakers; language }modequick | deep | debatespeakersspeakerInnerId[]languageen | zh | ja

Flow Speech / TTS

方法端点返回
createTTS(params)POST v1/episodes/flow-speech{ episodeId }
listTTS(params?)GET v1/episodesproductId=textToSpeechListEpisodesResponse

createTTS 参数(CreateTTSParams):{ sources, template: { type: 'flowspeech', mode: 'smart' | 'direct', speakers, language } }

Storybook(解说视频 / 幻灯片)

方法端点返回
createExplainerVideo(params)POST v1/episodes/storybook{ episodeId }
createSlides(params)POST v1/episodes/storybookmode: 'slides'skipAudio: true{ episodeId }
exportExplainerVideo(episodeId)POST v1/episodes/{episodeId}/storybook/videovoid
listExplainerVideos(params?)GET v1/episodesproductId=explainerVideoListEpisodesResponse
listSlides(params?)GET v1/episodesproductId=slideDeckListEpisodesResponse

createExplainerVideocreateSlides 共用结构:{ query?, sources?, style?, styleOverride?, skipAudio?, imageConfig?, template }template 携带 type: 'storybook'mode(解说用 info / story,幻灯片用 slides)、speakerslanguage,以及可选的 stylesize2K / 4K)、aspectRatio16:9 / 9:16 / 1:1)、pageCountcreateSlides 默认 skipAudiotrue 并固定 modeslidesexportExplainerVideo 触发可下载视频的渲染。

Episodes(通用)

以下方法在 ListenHubClient 的四个产品间通用。

方法端点返回
getCreation(episodeId)GET v5/episodes/{episodeId}/detailEpisodeDetail
deleteCreations(params)DELETE v1/episodesvoid

getCreation 返回完整的 EpisodeDetail(状态、speakers、含 标题/大纲/音频/视频/页面/脚本 的 topicDetail)。deleteCreations({ ids }) 按 id 批量软删除至多 100 个 episode;传入视频 episode id 还会软删除其视频任务,并为进行中的任务退还积分。各产品的 list* 方法都命中 GET v1/episodes 并带 productId 过滤,接收 { page?, pageSize? }

Image(图片)

方法端点返回
createAIImage(params)POST v1/images{ imageId }
getAIImage(imageId)GET v1/images/{imageId}AIImageItem
listAIImages(params?)GET v1/images{ items, pagination }
deleteAIImages(params)DELETE v1/imagesvoid

createAIImage 参数(CreateAIImageParams):

参数类型说明
promptstring必填
referenceImageUrlsstring[]参考图 URL
language'auto' | 'en' | 'ja' | 'ko' | 'hi' | 'zh' | 'pt' | 'es'提示语言
aspectRatio'1:1' | '2:3' | '3:2' | '3:4' | '4:3' | '9:16' | '16:9' | '21:9' | …输出宽高比
imageSize'1K' | '2K' | '4K'输出分辨率
model'gemini-3-pro-image' | 'gemini-3.1-flash-image'图片模型
isLosslessboolean无损编码
enableSearchboolean允许联网搜索做内容支撑

生成是异步的——轮询 getAIImage(imageId),直到 status 为终态且 imageUrl 已设置。deleteAIImages({ ids }) 批量软删除至多 100 张图片(限本人,未知 id 忽略)。

Music(音乐)

ListenHubClient 暴露的音乐方法集与 OpenAPIClient 相同(端点相同、参数相同):createMusicGeneratecreateMusicCovercreateMusicExtendcreateMusicRemixcreateMusicInstrumentalcreateMusicSoundtrackcreateMusicTrackrecognizeMusicdescribeMusicstemMusicgetMusicTasklistMusicTasks。参数和轮询循环见上文 Music

Lyrics(歌词)

方法端点返回
createLyrics(params)POST v1/lyrics/generate{ taskId, status }
getLyricsTask(taskId)GET v1/lyrics/tasks/{taskId}LyricsTaskDetail
listLyricsTasks(params?)GET v1/lyrics/tasks{ items, page, pageSize, total }

createLyrics({ prompt }) 启动异步歌词任务;轮询 getLyricsTask 直到 statussuccess,再读取 variants(每项 { text, title, status })。

Video Generation(视频生成)

ListenHubClient 暴露与 OpenAPIClient 相同的视频方法,仅有一处命名差异:SeeDance/HappyHorse 的估算方法是 estimateVideoGenerationCreditsOpenAPIClient 上为 estimateVideoCredits)。

方法端点返回
createVideoGeneration(params)POST v1/video-generation/generate{ taskId, status }
getVideoGenerationTask(taskId)GET v1/video-generation/tasks/{taskId}VideoGenerationTaskDetail
listVideoGenerationTasks(params?)GET v1/video-generation/tasks{ items, page, pageSize, total }
estimateVideoGenerationCredits(params)POST v1/video-generation/estimate-credits{ tokens, credits }
createPixVerseVideoGeneration(params)POST v1/video-generation/pixverse/generate{ taskId, episodeId?, status }
estimatePixVerseVideoCredits(params)POST v1/video-generation/pixverse/estimate-credits{ tokens, credits }

参数与上文 Video 一致。

Subscription & user(订阅与用户)

方法端点返回
getCurrentUser()GET v1/users/meUserProfile
getSubscription()GET v1/users/subscriptionSubscriptionInfo
getSettings()GET v2/settingsSettingsResponse

注意端点与 OpenAPIClient 不同(v1/users/subscriptionv1/user/subscription)。getSettings 返回用户保存的各产品默认配置(speakers、language、duration、mode、风格图片)。

Checkin(签到)

方法端点返回
checkinSubmit()POST v1/checkin{ checkinDate, rewardCredits }
checkinStatus()GET v1/checkin/statusCheckinStatusResponse

每日签到领取奖励积分。checkinStatus 报告 hasCheckedInTodaylastCheckinTimemonthlyCheckinCount

Settings / API key

方法端点返回
getApiKey()GET v1/settings/api-key{ key }
regenerateApiKey()POST v1/settings/api-key/regenerate{ key }

让已登录用户读取或轮换自己的 OpenAPI key。regenerateApiKey 会使旧 key 失效。

Files(文件)

方法端点返回
createFileUpload(params)POST v1/files{ presignedUrl, fileUrl }
getFileDownloadUrl(fileUrl)GET v1/files{ downloadUrl }

createFileUpload({ fileKey, contentType, category }) 返回用于 PUT 上传字节的 presignedUrl,以及之后用于引用的 fileUrlgetFileDownloadUrl(fileUrl) 把已存储的文件 URL 重新签名为带时效的 downloadUrl


client.api 逃生舱

ListenHubClient 把其底层的 ky 实例暴露为 client.api,用于 SDK 尚未封装的端点。它应用相同的认证、Base URL 和重试行为,但需要你自己解析响应。路径相对于 Base URL——不带前导 /(ky 的要求):

const me = await client.api.get('v1/users/me').json();

OpenAPIClient 不暴露 client.api。若某个 OpenAPI 端点 SDK 尚未覆盖,请用你自己的 HTTP 客户端、以相同的 Authorization: Bearer 头去调用——见 OpenAPI 参考

错误

每个方法在 code 非零或 HTTP 出错时都会抛出 ListenHubError,携带 statuscoderequestId——上报问题时请附上 requestId

import { ListenHubError } from '@marswave/listenhub-sdk';

try {
  await client.getPodcast('nope');
} catch (err) {
  if (err instanceof ListenHubError) {
    console.error(`[${err.status}] code ${err.code} (request ${err.requestId})`);
  } else {
    throw err;
  }
}

下一步

On this page