Catalog npm
Back to packageRELEASE DETAILS

2.3.0

npm

@0xshariq/voxa

A modern HTTP client library built on native Fetch API with advanced features like caching, retry, and request deduplication.

axioscachefetchhttphttp-clientrequestretrytypescript
Published2 Dec 2025
Direct dependencies6
Transitive dependenciesNot calculated

README

Current package documentation

Voxa HTTP Client

Modern, feature-rich HTTP client for Node.js and browsers, built on the native Fetch API. Supports REST and GraphQL, automatic JSON parsing, metadata, caching, deduplication, queueing, and more.

npm version License: MIT

✨ Features

  • 🔄 Automatic Retry (exponential backoff)
  • 💾 Response Caching (memory/redis/custom)
  • 🎯 Request Deduplication
  • ⚡ Priority Queue
  • 🔒 TypeScript First
  • 🔌 Interceptors
  • 📊 Request Tracking & Metadata
  • ⏱️ Timeout Control
  • 🚀 Static Methods
  • 🛑 CancelManager
  • 📡 OfflineQueueManager
  • 🪪 TokenManager
  • 🧬 GraphQL Support
  • 🧪 Automatic JSON Parsing
  • 📹 Streaming Images/Videos (with progress tracking)
  • 🔐 SSRF Protection

📦 Installation

npm install @0xshariq/voxa
# or
pnpm install @0xshariq/voxa
# or
yarn add @0xshariq/voxa

🚀 Usage

🧩 Feature Modularity & Extensibility

Voxa's features (cache, retry, queue, batch, deduplication, interceptors, etc.) are fully modular and can be enabled, disabled, or extended at runtime.

Enabling/Disabling Features at Runtime

You can toggle features on/off by updating the instance configuration:

// Disable cache and queue at runtime
api.updateConfig({
  cache: { enabled: false },
  queue: { enabled: false },
});

// Enable retry and set new retry count
api.updateConfig({
  retry: { enabled: true, count: 10 },
});

Note: Not all features support dynamic reconfiguration in-flight. For critical changes, create a new instance with the desired config.

Extending with Plugins (Custom Features)

You can add your own features or override built-in ones by attaching custom managers or hooks:

// Example: Add a custom logging plugin
api.usePlugin({
  onRequest(config) {
    console.log("Request:", config.url);
    return config;
  },
  onResponse(response) {
    console.log("Response:", response.status);
    return response;
  },
});

Plugin Interface

A plugin is an object with any of these hooks:

  • onRequest(config)
  • onResponse(response)
  • onError(error)
  • onBatch(batch)
  • onCacheEvent(event)

You can register multiple plugins. They are called in the order added.

Disabling a Feature for a Single Request

// Disable cache for a single request
await api.get('/users', { cache: { enabled: false } });

// Set custom queue priority for a single request
await api.post('/orders', { ... }, { priority: 'critical' });

See Advanced Features for more on feature modularity and plugins.

Using Voxa with an Instance

Injecting Custom requestId & Metadata

You can supply your own requestId or custom metadata for distributed tracing or advanced tracking:

// Provide a custom requestId and metadata for tracing
const response = await api.get("/users/1", {
  requestId: "trace-abc-123",
  metadata: {
    traceId: "trace-abc-123",
    userId: "user-42",
    customField: "my-value",
  },
});
console.log(response.metadata); // includes your custom fields

Note: If you provide a requestId, it will be used for all feature tracking (cache, batch, queue, etc.).

Create a client instance to reuse configuration and advanced features:

import voxa from "@0xshariq/voxa";

const api = voxa.create({
  baseURL: "https://api.example.com",
  timeout: 5000,
  // ...other options
});

// Make requests (response is always parsed JSON)
const response = await api.get<User>("/users/1");
console.log(response.data); // { id, name, ... }

// You can also use other HTTP methods:
await api.post("/users", { name: "John" });
await api.put("/users/1", { name: "Jane" });
await api.delete("/users/1");

Using Voxa Without an Instance (Static Methods)

Call static methods directly for one-off requests:

import { Voxa } from "@0xshariq/voxa";

const response = await Voxa.get<User>("https://api.example.com/users/1");
console.log(response.data);

// Other static methods:
await Voxa.post("https://api.example.com/users", { name: "John" });
await Voxa.put("https://api.example.com/users/1", { name: "Jane" });
await Voxa.delete("https://api.example.com/users/1");

Use an instance for advanced features (caching, queueing, interceptors, GraphQL, etc.), or static methods for simple requests.

🚀 Quick Start

Complete Instance Example

import voxa from "@0xshariq/voxa";

