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

@mhmdhammoud/meritt-dev-sdk

v0.1.0

Published

SDK for Meritt Engine content management with Firebase integration

Readme

@meritt-dev/sdk

A powerful SDK for Meritt Engine content management with Firebase integration. This SDK provides a seamless interface for managing content, media, and more in your Meritt Engine projects.

Features

  • ✅ Direct Firebase integration
  • ✅ Type-safe API with TypeScript
  • ✅ React hooks for easy integration
  • ✅ Zustand stores for state management
  • ✅ Comprehensive content types (Products, Articles, Portfolio Projects)
  • ✅ Media management with upload progress
  • ✅ Built-in pagination and filtering
  • ✅ Provider-based architecture for clean integration

Installation

# Using npm
npm install @meritt-dev/sdk

# Using yarn
yarn add @meritt-dev/sdk

# Using pnpm
pnpm add @meritt-dev/sdk

Prerequisites

The SDK requires Firebase as a peer dependency, and React for hooks functionality.

# For React integration
npm install react react-dom

# Firebase is included as a dependency

Quick Start

Setup with Provider

Wrap your application with the MerittProvider at the root level:

import { MerittProvider } from '@meritt-dev/sdk';

function App() {
  return (
    <MerittProvider
      config={{
        apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY!,
        authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN!,
        projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID!,
        storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET!,
        messagingSenderId:
          process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID!,
        appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID!,
      }}
    >
      <YourAppContent />
    </MerittProvider>
  );
}

Using Content Hooks

Products

import { useProducts } from '@meritt-dev/sdk';

function ProductsList() {
  const { products, loading, error, loadMore } = useProducts({
    featured: true,
    limit: 10,
  });

  if (loading) return <div>Loading products...</div>;
  if (error) return <div>Error: {error.message}</div>;

  return (
    <div>
      <h2>Featured Products</h2>
      <div className="grid">
        {products.map((product) => (
          <div key={product.id} className="product-card">
            <img src={product.images[0]} alt={product.name} />
            <h3>{product.name}</h3>
            <p>${product.price.toFixed(2)}</p>
          </div>
        ))}
      </div>
      <button onClick={loadMore}>Load More</button>
    </div>
  );
}

Media Management

Use the useMedia hook to fetch and manage media assets:

import { useMedia } from '@meritt-dev/sdk';

function MediaGallery() {
  const { media, loading, uploadMedia, isUploading, progress } = useMedia({
    fileType: 'image',
    limit: 20,
  });

  const handleFileChange = async (event) => {
    const file = event.target.files[0];
    if (file) {
      try {
        const result = await uploadMedia(file, {
          folder: 'products',
          alt: 'Product image',
        });
        console.log('Uploaded successfully:', result.downloadUrl);
      } catch (error) {
        console.error('Upload failed:', error);
      }
    }
  };

  return (
    <div>
      <h2>Media Gallery</h2>

      <div className="upload-section">
        <input type="file" onChange={handleFileChange} />
        {isUploading && (
          <div className="progress-bar">
            <div className="progress" style={{ width: `${progress}%` }}></div>
            <span>{progress.toFixed(0)}%</span>
          </div>
        )}
      </div>

      <div className="media-grid">
        {media.map((item) => (
          <div key={item.id} className="media-item">
            <img src={item.thumbnailUrl} alt={item.alt || item.fileName} />
            <p>{item.fileName}</p>
          </div>
        ))}
      </div>
    </div>
  );
}

Direct File Upload

If you only need file upload functionality without creating media records:

import { useUpload } from '@meritt-dev/sdk';

function FileUploader() {
  const { uploadFile, isUploading, progress, downloadUrl } = useUpload();

  const handleFileChange = async (event) => {
    const file = event.target.files[0];
    if (file) {
      try {
        const result = await uploadFile(file, { folder: 'documents' });
        console.log('Download URL:', result.downloadUrl);
      } catch (error) {
        console.error('Upload error:', error);
      }
    }
  };

  return (
    <div>
      <input type="file" onChange={handleFileChange} />
      {isUploading && <progress value={progress} max="100" />}
      {downloadUrl && <div>File uploaded: {downloadUrl}</div>}
    </div>
  );
}

API Reference

Provider

MerittProvider

The main provider component that initializes Firebase and provides context to all child components.

<MerittProvider
  config={{
    apiKey: string,
    authDomain: string,
    projectId: string,
    storageBucket: string,
    messagingSenderId: string,
    appId: string,
  }}
  namespace?: string // Optional namespace for multiple instances
>
  <App />
</MerittProvider>

useMerittContext()

Hook to access the Meritt context within components.

const {
  config, // Firebase configuration
  namespace, // Optional namespace
  isInitialized, // Boolean indicating if Firebase is ready
  firebase, // Firebase instances (db, auth, storage)
  error, // Initialization error if any
} = useMerittContext();

useFirebaseInstances()

Hook to directly access Firebase instances.

const {
  db, // Firestore database
  auth, // Firebase Auth
  storage, // Firebase Storage
} = useFirebaseInstances();

