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

clefbase

v2.1.5

Published

Firebase-style SDK and CLI for Clefbase — database, auth, storage, hosting, and functions

Downloads

3,502

Readme

clefbase

Firebase-style SDK and CLI for Clefbase / Cleforyx. Database, auth, storage, functions, AI, and hosting in one package.

Install

npm install clefbase

Quick Start

1 — Initialize your project

npx clefbase init

The CLI will ask for your Project ID, API Key, and Admin Secret, let you pick which services you need, and optionally set up hosting. It writes a clefbase.json config file (automatically added to .gitignore) and a .env.example.

2 — Use the SDK

import { initClefbase, getDatabase, getAuth, getStorage, getHosting, getFunctions, getAI } from "clefbase";
import config from "./clefbase.json";

const app = initClefbase(config);

const db        = getDatabase(app);
const auth      = getAuth(app);
const storage   = getStorage(app);
const hosting   = getHosting(app);  // requires adminSecret in config
const functions = getFunctions(app);
const ai        = getAI(app);

Database

Add a document

const post = await db.collection("posts").add({
  title: "Hello World",
  published: true,
  views: 0,
});
// post.id, post._createdAt, post._updatedAt are set by the server

Get a document

const user = await db.collection("users").doc("uid-123").get();
// returns null if not found

Update a document

// Merge (default) — only changes the fields you pass
await db.collection("users").doc("uid-123").update({ name: "Alice" });

// Full overwrite
await db.collection("users").doc("uid-123").set({ name: "Alice", age: 30 });

Delete a document

await db.collection("users").doc("uid-123").delete();

Query a collection

const results = await db.collection("posts")
  .where({ published: true, views: { $gt: 100 } })
  .orderBy("_createdAt", "desc")
  .limit(10)
  .query();  // returns { data, total, limit, offset }

// Or just the array:
const posts = await db.collection("posts")
  .where({ published: true })
  .getDocs();   // alias: .get()

Filter operators

| Operator | Meaning | |---|---| | { $gt: n } | greater than | | { $gte: n } | greater than or equal | | { $lt: n } | less than | | { $lte: n } | less than or equal | | { $ne: val } | not equal | | { $contains: "str" } | string contains (case-insensitive) |

Subcollections

// posts → [postId] → comments
const comments = db.collection("posts").doc("post-abc").collection("comments");
await comments.add({ text: "Great post!", author: "Bob" });
const all = await comments.getDocs();

Batch operations

const batch = db.batch();
batch.set(db.collection("users").doc("user-1"), { name: "Alice" });
batch.update(db.collection("users").doc("user-2"), { status: "active" });
batch.delete(db.collection("logs").doc("log-1"));
await batch.commit();

Transactions

await db.runTransaction(async (tx) => {
  const balance = await tx.collection("accounts").doc("acc-1").get();
  const newBalance = (balance?.balance ?? 0) - 100;
  tx.update(db.collection("accounts").doc("acc-1"), { balance: newBalance });
  tx.set(db.collection("transactions").doc(), { amount: 100, type: "withdraw" });
});

Convenience helpers

await db.getDoc("users", "uid-123");
await db.addDoc("logs", { action: "login" });
await db.updateDoc("users", "uid-123", { lastSeen: new Date().toISOString() });
await db.deleteDoc("users", "uid-123");

FieldValue helpers

import { FieldValue } from "clefbase";

await db.collection("posts").doc("p1").update({
  views:       FieldValue.increment(1),
  publishedAt: FieldValue.serverTimestamp(),
  tags:        FieldValue.arrayUnion(["new-tag"]),
});

Auth

Email / Password

// Sign up
const { user, token } = await auth.signUp("[email protected]", "password123", {
  displayName: "Alice",
  metadata: { role: "member" },
});

// Sign in
const { user, token } = await auth.signIn("[email protected]", "password123");

// Sign out
await auth.signOut();

// Current user
const me = auth.currentUser; // AuthUser | null

Auth state listener

const unsubscribe = auth.onAuthStateChanged((user) => {
  if (user) console.log("Signed in as", user.email);
  else      console.log("Signed out");
});

// Cleanup
unsubscribe();

Profile management

// Update profile
await auth.updateProfile({ 
  displayName: "Bob", 
  metadata: { theme: "dark" } 
});

Password management

// Change password
await auth.changePassword("oldPass", "newPass");

// Send password reset email
await auth.sendPasswordResetEmail("[email protected]");

// Confirm reset (call from link in email)
await auth.confirmPasswordReset(resetToken, "newPassword");

Email verification

// Send verification email
await auth.sendEmailVerification();

