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

@sldm/integrations

v0.3.0

Published

Integration adapters for feeds, APIs, MCPs, authentication, and third-party services

Readme

@sldm/integrations

Comprehensive integration adapters for REST APIs, GraphQL, WebSockets, feeds, authentication, and third-party services.

Installation

npm install @sldm/integrations
# or
pnpm add @sldm/integrations

Features

  • REST API Client - Full-featured HTTP client with interceptors
  • GraphQL Client - Query, mutation, and subscription support
  • WebSocket Client - Real-time communication with auto-reconnection
  • Server-Sent Events (SSE) - Unidirectional server streaming
  • Feed Readers - RSS, Atom, and JSON feed parsing
  • Model Context Protocol (MCP) - AI/LLM integration client
  • OAuth 2.0 - Complete authorization flow implementation
  • Webhook Handlers - HMAC signature verification
  • Analytics - Google Analytics integration
  • ⚠️ gRPC - Stub implementation (requires additional setup)

Quick Start

REST API Client

import { createRESTClient } from '@sldm/integrations';

const api = createRESTClient({
  name: 'my-api',
  baseUrl: 'https://api.example.com',
  defaultHeaders: {
    'Authorization': 'Bearer YOUR_TOKEN'
  },
  interceptors: {
    request: [(config) => {
      console.log('Making request:', config.url);
      return config;
    }],
    response: [(response) => {
      console.log('Received response:', response.status);
      return response;
    }]
  }
});

// Make requests
const response = await api.get<User>('/users/123');
console.log(response.data);

await api.post('/users', {
  name: 'John Doe',
  email: '[email protected]'
});

GraphQL Client

import { createGraphQLClient } from '@sldm/integrations';

const graphql = createGraphQLClient({
  name: 'my-graphql',
  endpoint: 'https://api.example.com/graphql',
  headers: {
    'Authorization': 'Bearer YOUR_TOKEN'
  }
});

// Queries
const user = await graphql.query<{ user: User }>(`
  query GetUser($id: ID!) {
    user(id: $id) {
      id
      name
      email
    }
  }
`, { id: '123' });

// Mutations
const result = await graphql.mutate<{ createUser: User }>(`
  mutation CreateUser($input: CreateUserInput!) {
    createUser(input: $input) {
      id
      name
    }
  }
`, { input: { name: 'John', email: '[email protected]' } });

WebSocket Client

import { createWebSocketClient } from '@sldm/integrations';

const ws = createWebSocketClient({
  name: 'my-websocket',
  url: 'wss://api.example.com/ws',
  reconnect: true,
  maxReconnectAttempts: 5,
  reconnectInterval: 1000
});

// Handle events
ws.on('open', () => {
  console.log('Connected!');
  ws.send(JSON.stringify({ type: 'subscribe', channel: 'updates' }));
});

ws.on('message', (data) => {
  console.log('Received:', data);
});

ws.on('error', (error) => {
  console.error('WebSocket error:', error);
});

ws.on('close', () => {
  console.log('Disconnected');
});

// Connect
await ws.connect();

// Later: disconnect
ws.disconnect();

Server-Sent Events (SSE)

import { createSSEClient } from '@sldm/integrations';

const sse = createSSEClient({
  name: 'my-sse',
  url: 'https://api.example.com/events'
});

// Listen for events
const unsubscribe = sse.on('message', (event) => {
  console.log('New event:', event.data);
});

// Connect to stream
sse.connect();

// Later: disconnect
sse.disconnect();

Feed Reader (RSS/Atom/JSON)

import { createFeedReader } from '@sldm/integrations';

const reader = createFeedReader({
  name: 'tech-news',
  url: 'https://example.com/feed.xml',
  type: 'rss' // or 'atom' or 'json'
});

// Fetch feed once
const feed = await reader.fetch();
console.log(`${feed.title}: ${feed.items.length} items`);

feed.items.forEach(item => {
  console.log(`- ${item.title} (${item.pubDate})`);
});

// Subscribe to feed updates (polls every 60 seconds)
const unsubscribe = reader.subscribe((newItems) => {
  console.log(`${newItems.length} new items:`);
  newItems.forEach(item => console.log(`- ${item.title}`));
}, 60000);

// Later: stop polling
unsubscribe();

Model Context Protocol (MCP) Client

import { createMCPClient } from '@sldm/integrations';

const mcp = createMCPClient({
  name: 'ai-assistant',
  endpoint: 'https://api.openai.com/v1',
  apiKey: process.env.OPENAI_API_KEY,
  model: 'gpt-4',
  temperature: 0.7,
  maxTokens: 1000
});

// Chat completion
const response = await mcp.chat({
  messages: [
    { role: 'system', content: 'You are a helpful assistant.' },
    { role: 'user', content: 'What is TypeScript?' }
  ]
});

console.log(response.choices[0].message.content);

// Streaming response
await mcp.stream({
  messages: [
    { role: 'user', content: 'Write a haiku about programming' }
  ]
}, (chunk) => {
  process.stdout.write(chunk);
});

OAuth 2.0 Client

import { createOAuthClient } from '@sldm/integrations';

