byteplus-js
v0.8.0
Published
Provider-native TypeScript SDK for BytePlus ModelArk: Seedance video, Seedream images, embeddings, and Assets.
Downloads
2,832
Maintainers
Readme
byteplus-js
TypeScript SDK for BytePlus ModelArk: provider-native Seedance video, Seedream images, embeddings, and the signed Asset Library.
0.4.0 introduced breaking API changes. See the migration guide.
Configure
import { createBytePlus } from "byteplus-js";
const client = createBytePlus({
apiKey: process.env.BYTEPLUS_API_KEY,
region: "ap-southeast-1",
});Each client owns its configuration. Bearer credentials resolve lazily from an explicit key, then BYTEPLUS_API_KEY / ARK_API_KEY. Assets use separate AK/SK credentials. In multi-account applications, construct clients from the current account's explicit credentials; store receipts within that same account scope.
The root entry includes Node signing. For a portable video-only client:
import { createSeedance } from "byteplus-js/seedance";
const video = createSeedance({ apiKey: "server-side-key", fetch });Portable means no Node filesystem/signing imports; it does not make exposing an API key to untrusted browser users appropriate.
Submit and observe video
import { text, videoUrl } from "byteplus-js/seedance";
const submission = await client.seedance.create({
model: "dreamina-seedance-2-5-260628",
content: [text("A cinematic tracking shot."), videoUrl("asset://reference-id")],
omni_reference_task_type: "reference",
resolution: "1080p",
duration: 8,
generate_audio: false,
});
if (submission.outcome === "accepted") {
// Persist submission.receipt in your application's account-scoped storage.
const task = await client.seedance.retrieve(submission.receipt);
console.log(task); // safe summary
} else if (submission.outcome === "indeterminate") {
// Preserve uncertainty for reconciliation. Do not automatically create again.
console.error(submission);
} else {
console.error(submission.phase, submission.error);
}Native requests use one body with provider field names. Additive fields and unknown models work without an SDK update. Prompts remain opaque and omitted options remain omitted.
To opt into checks against an exact, dated model contract:
const prepared = client.seedance.prepare({
model: "ep-your-endpoint",
content: [text("A forest at sunrise.")],
resolution: "720p",
}, { validation: "dreamina-seedance-2-5-260628" });
// Explicit sensitive access; includes the full prompt and any media.
const exactJson = prepared.inspectBody();
const result = await client.seedance.submit(prepared);Validation of an endpoint asserts which model it serves; it does not verify its remote configuration. Preparation snapshots once and submission sends that exact JSON. A prepared value is transient. Persist the versioned receipt instead and restore it with decodeSeedanceReceipt.
Preparation throws a BytePlusValidationError at the first failing check.
create returns that failure as a local rejection with the same message and
error.validationIssues: stable codes, path segments, and explanations without
the rejected input. For example, an invalid second media URL has path
["content", 1, "video_url", "url"]. Validation details require explicit access
and are excluded from default error diagnostics.
Seedance 2.5 draft mode
Create a 480p preview, inspect its succeeded video, then finalize the selected draft as a 1080p video using the same exact model. Both requests can opt into checked validation:
import { draftTask, text } from "byteplus-js/seedance";
const model = "dreamina-seedance-2-5-260628";
const preview = await client.seedance.create({
model,
content: [text("A fox runs through a sunlit forest.")],
draft: true,
resolution: "480p",
}, { validation: model });
// Persist an accepted receipt, wait for a succeeded task, and review its video.After selecting a succeeded preview, use its task ID to create the final video:
const finalizeSelectedDraft = (selectedDraftTaskId: string) =>
client.seedance.create({
model,
content: [draftTask(selectedDraftTaskId)],
resolution: "1080p",
}, { validation: model });
// Call after review; persist an accepted final receipt and reconcile uncertainty.The final request omits prompt, media, duration, ratio, seed, audio setting, and
omni_reference_task_type; BytePlus reuses them from the preview. It may set
output_format, watermark, return_last_frame, and lifecycle options again.
These are not inherited: repeat output_format: "mov" on the final if the
preview used it, because an omitted value takes the model default.
The draft task ID remains usable for seven days from creation. See the
current BytePlus draft guide.
Seedance 2.5 at 4k
Accounts in BytePlus's Premium Program can generate Seedance 2.5 at
resolution: "4k" and finalize a 2.5 draft at "4k" as well as "1080p".
The checked 2.5 contract accepts both. BytePlus documents this in its
Seedance 2.5 4K API Guide for allowlisted accounts, not on the public API
reference. The SDK does not check account entitlements, so a request from an
account without 4k access gets the provider's rejection.
create/submit return accepted, rejected, or indeterminate. A 4xx response with
a structured error code and no task ID is a provider rejection: basis is
"documented" for a code in BytePlus's error table and "client_error" for any
other 4xx code. A timeout, network loss, in-flight abort, 408, 499, 5xx, or
malformed response after dispatch leaves acceptance unknown. No create retries
occur. The default create deadline is 240 seconds;
a call timeout or explicit client timeout overrides it.
Full task lifecycle
const page = await client.seedance.list({
page_num: 1, page_size: 20, "filter.status": "failed",
"filter.task_ids": ["task-a", "task-b"],
});
const observed = await client.seedance.watch("task-a", { timeout: 900_000 });
console.log(observed.reason, observed.task.status);
await client.seedance.delete("task-a");watch observes an existing task; it never submits. It returns a terminal task (including failed/expired/cancelled) or stops explicitly on an unrecognized status. Observation exceptions carry taskId. A watch deadline does not cancel provider execution.
Provider DELETE cancels queued work or removes eligible terminal records. Running work cannot be cancelled. Query records last seven days and output URLs last 24 hours per the checked provider reference.
SeedanceTask preserves duration, resolution, ratio, frames, frame rate, audio, seed, output format, draft, timestamps, usage, and other documented metadata. Access videoUrl/lastFrameUrl or raw deliberately; JSON serialization emits a safe summary. decodeSeedanceTask also parses callbacks, but does not authenticate them.
Node file helpers
import { dataUrl, downloadVideo } from "byteplus-js/node";
import { imageUrl } from "byteplus-js/seedance";
const image = imageUrl(dataUrl("./portrait.png"));
const task = await client.seedance.retrieve("task-a");
if (task.status === "succeeded") {
await downloadVideo(task, { outputDir: "./downloads" });
}Downloads stream to a temporary file, refuse overwrite by default, and apply cancellation/deadlines to the body. They use a separate fetch without SDK credentials. Cancellation during a filesystem operation is checked after it settles; a complete file already published atomically is retained even when cancellation is reported. Image/audio data URIs are supported; videos require URL/asset references. Native request bodies are limited to 64 MiB.
Optional provider-cost evidence
import { estimateProviderCost } from "byteplus-js/seedance";
const estimate = estimateProviderCost({
model: "dreamina-seedance-2-5-260628",
completionTokens: 100_000,
resolution: "1080p",
serviceTier: "default",
inputIncludesVideo: true,
});
if (estimate.kind === "estimated") console.log(estimate.amountUsdDecimal);Supply measured completion tokens and the required selectors. Missing evidence returns unavailable. The result records the rate card's source, observation date and assumptions, the rate, and the exact decimal calculation. List rates exclude promotions and negotiated discounts; an estimate is neither a provider invoice nor customer billing.
The SDK has one rate card, SEEDANCE_RATE_CARD: the latest rates it has
observed. When BytePlus changes a rate, a new SDK release updates the card and
its observedAt, so persist the estimate itself if you need the rate an
earlier estimate used. The card includes Seedance 2.5 at 4k at the Premium
Program rate: USD 4.70 per million tokens without input video and 2.90 with it.
seedanceCostSelectors derives the selectors a prepared request, receipt, or
context establishes. It reads structured video_url parts, never prompt text.
A draft final's body contains only draft_task, but BytePlus rates it by
whether the draft had input video, so pass the draft as draftSource:
import { seedanceCostSelectors } from "byteplus-js/seedance";
const selectors = seedanceCostSelectors(finalReceipt, { draftSource: draftReceipt });
const finalEstimate = estimateProviderCost({
completionTokens: 250_000, ...selectors,
// Fill provider-defaulted settings from the observed task.
resolution: finalTask.resolution, serviceTier: finalTask.serviceTier,
});Omitted settings stay undefined rather than assumed defaults. Without
draftSource, a final's inputIncludesVideo stays unknown.
Documented model data
seedanceOutputCanvas(model, resolution, ratio) returns the documented output
width and height, for example 854×480 for Seedance 2.5 at 480p 16:9, where the
2.0 series uses 864×496. Seedance 2.5 at 4k is not in BytePlus's table: 16:9 was
measured at 3840×2160, and the other ratios assume Seedance 2.0's 4k sizes.
adaptive has no fixed canvas. seedanceMediaLimits(model)
returns documented reference counts, per-item and total durations, and media
format and size limits. Both are dated data for callers that measure their own
media. Preparation does not enforce durations or dimensions it cannot observe,
and the SDK does not predict token usage.
Images, embeddings, and Assets
These namespace request shapes remain unchanged, apart from additive typed fields.
const images = await client.images.generate({
model: "seedream-5-0-lite-260128",
prompt: "A glass teapot with jasmine tea.",
size: "2048x2048", responseFormat: "url", watermark: false,
});
const embeddings = await client.embeddings.create({
model: "ep-your-embedding-endpoint", input: "The quick brown fox.",
});Assets use AK/SK Signature V4 through their own account plane:
const assetsClient = createBytePlus({
accessKeyId: process.env.BYTEPLUS_ACCESS_KEY_ID,
secretAccessKey: process.env.BYTEPLUS_SECRET_ACCESS_KEY,
region: "ap-southeast-1",
});
const groups = await assetsClient.assets.listAssetGroups({
groupType: "AIGC", pageSize: 20,
});Group/asset CRUD, moderation/status polling, visual validation sessions, image
layer separation (Seedream 5.0 Pro and 5.0 Flash), the background alpha
option, and sequential image generation remain supported. See
examples and the exported TypeScript declarations.
Seedream has its own rate card, SEEDREAM_RATE_CARD. Supply the reported
usage, and for 5.0 Pro, the reported size of each billed image:
import { estimateSeedreamProviderCost } from "byteplus-js/images";
const imageEstimate = estimateSeedreamProviderCost({
model: "dola-seedream-5-0-pro-260628", mode: "generation",
generatedImages: 1, inputImages: 3, outputSizes: ["2048x1152"],
});
// 1.5K output ($0.045) plus two additional reference images ($0.003 each).
if (imageEstimate.kind === "estimated") console.log(imageEstimate.amountUsdDecimal); // "0.051"Unlisted cases, such as Flash layer decomposition or a count mismatch between
generated_images and the reported sizes, return unavailable.
Errors and diagnostics
Errors expose kind, dispatched, retryable, taskId and available HTTP/correlation
metadata. retryable is an observation hint, not permission to repeat a generation.
Default messages, JSON and Node inspection exclude raw provider text. Read
providerMessage, response and cause deliberately when needed.
Task summaries from task.toJSON() include a bounded errorCode for terminal
failure routing; the original code and message remain available at task.error.
An optional onResponse hook receives bounded metadata. It is best effort and never affects a request result. Read retries share one total deadline including body consumption and backoff. Seedance create/DELETE and signed writes do not retry automatically.
Develop
npm ci
npm run typecheck
npm test
npm run build
npm run check:package
npm run measure:seedance-memorySmoke examples call real provider services and can incur usage. Local tests and package checks inject fetch and require no provider credentials.
The five consumer examples are compiled and
executed by check:package against its offline tarball install.
See SPEC, the provider inventory, and the migration guide.
