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

@pocketsignals/broker-client

v2.0.0

Published

Webhook server for receiving PocketSignals trading signals and dispatch client

Readme

@pocketsignals/broker-client

Webhook server and dispatch client for receiving PocketSignals trading signals.

Contract Version

v2.0.0 - Push/Webhook Architecture

v2.0.0 Breaking Changes

  • Architecture Change: PocketSignals now PUSHES signals to your webhook server
  • BrokerPollingClient is deprecated - use WebhookServer instead
  • New push model is more efficient and lower latency

Installation

npm install @pocketsignals/broker-client

Quick Start - Webhook Server (Recommended)

The webhook server receives push signals from PocketSignals:

import { WebhookServer } from '@pocketsignals/broker-client';

const server = new WebhookServer({
  config: {
    port: 8080,
    serviceKey: process.env.POCKETSIGNALS_SERVICE_KEY!,
    basePath: '/broker/signals', // Optional, this is the default
  },
  handlers: {
    onEntry: async (signal) => {
      console.log('Entry signal received:', {
        symbol: signal.symbol,
        direction: signal.direction,
        price: signal.price,
        tsid: signal.tsid,
      });
      
      // Execute your trade logic here...
      const result = await executeAlpacaOrder(signal);
      
      return {
        success: true,
        signalId: signal.signalId,
        accepted: true,
      };
    },
    
    onExit: async (signal) => {
      console.log('Exit signal received:', {
        symbol: signal.symbol,
        exitReason: signal.exitReason,
        tsid: signal.tsid,
      });
      
      // Close your position here...
      const result = await closeAlpacaPosition(signal);
      
      return {
        success: true,
        signalId: signal.signalId,
        accepted: true,
      };
    },
    
    onStatus: async (signal) => {
      console.log('Status update:', signal.status);
      return { success: true };
    },
    
    onError: (error, payload) => {
      console.error('Handler error:', error, payload);
    },
  },
});

// Start the server
await server.start();
console.log(`Webhook server running on port ${server.getPort()}`);

// Check metrics
const metrics = server.getMetrics();
console.log('Signals received:', metrics.signalsReceived);

// Graceful shutdown
process.on('SIGTERM', async () => {
  await server.stop();
});

Webhook Endpoints

PocketSignals will push signals to:

| Endpoint | Description | |----------|-------------| | POST /broker/signals/entry | Entry signals (buy/call) | | POST /broker/signals/exit | Exit signals (sell/close) | | POST /broker/signals/status | Status updates |

Health endpoints:

| Endpoint | Description | |----------|-------------| | GET /health | Health check | | GET /ready | Readiness check | | GET /metrics | Server metrics |

Entry Signal Payload

interface EntrySignalWebhook {
  signalType: 'ENTRY';
  signalId: string;
  idempotencyKey: string;
  tsid: string;
  userId: string;
  symbol: string;
  assetType: 'options' | 'crypto';
  direction: 'BUY' | 'SELL' | 'CALL' | 'PUT';
  quantity: number;
  price: number;
  confidence: number;
  rationale: string;
  contractParams?: {
    strike: number;
    expiry: string;
    type: 'CALL' | 'PUT';
    contractSymbol?: string;
  };
  riskManagement?: RiskManagement;
  contractVersion: string;
  timestamp: number;
}

Exit Signal Payload

interface ExitSignalWebhook {
  signalType: 'EXIT';
  signalId: string;
  idempotencyKey: string;
  tsid: string;
  userId: string;
  symbol: string;
  assetType: 'options' | 'crypto';
  quantity: number;
  exitReason: 'AI_COACH' | 'STOP_LOSS' | 'TAKE_PROFIT' | 'CIRCUIT_BREAKER' | 'MANUAL' | 'EXPIRY';
  riskManagement?: RiskManagement;
  contractVersion: string;
  timestamp: number;
}

HMAC Authentication

All incoming requests include HMAC signatures for security:

| Header | Description | |--------|-------------| | X-Broker-Signature | HMAC-SHA256 signature of <timestamp>.<body> | | X-Broker-Timestamp | Unix timestamp in milliseconds | | Content-Type | Must be application/json |

Security Guarantees

  • Timestamp validation: ±30 second drift tolerance (configurable)
  • Replay protection: Duplicate signature+timestamp+body combinations are blocked
  • Timing-safe comparison: Constant-time signature verification to prevent timing attacks

Error Codes

| HTTP Code | Description | |-----------|-------------| | 401 | Missing or invalid signature | | 408 | Timestamp expired (outside ±30s window) | | 409 | Duplicate request (replay attack blocked) |

The WebhookServer automatically verifies signatures. For custom verification:

import { WebhookHmacVerifier } from '@pocketsignals/broker-client';

const verifier = new WebhookHmacVerifier({
  serviceKey: process.env.POCKETSIGNALS_SERVICE_KEY!,
  maxTimestampDriftMs: 30000, // 30 seconds (default, contract-compliant)
});

