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

saas-base

v0.0.2

Published

Shared core logic (Firebase, Auth, State) for SaaS apps.

Readme

saas-back (Core Services Package) This is the core backend-as-a-service package for building SaaS apps. It provides a set of shared utilities to be used across all applications (pro-editor, design-studio, televerse).

This package MUST NOT contain app-specific business logic.

Its core responsibilities are: Initializing Firebase (Auth, Firestore, Storage)Providing a global Zustand store for authenticationExporting a React hook to listen to auth state changes

  1. Installation

Install the package and its required peer dependencies into your Expo application.# Install the package (use your scoped name if you published one)

npm install saas-back

Install its peer dependencies

npm install firebase zustand

  1. Quick Start: Connecting Your AppThis package requires the consuming application (e.g., pro-editor) to provide the Firebase API keys.Step

2a: Set Environment Variables

In the root of your pro-editor project, create a .env file. Expo requires the EXPO_PUBLIC_ prefix to read variables on the client.

pro-editor/.env

EXPO_PUBLIC_FIREBASE_API_KEY="AIzaSy...YOUR_API_KEY"
EXPO_PUBLIC_FIREBASE_AUTH_DOMAIN="your-project-id.firebaseapp.com"
EXPO_PUBLIC_FIREBASE_PROJECT_ID="your-project-id"
EXPO_PUBLIC_FIREBASE_STORAGE_BUCKET="your-project-id.appspot.com"
EXPO_PUBLIC_FIREBASE_MESSAGING_SENDER_ID="1234567890"
EXPO_PUBLIC_FIREBASE_APP_ID="1:1234567890:web:abcdef123456"

Step 2b: Initialize in Your Root LayoutIn your Expo app's root layout (app/_layout.tsx), you must import and call the initializeFirebaseCore function once. This configures the package for the rest of your app's lifecycle.This file also shows the complete implementation of protected routes using the package's auth listener.// pro-editor/app/_layout.tsx

import { 
  initializeFirebaseCore, 
  FirebaseCoreConfig, 
  useAuthStateListener, 
  useAuthStore 
} from 'saas-back';

import { Slot, useRouter, useSegments } from 'expo-router';
import { useEffect } from 'react';
import { View, ActivityIndicator } from 'react-native';

// --- 1. Load Config & Initialize ---
// This code runs ONCE when the app module is loaded
const firebaseConfig: FirebaseCoreConfig = {
  apiKey: process.env.EXPO_PUBLIC_FIREBASE_API_KEY!,
  authDomain: process.env.EXPO_PUBLIC_FIREBASE_AUTH_DOMAIN!,
  projectId: process.env.EXPO_PUBLIC_FIREBASE_PROJECT_ID!,
  storageBucket: process.env.EXPO_PUBLIC_FIREBASE_STORAGE_BUCKET!,
  messagingSenderId: process.env.EXPO_PUBLIC_FIREBASE_MESSAGING_SENDER_ID!,
  appId: process.env.EXPO_PUBLIC_FIREBASE_APP_ID!,
};

// Call the init function to configure the package
initializeFirebaseCore(firebaseConfig);
// --- End of Initialization ---
/**
 * This is the main layout for the entire app.
 * It sets up the auth listener and handles protected routes.
 */
export default function RootLayout() {
  
  // --- 2. Set up Auth Listener & Protected Routes ---
  
  // This hook now works because 'auth' is initialized.
  // It subscribes to Firebase and updates the Zustand store.
  useAuthStateListener();

  // Get auth state from the Zustand store
  const { user, isLoading } = useAuthStore();
  const segments = useSegments();
  const router = useRouter();

  useEffect(() => {
    if (isLoading) {
      // Wait until the auth state is confirmed
      return;
    }

    const inAuthGroup = segments[0] === '(auth)';

    if (!user && !inAuthGroup) {
      // If user is NOT logged in and is NOT on an auth screen,
      // redirect them to the sign-in page.
      router.replace('/(auth)/sign-in');
    } else if (user && inAuthGroup) {
      // If user IS logged in but is still on an auth screen (e.g. sign-in),
      // redirect them to the app's home screen.
      router.replace('/(app)/home');
    }
  }, [user, isLoading, segments, router]); // Re-run effect when state changes

  // Show a loading indicator while the initial auth check is running
  if (isLoading) {
    return (
      <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
        <ActivityIndicator size="large" color="#0000ff" />
      </View>
    );
  }

  // Once loaded, render the current child route (e.g., sign-in or home)
  return <Slot />;
}
  1. Available UtilitiesYour app is now set up. Here is how to use the package utilities.Accessing Auth StateTo get the user's profile or check their auth status in any component:
import { useAuthStore } from 'saas-back';

function ProfileHeader() {
  // Select the 'user' object from the store
  const { user } = useAuthStore();

  if (!user) {
    return <Text>Not logged in</Text>;
  }

  return <Text>Welcome, {user.email}</Text>;
}

Using Firebase Services

The auth, firestore, and storage instances are now configured and can be imported directly for use in your app's screens or API files.// Example: A sign-in function

import { auth, firestore } from 'saas-back';
import { signInWithEmailAndPassword } from 'firebase/auth';
import { doc, getDoc } from 'firebase/firestore';

export async function handleSignIn(email, password) {
  try {
    const userCredential = await signInWithEmailAndPassword(auth, email, password);
    
    // Example: Fetch user profile from Firestore
    const userDoc = await getDoc(doc(firestore, 'users', userCredential.user.uid));
    
    if (userDoc.exists()) {
      console.log("User profile:", userDoc.data());
    }
  } catch (error) {
    console.error("Sign-in failed:", error);
  }
}
  1. For Package Maintainers (How to Update)To publish a new version of this saas-back package:Make your code changes in the saas-back/src directory.Increment the "version" number in saas-back/package.json (e.g., 0.0.1 -> 0.0.2).Run the build command: npm run buildPublish to the registry: npm publishIn your app (pro-editor, etc.), run npm install saas-back@latest to pull in the new version.