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 🙏

© 2026 – Pkg Stats / Ryan Hefner

protocolloadfallbackhandler

v4.0.0

Published

Allows the registration of custom protocol handlers to load resources if the browser fails to load the resource

Readme

protocolloadfallbackhandler.js

Currently, when adding an <img> or <video> to a webpage or when doing a fetch() or using an XMLHttpRequest in js, most browsers will only support http and https URLs. Specify a magnet uri as image source, for example, and it probably just won't work at all. The idea behind protocolloadfallbackhandler.js is to first give the browser a chance to load the resource, and if it fails, check if a protocol handler for that protocol has been specified, and if there is one, use it to load the resource. Changing what happens when such URIs are opened, however, is out of scope of this project and can already be changed by other means.

APIs

Protocol Handlers

Protocol handlers are used as a fallback if the browser fails to load a resource from a URI depending on the URI scheme. A protocol handler needs at least the fetch or the makeVirtualURI API. The fetch API is preferred, since a resource can sometimes be used before it is fully loaded, but can be tricky to get right, while makeVirtualURI is easier to implement.

You can register a resource handler using the protocolLoadFallbackHandler.setHandler("scheme",your_handler).

| Method | Description | | ------ | ----------- | | fetch | Must be a full implementation of the fetch Interface that can handle the scheme it was registered for | | makeVirtualURI(uri) | Make an URL from the URI the browser can understand | | renderTo(element,uri) | Use the URI as source for an element in a unknown special way. |

Globals

| Name | What | Default | Purpose | | ---- | ---- | ------- | ------- | | protocolLoadFallbackHandler | ProtocolLoadFallbackHandler | | The only instance of the ProtocolLoadFallbackHandler class. | | sourceIntercepter | SourceIntercepter | | Only instance of the SourceIntercepter class. | | CSSSourceIntercepter | CSSSourceIntercepter | | The only instance of the CSSSourceIntercepter class. | | URIMapCacher | URIMapCacher | | The only instance of the URIMapCacher class. | | ProtocolLoadFallbackHandlerError (message,soft) | class | | For creating errors originating from protocol handlers. The soft parameter indicates if the proxy url should be tried as a fallback if possible. | | nodeTypes | Map | | A Node type name -> Node type map. | | replaceFetch | Boolean | true | Specifies wether fetch should be replaced so it can handle registered protocols. | | nativeFetch | Function | | A reference to the browsers own fetch function | | replaceXMLHttpRequest | Boolean | true | Specifies wether XMLHttpRequest should be replaced so it can handle registered protocols. | | nativeXMLHttpRequest | Function | | A reference to the browsers own XMLHttpRequest class | | serviceWorkerDoesHandleLoadFallbackHandlers | Boolean | false | Wether a service worker shall handle registered protocols. | | serviceWorkerPrefix | string | location.origin + "/proxy/" | If there is a service worker capable of handling registered protocols, requests it shall handle will be passed to it as an url of the form serviceWorkerPrefix + btoa(URI). | | fallbackProxyAvailable | Boolean | false | Wether there is a proxy for handling requests the registered protocol handlers couldn't handle. | | proxybase | string | location.origin + "/proxy/" | The url of a proxy for handling failed requests. Such requests will be passed to it as an url of the form proxybase + btoa(URI). |

ProtocolLoadFallbackHandler

This class detects if loading a resource failed, and tries to use the registered protocol handlers if that is the case. It's also used to register protocol handlers. By itself, it only gets errors from nodes attached to the document body. It can be informed of errors from other sources using the onerror(event) method.

| Method | Description | | ------ | ----------- | | getHandler(scheme) | Returns the protocol handler for the given scheme using a promise. | | setHandler(scheme,handler) | Set a protocol handler for a specific URI scheme | | removeHandler(scheme) | Remove a protocol handler | | renderTo(element,uri) | Try to apply the URI to an element. This allows the usage of the MediaSource API and similar stuff. | | fetch | Same as a browsers fetch method, except that it tries to use the registered protocol handlers as a fallback | | makeVirtualURI(uri) | Try to create a URL from an URI that the Browser actually supports. Consider using renderTo or fetch instead whenever possible. |

SourceIntercepter

Intercepts the src and href properties of every Node instance, and renames the original ones to nativeSrc/nativeHref. This allows the ProtocolLoadFallbackHandler to set a blob url or something similar for the browser to load the resource from while not changing the uri where the resurece was actually loaded from. When setting a source using one of these Attributes, it will also register an error handler to inform the ProtocolLoadFallbackHandler when loading one of the resources fails. This is necessary because an element may not been attached to the document in some cases, like when loading images to draw in a canvas for example.

It also sets the class "loading", "ready", "loaded", "loaderror" or none when the loadState property of an element is set to one of them. The SourceIntercepter and ProtocolLoadFallbackHandler also try to set that property as accurately as possible, but since there is no unified way to figure out if a resource is loaded, loaded, or the loading failed, and sometimes there is none at all, it's not perfectly accurate and sometimes not set at all.

The SourceIntercepter also defines the property $sourcelock as a boolean for every html element. It's a workaround to only change the source of an element to load when changing the src or href properties, but not the values they return, which is necessary if a fallback protocol handler sets it using an independent library function that doesn't use this library to set the source. The ProtocolLoadFallbackHandler usually takes care of setting this property when necessary.

| Method | Description | | ------ | ----------- | | getNativeURI(element) | Get the URI the browser actually used to get the resource from | | setNativeURI(element,uri) | Set the URL to load, but don't modify the true URI of the resource or what getSource returns. |

CSSSourceIntercepter

Intercepts every CSS property that can take an image URL, uses the ProtocolLoadFallbackHandler to determine wheter the browser can handle the URI on it's own and tries to use the protocol handlers using the ProtocolLoadFallbackHandler class to load the images anyway.

| Method | Description | | ------ | ----------- | | CSSUnescape(value) | Unescape CSS Properties, reverses CSS.escape | | getCSSURIs(value) | Extract URIs from CSS String | | CSSURIReplace(value,uri,url) | Replace all occurances of url(uri) in value by url(url) |

URIMapCacher

Keeps track of URI => URL mappings. It's also an event target. Setting an url creates either a "newurl" or a "urlchange" event. If a mapping is removed, a "removed" event is generated.

| Method | Description | | ------ | ----------- | | getURL(uri) | Lookup the url for an uri. May return null, a string, or a promise returning null or a string. Also increments the url reference count. | | getURI(url) | Lookup the uri for an url. Returns the uri as a string, or null if not found | | set(uri,url) | Set a url for the uri. If a url for the uri is already set, override it. The url can be a promise or string, but the uri must be a string. Increments the url reference count. | | release | Decrements the url reference count. If it reaches 0, the uri => url mapping is remved. |

Events

Error events

While the ProtocolLoadFallbackHandler tries to stop the propagation of error events if a fallback is available and creates one if an unrecoverable error occures, it's not reliable. Because of this, if all fallbacks fail, it will also create a custom "loaderror" event, which is an instance of ErrorEvent. The "loaderror" event is cancellable. The ProtocolLoadFallbackHandler only sets the loadState property of an element to "loaderror" if the "loaderror" event wasn't cancelled. Other events indicating the start, end, etc. of resource loading should work as expected.

Custom events

| Name | detail property type | Description | | ---- | ----------------- | ----------- | | stylesheetadded | CSSStyleSheet | A new stylesheet was attached to the document. | | stylesheetremoved | CSSStyleSheet | A new stylesheet was removed from the document. |