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

@edge-markets/connect-node

v1.4.0

Published

Server SDK for EDGE Connect token exchange and API calls

Readme

@edge-markets/connect-node

Server SDK for EDGE Connect token exchange and API calls.

Features

  • 🔐 Secure token exchange - Exchange codes for tokens with PKCE
  • 🔄 Token refresh - Automatic refresh token handling
  • 📡 Full API client - User, balance, transfers
  • 🛡️ Typed errors - Specific error classes for each scenario
  • 📝 TypeScript first - Complete type definitions

Installation

npm install @edge-markets/connect-node
# or
pnpm add @edge-markets/connect-node
# or
yarn add @edge-markets/connect-node

Quick Start

import { EdgeConnectServer } from '@edgeboost/edge-connect-server'

// Create instance once (reuse for all requests)
const edge = new EdgeConnectServer({
  clientId: process.env.EDGE_CLIENT_ID!,
  clientSecret: process.env.EDGE_CLIENT_SECRET!,
  environment: 'staging',
})

// Exchange code from EdgeLink for tokens
const tokens = await edge.exchangeCode(code, codeVerifier)

// Make API calls
const user = await edge.getUser(tokens.accessToken)
const balance = await edge.getBalance(tokens.accessToken)

⚠️ Security

This SDK requires your client secret. Use it ONLY on your backend server!

Never expose your client secret to browsers or client-side code.

Configuration

interface EdgeConnectServerConfig {
  clientId: string              // Your OAuth client ID
  clientSecret: string          // Your OAuth client secret (keep secret!)
  environment: EdgeEnvironment  // 'production' | 'staging' | 'sandbox'
  
  // Optional
  apiBaseUrl?: string           // Custom API URL (dev only)
  authDomain?: string           // Custom Cognito domain (dev only)
  timeout?: number              // Request timeout (default: 30000ms)

  // Optional: Message Level Encryption (Connect endpoints only)
  mle?: {
    enabled: boolean
    edgePublicKey: string       // EDGE public encryption key (PEM)
    edgeKeyId: string           // EDGE key ID (kid) used for requests
    partnerPrivateKey: string   // Your private key (PEM) to decrypt responses
    partnerKeyId: string        // Your key ID (kid) expected in response headers
    strictResponseEncryption?: boolean // default true
  }
}

Message Level Encryption (MLE)

const edge = new EdgeConnectServer({
  clientId: process.env.EDGE_CLIENT_ID!,
  clientSecret: process.env.EDGE_CLIENT_SECRET!,
  environment: 'staging',
  mle: {
    enabled: true,
    edgePublicKey: process.env.EDGE_MLE_EDGE_PUBLIC_KEY!,
    edgeKeyId: process.env.EDGE_MLE_EDGE_KEY_ID!,
    partnerPrivateKey: process.env.EDGE_MLE_PARTNER_PRIVATE_KEY!,
    partnerKeyId: process.env.EDGE_MLE_PARTNER_KEY_ID!,
  },
})

When enabled, the SDK sends X-Edge-MLE: v1, encrypts request bodies, and decrypts encrypted Connect responses.

Token Exchange

After EdgeLink completes, exchange the code for tokens:

// In your /api/edge/exchange endpoint
export async function POST(req: Request) {
  const { code, codeVerifier } = await req.json()
  
  try {
    const tokens = await edge.exchangeCode(code, codeVerifier)
    
    // Store tokens securely (encrypted in database)
    await db.edgeConnections.upsert({
      userId: req.user.id,
      accessToken: encrypt(tokens.accessToken),
      refreshToken: encrypt(tokens.refreshToken),
      expiresAt: new Date(tokens.expiresAt),
    })
    
    return Response.json({ success: true })
  } catch (error) {
    if (error instanceof EdgeTokenExchangeError) {
      // Code expired or already used
      return Response.json({ error: 'Please try again' }, { status: 400 })
    }
    throw error
  }
}

Token Refresh

Refresh tokens before they expire:

async function getValidAccessToken(userId: string): Promise<string> {
  const connection = await db.edgeConnections.get(userId)
  
  // Refresh 5 minutes before expiry
  const BUFFER = 5 * 60 * 1000
  
  if (Date.now() > connection.expiresAt.getTime() - BUFFER) {
    const newTokens = await edge.refreshTokens(
      decrypt(connection.refreshToken)
    )
    
    await db.edgeConnections.update(userId, {
      accessToken: encrypt(newTokens.accessToken),
      refreshToken: encrypt(newTokens.refreshToken),
      expiresAt: new Date(newTokens.expiresAt),
    })
    
    return newTokens.accessToken
  }
  
  return decrypt(connection.accessToken)
}

API Methods

User & Balance

// Get user profile
const user = await edge.getUser(accessToken)
// Returns: { id, email, firstName, lastName, createdAt }