// Verify email (call from link in email)
await auth.verifyEmail("ABC123");

OAuth / Social login (Gateway)

// 1. Start sign-in with Google/GitHub/etc via gateway
await auth.signInWithGateway("google");
// Redirects to auth.cleforyx.com

// 2. Handle callback on every app load (before rendering)
const result = await auth.handleAuthCallback();
if (result) {
  console.log("Signed in:", result.user.email);
  setAuthToken(app, result.token);
}

Storage

Upload files

// Node.js
import fs from "fs";
const meta = await storage.ref("avatars/user-123.jpg").upload(
  fs.readFileSync("./photo.jpg"),
  { contentType: "image/jpeg" }
);

// Browser
const input = document.querySelector("input[type='file']");
const meta = await storage.ref(`uploads/${input.files[0].name}`).upload(input.files[0]);

console.log(meta.id, meta.sizeBytes, meta.md5);

Download files

// Get authenticated download URL
const url = await storage.ref("avatars/user-123.jpg").getDownloadURL();

// Use directly in img tags or fetch
const response = await fetch(url);
const blob = await response.blob();

File metadata

const meta = await storage.ref("avatars/user-123.jpg").getMetadata();
console.log(meta.size, meta.mimeType, meta.uploadedAt);

Delete files

await storage.ref("avatars/user-123.jpg").delete();

List files

// List root files
const files = await storage.ref("avatars/").list({ limit: 20 });

// List with folder filtering
const folderFiles = await storage.ref("avatars/2024/").list({ offset: 20 });

Named buckets

const userBucket = storage.bucket("user-uploads");

// Upload to bucket
const file = await userBucket.ref("documents/resume.pdf").upload(buffer, {
  contentType: "application/pdf"
});

// Download from bucket
const url = await userBucket.ref("documents/resume.pdf").getDownloadURL();

Set default bucket

storage.setDefaultBucket("media");
// Now storage.ref() uses "media" instead of "default"

Functions

Deploy a function

await functions.deploy({
  name:     "greetUser",
  runtime:  "node",
  trigger:  { type: "http" },
  source:   `export async function handler(ctx) {
    return { greeting: \`Hello, \${ctx.data.name}!\` };
  }`,
  timeoutMs: 30000,
});

Deploy from file (Node.js/CLI)

import { deployFromFile } from "clefbase";

await deployFromFile(functions, {
  name:     "analyzeImage",
  runtime:  "python",
  trigger:  { type: "http" },
  filePath: "./functions/analyze_image.py",
  env:      { API_KEY: process.env.API_KEY! },
});

Call HTTP-triggered functions

// One-shot call
const { data, durationMs } = await functions.call("greetUser", { name: "Alice" });

// Typed callable (recommended)
const greet = httpsCallable<{ name: string }, { greeting: string }>(functions, "greetUser");
const result = await greet({ name: "Bob" });

Auth-aware function calls

import { setAuthToken } from "clefbase";

const { token } = await auth.signIn("[email protected]", "password");
setAuthToken(app, token);

// ctx.auth.uid and ctx.auth.email available inside the function
const { data } = await functions.call("getUserProfile");

Scheduled functions (Cron)

await functions.deploy({
  name:    "dailyReport",
  runtime: "node",
  trigger: { 
    type: "cron",
    cron: "0 9 * * *",  // Every day at 9 AM UTC
  },
  source: `export async function handler(ctx) {
    // Generate daily report
    return { status: "completed" };
  }`,
});

List and manage functions

// List all functions
const functions = await functions.list();

// Get executions / call history
const executions = await functions.executions("greetUser", 50);

// Delete a function
await functions.delete("greetUser");

AI

Text / Code generation

import { generateText } from "clefbase";

const { content, inputTokens, outputTokens } = await ai.text({
  model:        "claude-sonnet-4-5",
  prompt:       "Write a bubble-sort in Python",
  systemPrompt: "Return only code, no explanation.",
  maxTokens:    512,
  temperature:  0.3,
});

console.log(content);

Vision / Multimodal text generation

Send images (from URLs or base64) to text generation models for analysis, object detection, OCR, or image description. Supported by Claude 3+, Gemini 1.5+, and other vision-capable models.

// Single image from URL
const { content } = await ai.text({
  model:  "claude-sonnet-4-5",
  prompt: "What objects are in this image? List them.",
  images: [
    { source: "https://example.com/photo.jpg" }
  ],
});

