@reblu/site-contracts 1.7.0 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # @reblu/site-contracts
2
2
 
3
+ ## 1.8.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 23af6d5: `GET /api/site/pages/[slug]`'s `resolved` embed object (on `page_embed`/
8
+ `profile_embed` blocks, and their deprecated `doctor_embed`/`specialty_embed`
9
+ aliases) gains the target page's own `pageType` and `category: { name, slug }
10
+ | null` — so a SITE can build the embed's href/breadcrumb without a second
11
+ read. Both fields are OPTIONAL on `ResolvedEmbed`/`PageBlock['resolved']` —
12
+ additive for a consumer validating an older payload — but the route itself
13
+ always emits them.
14
+
15
+ `profile_embed` (and its deprecated `doctor_embed` alias) now resolve ONLY
16
+ when the referenced page is `pageType: 'team'`: any other published page
17
+ (a real, existing page of another pageType) degrades to `resolved: null`,
18
+ same as an unknown or unpublished slug. `page_embed`/`specialty_embed` are
19
+ unaffected — they keep resolving ANY published page regardless of pageType.
20
+
21
+ No new exported types — `pageType`/`category` widen the existing
22
+ `ResolvedEmbed` shape.
23
+
3
24
  ## 1.7.0
4
25
 
5
26
  ### Minor Changes
package/README.md CHANGED
@@ -30,7 +30,7 @@ async function getPosts(): Promise<{ data: BlogPostListItem[] }> {
30
30
  Pair it with `@reblu/site-client` for a typed client that already knows these
31
31
  shapes.
32
32
 
33
- ### Page blocks — canonical shape (REB-849 / REB-851 / REB-852)
33
+ ### Page blocks — canonical shape (REB-849 / REB-851 / REB-852 / REB-854)
34
34
 
35
35
  `GET /api/site/pages/[slug]` (`PageDetail`) returns BOTH `sections[]` (legacy,
36
36
  unchanged) and `blocks[]` (`PageBlock[]`, the typed registry — REB-75 D-D). A
@@ -63,7 +63,9 @@ const block: PageBlock = {
63
63
  data: { pageSlug: 'dra-perez' },
64
64
  // Present ONLY on page_embed/profile_embed blocks (optional on the type,
65
65
  // omitted entirely for every other blockType). null when the referenced
66
- // slug is unknown, unpublished, or belongs to another tenant.
66
+ // slug is unknown, unpublished, belongs to another tenant, OR — for
67
+ // profile_embed/doctor_embed specifically — is a real published page that
68
+ // is NOT pageType='team' (REB-854).
67
69
  resolved: {
68
70
  slug: 'dra-perez',
69
71
  title: 'Dra. Pérez',
@@ -72,14 +74,32 @@ const block: PageBlock = {
72
74
  // Sourced from the referenced page's professional profile ONLY when
73
75
  // that page is pageType='team' — null otherwise (e.g. any other page).
74
76
  role: 'Dermatóloga',
77
+ // REB-854: the target's own pageType/category — so a SITE can build the
78
+ // embed's href/breadcrumb with NO extra read. Optional on the type
79
+ // (additive for an older payload); the route always emits both.
80
+ pageType: 'team',
81
+ category: null,
75
82
  },
76
83
  }
77
84
  ```
78
85
 
79
86
  `heading`/`backgroundColor` are `string | null`; `cta` is `BlockCta` (`{
80
87
  label, url, isExternal, variant } | null`); `resolved` is `ResolvedEmbed | null`
