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

edges-svelte

v2.2.0

Published

A blazing-fast, extremely lightweight and SSR-friendly store for Svelte

Readme

EdgeS

A blazing-fast, extremely lightweight and SSR-friendly store for SvelteKit.

EdgeS brings seamless, per-request state management to Svelte apps — fully reactive, server-aware, and serialization-safe by default.

No context boilerplate. No hydration headaches. Just drop-in SSR-compatible state primitives with built-in support for client-side reactivity and server-side isolation.

  • 🔄 Unified state for server and client
  • 🧠 Persistent per-request memory via AsyncLocalStorage
  • 💧 Tiny API
  • 💥 Instant serialization without magic
  • 🧩 Dependency injection, zero runtime overhead

Designed for SvelteKit.


Installation

npm install edges-svelte

Setup

To enable EdgeS install edgesPlugin, it will wrap your SvelteKit handle hook with AsyncLocalStorage:

// vite.config.ts
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';
import { edgesPlugin } from 'edges-svelte/plugin';

export default defineConfig({
	plugins: [sveltekit(), edgesPlugin()]
});

Basic usage

createStore - creates a store function that can manage states

import { createStore } from 'edges-svelte';
const myStore = createStore('MyUniqueStoreName', ({ createState, createDerivedState }) => {
	// createState creates a writable, SSR-safe store with a unique key
	const collection = createState<number[]>([]);
	// createDerivedState creates a derived store, SSR-safe as well
	const collectionLengthDoubled = createDerivedState([collection], ([$c]) => $c.length * 2);

	const updateAction = (num: number) => {
		collection.update((n) => [...n, num]);
	};

	return { collection, collectionLengthDoubled, updateAction };
});
<script lang="ts">
	import { myStore } from 'your-alias';

	const { collection, collectionLengthDoubled, updateAction } = myStore();
</script>

{$collection.join(', ')}
{$collectionLengthDoubled}
<!-- 0 before button click, 2 after button click -->
{$collectionLengthMultiplied(5)}
<!-- 0 before button click, 5 after button click -->
<button onclick={() => updateAction(25)}>count update</button>
<!-- Will update the state -->
  • 💡 All stores created inside createStore use unique keys automatically and are request-scoped
  • 🛡️ Fully SSR-safe — stores are isolated per request and serialized automatically

Store Caching (built-in)

Stores are cached per request by their unique name (cache key). Calling the same store multiple times in the same request returns the cached instance.

const myCachedStore = createStore('MyUniqueStoreName', ({ createState }) => {
	const data = createState(() => 'cached data');
	return { data };
});

Core Concepts

SSR-safe state access

State is isolated per request using AsyncLocalStorage internally. You never share data between users.

You must always create stores inside using createStore.


State Primitives

createState

const count = createState(0);

$count; // reactive store value

count.update((n) => n + 1);

Behaves like Svelte’s writable, but is fully SSR-safe and scoped per-request.


createDerivedState

const count = createState(1);
const doubled = createDerivedState([count], ([$n]) => $n * 2);

$doubled;

Like Svelte’s derived.


createRawState

const counter = createRawState(0);
counter.value += 1;

Lightweight reactive variable, SSR-safe, no subscriptions, direct .value access.


Dependency Injection

You can inject dependencies into stores with createStoreFactory:

const withDeps = createStoreFactory({ user: getUserFromSession });

const useUserStore = withDeps(({ user, createState }) => {
	const userState = createState(user);
	return { userState };
});

createPresenter

A cached provider for UI logic without direct state management primitives. Perfect for separating business logic from state management.

When to use

createPresenter is ideal when you want to:

  1. Keep state management separate from UI logic
  2. Create reusable business logic that doesn't directly manage state
  3. Build presenters that orchestrate between services and stores
  4. Follow clean architecture patterns with clear separation of concerns

Difference from createStore While createStore provides state primitives (createState, createDerivedState, createRawState), createPresenter focuses purely on business logic and coordination. It maintains all the caching and dependency injection features of createStore but without state management utilities.


Batched Updates

import { batch, transaction } from 'edges-svelte';

// Batch multiple state updates to avoid re-renders
export const updateUserData = () => {
	const store = useUserStore();

	batch(() => {
		store.user.value = { id: 1, name: 'John' };
		store.isLoggedIn.set(true);
		store.preferences.set({ theme: 'dark' });
		// All updates happen in a single render cycle!
	});
};

// Transaction API for async operations
export const saveUserSettings = async (settings: Settings) => {
	return transaction(async () => {
		const store = useUserStore();

		const result = await api.saveSettings(settings);
		store.settings.set(result);
		store.lastSaved.set(new Date());

		return result;
	});
};

