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

@jk2908/solas

v0.4.1

Published

A Vite + React meta-framework exploring streaming, Server Components, and partial prerendering. Designed for simplicity and lightness

Readme

Solas

Solas is a minimal React meta-framework powered by Vite, created for experimenting with routing, streaming, and prerendering with React Server Components.

It has not been rigorously tested yet (there are currently no automated tests) ... and broken behaviour should be expected.

Solas currently requires Bun 1.2+ on your PATH. You can still manage dependencies with npm, pnpm, or yarn, but the Solas CLI and Vite plugin runtime use Bun APIs directly.

Install

npm install @jk2908/solas react react-dom react-server-dom-webpack vite
npm install -D @vitejs/plugin-react typescript vite-tsconfig-paths

Use

Create a Vite config that registers Solas.

import { defineConfig } from 'vite'

import solas from '@jk2908/solas'
import react from '@vitejs/plugin-react'

export default defineConfig({
	plugins: [solas(), react()],
})

Structure

Put your routes in app/.

app/
	+layout.tsx
	+page.tsx
	+middleware.ts
	+loading.tsx
	+401.tsx
	+403.tsx
	+404.tsx
	+500.tsx
	about/
		+layout.tsx
		+page.tsx
	api/
		+endpoint.ts
	posts/
		[id]/
			+page.tsx

Use these filename conventions:

  • +layout.tsx: shared layout for a route branch.
  • +page.tsx: page component for a route.
  • +endpoint.ts: request handler for non-page routes.
  • +middleware.ts: middleware that runs for the current route branch and is inherited by child routes. Parent and child middleware stack together.
  • +loading.tsx: loading fallback inherited by child routes.
  • +401.tsx: boundary for unauthorised responses in the current route branch and its children.
  • +403.tsx: boundary for forbidden responses in the current route branch and its children.
  • +404.tsx: boundary for not found responses in the current route branch and its children.
  • +500.tsx: boundary for server errors in the current route branch and its children.

Nested folders create nested routes. Dynamic segments use [param], and catch-all segments use [...param].

Status boundaries follow the same override pattern as layouts: a child route uses the nearest matching boundary file above it, and a more specific boundary replaces a parent one.

Config

All Solas options are passed to solas() inside defineConfig.

url

url is optional. If you set it, Solas treats it as the public origin for your app.

Solas resolves it in this order:

  • the url option passed to solas()
  • VITE_APP_URL

Current behaviour:

  • Solas reads that value during plugin configuration.
  • Solas exposes the resolved value as import.meta.env.VITE_APP_URL.
  • If url is set, prerender uses it as the request origin for build-time renders.
  • The runtime router does not otherwise require config.url for routing to work.

In practice, you only need url if your app code wants to read the public origin from import.meta.env.VITE_APP_URL, or if your prerendered output needs a real public origin.

If you do want to set it explicitly, this is the shape:

export default defineConfig(({ mode }) => ({
	plugins: [
		solas({
			url: mode === 'production' ? 'https://example.com' : 'http://localhost:8787',
		}),
	],
}))

If you prefer an environment variable, set this instead:

VITE_APP_URL=https://example.com

port

Use port to change the development server port.

Default: 8787

export default defineConfig({
	plugins: [
		solas({
			port: 4000,
		}),
	],
})

precompress

Use precompress to control whether Solas writes compressed build assets.

Default: true

export default defineConfig({
	plugins: [
		solas({
			precompress: false,
		}),
	],
})

prerender

Use prerender to set the default prerender mode for the app. Valid values are full, ppr, and false.

Default: false

  • false: do not prerender the route.
  • full: render the full route to HTML at build time.
  • ppr: prerender a static shell and defer dynamic regions to request time.
export default defineConfig({
	plugins: [
		solas({
			prerender: 'ppr',
		}),
	],
})

This value is only the default. Route files can override it with export const prerender = ..., and the nearest explicit export wins.

// vite.config.ts
export default defineConfig({
	plugins: [solas({ prerender: 'full' })],
})
// app/about/+layout.tsx
export const prerender = 'ppr'
// app/about/team/+page.tsx
export const prerender = false

In that example, the app default is full, the about layout overrides it to ppr, and the page overrides it again to false.

For dynamic routes, prerendering uses the params you export from the page:

export const params = () => [{ id: 'post-1' }, { id: 'post-2' }]
export const prerender = 'full'

In ppr mode, Solas prerenders the shell and lets you defer parts of the tree to request time.

Use dynamic() inside a Suspense boundary to mark a subtree as request-time only:

import { Suspense } from 'react'

import { dynamic } from '@jk2908/solas/server'

export const prerender = 'ppr'

export default function Page() {
	return (
		<Suspense fallback={<div>Loading...</div>}>
			<Ts />
		</Suspense>
	)
}

async function Ts() {
	dynamic()
	return <div>{Date.now()}</div>
}

During prerender, dynamic() suspends so the nearest Suspense fallback is written into the static shell. At request time, the deferred content resolves normally.

If you call dynamic() outside ppr mode, Solas does not defer that subtree. In full mode it logs a warning and the component still renders at build time.

headers(), cookies(), and url() also mark the current render path as dynamic, so they should be treated the same way when you are building a ppr shell.

metadata

Use metadata to set default document metadata.

