You're Invited:Meet the Socket Team at RSAC and BSidesSF 2026, March 23–26.RSVP
Socket
Book a DemoSign in
Socket

@humanwhocodes/safe-fetch

Package Overview
Dependencies
Maintainers
1
Versions
3
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@humanwhocodes/safe-fetch - npm Package Compare versions

Comparing version
1.0.1
to
1.1.0
+39
-3
dist/index.js

@@ -19,7 +19,43 @@ /**

return fetch(url, init).catch(error => {
// Serialize error to JSON
/** @type {Record<string, any>} */
let errorObject;
const errorMessage = typeof error === "string" ? error : error.message || "Unknown error";
if (typeof error === "string") {
errorObject = { message: error };
}
else {
// Extract all properties from the error object
errorObject = {};
const propertyNames = Object.getOwnPropertyNames(error);
for (const name of propertyNames) {
try {
const value = error[name];
// Skip functions and symbols as they can't be serialized
if (typeof value !== "function" &&
typeof value !== "symbol") {
errorObject[name] = value;
}
}
catch {
// Skip properties that throw on access
}
}
}
// Safely stringify with circular reference handling
let body;
try {
body = JSON.stringify(errorObject);
}
catch {
// Fallback if serialization fails (e.g., circular references)
body = JSON.stringify({ message: errorMessage });
}
// Create a custom Response-like object since ERROR_STATUS is out of valid range
const statusText = typeof error === "string" ? error : error.message;
const response = new Response(null, {
const response = new Response(body, {
status: 599,
statusText,
statusText: errorMessage,
headers: {
"Content-Type": "application/json",
},
});

@@ -26,0 +62,0 @@ // Override the status property with a custom value

+1
-1
{
"name": "@humanwhocodes/safe-fetch",
"version": "1.0.1",
"version": "1.1.0",
"description": "A fetch wrapper that returns Response objects for errors instead of rejecting",

@@ -5,0 +5,0 @@ "type": "module",

@@ -36,9 +36,17 @@ # Safe Fetch

// the ERROR_STATUS indicates it's a caught error
if (response.status === ERROR_STATUS) {
if (response.ok) {
const data = await response.json();
console.log(data);
} else if (response.status === ERROR_STATUS) {
// the ERROR_STATUS indicates it's a caught error
console.error("Error:", response.statusText);
// "This operation was aborted"
// You can also access the error details from the response body
const errorDetails = await response.json();
console.error("Error details:", errorDetails);
// { message: "This operation was aborted", stack: "..." }
} else {
const data = await response.json();
console.log(data);
// Handle HTTP errors (non-2xx status codes)
console.error(`HTTP Error: ${response.status} ${response.statusText}`);
}

@@ -63,6 +71,13 @@ ```

if (response.status === ERROR_STATUS) {
if (response.ok) {
console.log("Success!");
} else if (response.status === ERROR_STATUS) {
console.error("Error:", response.statusText);
// Access detailed error information from the response body
const errorDetails = await response.json();
console.error("Error details:", errorDetails);
} else {
console.log("Success!");
// Handle HTTP errors (non-2xx status codes)
console.error(`HTTP Error: ${response.status} ${response.statusText}`);
}

@@ -80,4 +95,15 @@ ```

if (response.status === ERROR_STATUS) {
if (response.ok) {
// Handle successful response
const data = await response.json();
console.log(data);
} else if (response.status === ERROR_STATUS) {
console.error("Error:", response.statusText);
// Get detailed error information from the response body
const errorDetails = await response.json();
console.error("Error details:", errorDetails);
} else {
// Handle HTTP errors (non-2xx status codes)
console.error(`HTTP Error: ${response.status} ${response.statusText}`);
}

@@ -96,3 +122,52 @@ ```

- `statusText`: The error message
- `body`: JSON-serialized error details
### Error Body Serialization
The error details are serialized as JSON in the response body, making it easy to access structured error information:
- **String errors**: Serialized as `{ message: "error string" }`
- **Error objects**: All properties (including `message`, `stack`, and custom properties) are extracted and serialized
**Example with Error object:**
```javascript
import { safeFetch, ERROR_STATUS } from "@humanwhocodes/safe-fetch";
const response = await safeFetch("https://invalid-domain.example");
if (response.status === ERROR_STATUS) {
const error = await response.json();
console.log(error.message); // "Failed to fetch"
console.log(error.stack); // Stack trace
}
```
**Example with custom error properties:**
```javascript
const mockFetch = async () => {
const error = new Error("Database connection failed");
error.code = "DB_CONN_ERROR";
error.retryAfter = 5000;
throw error;
};
const safeMockFetch = createSafeFetch(mockFetch);
const response = await safeMockFetch("https://api.example.com/data");
if (response.status === ERROR_STATUS) {
const error = await response.json();
console.log(error.message); // "Database connection failed"
console.log(error.code); // "DB_CONN_ERROR"
console.log(error.retryAfter); // 5000
}
```
**Safety features:**
- Circular references are handled gracefully with a fallback to a simple message format
- Non-serializable properties (functions, symbols) are automatically filtered out
- Property access errors are caught and handled
## License

@@ -99,0 +174,0 @@