@firemap/cli
v0.1.1
Published
Firemap CLI - Generate Cloud Functions, indexes, and security rules from decorators
Readme
@firemap/cli
Code generators for Firestore — generates Cloud Functions, indexes, and security rules from your @firemap/sdk decorators.
Installation
npm install -g @firemap/cliRequirements
- Node.js 18+
- TypeScript 5.0+ project with
@firemap/sdkdecorators - A Pro or Team license key from firemap.dev
Configuration
// firemap.config.js
export default {
models: ["src/models/**/*.ts"],
outDir: "./generated",
licenseKey: "fmk_pro_...", // or use FIREMAP_LICENSE_KEY env var
};License Key
There are three ways to provide your license key:
# Option 1: Environment variable
export FIREMAP_LICENSE_KEY="fmk_pro_..."
# Option 2: Config file (firemap.config.js)
export default {
licenseKey: "fmk_pro_...",
models: ["src/models/**/*.ts"],
};
# Option 3: .firemaprc (JSON)
{ "licenseKey": "fmk_pro_..." }Get your key at firemap.dev/settings under API Keys.
Commands
# Generate all files (functions, indexes, rules)
firemap generate:all
# Individual generators
firemap generate:functions # Cloud Functions for denormalization sync
firemap generate:indexes # firestore.indexes.json
firemap generate:rules # firestore.rules
# Preview without writing files
firemap generate:rules --dry-run
# Verbose output
firemap generate:all --verbose
# Machine-readable JSON output
firemap generate:indexes --jsonExport Schema
Export your decorator-defined schema as JSON for the web Schema Designer.
# Export schema metadata as JSON
firemap export
# Pipe to clipboard
firemap export | pbcopy # macOS
firemap export | Set-Clipboard # Windows (PowerShell)
# Save to file
firemap export > schema.jsonDenormalization
The killer feature of Firemap is automated denormalization sync. Define which fields to sync using @SyncTo and @DenormalizedFrom decorators in the SDK, then let the CLI generate the Cloud Functions that keep everything consistent.
Schema decorators (defined in your code with @firemap/sdk):
@Collection('users')
class User extends BaseModel {
@SyncTo('posts', { field: 'authorName', sourceField: 'name' })
@Field({ type: 'string' })
name!: string;
@SyncTo('posts', { field: 'authorAvatar', sourceField: 'avatarUrl' })
@Field({ type: 'string' })
avatarUrl!: string;
}
@Collection('posts')
class Post extends BaseModel {
@Field({ type: 'reference' })
authorRef!: string;
@DenormalizedFrom('users', { fields: ['name', 'avatarUrl'] })
@Field({ type: 'string' })
authorName!: string;
@DenormalizedFrom('users', { fields: ['name', 'avatarUrl'] })
@Field({ type: 'string' })
authorAvatar!: string;
}Run the generator:
firemap generate:functionsGenerated output (generated/functions/syncUsersToPost.ts):
import { onDocumentUpdated } from "firebase-functions/v2/firestore";
import { getFirestore } from "firebase-admin/firestore";
const db = getFirestore();
export const syncUsersToPosts = onDocumentUpdated("users/{docId}", async (event) => {
const before = event.data?.before?.data();
const after = event.data?.after?.data();
if (!before || !after) return;
// Only run if synced fields actually changed
const nameChanged = before.name !== after.name;
const avatarChanged = before.avatarUrl !== after.avatarUrl;
if (!nameChanged && !avatarChanged) return;
// Find all posts referencing this user
const snapshot = await db
.collection("posts")
.where("authorRef", "==", event.params.docId)
.get();
if (snapshot.empty) return;
// Batch-update denormalized fields
const batch = db.batch();
for (const doc of snapshot.docs) {
const updates: Record<string, any> = {};
if (nameChanged) updates.authorName = after.name;
if (avatarChanged) updates.authorAvatar = after.avatarUrl;
batch.update(doc.ref, updates);
}
await batch.commit();
});This is the boilerplate you would have to write and maintain by hand for every denormalization relationship. With Firemap, you declare it once and the CLI generates it -- type-safe, batched, and only triggered when the synced fields actually change.
What Gets Generated
Cloud Functions (generate:functions)
Creates Cloud Functions v2 that keep denormalized fields in sync, based on @SyncTo and @DenormalizedFrom decorators. Handles change detection, batched writes, and supports multiple sync targets per field.
Indexes (generate:indexes)
Generates firestore.indexes.json from @Index decorators for composite queries.
Security Rules (generate:rules)
Generates firestore.rules from @Rules, @AuthRequired, @AuthOwner, and @PublicRead decorators.
Links
- Documentation
- SDK Package
- Schema Designer - Visual schema editor
License
Proprietary — requires a Pro or Team subscription.
