@creativekit/server

中文文档
1.1.0发布于 2026/10/21MITTypeScriptESM + CJS零依赖近 30 天下载 3573

服务器端 CreativeKit SDK 有 OAuth 认证

中文使用文档
文档目录29 节
  1. 快速启动
  2. API 参考
  3. 创意
  4. Auth (密钥生成)
  5. 简介
  6. 套装
  7. 卫生
  8. 用户
  9. 调试
  10. 终到终流
  11. 方法-终点参考
  12. 1. 浏览器上传(建议)
  13. 2. 服务器端完整上传(文字、工人、队列)
  14. 3. 木马(动力槽)
  15. 4. 编辑已有的创意( 重新打开 替换)
  16. 4b. "Edit" 已定稿的创意(clone ~ 更改子集 ~ 已定稿)
  17. 5. 上载前验证(失效,无上载)
  18. 6. 取消、重试、删除、列表
  19. SSE 事件代理服务器
  20. 补全 Webhooks
  21. 最终确定工作流程(草案-永久)
  22. 预览 URL
  23. 处理失败的创意
  24. 校验错误
  25. 管道错误
  26. 快速端点示例
  27. 完整文档
  28. 警卫
  29. 许可证

@ creativekit/ 服务器

OAuth2 认证的服务器端 CreativeKit SDK

⚠️ 只有节点.js - 从不暴露在浏览器中


快速启动

npm install @creativekit/server
import { CreativeKitServer } from "@creativekit/server";

const ck = new CreativeKitServer({
  apiBase: "https://api.adswag.nl",
  clientId: process.env.CREATIVEKIT_CLIENT_ID!,
  clientSecret: process.env.CREATIVEKIT_CLIENT_SECRET!,
});

// Create creative with presigned upload URL (AWS-style)
const creative = await ck.creatives.create("audio:podcast-aac");

// Return to frontend (client uploads directly to presigned URL)
// IMPORTANT: After upload, client must call commit to start processing
res.json({
  creativeId: creative.id,
  uploadUrl: creative.uploadSlots?.[0]?.url,
  uploadHeaders: creative.uploadSlots?.[0]?.headers,
});

// Commit endpoint - triggers processing
await ck.creatives.commit(creative.id);

API 参考

创意

// Create creative + get presigned URL (AWS-style)
const creative = await ck.creatives.create(profile, options);
// Options:
//   multipart?: boolean     - Use multipart upload for large files
//   fileSize?: number       - File size (required for multipart)
//   metadata?: object       - Custom metadata to attach
//   autoFinalize?: boolean  - Auto-finalize when processing succeeds (skip draft workflow)

// Commit after upload (starts processing)
await ck.creatives.commit(id);

// Or fill the draft from an https link instead of uploading (scope creative:ingest).
// CreativeKit downloads the file server-side, then continues as if commit() ran.
const status = await ck.creatives.ingest(id, {
  sourceUrl: "https://assets.example.com/spot-30s.mp4",
  // slot?: "video"          - optional when the profile has one required slot
  // idempotencyKey?: string
});
// status.status === "QUEUED"; status.source.status === "PENDING"
// On a failed download the creative ends FAILED; failure names step "source_fetch"
// and status.source.cause gives the reason (HTTP_STATUS, TOO_LARGE, ...).

// Get creative status and artifacts
const creative = await ck.creatives.get(id);
// Status values: "AWAITING_UPLOAD" | "QUEUED" | "PROCESSING" | "SUCCEEDED" | "FAILED" | "CANCELED"
// AWAITING_UPLOAD = created with directUpload, waiting for file upload + commit
// Progress is 0.0-1.0 (multiply by 100 for percentage)

// List creatives with filtering
const list = await ck.creatives.list({ status: "SUCCEEDED", limit: 20 });
// Options: status?, profile?, finalized?, limit?, pageToken?

// Finalize (mark as permanent, prevent auto-cleanup)
await ck.creatives.finalize(id);

// Generate preview URL for completed creative
const preview = await ck.creatives.preview(id);
// Returns: { url: string, expiresAt: number }

// Management
await ck.creatives.delete(id);
await ck.creatives.cancel(id);
await ck.creatives.retry(id);

