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

@cmscure/javascript-sdk

v1.4.2

Published

Official JavaScript SDK for CMSCure content management platform

Readme

CMSCure JavaScript SDK

npm version GitHub release License: MIT TypeScript CDN CDN

The official CMSCure JavaScript SDK for web applications. Easily integrate dynamic content management, localization, and multi-language support into your web projects.

🚀 Get Started: Create your free account at app.cmscure.com and manage all your content from the powerful CMSCure Dashboard.

🔄 What’s New

  • Declarative bindings – reference any CMS value with strings like homepage:hero_title, color:primary_color, or image:logo and let resolve() / observe() keep your UI synced automatically.
  • Auto-realtime updatesobserve() handles caching, subscriptions, and socket re-syncs so you never wire contentUpdated listeners by hand.
  • Gateway-first networking – REST traffic is routed through https://gateway.cmscure.com while realtime sockets stay on wss://app.cmscure.com for the best mix of security and latency.
  • Immutable configuration – project ID, API key, and optional project secret are all you configure; endpoints are locked for consistency and safety.

✨ Key Features

  • 🌍 Multi-language Support: Seamless localization with automatic language resolution and instant switching.
  • 🎨 Dynamic Theming: Manage colors and themes from your CMSCure Dashboard with live cache refreshes.
  • 🖼️ Global Images: Centralized image management with CDN delivery and browser prefetching.
  • 📊 Data Stores: Structured data collections synced and cached for rapid UI updates.
  • 🔒 Secure: JWT-based authentication plus optional encrypted socket handshakes for real-time events.
  • 📦 Framework Agnostic: Works with vanilla JS, React, Next.js, Vue, Angular, and more.
  • 🎯 TypeScript Ready: Full TypeScript support with comprehensive type definitions.
  • ⚡ Fast & Offline Friendly: Persistent caching delivers instant loads and resilience during network hiccups.

🎛️ CMSCure Dashboard

All content management happens in your CMSCure Dashboard:

  • 📝 Content Editor: Create and manage strings, translations, and structured data
  • 🎨 Color Management: Define dynamic color schemes and themes
  • 📸 Asset Manager: Upload and organize images with automatic CDN optimization
  • 🌐 Language Manager: Configure locales and manage translations
  • 👥 Team Collaboration: Invite team members and manage permissions
  • 📊 Analytics: Track API usage and content performance
  • 🔄 Content Sync: Manage content updates from your dashboard

✨ New to CMSCure? Sign up for free and get your Project ID and API Key in minutes.

📦 Installation

NPM/Yarn (Recommended for frameworks)

npm install @cmscure/javascript-sdk
# or
yarn add @cmscure/javascript-sdk

CDN (For vanilla HTML/JS)

<!-- Latest version -->
<script src="https://cdn.jsdelivr.net/npm/@cmscure/javascript-sdk@latest/dist/cmscure.umd.min.js"></script>

<!-- Specific version (recommended) -->
<script src="https://cdn.jsdelivr.net/npm/@cmscure/[email protected]/dist/cmscure.umd.min.js"></script>

🏃‍♂️ Quick Start

Vanilla JavaScript/HTML

<!DOCTYPE html>
<html>
<head>
    <title>My App with CMSCure</title>
    <script src="https://cdn.jsdelivr.net/npm/@cmscure/[email protected]/dist/cmscure.umd.min.js"></script>
</head>
<body>
    <h1 data-cure="common:brand_name">[Brand Name]</h1>
    <p data-cure="homepage:hero_subtitle">[Hero Subtitle]</p>
    <button data-cure-color="secondary_button">Call To Action</button>
    <img data-cure-image="deals_banner" src="placeholder.jpg" alt="Deals Banner">

    <script>
        const cure = new CMSCureSDK();

        async function main() {
            await cure.configure({
                projectId: 'your-project-id',
                apiKey: 'your-api-key',
                projectSecret: 'optional-project-secret'
            });

            const brand = document.querySelector('[data-cure="common:brand_name"]');
            const subtitle = document.querySelector('[data-cure="homepage:hero_subtitle"]');
            const cta = document.querySelector('[data-cure-color="secondary_button"]');
            const banner = document.querySelector('[data-cure-image="deals_banner"]');

            cure.observe('common:brand_name', value => {
                if (brand) {
                    brand.textContent = value ?? '[common:brand_name]';
                }
            }, { defaultValue: '[common:brand_name]' });

            cure.observe('homepage:hero_subtitle', value => {
                if (subtitle) {
                    subtitle.textContent = value ?? '[homepage:hero_subtitle]';
                }
            }, { defaultValue: '[homepage:hero_subtitle]' });

            cure.observe('color:secondary_button', value => {
                if (cta && typeof value === 'string') {
                    cta.style.backgroundColor = value;
                }
            }, { defaultValue: '#663BEB' });

            cure.observe('image:deals_banner', value => {
                if (banner && typeof value === 'string') {
                    banner.src = value;
                }
            }, { defaultValue: null });
        }

        main();
    </script>
</body>
</html>

React/Next.js

import { useEffect, useMemo, useState } from 'react';
import { CMSCureSDK } from '@cmscure/javascript-sdk';

const App = () => {
  const sdk = useMemo(() => new CMSCureSDK(), []);
  const [heroTitle, setHeroTitle] = useState('[homepage:hero_title]');
  const [heroSubtitle, setHeroSubtitle] = useState('[homepage:hero_subtitle]');
  const [heroImage, setHeroImage] = useState<string | null>(null);
  const [buttonColor, setButtonColor] = useState('#663BEB');

  useEffect(() => {
    void sdk.configure({
      projectId: process.env.NEXT_PUBLIC_CMSCURE_PROJECT_ID,
      apiKey: process.env.NEXT_PUBLIC_CMSCURE_API_KEY,
      projectSecret: process.env.NEXT_PUBLIC_CMSCURE_SECRET,
      defaultLanguage: 'en'
    });

    const unsubscribeTitle = sdk.observe('homepage:hero_title', value => {
      setHeroTitle(typeof value === 'string' && value ? value : '[homepage:hero_title]');
    }, { defaultValue: '[homepage:hero_title]' });

    const unsubscribeSubtitle = sdk.observe('homepage:hero_subtitle', value => {
      setHeroSubtitle(typeof value === 'string' && value ? value : '[homepage:hero_subtitle]');
    }, { defaultValue: '[homepage:hero_subtitle]' });

    const unsubscribeImage = sdk.observe('image:deals_banner', value => {
      setHeroImage(typeof value === 'string' && value ? value : null);
    }, { defaultValue: null });

    const unsubscribeColor = sdk.observe('color:secondary_button', value => {
      setButtonColor(typeof value === 'string' && value ? value : '#663BEB');
    }, { defaultValue: '#663BEB' });

    return () => {
      unsubscribeTitle();
      unsubscribeSubtitle();
      unsubscribeImage();
      unsubscribeColor();
    };
  }, [sdk]);

  return (
    <section>
      <h1>{heroTitle}</h1>
      <p>{heroSubtitle}</p>
      {heroImage && <img src={heroImage} alt="Deals" />}
      <button style={{ backgroundColor: buttonColor }}>Learn more</button>
    </section>
  );
};

export default App;

Vue.js

<template>
  <div>
    <h1>{{ title }}</h1>
    <p>{{ subtitle }}</p>
    <img v-if="heroImage" :src="heroImage" alt="Hero" />

    <select v-model="language" @change="setLanguage(language)">
      <option v-for="lang in languages" :key="lang" :value="lang">
        {{ lang.toUpperCase() }}
      </option>
    </select>
  </div>
</template>

<script>
import CMSCureSDK from '@cmscure/javascript-sdk';

const cure = new CMSCureSDK();

export default {
  name: 'App',
  data() {
    return {
      title: '[common:brand_name]',
      subtitle: '[homepage:hero_subtitle]',
      heroImage: null,
      languages: ['en'],
      language: 'en',
      unsubscribers: []
    };
  },
  async mounted() {
    await cure.configure({
      projectId: 'your-project-id',
      apiKey: 'your-api-key',
      projectSecret: import.meta.env.VITE_CMSCURE_SECRET
    });

    this.unsubscribers = [
      cure.observe('common:brand_name', value => {
        this.title = typeof value === 'string' && value ? value : '[common:brand_name]';
      }, { defaultValue: '[common:brand_name]' }),
      cure.observe('homepage:hero_subtitle', value => {
        this.subtitle = typeof value === 'string' && value ? value : '[homepage:hero_subtitle]';
      }, { defaultValue: '[homepage:hero_subtitle]' }),
      cure.observe('image:deals_banner', value => {
        this.heroImage = typeof value === 'string' && value ? value : null;
      }, { defaultValue: null }),
      cure.observe('meta:languages', value => {
        this.languages = Array.isArray(value) && value.length ? value : ['en'];
      }, { defaultValue: ['en'] }),
      cure.observe('meta:language', value => {
        this.language = typeof value === 'string' && value ? value : 'en';
      }, { defaultValue: 'en' })
    ];
  },
  beforeUnmount() {
    this.unsubscribers.forEach(unsubscribe => unsubscribe());
  },
  methods: {
    setLanguage(lang) {
      void cure.setLanguage(lang);
    }
  }
};
</script>

🎯 API Reference

Configuration

const cure = new CMSCureSDK();

await cure.configure({
  projectId: 'your-project-id',          // Required
  apiKey: 'your-api-key',                // Required
  defaultLanguage: 'en',                 // Optional preferred language
  projectSecret: 'your-project-secret'   // Optional: enables realtime sockets
});

Note: Endpoints are fixed for security. REST requests are proxied through https://gateway.cmscure.com and realtime sockets connect to wss://app.cmscure.com.

Methods

translation(key: string, tab: string, defaultValue?: string): string

Get a translation for a specific key and tab. Automatically caches and subscribes to realtime updates for that tab.

const title = cure.translation('hero_title', 'homepage', '[homepage:hero_title]');

image(key: string, defaultValue?: string | null): string | null

Get a global image URL by key. Image URLs are cached and prefetched for smooth rendering.

const heroBanner = cure.image('deals_banner');

color(key: string, defaultValue?: string | null): string | null

Get a color value by key. Colors stay cached and refresh silently when changed.

const primary = cure.color('primary_color', '#663BEB');

dataStore(apiIdentifier: string, defaultValue?: any[]): any[]

Get data store items by API identifier. Stores are cached and resynced when updates arrive.

const products = cure.dataStore('products', []);

resolve(reference: string, defaultValue?: any): any

Resolve a CMSCure reference string. Supports translations (homepage:hero_title), colors (color:primary_color), images (image:logo), data stores (store:products), and metadata (meta:language).

const heroTitle = cure.resolve('homepage:hero_title');
const accentColor = cure.resolve('color:primary_accent', '#3B82F6');
const languages = cure.resolve('meta:languages', ['en']);

observe(reference: string, listener: (value: any, detail?: { reason?: string }) => void, options?: { defaultValue?: any }): () => void

Observe a CMSCure reference and receive callbacks whenever the underlying value changes. Returns an unsubscribe function.

const unsubscribe = cure.observe('homepage:hero_title', (value, detail) => {
  document.querySelector('#hero-title').textContent = value;
  console.log('Updated because:', detail?.reason);
});

setLanguage(language: string): Promise<void>

Switch the active language. Automatically triggers background resyncs and realtime updates.

getLanguage(): string

Get the current language. Alias: getCurrentLanguage().

getAvailableLanguages(): string[]

List the languages exposed by the project.

Backend Locale Utilities

detectLocaleFromRequest(req, options?)

Normalize incoming locale hints (query/body language, X-Locale, locale/lang, Accept-Language) and return the detected language plus metadata.

import { detectLocaleFromRequest } from '@cmscure/javascript-sdk';

app.get('/api/custom', (req, res) => {
  const localeInfo = detectLocaleFromRequest(req, { availableLanguages: ['en', 'fr'] });
  const copy = fetchLocalizedCopy(localeInfo.detected);
  res.json({ locale: localeInfo.detected, copy });
});

createLocaleMiddleware(options?)

Express-style middleware that populates req.locale / req.localeInfo and sets helpful response headers for debugging.

import express from 'express';
import { createLocaleMiddleware } from '@cmscure/javascript-sdk';

const app = express();
app.use(express.json());
app.use(createLocaleMiddleware({ availableLanguages: ['en', 'de'], fallback: 'en' }));

app.get('/api/profile', (req, res) => {
  res.json({ locale: req.locale, message: translate('profile_welcome', req.locale) });
});

🔄 Runtime Behaviour

Automatic Language Resolution

On first load the SDK restores any previously selected language. If none is stored it prefers defaultLanguage, then matches the browser locale (full and base codes), and finally falls back to English. Calling setLanguage() persists the choice and triggers targeted resyncs for the new language.

Caching Strategy

  • Translations, colors, images, and data stores are cached in local storage after every sync.
  • Cached values are returned instantly while background fetches refresh data on cache misses, language changes, and socket events.
  • Image URLs are prefetched into the browser cache to minimize flicker on render.

Binding Helpers

  • resolve(reference) returns the current value for any CMS reference string.
  • observe(reference, listener) keeps your UI in sync; it immediately calls the listener with cached data and replays updates whenever the SDK receives new content (Initial sync, language changes, realtime events, or manual refreshes).

Real-time Updates

Provide projectSecret during configure() to opt into live updates. The SDK performs an AES-GCM handshake and listens for translation, color, image, and data store events. Each event triggers a narrow resync and emits contentUpdated; language switches also emit languageChanged.

await cure.configure({
  projectId: 'your-project-id',
  apiKey: 'your-api-key',
  projectSecret: 'your-project-secret' // Enables sockets
});

const unsubscribe = cure.observe('homepage:hero_title', (value, detail) => {
  console.log('Content refreshed because:', detail?.reason);
  document.querySelector('#hero-title').textContent = value;
});

Events

  • contentUpdated – fires after cache refreshes triggered by initial sync, cache misses, language changes, or real-time updates. Inspect event.detail.reason for context (e.g., InitialSyncComplete, LanguageChange, RealtimeUpdate).
  • languageChanged – fires when the active language changes, providing the previous and new codes.

🎨 Styling with Dynamic Colors

:root {
  --primary-color: #007bff; /* fallback */
  --secondary-color: #6c757d; /* fallback */
}

.button-primary {
  background-color: var(--primary-color);
}
// Update CSS variables with CMSCure colors
cure.addEventListener('contentUpdated', () => {
  const primaryColor = cure.color('primary_color');
  const secondaryColor = cure.color('secondary_color');
  
  if (primaryColor) {
    document.documentElement.style.setProperty('--primary-color', primaryColor);
  }
  if (secondaryColor) {
    document.documentElement.style.setProperty('--secondary-color', secondaryColor);
  }
});

📱 Framework-Specific Guides

Next.js App Router

// app/components/CMSProvider.jsx
'use client';

import { createContext, useContext, useEffect, useState } from 'react';
import CMSCureSDK from '@cmscure/javascript-sdk';

const CMSContext = createContext();
const cure = new CMSCureSDK();

export function CMSProvider({ children, projectId, apiKey }) {
  const [isReady, setIsReady] = useState(false);

  useEffect(() => {
    cure.configure({
      projectId,
      apiKey,
      projectSecret: process.env.NEXT_PUBLIC_CMSCURE_SECRET
    }).then(() => setIsReady(true));
  }, [projectId, apiKey]);

  if (!isReady) return <div>Loading...</div>;

  return (
    <CMSContext.Provider value={cure}>
      {children}
    </CMSContext.Provider>
  );
}

export const useCMS = () => useContext(CMSContext);

export function HeroSection() {
  const cure = useCMS();
  const [title, setTitle] = useState('[homepage:hero_title]');

  useEffect(() => {
    const unsubscribe = cure.observe('homepage:hero_title', value => {
      setTitle(typeof value === 'string' && value ? value : '[homepage:hero_title]');
    }, { defaultValue: '[homepage:hero_title]' });

    return () => unsubscribe();
  }, [cure]);

  return <h1>{title}</h1>;
}

Nuxt.js Plugin

// plugins/cmscure.client.js
import CMSCureSDK from '@cmscure/javascript-sdk';

export default defineNuxtPlugin(async () => {
  const cure = new CMSCureSDK();
  
  await cure.configure({
    projectId: useRuntimeConfig().public.cmscureProjectId,
    apiKey: useRuntimeConfig().public.cmscureApiKey,
    projectSecret: useRuntimeConfig().public.cmscureProjectSecret
  });

  return {
    provide: {
      cure
    }
  };
});

🔧 Advanced Configuration

Error Handling

cure.addEventListener('error', (event) => {
  console.error('CMSCure error:', event.detail);
  // Implement fallback behavior
});

🏗️ Building from Source

# Clone the repository
git clone https://github.com/cmscure/javascript-sdk.git
cd javascript-sdk

# Install dependencies
npm install

# Build for development
npm run build:dev

# Build for production
npm run build:prod

# Run tests
npm test

# Lint code
npm run lint

📚 Examples

Check out our examples directory for complete working examples:

🆘 Support

🤝 Contributing

We welcome contributions! Please see our Contributing Guide for details.

📄 License

MIT © CMSCure