// Multiple images with descriptions
const { content } = await ai.text({
  model:  "gemini-2.5-flash",
  prompt: "Compare these two diagrams and describe the differences",
  images: [
    { 
      source: "https://example.com/diagram-1.png",
      description: "Original design" 
    },
    { 
      source: "https://example.com/diagram-2.png",
      description: "Updated design" 
    },
  ],
});

// Base64-encoded image (e.g., from canvas, screenshot, etc.)
const { content } = await ai.text({
  model:  "claude-sonnet-4-5",
  prompt: "Extract and read all text from this screenshot",
  images: [
    { 
      source: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEA...",
      mediaType: "image/png"
    }
  ],
});

// Vision with system prompt and history
const { content } = await ai.text({
  model:        "claude-sonnet-4-5",
  prompt:       "What color is the car in this image?",
  systemPrompt: "You are a visual expert. Be precise and concise.",
  images: [
    { source: "https://example.com/car.jpg" }
  ],
  history: [
    { role: "user", content: "Analyze this street scene" },
    { role: "assistant", content: "I can see a busy urban street..." },
  ],
});

File attachments for document and code analysis

Pass documents, code files, spreadsheets, and other files to text models for analysis, summarization, and extraction. Supports PDFs, Word docs, spreadsheets, code files, JSON, CSV, video/audio transcription, and more.

// Summarize a PDF from a URL
const { content } = await ai.text({
  model:  "claude-sonnet-4-5",
  prompt: "Summarize this document in 3 key points",
  files: [
    {
      source:      "https://example.com/whitepaper.pdf",
      mediaType:   "application/pdf",
      filename:    "whitepaper.pdf",
      description: "Technical whitepaper"
    }
  ],
});

// Extract data from a CSV (base64)
const csvBase64 = "data:text/csv;base64,bmFtZSxhZ2UsY2l0eSpFdmlzLDM1LExvbmRvbg==";
const { content } = await ai.text({
  model:  "gemini-2.5-flash",
  prompt: "Find all people over 30 and their cities",
  files: [
    {
      source:      csvBase64,
      mediaType:   "text/csv",
      filename:    "users.csv",
      description: "User database export"
    }
  ],
});

// Code review and security analysis
const { content } = await ai.text({
  model:  "claude-sonnet-4-5",
  prompt: "Find security vulnerabilities and suggest fixes",
  files: [
    {
      source:      "https://example.com/auth-handler.ts",
      mediaType:   "text/typescript",
      filename:    "auth.ts",
      description: "Authentication handler"
    }
  ],
});

// Compare multiple documents
const { content } = await ai.text({
  model:  "claude-sonnet-4-5",
  prompt: "Are these API schemas compatible? List differences.",
  files: [
    {
      source:      "data:application/json;base64,eyJwcm9wc...",
      mediaType:   "application/json",
      filename:    "v1-schema.json",
      description: "Original API schema"
    },
    {
      source:      "data:application/json;base64,eyJwcm9wc...",
      mediaType:   "application/json",
      filename:    "v2-schema.json",
      description: "New API schema"
    }
  ],
});

// Video/audio transcription and analysis
const { content } = await ai.text({
  model:  "claude-sonnet-4-5",
  prompt: "Transcribe and summarize this podcast episode",
  files: [
    {
      source:      "https://example.com/podcast.mp3",
      mediaType:   "audio/mpeg",
      filename:    "episode-42.mp3",
      description: "Weekly podcast episode"
    }
  ],
});

Local AI models (Ollama)

// If Ollama is configured on your server, use local models
const { content } = await ai.text({
  model:  "ollama:mistral",
  prompt: "Explain quantum computing",
});

Image generation

Text-to-Image:

const { files } = await ai.image({
  model:        "imagen-4.0-generate-001",
  prompt:       "A futuristic city at sunset",
  aspectRatio:  "16:9",
  numberOfImages: 2,
  outputFolder: "ai-generated", // saved to project storage
});

// Access generated images
for (const file of files) {
  console.log(file.fullPath); // e.g. "ai-generated/img_123.png"
  const url = await storage.ref(file.fullPath).getDownloadURL();
}

Image-to-Image (style transfer, upscaling, inpainting):

// Style transfer: apply Van Gogh style to a photo
const { files } = await ai.image({
  model: "imagen-4.0-generate-001",
  prompt: "Repaint in the style of Van Gogh's Starry Night",
  referenceImage: {
    source: "https://example.com/portrait.jpg",
    strength: 0.6, // 0–1: how much to preserve the reference
  },
  outputFolder: "styled",
});

