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

ogygia

v0.7.0

Published

Astro-style SSR islands for SvelteKit (no Kit patches)

Readme

No Kit client bootstrap — the shared runtime is a custom element plus the features your app actually uses (a load-only app is ~8 KB min+brotli; the SPA router, lakes, live regions, and persistence are bundled only when used). Mark components with an import attribute; only those get their own JS. Each hydrate island’s module URL is written onto <ogygia-region entry> (Astro-style), so the sticky runtime does not grow with app-wide island count. Not a new framework — it sits on SvelteKit.

Install

pnpm add ogygia
// vite.config.ts — ogygia MUST come before sveltekit()
import { sveltekit } from '@sveltejs/kit/vite';
import { ogygia } from 'ogygia/vite';
import { defineConfig } from 'vite';

export default defineConfig({
	plugins: [ogygia(), sveltekit()]
});
// src/routes/+layout.ts
export const csr = false;

Dev HMR still works with csr = false — soft updates for CSS and shared modules, full reload for route shells and island entry components. No extra setup; see the docs.

Example

<script>
	import Counter from '$lib/Counter.svelte' with { wake: 'load' };
	import Chart from '$lib/Chart.svelte' with { wake: 'visible' };
	import Greeting from '$lib/Greeting.svelte' with { render: 'deferred', wake: 'load' };

	// Counter is a portable island binding — lists / dynamic <Comp /> work too
	const Dyn = Counter;
</script>

<Counter start={10} />
<Dyn start={1} />
<Chart />
<Greeting name="world">
	{#snippet ogygiaFallback()}<p>loading…</p>{/snippet}
</Greeting>

That’s an island (JS on load), the same island used dynamically, a below-the-fold island, and a server island (HTML fetched later). Lakes, presets, the SPA router, remotes, and the rest live in the docs:

ogygia.puruvj.dev

Dynamic import() + region attributes

Not supported — ogygia fails the build if it sees import('./X.svelte', { with: { hydrate: 'load' } }) (same for defer / preset). Vite strips those attributes; runtimes reject unknown keys; islands need a static import … with { … } so SSR can emit a shell.

For a chunk that downloads only after a click, use a host island and plain await import('./Widget.svelte') (no region attributes) — that mounts a regular component, not a second island. Docs: pesky patterns · playground demo.

Trust boundaries and design constraints: INVARIANTS.md in the monorepo root.

Page data

$page.data — your load data, plus url / params / route / status / form / error — reads inside an island exactly like a Kit page:

<script>
	import { page } from '$app/state';
</script>

<p>Bonjour {page.data.user.name} — {page.url.pathname}</p>

A load that returns a promise streams into the island: the shell and the island’s {#await} pending branch paint immediately (first paint is never blocked on the slowest promise), and each promise resolves live as it settles. Rejections show {:catch}; custom transport types round-trip. Docs: page data.

Shared state & context

Each island is its own hydration root, so a value handed between islands crosses a serialization boundary. A live class opts in with a wire codec, and every island that receives it shares one live instance — mutate it in one, the others repaint:

<script>
	import Count from './Count.svelte' with { wake: 'load' };
	import Add from './Add.svelte' with { wake: 'visible' };
	import { Cart } from './cart.svelte.js'; // a class with a static `wire` codec

	const cart = new Cart();
</script>

<Count {cart} />
<Add {cart} />

To reach islands scattered down a subtree without prop drilling, provide it once as context — or adopt cross-island context in an existing csr = false layout by swapping import { setContext } from 'svelte' to from 'ogygia'. Docs: state & context.

Live regions

A region made from a with { region: 'raw' } import is awaitable. Await it on the server (or just yield it from a query.live — the language awaits it) and it renders to HTML there and travels with its markup, so the client swaps it in with no fetch:

export const dashboard = query.live(v.string(), async function* (id) {
	for await (const stats of feed(id)) yield region(StatCard, { stats });
});
<Region of={dashboard(id).current} />

Static dual regions (region: 'raw', no wake) morph in place across ticks; interactive ones (region: 'raw' + wake) keep-alive (new props pushed into the mounted island, local state intact). LiveView, with Svelte components.

Single-flight navigation

Each load-scheduled server-island hole fetches its own signed HTML on load. On a SPA navigation the router prescans the incoming page and pulls all its holes down one batch request — no fetch-per-hole waterfall. Holes stream back out of order (fast-first) as each settles, and a command that returns a region repaints in a single flight — one round trip that both mutates and repaints.

Content collections

RF-native content collections ship inside ogygia — content() mints Kit prerender / query / query.live remotes, and get(id) hands back { id, data, headings, body } where body is a region you render with <Region>. Import from ogygia/content; configure markdown via ogygia({ content: { markdown } }). mdsvex / shiki are optional peers.

License

MIT