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

devlock-sdk

v1.0.8

Published

DevLock Backend SDK for Node.js, Express, Fastify, and NestJS. Protect your APIs with real-time license validation, remote kill-switch, API suspension, and distributed caching features.

Downloads

279

Readme

devlock-sdk

Backend SDK for DevLock — License enforcement, remote management, and developer protection for Node.js applications.

npm version License: MIT

🌐 Website & Dashboard: devlock.tashanto.com · 🌍 Frontend SDK: devlock-client

Fail-safe by design. If DevLock's servers are ever unreachable, init() never throws and the middleware never blocks traffic on our outage — your service keeps serving requests. See Fail-open behavior.

Features

  • 🔐 License Validation — HMAC-signed server-to-server verification with caching
  • Kill Switch — Instant application disable via WebSocket
  • 🔧 Maintenance Mode — Return 503 automatically when enabled
  • 🏴 Feature Flags — Real-time feature toggling
  • 📡 Offline Support — Redis + in-memory cache with grace period
  • 🔄 Auto-Sync — Periodic config sync with WebSocket push updates
  • 📊 Telemetry — Batched event tracking
  • 🛡️ API Suspension — Remote API disable capability
  • 🔁 Retry Logic — Exponential backoff with jitter

Framework Support

| Framework | Import Path | |-----------|-------------| | Core (any Node.js) | devlock-sdk | | Express.js | devlock-sdk/express | | Fastify | devlock-sdk/fastify | | NestJS | devlock-sdk/nestjs |

Installation

npm install devlock-sdk
# or
yarn add devlock-sdk
# or
pnpm add devlock-sdk

Setup & Dashboard

Before using the SDK, you need to create a project and obtain your keys from the DevLock Dashboard:

  1. Go to DevLock Dashboard.
  2. Sign in and navigate to the Projects section.
  3. Click Create Project and fill in your details.
  4. Copy your Project Public Key (pk_live_...) and Secret Key (sk_live_...).

⚠️ Key Naming: The projectId field in the SDK config is your Public Key (pk_live_...), not a separate UUID. The Secret Key (sk_live_...) must be kept secure and never exposed to the frontend.

Recommended .env setup

DEVLOCK_PROJECT_ID=pk_live_your_public_key_here
DEVLOCK_SECRET_KEY=sk_live_your_secret_key_here
DEVLOCK_LICENSE_KEY=DLCK-XXXX-XXXX-XXXX-XXXX

Quick Start

Express.js (Recommended)

import express from 'express';
import { createMiddleware } from 'devlock-sdk/express';

const app = express();

app.use(createMiddleware({
  secretKey: process.env.DEVLOCK_SECRET_KEY!,
  projectId: process.env.DEVLOCK_PROJECT_ID!,   // ← your pk_live_... key
  excludePaths: ['/health', '/public', '/webhooks'],
  failBehavior: 'open',   // recommended — never block traffic on DevLock outage
  on: {
    onReady: () => {
      console.log('DevLock license protection active');
    },
    onKillSwitch: (reason) => {
      console.error('Kill switch activated:', reason);
    },
    onMaintenance: (enabled, message) => {
      console.log('Maintenance:', enabled, message);
    },
  },
}));

// Access license info in route handlers
app.get('/api/data', (req, res) => {
  const { license, isFeatureEnabled, track } = req.devlock!;

  if (isFeatureEnabled('advanced-export')) {
    // serve premium feature
  }

  track('data_accessed', { endpoint: '/api/data' });
  res.json({ features: license.features, status: license.status });
});

app.listen(3000);

Single-App License (No per-user license keys)

If your app has one license for the whole application (not per-user SaaS), use extractLicenseKey to always return your app's license key:

app.use(createMiddleware({
  secretKey: process.env.DEVLOCK_SECRET_KEY!,
  projectId: process.env.DEVLOCK_PROJECT_ID!,
  failBehavior: 'open',
  // Return the app's own license key for every request
  extractLicenseKey: (_req) => process.env.DEVLOCK_LICENSE_KEY,
  excludePaths: ['/health', '/auth/login'],
}));

This pattern is ideal for:

  • Internal tools / admin dashboards
  • B2B SaaS apps sold as a single deployment
  • Desktop apps built with Electron

Fastify

import Fastify from 'fastify';
import { devlockPlugin } from 'devlock-sdk/fastify';

const app = Fastify();

await app.register(devlockPlugin, {
  secretKey: process.env.DEVLOCK_SECRET_KEY!,
  projectId: process.env.DEVLOCK_PROJECT_ID!,
  excludePaths: ['/health'],
});

app.get('/api/data', (request, reply) => {
  const { license, isFeatureEnabled } = request.devlock;
  reply.send({ features: license.features });
});

await app.listen({ port: 3000 });

NestJS

// app.module.ts
import { Module } from '@nestjs/common';
import { DevLockModule } from 'devlock-sdk/nestjs';

@Module({
  imports: [
    DevLockModule.forRoot({
      secretKey: process.env.DEVLOCK_SECRET_KEY!,
      projectId: process.env.DEVLOCK_PROJECT_ID!,
      excludePaths: ['/health'],
    }),
  ],
})
export class AppModule {}

Core (Framework-Agnostic)

import { DevLock } from 'devlock-sdk';

const devlock = new DevLock({
  secretKey: process.env.DEVLOCK_SECRET_KEY!,
  projectId: process.env.DEVLOCK_PROJECT_ID!,
  on: {
    onKillSwitch: (reason) => console.error('Disabled:', reason),
    onMaintenance: (enabled) => console.log('Maintenance:', enabled),
  },
});

await devlock.init();

// Validate a license
const result = await devlock.validateLicense('DLCK-XXXX-XXXX-XXXX-XXXX');
console.log(result.valid, result.features);