const api = voxa.create({
  baseURL: "https://api.example.com", // string
  timeout: 5000, // number (ms)
  headers: {
    "Content-Type": "application/json", // string
    Authorization: "Bearer <token>", // string
  },
  priority: "high", // 'critical' | 'high' | 'normal' | 'low'
  retry: {
    enabled: true, // boolean (default: true)
    count: 5, // number (max: 5)
    delay: 1000, // number (ms)
    exponentialBackoff: true, // boolean
    maxRetry: 10000, // number (ms)
    statusCodes: [429, 500, 502, 503, 504], // number[]
  },
  deduplication: {
    enabled: true, // boolean (default: true)
    ttl: 300000, // number (ms)
  },
  cache: {
    enabled: true, // boolean (default: true)
    ttl: 300000, // number (ms, default: 5 min)
    storage: "memory", // 'memory' | 'custom'
    adapter: undefined, // custom cache adapter (optional)
  },
  queue: {
    enabled: true, // boolean
    maxConcurrent: 5, // number
  },
  batch: {
    enabled: true, // boolean
    endpoint: "/batch", // string (optional)
    wait: 100, // number (ms, optional)
    maxBatchSize: 10, // number (optional)
  },
  token: {
    enabled: true, // boolean
    type: "bearer", // 'bearer' | 'oauth2' | 'jwt'
    tokenEndpoint: "/auth/token", // string
    clientId: "client-id", // string
    clientSecret: "client-secret", // string
    refreshEndpoint: "/auth/refresh", // string
    storage: "memory", // 'memory' | 'localStorage'
    getToken: async () => "token", // function
    setToken: (token: string) => {}, // function
    refreshToken: async () => "new-token", // function
  },
  // Token refresh failure hook
  onTokenRefreshFailure: (error, context) => {
    // Custom logic: log, alert, or trigger re-authentication
    console.error("Token refresh failed:", error, context);
    // Optionally, redirect user or clear session
  },

  // Multi-tenant/multi-user support example
  getToken: async (userId) => {
    // Fetch token for a specific user/tenant
    return await fetchTokenForUser(userId);
  },
  setToken: (token, userId) => {
    // Store token for a specific user/tenant
    saveTokenForUser(token, userId);
  },
  refreshToken: async (userId) => {
    // Refresh token for a specific user/tenant
    return await refreshUserToken(userId);
  },

  // Usage:
  // await api.get('/resource', { userId: 'user-42' });
  offline: {
    enabled: true, // boolean (default: true)
    storage: "localStorage", // 'localStorage' | 'indexedDB'
  },
  circuitBreaker: {
    enabled: true, // boolean
    threshold: 5, // number
    timeout: 10000, // number (ms)
    onOpen: () => {}, // function (optional)
  },
  metrics: {
    enabled: true, // boolean
  },
  errors: {
    enabled: true, // boolean (default: true)
  },
  rate: {
    enabled: true, // boolean (default: true)
    maxRequests: 100, // number
    perMilliseconds: 60000, // number (ms)
  },
  schema: {
    enabled: true, // boolean
    requestSchema: undefined, // any (optional)
    responseSchema: undefined, // any (optional)
    library: "zod", // 'zod' | 'yup' (optional)
  },
  cancel: {
    enabled: true, // boolean (default: true)
  },
  graphql: {
    enabled: true, // boolean
    endpoint: "https://graphqlzero.almansi.me/api", // string
    logErrors: true, // boolean
    headers: undefined, // Record<string, string> (optional)
    timeout: undefined, // number (optional)
    cache: undefined, // boolean (optional)
  },
  interceptors: {
    request: [
      (config) => {
        /* modify config */ return config;
      },
    ],
    response: [
      (response) => {
        /* log/modify response */ return response;
      },
    ],
  },
  metadata: {
    enabled: true, // boolean (default: true)
    log: true, // boolean (log metadata events)
    fields: [
      "id",
      "method",
      "endpoint",
      "priority",
      "timestamp",
      "startTime",
      "endTime",
    ], // string[] (fields to track)
    maxEntries: 100, // number (max entries to keep)
    customHandler: (meta) => {}, // function (custom handler)
  },
});

// All options above are shown with possible values in comments. // You can use only the options you need.


### TypeScript Generics

```typescript
interface User {
  id: number;
  name: string;
  email: string;
}

// Type-safe responses
const response = await api.get<User>("/users/1");
const user: User = await response.json();
```

### Streaming Upload/Download

