@yoyo-org/progressive-json
Version:
Stream and render JSON data as it arrives - perfect for AI responses, large datasets, and real-time updates
111 lines (110 loc) • 3.88 kB
JavaScript
/**
* HTTP adapter for Axios instances
* Allows using pre-configured Axios instances with Progressive JSON
*/
export class AxiosAdapter {
constructor(axiosInstance) {
this.axiosInstance = axiosInstance;
}
async stream(url, options = {}) {
const response = await this.request(url, options);
return response.stream;
}
async request(url, options = {}) {
try {
const config = {
method: options.method || 'GET',
url,
headers: options.headers,
timeout: options.timeout,
responseType: 'stream', // Critical: we need the stream
signal: options.signal,
};
// Add body/data if provided
if (options.body) {
config.data = options.body;
}
const response = await this.axiosInstance.request(config);
// Convert the Node.js stream to Web Stream (for browser compatibility)
const stream = this.convertToWebStream(response.data);
return {
stream,
status: response.status,
statusText: response.statusText,
headers: response.headers,
ok: response.status >= 200 && response.status < 300,
};
}
catch (error) {
// Handle Axios errors
if (error.response) {
throw new Error(`HTTP Error: ${error.response.status} ${error.response.statusText}`);
}
else if (error.request) {
throw new Error('Network Error: No response received');
}
else {
throw new Error(`Request Error: ${error.message}`);
}
}
}
/**
* Convert Node.js readable stream or browser stream to Web ReadableStream<Uint8Array>
*/
convertToWebStream(data) {
// If it's already a ReadableStream, return it
if (data instanceof ReadableStream) {
return data;
}
// If it's a Node.js readable stream (server-side)
if (data && typeof data.on === 'function' && typeof data.read === 'function') {
return new ReadableStream({
start(controller) {
data.on('data', (chunk) => {
controller.enqueue(new Uint8Array(chunk));
});
data.on('end', () => {
controller.close();
});
data.on('error', (error) => {
controller.error(error);
});
},
cancel() {
if (typeof data.destroy === 'function') {
data.destroy();
}
}
});
}
// If it's a string (fallback)
if (typeof data === 'string') {
const encoder = new TextEncoder();
const bytes = encoder.encode(data);
return new ReadableStream({
start(controller) {
controller.enqueue(bytes);
controller.close();
}
});
}
// If it's already Uint8Array
if (data instanceof Uint8Array) {
return new ReadableStream({
start(controller) {
controller.enqueue(data);
controller.close();
}
});
}
throw new Error('Unsupported response data type for streaming');
}
}
/**
* Factory function to create an Axios adapter
* @param axiosInstance - Your pre-configured Axios instance
* @returns AxiosAdapter instance
*/
export function createAxiosAdapter(axiosInstance) {
return new AxiosAdapter(axiosInstance);
}