···14 */
1516import type * as PubLeafletDocument from "../api/types/pub/leaflet/document";
17-import type * as PubLeafletPublication from "../api/types/pub/leaflet/publication";
18import type * as PubLeafletContent from "../api/types/pub/leaflet/content";
19import type * as SiteStandardDocument from "../api/types/site/standard/document";
20import type * as SiteStandardPublication from "../api/types/site/standard/publication";
···31};
3233// Normalized publication type - uses the generated site.standard.publication type
34-export type NormalizedPublication = SiteStandardPublication.Record;
00000000000003536/**
37 * Checks if the record is a pub.leaflet.document
···210): NormalizedPublication | null {
211 if (!record || typeof record !== "object") return null;
212213- // Pass through site.standard records directly
214 if (isStandardPublication(record)) {
215- return record;
0000000216 }
217218 if (isLeafletPublication(record)) {
···225226 const basicTheme = leafletThemeToBasicTheme(record.theme);
227000000000000000228 // Convert preferences to site.standard format (strip/replace $type)
229 const preferences: SiteStandardPublication.Preferences | undefined =
230 record.preferences
···243 description: record.description,
244 icon: record.icon,
245 basicTheme,
246- theme: record.theme,
247 preferences,
248 };
249 }
···14 */
1516import type * as PubLeafletDocument from "../api/types/pub/leaflet/document";
17+import * as PubLeafletPublication from "../api/types/pub/leaflet/publication";
18import type * as PubLeafletContent from "../api/types/pub/leaflet/content";
19import type * as SiteStandardDocument from "../api/types/site/standard/document";
20import type * as SiteStandardPublication from "../api/types/site/standard/publication";
···31};
3233// Normalized publication type - uses the generated site.standard.publication type
34+// with the theme narrowed to only the valid pub.leaflet.publication#theme type
35+// (isTheme validates that $type is present, so we use $Typed)
36+// Note: We explicitly list fields rather than using Omit because the generated Record type
37+// has an index signature [k: string]: unknown that interferes with property typing
38+export type NormalizedPublication = {
39+ $type: "site.standard.publication";
40+ name: string;
41+ url: string;
42+ description?: string;
43+ icon?: SiteStandardPublication.Record["icon"];
44+ basicTheme?: SiteStandardThemeBasic.Main;
45+ theme?: $Typed<PubLeafletPublication.Theme>;
46+ preferences?: SiteStandardPublication.Preferences;
47+};
4849/**
50 * Checks if the record is a pub.leaflet.document
···223): NormalizedPublication | null {
224 if (!record || typeof record !== "object") return null;
225226+ // Pass through site.standard records directly, but validate the theme
227 if (isStandardPublication(record)) {
228+ // Validate theme - only keep if it's a valid pub.leaflet.publication#theme
229+ const theme = PubLeafletPublication.isTheme(record.theme)
230+ ? (record.theme as $Typed<PubLeafletPublication.Theme>)
231+ : undefined;
232+ return {
233+ ...record,
234+ theme,
235+ };
236 }
237238 if (isLeafletPublication(record)) {
···245246 const basicTheme = leafletThemeToBasicTheme(record.theme);
247248+ // Validate theme - only keep if it's a valid pub.leaflet.publication#theme with $type set
249+ // For legacy records without $type, add it during normalization
250+ let theme: $Typed<PubLeafletPublication.Theme> | undefined;
251+ if (record.theme) {
252+ if (PubLeafletPublication.isTheme(record.theme)) {
253+ theme = record.theme as $Typed<PubLeafletPublication.Theme>;
254+ } else {
255+ // Legacy theme without $type - add it
256+ theme = {
257+ ...record.theme,
258+ $type: "pub.leaflet.publication#theme",
259+ };
260+ }
261+ }
262+263 // Convert preferences to site.standard format (strip/replace $type)
264 const preferences: SiteStandardPublication.Preferences | undefined =
265 record.preferences
···278 description: record.description,
279 icon: record.icon,
280 basicTheme,
281+ theme,
282 preferences,
283 };
284 }