Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.law4devs.eu/llms.txt

Use this file to discover all available pages before exploring further.

The Page<T> type

Every list() method returns a Promise<Page<T>>. The Page<T> object has three properties:
interface Page<T> {
  data: T[];           // items on the current page
  meta: PageMeta;      // totals and current position
  links: PageLinks;    // pre-built URLs for adjacent pages
}

interface PageMeta {
  total: number;       // total items across all pages
  page: number;        // current page number (1-based)
  perPage: number;     // items per page
  pages: number;       // total number of pages
  apiVersion: string;  // API version string
}

interface PageLinks {
  next: string | null; // URL of the next page, or null on the last page
  prev: string | null; // URL of the previous page, or null on the first page
}

Manual pagination

Use links.next to detect when there are more pages and increment page manually.
let page = 1;
let total = 0;

while (true) {
  const result = await client.frameworks.list({ page, perPage: 10 });
  total += result.data.length;

  console.log(`Page ${result.meta.page}/${result.meta.pages}: ${result.data.length} items`);

  if (!result.links.next) break; // no more pages
  page++;
}

console.log(`Fetched ${total} frameworks in total`);

Auto-pagination with for await

Every resource exposes an iter() method (or iterDeadlines() for compliance) that returns an AsyncGenerator<T>. Pages are fetched lazily — only when the current batch is exhausted.
// Frameworks
for await (const fw of client.frameworks.iter()) {
  console.log(fw.slug);
}

// Articles scoped to a framework
for await (const article of client.articles.iter('gdpr')) {
  console.log(`Art. ${article.articleNumber}: ${article.title}`);
}

// Compliance deadlines
for await (const deadline of client.compliance.iterDeadlines({ frameworkSlug: 'nis2' })) {
  console.log(deadline.description);
}
TypeScript infers the correct item type from the generator signature:
// article is typed as ArticleSummary — no cast needed
for await (const article of client.articles.iter('cra')) {
  const tags: Tag[] = article.tags; // fully typed
}

Early exit

Because iter() is a lazy AsyncGenerator, breaking out of the loop stops further fetches immediately.
// Find the first article tagged 'security' — stop as soon as found
let found: ArticleSummary | undefined;

for await (const article of client.articles.iter('nis2')) {
  if (article.tags.some(t => t.slug === 'security')) {
    found = article;
    break; // no further pages are fetched
  }
}

if (found) {
  console.log(`First security article: Art. ${found.articleNumber}`);
}

Controlling page size

Pass perPage to iter() or list() to tune the number of items fetched per HTTP request. Valid range is 1–100; default is 20.
// Fewer, larger pages — fewer HTTP requests
for await (const req of client.requirements.iter({
  frameworkSlug: 'gdpr',
  perPage: 100,
})) {
  // process requirement
}
For large datasets, a higher perPage value reduces the number of HTTP round-trips. For interactive UIs where you want to display results quickly, a smaller perPage value returns the first items faster.

Collecting all results into an array

async function collectAll<T>(gen: AsyncGenerator<T>): Promise<T[]> {
  const items: T[] = [];
  for await (const item of gen) {
    items.push(item);
  }
  return items;
}

const allFrameworks = await collectAll(client.frameworks.iter());
console.log(`${allFrameworks.length} total frameworks`);
Collecting all results into memory with a helper like collectAll is convenient but be mindful of response size. For large resources such as requirements or articles across all frameworks, stream and process items one-by-one inside the for await loop instead.