// Get balance
const balance = await edge.getBalance(accessToken)
// Returns: { userId, availableBalance, currency, asOf }

Transfers

// Initiate transfer (requires OTP verification)
const transfer = await edge.initiateTransfer(accessToken, {
  type: 'debit',           // 'debit' = pull from user, 'credit' = push to user
  amount: '100.00',
  idempotencyKey: `txn_${userId}_${Date.now()}`,
})
// Returns: { transferId, status: 'pending_verification', otpMethod }

// Verify with OTP
const result = await edge.verifyTransfer(accessToken, transfer.transferId, userOtp)
// Returns: { transferId, status: 'completed' | 'failed' }

// Get transfer status
const status = await edge.getTransfer(accessToken, transferId)

// List transfers
const { transfers, total } = await edge.listTransfers(accessToken, {
  status: 'completed',
  limit: 10,
  offset: 0,
})

Consent

// Revoke consent (disconnect user)
await edge.revokeConsent(accessToken)

// Clean up stored tokens
await db.edgeConnections.delete(userId)

Error Handling

import {
  EdgeError,
  EdgeAuthenticationError,
  EdgeTokenExchangeError,
  EdgeConsentRequiredError,
  isEdgeError,
} from '@edge-markets/connect-node'

try {
  const balance = await edge.getBalance(accessToken)
} catch (error) {
  if (error instanceof EdgeAuthenticationError) {
    // Token expired - try refresh or reconnect
    return { error: 'session_expired' }
  }
  
  if (error instanceof EdgeConsentRequiredError) {
    // User revoked consent - need to reconnect
    return { error: 'reconnect_required' }
  }
  
  if (isEdgeError(error)) {
    // Some other SDK error
    console.error(`Edge Error [${error.code}]: ${error.message}`)
    return { error: error.code }
  }
  
  // Unknown error
  throw error
}

Error Types

| Error | When | What to do | |-------|------|------------| | EdgeAuthenticationError | Token invalid/expired | Refresh token or reconnect | | EdgeTokenExchangeError | Code exchange failed | Ask user to try again | | EdgeConsentRequiredError | User hasn't granted consent | Open EdgeLink | | EdgeInsufficientScopeError | Missing required scopes | Request more scopes | | EdgeNotFoundError | Resource not found | Check ID | | EdgeApiError | Other API error | Check error.code | | EdgeNetworkError | Network failure | Retry request |

NestJS Example

import { Injectable, Logger } from '@nestjs/common'
import { ConfigService } from '@nestjs/config'
import { EdgeConnectServer, EdgeConsentRequiredError } from '@edge-markets/connect-node'

@Injectable()
export class EdgeService {
  private readonly edge: EdgeConnectServer
  private readonly logger = new Logger(EdgeService.name)

  constructor(private config: ConfigService) {
    this.edge = new EdgeConnectServer({
      clientId: this.config.getOrThrow('EDGE_CLIENT_ID'),
      clientSecret: this.config.getOrThrow('EDGE_CLIENT_SECRET'),
      environment: this.config.get('EDGE_ENVIRONMENT', 'staging'),
    })
  }

  async exchangeCode(code: string, codeVerifier: string) {
    return this.edge.exchangeCode(code, codeVerifier)
  }

  async getBalance(accessToken: string) {
    try {
      return await this.edge.getBalance(accessToken)
    } catch (error) {
      if (error instanceof EdgeConsentRequiredError) {
        this.logger.warn('User consent required')
        throw error
      }
      this.logger.error('Failed to get balance', error)
      throw error
    }
  }
}

Express Example

import express from 'express'
import { EdgeConnectServer, isEdgeError } from '@edge-markets/connect-node'

const edge = new EdgeConnectServer({
  clientId: process.env.EDGE_CLIENT_ID!,
  clientSecret: process.env.EDGE_CLIENT_SECRET!,
  environment: 'staging',
})

const app = express()
app.use(express.json())

// Exchange code for tokens
app.post('/api/edge/exchange', async (req, res) => {
  try {
    const { code, codeVerifier } = req.body
    const tokens = await edge.exchangeCode(code, codeVerifier)
    
    // Store tokens for user...
    
    res.json({ success: true })
  } catch (error) {
    if (isEdgeError(error)) {
      res.status(400).json({ error: error.code, message: error.message })
    } else {
      res.status(500).json({ error: 'internal_error' })
    }
  }
})

// Get balance
app.get('/api/edge/balance', async (req, res) => {
  try {
    const accessToken = await getAccessTokenForUser(req.user.id)
    const balance = await edge.getBalance(accessToken)
    res.json(balance)
  } catch (error) {
    // Handle errors...
  }
})

Related Packages

  • @edge-markets/connect - Core types and utilities
  • @edge-markets/connect-link - Browser SDK for popup authentication

License

MIT