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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@netgen/storyblok-siteaccess

v0.1.10

Published

Generic siteaccess management for multi-market, multi-language Storyblok websites

Readme

@netgen/storyblok-siteaccess

Generic siteaccess management for multi-market, multi-language Storyblok websites.

Features

  • Generic & Type-safe: Works with any market/language structure using TypeScript generics
  • URL Generation: Convert between Storyblok paths, URLs, and pathnames
  • Multi-market Support: Handle multiple markets with different languages
  • Alternate Language Management: Generate language/market alternatives for SEO
  • Framework Agnostic Core: Works with any framework, with optional React hooks
  • Environment Management: Support for different environments (dev, prod, etc.)
  • Next.js Integration: Built-in utilities for Next.js routing and redirects
  • Internationalization: Generate next-intl routing configurations automatically

Installation

npm install @netgen/storyblok-siteaccess

Basic Usage

1. Define Your Types

// Your project types
export enum Market {
  us = 'us',
  uk = 'uk',
  de = 'de'
}

export enum Language {
  en = 'en',
  de = 'de'
}

// Type your configurations
export type ProjectSiteaccessConfig = SiteaccessConfig<Market, Language>;
export type ProjectEnvironmentConfig = EnvironmentConfig<Market, Language>;

2. Create Configuration

import { SiteaccessResolver, Siteaccess } from '@netgen/storyblok-siteaccess';

const environmentConfig: ProjectEnvironmentConfig = {
  siteaccess: [
    {
      host: 'example.com',
      locale: 'en',
      market: Market.us,
      language: Language.en,
      storyblokFolderPrefix: 'us',
      storyblokVisualEditorPrefix: 'us',
    },
    {
      host: 'example.de',
      locale: 'de',
      market: Market.de,
      language: Language.de,
      storyblokFolderPrefix: 'de',
      storyblokVisualEditorPrefix: 'de',
    }
  ],
  marketConfigs: {
    [Market.us]: {
      primaryLanguage: Language.en,
      tosStoryblokPath: 'terms-of-service'
    },
    [Market.de]: {
      primaryLanguage: Language.de,
      tosStoryblokPath: 'nutzungsbedingungen'
    }
  },
  siteinfoIds: {
    [Market.us]: 'us-siteinfo-id',
    [Market.de]: 'de-siteinfo-id'
  },
  partnersFolderStoryblokPrefix: 'partners',
  hosts: [
    { host: 'example.com', defaultLocale: 'en' },
    { host: 'example.de', defaultLocale: 'de' }
  ]
};

// Create resolver
const siteaccessResolver = new SiteaccessResolver(
  environmentConfig.siteaccess,
  environmentConfig
);

3. Use Siteaccess

// Resolve configuration
const config = siteaccessResolver.resolveByLocale({ locale: 'en' });

// Create siteaccess instance
const siteaccess = new Siteaccess(config, environmentConfig);

// Generate URLs
const url = siteaccess.getUrl({ storyblokPath: 'about' });
// Result: 'https://example.com/about'

const storyblokPath = siteaccess.getStoryblokPath({ pathname: '/about' });
// Result: 'us/about'

React Integration

Basic Hook Usage

import { useSiteaccess } from '@netgen/storyblok-siteaccess';

function MyComponent() {
  const siteaccess = useSiteaccess(siteaccessConfig, environmentConfig);
  
  const aboutUrl = siteaccess.getUrl({ storyblokPath: 'about' });
  
  return <a href={aboutUrl}>About Us</a>;
}

Create Project-Specific Hook

import { createSiteaccessHook } from '@netgen/storyblok-siteaccess';

// Create your typed hook
export const useProjectSiteaccess = createSiteaccessHook<Market, Language>(
  () => getCurrentSiteaccessConfig(),
  () => environmentConfig
);

// Use in components
function MyComponent() {
  const siteaccess = useProjectSiteaccess();
  // Fully typed with your Market and Language enums
}

Advanced Features

Market Alternates

const alternates = siteaccess.getMarketAlternates(
  Object.values(Market), // All available markets
  { storyblokAlternates: story.alternates }
);

// Result: Array of alternate URLs for different markets

Language Validation

const isValid = siteaccess.isStoryLanguageTranslationValid(story);
// Checks if the current language has a valid translation

Storyblok API Integration

const storyblokLanguage = siteaccess.getStoryblokLanguage();
// Returns 'default' for primary language, actual language code otherwise

const apiLanguage = siteaccess.getLanguageForStoryblok();
// Returns undefined for primary language, language code otherwise

Client/Server Resolution

Next.js Example

import { 
  createLocaleBasedClientResolver,
  createLocaleBasedServerResolver,
  createUniversalSiteaccessResolver 
} from '@netgen/storyblok-siteaccess';
import { useLocale } from 'next-intl';
import { getLocale } from 'next-intl/server';

// Create resolvers
const clientResolver = createLocaleBasedClientResolver(
  useLocale,
  (locale) => siteaccessResolver.resolveByLocale({ locale })
);

const serverResolver = createLocaleBasedServerResolver(
  getLocale,
  (locale) => siteaccessResolver.resolveByLocale({ locale })
);

const universalResolver = createUniversalSiteaccessResolver(
  clientResolver,
  serverResolver
);

// Use in your app
export const getCurrentSiteaccessConfig = {
  client: universalResolver.client,
  server: universalResolver.server
};

API Reference

Classes

  • Siteaccess<TMarket, TLanguage>: Main class for URL generation and path conversion
  • SiteaccessResolver<TMarket, TLanguage>: Resolves siteaccess configurations based on various criteria

Types

  • SiteaccessConfig<TMarket, TLanguage>: Configuration for a single siteaccess
  • EnvironmentConfig<TMarket, TLanguage>: Complete environment configuration
  • AlternateStory<TMarket, TLanguage>: Language/market alternate information
  • SiteaccessInputType: Input union type for path conversion methods

Hooks

  • useSiteaccess(): React hook for creating Siteaccess instances
  • createSiteaccessHook(): Factory for creating project-specific hooks

Resolvers

  • createClientSiteaccessResolver(): Create client-side resolver
  • createServerSiteaccessResolver(): Create server-side resolver
  • createUniversalSiteaccessResolver(): Create universal resolver

Migration from Project-Specific Implementation

  1. Extract your types: Move Market/Language enums to your project
  2. Update imports: Import from @netgen/storyblok-siteaccess
  3. Add type parameters: Add <Market, Language> to class instantiations
  4. Update configurations: Move environment configs to your project
  5. Create typed hooks: Use createSiteaccessHook() for React integration

Next.js Integration

Automatic Routing Configuration

Generate Next.js internationalization routing from your environment config:

import { generateNextIntlRouting } from '@netgen/storyblok-siteaccess';
import { defineRouting } from 'next-intl/routing';

// Generate routing configuration
const routingConfig = generateNextIntlRouting(environmentConfig, {
  defaultLocale: 'en',
  alternateLinks: false,
  localeCookie: false,
  localePrefix: { mode: 'always' }
});

export const routing = defineRouting(routingConfig);

Storyblok Visual Editor Redirects

Generate redirects for Storyblok's visual editor:

import { generateStoryblokRedirects } from '@netgen/storyblok-siteaccess';

// Generate redirects
export const storyblokRedirects = generateStoryblokRedirects(environmentConfig, {
  permanent: false
});

// Use in next.config.js
module.exports = {
  async redirects() {
    return storyblokRedirects;
  }
};

Utility Functions

import {
  getLocales,
  getHosts,
  getDomainConfig,
  isValidLocale,
  getDefaultLocaleForHost
} from '@netgen/storyblok-siteaccess';

// Get all locales
const locales = getLocales(environmentConfig);

// Check if locale is valid
const isValid = isValidLocale(environmentConfig, 'en-US');

// Get domain configuration
const domainConfig = getDomainConfig(environmentConfig, 'example.com');

Integration with next-intl

import { isValidLocale } from '@netgen/storyblok-siteaccess';
import { getRequestConfig } from 'next-intl/server';

export default getRequestConfig(async ({ requestLocale }) => {
  const locale = await requestLocale;

  // Validate locale using the package utility
  if (!isValidLocale(environmentConfig, locale)) {
    // Handle invalid locale
    return { locale: 'en', messages: {} };
  }

  return {
    locale,
    messages: (await import(`./messages/${locale}.json`)).default
  };
});

API Reference

Utility Functions

  • generateNextIntlRouting(config, options?): Generate Next.js internationalization routing
  • generateStoryblokRedirects(config, options?): Generate Storyblok visual editor redirects
  • getLocales(config): Extract all unique locales
  • getHosts(config): Extract all unique hosts
  • getDomainConfig(config, host): Get domain configuration for specific host
  • isValidLocale(config, locale): Check if locale exists in configuration
  • getDefaultLocaleForHost(config, host): Get default locale for specific host

Types

  • NextRoutingConfig: Next.js routing configuration interface
  • NextRedirectConfig: Next.js redirect configuration interface
  • NextDomainConfig: Next.js domain configuration interface

License

ISC