| layout | title | nav_order | parent |
|---|---|---|---|
default |
Chapter 1: Getting Started |
1 |
Fireproof Tutorial |
Welcome to Chapter 1: Getting Started. In this part of Fireproof Tutorial: Local-First Document Database for AI-Native Apps, you will build an intuitive mental model first, then move into concrete implementation details and practical production tradeoffs.
This chapter gets Fireproof running with both React-hook and core API entry points.
npm install use-fireproofOr core API only:
npm install @fireproof/coreimport { fireproof } from "@fireproof/core";
const db = fireproof("music-app");
await db.put({ _id: "beyonce", name: "Beyonce", hitSingles: 29 });
const doc = await db.get("beyonce");- initialize a Fireproof database
- write and read documents
- confirm local-first behavior in your runtime
You now have Fireproof running with a minimal document lifecycle.
Next: Chapter 2: Core Document API and Query Lifecycle
The VersionPinner class in cli/version-pinner.ts handles a key part of this chapter's functionality:
}
export class VersionPinner {
private allDeps: Record<string, string> = {};
private constructor(allDeps: Record<string, string>) {
this.allDeps = allDeps;
}
/**
* Helper function to pin dependencies
*/
private pinDependencies(
deps: Record<string, string> | undefined,
workspaceVersion: string,
_3rdPartyVersionModifier: "~" | "^" | "" | undefined,
): Record<string, string> {
const pinnedDeps: Record<string, string> = {};
if (!deps) {
return pinnedDeps;
}
for (const [name, version] of Object.entries(deps)) {
// Check if version is not pinned (starts with ^ or ~ or *)
// Note: Also catch malformed versions like "1-beta" that should be resolved from lockfile
if (version.startsWith("workspace:")) {
// Replace workspace dependencies with the workspace version
pinnedDeps[name] = workspaceVersion;
} else {
// Look up the exact version in lockfile
if (this.allDeps[name]) {This class is important because it defines how Fireproof Tutorial: Local-First Document Database for AI-Native Apps implements the patterns covered in this chapter.
The getPackageDependencies function in cli/version-pinner.ts handles a key part of this chapter's functionality:
* @returns Package dependencies information or null if not found
*/
export async function getPackageDependencies(packageName: string, lockfilePath: string): Promise<PackageDependencies | null> {
const projectDir = lockfilePath.replace(/\/[^/]+$/, "");
const lockfile = await readWantedLockfile(projectDir, { ignoreIncompatible: false });
if (!lockfile?.packages) {
throw new Error(`No lockfile found at ${lockfilePath}`);
}
// Find the package in the lockfile
// Key format examples:
// - "/@adviser/cement@0.5.2"
// - "/@adviser/cement@0.5.2(typescript@5.9.3)"
for (const [key, pkgInfo] of Object.entries(lockfile.packages)) {
const match = key.match(/^\/?(@?[^@]+)@(.+?)(?:\(|$)/);
if (match) {
const [, name, version] = match;
if (name === packageName) {
return {
name,
version,
dependencies: pkgInfo.dependencies || {},
peerDependencies: pkgInfo.peerDependencies || {},
transitivePeerDependencies: pkgInfo.transitivePeerDependencies || [],
};
}
}
}
return null;
}This function is important because it defines how Fireproof Tutorial: Local-First Document Database for AI-Native Apps implements the patterns covered in this chapter.
The getAllTransitiveDependencies function in cli/version-pinner.ts handles a key part of this chapter's functionality:
* @returns Map of package name to version
*/
export async function getAllTransitiveDependencies(
packageName: string,
lockfilePath: string,
depth = Infinity,
): Promise<Map<string, string>> {
const result = new Map<string, string>();
const visited = new Set<string>();
async function traverse(pkgName: string, currentDepth: number) {
if (currentDepth > depth || visited.has(pkgName)) {
return;
}
visited.add(pkgName);
const pkgInfo = await getPackageDependencies(pkgName, lockfilePath);
if (!pkgInfo) {
return;
}
result.set(pkgName, pkgInfo.version);
// Traverse dependencies
for (const [depName] of Object.entries(pkgInfo.dependencies)) {
await traverse(depName, currentDepth + 1);
}
}
await traverse(packageName, 0);
return result;
}This function is important because it defines how Fireproof Tutorial: Local-First Document Database for AI-Native Apps implements the patterns covered in this chapter.
The traverse function in cli/version-pinner.ts handles a key part of this chapter's functionality:
* @param packageName - Name of the package
* @param lockfilePath - Path to the directory containing pnpm-lock.yaml
* @param depth - Maximum depth to traverse (default: Infinity)
* @returns Map of package name to version
*/
export async function getAllTransitiveDependencies(
packageName: string,
lockfilePath: string,
depth = Infinity,
): Promise<Map<string, string>> {
const result = new Map<string, string>();
const visited = new Set<string>();
async function traverse(pkgName: string, currentDepth: number) {
if (currentDepth > depth || visited.has(pkgName)) {
return;
}
visited.add(pkgName);
const pkgInfo = await getPackageDependencies(pkgName, lockfilePath);
if (!pkgInfo) {
return;
}
result.set(pkgName, pkgInfo.version);
// Traverse dependencies
for (const [depName] of Object.entries(pkgInfo.dependencies)) {
await traverse(depName, currentDepth + 1);
}
}This function is important because it defines how Fireproof Tutorial: Local-First Document Database for AI-Native Apps implements the patterns covered in this chapter.
flowchart TD
A[VersionPinner]
B[getPackageDependencies]
C[getAllTransitiveDependencies]
D[traverse]
E[PinVersionOptions]
A --> B
B --> C
C --> D
D --> E