@apicity/alibaba

中文文档
0.27.0发布于 2026/11/06MITTypeScriptES Module近 30 天下载 4277

Alibaba Cloud Model Studio provider for chat completions, image generation, and streaming.

原始使用文档
文档目录10 节
  1. Installation
  2. Quick Start
  3. Real-world example: Wan 2.7 image-to-video with async task …
  4. API Reference
  5. compatibleMode
  6. services
  7. tasks
  8. uploads
  9. Middleware
  10. License

@apicity/alibaba

npm dependencies TypeScript

Alibaba Cloud Model Studio provider for chat completions, image generation, and streaming.

Runtime dependencies:

  • zod@^4.6.6 — request schemas attached to every POST endpoint as .schema

Installation

npm install @apicity/alibaba
# or
pnpm add @apicity/alibaba

Quick Start

import { createAlibaba } from "@apicity/alibaba";

const alibaba = createAlibaba({ apiKey: process.env.ALIBABA_API_KEY! });

Real-world example: Wan 2.7 image-to-video with async task polling

DashScope's aigc/* family is async-by-default: every video, image, and audio generation endpoint returns immediately with a task_id and a task_status of PENDING, and the actual artifact lives behind a separate GET /api/v1/tasks/{taskId} you poll until it transitions to SUCCEEDED. The provider hides the X-DashScope-Async: enable header plumbing but keeps the two-call shape visible because it lets you checkpoint the task_id, walk away, and resume later from any process. The example below mines every task_id, timestamp, prompt, and resolution from tests/recordings/alibaba_1329897167/wan-i2v_2196817451/, which is the HAR replayed by tests/integration/alibaba-wan-i2v.test.ts.

import { readFileSync } from "node:fs";
import { createAlibaba, AlibabaError } from "@apicity/alibaba";
import type {
  AlibabaVideoSynthesisSubmitResponse,
  AlibabaTaskStatusResponse,
  AlibabaTaskStatus,
} from "@apicity/alibaba";

const alibaba = createAlibaba({
  apiKey: process.env.DASHSCOPE_API_KEY!,
  // The SUCCEEDED-path round-trip in the recording is ~47s wall-clock;
  // bump the per-request timeout above the default 30s so the submit
  // call doesn't fight a slow scheduling spike.
  timeout: 60_000,
});

// 1. Inline the source frame as a `data:` URL. DashScope also accepts
//    https:// URLs and `oss://` URIs (the latter only when the request
//    carries `X-DashScope-OssResourceResolve: enable`, which the
//    provider sets automatically on every aigc/* call). Inlining is the
//    zero-infra path — no public bucket, no presigned URL — at the cost
//    of paying the upload bytes once per submit.
const frame = readFileSync("./cat.jpg");
const dataUrl = `data:image/jpeg;base64,${frame.toString("base64")}`;

// 2. `media[].type: "first_frame"` is the I2V kick-off — Wan animates
//    forward from the still. Other media types in the same array slot
//    drive different conditioning modes: `last_frame` (animate
//    backward), `first_clip` (continue a video), `reference` (style
//    transfer). The Zod schema enforces that `first_frame` cannot
//    coexist with `first_clip` and that exactly one of each type is
//    present — invalid combinations fail at `.schema.safeParse(...)`
//    before a single byte hits the wire.
//
// 3. `prompt_extend: true` runs the prompt through DashScope's
//    server-side prompt-enhancement model first, which materially
//    improves motion fidelity on terse prompts like the one below.
//    The enhanced prompt is echoed back in the SUCCEEDED response as
//    `actual_prompt` so you can audit what actually got rendered.
//    `watermark: false` removes the corner badge — silently ignored
//    on tiers that don't permit it.
const submit: AlibabaVideoSynthesisSubmitResponse =
  await alibaba.post.api.v1.services.aigc.videoGeneration.videoSynthesis({
    model: "wan2.7-i2v",
    input: {
      prompt:
        "The odd-eyed white cat blinks slowly, whiskers twitching, " +
        "then turns its head toward the camera",
      media: [{ type: "first_frame", url: dataUrl }],
    },
    parameters: {
      resolution: "720P",
      duration: 5,
      prompt_extend: true,
      watermark: false,
    },
  });

