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

law4devs

v1.0.0

Published

Official TypeScript/JavaScript SDK for the Law4Devs EU Regulatory Compliance API

Readme

law4devs

Official TypeScript SDK for the Law4Devs API — structured EU regulatory compliance data for developers.

npm version License: MIT

Features

  • Full TypeScript types for all API resources
  • Zero runtime dependencies (uses Node 18+ built-in fetch)
  • Automatic pagination with AsyncGenerator (iter())
  • Automatic retry with exponential backoff on 429/5xx
  • Dual CJS + ESM output

Installation

npm install law4devs

Quick Start

import { Law4DevsClient } from 'law4devs';

const client = new Law4DevsClient();

// List all frameworks
const page = await client.frameworks.list();
console.log(page.data.map(f => f.slug));

// Get a specific framework
const gdpr = await client.frameworks.get('gdpr');
console.log(gdpr.name, gdpr.requirementCount);

// Iterate all articles in a framework (auto-pagination)
for await (const article of client.articles.iter('gdpr')) {
  console.log(article.articleNumber, article.title);
}

Authentication

No API key is required for public endpoints. To use an API key:

const client = new Law4DevsClient({ apiKey: 'your-key-here' });

Configuration

const client = new Law4DevsClient({
  baseUrl: 'https://api.law4devs.eu/v1', // default
  apiKey: 'optional-key',
  timeout: 30_000,    // milliseconds, default 30s
  maxRetries: 3,      // default 3
});

Resources

Frameworks

// List frameworks (paginated)
const page = await client.frameworks.list({ page: 1, perPage: 20 });

// Get framework detail
const fw = await client.frameworks.get('cra');

// Iterate all frameworks (auto-pagination)
for await (const fw of client.frameworks.iter()) {
  console.log(fw.slug);
}

Articles

// List articles in a framework
const page = await client.articles.list('gdpr', { page: 1, perPage: 20 });

// Get a specific article
const article = await client.articles.get('gdpr', 5);

// Get related articles
const related = await client.articles.related('gdpr', 5);

// Iterate all articles
for await (const article of client.articles.iter('gdpr')) {
  console.log(article.articleNumber, article.title);
}

Recitals

const page = await client.recitals.list('gdpr');
const recital = await client.recitals.get('gdpr', 1);
for await (const r of client.recitals.iter('gdpr')) { /* ... */ }

Requirements

// All requirements
const page = await client.requirements.list();

// Filter by framework
const gdprReqs = await client.requirements.list({ frameworkSlug: 'gdpr' });

// Iterate
for await (const req of client.requirements.iter({ frameworkSlug: 'gdpr' })) {
  console.log(req.requirementText);
}

Tags

const page = await client.tags.list();
const tag = await client.tags.get('data-protection');
for await (const tag of client.tags.iter()) { /* ... */ }

Compliance Deadlines

const page = await client.compliance.deadlines({ frameworkSlug: 'nis2' });
for await (const d of client.compliance.iterDeadlines({ frameworkSlug: 'nis2' })) {
  console.log(d.deadlineDate, d.description);
}

Annexes

const page = await client.annexes.list('cra');
const annex = await client.annexes.get('cra', 'I');
for await (const annex of client.annexes.iter('cra')) { /* ... */ }

Search

const results = await client.search.query('data breach notification', {
  framework: 'gdpr',
  resultType: 'article',
});

for await (const result of client.search.iter('security requirements')) {
  console.log(result.type, result.matchContext);
}

Pagination

All list() methods return a Page<T> object:

const page = await client.frameworks.list({ page: 1, perPage: 10 });
console.log(page.meta.total);    // total items
console.log(page.meta.pages);    // total pages
console.log(page.links.next);    // URL of next page, or null
console.log(page.data);          // array of items

For automatic iteration, use iter():

for await (const item of client.frameworks.iter({ perPage: 50 })) {
  // Automatically fetches next page when needed
}

Error Handling

import { Law4DevsClient, NotFoundError, RateLimitError, ValidationError } from 'law4devs';

try {
  const fw = await client.frameworks.get('unknown-slug');
} catch (err) {
  if (err instanceof NotFoundError) {
    console.error('Framework not found:', err.message);
  } else if (err instanceof RateLimitError) {
    console.error('Rate limited — will retry automatically');
  } else if (err instanceof ValidationError) {
    console.error('Bad request:', err.message, err.statusCode);
  }
}

Error classes: Law4DevsError (base), NotFoundError, ValidationError, RateLimitError, ServerError.

Available Frameworks

| Slug | Name | CELEX | Status | |------|------|-------|--------| | gdpr | General Data Protection Regulation | 32016R0679 | Active | | nis2 | Network and Information Security Directive 2 | 32022L2555 | Active | | cra | Cyber Resilience Act | 32024R2847 | Active | | ai-act | Artificial Intelligence Act | 32024R1689 | Active | | dora | Digital Operational Resilience Act | 32022R2554 | Active | | dsa | Digital Services Act | 32022R2065 | Active | | dma | Digital Markets Act | 32022R1925 | Active | | eidas2 | eIDAS 2.0 | 32024R1183 | Active | | data-act | Data Act | 32023R2854 | Active | | data-governance-act | Data Governance Act | 32022R0868 | Active | | eu-ai-liability | EU AI Liability Directive | — | Active | | product-liability | Product Liability Directive | — | Active | | eprivacy | ePrivacy Regulation | — | Active | | psd3 | Payment Services Directive 3 | — | Active | | micar | Markets in Crypto-Assets Regulation | 32023R1114 | Active | | open-finance | Open Finance Framework | — | Active | | fida | Financial Data Access | — | Active | | nis1 | Network and Information Security Directive 1 | 32016L1148 | Superseded | | csd-r | Cyber Security Delegated Regulation | — | Active |

License

MIT