81
- (`{ slug, title, excerpt, coverImageUrl, role }`). `sections[]` is never
82
- mutated by either feature.
88
+ (`{ slug, title, excerpt, coverImageUrl, role, pageType?, category? }`).
89
+ `sections[]` is never mutated by any of these features.
90
+
91
+ **REB-854 guarantees:**
92
+
93
+ - `resolved` carries the target page's own `pageType` and `category: { name,
94
+ slug } | null`, so a SITE can build the embed's href (or a breadcrumb) from
95
+ `resolved` alone — no second fetch against `GET /api/site/pages/[slug]` or
96
+ `GET /api/site/pages` for the referenced page.
97
+ - A `profile_embed` block (and its deprecated `doctor_embed` alias) resolves
98
+ ONLY when the referenced page is `pageType: 'team'`. Any other published
99
+ page — a real, existing page of another `pageType` — degrades `resolved`
100
+ to `null`, exactly like an unknown or unpublished slug. `page_embed` (and
101
+ its deprecated `specialty_embed` alias) are unaffected: they keep
102
+ resolving ANY published page regardless of `pageType`.
83
103
 
84
104
  #### `page_embed` / `profile_embed` — niche-agnostic, and their deprecated aliases
85
105
 
package/dist/index.d.cts CHANGED
@@ -89,13 +89,13 @@ export type LegacyPageType = "SERVICE" | "CUSTOM"
89
89
 
90
90
  export type Legal = { privacyPolicy: string | null; termsAndConditions: string | null; cookiePolicy: string | null;}
91
91
 
92
- export type PageBlock = { id: string; order: number; heading?: string | null | undefined; backgroundColor?: string | null | undefined; cta?: { label: string; url: string; isExternal: boolean; variant: string | null; } | null | undefined; resolved?: { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; } | null | undefined; blockType: "hero"; data: { title: string; subtitle?: string | undefined; imageUrl?: string | undefined; ctaSlot?: string | undefined; };} | { id: string; order: number; heading?: string | null | undefined; backgroundColor?: string | null | undefined; cta?: { label: string; url: string; isExternal: boolean; variant: string | null; } | null | undefined; resolved?: { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; } | null | undefined; blockType: "richtext"; data: { html: string; };} | { id: string; order: number; heading?: string | null | undefined; backgroundColor?: string | null | undefined; cta?: { label: string; url: string; isExternal: boolean; variant: string | null; } | null | undefined; resolved?: { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; } | null | undefined; blockType: "faq"; data: { items: { q: string; a: string; }[]; };} | { id: string; order: number; heading?: string | null | undefined; backgroundColor?: string | null | undefined; cta?: { label: string; url: string; isExternal: boolean; variant: string | null; } | null | undefined; resolved?: { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; } | null | undefined; blockType: "stats"; data: { items: { label: string; value: string; }[]; };} | { id: string; order: number; heading?: string | null | undefined; backgroundColor?: string | null | undefined; cta?: { label: string; url: string; isExternal: boolean; variant: string | null; } | null | undefined; resolved?: { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; } | null | undefined; blockType: "testimonial"; data: { quote: string; author: string; role?: string | undefined; avatarUrl?: string | undefined; };} | { id: string; order: number; heading?: string | null | undefined; backgroundColor?: string | null | undefined; cta?: { label: string; url: string; isExternal: boolean; variant: string | null; } | null | undefined; resolved?: { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; } | null | undefined; blockType: "cta"; data: { slot: string; };} | { id: string; order: number; heading?: string | null | undefined; backgroundColor?: string | null | undefined; cta?: { label: string; url: string; isExternal: boolean; variant: string | null; } | null | undefined; resolved?: { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; } | null | undefined; blockType: "feature_list"; data: { items: { text: string; icon?: string | undefined; }[]; };} | { id: string; order: number; heading?: string | null | undefined; backgroundColor?: string | null | undefined; cta?: { label: string; url: string; isExternal: boolean; variant: string | null; } | null | undefined; resolved?: { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; } | null | undefined; blockType: "gallery"; data: { images: { url: string; alt?: string | undefined; caption?: string | undefined; }[]; };} | { id: string; order: number; heading?: string | null | undefined; backgroundColor?: string | null | undefined; cta?: { label: string; url: string; isExternal: boolean; variant: string | null; } | null | undefined; resolved?: { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; } | null | undefined; blockType: "page_embed"; data: { pageSlug: string; };} | { id: string; order: number; heading?: string | null | undefined; backgroundColor?: string | null | undefined; cta?: { label: string; url: string; isExternal: boolean; variant: string | null; } | null | undefined; resolved?: { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; } | null | undefined; blockType: "profile_embed"; data: { pageSlug: string; };} | { id: string; order: number; heading?: string | null | undefined; backgroundColor?: string | null | undefined; cta?: { label: string; url: string; isExternal: boolean; variant: string | null; } | null | undefined; resolved?: { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; } | null | undefined; blockType: "doctor_embed"; data: { pageSlug: string; };} | { id: string; order: number; heading?: string | null | undefined; backgroundColor?: string | null | undefined; cta?: { label: string; url: string; isExternal: boolean; variant: string | null; } | null | undefined; resolved?: { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; } | null | undefined; blockType: "specialty_embed"; data: { pageSlug: string; };}
92
+ export type PageBlock = { id: string; order: number; heading?: string | null | undefined; backgroundColor?: string | null | undefined; cta?: { label: string; url: string; isExternal: boolean; variant: string | null; } | null | undefined; resolved?: { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; pageType?: "custom" | "service" | "treatments" | "specialties" | "team" | "generic" | undefined; category?: { name: string; slug: string; } | null | undefined; } | null | undefined; blockType: "hero"; data: { title: string; subtitle?: string | undefined; imageUrl?: string | undefined; ctaSlot?: string | undefined; };} | { id: string; order: number; heading?: string | null | undefined; backgroundColor?: string | null | undefined; cta?: { label: string; url: string; isExternal: boolean; variant: string | null; } | null | undefined; resolved?: { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; pageType?: "custom" | "service" | "treatments" | "specialties" | "team" | "generic" | undefined; category?: { name: string; slug: string; } | null | undefined; } | null | undefined; blockType: "richtext"; data: { html: string; };} | { id: string; order: number; heading?: string | null | undefined; backgroundColor?: string | null | undefined; cta?: { label: string; url: string; isExternal: boolean; variant: string | null; } | null | undefined; resolved?: { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; pageType?: "custom" | "service" | "treatments" | "specialties" | "team" | "generic" | undefined; category?: { name: string; slug: string; } | null | undefined; } | null | undefined; blockType: "faq"; data: { items: { q: string; a: string; }[]; };} | { id: string; order: number; heading?: string | null | undefined; backgroundColor?: string | null | undefined; cta?: { label: string; url: string; isExternal: boolean; variant: string | null; } | null | undefined; resolved?: { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; pageType?: "custom" | "service" | "treatments" | "specialties" | "team" | "generic" | undefined; category?: { name: string; slug: string; } | null | undefined; } | null | undefined; blockType: "stats"; data: { items: { label: string; value: string; }[]; };} | { id: string; order: number; heading?: string | null | undefined; backgroundColor?: string | null | undefined; cta?: { label: string; url: string; isExternal: boolean; variant: string | null; } | null | undefined; resolved?: { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; pageType?: "custom" | "service" | "treatments" | "specialties" | "team" | "generic" | undefined; category?: { name: string; slug: string; } | null | undefined; } | null | undefined; blockType: "testimonial"; data: { quote: string; author: string; role?: string | undefined; avatarUrl?: string | undefined; };} | { id: string; order: number; heading?: string | null | undefined; backgroundColor?: string | null | undefined; cta?: { label: string; url: string; isExternal: boolean; variant: string | null; } | null | undefined; resolved?: { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; pageType?: "custom" | "service" | "treatments" | "specialties" | "team" | "generic" | undefined; category?: { name: string; slug: string; } | null | undefined; } | null | undefined; blockType: "cta"; data: { slot: string; };} | { id: string; order: number; heading?: string | null | undefined; backgroundColor?: string | null | undefined; cta?: { label: string; url: string; isExternal: boolean; variant: string | null; } | null | undefined; resolved?: { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; pageType?: "custom" | "service" | "treatments" | "specialties" | "team" | "generic" | undefined; category?: { name: string; slug: string; } | null | undefined; } | null | undefined; blockType: "feature_list"; data: { items: { text: string; icon?: string | undefined; }[]; };} | { id: string; order: number; heading?: string | null | undefined; backgroundColor?: string | null | undefined; cta?: { label: string; url: string; isExternal: boolean; variant: string | null; } | null | undefined; resolved?: { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; pageType?: "custom" | "service" | "treatments" | "specialties" | "team" | "generic" | undefined; category?: { name: string; slug: string; } | null | undefined; } | null | undefined; blockType: "gallery"; data: { images: { url: string; alt?: string | undefined; caption?: string | undefined; }[]; };} | { id: string; order: number; heading?: string | null | undefined; backgroundColor?: string | null | undefined; cta?: { label: string; url: string; isExternal: boolean; variant: string | null; } | null | undefined; resolved?: { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; pageType?: "custom" | "service" | "treatments" | "specialties" | "team" | "generic" | undefined; category?: { name: string; slug: string; } | null | undefined; } | null | undefined; blockType: "page_embed"; data: { pageSlug: string; };} | { id: string; order: number; heading?: string | null | undefined; backgroundColor?: string | null | undefined; cta?: { label: string; url: string; isExternal: boolean; variant: string | null; } | null | undefined; resolved?: { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; pageType?: "custom" | "service" | "treatments" | "specialties" | "team" | "generic" | undefined; category?: { name: string; slug: string; } | null | undefined; } | null | undefined; blockType: "profile_embed"; data: { pageSlug: string; };} | { id: string; order: number; heading?: string | null | undefined; backgroundColor?: string | null | undefined; cta?: { label: string; url: string; isExternal: boolean; variant: string | null; } | null | undefined; resolved?: { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; pageType?: "custom" | "service" | "treatments" | "specialties" | "team" | "generic" | undefined; category?: { name: string; slug: string; } | null | undefined; } | null | undefined; blockType: "doctor_embed"; data: { pageSlug: string; };} | { id: string; order: number; heading?: string | null | undefined; backgroundColor?: string | null | undefined; cta?: { label: string; url: string; isExternal: boolean; variant: string | null; } | null | undefined; resolved?: { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; pageType?: "custom" | "service" | "treatments" | "specialties" | "team" | "generic" | undefined; category?: { name: string; slug: string; } | null | undefined; } | null | undefined; blockType: "specialty_embed"; data: { pageSlug: string; };}
93
93
 
94
94
  export type PageCategoryRef = { name: string; slug: string;}
95
95
 
96
96
  export type PageContentMode = "BLOCKS" | "HTML"
97
97
 
98
- export type PageDetail = { slug: string; title: string; subtitle: string | null; excerpt: string | null; coverImageUrl: string | null; type: "SERVICE" | "CUSTOM"; pageType: "custom" | "service" | "treatments" | "specialties" | "team" | "generic"; contentMode: "BLOCKS" | "HTML"; customHtml: string | null; seoTitle: string | null; seoDescription: string | null; category: { name: string; slug: string; } | null; sections: { id: string; order: number; heading: string | null; contentHtml: string; layout: "TEXT" | "TEXT_IMAGE" | "IMAGE_TEXT" | "IMAGE_FULL" | "FEATURE_LIST" | "GALLERY" | "CTA_BLOCK"; backgroundColor: string | null; features: unknown; ctaLabel: string | null; ctaUrl: string | null; ctaIsExternal: boolean; ctaVariant: string | null; images: { url: string; alt: string; caption: string | null; order: number; }[]; }[]; blocks: ({ id: string; order: number; heading?: string | null | undefined; backgroundColor?: string | null | undefined; cta?: { label: string; url: string; isExternal: boolean; variant: string | null; } | null | undefined; resolved?: { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; } | null | undefined; } & ({ blockType: "hero"; data: { title: string; subtitle?: string | undefined; imageUrl?: string | undefined; ctaSlot?: string | undefined; }; } | { blockType: "richtext"; data: { html: string; }; } | { blockType: "faq"; data: { items: { q: string; a: string; }[]; }; } | { blockType: "stats"; data: { items: { label: string; value: string; }[]; }; } | { blockType: "testimonial"; data: { quote: string; author: string; role?: string | undefined; avatarUrl?: string | undefined; }; } | { blockType: "cta"; data: { slot: string; }; } | { blockType: "feature_list"; data: { items: { text: string; icon?: string | undefined; }[]; }; } | { blockType: "gallery"; data: { images: { url: string; alt?: string | undefined; caption?: string | undefined; }[]; }; } | { blockType: "page_embed"; data: { pageSlug: string; }; } | { blockType: "profile_embed"; data: { pageSlug: string; }; } | { blockType: "doctor_embed"; data: { pageSlug: string; }; } | { blockType: "specialty_embed"; data: { pageSlug: string; }; }))[]; jsonLd: unknown; professional: { role: string | null; socialLinks: { platform: "linkedin" | "twitter" | "facebook" | "instagram" | "website" | "other"; url: string; }[]; cv: { education: { id: string; title: string; organization: string | null; startYear: number | null; endYear: number | null; description: string | null; }[]; experience: { id: string; title: string; organization: string | null; startYear: number | null; endYear: number | null; description: string | null; }[]; certifications: { id: string; title: string; organization: string | null; startYear: number | null; endYear: number | null; description: string | null; }[]; memberships: { id: string; title: string; organization: string | null; startYear: number | null; endYear: number | null; description: string | null; }[]; languages: { language: string; level: "basic" | "conversational" | "fluent" | "native" | null; }[]; } | null; } | null;}
98
+ export type PageDetail = { slug: string; title: string; subtitle: string | null; excerpt: string | null; coverImageUrl: string | null; type: "SERVICE" | "CUSTOM"; pageType: "custom" | "service" | "treatments" | "specialties" | "team" | "generic"; contentMode: "BLOCKS" | "HTML"; customHtml: string | null; seoTitle: string | null; seoDescription: string | null; category: { name: string; slug: string; } | null; sections: { id: string; order: number; heading: string | null; contentHtml: string; layout: "TEXT" | "TEXT_IMAGE" | "IMAGE_TEXT" | "IMAGE_FULL" | "FEATURE_LIST" | "GALLERY" | "CTA_BLOCK"; backgroundColor: string | null; features: unknown; ctaLabel: string | null; ctaUrl: string | null; ctaIsExternal: boolean; ctaVariant: string | null; images: { url: string; alt: string; caption: string | null; order: number; }[]; }[]; blocks: ({ id: string; order: number; heading?: string | null | undefined; backgroundColor?: string | null | undefined; cta?: { label: string; url: string; isExternal: boolean; variant: string | null; } | null | undefined; resolved?: { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; pageType?: "custom" | "service" | "treatments" | "specialties" | "team" | "generic" | undefined; category?: { name: string; slug: string; } | null | undefined; } | null | undefined; } & ({ blockType: "hero"; data: { title: string; subtitle?: string | undefined; imageUrl?: string | undefined; ctaSlot?: string | undefined; }; } | { blockType: "richtext"; data: { html: string; }; } | { blockType: "faq"; data: { items: { q: string; a: string; }[]; }; } | { blockType: "stats"; data: { items: { label: string; value: string; }[]; }; } | { blockType: "testimonial"; data: { quote: string; author: string; role?: string | undefined; avatarUrl?: string | undefined; }; } | { blockType: "cta"; data: { slot: string; }; } | { blockType: "feature_list"; data: { items: { text: string; icon?: string | undefined; }[]; }; } | { blockType: "gallery"; data: { images: { url: string; alt?: string | undefined; caption?: string | undefined; }[]; }; } | { blockType: "page_embed"; data: { pageSlug: string; }; } | { blockType: "profile_embed"; data: { pageSlug: string; }; } | { blockType: "doctor_embed"; data: { pageSlug: string; }; } | { blockType: "specialty_embed"; data: { pageSlug: string; }; }))[]; jsonLd: unknown; professional: { role: string | null; socialLinks: { platform: "linkedin" | "twitter" | "facebook" | "instagram" | "website" | "other"; url: string; }[]; cv: { education: { id: string; title: string; organization: string | null; startYear: number | null; endYear: number | null; description: string | null; }[]; experience: { id: string; title: string; organization: string | null; startYear: number | null; endYear: number | null; description: string | null; }[]; certifications: { id: string; title: string; organization: string | null; startYear: number | null; endYear: number | null; description: string | null; }[]; memberships: { id: string; title: string; organization: string | null; startYear: number | null; endYear: number | null; description: string | null; }[]; languages: { language: string; level: "basic" | "conversational" | "fluent" | "native" | null; }[]; } | null; } | null;}
99
99
 
100
100
  export type PageListItem = { slug: string; title: string; subtitle: string | null; excerpt: string | null; coverImageUrl: string | null; type: "SERVICE" | "CUSTOM"; pageType: "custom" | "service" | "treatments" | "specialties" | "team" | "generic"; order: number; seoTitle: string | null; seoDescription: string | null; category: { name: string; slug: string; } | null; professional: { role: string | null; } | null;}
101
101
 
@@ -129,7 +129,7 @@ export type ProfessionalSocialPlatform = "linkedin" | "twitter" | "facebook" | "
129
129
 
130
130
  export type ProfessionalSummary = { role: string | null;}
131
131
 
132
- export type ResolvedEmbed = { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null;}
132
+ export type ResolvedEmbed = { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; pageType?: "custom" | "service" | "treatments" | "specialties" | "team" | "generic" | undefined; category?: { name: string; slug: string; } | null | undefined;}
133
133
 
134
134
  export type SectionLayout = "TEXT" | "TEXT_IMAGE" | "IMAGE_TEXT" | "IMAGE_FULL" | "FEATURE_LIST" | "GALLERY" | "CTA_BLOCK"
135
135
 
package/dist/index.d.ts CHANGED
@@ -89,13 +89,13 @@ export type LegacyPageType = "SERVICE" | "CUSTOM"
89
89
 
90
90
  export type Legal = { privacyPolicy: string | null; termsAndConditions: string | null; cookiePolicy: string | null;}
91
91
 
92
- export type PageBlock = { id: string; order: number; heading?: string | null | undefined; backgroundColor?: string | null | undefined; cta?: { label: string; url: string; isExternal: boolean; variant: string | null; } | null | undefined; resolved?: { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; } | null | undefined; blockType: "hero"; data: { title: string; subtitle?: string | undefined; imageUrl?: string | undefined; ctaSlot?: string | undefined; };} | { id: string; order: number; heading?: string | null | undefined; backgroundColor?: string | null | undefined; cta?: { label: string; url: string; isExternal: boolean; variant: string | null; } | null | undefined; resolved?: { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; } | null | undefined; blockType: "richtext"; data: { html: string; };} | { id: string; order: number; heading?: string | null | undefined; backgroundColor?: string | null | undefined; cta?: { label: string; url: string; isExternal: boolean; variant: string | null; } | null | undefined; resolved?: { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; } | null | undefined; blockType: "faq"; data: { items: { q: string; a: string; }[]; };} | { id: string; order: number; heading?: string | null | undefined; backgroundColor?: string | null | undefined; cta?: { label: string; url: string; isExternal: boolean; variant: string | null; } | null | undefined; resolved?: { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; } | null | undefined; blockType: "stats"; data: { items: { label: string; value: string; }[]; };} | { id: string; order: number; heading?: string | null | undefined; backgroundColor?: string | null | undefined; cta?: { label: string; url: string; isExternal: boolean; variant: string | null; } | null | undefined; resolved?: { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; } | null | undefined; blockType: "testimonial"; data: { quote: string; author: string; role?: string | undefined; avatarUrl?: string | undefined; };} | { id: string; order: number; heading?: string | null | undefined; backgroundColor?: string | null | undefined; cta?: { label: string; url: string; isExternal: boolean; variant: string | null; } | null | undefined; resolved?: { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; } | null | undefined; blockType: "cta"; data: { slot: string; };} | { id: string; order: number; heading?: string | null | undefined; backgroundColor?: string | null | undefined; cta?: { label: string; url: string; isExternal: boolean; variant: string | null; } | null | undefined; resolved?: { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; } | null | undefined; blockType: "feature_list"; data: { items: { text: string; icon?: string | undefined; }[]; };} | { id: string; order: number; heading?: string | null | undefined; backgroundColor?: string | null | undefined; cta?: { label: string; url: string; isExternal: boolean; variant: string | null; } | null | undefined; resolved?: { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; } | null | undefined; blockType: "gallery"; data: { images: { url: string; alt?: string | undefined; caption?: string | undefined; }[]; };} | { id: string; order: number; heading?: string | null | undefined; backgroundColor?: string | null | undefined; cta?: { label: string; url: string; isExternal: boolean; variant: string | null; } | null | undefined; resolved?: { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; } | null | undefined; blockType: "page_embed"; data: { pageSlug: string; };} | { id: string; order: number; heading?: string | null | undefined; backgroundColor?: string | null | undefined; cta?: { label: string; url: string; isExternal: boolean; variant: string | null; } | null | undefined; resolved?: { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; } | null | undefined; blockType: "profile_embed"; data: { pageSlug: string; };} | { id: string; order: number; heading?: string | null | undefined; backgroundColor?: string | null | undefined; cta?: { label: string; url: string; isExternal: boolean; variant: string | null; } | null | undefined; resolved?: { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; } | null | undefined; blockType: "doctor_embed"; data: { pageSlug: string; };} | { id: string; order: number; heading?: string | null | undefined; backgroundColor?: string | null | undefined; cta?: { label: string; url: string; isExternal: boolean; variant: string | null; } | null | undefined; resolved?: { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; } | null | undefined; blockType: "specialty_embed"; data: { pageSlug: string; };}
92
+ export type PageBlock = { id: string; order: number; heading?: string | null | undefined; backgroundColor?: string | null | undefined; cta?: { label: string; url: string; isExternal: boolean; variant: string | null; } | null | undefined; resolved?: { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; pageType?: "custom" | "service" | "treatments" | "specialties" | "team" | "generic" | undefined; category?: { name: string; slug: string; } | null | undefined; } | null | undefined; blockType: "hero"; data: { title: string; subtitle?: string | undefined; imageUrl?: string | undefined; ctaSlot?: string | undefined; };} | { id: string; order: number; heading?: string | null | undefined; backgroundColor?: string | null | undefined; cta?: { label: string; url: string; isExternal: boolean; variant: string | null; } | null | undefined; resolved?: { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; pageType?: "custom" | "service" | "treatments" | "specialties" | "team" | "generic" | undefined; category?: { name: string; slug: string; } | null | undefined; } | null | undefined; blockType: "richtext"; data: { html: string; };} | { id: string; order: number; heading?: string | null | undefined; backgroundColor?: string | null | undefined; cta?: { label: string; url: string; isExternal: boolean; variant: string | null; } | null | undefined; resolved?: { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; pageType?: "custom" | "service" | "treatments" | "specialties" | "team" | "generic" | undefined; category?: { name: string; slug: string; } | null | undefined; } | null | undefined; blockType: "faq"; data: { items: { q: string; a: string; }[]; };} | { id: string; order: number; heading?: string | null | undefined; backgroundColor?: string | null | undefined; cta?: { label: string; url: string; isExternal: boolean; variant: string | null; } | null | undefined; resolved?: { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; pageType?: "custom" | "service" | "treatments" | "specialties" | "team" | "generic" | undefined; category?: { name: string; slug: string; } | null | undefined; } | null | undefined; blockType: "stats"; data: { items: { label: string; value: string; }[]; };} | { id: string; order: number; heading?: string | null | undefined; backgroundColor?: string | null | undefined; cta?: { label: string; url: string; isExternal: boolean; variant: string | null; } | null | undefined; resolved?: { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; pageType?: "custom" | "service" | "treatments" | "specialties" | "team" | "generic" | undefined; category?: { name: string; slug: string; } | null | undefined; } | null | undefined; blockType: "testimonial"; data: { quote: string; author: string; role?: string | undefined; avatarUrl?: string | undefined; };} | { id: string; order: number; heading?: string | null | undefined; backgroundColor?: string | null | undefined; cta?: { label: string; url: string; isExternal: boolean; variant: string | null; } | null | undefined; resolved?: { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; pageType?: "custom" | "service" | "treatments" | "specialties" | "team" | "generic" | undefined; category?: { name: string; slug: string; } | null | undefined; } | null | undefined; blockType: "cta"; data: { slot: string; };} | { id: string; order: number; heading?: string | null | undefined; backgroundColor?: string | null | undefined; cta?: { label: string; url: string; isExternal: boolean; variant: string | null; } | null | undefined; resolved?: { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; pageType?: "custom" | "service" | "treatments" | "specialties" | "team" | "generic" | undefined; category?: { name: string; slug: string; } | null | undefined; } | null | undefined; blockType: "feature_list"; data: { items: { text: string; icon?: string | undefined; }[]; };} | { id: string; order: number; heading?: string | null | undefined; backgroundColor?: string | null | undefined; cta?: { label: string; url: string; isExternal: boolean; variant: string | null; } | null | undefined; resolved?: { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; pageType?: "custom" | "service" | "treatments" | "specialties" | "team" | "generic" | undefined; category?: { name: string; slug: string; } | null | undefined; } | null | undefined; blockType: "gallery"; data: { images: { url: string; alt?: string | undefined; caption?: string | undefined; }[]; };} | { id: string; order: number; heading?: string | null | undefined; backgroundColor?: string | null | undefined; cta?: { label: string; url: string; isExternal: boolean; variant: string | null; } | null | undefined; resolved?: { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; pageType?: "custom" | "service" | "treatments" | "specialties" | "team" | "generic" | undefined; category?: { name: string; slug: string; } | null | undefined; } | null | undefined; blockType: "page_embed"; data: { pageSlug: string; };} | { id: string; order: number; heading?: string | null | undefined; backgroundColor?: string | null | undefined; cta?: { label: string; url: string; isExternal: boolean; variant: string | null; } | null | undefined; resolved?: { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; pageType?: "custom" | "service" | "treatments" | "specialties" | "team" | "generic" | undefined; category?: { name: string; slug: string; } | null | undefined; } | null | undefined; blockType: "profile_embed"; data: { pageSlug: string; };} | { id: string; order: number; heading?: string | null | undefined; backgroundColor?: string | null | undefined; cta?: { label: string; url: string; isExternal: boolean; variant: string | null; } | null | undefined; resolved?: { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; pageType?: "custom" | "service" | "treatments" | "specialties" | "team" | "generic" | undefined; category?: { name: string; slug: string; } | null | undefined; } | null | undefined; blockType: "doctor_embed"; data: { pageSlug: string; };} | { id: string; order: number; heading?: string | null | undefined; backgroundColor?: string | null | undefined; cta?: { label: string; url: string; isExternal: boolean; variant: string | null; } | null | undefined; resolved?: { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; pageType?: "custom" | "service" | "treatments" | "specialties" | "team" | "generic" | undefined; category?: { name: string; slug: string; } | null | undefined; } | null | undefined; blockType: "specialty_embed"; data: { pageSlug: string; };}
93
93
 
94
94
  export type PageCategoryRef = { name: string; slug: string;}
95
95
 
96
96
  export type PageContentMode = "BLOCKS" | "HTML"
97
97
 
98
- export type PageDetail = { slug: string; title: string; subtitle: string | null; excerpt: string | null; coverImageUrl: string | null; type: "SERVICE" | "CUSTOM"; pageType: "custom" | "service" | "treatments" | "specialties" | "team" | "generic"; contentMode: "BLOCKS" | "HTML"; customHtml: string | null; seoTitle: string | null; seoDescription: string | null; category: { name: string; slug: string; } | null; sections: { id: string; order: number; heading: string | null; contentHtml: string; layout: "TEXT" | "TEXT_IMAGE" | "IMAGE_TEXT" | "IMAGE_FULL" | "FEATURE_LIST" | "GALLERY" | "CTA_BLOCK"; backgroundColor: string | null; features: unknown; ctaLabel: string | null; ctaUrl: string | null; ctaIsExternal: boolean; ctaVariant: string | null; images: { url: string; alt: string; caption: string | null; order: number; }[]; }[]; blocks: ({ id: string; order: number; heading?: string | null | undefined; backgroundColor?: string | null | undefined; cta?: { label: string; url: string; isExternal: boolean; variant: string | null; } | null | undefined; resolved?: { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; } | null | undefined; } & ({ blockType: "hero"; data: { title: string; subtitle?: string | undefined; imageUrl?: string | undefined; ctaSlot?: string | undefined; }; } | { blockType: "richtext"; data: { html: string; }; } | { blockType: "faq"; data: { items: { q: string; a: string; }[]; }; } | { blockType: "stats"; data: { items: { label: string; value: string; }[]; }; } | { blockType: "testimonial"; data: { quote: string; author: string; role?: string | undefined; avatarUrl?: string | undefined; }; } | { blockType: "cta"; data: { slot: string; }; } | { blockType: "feature_list"; data: { items: { text: string; icon?: string | undefined; }[]; }; } | { blockType: "gallery"; data: { images: { url: string; alt?: string | undefined; caption?: string | undefined; }[]; }; } | { blockType: "page_embed"; data: { pageSlug: string; }; } | { blockType: "profile_embed"; data: { pageSlug: string; }; } | { blockType: "doctor_embed"; data: { pageSlug: string; }; } | { blockType: "specialty_embed"; data: { pageSlug: string; }; }))[]; jsonLd: unknown; professional: { role: string | null; socialLinks: { platform: "linkedin" | "twitter" | "facebook" | "instagram" | "website" | "other"; url: string; }[]; cv: { education: { id: string; title: string; organization: string | null; startYear: number | null; endYear: number | null; description: string | null; }[]; experience: { id: string; title: string; organization: string | null; startYear: number | null; endYear: number | null; description: string | null; }[]; certifications: { id: string; title: string; organization: string | null; startYear: number | null; endYear: number | null; description: string | null; }[]; memberships: { id: string; title: string; organization: string | null; startYear: number | null; endYear: number | null; description: string | null; }[]; languages: { language: string; level: "basic" | "conversational" | "fluent" | "native" | null; }[]; } | null; } | null;}
98
+ export type PageDetail = { slug: string; title: string; subtitle: string | null; excerpt: string | null; coverImageUrl: string | null; type: "SERVICE" | "CUSTOM"; pageType: "custom" | "service" | "treatments" | "specialties" | "team" | "generic"; contentMode: "BLOCKS" | "HTML"; customHtml: string | null; seoTitle: string | null; seoDescription: string | null; category: { name: string; slug: string; } | null; sections: { id: string; order: number; heading: string | null; contentHtml: string; layout: "TEXT" | "TEXT_IMAGE" | "IMAGE_TEXT" | "IMAGE_FULL" | "FEATURE_LIST" | "GALLERY" | "CTA_BLOCK"; backgroundColor: string | null; features: unknown; ctaLabel: string | null; ctaUrl: string | null; ctaIsExternal: boolean; ctaVariant: string | null; images: { url: string; alt: string; caption: string | null; order: number; }[]; }[]; blocks: ({ id: string; order: number; heading?: string | null | undefined; backgroundColor?: string | null | undefined; cta?: { label: string; url: string; isExternal: boolean; variant: string | null; } | null | undefined; resolved?: { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; pageType?: "custom" | "service" | "treatments" | "specialties" | "team" | "generic" | undefined; category?: { name: string; slug: string; } | null | undefined; } | null | undefined; } & ({ blockType: "hero"; data: { title: string; subtitle?: string | undefined; imageUrl?: string | undefined; ctaSlot?: string | undefined; }; } | { blockType: "richtext"; data: { html: string; }; } | { blockType: "faq"; data: { items: { q: string; a: string; }[]; }; } | { blockType: "stats"; data: { items: { label: string; value: string; }[]; }; } | { blockType: "testimonial"; data: { quote: string; author: string; role?: string | undefined; avatarUrl?: string | undefined; }; } | { blockType: "cta"; data: { slot: string; }; } | { blockType: "feature_list"; data: { items: { text: string; icon?: string | undefined; }[]; }; } | { blockType: "gallery"; data: { images: { url: string; alt?: string | undefined; caption?: string | undefined; }[]; }; } | { blockType: "page_embed"; data: { pageSlug: string; }; } | { blockType: "profile_embed"; data: { pageSlug: string; }; } | { blockType: "doctor_embed"; data: { pageSlug: string; }; } | { blockType: "specialty_embed"; data: { pageSlug: string; }; }))[]; jsonLd: unknown; professional: { role: string | null; socialLinks: { platform: "linkedin" | "twitter" | "facebook" | "instagram" | "website" | "other"; url: string; }[]; cv: { education: { id: string; title: string; organization: string | null; startYear: number | null; endYear: number | null; description: string | null; }[]; experience: { id: string; title: string; organization: string | null; startYear: number | null; endYear: number | null; description: string | null; }[]; certifications: { id: string; title: string; organization: string | null; startYear: number | null; endYear: number | null; description: string | null; }[]; memberships: { id: string; title: string; organization: string | null; startYear: number | null; endYear: number | null; description: string | null; }[]; languages: { language: string; level: "basic" | "conversational" | "fluent" | "native" | null; }[]; } | null; } | null;}
99
99
 
100
100
  export type PageListItem = { slug: string; title: string; subtitle: string | null; excerpt: string | null; coverImageUrl: string | null; type: "SERVICE" | "CUSTOM"; pageType: "custom" | "service" | "treatments" | "specialties" | "team" | "generic"; order: number; seoTitle: string | null; seoDescription: string | null; category: { name: string; slug: string; } | null; professional: { role: string | null; } | null;}
101
101
 
@@ -129,7 +129,7 @@ export type ProfessionalSocialPlatform = "linkedin" | "twitter" | "facebook" | "
129
129
 
130
130
  export type ProfessionalSummary = { role: string | null;}
131
131
 
132
- export type ResolvedEmbed = { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null;}
132
+ export type ResolvedEmbed = { slug: string; title: string; excerpt: string | null; coverImageUrl: string | null; role: string | null; pageType?: "custom" | "service" | "treatments" | "specialties" | "team" | "generic" | undefined; category?: { name: string; slug: string; } | null | undefined;}
133
133
 
134
134
  export type SectionLayout = "TEXT" | "TEXT_IMAGE" | "IMAGE_TEXT" | "IMAGE_FULL" | "FEATURE_LIST" | "GALLERY" | "CTA_BLOCK"
135
135
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reblu/site-contracts",
3
- "version": "1.7.0",
3
+ "version": "1.8.0",
4
4
  "private": false,
5
5
  "description": "Public, dependency-free TypeScript types for the Reblu SITE API (types only — no Zod, no Prisma at runtime).",
6
6
  "license": "Apache-2.0",