flowbar
v0.1.3
Published
A zero-dependency progress toolkit for modern Node.js workflows.
Maintainers
Readme
flowbar
flowbar is a progress toolkit for modern Node.js workflows. If Python has tqdm, flowbar aims to be the small Node.js toolkit you reach for when loops, async iterables, concurrent tasks, streams, or unknown-duration work need progress.
Remember this first
import { pipeline } from "node:stream/promises";
import flowbar, { each, stream, wait } from "flowbar";
for (const file of flowbar(files, { label: "files" })) {
await upload(file);
}
for await (const row of flowbar(readRows(), { label: "rows" })) {
await save(row);
}
await each(urls, async (url) => {
await fetch(url);
}, { label: "fetch", concurrency: 8 });
await pipeline(
input,
stream({ label: "copy", total: size, unit: "byte" }),
output,
);
const waiting = wait({ label: "connect", status: "waiting" });
await connect();
waiting.succeed("connected");The idea scales without changing tools: wrap an iterable, consume an async iterable, run bounded concurrency, track a byte stream, or show a wait state with one progress API.
The default export is only the iterable wrapper. Helper APIs are named exports, so a callable function no longer doubles as a namespace. configure(defaults) returns a non-callable client object with the same helper methods.
Node.js의 async iterable, promise concurrency, stream, indeterminate task까지 자연스럽게 다루는 zero-dependency progress toolkit입니다.
flowbar의 목표는 progress bar 객체를 복잡하게 조작하게 만드는 것이 아니라, 작업을 감싸면 진행 상태가 자연스럽게 드러나도록 하는 것입니다.
빠른 선택
- iterable을 감싸려면
flowbar(input, options) - 결과 배열이 필요하면 named export
map(input, mapper, options) - 결과 배열이 필요 없으면 named export
each(input, handler, options) - 수동으로 값과 상태를 제어하려면 named export
create(options) - total을 모르는 대기 작업은 named export
wait(options) - Node.js byte stream은 named export
stream(options)
특징
for ... of,for await ... of에서 바로 사용elapsed,remaining,rate기본 표시- 전체 수량이 없는 counting mode 지원
- 남은 시간을 알 수 없는 indeterminate mode 지원
- spinner, marquee, bounce, pulse 애니메이션 지원
- 터미널 창 크기 변경에 자동 대응
- 같은 줄 또는 같은 live region에서 갱신
console.log와 섞일 때를 위한 safe logging API 제공- Node.js stream byte progress 지원
- TypeScript declaration 내장
- runtime dependency 없음
- native addon, postinstall script 없음
- CI, pipe, non-TTY 환경에서는 plain log로 자동 전환
- LLM 친화 문서 제공:
llms.txt,llms-full.txt,docs/ - strict TypeScript source에서
dist와 declaration 생성
설치
npm install flowbar현재 저장소를 직접 검증하려면 다음 명령을 사용합니다.
npm run typecheck
npm run lint
npm run build
npm test
npm run test:pty
node --check dist/index.js
npm pack --dry-run기본 사용법
import flowbar from "flowbar";
const files = ["a.txt", "b.txt", "c.txt"];
for (const file of flowbar(files, { label: "files" })) {
await upload(file);
}AsyncIterable
import flowbar from "flowbar";
async function* createJobs() {
yield "job-a";
yield "job-b";
yield "job-c";
}
for await (const job of flowbar(createJobs(), { label: "jobs", total: 3 })) {
await runJob(job);
}Concurrency map
import { each, map } from "flowbar";
const results = await map(
files,
async (file) => {
return upload(file);
},
{
label: "upload",
concurrency: 8,
},
);결과 배열이 필요 없으면 each를 사용합니다.
await each(files, async (file) => {
await upload(file);
}, {
label: "upload",
concurrency: 8,
});수동 제어
import { create } from "flowbar";
const bar = create({ label: "manual", total: 100 });
bar.increment(10);
bar.setPostfix({ phase: "download" });
bar.increment(20);
bar.succeed("complete");Indeterminate mode
남은 시간을 알 수 없을 때는 fake ETA를 표시하지 않습니다. 대신 상태, elapsed, 애니메이션을 보여 줍니다.
import { wait } from "flowbar";
const waiting = wait({
label: "connect",
status: "waiting",
animation: "marquee",
});
await connectToServer();
waiting.succeed("connected");Stream byte progress
import { createReadStream, createWriteStream, statSync } from "node:fs";
import { pipeline } from "node:stream/promises";
import { stream } from "flowbar";
const input = "input.bin";
const output = "output.bin";
await pipeline(
createReadStream(input),
stream({
label: "copy",
total: statSync(input).size,
unit: "byte",
}),
createWriteStream(output),
);Safe logging
import { create } from "flowbar";
const bar = create({ label: "build", total: 3 });
bar.log("build started");
bar.increment();
bar.warn("slow test detected");
bar.increment();
bar.increment();
bar.succeed("done");Terminal rendering contract
flowbar는 TTY 환경에서 다음 동작을 기본으로 합니다.
- progress line을 터미널 폭보다 길게 출력하지 않습니다.
- 빠른 loop에서
interval기준으로 렌더링을 throttle합니다. - 터미널 창 크기가 바뀌면 자동으로 레이아웃을 다시 계산합니다.
- 업데이트마다 새 줄을 만들지 않고 같은 줄 또는 같은 live region을 갱신합니다.
- 완료, 실패, 취소 시에만 최종 줄을 남깁니다.
charset: "ascii"에서는 최종 상태 marker도 ASCII로 출력합니다.color: true를 주면 최종 상태 marker에 ANSI 색상을 적용합니다.- safe logging을 사용할 때는 live region을 보존하면서 로그를 출력합니다.
- non-TTY, CI, pipe 환경에서는 ANSI 제어 문자를 남기지 않는 plain renderer로 전환합니다.
Runtime contract
concurrency는 1부터 1024까지의 정수이며, 알려진 입력 크기보다 많은 worker를 만들지 않습니다.- handler의 네 번째 인자는 첫 실패나 caller abort를 알리는
AbortSignal입니다. 반환 promise는 이미 실행 중인 handler가 정리된 뒤 reject합니다. unit: "byte"는 문자열 chunk를 실제 encoding의 byte length로 계산합니다.objectMode: true의 기본 unit은"item"입니다.total,current,setTotal(total)은 음수를 허용하지 않습니다.setMode(mode)는"auto","determinate","counting","indeterminate"만 허용합니다.ProgressBar의 공개 상태 필드는 getter로 노출되며 직접 대입으로 변경하지 않습니다. 상태 변경은increment,update,setTotal,setStatus,setPostfix를 사용합니다.map/each처리 중 mapper 또는 handler가 실패하면 bar는 failure 상태가 되고 async iterator cleanup을 위해return()을 호출합니다.each는 대량 작업에서 불필요한 결과 배열을 만들지 않습니다.- JSON renderer도
interval을 적용하며, snapshot은 output/signal/callback을 제외한 깊은 읽기 전용 데이터입니다.
문서
LLM과 사람이 빠르게 읽기 위한 문서는 다음 순서로 보면 됩니다.
docs/index.mddocs/llm-guide.mddocs/quickstart.mddocs/api/flowbar.mddocs/api/create.mddocs/api/map.mddocs/api/stream.mddocs/api/wait.mddocs/api/group.mddocs/api/task.mddocs/api/types.mddocs/terminal-behavior.mddocs/terminal-reliability.mddocs/recipes.mddocs/comparison.mddocs/release.mdCHANGELOG.md
전체 문서는 docs/full.md에 있습니다.
LLM용 요약 색인은 llms.txt, 전체 LLM 문서는 llms-full.txt에 있습니다.
라이선스
MIT
