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

@geoleaf-plugins/connector

v1.3.2

Published

GeoLeaf Connector Plugin — Universal fetch interceptor for authenticated GeoJSON, FlatGeobuf, KML, CSV and OGC API data sources

Readme

@geoleaf-plugins/connector

MIT plugin for GeoLeaf — transparent authentication and Authorization header injection on every GeoJSON / WFS / REST fetch request.

npm License: MIT


Installation

npm install @geoleaf-plugins/connector

Important — Requires @geoleaf/core v3.x, declared as a peer dependency: install it yourself — the plugin uses your copy, and never bundles a second one.


Quick start

Static token — scenario S6 in the table below, for development and public demos:

<script type="module" src="geoleaf-connector.plugin.js"></script>
<script>
    GeoLeaf.Connector.configure({
        baseUrl: "http://localhost:3000",
        getToken: () => "MY_DEV_TOKEN",
    });
</script>

Note — A console.warn is emitted when the token contains no . (not a JWT). This is expected in development mode.


Usage scenarios

| Scenario | Config | Use case | | -------- | ------------------------------------------- | ----------------------------------------- | | S1 | getToken: () => 'static' | Development / smoke test without a server | | S2 | auth: { endpoint, ui: true } | Login modal + JWT + auto refresh (IDB) | | S3 | getToken: () => localStorage.getItem(...) | Existing SSO — external token | | S4 | getToken: async () => await myAuth.get() | Async provider (any identity SDK) | | S5 | auth: { endpoint, ui: false } | Token preloaded in IDB — silent | | S6 | getToken: () => 'STATIC_DEV_TOKEN' | Non-sensitive data, public demo |


What the server must answer

There are two modes, getToken and auth, and no API-key mode: a key is handed over by getToken and travels as Authorization: Bearer <key>. The exchange the auth mode expects — POST {endpoint} with { login, password }, a { token, expiresIn } answer, renewal at POST {endpoint}/refresh with the current token as Bearer, and how every status is read — is written once, in §3 of the server contract.

A server that speaks another dialect — an OAuth 2 token endpoint answering access_token, a key read from a header of its own — is served in one of two ways, both described in §7.6 of the security guide: getToken with the page's own client, or a thin adapter on the server that answers the contract.


API

GeoLeaf.Connector.configure(config)

await GeoLeaf.Connector.configure({
    baseUrl: "https://api.example.com",
    getToken: () => "JWT_TOKEN",
    // — OR —
    auth: {
        endpoint: "https://api.example.com/auth/login",
        ui: true, // Show login modal if no valid token found
        signupUrl: "https://app.example.com/signup", // "Create an account" link (optional)
        forgotPasswordUrl: "https://app.example.com/forgot", // "Forgot password" link (optional)
        credentialButton: {
            enabled: true, // Auto-inject credential button in UI
            iconVariant: "lock", // "lock" (default) or "user"
        },
    },
});

getToken and auth are mutually exclusive.

With getToken, the provider is called for every request that needs the token: each intercepted fetch, each vector tile, each GeoJSON load the worker makes. Nothing keeps a copy. A provider that answers with a promise reaches the tiles on MapLibre 5.21 or later, and the GeoJSON worker on @geoleaf/core 3.4.0 or later; older versions send those requests without a token. A provider that throws or rejects fails the page's request with its error, while tiles and worker loads go without a token until it answers again.

GeoLeaf.Connector.openLoginModal()

Opens the login modal manually. Requires a prior configure() call carrying auth.

GeoLeaf.Connector.openLoginModal();

createConnector(config) — ESM named export

For advanced integration cases and unit tests:

import { createConnector } from "@geoleaf-plugins/connector";

const conn = createConnector({ baseUrl: "...", getToken: () => "TOKEN" });
const token = await conn.getTokenAsync();
conn.destroy();

The instance installs no fetch interception, worker hook, tile bridge or renewal delegate, and never opens the login window, auth.ui included. With auth.endpoint, it renews its own reads against its endpoint, and destroy() only deactivates its token reads: the configure() singleton's session, renewal included, is never its business. ⚠️ A session is still a baseUrl's: an instance and configure() on the same API share the stored token.


DOM events

| Event | Detail | Fired when | Cancelable | | --------------------------------------------- | ---------------------------- | --------------------------- | ---------- | | geoleaf:connector:authenticated | { baseUrl } | Login modal succeeded | No | | geoleaf:connector:token-refreshed | { baseUrl } | Automatic renewal succeeded | No | | geoleaf:connector:auth-error | { baseUrl, error } | The session ended: refused | No | | geoleaf:connector:credential-button-clicked | { baseUrl, authenticated } | Credential button clicked | No | | geoleaf:connector:signup-requested | { url } | "Create an account" clicked | Yes | | geoleaf:connector:forgot-password-requested | { url } | "Forgot password" clicked | Yes |

The cancelable events let the host application intercept the default behaviour through preventDefault():

document.addEventListener("geoleaf:connector:signup-requested", (e) => {
    e.preventDefault(); // Prevents the link from opening
    myApp.showCustomSignup(); // Show a custom UI instead
});
document.addEventListener("geoleaf:connector:authenticated", (e) => {
    console.log("Authenticated on", e.detail.baseUrl);
});

When the authentication server cannot be reached

auth-error means the session ended: the renewal was refused (a 401, a 403, no renewal offered, an answer that cannot be used). A renewal that could not conclude — no network, a time-out, a 503, a body cut in transit — keeps the session and fires nothing:

  • a request that met a 401 gets it back, and the core's drain waits for the session;
  • configure() resolves when a stored session cannot be renewed right now — with or without auth.ui — instead of opening a login window that needs the missing network;
  • the renewal is tried again when the network returns, when the application comes back to the foreground, and when a capture enters the offline queue. Online, in the foreground and with no new capture, it waits for the next of those moments.

A server that renews the session and then refuses the token it has just issued — a signing key out of step between two nodes, a wrong audience — is treated the same way: the session is kept, the request gets its 401, and no renewal is tried again for as long as one renewal exchange may take, except at the moments above. Without that pause, each refused request renewed again, and the offline queue's resume could loop on it.

What a returning session does to the offline queue

When the session had died, the core's drain stopped at the first 401 and set that capture aside; it cannot see a sign-in, so it waits. On authenticated and on token-refreshed naming its session — the baseUrl given to configure() — this plugin therefore asks the core to take them back, through two public calls:

await GeoLeaf.Storage.requeueAll("authRequired");
await GeoLeaf.Storage.pushOutbox();

An application that signs in by its own means makes exactly those two calls. Without the offline capability, there is nothing to resume and nothing happens. The session of another API coming back — an instance of createConnector(), another copy of this plugin — resumes nothing.

A session can also come back before the offline engine does: a configure() called before GeoLeaf.boot() renews an expired session while GeoLeaf.Storage has no engine yet, and both calls answer engineUnavailable. The plugin then waits for GeoLeaf.Storage.whenReady(), lets the core's own first pass end, and makes the two calls — once per page, however many renewals came before.


Security

  • The token is never passed in a query string.
  • Passwords are wiped from memory after use (OWASP A02).
  • baseUrl must use HTTPS in production (an error is raised otherwise). http:// is tolerated, with a console warning, only when the page runs on a development host — localhost, *.localhost, the loopback addresses, or a name under .test, reserved for testing (RFC 6761).
  • The modal's XSS sanitisation relies on textContent — no innerHTML with user data.
  • Vector tiles (MVT) get the token through map.setTransformRequest() (MapLibre bridge); PMTiles archives through window.fetch, which the pmtiles library reads them with.

License

MIT — see LICENSE.