Content Hooks

useProducts(options?)

const {
  products, // Array of products
  loading, // Boolean loading state
  error, // Error object if any
  fetchProduct, // Function to fetch a single product
  loadMore, // Function to load more products
  createProduct, // Function to create a new product
  updateProduct, // Function to update a product
  deleteProduct, // Function to delete a product
} = useProducts({
  featured: boolean, // Filter by featured status
  inStock: boolean, // Filter by stock status
  categoryId: string, // Filter by category ID
  limit: number, // Number of items to fetch
  offset: number, // Offset for pagination
});

useMedia(options?)

const {
  media,             // Array of media items
  loading,           // Boolean loading state
  error,             // Error object if any

  // Upload state
  isUploading,       // Boolean upload state
  progress,          // Upload progress (0-100)
  downloadUrl,       // URL of the last uploaded file
  uploadError,       // Upload error if any

  // Operations
  uploadMedia,       // Function to upload a file and create a media record
  getMediaById,      // Function to fetch a single media item
  loadMore,          // Function to load more media items
  updateMedia,       // Function to update a media item
  deleteMedia,       // Function to delete a media item
  resetUploadState,  // Function to reset upload state
} = useMedia({
  fileType?: string | string[],  // Filter by file type
  folder?: string,               // Filter by folder
  tags?: string[],               // Filter by tags
  limit?: number,                // Number of items to fetch
  offset?: number,               // Offset for pagination
});

useUpload()

const {
  isUploading, // Boolean upload state
  progress, // Upload progress (0-100)
  downloadUrl, // URL of the last uploaded file
  error, // Upload error if any
  uploadFile, // Function to upload a file
  resetUploadState, // Function to reset upload state
} = useUpload();

Type Definitions

The SDK exports TypeScript interfaces for all content types:

  • Product - E-commerce product
  • Article - Blog article
  • PortfolioProject - Portfolio project
  • Media - Media asset
  • Category - Content category
  • Order - E-commerce order

Refer to the Types Documentation for detailed type definitions.

Advanced Usage

Multiple Instances

You can use multiple provider instances for multi-tenant applications:

import { MerittProvider } from '@meritt-dev/sdk';

function MultiTenantApp() {
  return (
    <div>
      <MerittProvider config={tenant1Config} namespace="tenant1">
        <TenantDashboard tenantId="tenant1" />
      </MerittProvider>

      <MerittProvider config={tenant2Config} namespace="tenant2">
        <TenantDashboard tenantId="tenant2" />
      </MerittProvider>
    </div>
  );
}

Using Stores Directly

You can use the Zustand stores directly for more advanced use cases:

import {
  useProductStore,
  useMediaStore,
  useFirebaseInstances,
} from '@meritt-dev/sdk';

function AdvancedComponent() {
  const firebase = useFirebaseInstances();
  const products = useProductStore((state) => state.products);
  const fetchProducts = useProductStore((state) => state.fetchProducts);

  // Use store methods with Firebase instances
  const loadProducts = async () => {
    await fetchProducts({ limit: 20 }, firebase);
  };

  return <div>Advanced component content</div>;
}

Custom Firebase Queries

For advanced use cases, you can access the Firebase instances directly:

import { useFirebaseInstances } from '@meritt-dev/sdk';
import { collection, query, where, getDocs } from 'firebase/firestore';

function CustomQueryComponent() {
  const { db } = useFirebaseInstances();

  const customQuery = async () => {
    const productsRef = collection(db, 'products');
    const q = query(productsRef, where('price', '<', 50));
    const snapshot = await getDocs(q);
    // Process results...
  };

  return <div>Custom query component</div>;
}

Testing

For testing, you can provide mock Firebase configurations:

import { MerittProvider } from '@meritt-dev/sdk';

function TestWrapper({ children }) {
  const mockConfig = {
    apiKey: 'test-api-key',
    authDomain: 'test.firebaseapp.com',
    projectId: 'test-project',
    storageBucket: 'test-project.appspot.com',
    messagingSenderId: '123456789',
    appId: 'test-app-id',
  };

  return <MerittProvider config={mockConfig}>{children}</MerittProvider>;
}

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

This project is licensed under the MIT License - see the LICENSE file for details.

Support

If you have any questions or need help integrating the SDK, please open an issue on the GitHub repository or contact us at [email protected].

Firestore Indexes

The SDK requires specific Firestore indexes for optimal query performance. A firestore.indexes.json file is included with the SDK.

Setup

  1. Copy the indexes file to your Firebase project root:

    cp node_modules/@meritt-dev/sdk/firestore.indexes.json .
  2. Deploy the indexes:

    firebase deploy --only firestore:indexes
  3. Wait for indexes to build (usually 2-5 minutes)

Prerequisites

  • Firebase CLI installed: npm install -g firebase-tools
  • Firebase project initialized: firebase init
  • Logged in to Firebase: firebase login

Troubleshooting

If you get index-related errors:

  1. Ensure the firestore.indexes.json file is in your project root
  2. Check the Firebase Console for index build status
  3. Wait for indexes to finish building before testing queries