console.log(
  `task=${submit.output.task_id} status=${submit.output.task_status}`,
);
// → "task=5a674d6b-6a42-4b07-98bb-147ba79879ea status=PENDING"

// 4. Poll until terminal. The status state machine is
//    PENDING → RUNNING → (SUCCEEDED | FAILED | CANCELED), with
//    SUSPENDED as a transient quota-bound retry state. Treat anything
//    not in TERMINAL as "keep polling." A 5–10s interval matches the
//    server-side scheduling cadence — the recorded run did 8 polls
//    over ~47s, so faster polling just burns rate-limit budget without
//    moving the task forward.
const TERMINAL: ReadonlyArray<AlibabaTaskStatus> = [
  "SUCCEEDED",
  "FAILED",
  "CANCELED",
];
let status: AlibabaTaskStatusResponse = await alibaba.get.api.v1.tasks(
  submit.output.task_id,
);
while (!TERMINAL.includes(status.output.task_status)) {
  await new Promise((r) => setTimeout(r, 5000));
  status = await alibaba.get.api.v1.tasks(submit.output.task_id);
}

// 5. The task-status response shape *grows* as the task progresses —
//    `submit_time` and `scheduled_time` appear once it leaves PENDING;
//    `end_time`, `orig_prompt`, `video_url`, and `usage` only land on
//    SUCCEEDED. `code` and `message` populate on FAILED. Always branch
//    on `task_status` before reading the success-only fields, since
//    they're typed `string | undefined`.
if (status.output.task_status !== "SUCCEEDED") {
  throw new AlibabaError(
    `i2v task ${status.output.task_id} ${status.output.task_status}: ` +
      `${status.output.code ?? "?"}: ${status.output.message ?? "?"}`,
    500,
    status.output,
    status.output.code,
  );
}

console.log(status.output.video_url);
// → "https://dashscope-a717.oss-accelerate.aliyuncs.com/.../70873660-metadata_user_a54afaea6b53dd4e.mp4?Expires=1776489167&..."

const elapsed =
  new Date(status.output.end_time!).getTime() -
  new Date(status.output.submit_time!).getTime();
console.log(
  `model=wan2.7-i2v ${status.usage!.SR}p×${status.usage!.output_video_duration}s ` +
    `elapsed=${(elapsed / 1000).toFixed(1)}s videos=${status.usage!.video_count}`,
);
// → "model=wan2.7-i2v 720p×5s elapsed=47.4s videos=1"

Notes

  • The returned video_url is a presigned OSS URL with a short Expires= window (≈1 hour in the recording above) — download or re-host it immediately, don't store the URL itself. The bucket is hosted on oss-accelerate.aliyuncs.com, which fronts an Alibaba CDN that resolves close to the caller; no auth header is required for the GET.
  • The submit call is cheap even when the task later FAILS — billing is only charged on SUCCEEDED tasks per usage.duration (seconds of output video). A failed content-safety screen (code: "DataInspectionFailed") on the input frame returns a SUCCEEDED-shape HTTP 200 with task_status: "FAILED", not a 4xx — this is why the example above always reads task_status rather than relying on exception flow for content-related rejects.
  • The same videoSynthesis endpoint dispatches across the entire Wan 2.7 family by changing model: wan2.7-i2v for image→video, wan2.7-t2v for text→video (drop the media array), and wan2.7-videoedit for video-style transfer (use media[].type: "video"). The Zod schema enforces the per-model media-type combinations — videoedit requires a video entry, i2v requires first_frame or first_clip, etc.
  • For payloads where the input frame exceeds DashScope's 10MB embedded-data-URL ceiling, swap the inline data: URL for an oss://{key} URI obtained via uploadFile(provider, {...}) — the exported helper does the getPolicy + multipart OSS PostObject dance and returns the URI ready to drop into media[].url. The X-DashScope-OssResourceResolve header is set automatically on every aigc/* call so the URI resolves server-side.
  • Errors throw AlibabaError with status and the parsed body. The native aigc error shape ({code, message, request_id}) is surfaced in error.code — wrap with withRetry from @apicity/alibaba for 429 / 503, but skip retries on code === "DataInspectionFailed" / "InvalidParameter" since those are deterministic rejects.

