| layout | title | nav_order | parent |
|---|---|---|---|
default |
Chapter 8: Production Operations, Security, and Debugging |
8 |
Fireproof Tutorial |
Welcome to Chapter 8: Production Operations, Security, and Debugging. 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.
Production Fireproof deployments need explicit practices for observability, key handling, and test discipline.
- define storage and sync boundaries per environment
- validate backup/recovery behavior of persisted stores
- enforce version pinning in lockfiles and CI
- run representative integration tests for gateway paths
- use
FP_DEBUGfor targeted module logging - standardize log format options per environment (
json,yaml, etc.) - track sync and conflict behavior during load and offline/online transitions
- treat key material management as a first-class deployment concern
- audit any insecure/deprecated key extraction behavior before production use
- document trust model when syncing over shared object storage
You now have a practical baseline for operating Fireproof in production-grade app workflows.
The setPresetEnv function in core/runtime/utils.ts handles a key part of this chapter's functionality:
...Array.from(
Object.entries({
...setPresetEnv({}),
...preset,
}),
), // .map(([k, v]) => [k, v as string])
]);
// console.log(">>>>>>", penv)
return penv;
}
// const envImpl = envFactory({
// symbol: "FP_ENV",
// presetEnv: presetEnv(),
// });
class pathOpsImpl implements PathOps {
join(...paths: string[]): string {
return paths.map((i) => i.replace(/\/+$/, "")).join("/");
}
dirname(path: string) {
return path.split("/").slice(0, -1).join("/");
}
basename(path: string): string {
return path.split("/").pop() || "";
}
// homedir() {
// throw new Error("SysContainer:homedir is not available in seeded state");
// }
}
const pathOps = new pathOpsImpl();
const txtOps = ((txtEncoder, txtDecoder) => ({
id: () => "fp-txtOps",
encode: (input: string) => txtEncoder.encode(input),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 hashStringAsync function in core/runtime/utils.ts handles a key part of this chapter's functionality:
}
}
export async function hashStringAsync(str: string): Promise<string> {
const bytes = json.encode(str);
const hash = await sha256.digest(bytes);
return CID.create(1, json.code, hash).toString();
}
export function hashStringSync(str: string): string {
return new Hasher().update(str).digest();
}
export function hashObjectSync<T extends NonNullable<S>, S>(o: T): string {
const hasher = new Hasher();
toSorted(o, (x, key) => {
switch (key) {
case "Null":
case "Array":
case "Function":
break;
case "Date":
hasher.update(`D:${(x as Date).toISOString()}`);
break;
case "Symbol":
hasher.update(`S:(x as symbol).toString()}`);
break;
case "Key":
hasher.update(`K:${x as string}`);
break;
case "String":
hasher.update(`S:${x as string}`);
break;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 hashStringSync function in core/runtime/utils.ts handles a key part of this chapter's functionality:
}
export function hashStringSync(str: string): string {
return new Hasher().update(str).digest();
}
export function hashObjectSync<T extends NonNullable<S>, S>(o: T): string {
const hasher = new Hasher();
toSorted(o, (x, key) => {
switch (key) {
case "Null":
case "Array":
case "Function":
break;
case "Date":
hasher.update(`D:${(x as Date).toISOString()}`);
break;
case "Symbol":
hasher.update(`S:(x as symbol).toString()}`);
break;
case "Key":
hasher.update(`K:${x as string}`);
break;
case "String":
hasher.update(`S:${x as string}`);
break;
case "Boolean":
hasher.update(`B:${x ? "true" : "false"}`);
break;
case "Number":
hasher.update(`N:${(x as number).toString()}`);
break;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 sleep function in core/runtime/utils.ts handles a key part of this chapter's functionality:
}
export function sleep(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
/**
* Deep clone a value
*/
export function deepClone<T>(value: T): T {
return (structuredClone ?? ((v: T) => JSON.parse(JSON.stringify(v))))(value);
}
function coerceLogger(loggerOrHasLogger: Logger | HasLogger): Logger {
if (IsLogger(loggerOrHasLogger)) {
return loggerOrHasLogger;
} else {
return loggerOrHasLogger.logger;
}
}
export function timerStart(loggerOrHasLogger: Logger | HasLogger, tag: string) {
coerceLogger(loggerOrHasLogger).Debug().TimerStart(tag).Msg("Timing started");
}
export function timerEnd(loggerOrHasLogger: Logger | HasLogger, tag: string) {
coerceLogger(loggerOrHasLogger).Debug().TimerEnd(tag).Msg("Timing ended");
}
export function deepFreeze<T extends object>(o?: T): T | undefined {
if (!o) return undefined;
Object.freeze(o);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[setPresetEnv]
B[hashStringAsync]
C[hashStringSync]
D[sleep]
E[coerceLogger]
A --> B
B --> C
C --> D
D --> E