Node.js에서 스템 분리.
AI Stem Splitter용 typed Node 및 TypeScript client입니다. npm 또는 JSR에서 설치하고, Node, Bun, Deno에서 실행하며, 실제로 동작하는 스템 분리 기능을 문자 그대로 12줄 스크립트로 출시하세요. 트랙을 제출하고, 준비될 때까지 폴링한 뒤, 다음 standup demo 전에 4개 스템을 디스크에 저장합니다.
설치
인증
developer settings에서 키를 생성하고, 환경 변수 AISTEMSPLITTER_API_KEY로 넣은 뒤 client constructor에 전달하세요. SDK는 키를 절대 로그로 남기지 않으며, 이 페이지는 tooltips에 공개해도 안전한 ast_live_ 접두사 이상을 렌더링하지 않습니다.
import { AiStemSplitter } from "@aistemsplitter/sdk";
const client = new AiStemSplitter({
apiKey: process.env.AISTEMSPLITTER_API_KEY!,
});Hello world
12줄, end-to-end. 트랙을 제출하고 htdemucs_ft 모델이 완료될 때까지 기다린 다음 vocals, drums, bass, other 네 개 스템을 디스크에 씁니다. 이 코드를 단일 .mjs 파일에 붙여 넣고, 키를 설정한 뒤, standup demo 전에 실행하세요.
import { AiStemSplitter } from "@aistemsplitter/sdk";
import { writeFile } from "node:fs/promises";
const client = new AiStemSplitter({
apiKey: process.env.AISTEMSPLITTER_API_KEY!,
});
// 1. Submit a split job
const job = await client.createSplit({
input: { type: "direct_url", url: "https://example.com/song.mp3" },
stemModel: "htdemucs_ft",
});
// 2. Wait until completion (polls under the hood)
const result = await client.waitForSplit(job.id);
// 3. Download all six stems
for (const [name, url] of Object.entries(result.stems)) {
const audio = await fetch(url).then((r) => r.arrayBuffer());
await writeFile(`./${name}.wav`, Buffer.from(audio));
}메서드
6개의 typed methods가 전체 job lifecycle을 다룹니다. 각각은 게시된 패키지의 실제 TypeScript signature입니다. 에디터에서 자동완성되고, fetch wrappers를 직접 쓰거나 schema를 외울 필요가 없습니다.
새 split job을 제출하고 job id와 queued status를 반환합니다.
split job의 현재 status를 가져옵니다.
job이 성공, 실패하거나 timeout이 지날 때까지 폴링합니다.
API 키의 최근 split jobs를 paginated list로 반환합니다.
직접 browser/server uploads를 위한 pre-signed PUT URL을 받습니다.
수신 webhook payload의 HMAC-SHA256 signature를 검증합니다.
Webhooks
폴링은 demo까지 충분합니다. Webhooks는 production으로 가는 길입니다. signed callback URL을 createSplit에 넣고, 기존 Express 또는 Hono handler에서 한 번의 SDK 호출로 HMAC-SHA256 signature를 검증하세요.
import { AiStemSplitter } from "@aistemsplitter/sdk";
import { Hono } from "hono";
const app = new Hono();
const client = new AiStemSplitter({
apiKey: process.env.AISTEMSPLITTER_API_KEY!,
});
app.post("/webhooks/aistemsplitter", async (c) => {
const raw = await c.req.text();
const event = client.verifyWebhook(c.req.header(), raw); // throws if invalid
switch (event.type) {
case "split.succeeded":
// event.data.stems → six URLs
break;
case "split.failed":
// event.data.error → { code, message }
break;
}
return c.text("ok");
});FAQ
Does @aistemsplitter/sdk work in Bun and Deno without polyfills?
Yes. The package is dual-published to npm and JSR, so Bun installs via `bun add jsr:@aistemsplitter/sdk` and Deno via `deno add jsr:@aistemsplitter/sdk`. There are no @types/node polyfills, no Buffer shimming required, and no node:fs imports in the client core — the typed surface uses the Web Fetch + Web Streams APIs, which Node 18+, Bun, and Deno all implement natively.
How do I verify webhook signatures in Express, Hono, or Next.js?
Call ast.verifyWebhook({ headers, body }) — it computes the HMAC-SHA256 over the raw body, constant-time-compares against the aistemsplitter-signature header, and throws on tamper. The Webhooks section above shows runnable Express and Hono handlers; for Next.js App Router, use the Hono pattern in a route.ts handler with `await request.text()` to read the raw body before verification.
Is the TypeScript surface real, or `any` everywhere?
Real. Every method on AistemsplitterClient has a typed input + Promise return: createSplit(input: CreateSplitInput) → Promise<Split>, getSplit(id: string) → Promise<Split>, waitForSplit, listSplits, presignUpload, verifyWebhook. The Split + Stem + WebhookEvent types are exported from the package root, so you can import them into your own handlers and storage layer without re-deriving the shape.
How do I handle errors and retries from the SDK?
All methods throw typed errors: AistemsplitterApiError (4xx/5xx with code + message + requestId), AistemsplitterRateLimitError (429 with retryAfter seconds), AistemsplitterNetworkError (transport-level). waitForSplit retries polls automatically with exponential backoff until the SDK timeout (default 5 min) — wrap createSplit / presignUpload in your own retry helper if you need at-least-once submission semantics.
Can I run this in the browser?
No — the SDK is a server-side client. Browser use would expose your API key (any code that reaches the user's machine can read it) and run into CORS on the upload endpoints. Mint a short-lived signed URL on your server with presignUpload and hand only that URL to the browser; do the actual createSplit + waitForSplit calls from a server route, n8n workflow, or background worker.
@aistemsplitter/sdk는 polyfills 없이 Bun과 Deno에서 동작하나요?
네. 패키지는 npm과 JSR에 dual-published되어 있으므로 Bun은 `bun add jsr:@aistemsplitter/sdk`, Deno는 `deno add jsr:@aistemsplitter/sdk`로 설치합니다. @types/node polyfills도, Buffer shimming도 필요 없고, client core에는 node:fs imports가 없습니다. typed surface는 Node 18+, Bun, Deno가 모두 native로 구현하는 Web Fetch + Web Streams APIs를 사용합니다.
Express, Hono, Next.js에서 webhook signatures를 어떻게 검증하나요?
ast.verifyWebhook({ headers, body })를 호출하세요. raw body에 대해 HMAC-SHA256을 계산하고, aistemsplitter-signature header와 constant-time 비교한 뒤, tamper가 있으면 throw합니다. 위 Webhooks 섹션에는 실행 가능한 Express와 Hono handlers가 있습니다. Next.js App Router에서는 route.ts handler에서 Hono 패턴을 사용하고, 검증 전에 `await request.text()`로 raw body를 읽으세요.
TypeScript surface가 실제인가요, 아니면 모든 곳이 `any`인가요?
실제입니다. AistemsplitterClient의 모든 메서드는 typed input + Promise return을 갖습니다: createSplit(input: CreateSplitInput) → Promise<Split>, getSplit(id: string) → Promise<Split>, waitForSplit, listSplits, presignUpload, verifyWebhook. Split + Stem + WebhookEvent types는 package root에서 export되므로, shape를 다시 만들지 않고도 자체 handlers와 storage layer로 가져올 수 있습니다.
SDK의 errors와 retries는 어떻게 처리하나요?
모든 메서드는 typed errors를 throw합니다: AistemsplitterApiError(4xx/5xx with code + message + requestId), AistemsplitterRateLimitError(429 with retryAfter seconds), AistemsplitterNetworkError(transport-level). waitForSplit은 SDK timeout(기본 5분)까지 exponential backoff로 polls를 자동 재시도합니다. at-least-once submission semantics가 필요하면 createSplit / presignUpload을 자체 retry helper로 감싸세요.
브라우저에서 실행할 수 있나요?
아니요. SDK는 server-side client입니다. 브라우저에서 사용하면 API 키가 노출되고(사용자 기기에 도달하는 코드는 누구나 읽을 수 있음) upload endpoints에서 CORS 문제가 생깁니다. 서버에서 presignUpload으로 short-lived signed URL을 발급하고 브라우저에는 그 URL만 넘기세요. 실제 createSplit + waitForSplit 호출은 server route, n8n workflow, background worker에서 실행하세요.