npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@blax-software/networking

v0.3.1

Published

Plug-and-play API + WebSocket client. Framework-agnostic core with optional Vue, Nuxt, and React bindings.

Readme

@blax-software/networking

Framework-agnostic API and WebSocket client library with optional Vue, Nuxt, and axios adapters.

Features

  • Zero required dependencies — core uses native fetch and WebSocket
  • Tree-shakeable — import only what you need
  • SSR-safe — server detection with automatic no-op stubs
  • Framework adapters — Vue ref() reactivity, Nuxt auto-config, axios compatibility
  • TypeScript-first — Full type coverage with .d.ts exports

Install

npm install @blax-software/networking

# Optional peer dependencies:
npm install vue          # for /vue and /nuxt entry points
npm install axios        # for /axios adapter

Quick Start

Vanilla / React / Any framework

import { createApiClient, createWsClient } from '@blax-software/networking'

const api = createApiClient({
  serverUrl: 'https://api.example.com',
})

const ws = createWsClient({
  url: 'wss://api.example.com/app/ws',
  getAuthToken: () => api.bearerToken,
})

// REST
const users = await api.get('users')

// WebSocket
await ws.connect()
ws.setAppReady()
const result = await ws.send('user.profile', { id: 123 })

// Listen for events — returns an unsubscribe function
const off = ws.listen('chat.message', null, (data) => {
  console.log('New message:', data)
})
// Call off() to stop listening (works with React useEffect cleanup, etc.)

Vue 3

import { useApiClient, useWsClient, useWsListener } from '@blax-software/networking/vue'

const api = useApiClient({
  serverUrl: 'https://api.example.com',
})

const ws = useWsClient({
  url: 'wss://api.example.com/app/ws',
  getAuthToken: () => api.bearerToken,
})

// ws.is_setup, ws.is_opened etc. are Vue refs
watch(ws.is_setup, (ready) => {
  if (ready) console.log('WebSocket ready')
})

// Auto-cleanup on component unmount
useWsListener(ws, 'notifications.new', null, (data) => {
  console.log('Notification:', data)
})

Nuxt 3

// plugins/networking.client.ts
import { createFromNuxtConfig } from '@blax-software/networking/nuxt'

export default defineNuxtPlugin(() => {
  const { api, ws } = createFromNuxtConfig()

  // Optional: store bearer, connect WS, etc.
  api.setBearer(localStorage.getItem('bearerToken') ?? '')
  ws.connect()
  ws.setAppReady()

  return { provide: { api, ws } }
})

Reads these keys from useRuntimeConfig().public:

| Key | Description | |-----------------------|-------------------------------| | SERVER_URL | REST API base URL | | SERVER_URL_INTERNAL | Internal URL for SSR requests | | WEBS_URL | WebSocket hostname | | WS_PROTOCOL | 'wss' or 'ws' |

With axios

import { createApiClient } from '@blax-software/networking'
import { createAxiosAdapter } from '@blax-software/networking/axios'
import axios from 'axios'

const axiosInstance = axios.create({
  baseURL: 'https://api.example.com',
  withCredentials: true,
})

const api = createApiClient({
  serverUrl: 'https://api.example.com',
  http: createAxiosAdapter(axiosInstance),
})

API Reference

createApiClient(config: ApiClientConfig): ApiClient

| Config | Type | Default | Description | |-------------------|----------------------------|------------------|----------------------------------------| | serverUrl | string \| () => string | required | Base URL for HTTP requests | | ssrServerUrl | string \| () => string | — | Alternate URL for server-side requests | | http | HttpAdapter | fetchAdapter | HTTP adapter (fetch, axios, custom) | | notify | NotifyFn | — | Notification callback for errors | | storage | StorageAdapter | browserStorage | Token persistence adapter | | storageKey | string | 'bearerToken' | Storage key for the bearer token | | timeout | number | 10000 | Request timeout in ms | | withCredentials | boolean | true | Include cookies in requests | | retryOn503 | boolean | true | Auto-retry on HTTP 503 | | apiPrefix | string | 'api/' | Prefix prepended to relative paths | | isServer | boolean \| () => boolean | false | Whether running on the server (SSR) |

ApiClient methods:

| Method | Returns | Description | |---------------------------------|-------------------------|----------------------------------------| | get(path, params?) | Promise<HttpResponse> | GET request | | post(path, data?, headers?) | Promise<HttpResponse> | POST request | | put(path, data?) | Promise<HttpResponse> | PUT request | | delete(path, headers?) | Promise<HttpResponse> | DELETE request | | patch(path, data?) | Promise<HttpResponse> | PATCH request | | csrf(path?) | Promise<HttpResponse> | Fetch CSRF cookie | | setBearer(token \| null) | void | Set the auth token (pass null to clear) | | bearerToken | string (getter) | Current auth token | | loadBearerFromStorage() | string \| null | Load the token from the storage adapter | | getBackendUrl() | string | Resolve current server base URL | | clientAsset(path) | string | Build a backend asset URL | | cleanseUrl(url) | string | Normalize a URL/path | | parseError(error) | never | Extract error, notify, and re-throw | | parseThen(response, msg?) | any | Show success notification, return data | | configure(partial) | void | Update config at runtime |

createWsClient(config: WsClientConfig, createRef?): WsClient

| Config | Type | Default | Description | |---------------------|----------------------------|---------------|--------------------------------------------| | url | string \| () => string | required | Full WebSocket URL | | getAuthToken | () => string \| null | — | Auth token getter for channel subscription | | notify | NotifyFn | — | Connection state notifications | | translate | TranslateFn | — | Translation function for notification text | | defaultChannel | string | 'websocket' | Default channel name | | heartbeatInterval | number | 20000 | Ping interval (ms) | | reconnectDelay | number | 3000 | Delay before reconnect attempt (ms) | | autoReconnect | boolean | true | Auto-reconnect on disconnect | | isServer | boolean \| () => boolean | false | Returns safe no-op stub when true | | isNativePlatform | boolean \| () => boolean | false | Suppresses browser-only notifications |

WsClient methods:

| Method | Returns | Description | |-------------------------------------------|------------------------------|------------------------------------------| | connect(force?) | Promise<WebSocket \| void> | Open socket connection | | send(event, data?, channel?, progress?) | Promise<T> | Send event, await response | | listen(event, channel, callback) | () => void | Listen for event, returns unsubscribe fn | | listenOnce(event, channel?) | Promise<any> | Resolve on next occurrence | | setAppReady() | void | Unblock gated send() calls | | resetConnection() | void | Force channels to re-subscribe | | destroy() | void | Close and clean up everything |

Reactive state (Vue refs when using vue/nuxt adapters, plain objects otherwise):

| Property | Type | Description | |----------------------------|------------------------|-----------------------------| | is_opened | ReactiveRef<boolean> | Socket is open | | is_setup | ReactiveRef<boolean> | Default channel established | | is_connecting_socket | ReactiveRef<boolean> | Connection in progress | | is_after_lost_connection | ReactiveRef<boolean> | Had a connection loss |

Storage Adapters

import { browserStorage, memoryStorage } from '@blax-software/networking'

// Default — uses localStorage (safe for SSR, returns null on errors)
const api1 = createApiClient({ serverUrl: '...', storage: browserStorage })

// In-memory — for SSR, tests, or environments without localStorage
const api2 = createApiClient({ serverUrl: '...', storage: memoryStorage() })

License

MIT

Star History