// Edit a draft: reopen one slot → (client uploads) → replace to reprocess
const { uploadSlots } = await ck.creatives.reopenSlot(id, "frame_2");
await ck.creatives.replaceSlot({ id, slot: "frame_2" }); // file already re-uploaded
// …or do the whole thing server-side in one call (reopen + upload + reprocess):
await ck.creatives.replaceSlot({ id, slot: "frame_2", file: newImage });

// Edit a FINALIZED creative: clone into a fresh draft, change a subset of
// slots, then commit + finalize (the original is never modified).
const draft = await ck.creatives.clone(finalizedId); // copies all raw uploads
// draft.uploadSlots covers every slot; PUT new files only for the changed ones
await ck.creatives.commit(draft.id);
await ck.creatives.finalize(draft.id);

// Server-side upload (Node.js scripts/workers); supports slotCounts + slotTransforms
const result = await ck.creatives.upload({ profile, files });

// SSE proxy to frontend (recommended)
await ck.creatives.getEventsStream(id, res);

编辑只是草稿 . reopenSlot编号 :replaceSlot 需要创造力 SUCCEEDED 或者说 FAILED 财务报告和审定财务报表 未定稿. 后处理总是从原生上传出再运行,所以没有世代质量损失. 见 终到终流。 。 。 .

Auth (密钥生成)

在不暴露客户秘密的情况下, 生成用于客户端的短寿命符号 :

// Generate a scoped access token
const tokenData = await ck.auth.generateToken("creative:create creative:read creative:commit");

// Return to frontend
res.json({
  token: tokenData.accessToken,
  expiresIn: tokenData.expiresIn, // seconds
});

简介

// List available processing profiles
const profiles = await ck.profiles.list();
// Returns: Profile[] with id, type, description, etc.

// Pre-validate declared file metadata against a profile WITHOUT uploading.
// Advisory pre-flight check — the authoritative validation still runs on the
// real bytes after upload. Returns the same { errors, warnings } shapes the
// processing pipeline emits, namespaced per slot (e.g. "standard.aspectRatio").
const result = await ck.profiles.validateMetadata("native:image", {
  slots: {
    standard: {
      filename: "banner.png",
      mimeType: "image/png",
      sizeBytes: 1_048_576,
      width: 1200,
      height: 628,
    },
  },
});
// Returns: { passed: boolean, errors: ValidationError[], warnings?: ValidationWarning[] }

// For dynamic-slot profiles (e.g. native:carousel), pass slotCounts so per-frame
// slots (frame_1..frame_N) and slot-group rules resolve:
await ck.profiles.validateMetadata("native:carousel", {
  slotCounts: { frame: 4 },
  slots: { frame_1: { width: 1080, height: 1080, sizeBytes: 500_000 } },
});

套装

Bundles集团相关配置文件一起销售(例如: native 广告包 : standard + 键 large) (中文(简体) ).

// List all bundles. Pass { expandProfiles: true } to inline each member's
// full profile spec (upload slots + validation rules) in one request.
const bundles = await ck.profiles.listBundles({ expandProfiles: true });

// Get a single bundle by id (throws ApiError with status 404 if missing)
const bundle = await ck.profiles.getBundle("native:standard", {
  expandProfiles: true,
});

卫生

// Comprehensive health check (API + credentials)
const health = await ck.health.check();
// Returns: { isHealthy, apiReachable, credentialsValid, details }

// Basic connectivity test
const reachable = await ck.health.ping();
// Returns: boolean

// Validate OAuth credentials
const validation = await ck.health.validateCredentials();
// Returns: { valid: boolean, error?: string }

用户

// Check if client has valid credentials configured
const authenticated = ck.utils.isAuthenticated();

// Get current API configuration
const config = ck.utils.getConfig();
// Returns: { apiBase, hasCredentials }

// Get last known connection status
const status = ck.utils.getConnectionStatus();

调试

诊断认证问题的解决问题的方法:

// Validate credentials with detailed error info
const result = await ck.debug.validateCredentials();
// Returns: { valid, error?, details? }

// Test API connection with diagnostics
const conn = await ck.debug.testConnection();
// Returns: { apiReachable, credentialsValid, responseTime?, error?, details? }

// Get current token information
const tokenInfo = await ck.debug.getTokenInfo();
// Returns: { hasCredentials, tokenCached, tokenExpiry?, error? }

终到终流

下方的每道流可复制-可复制. 它们涵盖整个创造性生命周期: 创建 /上传 / 承诺 / 监视 / 预览 / 定稿附加时 编辑 (重新开放/更换), 多相相/相机, (中文(简体) ), 预加载验证,以及 取消/重试/删除。 。 。 .

