BREAKING CHANGE(client/streaming): Unify streaming APIs: remove raw()/streamNode() and standardize on web ReadableStream across runtimes

This commit is contained in:
2025-11-17 14:18:58 +00:00
parent 1305b92ebe
commit 0cf48b3688
15 changed files with 1273 additions and 1524 deletions

183
readme.md
View File

@@ -182,11 +182,11 @@ async function downloadImage(url: string) {
return Buffer.from(buffer); // Convert ArrayBuffer to Buffer if needed
}
// Streaming response (Web Streams API)
// Streaming response (Web Streams API - cross-platform)
async function streamLargeFile(url: string) {
const response = await SmartRequest.create().url(url).get();
// Get a web-style ReadableStream (works in both Node.js and browsers)
// Get a web-style ReadableStream (works everywhere)
const stream = response.stream();
if (stream) {
@@ -204,12 +204,14 @@ async function streamLargeFile(url: string) {
}
}
// Node.js specific stream (only in Node.js environment)
// Convert to Node.js stream if needed (Node.js only)
async function streamWithNodeApi(url: string) {
const response = await SmartRequest.create().url(url).get();
// Only available in Node.js, throws error in browser/Bun/Deno
const nodeStream = response.streamNode();
// Convert web stream to Node.js stream
import { Readable } from 'stream';
const webStream = response.stream();
const nodeStream = Readable.fromWeb(webStream);
nodeStream.on('data', (chunk) => {
console.log(`Received ${chunk.length} bytes of data`);
@@ -230,8 +232,7 @@ The response object provides these methods:
- `text(): Promise<string>` - Get response as text
- `arrayBuffer(): Promise<ArrayBuffer>` - Get response as ArrayBuffer
- `stream(): ReadableStream<Uint8Array> | null` - Get web-style ReadableStream (cross-platform)
- `streamNode(): NodeJS.ReadableStream` - Get Node.js stream (Node.js only, throws in browser/Bun/Deno)
- `raw(): Response | http.IncomingMessage` - Get the underlying platform response
- `raw(): Response | http.IncomingMessage` - Get the underlying platform response object
Each body method can only be called once per response, similar to the fetch API.
@@ -368,24 +369,7 @@ async function streamData(dataSource: Readable) {
return await response.json();
}
// Advanced: Full control over request streaming (Node.js only)
async function customStreaming() {
const response = await SmartRequest.create()
.url('https://api.example.com/stream')
.raw((request) => {
// Custom streaming logic - you have full control
request.write('chunk1');
request.write('chunk2');
// Stream from another source
someReadableStream.pipe(request);
})
.post();
return await response.json();
}
// Send Uint8Array (works in both Node.js and browser)
// Send Uint8Array (works everywhere)
async function uploadBinaryData() {
const data = new Uint8Array([72, 101, 108, 108, 111]); // "Hello"
@@ -411,11 +395,6 @@ async function uploadBinaryData() {
- ✅ Web ReadableStream works everywhere (Node.js, Bun, Deno, browsers)
- ⚠️ Node.js streams only work in Node.js (automatically converted to web streams in Bun/Deno)
- **`.raw(streamFunc)`** - Advanced control over request streaming
- `streamFunc`: Function that receives the raw request object for custom streaming
-**Node.js only** - not supported in browsers, Bun, or Deno
- Use for advanced scenarios like chunked transfer encoding
These methods are particularly useful for:
- Uploading large files without loading them into memory
- Streaming real-time data to servers
@@ -687,13 +666,12 @@ const response = await SmartRequest.create()
})
.get();
// Bun uses web streams - streamNode() throws an error
// Bun uses web streams natively
const streamResponse = await SmartRequest.create()
.url('https://api.example.com/data')
.get();
const webStream = streamResponse.stream(); // ✅ Use web streams in Bun
// streamNode() is not available - throws error directing you to use stream()
```
### Deno-Specific Options
@@ -716,13 +694,12 @@ const response = await SmartRequest.create()
// Remember to clean up clients when done
client.close();
// Deno uses web streams - streamNode() throws an error
// Deno uses web streams natively
const streamResponse = await SmartRequest.create()
.url('https://api.example.com/data')
.get();
const webStream = streamResponse.stream(); // ✅ Use web streams in Deno
// streamNode() is not available - throws error directing you to use stream()
```
## Complete Example: Building a REST API Client
@@ -838,6 +815,144 @@ async function fetchWithErrorHandling(url: string) {
## Migrating from Earlier Versions
### From v4.x to v5.x
Version 5.0 completes the transition to modern web standards by removing Node.js-specific streaming APIs:
#### **Breaking Changes**
1. **`.streamNode()` Method Removed**
- The `.streamNode()` method has been removed from all response objects
- Use the cross-platform `.stream()` method instead, which returns a web `ReadableStream<Uint8Array>`
- For Node.js users who need Node.js streams, convert using `Readable.fromWeb()`
```typescript
// ❌ Before (v4.x) - Node.js only
const response = await SmartRequest.create().url(url).get();
const nodeStream = response.streamNode();
// ✅ After (v5.x) - Cross-platform
import { Readable } from 'stream';
const response = await SmartRequest.create().url(url).get();
const webStream = response.stream();
const nodeStream = Readable.fromWeb(webStream); // Convert to Node.js stream
```
2. **Request `.raw()` Method Removed**
- The `.raw(streamFunc)` method has been removed from the SmartRequest client
- Use `.stream()` with a web `ReadableStream` instead for request body streaming
- Node.js users can create web streams from Node.js streams using `Readable.toWeb()`
```typescript
// ❌ Before (v4.x) - Node.js only
const response = await SmartRequest.create()
.url(url)
.raw((request) => {
request.write('chunk1');
request.write('chunk2');
request.end();
})
.post();
// ✅ After (v5.x) - Cross-platform
const stream = new ReadableStream({
start(controller) {
controller.enqueue(new TextEncoder().encode('chunk1'));
controller.enqueue(new TextEncoder().encode('chunk2'));
controller.close();
}
});
const response = await SmartRequest.create()
.url(url)
.stream(stream)
.post();
// Or convert from Node.js stream (Node.js only)
import { Readable } from 'stream';
import * as fs from 'fs';
const nodeStream = fs.createReadStream('file.txt');
const webStream = Readable.toWeb(nodeStream);
const response = await SmartRequest.create()
.url(url)
.stream(webStream)
.post();
```
3. **Response `.raw()` Method Preserved**
- The `response.raw()` method is still available for accessing platform-specific response objects
- Returns `http.IncomingMessage` in Node.js or `Response` in other runtimes
- Use for advanced scenarios requiring access to raw platform objects
```typescript
// ✅ Still works in v5.x
const response = await SmartRequest.create().url(url).get();
const rawResponse = response.raw(); // http.IncomingMessage or Response
```
#### **Migration Guide**
**For Response Streaming:**
```typescript
// Before (v4.x)
const response = await SmartRequest.create().url(url).get();
const nodeStream = response.streamNode();
nodeStream.on('data', (chunk) => {
console.log(`Received ${chunk.length} bytes`);
});
// After (v5.x) - Option 1: Use web streams directly
const response = await SmartRequest.create().url(url).get();
const webStream = response.stream();
if (webStream) {
const reader = webStream.getReader();
while (true) {
const { done, value } = await reader.read();
if (done) break;
console.log(`Received ${value.length} bytes`);
}
reader.releaseLock();
}
// After (v5.x) - Option 2: Convert to Node.js stream (Node.js only)
import { Readable } from 'stream';
const response = await SmartRequest.create().url(url).get();
const webStream = response.stream();
const nodeStream = Readable.fromWeb(webStream);
nodeStream.on('data', (chunk) => {
console.log(`Received ${chunk.length} bytes`);
});
```
**For Request Streaming:**
Node.js streams are still accepted by the `.stream()` method and automatically converted internally. No changes required for most use cases:
```typescript
// ✅ Still works in v5.x
import * as fs from 'fs';
const fileStream = fs.createReadStream('large-file.bin');
const response = await SmartRequest.create()
.url('https://api.example.com/upload')
.stream(fileStream, 'application/octet-stream')
.post();
```
**Benefits:**
- ✅ True cross-platform compatibility
- ✅ Modern web standards
- ✅ Cleaner API surface
- ✅ Single streaming approach works everywhere
### From v3.x to v4.x
Version 4.0 adds comprehensive cross-platform support: