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

@competitionlabs/gamification-widget-loader

v1.1.0

Published

Browser-side loader for the CompetitionLabs gamification widget. It retrieves the active widget configuration from the CompetitionLabs gateway, loads the JavaScript and CSS assets declared by that configuration, and mounts the widget in the containers sup

Readme

CompetitionLabs Gamification Widget Loader

Browser-side loader for the CompetitionLabs gamification widget. It retrieves the active widget configuration from the CompetitionLabs gateway, loads the JavaScript and CSS assets declared by that configuration, and mounts the widget in the containers supplied by the host application.

The package exposes a singleton at window.clLoaderV3.

Prerequisites

  • Node.js 22.16.0 (the version is defined in .nvmrc)
  • npm
  • A CompetitionLabs space name
  • A CompetitionLabs member ID from the host application's authenticated session
  • Access to a CompetitionLabs gateway, either directly with the required CORS configuration or through a same-origin backend proxy
  • A restricted API key for local testing, or a backend proxy that adds the API key server-side in production

Install and run the project

Clone the repository, select the expected Node.js version, and install the locked dependencies:

nvm use
npm ci

Start the Vite development server:

npm run dev

Vite opens the example page at /example/index.html. Update example/example.js with settings for a development environment before testing the widget.

Do not commit real API keys, production credentials, or member data to the example files.

Build

Create the production bundle with:

npm run build

Vite writes the following browser assets to dist/:

  • loader.js — IIFE browser bundle
  • loader.js.gz — gzip-compressed bundle
  • loader.js.br — Brotli-compressed bundle

Project scripts

| Command | Description | | --- | --- | | npm run dev | Starts Vite and opens the example page. | | npm run build | Builds the loader and its precompressed variants into dist/. | | npm run publish:restricted | Builds and publishes the npm package with restricted access. Requires npm registry authorization. | | npm test | Placeholder only; automated tests are not currently configured. |

Add the loader to a vanilla JavaScript application

The complete walkthrough is available in docs/GamificationWidgetVanillaJs.md. The essential setup is included below.

1. Install the package

npm install @competitionlabs/gamification-widget-loader

For an application that uses Vite or another bundler, import the package once in the browser entry point:

import '@competitionlabs/gamification-widget-loader';

For a site without a bundler, copy node_modules/@competitionlabs/gamification-widget-loader/dist/loader.js to a public vendor directory and load it before the site's application script:

<script src="/vendor/competitionlabs/loader.js"></script>
<script src="/js/main.js"></script>

Do not expose the entire node_modules directory from a production web server.

2. Add the widget containers

Both containers must exist before init() is called:

<body>
    <main>
        <div id="clv3WidgetMini"></div>
    </main>

    <div id="clv3Widget"></div>

    <script type="module" src="/src/main.js"></script>
</body>

3. Configure and initialise the loader

// src/main.js
import '@competitionlabs/gamification-widget-loader';

function initialiseGamificationWidget({
    apiKey = '',
    spaceName,
    memberId,
    language = 'en',
    themeMode = 'light',
    startMinimised = true,
}) {
    const loader = window.clLoaderV3;
    const expandedContainer = document.getElementById('clv3Widget');
    const minimisedContainer = document.getElementById('clv3WidgetMini');

    if (!loader) {
        throw new Error('CompetitionLabs widget loader was not created');
    }

    if (!expandedContainer || !minimisedContainer) {
        throw new Error('CompetitionLabs widget containers were not found');
    }

    // This example expects the host application to proxy gateway requests
    // through /cl_public and add the API key on the server.
    const gatewayDomain = new URL('/cl_public', window.location.origin)
        .toString()
        .replace(/\/$/, '');
    const gatewayWSDomain = `${window.location.protocol === 'https:' ? 'wss:' : 'ws:'}//${window.location.host}`;

    loader.settings.apiKey = apiKey;
    loader.settings.spaceName = spaceName;
    loader.settings.memberId = memberId;
    loader.settings.uri.gatewayDomain = gatewayDomain;
    loader.settings.uri.gatewayWSDomain = gatewayWSDomain;
    loader.settings.uomSymbol = '€';
    loader.settings.language = language;
    loader.settings.themeMode = themeMode;
    loader.settings.widgetStatus = 'Live';
    loader.settings.isWidgetMinimized = startMinimised;
    loader.settings.enableNotifications = false;
    loader.settings.bindContainer = expandedContainer;
    loader.settings.miniBindContainer = minimisedContainer;
    loader.settings.resources = [
        'https://fonts.googleapis.com/css2?family=Public+Sans:ital,wght@0,100..900;1,100..900&display=swap',
    ];

    loader.init(() => {
        console.log('CompetitionLabs widget initialised');
    });
}

initialiseGamificationWidget({
    spaceName: 'SPACE_NAME',
    memberId: 'MEMBER_ID',
});

Replace SPACE_NAME and MEMBER_ID with values from the target environment and authenticated user session. If the integration does not use a same-origin proxy, also set the gateway URLs and supply a restricted API key appropriate for that environment.

The loader requests the active widget configuration, then loads and initialises the script and styles associated with its layout. The gateway must allow the request and return a matching live widget from:

GET {gatewayDomain}/api/v1/{spaceName}/widget?status=Live&startDate<=...&endDate>=...&themeMode=LIGHT

Security note

An API key embedded in browser JavaScript is visible in page source, developer tools, and network requests. Use a restricted, short-lived non-production key only for local testing. In production, route the request through a backend proxy that adds the API key server-side and leave loader.settings.apiKey empty in the browser.

Optional hosted widget implementation

A compatible self-initialising widget build can be loaded before the loader and application scripts. For the type_2 theme:

<script src="https://assets.competitionlabs.com/gamification-widget/competitionlabs-gamification-widget-v3/themes/type_2/javascript/gamification-ux-package.v3-selfinit.js.gz"></script>
<script src="/vendor/competitionlabs/loader.js"></script>
<script src="/js/main.js"></script>

The hosted script provides window._clWidgetV32026SelfInit; it does not replace window.clLoaderV3 or the loader.init() call. When it is not preloaded, the loader uses the gateway configuration to select the correct implementation.

Loader lifecycle

Calling init() again reloads the widget configuration and replaces an existing widget instance. This is useful when the member, language, or theme changes.

To remove the widget completely:

window._clWidgetV32026?.destroy?.();
document.getElementById('clv3Widget')?.replaceChildren();
document.getElementById('clv3WidgetMini')?.replaceChildren();

Enable notifications only when the WebSocket or SSE channel is configured and reachable.

Project structure

loader.js                              Loader entry point and widget lifecycle
ajax.js                                Browser request helper
sizeof.js                              Small object/DOM utility
example/                               Local Vite example
docs/GamificationWidgetVanillaJs.md    Detailed vanilla JavaScript integration guide
vite.config.js                         Library build and compression configuration
dist/                                  Generated distribution files

Deployment

The Jenkins pipelines install dependencies, build the bundle, upload dist/ to the configured S3 prefix, attach the correct metadata to gzip and Brotli assets, and invalidate CloudFront for non-dry-run deployments. Deployments require the Jenkins AWS credentials and should first be verified with the DRY_RUN parameter enabled.

License

ISC