// Check state
if (devlock.isMaintenanceMode()) { /* ... */ }
if (devlock.isKillSwitchActive()) { /* ... */ }
if (devlock.isFeatureEnabled('premium')) { /* ... */ }

// Track events
devlock.track({ type: 'api_call', timestamp: Date.now(), path: '/users' });

// Cleanup
devlock.destroy();

Configuration

const devlock = new DevLock({
  // Required
  secretKey: 'sk_live_xxx',          // Project secret key (keep server-side only)
  projectId: 'pk_live_xxx',          // Project public key (from Dashboard → Projects)

  // Optional
  apiUrl: 'https://dl-api.tashanto.com',  // Custom API URL
  wsUrl: 'wss://dl-ws.tashanto.com',      // Custom WebSocket URL
  environment: 'production',          // 'production' | 'staging' | 'development'
  syncInterval: 300000,               // Config sync interval (ms, default: 5min)
  cacheTtl: 300000,                   // License cache TTL (ms, default: 5min)
  offlineGraceHours: 72,             // Offline grace period (hours)
  realtime: true,                     // Enable WebSocket updates
  failBehavior: 'open',              // 'open' (default) | 'closed'
  redis: redisClient,                 // Optional Redis for distributed caching
  logger: customLogger,               // Custom logger (default: console)
});

Redis Caching (Recommended for Production)

import Redis from 'ioredis';
import { createMiddleware } from 'devlock-sdk/express';

const redis = new Redis(process.env.REDIS_URL);

app.use(createMiddleware({
  secretKey: process.env.DEVLOCK_SECRET_KEY!,
  projectId: process.env.DEVLOCK_PROJECT_ID!,
  redis: redis,  // Enables distributed caching across instances
}));

API Reference

DevLock Class

| Method | Returns | Description | |--------|---------|-------------| | init() | Promise<void> | Initialize SDK, sync config, connect WebSocket | | validateLicense(key, opts?) | Promise<ValidationResult> | Validate a license key | | isFeatureEnabled(flag) | boolean | Check feature flag | | isMaintenanceMode() | boolean | Check maintenance status | | isKillSwitchActive() | boolean | Check kill switch | | isApiSuspended() | boolean | Check API suspension | | getConfig(key, default?) | T | Get remote config value | | getState() | SDKState | Get full SDK state | | track(event) | void | Track telemetry event | | sync() | Promise<void> | Force config re-sync | | invalidateLicense(key) | Promise<void> | Clear cached validation | | destroy() | void | Cleanup resources |

ValidationResult

interface ValidationResult {
  valid: boolean;
  status: 'active' | 'suspended' | 'expired' | 'revoked' | 'trial' | 'unknown';
  features: string[];
  expiresAt?: string;
  error?: string;
  cached?: boolean;
}

Express Middleware (req.devlock)

interface RequestDevLock {
  license: ValidationResult;
  isFeatureEnabled: (flag: string) => boolean;
  getConfig: <T>(key: string, defaultValue?: T) => T;
  track: (event: string, metadata?: Record<string, unknown>) => void;
}

License Key Extraction

By default, the middleware looks for the license key in:

  1. X-License-Key header
  2. Authorization: License <key> header
  3. ?license_key= query parameter

Custom extraction:

app.use(createMiddleware({
  ...config,
  extractLicenseKey: (req) => req.headers['x-my-license'] as string,
}));

For single-app deployments (one license for the whole app):

app.use(createMiddleware({
  ...config,
  extractLicenseKey: (_req) => process.env.DEVLOCK_LICENSE_KEY,
}));

Fail-open behavior

🔒 The safety guarantee

Your service is disabled ONLY when you explicitly lock it from the DevLock dashboard. A DevLock outage, a network/API error, a request timeout, a malformed response, or the SDK itself failing will never block traffic, return 503/403, or crash your process. Errors always resolve to allow. A block is applied only when the server explicitly reports enabled: true for a kill-switch / maintenance / suspension you turned on.

DevLock is a safety layer for your service — it must never become a single point of failure. If DevLock's servers are unreachable and there is no cached decision:

  • init() never throws (resolves in a permissive offline state).
  • The middleware does not block traffic — a request that can only be validated as 'unknown' (server unreachable) is allowed through instead of returning 403.
  • Lock flags are normalised — only an explicit enabled === true blocks; missing or malformed config can never take your service down.
app.use(createMiddleware({
  secretKey: process.env.DEVLOCK_SECRET_KEY!,
  projectId: process.env.DEVLOCK_PROJECT_ID!,
  failBehavior: 'open',    // default — never break the host service
  // failBehavior: 'closed', // opt in to blocking when DevLock is unreachable
}));

Definitive enforcement signals (kill-switch, API suspension, maintenance, and suspended / expired / revoked licenses) are cached and still block — once received they persist across restarts, so an outage cannot be used to bypass a lock that was already issued.

Local Development & Testing

When integrating the SDK into a local service (e.g., http://localhost:3000), you can test it directly against your production DevLock account.

  1. No URL changes needed: Do not set apiUrl or wsUrl locally unless you are running your own self-hosted DevLock server. The SDK will automatically connect to your production DevLock servers.
  2. Domain Lock: For backend API endpoints, domain locking usually applies to where the request originates. If you enforce Domain Locking, ensure localhost or 127.0.0.1 is added to the Allowed Domains in your DevLock Dashboard (or leave the list completely empty to allow all domains).
  3. Use failBehavior: 'open' (default) during development — if DevLock servers are unreachable, your app will still run normally. You'll see [DevLock] Config sync failed in the logs, which is expected in offline/local environments.

Links

License

MIT


Built by Md Tanvir Ahamed Shanto · devlock.tashanto.com