Repository navigation
better-content 0.9.0
Both adapters now read back the same shape
The seam exists so behaviour does not change when the backend does. Write contracts were pinned per adapter; read shapes were not, and two divergences had survived there in opposite directions:
- The Postgres adapter added a
collectionfield to every record it read. Firestore never did,Itemdoes not declare it, andtoRowalready stripped it going in — so it was synthesized on read rather than stored. It is gone. - The Postgres adapter stripped
createdAtandupdatedAt, which Firestore returned. Those are real stored columns written by the adapter itself, so they are no longer hidden.
The rule both now follow: a read returns the record's stored fields plus id. An adapter neither invents fields nor hides them.
{ id: "hero", title: "Hello", createdAt: "2026-09-06T…", updatedAt: "…" }Timestamps are ISO strings on both backends
Matching field names is not parity if one backend yields a Date and the other a string — and these records are JSON-serialized across createContentHandler and server-rendered payloads, where a Date becomes a string in transit regardless.
Writes accept either form, because an adapter that cannot be handed back what it just returned is not round-trippable, and copying one environment into another does exactly that. That was found by a test rather than by reasoning: the first cut serialized reads and broke seedItemMap.
seedItemMap strips the timestamps too
Alongside id and collection. All four address the record or belong to the adapter rather than being content, and a snapshot read from a backend carries all four. Passing the timestamps through would also have broken the documented promise that createdAt is reset — Firestore's createWithId overrides what it is handed, while Postgres would have inserted it verbatim. Divergence again, one layer up.
⚠️ Behavior change for Postgres consumers
Reading item.collection now returns undefined, and reads carry createdAt/updatedAt that were not there before. Nothing in the library consumed collection from a fetched record, and it was undocumented.
Added
A cross-adapter parity suite running the real Postgres adapter against PGlite and the Firestore adapter against a stub, pinning that the two agree on field names, on how a timestamp is represented, and that each accepts back what it returned. Its first run is what found the timestamp divergence.
Verified against the real Postgres consumer: portfolio-2026 typechecks and builds green, its SSG pages still generating from live Postgres rows.
Docs: adapters
Requires create-better-content@0.8.0 for newly generated apps to pick this up.