@d-ai/media-sdk
v0.2.0
Published
Universal TypeScript SDK for D.AI image, video, and audio generation
Readme
@d-ai/media-sdk
Universal TypeScript client for D.AI image, video, and audio generation. It runs on Node.js 18+, modern browsers, Workers, Bun, and other Fetch API runtimes.
Install
npm install @d-ai/media-sdkConfigure
import { DaiMediaClient } from "@d-ai/media-sdk";
const client = new DaiMediaClient({ apiKey: process.env.DAI_API_KEY!, baseUrl: "https://gateway.example.com/dai", timeoutMs: 90_000, });
A path prefix in `baseUrl` is preserved. Authentication and content-type headers are managed by the SDK and cannot be overridden by global headers. A custom `fetch` implementation can be injected for Workers, tests, or instrumented transports.
## Image
```ts
const result = await client.images.openai.generate({
model: "gpt-image-2",
prompt: "A glass greenhouse at sunrise",
size: "1024x1024",
});
console.log(result.images[0]?.url);For GPT Image 2.5(经济·非官方), explicitly choose gpt-image-2.5 and the asynchronous method. It is a separate, lower-cost unofficial channel: latency, reliability, and output may differ from official flare/sunburst. Official calls never switch channels automatically.
const job = await client.images.openai.gptGenerate({
model: "gpt-image-2.5",
prompt: "Draw a glass greenhouse at sunrise",
n: 1,
});
const economyImage = await client.jobs.wait(job);
console.log(economyImage.assets[0]);Economy requests generate one image (n omitted or 1) and do not support size, quality, aspect_ratio, response_format, background, or output_format; unsupported controls are rejected, not ignored. Use generate with gpt-image-2.5-flare / gpt-image-2.5-sunburst for the official channel. Sending the economy model to generate is an error.
Flux image jobs are asynchronous:
const job = await client.images.flux.generate({
model: "flux1-dev",
prompt: "A cinematic portrait of a fox in neon rain",
size: "1024x1024",
});
const flux = await client.jobs.wait(job);
console.log(flux.assets[0]);flux1-schnell is edits-only (client.images.flux.edits).
Grok Image is asynchronous. The model catalog exposes grok-image; generation and editing share the same polling endpoint:
const generated = await client.images.grok.generate({
model: "grok-image",
prompt: "A glass greenhouse at sunrise",
aspectRatio: "16:9",
});
const generatedImage = await client.jobs.wait(generated);
const edited = await client.images.grok.edits({
model: "grok-image",
prompt: "Add warm lantern light",
images: ["https://cdn.example.com/greenhouse.png"],
});
const editedImage = await client.jobs.wait(edited);Both methods return a MediaJobHandle. The SDK submits to /api/image/grok/v1/generations or /api/image/grok/v1/edits, then polls /api/image/grok/v1/fetch through client.jobs.fetch or client.jobs.wait.
Video and jobs
const job = await client.videos.gemini.generate({
prompt: "A slow orbital camera move around a glass greenhouse",
model: "veo-3.1-fast",
aspectRatio: "16:9",
});
const result = await client.jobs.wait(job, {
pollIntervalMs: 2_000,
maxWaitMs: 20 * 60_000,
});The SDK rebuilds every polling URL from the configured baseUrl. An absolute fetchUrl returned by the server is informational and never changes the polling host.
Grok Imagine Video 1.5 is also asynchronous. The model catalog exposes grok-imagine-video-1.5; it requires exactly one reference image and supports 1–15 seconds at 480p, 720p, or 1080p:
const grokVideo = await client.videos.grok.generate({
model: "grok-imagine-video-1.5",
prompt: "A slow orbital camera move around the greenhouse",
aspectRatio: "16:9",
resolutionName: "720p",
videoLength: 10,
referImages: ["https://cdn.example.com/greenhouse.png"],
referenceAudios: [{ voiceId: "voice-id" }],
});
const video = await client.jobs.wait(grokVideo, {
pollIntervalMs: 2_000,
maxWaitMs: 20 * 60_000,
});The request maps aspectRatio, resolutionName, videoLength, referImages, and referenceAudios to the API's aspect_ratio, resolution_name, video_length, refer_images, and reference_audios fields. Polling uses /api/video/grok/v1/fetch on the configured host.
Wan 3.0 Video is asynchronous and supports prompt-only, frame, reference-media,
URL, and file inputs. Supply the exact wan3.0-video model and optional output
parameters; polling uses /api/video/wan/v1/fetch through the configured host:
const wanJob = await client.videos.wan.generate({
model: "wan3.0-video",
input: {
prompt: "A slow camera move through a misty bamboo forest",
media: [{ type: "reference_image", url: "https://cdn.example.com/forest.png" }],
},
parameters: {
resolution: "1080P",
ratio: "16:9",
duration: 5,
audio: true,
},
});
const wanVideo = await client.jobs.wait(wanJob);
console.log(wanVideo.assets[0]);Wan parameters.duration accepts integer seconds 2..30 or -1 for smart
duration. parameters.resolution accepts 480P, 720P, or 1080P; media
types are first_frame, last_frame, reference_image, reference_video,
reference_audio, link, and file.
Cancellation
Every request accepts AbortSignal:
const controller = new AbortController();
const request = client.audio.suno.music(
{
custom: false,
instrumental: true,
mv: "chirp-v5",
gptDescriptionPrompt: "Night city lo-fi piano",
},
{ signal: controller.signal },
);
controller.abort();
await request;Billed POST requests are never automatically retried.
Browser security
Do not embed an application-owned long-lived API key in public JavaScript. Browser execution is appropriate for user-supplied keys, trusted internal applications, or future short-lived scoped tokens. Public products should call D.AI from their own backend; see examples/nextjs-media.