const oauth = createOAuthClient({
  name: 'github-oauth',
  clientId: process.env.GITHUB_CLIENT_ID!,
  clientSecret: process.env.GITHUB_CLIENT_SECRET!,
  authorizationUrl: 'https://github.com/login/oauth/authorize',
  tokenUrl: 'https://github.com/login/oauth/access_token',
  redirectUri: 'http://localhost:3000/callback',
  scope: ['user', 'repo']
});

// Step 1: Redirect user to authorization URL
const authUrl = oauth.getAuthorizationUrl('random-state-string');
console.log('Redirect to:', authUrl);

// Step 2: Exchange authorization code for tokens
const tokens = await oauth.exchangeCode('authorization-code-from-callback');
console.log('Access token:', tokens.accessToken);

// Step 3: Refresh token when needed
const refreshed = await oauth.refreshToken(tokens.refreshToken!);
console.log('New access token:', refreshed.accessToken);

// Step 4: Revoke token when done
await oauth.revokeToken(tokens.accessToken);

Webhook Handler

import { createWebhookHandler } from '@sldm/integrations';

const handler = createWebhookHandler({
  secret: process.env.WEBHOOK_SECRET!,
  signatureHeader: 'X-Hub-Signature-256',
  signatureAlgorithm: 'sha256'
});

// In your HTTP server
app.post('/webhook', async (req, res) => {
  const signature = req.headers['x-hub-signature-256'];
  const payload = JSON.stringify(req.body);

  // Verify signature
  const isValid = await handler.verify(payload, signature, process.env.WEBHOOK_SECRET!);
  if (!isValid) {
    return res.status(401).send('Invalid signature');
  }

  // Handle webhook
  await handler.handle({
    event: req.body.event,
    data: req.body.data,
    timestamp: Date.now()
  }, (data) => {
    console.log('Webhook received:', data);
  });

  res.status(200).send('OK');
});

Analytics Client

import { createAnalyticsClient } from '@sldm/integrations';

const analytics = createAnalyticsClient({
  name: 'my-analytics',
  trackingId: 'UA-XXXXX-Y',
  debug: process.env.NODE_ENV === 'development',
  anonymizeIp: true
});

// Track page views
analytics.pageView({
  path: '/home',
  title: 'Home Page',
  referrer: document.referrer
});

// Track events
analytics.event({
  category: 'User',
  action: 'Login',
  label: 'OAuth',
  value: 1
});

// Set user properties
analytics.setUser('user-123');
analytics.setProperty('plan', 'premium');

Advanced Usage

REST Client with Retry Logic

import { createRESTClient } from '@sldm/integrations';

const api = createRESTClient({
  name: 'retry-api',
  baseUrl: 'https://api.example.com',
  timeout: 10000,
  interceptors: {
    request: [
      async (config) => {
        // Add retry logic
        let attempt = 0;
        while (attempt < 3) {
          try {
            return config;
          } catch (error) {
            attempt++;
            if (attempt === 3) throw error;
            await new Promise(r => setTimeout(r, 1000 * attempt));
          }
        }
        return config;
      }
    ]
  }
});

WebSocket with Custom Protocols

import { createWebSocketClient } from '@sldm/integrations';

const ws = createWebSocketClient({
  name: 'protocol-ws',
  url: 'wss://api.example.com/ws',
  protocols: ['v1.protocol.example.com'],
  reconnect: true,
  reconnectInterval: 2000,
  maxReconnectAttempts: 10
});

ws.on('open', () => {
  ws.send(JSON.stringify({
    type: 'authenticate',
    token: 'YOUR_TOKEN'
  }));
});

Feed Reader with Multiple Feeds

import { createFeedReader } from '@sldm/integrations';

const feeds = [
  'https://example.com/feed1.xml',
  'https://example.com/feed2.xml',
  'https://example.com/feed3.xml'
].map(url => createFeedReader({ name: url, url, type: 'rss' }));

// Fetch all feeds in parallel
const results = await Promise.all(feeds.map(f => f.fetch()));
const allItems = results.flatMap(feed => feed.items);

// Sort by date
allItems.sort((a, b) =>
  (b.pubDate?.getTime() || 0) - (a.pubDate?.getTime() || 0)
);

console.log('Latest items:');
allItems.slice(0, 10).forEach(item => {
  console.log(`- ${item.title} (${item.pubDate})`);
});

Type Definitions

All clients are fully typed with TypeScript. Import types as needed:

import type {
  RESTClient,
  RESTConfig,
  GraphQLClient,
  WebSocketClient,
  SSEClient,
  FeedReader,
  MCPClient,
  OAuthClient,
  WebhookHandler,
  AnalyticsClient
} from '@sldm/integrations';

Browser vs Node.js

Most integrations work in both browser and Node.js environments:

  • ✅ REST, GraphQL, WebSocket, MCP, OAuth, Analytics: Universal
  • ⚠️ Feed Reader: Requires DOMParser (browser only, or use a polyfill in Node.js)
  • ⚠️ SSE: Requires EventSource (browser only, or use eventsource package in Node.js)

gRPC Setup

The gRPC client is a stub implementation. For full support:

Browser:

npm install @improbable-eng/grpc-web

Node.js:

npm install @grpc/grpc-js @grpc/proto-loader

See packages/integrations/src/grpc-client.ts for integration examples.

Testing

All integrations include comprehensive tests. Run them with:

pnpm --filter @sldm/integrations test

License

MIT

Contributing

Contributions welcome! Please see the main repository for contribution guidelines.