```typescript
import { StreamingImageManager, StreamingVideoManager } from '@0xshariq/voxa';

// Upload image with progress tracking
const streamingImages = new StreamingImageManager({});

const fileInput = document.querySelector('input[type="file"]');
const file = fileInput.files[0];

await streamingImages.upload(
  'https://api.example.com/images/upload',
  file,
  { 'Content-Type': 'image/jpeg' },
  (sentBytes, totalBytes) => {
    const percentage = (sentBytes / totalBytes) * 100;
    console.log(`Upload progress: ${percentage.toFixed(2)}%`);
  }
);

// Download video with progress
const streamingVideos = new StreamingVideoManager({});

const response = await streamingVideos.download(
  'https://api.example.com/videos/12345',
  {},
  (receivedBytes, totalBytes) => {
    console.log(`Downloaded: ${receivedBytes}/${totalBytes} bytes`);
  }
);

const blob = await response.blob();
const videoUrl = URL.createObjectURL(blob);
```

See [Streaming Guide](./docs/STREAMING.md) for complete examples and advanced usage.

## 📖 Documentation

### Core Documentation

**Documentation:**

- [Configuration Guide](./docs/CONFIGURATION.md) — All config options
- [Advanced Features](./docs/ADVANCED.md) — Caching, deduplication, queueing, interceptors, GraphQL, etc.
- [Streaming Guide](./docs/STREAMING.md) — Image/video upload/download with progress tracking
- [Developer Experience](./docs/DEVELOPER_EXPERIENCE.md) — Debug mode, logging, public getters, type safety
- [Troubleshooting](./docs/TROUBLESHOOTING.md) — Common issues and solutions
- [Custom Cache](./docs/CUSTOM_CACHE.md) — Custom cache implementation
- [Batch Usage](./docs/BATCH_USAGE.md) — Batch request patterns
- [Examples](./docs/EXAMPLES.md) — Usage patterns and code samples

See docs/ for full details and up-to-date usage.

## 🎯 Key Features

### Automatic Retry with Exponential Backoff

```typescript
const api = voxa.create({
  baseURL: "https://api.example.com",
  retry: {
    count: 3, // Max 3 retries
    delay: 1000, // Initial delay: 1s
    exponentialBackoff: true, // 1s → 2s → 4s
    maxRetry: 10000, // Max delay: 10s
  },
});
```

### Response Structure

```typescript
{
  response: Response, // Http Response object
  data: {}, // Api Data will store here
  metadata: {
    id: "string", // requestId used everywhere
    method: "'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS'",
    endpoint: "string",
    priority: "'critical' | 'high' | 'normal' | 'low'",
    timestamp: 2000,
    startTime: 2000,
    endTime: 2000
  },
  requestId: string, // Unique requestId, used in all features (queue, batch, cache, metrics, etc.)
  status: 200,
  statusText: "Ok"
}
```

See [Response Structure](./src/lib/types/client-types.ts) for detailed info.

### Response Caching

```typescript
// Memory cache (default)
const api = voxa.create({
  cache: {
    enabled: true,
    type: "memory",
    ttl: 300000, // 5 minutes
  },
});

// Redis cache
const api = voxa.create({
  cache: {
    enabled: true,
    type: "redis",
    ttl: 300000,
  },
});
```

### Request Prioritization

```typescript
// High priority request
await api.get("/critical-data", { priority: "critical" });

// Normal priority (default)
await api.get("/regular-data");

// Low priority
await api.get("/background-data", { priority: "low" });
```

### Request Interceptors

```typescript
// Add authentication header
api.interceptors.request.use((config) => {
  config.headers = {
    ...config.headers,
    Authorization: `Bearer ${getToken()}`,
  };
  return config;
});

// Log responses
api.interceptors.response.use((response) => {
  console.log("Response:", response.status);
  return response;
});
```

## 🔧 Configuration

### Environment Variables

Create a `.env` file in your project root:

```env
# Cache Configuration (Generic - works with any cache backend)
CACHE_URL=redis://localhost:6379
CACHE_PASSWORD=your-password
CACHE_HOST=localhost
CACHE_PORT=6379
CACHE_DB=0

# HTTP Configuration
HTTP_TIMEOUT=5000
HTTP_BASE_URL=https://api.example.com
```

See [Configuration Guide](./docs/CONFIGURATION.md) for detailed options.

## 📊 Monitoring & Statistics

```typescript
// Get cache statistics
const cacheStats = api.getCacheStats();
console.log(cacheStats); // { storage: 'memory', size: 10, entries: [...] }

// Get queue statistics
const queueStats = api.getQueueStats();
console.log(queueStats); // { queueSize: 2, activeRequests: 3, maxConcurrent: 5 }

// Get request metadata
const metadata = api.getRequestMetadata("request-id-123");
console.log(metadata); // { id, method, endpoint, duration, ... }
```

## Request ID Format and Expiry

