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

@proteles/solid

v0.1.1

Published

Solid 1.x primitives and components for Proteles authentication, plus SolidStart server handlers. Tokens never reach the browser.

Readme

@proteles/solid

Solid primitives and components for Proteles authentication, plus the SolidStart server handlers.

Tokens live only in an encrypted, httpOnly cookie set by your own server — the browser never receives one, only the sanitized user from /api/auth/me.

Install

npm install @proteles/solid

The five-minute setup (SolidStart)

1. The auth routes — the whole OAuth flow, in one file:

// src/routes/api/auth/[...proteles].ts
import { protelesAuthHandler } from "@proteles/solid/server";

export const GET = protelesAuthHandler;
export const POST = protelesAuthHandler;

2. Middleware — put the user on the event and guard routes:

// src/middleware.ts   (register it via `middleware` in app.config.ts)
import { createMiddleware } from "@solidjs/start/middleware";
import { attachUser, guardRequest } from "@proteles/solid/server";

export default createMiddleware({
  onRequest: [
    async (event) => {
      await attachUser(event);
      return guardRequest(event, { publicPaths: ["/"] });
    },
  ],
});

3. Wrap the app so the UI can read auth state:

// src/app.tsx
import { AuthProvider } from "@proteles/solid";

export default function App() {
  return (
    <AuthProvider>
      <Router>{/* … */}</Router>
    </AuthProvider>
  );
}

Then use the components anywhere:

import { SignedIn, SignedOut, SignInButton, UserButton, useUser } from "@proteles/solid";

export default function Home() {
  const { user } = useUser();
  return (
    <>
      <SignedOut>
        <SignInButton />
      </SignedOut>

      <SignedIn>
        Hi {user()?.email} <UserButton />
      </SignedIn>
    </>
  );
}

Client API

<AuthProvider>

Wrap your app once. Creates the auth object, provides it to every descendant, and revalidates against /api/auth/me on mount (so a stale initialUser — e.g. after a logout in another tab — self-corrects). onMount never runs during SSR, so server rendering stays pure.

| Prop | Notes | | --- | --- | | initialUser | From the server. Omit = fetch on mount, null = known signed-out, an object = known signed-in. | | basePath | BFF mount path. Defaults to VITE_PROTELES_BASE_PATH or /api/auth. |

useUser() / useAuth()

State is exposed as Solid accessors — call them:

const { user, isLoading, isAuthenticated, signIn, signOut, reload } = useAuth();

return (
  <Show when={!isLoading()} fallback={<p>Loading…</p>}>
    <Show when={isAuthenticated()}>{user()!.sub}</Show>
    <button onClick={() => signIn({ connection: "google" })}>Google</button>
  </Show>
);

They track inside JSX, createMemo, and createEffect like any signal. useUser() returns just the three state accessors. Both throw a clear error if used outside an <AuthProvider>.

isAuthenticated is a plain derived accessor rather than a createMemo, so it works even when createAuth() is called outside a component (a memo needs a reactive owner and would silently stop updating there).

Components

| Component | Renders | | --- | --- | | <SignedIn> | its children when a user is signed in | | <SignedOut> | its children when no user is signed in | | <Protect fallback={…}> | its children when signed in, else fallback (nothing while loading) | | <SignInButton returnTo? connection?> | a button that starts login (connection picks a social provider) | | <SignOutButton returnTo?> | a button that logs out | | <UserButton> | the user's name/email plus a sign-out control |

<SignInButton>/<SignOutButton>/<UserButton> are unstyled by design — pass class. The three wrappers (<SignedIn>, <SignedOut>, <Protect>) render only their children and take no class; passing one is a type error.

<SignedIn>/<SignedOut> render nothing while the first /api/auth/me is in flight, so there's no signed-in/out flash.

Server API (@proteles/solid/server)

| Export | Purpose | | --- | --- | | protelesAuthHandler(event, config?) | Handles login/callback/logout/me; assign straight to GET/POST | | attachUser(event, config?) | Resolves the user and stores it on the event (locals, else context) | | getUser(event, config?) | The sanitized user (no tokens) — reuses attachUser's value when present | | getSession(event, config?) | The full session including tokens — server-side only | | guardRequest(event, { publicPaths }, config?) | A redirect Response when the request should bounce to login, else undefined | | toWebRequest(source) | The adapter (shared with @proteles/vue): accepts a Web Request, a SolidStart FetchEvent, or an h3 event |

publicPaths entries match exactly or as a path-segment prefix: "/blog" covers /blog and /blog/post but not /blogging. "/" is exact-only, so listing the home page doesn't accidentally make the whole app public.

Configuration (environment)

Server-side, read by the handlers — same names as every Proteles BFF package:

| Variable | Required | Default | | --- | --- | --- | | PROTELES_ISSUER | ✅ | | | PROTELES_CLIENT_ID | ✅ | | | PROTELES_CLIENT_SECRET | | (omit for a public PKCE client) | | PROTELES_SESSION_SECRET | ✅ | base64 of 32 random bytes | | PROTELES_REDIRECT_URI | ✅* | * or derived from PROTELES_APP_URL | | PROTELES_APP_URL | | | | PROTELES_SCOPES | | openid profile email offline_access | | PROTELES_COOKIE_SECURE | | true | | PROTELES_BASE_PATH | | /api/auth |

Client-side, only VITE_PROTELES_BASE_PATH is read (and only if you moved the routes). Generate a session secret:

node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"

Packaging note

Solid's JSX is compiled by its own Babel preset, and it compiles differently for the browser (fine-grained DOM updates) than for SSR (string concatenation). So this package ships the conventional Solid layout:

  • dist/source/ — untranspiled JSX, selected by the solid export condition. This is the preferred path: your build (vite-plugin-solid) compiles it for whichever target you're building.
  • dist/dom/ and dist/ssr/ — precompiled fallbacks for tooling that ignores the solid condition.
  • dist/api/ — the ./server entry (plain TS, no JSX).

Develop

npm install      # from the sdk/ workspace root
npm run build    # babel (source/dom/ssr) + tsc types -> dist
npm test         # tsx + node:test

Tests cover the reactive auth object, the components (compiled with babel-preset-solid and server-rendered via solid-js/web — no bundler, no jsdom), and the SolidStart bindings for both event shapes. The full loop also runs against a live server via sdk/scripts/verify-solid.mjs (Test 14d of scripts/e2e-smoke-test.sh), which renders the published SSR bundle.