// Upscaling: enhance and detail an existing image
const { files: upscaled } = await ai.image({
  model: "imagen-4.0-generate-001",
  prompt: "Upscale with enhanced details, make it sharper and more vibrant",
  referenceImage: {
    source: "data:image/jpeg;base64,/9j/4AAQSkZJRg...", // base64 image
    strength: 0.9, // high similarity to original
  },
});

// Inpainting: modify objects in an image
const { files: inpainted } = await ai.image({
  model: "imagen-4.0-generate-001",
  prompt: "Replace the sky with a dramatic sunset",
  referenceImage: {
    source: "https://example.com/landscape.jpg",
    strength: 0.7,
  },
});

Video generation (Veo 2)

Text-to-Video:

// Async operation — waits for completion (1–5 minutes)
const { status, files } = await ai.video({
  model:           "veo-3.1-generate-preview",
  prompt:          "A golden retriever on a sunny beach",
  durationSeconds: 5,
  aspectRatio:     "16:9",
  outputFolder:    "videos",
});

const videoUrl = await storage.ref(files[0].fullPath).getDownloadURL();

Image-to-Video (animate photos, create camera movements):

// Animate a static photo
const { files } = await ai.video({
  model: "veo-3.1-generate-preview",
  prompt: "The person starts walking toward the camera with a smile",
  referenceImage: {
    source: "https://example.com/portrait.jpg",
    strength: 0.8, // strong visual consistency
  },
  durationSeconds: 4,
  outputFolder: "animations",
});

// Cinematic camera movement
const { files: cinematic } = await ai.video({
  model: "veo-3.1-generate-preview",
  prompt: "Smooth dolly-in camera movement, revealing more landscape detail",
  referenceImage: {
    source: "https://example.com/landscape.jpg",
    strength: 0.7,
  },
  durationSeconds: 6,
  aspectRatio: "16:9",
});

// Temporal extension (what happens next?)
const { files: extended } = await ai.video({
  model: "veo-3.1-generate-preview",
  prompt: "The scene transitions to evening with golden hour lighting",
  referenceImage: {
    source: "data:image/jpeg;base64,/9j/4AAQSkZJRg...",
    strength: 0.6, // more creative freedom
  },
  durationSeconds: 5,
});

Embeddings

const { embeddings } = await ai.embedding({
  model: "gemini-embedding-001",
  input: ["apple", "orange", "banana"],
});

// embeddings[0] → vector for "apple"
// embeddings[1] → vector for "orange"
// etc.

List available models

// All models
const all = await ai.listModels();

// Filter by category
const textModels = await ai.listModels({ category: "text" });
const imageModels = await ai.listModels({ category: "image" });

// Filter by provider
const googleModels = await ai.listModels({ provider: "google" });
const anthropicModels = await ai.listModels({ provider: "anthropic" });

Usage statistics

const stats = await ai.getStats();
console.log(stats.totalRequests, stats.totalInputTokens, stats.totalMediaGenerated);

// Get request log
const records = await ai.getUsage({ limit: 20 });
for (const r of records) {
  console.log(r.model, r.status, r.createdAt);
}

Hosting

SDK: Deploy and manage sites

import fs from "fs";
import { getHosting } from "clefbase";

const hosting = getHosting(app);

// List all sites
const sites = await hosting.listSites();

// Create a site
const site = await hosting.createSite("my-app", "My awesome app");

// Deploy files
const result = await hosting.site(site.id).deployFiles({
  "index.html": fs.readFileSync("dist/index.html"),
  "app.js":     fs.readFileSync("dist/app.js"),
  "styles.css": fs.readFileSync("dist/styles.css"),
}, {
  entrypoint: "index.html",
  message:    "v1.2.0 release",
  onProgress: (done, total) => console.log(`${done}/${total} files`),
});

console.log(`Live at: ${result.url}`);

// Get active deploy
const active = await hosting.site(site.id).getActiveDeploy();

// List deploy history
const deploys = await hosting.site(site.id).listDeploys({ limit: 10 });

CLI: Deploy from command line

# First-time setup (interactive)
clefbase init

# Build then deploy
npm run build && clefbase deploy

# Deploy with options
clefbase deploy --dir ./build --message "v2 release"
clefbase deploy --site <siteId>     # override linked site

# Manage sites
clefbase hosting:init               # link or create a site
clefbase hosting:status             # show current live deploy
clefbase hosting:sites              # list all sites
clefbase hosting:list-deploys       # show deployment history

# Project info
clefbase info                       # show config and connectivity
clefbase --version                  # show SDK version

Custom domains

// Add custom domain to site
await hosting.site(siteId).addCustomDomain("app.example.com");

// Get custom domains
const domains = await hosting.site(siteId).getCustomDomains();

