Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 
 
 

README.md

chat example

The worked reference for the real layered firepact setup: Firestore documents and plain HTTP DTOs, generated into separate files with each shared enum defined exactly once. This one uses the decorator-on-model style; see ../realtime_app/ for the production style (firepact kept out of the model source, snake_case wire).

datetime is not one TypeScript type

A Pydantic datetime maps to a different TS type depending on where the value lives. This example shows all three:

Field Annotation read view write view
Message.createdAt datetime + FirestoreServerTimestamp() Timestamp | null FieldValue (serverTimestamp())
Message.editedAt plain datetime (Firestore field) Timestamp Timestamp | Date
SendMessageRequest.clientTime plain datetime (HTTP DTO, --plain) string string

So on a Firestore read you get a real Timestamp (data.editedAt.toDate()), while an HTTP payload gives you a string (new Date(clientTime)) -- the two are never confused because they are different generated types.

Inputs (Pydantic)

  • models.py - the Firestore document models. Message is a @firestore_realtime root; Profile/Reaction/Attachment are its transitive closure. Wire keys are camelCase (by_alias=True + to_camel), matching the backend's write serialization.
  • dtos.py - plain HTTP request/response DTOs (SendMessageRequest, SendMessageResponse). Their datetime is an ISO string over HTTP, not a Firestore Timestamp. MessageKind is shared with Message and is defined here (the plain layer is the single source).

Outputs

  • dtos.ts - generated with firepact-gen --plain: one plain interface per model, datetime -> string, strict enums. Defines MessageKind.
  • generated.ts - the Firestore contract (TypeScript): read/write/update views, the read converter (doc-id injection), open string enums, a typed path helper. It imports MessageKind from ./dtos (via --shared-from) instead of redefining it, so every type is defined exactly once across the two files.
  • bundle.json - the deterministic contract bundle (--bundle-out): the enriched JSON Schema that both the TypeScript above and the compatibility gate consume. It is the artifact a project freezes as schema history (see ../../compat/).

Regenerate

just example
# which runs:
firepact-gen --plain --module examples.gen.chat.dtos --output examples/gen/chat/dtos.ts
firepact-gen --module examples.gen.chat.models --output examples/gen/chat/generated.ts \
  --shared ./dtos --shared-from examples.gen.chat.dtos

--shared-from examples.gen.chat.dtos derives the shared names from the dtos module's own output (the types it defines), so there is no hand-maintained list and the imported names are guaranteed to exist in dtos.ts; firepact imports only the ones the Firestore docs actually reference.

tests/integration/test_emit_chain.py keeps both outputs from drifting.