Skip to content

Versions and Upgrading

m4bwav edited this page Sep 29, 2026 · 1 revision

Every published version, and what changes for a caller moving from 1.x to 2.0.0. The comparisons come from two sources. One is the repository's golden capture of 1.1.7, replayed on 2026-09-29 against 1.1.7 and 2.0.0 as installed from npm that day. The other is the same calls run side by side against the local stand-in for the API.

Releases

Dates are from the npm registry; downloads are the registry's per-version counts for the week of 2026-09-21 to 2026-09-27 (both read on 2026-09-29).

Version Published Downloads that week Status
2.0.0 2026-09-26 182 latest
2.0.0-beta.1 2026-09-26 132 prerelease
1.1.7 2019-11-28 61 deprecated
1.1.6 2017-04-23 13 deprecated
1.1.3 to 1.1.5 2017-04-23 6 to 9 each deprecated
1.1.1 and 1.1.2 2016-09-18 6 each deprecated
1.1.0 2016-08-17 6 deprecated
1.0.0 to 1.0.2 2016-05-27 and 2016-05-30 6 each deprecated

Every 1.x version carries this npm deprecation message:

1.x depends on the deprecated request package, its CLI was never installable and -a was ignored; use 2.x

1.1.7 still installs (with request 2.88.2 and commander 4.1.1) and still runs on Node 20.20.2 and 24.18.0. The CHANGELOG describes 2.0.0 in full and 1.1.7 in one paragraph. The GitHub tags stop at v1.1.2 for 1.x, so 1.1.3 to 1.1.7 exist only on npm.

Moving from 1.x to 2.0.0

For a real post id, require('stack-exchange-markdown-retriever').retrieveMarkdown(options, callback) sends the same request and calls back with the same (markdown, error) in 2.0.0. What changes:

  1. Node 20 or later, and no deep imports (the package has an exports map).
  2. Ids that are not post ids ('abc', -1, 1.5, arrays, paths) throw a TypeError instead of being sent.
  3. Errors from the API are StackExchangeError objects with the same message, plus status, errorId and errorName. Bodies that are not JSON give StackExchangeError: The response is not JSON where 1.x gave a TypeError about toString.
  4. A callback that is not a function throws before any request; 1.x sent the request and then crashed.
  5. A callback that throws is called once.
  6. Leaving out the callback returns a Promise; 1.x sent the request and then crashed with callback is not a function.
  7. Requests go through fetch, which on Node uses a proxy only when told to (Recipes); 1.x's request read HTTPS_PROXY by itself.
  8. A 30-second timeout, where 1.x waited for ever.
  9. The command line tool is installed, -a works, and errors exit 1.

The same calls on both versions

This CommonJS program ran once in a project with 1.1.7 and once with 2.0.0, against the same stand-in:

const {retrieveMarkdown} = require('stack-exchange-markdown-retriever');

const calls = [
  {entityId: 127968, site: 'scifi'},
  {entityId: 1010, isForAnswer: true},
  {entityId: 404},
  {entityId: 9001},
  {entityId: 9004},
  {entityId: 'abc'},
];
(async () => {
  for (const options of calls) {
    await new Promise(resolve => {
      try {
        retrieveMarkdown(options, (markdown, error) => {
          console.log(JSON.stringify(options.entityId), '->', JSON.stringify(markdown), error ? error.name + ': ' + error.message : null);
          resolve();
        });
      } catch (error) {
        console.log(JSON.stringify(options.entityId), '-> threw', error.name + ': ' + error.message);
        resolve();
      }
    });
  }
})();

9001 is the stand-in's API error and 9004 its plain-JSON body (no compression). 1.1.7 printed (sample content):

127968 -> "Sample question body, made up for this wiki (not the real post).\n\nIt keeps HTML entities: "quoted" & more.\n\n    an indented code line" null
1010 -> "Sample answer, made up for this wiki, with a [link](https://example.com/)." null
404 -> null null
9001 -> null Error: ids
9004 -> null TypeError: Cannot read properties of undefined (reading 'toString')
"abc" -> null null

2.0.0 printed (sample content):

