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

@framework-cwf/core

v0.2.6

Published

App-shell utilities: published-config loader, <Providers> wrapper, layout primitives, error boundaries, 404/500 pages.

Readme

@framework-cwf/core

The app shell — composes every foundation package (auth / tokens / seo / ui / contracts) into the primitives a per-business Next.js site needs to boot. Consumers import <Layout> once at app/layout.tsx and the framework wires brand theming, auth providers, and SSR-safe Server / Client boundary defaults from there.

Static-export only: the framework targets output: 'export' (locked decision #7). The published-config loader is a build-time fetch; the deploy controller (PROJECT_PLAN §5) handles rebuilds via GitHub Actions workflow_dispatch. No revalidateTag, no /api/revalidate — those patterns require an SSR/ISR runtime the framework deliberately doesn't ship.

Installation

Published to GitHub Packages under the @framework-cwf scope. Consumers need an .npmrc pointing the scope at the GitHub Packages registry plus an auth token:

@framework-cwf:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${NODE_AUTH_TOKEN}
pnpm add @framework-cwf/core

Public surface

| Export | Where it runs | Purpose | | ------------------------ | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | | loadWebsiteConfig | Node / build | Fetches the published config from booking-api at build time, validates via WebsiteConfigSchema. | | <Layout> | Server Component | Drop into app/layout.tsx. Wires <html lang>, favicon, providers, optional Nav / Footer slots. | | <Providers> | Server Component | Composes <AuthProvider> + <ThemeProvider> + <AuthBootstrap />. | | <ThemeProvider> | Server Component | Emits the brand @theme { ... } + :root { ... } CSS variable block into the document. | | <AuthBootstrap /> | 'use client' | Calls auth configure() on first mount. T1.C.2 deferred follow-up #2 — lives here, not in auth. | | <CallbackRoute /> | 'use client' | Drop into app/auth/callback/page.tsx. Wraps auth's <AuthCallbackHandler />. | | <ErrorBoundary> | 'use client' | Class-based section-level error boundary with a brand-aware default fallback. | | <NotFoundPage> | Server Component | Drop-in for app/not-found.tsx. Brand-aware via CSS variables. | | <ErrorPage> | 'use client' | Drop-in for app/error.tsx. Receives { error, reset } from Next.js. | | WebsiteConfigLoadError | — | Typed error thrown by loadWebsiteConfig on unrecoverable failure (http-4xx / http-5xx / network / parse-json / parse-schema). |

Providers composition

<Layout>                             (Server Component — <html><body>)
  └── <Providers>                    (Server Component — composer)
       └── <AuthProvider>            (Server Component — auth context)
            ├── <ThemeProvider />    (Server Component — <style> emitter)
            ├── <AuthBootstrap />    ('use client' — calls configure())
            └── {children}           (consumer pages)

The only 'use client' boundary the shell introduces by itself is <AuthBootstrap /> (and the <AuthHydrator /> inside <AuthProvider>). Marketing pages that never call useAuth() ship effectively zero auth-related client JS.

Brand CSS — two outputs, one provider

<ThemeProvider> emits both a Tailwind @theme { ... } block AND a :root { ... } block with the same variables. Reasoning:

  • Tailwind v4 reads @theme at build time to generate utility classes.
  • Browsers ignore @theme as an unknown at-rule, so variables under it don't apply at runtime without Tailwind processing.
  • The mirror in :root { ... } makes var(--color-primary-500) work in every consumer, Tailwind-pipelined or not.

The duplication is ~1 KB and the static export gzips it.

Usage

// app/layout.tsx — Server Component
import { Layout, loadWebsiteConfig } from "@framework-cwf/core";

const BUSINESS_GUID = "a1b20001-0000-4000-8000-000000000001";

export default async function RootLayout({ children }) {
  // Build-time fetch — no runtime calls during static export.
  const config = await loadWebsiteConfig(BUSINESS_GUID, {
    apiBaseUrl: process.env.BOOKING_API_BASE_URL,
  });
  return (
    <Layout
      business={config.operational}
      marketing={config.marketing!}
      authConfig={{
        cognitoClientId: process.env.COGNITO_CLIENT_ID!,
        cognitoHostedUiDomain: process.env.COGNITO_HOSTED_UI_DOMAIN!,
        redirectUri: process.env.SITE_ORIGIN! + "/auth/callback/",
      }}
    >
      {children}
    </Layout>
  );
}
// app/auth/callback/page.tsx
import { CallbackRoute } from "@framework-cwf/core";
export default CallbackRoute;
// app/not-found.tsx — Server Component
import { NotFoundPage } from "@framework-cwf/core";
export default function NotFound() {
  return <NotFoundPage businessName="Acme Salon" />;
}
// app/error.tsx — 'use client' is mandatory per Next.js App Router
"use client";
import { ErrorPage } from "@framework-cwf/core";
export default function Error({ error, reset }) {
  return <ErrorPage businessName="Acme Salon" error={error} reset={reset} />;
}

Example app

packages/core/example/ is a complete Next.js 16 app that consumes the shell against a fixture config. It is the acceptance harness for the "brand visibly applied" criterion:

pnpm --filter @framework-cwf/core-example build
# → produces packages/core/example/out/ (1.5 MB)
# → out/index.html contains @theme + :root blocks with --color-primary-500

The example never hits the network — the fixture config is imported directly. Real per-business sites call loadWebsiteConfig(...) at build time against booking-api.

Tests

pnpm --filter @framework-cwf/core test

36 tests across 7 files:

  • load-website-config.test.ts (12) — happy path, 4xx/5xx/network/parse failure modes, retry-with-backoff, header injection, anti-Next-options guard (no next: { tags } ever attached to the fetch).
  • ThemeProvider.test.tsx (3) — emits @theme + :root blocks with the brand colours + font stacks.
  • Layout.test.tsx (7) — <html lang> default + override, favicon fallback + override, brand block emission, children + nav + footer slot composition.
  • hydration.test.tsx (1) — renderToString + hydrateRoot round-trip through <Providers> with no React mismatch warnings (same pattern as T1.C.2's hydration test).
  • ErrorBoundary.test.tsx (6) — happy path, default + ReactNode + function fallbacks, onError callback, reset() lifecycle.
  • not-found-and-error-page.test.tsx (5) — <NotFoundPage> + <ErrorPage> rendering, default + override props, reset callback wiring.
  • ssr-import.test.ts (2) — locks in the Node-import path.

What's not here

  • /api/revalidate — TASKS.md T1.G.1 listed it; PROJECT_PLAN §3.7 explicitly forbids it. Static export has no runtime to revalidate.
  • Tagged fetchnext: { tags: ... } only works under SSR/ISR. The loader uses plain fetch with retries.
  • Rich page-level UIapps/template (T1.G.2) composes ui's primitives into actual marketing pages; this shell is the wiring.

SSR safety

The package imports cleanly from Node 24 with no browser globals available — verified by ssr-import.test.ts. Every browser-touching behaviour is gated behind a 'use client' boundary (the hydrator inside <AuthProvider>, the <AuthBootstrap />, <ErrorBoundary>, and the <ErrorPage> / <CallbackRoute> route components).