export default defineConfig({
	plugins: [
		solas({
			metadata: {
				title: '%s - Solas',
				meta: [
					{
						name: 'description',
						content: 'My Solas app',
					},
				],
			},
		}),
	],
})

This is also only the default. Route metadata is merged in order, so config metadata can be extended or overridden by the shell, layouts, page, and status boundaries. The later, more specific route metadata wins for titles and duplicate tags.

// vite.config.ts
solas({
	metadata: {
		title: '%s - Solas',
	},
})

// app/+layout.tsx
export const metadata = {
	title: 'Docs',
}

// app/guides/+page.tsx
export const metadata = {
	title: 'Routing',
}

In that example, the final page title becomes Routing - Solas.

trailingSlash

Use trailingSlash to set the app-wide URL policy.

Default: never

  • never: /about/ redirects to /about
  • always: /about redirects to /about/
  • ignore: both forms resolve without a canonical redirect

This is a global setting in solas(). Solas does not read trailingSlash from route files.

Prerendered output follows the same policy. always writes route HTML as about/index.html, while never and ignore write it as about.html.

export default defineConfig({
	plugins: [
		solas({
			trailingSlash: 'always',
		}),
	],
})

trustedOrigins

Use trustedOrigins to allow specific origins to make cross-origin browser submissions to your app.

Default: []

Solas protects server actions and +endpoint handlers against CSRF.

Server actions are always POST requests. +endpoint handlers are protected on POST, PUT, PATCH, and DELETE requests.

By default, only same-origin browser requests are allowed. Add a trusted origin when a third-party service needs to submit through the user's browser, such as a payment gateway or identity provider.

Each value must be a complete origin including protocol:

export default defineConfig({
	plugins: [
		solas({
			trustedOrigins: ['https://payments.example.com', 'https://login.example.com'],
		}),
	],
})

Only add origins you completely trust. These origins are treated as allowed browser sources for unsafe requests.

sitemap

Use sitemap to generate a sitemap.xml at build time.

Default: false

When enabled, Solas writes a sitemap containing all routes with deterministic URLs: static routes, prerendered routes, and dynamic routes resolved via params. The origin for each URL comes from config.url.

export default defineConfig(({ mode }) => ({
	plugins: [
		solas({
			url: mode === 'production' ? 'https://example.com' : 'http://localhost:8787',
			sitemap: true,
		}),
	],
}))

Routes with dynamic segments ([id]) or catch-all segments ([...param]) are only included if they export params and prerender.

To add routes that Solas cannot discover automatically (for example, catch-all routes backed by a CMS), pass an object with a routes function. The function receives the auto-discovered routes and returns the final list:

export default defineConfig(({ mode }) => ({
	plugins: [
		solas({
			url: mode === 'production' ? 'https://example.com' : 'http://localhost:8787',
			sitemap: {
				async routes(existing) {
					const posts = await getPosts()
					return [...existing, ...posts.map(p => `/blog/${p.slug}`)]
				},
			},
		}),
	],
}))

The routes function can be async. The callback also lets you filter routes:

sitemap: {
	routes: (r) => r.filter(route => !route.startsWith('/admin')),
}

The sitemap is written to the build output directory as sitemap.xml after prerendering and before precompression.

logger.level

Use logger.level to control internal Solas logging.

Default: info

Valid values are debug, info, warn, error, and fatal.

  • debug: show everything
  • info: the default
  • warn: only warnings and errors
  • error: only errors
  • fatal: only fatal errors

This is mainly useful when debugging framework behaviour such as routing and prerendering. It is for Solas internals, not your app's general-purpose logging, and it does not control top-level CLI status output such as build and preview progress messages.

export default defineConfig({
	plugins: [
		solas({
			logger: {
				level: process.env.NODE_ENV === 'production' ? 'fatal' : 'info',
			},
		}),
	],
})

Scripts

Add scripts to your app:

{
	"scripts": {
		"dev": "bunx --bun vite dev",
		"build": "bunx --bun vite build",
		"preview": "bunx --bun vite preview"
	}
}

Commands

  • bunx --bun vite dev starts the development server.
  • bunx --bun vite build creates a production build. Solas finalizes that build by prerendering configured routes, writing the runtime manifest, generating sitemap.xml when enabled, and precompressing output when enabled.
  • bunx --bun vite preview serves the built app for local verification.

Security

CSRF

Solas protects server actions and +endpoint handlers against CSRF.

Server actions are always POST requests. +endpoint handlers are protected on browser-initiated POST, PUT, PATCH, and DELETE requests.

By default, browser requests must be same-origin.

When available, Solas checks browser provenance using:

  • Sec-Fetch-Site
  • Origin
  • Referer

Solas also considers the effective request origin when your app is behind a proxy by using X-Forwarded-Host, X-Forwarded-Proto, and config.url when present.

If you need to allow a trusted third-party browser POST source, configure it explicitly:

export default defineConfig({
	plugins: [
		solas({
			trustedOrigins: ['https://payments.example.com'],
		}),
	],
})

Requests from non-browser callers that do not send browser provenance headers are allowed by default, so typical server-to-server integrations and webhooks continue to work.

Cookie-backed app mutations should keep the default same-origin protection and only use trustedOrigins for narrowly scoped integrations that genuinely need cross-origin browser submissions.