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 🙏

© 2024 – Pkg Stats / Ryan Hefner

@uppajung/hardy-har

v0.1.8

Published

A Hardy HTTP Archive (HAR) Generator

Downloads

593

Readme

Hardy-Har: A Hardy HTTP Archive (HAR) Generator

HTTP Archives (HARs) are the de-facto[^frozen] standard for exporting network debugger logs from browsers. The acronym HAR is used to refer to both the JSON object data format and the files into which the format is written, which use the extension .har.[^hardy-har-har]

This module will generate HTTP Archives in HAR format from Page. and Network. debugger events generated by the Chrome DevTools Protocol. These events can be recorded by browser extensions and via headless browser tools such as Puppeteer and Playwright[^playwright].

hardy-har is backwards compatible with the chrome-har API, from which it still borrows a small amount of code, a wealth of test cases, and a huge amount of expertise.[^port-or-rewrite] I created hardy-har because I wanted/needed:

  • support for archiving Web Sockets messages,
  • strong typings (a fully-typed all TypeScript codebase), and,
  • to understand the code well enough to be confident in its accuracy in a court of law.

Further, I wanted code that was I could easily understand. The code is architected with intention, using a declarative structure that ensures each value produced in a HAR archive can be traced to a single point of calculation. The style is intended not just to make the code easier to use, but to make it easier to read, maintain, verify, and debug: hardy.

Installation

NPM's algorithms wouldn't let me register hardy-har because it was too close to someone else's abandoned package. The joke's on them, because their algorithm allowed the next incremental option (in unary).

npm install @uppajung/hardy-har

Sample Use

From within a browser extension in strongly-typed TypeScript

// requires types from @types/chrome
import {
  type HarEvent,
  type HarEventNameAndObject,
  type DevToolsProtocolGetResponseBodyRequest,
  type DevToolsProtocolGetResponseBodyResponse,
  GetResponseBodyResponseMetaEventName,
  isHarEventName,
  harFromNamedDebuggerEvents,
} from "hardy-har";

export const recordBrowserTabToHarFromWithinExtension = async (
  tabId: number,
  executeBrowserTaskToRecord: () => Promise<void>
) => {
  const debuggerEventArray = [] as HarEventNameAndObject[]; 
  
  const onDebugEvent = async (source: chrome.debugger.Debuggee, eventName: string, event: unknown) => {
    // Ignore debugger events for other tabs
    if (source.tabId !== tabId) return;
    // Ignore events that aren't needed to generate HARs 
    if (!isHarEventName(eventName)) return;
    debuggerEventArray.push({eventName, event: event as HarEvent<typeof eventName>});

    if (eventName === 'Network.loadingFinished') {
      // The chrome Network protocol doesn't provide response bodies unless you ask.
      const requestId = (event as HarEvent<typeof eventName>).requestId;
      // Request the response body
      const responseBodyObj = (await (chrome.debugger.sendCommand(
        {tabId},
        "Network.getResponseBody",
        {requestId} satisfies DevToolsProtocolGetResponseBodyRequest)
      )) as DevToolsProtocolGetResponseBodyResponse | undefined;
      if (responseBodyObj != null) {
        // Record a meta event consisting of the requestId and the response body, as if the Chrome DevTools protocol
        // had been generous enough to volunteer this information without us begging for it.
        debuggerEventArray.push({
          eventName: GetResponseBodyResponseMetaEventName,
          event: {requestId, ...responseBodyObj} satisfies HarEvent<typeof GetResponseBodyResponseMetaEventName>
        });
      }
    }		
  }

  try {
    await chrome.debugger.attach({tabId}, '1.3');
    await chrome.debugger.sendCommand({tabId}, "Page.enable");
    await chrome.debugger.sendCommand({tabId}, "Network.enable");
    chrome.debugger.onEvent.addListener(onDebugEvent);

    await executeBrowserTaskToRecord();
    return harFromNamedDebuggerEvents(debuggerEventArray);

  } finally {
    await chrome.debugger.detach({tabId});
  }
}

As a drop-in replacement for chrome-har

Just replace harFromMessages with harFromChromeHarMessageParamsObjects. If you follow the chrome-har convention and embed captured response bodies to a network event, such as Network.loadingFinished, hardy-har should still find and include them.

import {harFromChromeHarMessageParamsObjects} from "jsr:@stuartschechter/hardy-har";

// ... follow chrome-har example to generate events and options

harFromChromeHarMessageParamsObjects(harEvents, options);

More info

For typings of the debugger events generated by the Chrome DevTools Protocol and consumed by this module, import the NPM devtools-protocol package.

For HAR format typings, use the NPM @types/har-format package.

To dos (help wanted)

  • Test cases for web sockets
  • Create additional test cases by recording a tab in Chrome via the debugger UI while also capturing the debugger API to generate a hardy-har .har. Then compare the two.
  • Add more examples.

[^playwright]: Though Playwright has built-in support for recording HAR files from its internal data structures and the code, while undocumented, looks fairly modern and well architected.

[^frozen]: The standard is "frozen" though supports extensions made by adding fields starting with underscores (_). Such extensions are how the "frozen" standard was extended by the Chrome Team to support Web Sockets.

[^hardy-har-har]: By implication, one might refer to a HTTP Archive file generated by this module as a hardy-har .har.

[^port-or-rewrite]: Whether hardy-har is a port or re-write of chrome-har is a question made largely irrelevant by the chrome-har team's generous use of the MIT License. Regardless, they are owed much gratitude.

License

Released under the MIT License.