Skip to content

Lifecycle and locales ​

Schemas default to operational: rows are live immediately and edit in place. Opt-in publishing adds status (draft/published/archived), nullable published_at and a scope-aware (published_at, id) index.

Generated <table>.publish, .unpublish and .archive Procedures take { id, expectedVersion }, require admin/system and perform one atomic UPDATE. Publish checks required fields, visibility, TTL, source state and OCC. A failed guard is CONFLICT. Store cannot write status/published_at directly. Admin permits generic publishing edits only on drafts; Store does not add that separate Admin editing rule.

Public Views see published rows only. Other reads expose drafts only to admin/system. This policy applies to joins and nested queries too.

Translations ​

localized: true declares a locale string. translates: { parent, on } declares a localized child sharing a join key with its parent. A scoped parent needs the same child scope column. A publishing translation can publish only when its caller-visible parent is published (or operational); the parent guard is inside the atomic UPDATE. Unpublishing a parent hides translations without changing their status.

Store translation reads merge visible parent fields, with child fields taking precedence. Authored Views return only their SELECT outputs. Generated translations.ts exports translationLocales(db, caller, parent, rows) for a parent page (up to 500 storage-named rows); it uses batched authorized child reads rather than one query per parent. Stored locale values remain plain strings; site locales do not rewrite or validate them automatically.

SQLite/PostgreSQL interactive Store transactions refuse to combine translation publication and a parent status change in either order. D1 has no interactive Store transactions. The app owns consistency for native transactions outside Store.

Expiry ​

TTL hides expired rows but does not delete them. Use generated system-only <schema>.sweepExpired from an application scheduler; TTL maintenance defines limits and cursors. Until removed, expired rows still occupy unique keys.