Documentation
Complete reference for Next.js server initialization, models, Server Actions, and RSC serialization.
@dharayush7/fireclass-ssr is the Next.js App Router runtime. Its root entry is
server-only and combines the Firebase Admin model API with memoized
initialization, Server Action error handling, and an RSC serialization bridge.
npm install @dharayush7/fireclass-ssr firebase-admin class-validator class-transformer reflect-metadata server-only| Import | Environment | Exports |
|---|---|---|
@dharayush7/fireclass-ssr | Server Components, Route Handlers, Server Actions | Full Node/core API plus admin, action, and serialization helpers |
@dharayush7/fireclass-ssr/client | Client Components | serialize, serializeList, reviveDates, and Serialized only |
Use the client subpath in Client Components
The root entry imports server-only and Firebase Admin. Importing it from a
Client Component is a build error. Use @dharayush7/fireclass-ssr/client for
the pure serialization helpers.
| Export | Kind | Purpose |
|---|---|---|
getFireclass | Function | Return the memoized { BaseModel, adapter }. |
initFireclassAdmin | Function | Initialize and cache Admin Firestore. |
resetFireclassAdmin | Function | Clear the Admin Firestore cache. |
FireclassAdminOptions | Interface | Configure credentials and project id. |
runAction | Function | Convert Fireclass errors into serializable action results. |
ActionResult | Type | Discriminated Server Action result. |
ActionFieldError | Interface | Field-level validation detail. |
serialize | Function | Convert one model into an RSC-safe object. |
serializeList | Function | Convert a model list. |
reviveDates | Function | Revive selected top-level string fields as dates. |
Serialized | Type | Recursive serialized model shape. |
The root also re-exports the complete fireclass-js and
fireclass-core surfaces.
function getFireclass(options?: FireclassAdminOptions): {
BaseModel: BaseModelClass;
adapter: AdminAdapter;
};Returns a process-global Fireclass binding. The first call initializes Firebase Admin and creates the adapter; subsequent calls return the same object.
import "reflect-metadata";
import "server-only";
import { getFireclass } from "@dharayush7/fireclass-ssr";
export const { BaseModel, adapter } = getFireclass();Options passed after the first successful call do not replace the cached binding. Configure credentials before models import this entry.
interface FireclassAdminOptions {
serviceAccount?: ServiceAccount | string;
projectId?: string;
}serviceAccount accepts a Firebase Admin service-account object or its JSON
string. An explicit account takes precedence over environment credentials.
const { BaseModel } = getFireclass({
serviceAccount: process.env.FIREBASE_SERVICE_ACCOUNT_JSON,
projectId: process.env.FIREBASE_PROJECT_ID,
});function initFireclassAdmin(
options?: FireclassAdminOptions,
): Firestore;Initializes Firebase Admin once and caches its Firestore instance on
globalThis. Resolution order when no Firebase app already exists:
options.serviceAccount, object or JSON string.| Value | Preferred | Fallback |
|---|---|---|
| Project id | FIREBASE_PROJECT_ID | PROJECT_ID |
| Client email | FIREBASE_CLIENT_EMAIL | CLIENT_EMAIL |
| Private key | FIREBASE_PRIVATE_KEY | PRIVATE_KEY |
Escaped \\n sequences in the private key are converted to real newlines. An
explicit options.projectId overrides both project-id environment variables.
If Firebase Admin already has an initialized app, Fireclass reuses the first app
returned by getApps() instead of creating another one.
function resetFireclassAdmin(): void;Clears Fireclass's cached Admin app and Firestore references. It does not delete
an app from Firebase Admin's registry, and it does not clear the separate object
cached by getFireclass().
Use this advanced hook for isolated initialization tests or direct
initFireclassAdmin workflows. It is not a credential-rotation API for an
already-created model binding.
async function runAction<T>(
fn: () => Promise<T>,
): Promise<ActionResult<T>>;Runs an async Server Action body and maps Fireclass errors to a serializable, discriminated result.
type ActionResult<T> =
| { ok: true; data: T }
| { ok: false; error: string; details?: ActionFieldError[] };
interface ActionFieldError {
property: string;
constraints: Record<string, string>;
}"use server";
import {
runAction,
serialize,
} from "@dharayush7/fireclass-ssr";
import { Post } from "@/models/post";
export async function createPost(formData: FormData) {
return runAction(async () => {
const post = new Post({
title: String(formData.get("title") ?? ""),
});
await post.save();
return serialize(post);
});
}| Outcome | Result |
|---|---|
| Function resolves | { ok: true, data } |
ValidationFailedError | { ok: false, error, details } |
Other FireclassError | { ok: false, error } |
| Non-Fireclass error | Re-thrown for Next.js error handling |
Validation details include top-level property and constraints values.
type Serialized<T> = {
[K in keyof T]: SerializedValue<T[K]>;
};The mapped type recursively changes Date fields to string, including dates
inside arrays and nested object types. Other field types are preserved.
function serialize<T extends object>(model: T): Serialized<T>;Returns a plain object containing own enumerable fields. Dates become ISO strings recursively; prototype methods are excluded.
import { serialize } from "@dharayush7/fireclass-ssr";
import { PostCard } from "./post-card";
export default async function Page() {
const post = await Post.findById("post_123");
return post ? <PostCard post={serialize(post)} /> : null;
}function serializeList<T extends object>(
models: T[],
): Serialized<T>[];Equivalent to models.map(serialize).
const posts = serializeList(await Post.findMany());function reviveDates<
T extends Record<string, unknown>,
K extends keyof T,
>(
object: T,
dateKeys: K[],
): Omit<T, K> & Record<K, Date>;Creates a shallow copy and converts selected top-level string fields with
new Date(value).
"use client";
import {
reviveDates,
type Serialized,
} from "@dharayush7/fireclass-ssr/client";
interface PostShape {
id?: string;
title: string;
createdAt: Date;
}
export function PostCard({ post }: { post: Serialized<PostShape> }) {
const revived = reviveDates(post, ["createdAt"]);
return <time>{revived.createdAt.toLocaleDateString()}</time>;
}Only selected top-level string values are converted. Missing and non-string
values remain unchanged; nested paths are not traversed by reviveDates.