API Reference

7 endpoints across 4 groups. Each method mirrors an upstream URL path.

compatibleMode

GET alibaba.compatibleMode.v1.models

GET https://dashscope.aliyuncs.com/compatible-mode/v1/models

Cost tier: expensive

Upstream docs ↗

const res = await alibaba.get.compatibleMode.v1.models();

Source: packages/provider/alibaba/src/alibaba.ts

POST alibaba.compatibleMode.v1.chat.completions

POST https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions

Cost tier: expensive

Upstream docs ↗

const res = await alibaba.post.compatibleMode.v1.chat.completions({ /* ... */ });

Source: packages/provider/alibaba/src/alibaba.ts

services

POST alibaba.api.v1.services.aigc.imageGeneration.generation

POST https://dashscope.aliyuncs.com/api/v1/services/aigc/image-generation/generation

Cost tier: expensive

const res = await alibaba.post.api.v1.services.aigc.imageGeneration.generation({ /* ... */ });

Source: packages/provider/alibaba/src/alibaba.ts

POST alibaba.api.v1.services.aigc.multimodalGeneration.generation

POST https://dashscope.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation

Cost tier: expensive

Upstream docs ↗

const res = await alibaba.post.api.v1.services.aigc.multimodalGeneration.generation({ /* ... */ });

Source: packages/provider/alibaba/src/alibaba.ts

POST alibaba.api.v1.services.aigc.videoGeneration.videoSynthesis

POST https://dashscope.aliyuncs.com/api/v1/services/aigc/video-generation/video-synthesis

Cost tier: expensive

Upstream docs ↗

const res = await alibaba.post.api.v1.services.aigc.videoGeneration.videoSynthesis({ /* ... */ });

Source: packages/provider/alibaba/src/alibaba.ts

tasks

GET alibaba.api.v1.tasks

GET https://dashscope.aliyuncs.com/api/v1/tasks/{taskId}

Cost tier: expensive

Upstream docs ↗

const res = await alibaba.get.api.v1.tasks({ /* ... */ });

Source: packages/provider/alibaba/src/alibaba.ts

uploads

GET alibaba.api.v1.uploads

GET https://dashscope.aliyuncs.com/api/v1/uploads

Cost tier: expensive

Upstream docs ↗

const res = await alibaba.get.api.v1.uploads({ /* ... */ });

Source: packages/provider/alibaba/src/alibaba.ts

Middleware

import { createAlibaba, withRetry } from "@apicity/alibaba";

const alibaba = createAlibaba({ apiKey: process.env.ALIBABA_API_KEY! });
const getTask = withRetry(alibaba.get.api.v1.tasks, { retries: 3 });

Part of the apicity monorepo.

License

MIT — see LICENSE.

版本与发布记录

@apicity/alibaba 共发布 90 个版本,首次发布于 2026/05/10;过去 12 个月发布了 90 个版本。

版本发布日期距今
0.27.0latest2026/11/06今天
0.26.02026/11/051 天前
0.25.02026/11/033 天前
0.24.12026/11/024 天前
0.24.02026/11/014 天前
0.23.12026/11/015 天前

关于 @apicity/alibaba 的常见问题

@apicity/alibaba 是什么?

Alibaba Cloud Model Studio provider for chat completions, image generation, and streaming.

如何安装 @apicity/alibaba?

在项目目录运行 npm install @apicity/alibaba,或使用 pnpm add / yarn add / bun add。

@apicity/alibaba 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@apicity/alibaba 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@apicity/alibaba 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=18.0.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@apicity/alibaba 可以商用吗?

@apicity/alibaba 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@apicity/alibaba 的下载量有多少?

根据 npm 官方下载统计,@apicity/alibaba 在 2026/10/06 – 2026/11/04 这 30 天内被下载 4,277 次,日均约 143 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@apicity/alibaba 还在维护吗?

最新版本 0.27.0 发布于 2026/11/06(今天);至今共发布 90 个版本,其中过去 12 个月发布了 90 个;首次发布于 2026/05/10。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。