Skip to main content

Habr

@magistr/habrv2026.10.25.10· MIT· 6d agoBEHAVIORS
01README

Habr for swamp — read a Habr user's publications and full article bodies from Habr's public JSON API (habr.com/kek/v2), no credentials required.

Model:

  • @magistr/habr — list-articles fans out over every page of a user's feed (by alias, e.g. Milfgard) and writes one articles resource with the parsed summaries (title, url, published time, reading time, complexity, tags, hubs, and read/vote/comment statistics), newest first. get-article fetches a single publication by its numeric id, including the full HTML body (textHtml).
02Release Notes

2026.10.25.10

  • Repo-wide republish; no functional change.
03Behaviors1
@magistr/habrv2026.10.25.10extensions/models/habr.ts
fn list-articles()
List all publications by a Habr user (by alias, e.g. 'Milfgard').
fn get-article()
Fetch a single Habr article by its numeric publication id, including
fn get-articles()
Fetch several Habr articles by their numeric ids in a single run

Resources

articles(infinite)— A Habr user's publications (all pages of their feed), newest first
article(infinite)— A single Habr article with its full HTML body
04Previous Versions9
2026.10.15.9MIT

2026.10.15.9

Changed

  • Repo-wide maintenance release: version bump to republish the current source. No schema change.
2026.10.15.8MIT

2026.10.15.8

Fixed

  • parseSummary, articles and article no longer crash on a malformed API response. String() and Number() on a JSON object whose toString / valueOf is not callable (e.g. {"toString": ""}) threw "Cannot convert object to primitive value" and aborted the run. Untrusted scalars now go through str() / toNumber(), which accept only strings and numbers. Found by the property suite at nightly-soak scale; both counterexamples are pinned as regression tests.

Changed

  • Repo-wide maintenance release: version bump to republish the current source. No schema change.
2026.10.15.6MIT

2026.10.15.6

Changed

  • Repo-wide maintenance release: version bump to republish the current source. No schema change.
2026.10.15.5MIT

2026.10.15.5

Changed

  • Repo-wide maintenance release: version bump to republish the current source. No schema change.
2026.10.15.4MIT

2026.10.15.4

Changed

  • Repo-wide maintenance release: version bump to republish the current source. No schema change.
2026.10.15.3MIT

2026.10.15.3

Changed

  • Repo-wide maintenance release: version bump to republish the current source. No schema change.
2026.10.15.2MIT

2026.10.15.2

Changed

  • Repo-wide maintenance release: version bump to republish the current source. No schema change.
2026.10.15.1MIT

2026.10.15.1

Changed

  • Repo-wide maintenance release: version bump to republish the current source. No schema change.
2026.09.09.2MIT

2026.09.09.2

Initial release of @magistr/habr: read a Habr user's publications and full article bodies from Habr's public /kek/v2 JSON API, no credentials required.

  • list-articles fans out over every page of a user's feed in one run and writes one articles resource, newest first. maxPages caps the fan-out.
  • get-article fetches one publication by numeric id with its HTML body (textHtml) and a block-aware plain-text rendering (text).
  • get-articles fetches several ids in one run, one article resource per id.
  • The user alias, article id and language are shape-checked before they are put in a URL. Every request and every redirect hop is checked against a host allowlist (the configured base host, habr.com, *.habr.com).

Fixed (found while writing the test suites)

  • decodeEntities threw a RangeError on a numeric reference above U+10FFFF (for example �), which aborted the whole method run. Such a reference is now left as-is.
  • The lang global argument was put in the query string and the article URL path without a check, so a value such as ru&user=other could add query params. It is now validated (2–8 letters). A server-supplied lang that fails the same check is replaced by the configured language.
  • A non-numeric pagesCount produced NaN, which the articles schema rejects. A very large pagesCount made the page loop unbounded. The value is now coerced to an integer from 1 to 500. A fractional maxPages is floored.
  • Non-numeric statistics and a NaN readingTime produced NaN fields that failed schema validation. They now become 0 and null.
  • htmlToText put a blank line between list items and treated tags such as <link> as list items. List items are now single-spaced, the end of a list ends a paragraph, and only a real <li> gets a bullet.
05Stats
A
100 / 100
Downloads
19
Archive size
12.3 KB
  • Has README or module doc2/2earned
  • README has a code example1/1earned
  • README is substantive1/1earned
  • Most symbols documented1/1earned
  • No slow types (deprecated)1/1earned
  • Dependencies pass trust audit2/2earned
  • Docs keep secrets in a vault1/1earned
  • Has description1/1earned
  • Platform support declared (or universal)2/2earned
  • License2/2earned
  • Verified public repository2/2earned
06Platforms
07Labels