// Remove custom domain
await hosting.site(siteId).removeCustomDomain("app.example.com");

TypeScript

Full type safety

import type { ClefbaseDocument } from "clefbase";

interface Post extends ClefbaseDocument {
  title:     string;
  published: boolean;
  views:     number;
  tags:      string[];
}

const posts = db.collection<Post>("posts");
const post = await posts.doc("p1").get();
// post.views is number ✓, post.author doesn't exist ✗

Function types

import { httpsCallable } from "clefbase";

const add = httpsCallable<
  { a: number; b: number },
  { sum: number }
>(functions, "add");

const { data } = await add({ a: 3, b: 4 });
console.log(data.sum); // ✓
// console.log(data.product); // ✗ TypeScript error

Auth types

import type { AuthUser } from "clefbase";

const user: AuthUser | null = auth.currentUser;
if (user) {
  console.log(user.uid, user.email, user.displayName);
}

Configuration

clefbase.json

Written by clefbase init. Never commit this file — add to .gitignore automatically.

{
  "serverUrl":   "https://api.cleforyx.com",
  "projectId":   "my_project_abc123",
  "apiKey":      "cfx_...",
  "adminSecret": "...",
  "services": {
    "database": true,
    "auth":     true,
    "storage":  true,
    "hosting":  true,
    "functions": true,
    "ai":        true
  },
  "hosting": {
    "siteId":     "355f3976-89dc-...",
    "siteName":   "my-app",
    "distDir":    "dist",
    "entrypoint": "index.html"
  }
}

Error Handling

Database errors

import { ClefbaseError } from "clefbase";

try {
  await db.collection("users").doc("id").get();
} catch (err) {
  if (err instanceof ClefbaseError) {
    console.error(err.message, err.code, err.status);
  }
}

Functions errors

import { FunctionsError } from "clefbase";

try {
  await functions.call("myFunction");
} catch (err) {
  if (err instanceof FunctionsError) {
    console.error(err.message, err.httpStatus);
  }
}

AI errors

import { AIError } from "clefbase";

try {
  await ai.text({ model: "claude-sonnet-4-5", prompt: "Hi" });
} catch (err) {
  if (err instanceof AIError) {
    console.error(err.message, err.httpStatus);
  }
}

Environment variables

Create a .env file with:

CLEFORYX_SERVER_URL=https://api.cleforyx.com
CLEFORYX_PROJECT_ID=your_project_id
CLEFORYX_API_KEY=your_api_key
CLEFORYX_ADMIN_SECRET=your_admin_secret

Or load into environment and use:

const app = initClefbase({
  serverUrl:   process.env.CLEFORYX_SERVER_URL!,
  projectId:   process.env.CLEFORYX_PROJECT_ID!,
  apiKey:      process.env.CLEFORYX_API_KEY!,
  adminSecret: process.env.CLEFORYX_ADMIN_SECRET,
});

Advanced topics

Custom HTTP headers

import { HttpClient } from "clefbase";

const client = new HttpClient(
  "https://api.cleforyx.com/db",
  { "x-cfx-key": "your-api-key" }
);

Offline-first patterns

// Store auth token locally
localStorage.setItem("cfx_token", token);

// On app load
const saved = localStorage.getItem("cfx_token");
if (saved) {
  setAuthToken(app, saved);
  const user = auth.currentUser;
  // Use cached state while syncing in background
}

Server-side usage (Node.js)

All SDK methods work on Node.js:

import { initClefbase, getDatabase } from "clefbase";

const app = initClefbase({
  serverUrl: "https://api.cleforyx.com",
  projectId: "my_project",
  apiKey: process.env.CLEFORYX_API_KEY!,
});

const db = getDatabase(app);
const users = await db.collection("users").getDocs();

Support

  • Docs: https://cleforyx.com/docs
  • GitHub: https://github.com/cleforyx/clefbase
  • Issues: https://github.com/cleforyx/clefbase/issues
  • Community: https://discord.gg/cleforyx const post = await posts.doc("abc").get(); // Post | null

---

## Error handling

```ts
import { ClefbaseError } from "clefbase";

try {
  await auth.signIn("[email protected]", "wrong");
} catch (err) {
  if (err instanceof ClefbaseError) {
    console.log(err.message); // "Invalid credentials"
    console.log(err.status);  // 401
  }
}

Multiple apps

const defaultApp = initClefbase({ serverUrl, projectId, apiKey });
const adminApp   = initClefbase({ serverUrl, projectId, apiKey: adminKey, adminSecret }, "admin");

const db      = getDatabase(defaultApp);
const hosting = getHosting(adminApp);