127968 -> "Sample question body, made up for this wiki (not the real post).\n\nIt keeps HTML entities: "quoted" & more.\n\n    an indented code line" null
1010 -> "Sample answer, made up for this wiki, with a [link](https://example.com/)." null
404 -> null null
9001 -> null StackExchangeError: ids
9004 -> "Sample plain JSON body." null
"abc" -> threw TypeError: entityId must be a post id (digits, or ids joined by ";"), not "abc"

1.1.7 sent abc to the API as /2.2/questions/abc; 2.0.0 sent nothing for it. The first five requests were the same on both.

The command line

1.1.7's package had no bin entry, so its cli.js ran only as node node_modules/stack-exchange-markdown-retriever/cli.js. Run that way, cli.js -a 1010 fetched question 1010 and printed null, and an API error also printed null with exit 0. 2.0.0:

exit 0
--- stdout
Sample answer, made up for this wiki, with a [link](https://example.com/).

for -a 1010 (sample content), and for the API error:

exit 1
--- stdout
--- stderr (first line)
StackExchangeError: ids

1.1.7's cli.js also refused --version (error: unknown option '--version').

The golden capture of 1.1.7, replayed

The repository keeps test/golden/capture-1.1.7.cjs and its recording test/golden/1.1.7.json: 90 calls and 20 command line runs of the published 1.1.7, recorded on 2026-09-26 through the capture's own proxy with TLS. Replayed on 2026-09-29, as child processes one after the other, and compared in three parts (the answer, the callback timing, and the request lines without the CONNECT):

Replayed against Answers Timing Request lines CLI answers CLI request lines
1.1.7, installed today 90 of 90 90 of 90 90 of 90 20 of 20 20 of 20
2.0.0 56 of 90 71 of 90 73 of 90 10 of 20 17 of 20 (16 when a late request lands, below)

The same numbers came out on Node 24.18.0 and Node 20.20.2, so the recording still stands for 1.1.7. The 34 answers that differ in 2.0.0 group like this:

Calls What 2.0.0 does CHANGELOG line
17 ids that are not post ids throws TypeError, no request Changed: entityId must be a post id
no callback, callback null returns a Promise Added: the Promise form
no arguments at all the returned Promise rejects (1.1.7 threw) Added: the Promise form, argument errors included
callback a string throws TypeError, no request Changed: a callback that is not a function
callback that throws called once Fixed
5 API errors (error_message), one of them with a throwing callback StackExchangeError, same message Changed: errors are StackExchangeError
4 bodies that are not JSON StackExchangeError: The response is not JSON Changed: errors are StackExchangeError
plain JSON body read Fixed
proxy refuses the tunnel (502) TypeError: fetch failed Changed: network failures are the platform's errors
proxy drops the connection during the tunnel no callback within the capture's 10-second wait none (see below)

Of the 19 timing differences, 17 are the refused ids, which now throw before any callback. One is the throwing callback's missing second call, and one is the dropped tunnel (below), which gave no callback within the capture's wait. Every callback that does run still runs after the call returns, as in 1.1.7. The 17 request differences are the 17 refused calls.

The 10 command line differences:

  • the new help text, for --help and -h;
  • --version, which 1.1.7 refused;
  • -a and --answer, which now fetch the answer;
  • errors that now exit 1: an API error, letters as the id, a proxy refusing the tunnel;
  • the plain-JSON body, now read;
  • parseArgs' wording for an unknown option.

The one difference without a CHANGELOG line is the dropped tunnel. 1.1.7 called back at once with tunneling socket could not be established, cause=socket hang up. Under 2.0.0 Node's fetch sends the CONNECT again and again until the timeout; Edge cases and errors shows it. Sometimes one of those late requests reaches the stand-in during the next case, a command line run with no arguments, which then shows an extra request line. In the saved runs it happened on Node 20.20.2 (16 of 20) and not on Node 24.18.0 (17 of 20); an earlier run showed the opposite, so it is timing, not the Node line.

The copy run against 2.0.0 needed three changes, none to the cases:

  1. the bin's path read from package.json (cli.js became dist/cli.mjs);
  2. none for the dependencies 2.0.0 dropped (commander, request);
  3. undici's EnvHttpProxyAgent installed after the capture sets its proxy variables, and preloaded in its command line children.

The golden files were only read.

Clone this wiki locally