const result = verifier.verify(
  req.headers['x-broker-signature'],
  req.headers['x-broker-timestamp'],
  requestBody
);

if (!result.valid) {
  console.error('Auth failed:', result.error);
}

Idempotency / Duplicate Suppression

The WebhookServer includes built-in duplicate detection using idempotency keys.

For single-instance deployments (default):

import { InMemoryIdempotencyStorage } from '@pocketsignals/broker-client';

const storage = new InMemoryIdempotencyStorage({
  defaultTtlMs: 3600000, // 1 hour
});

For multi-instance deployments with Redis:

import Redis from 'ioredis';
import { RedisIdempotencyStorage } from '@pocketsignals/broker-client';

const redis = new Redis(process.env.REDIS_URL);
const storage = new RedisIdempotencyStorage(redis, {
  prefix: 'ps:idempotency:',
  defaultTtlMs: 3600000,
});

const server = new WebhookServer({
  config: { port: 8080, serviceKey: '...' },
  handlers: { ... },
  idempotencyStorage: storage,
});

Environment Variables

| Variable | Description | Required | |----------|-------------|----------| | POCKETSIGNALS_SERVICE_KEY | HMAC secret for signature verification | Yes |

Response Format

Handlers should return a WebhookResponse:

interface WebhookResponse {
  success: boolean;
  signalId?: string;
  accepted?: boolean;     // True if signal was acted upon
  duplicate?: boolean;    // True if duplicate was detected
  error?: string;         // Error message if failed
  retryAfterMs?: number;  // Request retry after this delay
}

Return codes:

  • 200 - Signal processed successfully
  • 400 - Bad request / handler rejected
  • 401 - Authentication failed
  • 408 - Timestamp too old
  • 409 - Duplicate request
  • 503 - Temporary failure (retry)

Retry Semantics

PocketSignals will retry failed webhook deliveries with exponential backoff:

| Attempt | Delay | |---------|-------| | 1 | Immediate | | 2 | 5 seconds | | 3 | 15 seconds | | 4 | 60 seconds | | 5 | 300 seconds |

Return 503 Service Unavailable with optional retryAfterMs in response body to request custom retry timing.

Production Requirements

  • TLS: Webhook endpoints MUST be served over HTTPS in production
  • Timeouts: Handler execution should complete within 10 seconds
  • Idempotency: Use Redis storage for multi-instance deployments
  • Monitoring: Use /metrics endpoint for observability

Migration from v1.x (Polling Client)

// OLD (deprecated) - Polling for commands
import { BrokerPollingClient } from '@pocketsignals/broker-client';

const client = new BrokerPollingClient({ ... });
while (true) {
  const result = await client.pollCommands();
  // Process commands...
  await sleep(5000);
}

// NEW (v2.0.0) - Receive pushed signals
import { WebhookServer } from '@pocketsignals/broker-client';

const server = new WebhookServer({
  config: { port: 8080, serviceKey: '...' },
  handlers: {
    onEntry: async (signal) => { /* handle entry */ },
    onExit: async (signal) => { /* handle exit */ },
  },
});
await server.start();

Dispatch Client (PocketSignals Internal Use)

For PocketSignals to push signals to Trade Automator:

import axios from 'axios';
import { BrokerDispatchClient } from '@pocketsignals/broker-client';

const client = new BrokerDispatchClient({
  config: {
    enabled: true,
    brokerBaseUrl: process.env.BROKER_BASE_URL!,
    serviceKey: process.env.BROKER_SERVICE_KEY!,
    callbackUrl: process.env.BROKER_CALLBACK_URL!,
    environment: 'production',
  },
  axios: axios.create(),
  logger: console,
});

const result = await client.dispatchSignal({ ... });

API Reference

WebhookServer

class WebhookServer {
  constructor(options: WebhookServerOptions);
  start(): Promise<void>;
  stop(): Promise<void>;
  isRunning(): boolean;
  getPort(): number;
  getMetrics(): WebhookMetrics;
}

WebhookHmacVerifier

class WebhookHmacVerifier {
  constructor(config: { serviceKey: string; maxTimestampDriftMs?: number });
  verify(signature: string, timestamp: string, body: string): HmacVerifyResult;
  sign(timestamp: number, body: string): string;
  stop(): void;
}

InMemoryIdempotencyStorage

class InMemoryIdempotencyStorage implements IdempotencyStorage {
  constructor(options?: { defaultTtlMs?: number; cleanupIntervalMs?: number });
  has(key: string): Promise<boolean>;
  set(key: string, ttlMs?: number): Promise<void>;
  delete(key: string): Promise<void>;
  size(): number;
  stop(): void;
}

Version Compatibility

| Package Version | Contract Version | Architecture | |-----------------|------------------|--------------| | 2.0.x | 2.0.0 | Push/Webhook (recommended) | | 1.4.x | 1.4.0 | Polling (deprecated) | | 1.3.x | 1.3.0 | Polling |

License

MIT