@push.rocks/smartrequest
Version:
A module for modern HTTP/HTTPS requests with support for form data, file uploads, JSON, binary data, streams, and more.
210 lines • 17.3 kB
JavaScript
import * as types from './types.js';
import { CoreResponse } from './response.js';
import { CoreRequest as AbstractCoreRequest } from '../core_base/request.js';
/**
* Bun implementation of Core Request class using native fetch with unix socket support
*/
export class CoreRequest extends AbstractCoreRequest {
constructor(url, options = {}, requestDataFunc = null) {
super(url, options);
this.timeoutId = null;
this.abortController = null;
this.requestDataFunc = requestDataFunc;
// Check for unsupported Node.js-specific options
if (options.agent) {
throw new Error('Node.js specific option (agent) is not supported in Bun implementation');
}
// Handle Node.js stream conversion if requestDataFunc is provided
if (requestDataFunc && options.__nodeStream) {
// Convert Node.js stream to web ReadableStream for Bun
const nodeStream = options.__nodeStream;
// Bun can handle Node.js streams via Readable.toWeb if available
// Or we can create a web stream that reads from the Node stream
if (typeof nodeStream.toWeb === 'function') {
this.options.requestBody = nodeStream.toWeb();
}
else {
// Create web ReadableStream from Node.js stream
this.options.requestBody = new ReadableStream({
async start(controller) {
nodeStream.on('data', (chunk) => {
controller.enqueue(new Uint8Array(chunk));
});
nodeStream.on('end', () => {
controller.close();
});
nodeStream.on('error', (err) => {
controller.error(err);
});
},
});
}
}
// Warn if raw streaming function is provided (not supported in Bun)
if (requestDataFunc && options.__rawStreamFunc) {
throw new Error('Raw streaming with .raw() is not supported in Bun. Use .stream() with web ReadableStream instead.');
}
}
/**
* Build the full URL with query parameters
*/
buildUrl() {
// For unix sockets, we need to extract the HTTP path part
if (CoreRequest.isUnixSocket(this.url)) {
const { path } = CoreRequest.parseUnixSocketUrl(this.url);
// Build URL for the HTTP request (the hostname doesn't matter for unix sockets)
if (!this.options.queryParams ||
Object.keys(this.options.queryParams).length === 0) {
return `http://localhost${path}`;
}
const url = new URL(`http://localhost${path}`);
Object.entries(this.options.queryParams).forEach(([key, value]) => {
url.searchParams.append(key, value);
});
return url.toString();
}
// Regular HTTP/HTTPS URL
if (!this.options.queryParams ||
Object.keys(this.options.queryParams).length === 0) {
return this.url;
}
const url = new URL(this.url);
Object.entries(this.options.queryParams).forEach(([key, value]) => {
url.searchParams.append(key, value);
});
return url.toString();
}
/**
* Convert our options to fetch RequestInit with Bun-specific extensions
*/
buildFetchOptions() {
const fetchOptions = {
method: this.options.method,
headers: this.options.headers,
credentials: this.options.credentials,
mode: this.options.mode,
cache: this.options.cache,
redirect: this.options.redirect,
referrer: this.options.referrer,
referrerPolicy: this.options.referrerPolicy,
integrity: this.options.integrity,
keepalive: this.options.keepAlive,
signal: this.options.signal,
};
// Handle unix socket
if (CoreRequest.isUnixSocket(this.url)) {
const { socketPath } = CoreRequest.parseUnixSocketUrl(this.url);
fetchOptions.unix = socketPath;
}
else if (this.options.unix) {
// Direct unix option was provided
fetchOptions.unix = this.options.unix;
}
else if (this.options.socketPath) {
// Legacy Node.js socketPath option - convert to Bun's unix option
fetchOptions.unix = this.options.socketPath;
}
// Handle request body
if (this.options.requestBody !== undefined) {
if (typeof this.options.requestBody === 'string' ||
this.options.requestBody instanceof ArrayBuffer ||
this.options.requestBody instanceof Uint8Array ||
this.options.requestBody instanceof FormData ||
this.options.requestBody instanceof URLSearchParams ||
this.options.requestBody instanceof ReadableStream ||
// Check for Buffer (Bun supports Node.js Buffer)
(typeof Buffer !== 'undefined' && this.options.requestBody instanceof Buffer)) {
fetchOptions.body = this.options.requestBody;
// If streaming, we need to set duplex mode
if (this.options.requestBody instanceof ReadableStream) {
fetchOptions.duplex = 'half';
}
}
else {
// Convert objects to JSON
fetchOptions.body = JSON.stringify(this.options.requestBody);
// Set content-type if not already set
if (!fetchOptions.headers) {
fetchOptions.headers = { 'Content-Type': 'application/json' };
}
else if (fetchOptions.headers instanceof Headers) {
if (!fetchOptions.headers.has('Content-Type')) {
fetchOptions.headers.set('Content-Type', 'application/json');
}
}
else if (typeof fetchOptions.headers === 'object' &&
!Array.isArray(fetchOptions.headers)) {
const headersObj = fetchOptions.headers;
if (!headersObj['Content-Type']) {
headersObj['Content-Type'] = 'application/json';
}
}
}
}
// Handle timeout
if (this.options.timeout || this.options.hardDataCuttingTimeout) {
const timeout = this.options.hardDataCuttingTimeout || this.options.timeout;
this.abortController = new AbortController();
this.timeoutId = setTimeout(() => {
if (this.abortController) {
this.abortController.abort();
}
}, timeout);
fetchOptions.signal = this.abortController.signal;
}
return fetchOptions;
}
/**
* Fire the request and return a CoreResponse
*/
async fire() {
const response = await this.fireCore();
return new CoreResponse(response);
}
/**
* Fire the request and return the raw Response
*/
async fireCore() {
const url = this.buildUrl();
const options = this.buildFetchOptions();
try {
const response = await fetch(url, options);
// Clear timeout on successful response
this.clearTimeout();
return response;
}
catch (error) {
// Clear timeout on error
this.clearTimeout();
if (error.name === 'AbortError') {
throw new Error('Request timed out');
}
throw error;
}
}
/**
* Clear the timeout and abort controller
*/
clearTimeout() {
if (this.timeoutId) {
clearTimeout(this.timeoutId);
this.timeoutId = null;
}
if (this.abortController) {
this.abortController = null;
}
}
/**
* Static factory method to create and fire a request
*/
static async create(url, options = {}) {
const request = new CoreRequest(url, options);
return request.fire();
}
}
/**
* Convenience exports for backward compatibility
*/
export const isUnixSocket = CoreRequest.isUnixSocket;
export const parseUnixSocketUrl = CoreRequest.parseUnixSocketUrl;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVxdWVzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzL2NvcmVfYnVuL3JlcXVlc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLEtBQUssTUFBTSxZQUFZLENBQUM7QUFDcEMsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUM3QyxPQUFPLEVBQUUsV0FBVyxJQUFJLG1CQUFtQixFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFFN0U7O0dBRUc7QUFDSCxNQUFNLE9BQU8sV0FBWSxTQUFRLG1CQUdoQztJQUtDLFlBQ0UsR0FBVyxFQUNYLFVBQW9DLEVBQUUsRUFDdEMsa0JBQStDLElBQUk7UUFFbkQsS0FBSyxDQUFDLEdBQUcsRUFBRSxPQUFPLENBQUMsQ0FBQztRQVRkLGNBQVMsR0FBeUMsSUFBSSxDQUFDO1FBQ3ZELG9CQUFlLEdBQTJCLElBQUksQ0FBQztRQVNyRCxJQUFJLENBQUMsZUFBZSxHQUFHLGVBQWUsQ0FBQztRQUV2QyxpREFBaUQ7UUFDakQsSUFBSSxPQUFPLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDbEIsTUFBTSxJQUFJLEtBQUssQ0FDYix3RUFBd0UsQ0FDekUsQ0FBQztRQUNKLENBQUM7UUFFRCxrRUFBa0U7UUFDbEUsSUFBSSxlQUFlLElBQUssT0FBZSxDQUFDLFlBQVksRUFBRSxDQUFDO1lBQ3JELHVEQUF1RDtZQUN2RCxNQUFNLFVBQVUsR0FBSSxPQUFlLENBQUMsWUFBWSxDQUFDO1lBRWpELGlFQUFpRTtZQUNqRSxnRUFBZ0U7WUFDaEUsSUFBSSxPQUFRLFVBQWtCLENBQUMsS0FBSyxLQUFLLFVBQVUsRUFBRSxDQUFDO2dCQUNwRCxJQUFJLENBQUMsT0FBTyxDQUFDLFdBQVcsR0FBSSxVQUFrQixDQUFDLEtBQUssRUFBRSxDQUFDO1lBQ3pELENBQUM7aUJBQU0sQ0FBQztnQkFDTixnREFBZ0Q7Z0JBQ2hELElBQUksQ0FBQyxPQUFPLENBQUMsV0FBVyxHQUFHLElB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