Getting Started
Installation
npm install @codecompose/typed-pubsubPeer Dependencies
This package requires the following peer dependencies:
@google-cloud/pubsub(>= 4)firebase-functions(>= 6)zod(>= 3)
Install them if you haven't already:
npm install @google-cloud/pubsub firebase-functions zodBasic Setup
1. Define your schemas
Create a file to define your PubSub topic schemas using Zod. Each key becomes a topic name, and its value defines the expected message payload.
// pubsub.ts
import { PubSub } from "@google-cloud/pubsub";
import { createTypedPubsub } from "@codecompose/typed-pubsub";
import { z } from "zod";
const schemas = {
user_created: z.object({
userId: z.string(),
email: z.string().email(),
}),
order_placed: z.object({
orderId: z.string(),
userId: z.string(),
total: z.number().positive(),
}),
} as const;
export const pubsub = createTypedPubsub({
client: new PubSub(),
schemas,
region: "us-central1",
});2. Create a publisher
Use createPublisher to publish type-safe messages. The topic name is autocompleted, and the payload is validated against the schema at compile time.
import { pubsub } from "./pubsub";
export async function onUserSignup(userId: string, email: string) {
await pubsub.createPublisher("user_created")({ userId, email });
}3. Create a handler
Use createHandler to create a Firebase Cloud Function that processes messages from a topic. The handler receives a fully typed payload.
import { pubsub } from "./pubsub";
export const handle_user_created = pubsub.createHandler({
topic: "user_created",
handler: async (data) => {
// data.userId and data.email are fully typed
console.log(`New user created: ${data.email}`);
},
});Snake case convention
The examples use snake_case for topic names and exported cloud functions. This is because casing is currently ignored in Cloud Run function names in GCP, so snake_case is preferred for consistency.
4. Export as Cloud Functions
Export handlers from your functions entry point so Firebase deploys them:
// index.ts
export { handle_user_created } from "./handlers/user-created";
export { handle_order_placed } from "./handlers/order-placed";Next Steps
- Configuration — Customize default options and per-handler overrides
- Event Marking — Prevent duplicate processing with Redis
- Stale Events — Drop old messages during retry storms