DevTools Integration

// DevTools are automatically enabled in development
// Access them in browser console:

window.__EDGES_DEVTOOLS__.visualizeState(); // See state tree
window.__EDGES_DEVTOOLS__.getStats(); // Get performance stats
window.__EDGES_DEVTOOLS__.clearCache(); // Clear state cache

// The package will warn you about:
// - Large state objects (>50KB)
// - Direct state mutations
// - Factory collisions
// - Slow operations (>16ms)

Monitoring & Debugging

// Enable detailed logging in development
import { DevTools } from 'edges-svelte/dev';

// Monitor state changes
const store = useUserStore();
DevTools.warnOnLargeState('user', store.user.value);

// Measure performance
DevTools.measurePerformance('heavy-computation', () => {
	// Your code here
});

// Visualize state in console
if (browser && dev) {
	DevTools.visualizeStateTree(window.__SAFE_SSR_STATE__);
}

Minification-safe stores

Pass key as first argument

// Super clean - just pass the unique key as first argument!
export const useUserStore = createStore('MyUniqueStoreName', ({ createState, createRawState }) => {
	const user = createRawState<User | null>(null);
	const isLoggedIn = createState(false);

	return { user, isLoggedIn };
});

// Same for presenters
export const useAuthPresenter = createPresenter('MyUniquePresenterName', () => {
	const login = async (credentials) => {};
	const logout = () => {};

	return { login, logout };
});

You can skip specifying a unique key and pass the factory as the first argument — edges will generate a unique key for you using its internal algorithms. The chances of collisions are minimal, but they still exist.


State Compression

Method 1: Via Plugin (Recommended) ✨

// vite.config.ts - Zero config compression!
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';
import { edgesPlugin } from 'edges-svelte/plugin';

export default defineConfig({
	plugins: [
		sveltekit(),
		edgesPlugin({
			compression: {
				enabled: true, // Enable compression
				threshold: 2048 // Compress states > 2KB
			},
			silentChromeDevtools: true // Optional: silence devtools requests
		})
	]
});

// That's it! No need to touch hooks.server.ts

Method 2: Manual Setup (For advanced use cases)

// hooks.server.ts - If you need custom control
import { edgesHandle } from 'edges-svelte/server';

export const handle = edgesHandle(({ serialize, edgesEvent, resolve }) => {
	return resolve(edgesEvent, {
		transformPageChunk: ({ html }) =>
			serialize(html, {
				compress: true, // Enable compression
				compressionThreshold: 2048 // Compress states > 2KB
			})
	});
});

Exports summary

| Feature | Import from | | -------------------------------------------------------------------------------------------------------- | --------------------- | | createStore, createStoreFactory, createPresenter, createPresenterFactory, batch, transaction | edges-svelte | | edgesPlugin, createEdgesPluginFactory | edges-svelte/plugin | | edgesHandle | edges-svelte/server | | DevTools | edges-svelte/dev |


Creating Wrapper Packages

If you're building a custom state management solution on top of edges-svelte, you can create your own plugin using the factory:

// my-awesome-edges/plugin/index.ts
import { createEdgesPluginFactory } from 'edges-svelte/plugin';

// Create your plugin with custom package name and server path
export const myAwesomePlugin = createEdgesPluginFactory(
	'my-awesome-edges', // Your package name
	'my-awesome-edges/server' // Your server module path
);

Then your users can use it just like the original:

// User's vite.config.ts
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';
import { myAwesomePlugin } from 'my-awesome-edges/plugin';

export default defineConfig({
	plugins: [sveltekit(), myAwesomePlugin()]
});

For package development/testing:

// vite.config.ts - when developing edges-svelte itself
import { createEdgesPluginFactory } from './src/lib/plugin/index.js';

const edgesPluginDev = createEdgesPluginFactory('edges-svelte', '$lib/server');

export default defineConfig({
	plugins: [sveltekit(), edgesPluginDev()]
});

FAQ

Why not just use writable, derived from Svelte?

Because those stores share state between requests when used on the server, potentially leaking data between users.

EdgeS ensures per-request isolation, so your server state is never shared accidentally.

What is the difference between createState and createRawState?

  • createState returns a full Svelte writable store with subscription and $ store syntax.
  • createRawState is a minimal reactive variable, no subscriptions, accessed via .value.

Use createRawState for simple values where you don’t need reactive subscriptions.


License

MIT


Crafted with ❤️ by Pixel1917.