方法-终点参考

SDK 方法REST 终点
ck.creatives.create(profile, opts)POST /v1/creatives
ck.creatives.commit(id, body?)POST /v1/creatives/{id}/commit
ck.creatives.ingest(id, opts)POST /v1/creatives/{id}/ingest
ck.creatives.upload(params)创建 + PUT + 承诺(服务器侧方便)
ck.creatives.get(id)GET /v1/creatives/{id}
ck.creatives.list(opts)GET /v1/creatives
ck.creatives.cancel(id) 编号 : retry(id)PATCH /v1/creatives/{id}
ck.creatives.delete(id)DELETE /v1/creatives/{id}
ck.creatives.reopenSlot(id, slot)POST /v1/creatives/{id}/slots/{slot}/reopen
ck.creatives.replaceSlot(params)POST /v1/creatives/{id}/slots/{slot}/replace
ck.creatives.preview(id)POST /v1/creatives/{id}/preview
ck.creatives.finalize(id)POST /v1/creatives/{id}/finalize
ck.creatives.clone(id)POST /v1/creatives/{id}/clone
ck.creatives.getEventsStream(id, res)GET /v1/creatives/{id}/events (SSE) (英语)
ck.profiles.list(opts?)GET /v1/profiles
ck.profiles.validateMetadata(id, body)POST /v1/profiles/{id}/validate
ck.profiles.listBundles(opts?)GET /v1/bundles
ck.profiles.getBundle(id, opts?)GET /v1/bundles/{id}
ck.auth.generateToken(scopes)POST /oauth/token

浏览器通过预先签名的 URL 直接上传到存储; 您的后端 发布 URL 和 代理 生命周期 调用 。 用这个 @creativekit/client。 。 。 .

后端( Express) — 薄的代理 :

// Create + return presigned upload slot(s)
app.post("/api/creatives", async (req, res) => {
  const { profile, slotCounts } = req.body;
  const creative = await ck.creatives.create(profile, { slotCounts });
  res.json({ creativeId: creative.id, uploadSlots: creative.uploadSlots });
});

// Commit to start processing (optionally pass slotTransforms for crops)
app.post("/api/creatives/:id/commit", async (req, res) => {
  await ck.creatives.commit(req.params.id, { slotTransforms: req.body?.slotTransforms });
  res.status(204).send();
});

// Status + live events + finalize
app.get("/api/creatives/:id", async (req, res) => res.json(await ck.creatives.get(req.params.id)));
app.get("/api/creatives/:id/events", (req, res) => ck.creatives.getEventsStream(req.params.id, res, { corsOrigin: req.headers.origin }));
app.post("/api/creatives/:id/finalize", async (req, res) => { await ck.creatives.finalize(req.params.id); res.status(204).send(); });

浏览器侧( O)client.upload(...), (中文(简体) ), client.streamEvents(...)) 位于 @ creativekit/ 客户端 README。 。 。 .

2. 服务器端完整上传(文字、工人、队列)

ck.creatives.upload() 正在创建 ^ PUT 每个文件 ^ 承诺 ^ 等待,全部在 节点. 过 slotCounts 动态剖面图和 slotTransforms 用于农作物.

import { readFile } from "node:fs/promises";

// Single-file profile
const audio = await ck.creatives.upload({
  profile: "audio:podcast-aac",
  files: { audio: new File([await readFile("ep.mp3")], "ep.mp3", { type: "audio/mpeg" }) },
  // `progress` (0-100) is the canonical progress field across CreativeKit
  // SDKs (the client SDK's `percent` is a deprecated alias of it).
  onProgress: (p) => console.log(`${p.stage} ${p.progress}%`),
});

// Native ad pack (multi-slot): "standard" + "large" are sold as one bundle.
// Each slot is a separate file; optionally crop each to its target.
const native = await ck.creatives.upload({
  profile: "native:image",
  files: { standard: standardFile, large: largeFile },
  slotTransforms: {
    // crop rect is in SOURCE pixels; target is the output resolution after crop+scale
    standard: { aspectRatio: "1.91:1", cropX: 0, cropY: 0, cropW: 1200, cropH: 628, targetWidth: 1200, targetHeight: 628 },
  },
});

if (native.status === "SUCCEEDED") console.log(native.artifacts);

