@akrc/buf
v1.0.0
Published
A lightweight, isomorphic library that provides seamless conversion between different binary data formats in Node.js and browsers. **Extends Uint8Array** for native compatibility with all binary APIs.
Readme
@akrc/buf - Unified Binary Data Interface
A lightweight, isomorphic library that provides seamless conversion between different binary data formats in Node.js and browsers. Extends Uint8Array for native compatibility with all binary APIs.
Overview
@akrc/buf extends Uint8Array to create a unified interface for working with binary data. It makes it trivial to convert between:
Synchronous Formats
- Node.js Buffer
- Uint8Array
- ArrayBuffer / SharedArrayBuffer
- DataView
- ArrayLike (arrays, array-like objects)
- ImageData (Canvas API)
- Base64 strings (auto-detected)
- Data URIs (RFC 2379, auto-detected)
Asynchronous Formats
- Blob / File (Web API)
- Response (Fetch API)
- Node.js Readable streams
- Web ReadableStream
Installation
npm install @akrc/bufor with pnpm:
pnpm add @akrc/bufQuick Start
Synchronous Construction
import { Buf } from '@akrc/buf'
// Create from various synchronous sources
const buf1 = new Buf(Buffer.from('hello'))
const buf2 = new Buf(new Uint8Array([1, 2, 3]))
const buf3 = new Buf('aGVsbG8=') // Base64 (auto-detected)
const buf4 = new Buf('data:text/plain;base64,aGVsbG8=') // Data URI (auto-detected)
const buf5 = new Buf(new ArrayBuffer(10))
const buf6 = new Buf([1, 2, 3, 4, 5]) // ArrayLike
// Convert to different formats
buf1.toBase64() // 'aGVsbG8='
buf1.toDataUri('text/plain') // 'data:text/plain;base64,aGVsbG8='
buf1.toArrayBuffer() // ArrayBuffer
buf1.toBuffer() // Buffer
buf1.toText() // 'hello'
// Use like Uint8Array (since Buf extends Uint8Array)
console.log(buf1[0]) // 104
for (const byte of buf1) console.log(byte)
buf1.slice(0, 2) // Native Uint8Array methods workAsynchronous Construction
// Create from asynchronous sources
const blob = new Blob(['hello'])
const buf = await Buf.fromAsync(blob)
const response = await fetch(url)
const buf = await Buf.fromAsync(response)
const fileStream = fs.createReadStream('file.bin')
const buf = await Buf.fromAsync(fileStream)
const webStream = response.body
const buf = await Buf.fromAsync(webStream)Features
📦 Comprehensive Format Support
Synchronous inputs:
- Buffer, Uint8Array, ArrayBuffer, SharedArrayBuffer, DataView
- ArrayLike objects (arrays, array-like objects)
- ImageData (Canvas API pixel data)
- Base64 strings (auto-detected)
- Data URIs (RFC 2379, auto-detected)
Asynchronous inputs:
- Blob / File (Web API)
- Response (Fetch API)
- Node.js Readable streams
- Web ReadableStream
🌐 True Isomorphic Design
- Works in Node.js and browsers without any configuration
- Uses constructor availability checks instead of platform detection for robustness
- Automatically selects appropriate APIs:
- Uses
Bufferin Node.js - Uses
btoa/atobin browsers - Gracefully degrades when APIs unavailable
- Uses
✨ Extends Uint8Array
Buf is a proper Uint8Array subclass, so you get:
- Direct indexing:
buf[0],buf[1] - Array methods:
buf.slice(),buf.forEach(),buf.map() - Array properties:
buf.length,buf.buffer - Full compatibility with any API expecting Uint8Array
const buf = new Buf(Buffer.from('hello'))
buf instanceof Uint8Array // true
buf.slice(0, 2) // Works perfectly
for (const byte of buf) console.log(byte)📝 Text Encoding
Support for multiple text encodings via native TextDecoder:
- UTF-8, UTF-16LE, UTF-16BE
- ISO-8859-1, Windows-1252, and more
const buf = new Buf(Buffer.from('こんにちは', 'utf8'))
buf.toText() // 'こんにちは'
buf.toText('utf-16le') // UTF-16LE decoded🌊 Stream Support
Full bidirectional stream support:
// From streams (async)
const buf = await Buf.fromAsync(response.body) // Web ReadableStream
const buf = await Buf.fromAsync(fsStream) // Node.js Readable
const buf = await Buf.fromAsync(blob) // Blob
// To streams (sync)
const nodeStream = buf.toReadableStream() // Node.js
const webStream = buf.toWebReadableStream() // Web
nodeStream.pipe(fs.createWriteStream('output.bin'))🔧 Global Configuration
Support for custom implementations (Buffer polyfills, custom TextEncoder, etc.):
import { Buf } from '@akrc/buf'
import BufferPolyfill from 'buffer'
Buf.setGlobalConfig({
Buffer: BufferPolyfill.Buffer,
TextEncoder: window.TextEncoder,
TextDecoder: window.TextDecoder,
Readable: customReadableClass,
})API Reference
Constructor
new Buf(input: Buffer | Uint8Array | ArrayBuffer | SharedArrayBuffer | DataView |
ArrayLike<number> | ImageData | string)Creates a Buf instance from synchronous sources:
- Buffer: Node.js Buffer
- Uint8Array: Typed array
- ArrayBuffer / SharedArrayBuffer: Raw binary buffers
- DataView: View into binary data
- ArrayLike: Arrays or array-like objects (e.g.,
{ 0: 1, 1: 2, length: 2 }) - ImageData: Canvas API pixel data
- string: Auto-detected as Base64 or Data URI
- Data URI:
data:text/plain;base64,aGVsbG8= - Base64:
aGVsbG8=
- Data URI:
Conversion Methods
toBuffer(): Buffer
Convert to Node.js Buffer. Throws if Buffer is not available.
const buf = new Buf('aGVsbG8=')
const buffer = buf.toBuffer()toUint8Array(): Uint8Array
Convert to a copy of Uint8Array. Useful when you need a standalone copy.
const buf = new Buf(Buffer.from('hello'))
const uint8 = buf.toUint8Array()toArrayBuffer(): ArrayBuffer
Convert to ArrayBuffer.
const buf = new Buf('aGVsbG8=')
const arrayBuffer = buf.toArrayBuffer()toBase64(): string
Convert to standard Base64 string (with padding).
const buf = new Buf(Buffer.from('hello'))
buf.toBase64() // 'aGVsbG8='toDataUri(mediaType?: string): string
Convert to Data URI with optional MIME type.
const buf = new Buf(Buffer.from('hello'))
buf.toDataUri() // 'data:application/octet-stream;base64,aGVsbG8='
buf.toDataUri('text/plain') // 'data:text/plain;base64,aGVsbG8='
buf.toDataUri('image/png') // 'data:image/png;base64,...'toText(encoding?: string): string
Decode to text with specified encoding (default: 'utf-8').
const buf = new Buf('aGVsbG8=')
buf.toText() // 'hello'
buf.toText('utf-8') // 'hello'
buf.toText('utf-16le') // UTF-16LE decodedtoDataUri(mediaType?: string): string
Convert to Data URI with optional MIME type.
const buf = new Buf(Buffer.from('hello'))
buf.toDataUri() // 'data:application/octet-stream;base64,aGVsbG8='
buf.toDataUri('text/plain') // 'data:text/plain;base64,aGVsbG8='toReadableStream(): NodeJS.ReadableStream
Convert to Node.js Readable stream (synchronous).
const buf = new Buf(Buffer.from('hello'))
const stream = buf.toReadableStream()
stream.pipe(fs.createWriteStream('output.txt'))toWebReadableStream(): ReadableStream<Uint8Array>
Convert to Web ReadableStream (synchronous).
const buf = new Buf('aGVsbG8=')
const stream = buf.toWebReadableStream()
const response = new Response(stream, {
headers: { 'Content-Type': 'text/plain' },
})Static Methods
static async fromAsync(input: BufAsyncInput): Promise<Buf>
Create Buf from asynchronous sources. Automatically detects input type and handles accordingly.
// From Blob or File
const buf = await Buf.fromAsync(new Blob(['hello']))
// From Fetch response
const response = await fetch(url)
const buf = await Buf.fromAsync(response)
// From Node.js Readable stream
const stream = fs.createReadStream('file.bin')
const buf = await Buf.fromAsync(stream)
// From Web ReadableStream
const buf = await Buf.fromAsync(response.body)Supported async inputs:
- Blob, File (Web API)
- Response (Fetch API)
- Node.js Readable stream
- Web ReadableStream
static setGlobalConfig(config): void
Set global configuration for custom implementations.
Buf.setGlobalConfig({
Buffer: customBuffer,
TextEncoder: customTextEncoder,
TextDecoder: customTextDecoder,
Readable: customReadableStream,
})static getGlobalConfig(): BufGlobalConfig
Get current global configuration.
const config = Buf.getGlobalConfig()
console.log(config.Buffer)Examples
Convert Image to Data URI
import { Buf } from '@akrc/buf'
import fs from 'fs'
const imageBuffer = fs.readFileSync('image.png')
const buf = new Buf(imageBuffer)
const dataUri = buf.toDataUri('image/png')
// Use in HTML
console.log(`<img src="${dataUri}" />`)Handle Data from Backend
// Backend sends Base64 in JSON
const response = await fetch('/api/data')
const { data } = await response.json()
// Create Buf from Base64 (auto-detected)
const buf = new Buf(data)
const bytes = buf.toUint8Array()Stream Large Files
import { Buf } from '@akrc/buf'
import fs from 'fs'
// Read file as stream and convert to Buf
const fileStream = fs.createReadStream('large-file.bin')
const buf = await Buf.fromAsync(fileStream)
// Convert to different formats
const base64 = buf.toBase64()
const uri = buf.toDataUri('application/octet-stream')Canvas ImageData Support
import { Buf } from '@akrc/buf'
const canvas = document.getElementById('canvas') as HTMLCanvasElement
const ctx = canvas.getContext('2d')!
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height)
// Convert ImageData to Buf
const buf = new Buf(imageData)
const png = buf.toDataUri('image/png')Text with Multiple Encodings
// UTF-8 encoded data
const utf8Buf = new Buf(Buffer.from('Hello', 'utf8'))
utf8Buf.toText() // 'Hello'
// UTF-16LE encoded data
const utf16Buf = new Buf(Buffer.from('Hello', 'utf16le'))
utf16Buf.toText('utf-16le') // 'Hello'Use in Browser with Polyfill
import { Buf } from '@akrc/buf'
import { Buffer } from 'buffer'
// Set up Buffer polyfill for browser
Buf.setGlobalConfig({
Buffer: Buffer,
})
// Now works in browser
const buf = new Buf([1, 2, 3, 4, 5])
const buffer = buf.toBuffer() // Works!Parse Data URI
import { Buf } from '@akrc/buf'
// Parse a Data URI
const buf = new Buf('data:text/plain;base64,aGVsbG8gd29ybGQ=')
buf.toText() // 'hello world'
buf.toBase64() // 'aGVsbG8gd29ybGQ='
// Extract from different sources
const response = await fetch(dataUriUrl)
const buf = await Buf.fromAsync(response)Browser Support
- Chrome/Edge: Full support
- Firefox: Full support
- Safari: Full support
- IE 11: Requires polyfills for TextEncoder/TextDecoder
Node.js support:
- Node.js 14+: Full support
- Node.js 18+: Full support including Blob/File APIs
Performance
- Minimal overhead: Extends native Uint8Array
- No data copying: Conversion methods reuse existing buffers where possible
- Efficient streams: Full bidirectional stream support without buffering entire contents unnecessarily
- Constructor-based API detection: Uses constructor availability checks instead of platform detection for robustness
- Modular architecture: Split utilities can be tree-shaken by bundlers
Contributing
We welcome contributions! Please ensure:
- All tests pass:
pnpm test - Code is formatted:
pnpm format - Types are correct:
pnpm typecheck - Build succeeds:
pnpm build
License
MIT
@akrc/buf - Making binary data conversion simple and painless.
