@catbee/utils
Version:
A modular, production-grade utility toolkit for Node.js and TypeScript, designed for robust, scalable applications (including Express-based services). All utilities are tree-shakable and can be imported independently.
145 lines (141 loc) • 4.99 kB
JavaScript
/*
* The MIT License
*
* Copyright (c) 2026 Catbee Technologies. https://catbee.in/license
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import { Readable, Transform } from 'stream';
var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
function bufferToStream(data) {
const readable = new Readable();
readable.push(data);
readable.push(null);
return readable;
}
__name(bufferToStream, "bufferToStream");
async function streamToBuffer(stream) {
return new Promise((resolve, reject) => {
const chunks = [];
stream.on("data", (chunk) => chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)));
stream.on("end", () => resolve(Buffer.concat(chunks)));
stream.on("error", reject);
});
}
__name(streamToBuffer, "streamToBuffer");
async function streamToString(stream, encoding = "utf8") {
const buffer = await streamToBuffer(stream);
return buffer.toString(encoding);
}
__name(streamToString, "streamToString");
function createThrottleStream(bytesPerSecond) {
let bytesSent = 0;
let startTime = Date.now();
return new Transform({
transform(chunk, _encoding, callback) {
const elapsedSeconds = (Date.now() - startTime) / 1e3;
const targetBytes = bytesPerSecond * elapsedSeconds;
const chunkSize = chunk.length;
if (bytesSent + chunkSize <= targetBytes) {
bytesSent += chunkSize;
callback(null, chunk);
return;
}
const delay = ((bytesSent + chunkSize) / bytesPerSecond - elapsedSeconds) * 1e3;
setTimeout(() => {
bytesSent += chunkSize;
callback(null, chunk);
}, delay);
}
});
}
__name(createThrottleStream, "createThrottleStream");
function createBatchStream(size, options = {}) {
const objectMode = options.objectMode !== false;
let batch = [];
let buffers = [];
let bufferSize = 0;
return new Transform({
objectMode,
transform(chunk, _encoding, callback) {
if (objectMode) {
batch.push(chunk);
if (batch.length >= size) {
this.push(batch);
batch = [];
}
} else {
const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
buffers.push(buffer);
bufferSize += buffer.length;
let combined = Buffer.concat(buffers, bufferSize);
while (combined.length >= size) {
this.push(combined.slice(0, size));
combined = combined.slice(size);
}
buffers = combined.length > 0 ? [
combined
] : [];
bufferSize = combined.length;
}
callback();
},
flush(callback) {
if (objectMode && batch.length > 0) {
this.push(batch);
} else if (!objectMode && buffers.length > 0 && bufferSize > 0) {
let combined = Buffer.concat(buffers, bufferSize);
while (combined.length >= size) {
this.push(combined.slice(0, size));
combined = combined.slice(size);
}
if (combined.length > 0) {
this.push(combined);
}
}
callback();
}
});
}
__name(createBatchStream, "createBatchStream");
function createLineStream(options = {}) {
const { encoding = "utf8", includeNewlines = false } = options;
let buffer = "";
return new Transform({
objectMode: true,
transform(chunk, _encoding, callback) {
const str = buffer + (Buffer.isBuffer(chunk) ? chunk.toString(encoding) : chunk);
const lines = str.split(/\r?\n/);
buffer = lines.pop() || "";
for (const line of lines) {
this.push(includeNewlines ? line + "\n" : line);
}
callback();
},
flush(callback) {
if (buffer) {
this.push(buffer);
}
callback();
}
});
}
__name(createLineStream, "createLineStream");
export { bufferToStream, createBatchStream, createLineStream, createThrottleStream, streamToBuffer, streamToString };