木马宣布 frame 模板插槽. slotCounts: { frame: N } 扩展它 输入 frame_1 … frame_N上传或预先签名 浏览器上传( 通过) slotCounts 改为 create) (中文(简体) ).

const carousel = await ck.creatives.upload({
  profile: "native:carousel",
  slotCounts: { frame: 4 },
  files: { frame_1: f1, frame_2: f2, frame_3: f3, frame_4: f4 },
});

修改一个框架后将整个管道重新运行(所有框架从 他们的生上传。 参见流量 4.

4. 编辑已有的创意( 重新打开 替换)

交换一个空档/空档 草案 (未定稿) 重新创造它。 创造力必须是 SUCCEEDED 或者说 FAILED,另一个 插槽的生上传必须仍然在TTL草稿内.

选项A——完全服务器侧(一个呼叫):

const updated = await ck.creatives.replaceSlot({
  id: creativeId,
  slot: "frame_2",
  file: newFrameFile,           // reopen + upload + reprocess + wait
  slotTransform: { aspectRatio: "1:1", cropX: 0, cropY: 0, cropW: 1080, cropH: 1080, targetWidth: 1080, targetHeight: 1080 }, // optional
});

选项B——浏览器驱动(已签名) :

// 1) Backend reopens the slot and returns fresh presigned URLs
app.post("/api/creatives/:id/slots/:slot/reopen", async (req, res) => {
  const { uploadSlots } = await ck.creatives.reopenSlot(req.params.id, req.params.slot);
  res.json({ uploadSlots });
});

// 2) Browser PUTs the new file to that URL (client.replaceSlot handles this)

// 3) Backend triggers reprocessing (no file arg → just reprocess)
app.post("/api/creatives/:id/slots/:slot/replace", async (req, res) => {
  await ck.creatives.replaceSlot({
    id: req.params.id,
    slot: req.params.slot,
    slotTransform: req.body?.slotTransform, // optional crop from the browser
  });
  res.status(204).send();
});

什么可以编辑? 只有插槽 目录 草稿(重新装入文件至 (a) 插槽) 配置/类型在创建时间被固定 。 一次 finalized,一个创造性是 不可改变, 克隆 (流程4b)。 公开 GET /c/{id}/{filename} 只服务于最终的创意, 所以活资产永远不会改变 在观看器下面.

4b. "Edit" 已定稿的创意(clone ~ 更改子集 ~ 已定稿)

最终的创意是不可改变的,所以编辑一个意味着产生一个 新设 创意. clone 使这个便宜:它把源头复制成新的草稿 (新身份证, AWAITING_UPLOAD和 服务器侧复制每个原始上传,所以请 没有改变的插槽不需要重新加载, 并且从原位置进行无损失的再处理 来源. 只更改您想要的槽, 然后承诺 + 完成 .

// 1) Clone the finalized creative → new draft seeded with all original frames
app.post("/api/creatives/:id/clone", async (req, res) => {
  const draft = await ck.creatives.clone(req.params.id);
  // draft.uploadSlots covers EVERY slot (e.g. frame_1..frame_8)
  res.status(201).json({ id: draft.id, uploadSlots: draft.uploadSlots });
});

// 2) Browser PUTs new files ONLY for the changed slots (e.g. 4 of 8 frames)
//    to their presigned URLs. The other slots keep the copied raw uploads.

// 3) Commit reprocesses all slots from raw (one clean pass), then finalize.
await ck.creatives.commit(draftId);
await ck.creatives.finalize(draftId);
// Result: a brand-new finalized creative (new ID/URL). The original is untouched;
// the platform should swap its reference to the new creative.

删除或重排自動滑行( 不仅仅是互换文件内容), pass slotPlan 复制时:

// 5-frame source → 3-frame draft (drops frame_2 and frame_4)
const draft = await ck.creatives.clone(finalizedId, {
  slotPlan: { frame: ["frame_1", "frame_3", "frame_5"] },
});
// draft.uploadSlots = frame_1..frame_3, seeded from source frame_1, frame_3, frame_5

克隆人依赖源头仍然有生上传(最终的创意) (续) 如果他们走了, clone 返回 409 ——创建新的创意 换句话说.

5. 上载前验证(失效,无上载)

根据配置文件的规则检查已申报的元数据 在此之前 推动字节. 仅咨询——权威检查仍在实际字节执行时运行.

const check = await ck.profiles.validateMetadata("native:image", {
  slots: { standard: { mimeType: "image/png", sizeBytes: 1_048_576, width: 1200, height: 628 } },
});

if (!check.passed) {
  // surface check.errors to the user and skip the upload
  return res.status(422).json({ errors: check.errors, warnings: check.warnings });
}
// else proceed with create/upload

6. 取消、重试、删除、列表

await ck.creatives.cancel(id);        // stop in-flight processing
await ck.creatives.retry(id);         // retry a FAILED creative
await ck.creatives.delete(id);        // remove a creative + its artifacts

// Paginate finalized creatives for a profile
let pageToken: string | undefined;
do {
  const page = await ck.creatives.list({ profile: "native:image", finalized: true, limit: 50, pageToken });
  page.items.forEach((c) => console.log(c.id, c.status));
  pageToken = page.nextPageToken;
} while (pageToken);

SSE 事件代理服务器

代理实时处理事件到您的前端, 使用单个方法调用 :

// NestJS
@Get(':id/events')
async streamEvents(@Param('id') id: string, @Res() res: Response) {
  await ck.creatives.getEventsStream(id, res);
}

// Express
app.get('/creatives/:id/events', async (req, res) => {
  await ck.creatives.getEventsStream(req.params.id, res);
});

SDK的手柄:

  • SSE 标题( Content- Type, 快取控制, 连接)
  • * 终端状态检测(自动关闭SUCCEED、故障、CANCED)
  • QQ 自动整流
  • QQ 客户端断开处理
  • QQ CORS 信头( 可选)

在CORS的支持和回调下:

await ck.creatives.getEventsStream(id, res, {
  corsOrigin: req.headers.origin,
  onComplete: (status) => console.log(`Creative ${id}: ${status}`),
  onError: (error) => console.error(`Stream error: ${error.message}`),
});

说明: SSE事件是最小信号(id, (中文(简体) ), status, (中文(简体) ), progress) (中文(简体) ). 客户端应该打电话 GET /creatives/:id 关于终点站的详情.


补全 Webhooks

而不是投票或SSE,在创建时注册一个网页。 后端 邮递到您的 callbackUrl 当创意达到终端状态时 (单位:千美元)SUCCEEDED 编号 : FAILED 编号 : CANCELED),与您签名 callbackSecret。 。 。 .

const creative = await ck.creatives.create("video:web-1080p-h264", {
  callbackUrl: "https://your-backend.example.com/webhooks/creativekit",
  callbackSecret: process.env.CREATIVEKIT_WEBHOOK_SECRET!, // required with callbackUrl
});

callbackSecret 实值 所需经费 任何时候 callbackUrl 设置—— API 拒绝未签名的webhook注册(400).

接收网点 - 核实 X-CreativeKit-Signature 标题 (hex HMAC-SHA256 over the bird body) 与SDK帮助者:

import express from "express";
import { parseWebhookEvent, WEBHOOK_SIGNATURE_HEADER } from "@creativekit/server";

// Use a raw body parser: the signature covers the exact bytes received.
app.post(
  "/webhooks/creativekit",
  express.raw({ type: "application/json" }),
  async (req, res) => {
    let event;
    try {
      event = parseWebhookEvent(req.body, {
        secret: process.env.CREATIVEKIT_WEBHOOK_SECRET!,
        signature: req.header(WEBHOOK_SIGNATURE_HEADER),
      });
    } catch {
      return res.sendStatus(401);
    }

    // Delivery is at-least-once — dedupe on event.eventId.
    // The payload is minimal ({ eventId, id, status, error }); on SUCCEEDED,
    // fetch the creative for artifacts and CDN URLs:
    if (event.status === "SUCCEEDED") {
      const creative = await ck.creatives.get(event.id);
      // ...store creative.artifacts...
    }

    res.sendStatus(204);
  }
);

verifyWebhookSignature(secret, rawBody, signature) 也导出 只想要布尔检查。 交付以指数回转 (~10个尝试)在5xx/网络错误上;2xx和4xx都算已交付,所以 将终端状态与 GET /v1/creatives/{id} 作为后退.


最终确定工作流程(草案-永久)

已处理的创意开始为"草稿",可以预览,但在草稿TTL过期后会自动被清理(默认:24h). 为了永久保持创造性:

// After user reviews the preview and confirms
await ck.creatives.finalize(creativeId);

// Check finalization status
const creative = await ck.creatives.get(creativeId);
console.log(creative.finalized); // true
console.log(creative.finalizedAt); // timestamp in ms

为什么要最后决定?

  • 成本控制: 仅用于确认的创意的存储费用
  • 用户确认: 让用户在承诺前预览
  • 《同上》: 安全呼叫多次

通过自动定稿跳过工作流程草稿 :

如果您不需要用户预览确认, 请自定义成功 :

const creative = await ck.creatives.create("video:web-1080p-h264", {
  autoFinalize: true, // Automatically finalized when processing succeeds
});

表示端点示例 :

app.post("/creatives/:id/finalize", async (req, res) => {
  await ck.creatives.finalize(req.params.id);
  res.status(204).send();
});

预览 URL

生成已完成的创建的签名预览 URL :

// Get a signed preview URL (expires after a period)
const { url, expiresAt } = await ck.creatives.preview(creativeId);

// Return to frontend for display
res.json({ previewUrl: url, expiresAt });

表示端点示例 :

// Note: The SDK uses POST internally to generate the preview URL
app.post("/creatives/:id/preview", async (req, res) => {
  const preview = await ck.creatives.preview(req.params.id);
  res.json(preview);
});

处理失败的创意

当创作失败时, 请检查两者 results.validation (用于验证错误)和 failure (用于管道错误):

校验错误

详细校验错误在 results.validation.errors数字 :

const creative = await ck.creatives.get(id);

if (creative.status === "FAILED" && creative.results?.validation) {
  console.log("Validation failed:");
  for (const error of creative.results.validation.errors) {
    console.log(`  ${error.field}: ${error.message}`);
    console.log(`    Expected: ${error.expected}, Got: ${error.actual}`);
    console.log(`    Code: ${error.code}`);
  }
}

校验出错字段 :

外地说明
field失败的财产(例如, aspectRatio, (中文(简体) ), duration(中文(简体) )
rule违反验证规则(例如:, allowedValues, (中文(简体) ), range(中文(简体) )
expected剖面图需要什么
actual在上传文件中发现了什么
code机器可读错误代码
message可读错误信息
profileHint概况限制的参考

管道错误

对于无法恢复的错误( 译码失败等) , 请检查 failure数字 :

if (creative.status === "FAILED" && creative.failure) {
  console.log(`Pipeline failed at step: ${creative.failure.step}`);
  console.log(`Error: ${creative.failure.message}`);
  console.log(`Retriable: ${creative.failure.retriable}`);
}

快速端点示例

app.get("/api/creatives/:id", async (req, res) => {
  const creative = await ck.creatives.get(req.params.id);

  // Return validation errors in a client-friendly format
  if (creative.status === "FAILED") {
    const validationErrors = creative.results?.validation?.errors || [];
    const pipelineError = creative.failure;

    return res.json({
      ...creative,
      // Flatten for easier client consumption
      errorSummary: validationErrors.length
        ? validationErrors.map((e) => e.message).join("; ")
        : pipelineError?.message || "Unknown error",
    });
  }

  res.json(creative);
});

完整文档

参见 SDK 主要文档 用于:

  • 完整 API 参考
  • 建筑格局
  • 完整实例( Express, Next.js, NestJS)
  • 安保最佳做法
  • 解决问题

警卫

  • 使用环境变量获取证书
  • QQ 从不向浏览器曝光此 SDK
  • 保留 clientSecret 安全
  • 在您的后端添加认证的中间软件

许可证

麻省理工学院

版本与发布记录

@creativekit/server 共发布 40 个版本,首次发布于 2025/11/12;过去 12 个月发布了 40 个版本。

版本发布日期距今
1.1.0latest2026/10/2120 天前
1.0.422026/08/112 个月前
1.0.412026/07/153 个月前
1.0.402026/07/034 个月前
1.0.392026/07/034 个月前
1.0.382026/06/304 个月前

关于 @creativekit/server 的常见问题

@creativekit/server 是什么?

服务器端 CreativeKit SDK 有 OAuth 认证

如何安装 @creativekit/server?

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

@creativekit/server 支持 TypeScript 吗?

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

@creativekit/server 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@creativekit/server 需要什么版本的 Node.js?

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

@creativekit/server 可以商用吗?

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

@creativekit/server 的下载量有多少?

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

@creativekit/server 还在维护吗?

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