Skip to content

Increasing popularity / download counts #56

Description

@karlhorky

Hi @dnut, thanks again for taking over this initiative to reboot @stkb's original (and unmaintained) Rewrap VS Code extension, looks like with 52k total downloads (estimated 3.4k/mo in Jul 2026), Rewrap Revived is gaining a bit on the original Rewrap with 891k total downloads (estimated 18.2k/mo in Jul 2026).

Image

Source: Internet Archive Wayback Machine snapshots

vscode-marketplace-install-history.ts

const extensions = process.argv.slice(2);

if (extensions.length === 0) {
  console.error(
    'Usage: node vscode-marketplace-install-history.mts <extension...>',
  );
  process.exit(1);
}

console.log('extension,captured_at,installs');

for (const extension of extensions) {
  const marketplaceUrl =
    `https://marketplace.visualstudio.com/items?itemName=${extension}`;

  console.error(`Finding Wayback captures for ${extension}...`);

  const cdxUrl = new URL('https://web.archive.org/cdx/search/cdx');
  cdxUrl.searchParams.set('url', marketplaceUrl);
  cdxUrl.searchParams.set('from', '202412');
  cdxUrl.searchParams.set('output', 'json');
  cdxUrl.searchParams.set('filter', 'statuscode:200');
  cdxUrl.searchParams.set('fl', 'timestamp');

  const cdxResponse = await fetch(cdxUrl);
  const captures = (await cdxResponse.json()) as string[][];

  for (const [timestamp] of captures.slice(1)) {
    console.error(`${extension} ${timestamp}`);

    const snapshotUrl =
      `https://web.archive.org/web/${timestamp}id_/${marketplaceUrl}`;

    let html = '';

    for (let attempt = 1; attempt <= 5; attempt++) {
      try {
        const response = await fetch(snapshotUrl);

        if (!response.ok) {
          throw new Error(`${response.status} ${response.statusText}`);
        }

        html = await response.text();
        break;
      } catch (error) {
        console.error(`  attempt ${attempt} failed: ${error}`);

        if (attempt < 5) {
          await new Promise((resolve) => setTimeout(resolve, 5000));
        }
      }
    }

    const text = html
      .replaceAll('&nbsp;', ' ')
      .replace(/<script\b[^>]*>[\s\S]*?<\/script>/gi, ' ')
      .replace(/<style\b[^>]*>[\s\S]*?<\/style>/gi, ' ')
      .replace(/<[^>]+>/g, ' ')
      .replace(/\s+/g, ' ');

    const match = text.match(
      /\|\s*([0-9][0-9,]*)\s+installs?\s*\|/i,
    );

    const installs = match?.[1].replaceAll(',', '') ?? '';

    const capturedAt =
      `${timestamp.slice(0, 4)}-${timestamp.slice(4, 6)}-${timestamp.slice(6, 8)}` +
      `T${timestamp.slice(8, 10)}:${timestamp.slice(10, 12)}:${timestamp.slice(12, 14)}Z`;

    console.log(`${extension},${capturedAt},${installs}`);

    // Avoid hammering the Internet Archive.
    await new Promise((resolve) => setTimeout(resolve, 2000));
  }

  console.error(`Fetching current count for ${extension}...`);

  const response = await fetch(marketplaceUrl);
  const html = await response.text();

  const text = html
    .replaceAll('&nbsp;', ' ')
    .replace(/<script\b[^>]*>[\s\S]*?<\/script>/gi, ' ')
    .replace(/<style\b[^>]*>[\s\S]*?<\/style>/gi, ' ')
    .replace(/<[^>]+>/g, ' ')
    .replace(/\s+/g, ' ');

  const match = text.match(
    /\|\s*([0-9][0-9,]*)\s+installs?\s*\|/i,
  );

  const installs = match?.[1].replaceAll(',', '') ?? '';

  console.log(`${extension},${new Date().toISOString()},${installs}`);
}

Usage:

node vscode-marketplace-install-history.ts stkb.rewrap dnut.rewrap-revived > installs.csv

Output (installs.csv):

extension,captured_at,installs
stkb.rewrap,2024-12-04T03:29:38Z,550569
stkb.rewrap,2024-12-21T20:52:36Z,557849
stkb.rewrap,2025-01-14T15:34:07Z,563637
stkb.rewrap,2025-02-01T04:35:13Z,570107
stkb.rewrap,2025-02-07T21:15:06Z,572487
stkb.rewrap,2025-02-13T12:43:51Z,574506
stkb.rewrap,2025-03-08T09:59:23Z,582969
stkb.rewrap,2025-03-20T03:08:44Z,587038
stkb.rewrap,2025-04-01T00:34:06Z,591332
stkb.rewrap,2025-04-05T23:14:49Z,593231
stkb.rewrap,2025-04-22T21:28:13Z,599288
stkb.rewrap,2025-04-24T18:07:21Z,600176
stkb.rewrap,2025-04-29T04:24:54Z,601559
stkb.rewrap,2025-05-10T00:01:45Z,606221
stkb.rewrap,2025-05-15T17:05:29Z,609056
stkb.rewrap,2025-06-02T19:59:26Z,617653
stkb.rewrap,2025-08-06T14:12:15Z,643575
stkb.rewrap,2025-08-19T17:28:03Z,650190
stkb.rewrap,2025-10-10T18:25:22Z,681365
stkb.rewrap,2025-12-12T05:38:48Z,730487
stkb.rewrap,2025-12-15T13:47:46Z,732314
stkb.rewrap,2025-12-30T17:49:26Z,739665
stkb.rewrap,2026-01-18T19:49:34Z,750913
stkb.rewrap,2026-02-23T04:22:30Z,775946
stkb.rewrap,2026-03-10T09:02:38Z,787939
stkb.rewrap,2026-05-09T14:13:34Z,828109
stkb.rewrap,2026-05-21T13:58:13Z,835851
stkb.rewrap,2026-08-18T19:42:04Z,888368
stkb.rewrap,2026-08-25T10:28:41.245Z,891338
dnut.rewrap-revived,2025-01-14T17:12:35Z,741
dnut.rewrap-revived,2025-05-10T00:01:39Z,7939
dnut.rewrap-revived,2025-07-14T12:43:42Z,12353
dnut.rewrap-revived,2025-09-11T18:05:52Z,16728
dnut.rewrap-revived,2025-11-18T23:00:49Z,22785
dnut.rewrap-revived,2026-04-14T12:47:21Z,37438
dnut.rewrap-revived,2026-08-25T10:29:29.407Z,52049

Some things that would help:

  1. marketing of Rewrap Revived
    1. maybe also renaming / rebranding of this repo to be clear that it's a separate, new project
  2. if the original was unpublished or marked as unmaintained / deprecated
  3. further features only available in Rewrap Revived such as a CLI or a Prettier plugin

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions