製作者的介紹僅有上面的一句話。 更多詳情請閱讀儲存庫 README。 儲存庫 README ↗
正在載入完整 README。
檢視完整 README ↗Web-standard building blocks for any JavaScript runtime.
The web's missing standard library: fast, lightweight, composable packages, so you can write your code once and run it in browsers, Cloudflare Workers, Node 24+, Bun, and Deno.
Save a streamed OpenAI chat completion to a file as JSON Lines:
import * as Jsonl from '@portable/jsonl';
import * as Sse from '@portable/sse';
import * as Streams from '@portable/streams';
const response = await fetch('https://api.openai.com/v1/chat/completions', {
method: 'POST',
headers: { authorization: `Bearer ${apiKey}`, 'content-type': 'application/json' },
body: JSON.stringify({ model, messages, stream: true }),
});
// `transcript` is a WritableStream<Uint8Array> that writes to a file.
await response.body!
.pipeThrough(new Sse.DecoderStream())
.pipeThrough(Streams.filter((event) => event.data !== '[DONE]'))
.pipeThrough(Streams.map((event) => JSON.parse(event.data)))
.pipeThrough(new Jsonl.EncoderStream())
.pipeTo(transcript);
Strip photo metadata (GPS, camera, dates) before uploading:
import * as Exif from '@portable/exif';
import * as ImageSize from '@portable/image-size';
// `file` is a JPEG, PNG or WebP File from a file input or a drop.
const photo = Exif.strip(new Uint8Array(await file.arrayBuffer()));
const { width, height } = ImageSize.parse(photo);
await fetch(`/upload?width=${width}&height=${height}`, { method: 'POST', body: photo });
Every package follows the same conventions, so once you've used one, you know how the others work:
import * as Csv from '@portable/csv', and call Csv.decode or new Csv.DecoderStream().Uint8Array, and a Node Buffer is accepted. Functions that take text also take its bytes.TransformStream that you pass to pipeThrough, as with TextDecoderStream.signal. Aborting it stops the fetch calls, timers, and nested streams underneath, and the call rejects with signal.reason, as fetch does.close() method, a signal option that closes it, or both. It works with await using where the runtime has Symbol.asyncDispose.now, accept a Date, or a Temporal.Instant. Times in results are Date objects.InvalidInputError means the data was malformed, and TypeError or RangeError means an argument was wrong.The tests run in Chromium, Firefox, WebKit, Node 24, Node 26, Bun, and Deno. A check of every package also runs in workerd, the Cloudflare Workers runtime. Every package runs in Chrome 116, Firefox 124, and Safari 17.4 or later. Ed25519 signatures, in @portable/web-crypto, @portable/dkim, @portable/arc, and @portable/mail-auth, need Chrome 137 and Firefox 129, and X25519 keys in @portable/web-crypto need Chrome 133 and Firefox 130. @portable/smtp and @portable/sockets need a TCP socket API, so they run in Workers, Node, Bun, and Deno but not in browsers. The packages don't include polyfills, so if you support older browsers, you'll need to add them yourself.
MIT