Each request is assigned a unique `requestId` for tracking and feature management. The format is:

```
<timestamp>-<expiry>-<random>
```

- `timestamp`: When the request was created
- `expiry`: When the requestId expires (used for cache/batch conflict avoidance)
- `random`: Random string for uniqueness

- **Cache feature** uses a 5 minute expiry (default).
- **Batch feature** uses a 15 minute expiry.

This prevents conflicts when the same request is sent at different times. Always use the generated requestId for all features (cache, batch, queue, etc.).

---

## Error Classification & Debugging

Voxa now provides detailed error classification and debugging messages for every request. Use `api.classifyError(error)` to get both the error category and a helpful message for easier troubleshooting.

---

### Feature Manager Access

All feature managers (cache, queue, deduplication, metadata, circuit breaker, batch, rate limiter, metrics, schema, error classifier) are accessible via public methods or stats getters:

- `api.getCacheStats()`
- `api.getQueueStats()`
- `api.getDeduplicationStats()`
- `api.getMetadataStats()`
- `api.circuitBreaker()`
- `api.batch()`
- `api.rate()`
- `api.metrics()`
- `api.schema()`
- `api.classifyError(error)`

---

## 🧪 Testing

```bash
# Run test file directly
pnpm test

# Or using development mode
pnpm dev
```

## 📝 HTTP Methods

Voxa supports all standard HTTP methods:

```typescript
await api.get("/users");
await api.post("/users", { name: "John" });
await api.put("/users/1", { name: "Jane" });
await api.patch("/users/1", { email: "new@example.com" });
await api.delete("/users/1");
await api.head("/users");
await api.options("/users");
```

## 🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

## 📄 License

MIT © [Sharique Chaudhary](https://github.com/0xshariq)

## 🔗 Links

- [GitHub Repository](https://github.com/0xshariq/voxa)
- [npm Package](https://www.npmjs.com/package/@0xshariq/voxa)
- [Issue Tracker](https://github.com/0xshariq/voxa/issues)

## 🌟 Credits

Built with inspiration from Axios and modern web standards.

---

**Note:** This project is built on the native Fetch API and requires Node.js 18+ or a modern browser environment.

Downloads & popularity

Awaiting observations

No metric observations yet

Download counts and popularity will appear here as the collector receives them.

Declared dependencies 6

Native requirements
6 direct targetsNot calculated transitive count
Package / targetRequirementRelationship
uuid
Environment
{
  "local_name": "uuid",
  "alias": false,
  "peer_metadata": null
}
^13.0.0runtime
redis
Environment
{
  "local_name": "redis",
  "alias": false,
  "peer_metadata": null
}
^5.10.0runtime
tsx
Environment
{
  "local_name": "tsx",
  "alias": false,
  "peer_metadata": null
}
^4.20.6development
typescript
Environment
{
  "local_name": "typescript",
  "alias": false,
  "peer_metadata": null
}
^5.9.3development
@types/node
Environment
{
  "local_name": "@types/node",
  "alias": false,
  "peer_metadata": null
}
^24.10.1development
@types/uuid
Environment
{
  "local_name": "@types/uuid",
  "alias": false,
  "peer_metadata": null
}
^11.0.0development

Distribution files

1 collected
Distribution 1

Source distribution

Source file
Checksums from source
{
  "shasum": "7922a0f01ca8b47c72528cdf2349c1a61721a768",
  "tarball": "https://registry.npmjs.org/@0xshariq/voxa/-/voxa-2.3.0.tgz",
  "fileCount": 103,
  "integrity": "sha512-h9R13hmlqexdMCn9ytG924UdX/v9hMyzxbOQE+FPAqpQvbQcVoWlyD/OVXy4T4LLzq+hRC/Zj7BWWCls7yabwA==",
  "signatures": [
    {
      "sig": "MEYCIQCtsZGCe9BCTkkX40zeQmmfGB8gT157fMueyXS4dXKqtAIhANsOXfUkppJm2Szp59X4+H1YtJOPPUiAGVh4RwreJsIR",
      "keyid": "SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"
    }
  ],
  "unpackedSize": 198735
}

Repository

PENDING
0xshariq/voxa

Shared repository data · GitHub

License detected in repository
Not collected

Metadata history

Meaningful changes
Current collected state Current

Observed since 21 Oct, 11:26 UTC

No superseded metadata states collected. Unchanged observations do not create new revisions.

Record identity

package_version:607aa20072d98e0026e02202fc98f9cd60c197de26bd8a6fd92c1f0e7b3323b9

Other collected versions

2.4.14 Dec2.4.04 Dec2.2.52 Dec2.2.41 Dec2.2.31 Dec2.2.21 DecView all collected versions →