@reblu/site-contracts 1.9.0 → 1.11.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,17 @@
1
1
  # @reblu/site-contracts
2
2
 
3
+ ## 1.11.0
4
+
5
+ ### Minor Changes
6
+
7
+ - e4dff25: Resolved page titles (REB-871). `PageDetail`, `BlogPostDetail`, `ShopProductDetail` and `AcademyCourseDetail` gain an optional `seo: { title }` — the final page title, already resolved by the API (the entity's own SEO title as-is when set, otherwise the tenant template applied once to the display title); render it verbatim. `AcademyCourseDetail` also exposes its optional `metaTitle`. `Config` gains an optional `seoTitleTemplate` (the tenant template, already resolved to the default `%s | {siteName}` when unset). New `Seo` type. Purely additive: `seoTitle`/`metaTitle` are unchanged.
8
+
9
+ ## 1.10.0
10
+
11
+ ### Minor Changes
12
+
13
+ - 00b203e: Page slugs are unique per category, not globally (REB-867). `@reblu/site-contracts` adds `PageAmbiguousSlugError` (the 409 `ambiguous_slug` body of `GET /api/site/pages/[slug]`), `EmbedReferenceData` (embed `data` gains optional `pageId`/`categorySlug`) and an optional `category` on `PageSlug`. `@reblu/site-client`'s `pages.bySlug(slug, { category })` addresses a page inside a category (`category: null` = uncategorised) and throws a typed `AmbiguousPageSlugError` (an `ApiError`, status 409, with `candidates`) when a slug exists in several categories; passing a cache policy as the second argument keeps working.
14
+
3
15
  ## 1.9.0
4
16
 
5
17
  ### Minor Changes
package/README.md CHANGED
@@ -113,6 +113,25 @@ longer offered as a choice for a new section in nexus. They will be removed
113
113
  after 2027-01-31, once no tenant data uses them (REB-852) — this release does
114
114
  not migrate existing data.
115
115
 
116
+ ### Page slugs are unique per category (REB-867)
117
+
118
+ A page slug is unique **within its category**, not globally — `micropigmentacion`
119
+ may exist in both `tratamientos` and `especialidades`. Consequences for a SITE:
120
+
121
+ - **Detail** — `GET /api/site/pages/[slug]` takes an optional `?category=`:
122
+ `?category=<categorySlug>` addresses the page in that category, `?category=`
123
+ (empty) the uncategorised page. Without it a unique slug is served as before;
124
+ an ambiguous one answers **409** with `PageAmbiguousSlugError`
125
+ (`{ error, code: 'ambiguous_slug', candidates: [{ categorySlug }] }`,
126
+ `categorySlug: null` = uncategorised) — the server never picks one for you.
127
+ - **Sitemap** — each `PageSlug` now carries `category` (`PageCategoryRef | null`)
128
+ so the URL can be built as `/<category>/<slug>`.
129
+ - **Embeds** — embed block `data` (`EmbedReferenceData`) gains optional
130
+ `pageId` and `categorySlug` next to `pageSlug`. nexus writes them on save;
131
+ the server resolves `pageId` first, then (`categorySlug`, `pageSlug`), then a
132
+ legacy slug-only reference **only when that slug is unique** — otherwise
133
+ `resolved` is `null`. Build the embed's href from `resolved.category`.
134
+
116
135
  ### Shop — product trust items (REB-858)
117
136
 
118
137
  `ShopConfig.productTrustItems` is the store-wide list of short trust messages
@@ -132,6 +151,24 @@ The shape is **forward-compatible** on purpose, so render it defensively:
132
151
  items and 1–80 characters of text are nexus write rules, not wire
133
152
  guarantees.
134
153
 
154
+ ### Page titles — resolved `seo.title` (REB-871)
155
+
156
+ Every detail response (`PageDetail`, `BlogPostDetail`, `ShopProductDetail`,
157
+ `AcademyCourseDetail`) carries `seo: { title }` — the **final** page title,
158
+ already resolved by the API with one rule:
159
+
160
+ - the entity's own SEO title (`seoTitle` on pages, `metaTitle` on posts,
161
+ products and courses) is used **as-is** when it is set — the site name is
162
+ never appended;
163
+ - otherwise the tenant template (`Config.seoTitleTemplate`, default
164
+ `%s | {siteName}`) is applied once to the display title.
165
+
166
+ Render `seo.title` verbatim (e.g. Next `title: { absolute }`) — never wrap it in
167
+ another `"… · Brand"` template. For list/index routes, or an older API without
168
+ `seo`, apply the same rule with `resolveSeoTitle` / `buildMetadata` from
169
+ `@reblu/site-next/seo`. Both fields are optional in the types so the minor stays
170
+ additive; `seoTitle`/`metaTitle` are unchanged.
171
+
135
172
  ## How the types stay correct
136
173
 
137
174
  The types are re-derived from the response schemas that live in the Reblu API
package/dist/index.d.cts CHANGED
@@ -5,7 +5,7 @@
5
5
  */
6
6
  export type AcademyCategoryPublic = { id: string; name: string; slug: string; sortOrder: number;}
7
7
 
8
- export type AcademyCourseDetail = { id: string; slug: string; title: string; shortDescription: string | null; coverUrl: string | null; priceCents: number; accessMode: "IMMEDIATE" | "DRIP" | "COHORT"; category: { id: string; name: string; slug: string; sortOrder: number; } | null; description: string | null; modules: { id: string; title: string; description: string | null; lessons: { id: string; slug: string; title: string; isFreePreview: boolean; durationSeconds: number | null; hasVideo: boolean; }[]; }[]; instructors: { id: string; firstName: string | null; lastName: string | null; avatarUrl: string | null; }[]; salesEnabled: boolean; requiresValidation: boolean; validationFieldLabel: string | null; validationFields: { key: string; label: string; required: boolean; maxLength?: number | undefined; }[];}
8
+ export type AcademyCourseDetail = { id: string; slug: string; title: string; shortDescription: string | null; coverUrl: string | null; priceCents: number; accessMode: "IMMEDIATE" | "DRIP" | "COHORT"; category: { id: string; name: string; slug: string; sortOrder: number; } | null; description: string | null; modules: { id: string; title: string; description: string | null; lessons: { id: string; slug: string; title: string; isFreePreview: boolean; durationSeconds: number | null; hasVideo: boolean; }[]; }[]; instructors: { id: string; firstName: string | null; lastName: string | null; avatarUrl: string | null; }[]; salesEnabled: boolean; requiresValidation: boolean; validationFieldLabel: string | null; validationFields: { key: string; label: string; required: boolean; maxLength?: number | undefined; }[]; metaTitle?: string | null | undefined; seo?: { title: string; } | undefined;}
9
9
 
10
10
  export type AcademyCourseSort = "price_asc" | "price_desc" | "newest"
11
11
 
@@ -21,11 +21,11 @@ export type AcademyValidationFieldPublic = { key: string; label: string;
21
21
 
22
22
  export type Analytics = { gaId: string | null; clarityId: string | null; recaptchaSiteKey: string | null; contactFormMode: "NOT_CONFIGURED" | "DISABLED" | "DB_ONLY" | "WEBHOOK" | "RESEND"; metaPixelId: string | null; metaVerificationContent: string | null; googleVerificationContent: string | null; consentRequired: boolean; cookiePolicyVersion: string | null; cookieBanner: { enabled: boolean; title: string | null; body: string | null; acceptLabel: string | null; rejectLabel: string | null; manageLabel: string | null; policyUrl: string | null; }; cookieInventory: { vendor: string; category: "necessary" | "analytics" | "marketing"; }[];}
23
23
 
24
- export type Block = { 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; };}
24
+ export type Block = { 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; pageId?: string | undefined; categorySlug?: string | null | undefined; };} | { blockType: "profile_embed"; data: { pageSlug: string; pageId?: string | undefined; categorySlug?: string | null | undefined; };} | { blockType: "doctor_embed"; data: { pageSlug: string; pageId?: string | undefined; categorySlug?: string | null | undefined; };} | { blockType: "specialty_embed"; data: { pageSlug: string; pageId?: string | undefined; categorySlug?: string | null | undefined; };}
25
25
 
26
26
  export type BlockCta = null | { label: string; url: string; isExternal: boolean; variant: string | null;}
27
27
 
28
- export type BlockType = "hero" | "richtext" | "faq" | "stats" | "testimonial" | "cta" | "feature_list" | "gallery" | "page_embed" | "profile_embed" | "doctor_embed" | "specialty_embed"
28
+ export type BlockType = "hero" | "page_embed" | "profile_embed" | "doctor_embed" | "specialty_embed" | "richtext" | "faq" | "stats" | "testimonial" | "cta" | "feature_list" | "gallery"
29
29
 
30
30
  export type BlogAuthor = { firstName: string | null; lastName: string | null; avatarUrl: string | null;}
31
31
 
@@ -35,17 +35,17 @@ export type BlogCategory = { id: string; name: string; slug: string;
35
35
 
36
36
  export type BlogCategoryWithCount = { id: string; name: string; slug: string; color: string; _count: { posts: number; };}
37
37
 
38
- export type BlogPostDetail = { id: string; slug: string; title: string; content: string; excerpt: string | null; featuredImageUrl: string | null; publishedAt: string | null; updatedAt: string; metaTitle: string | null; metaDescription: string | null; author: { id: string; firstName: string | null; lastName: string | null; avatarUrl: string | null; }; category: { id: string; name: string; slug: string; color: string; } | null; postTags: { id: string; name: string; slug: string; color: string; }[];}
38
+ export type BlogPostDetail = { id: string; slug: string; title: string; content: string; excerpt: string | null; featuredImageUrl: string | null; publishedAt: string | null; updatedAt: string; metaTitle: string | null; metaDescription: string | null; author: { id: string; firstName: string | null; lastName: string | null; avatarUrl: string | null; }; category: { id: string; name: string; slug: string; color: string; } | null; postTags: { id: string; name: string; slug: string; color: string; }[]; seo?: { title: string; } | undefined;}
39
39
 
40
40
  export type BlogPostListItem = { id: string; slug: string; title: string; excerpt: string | null; featuredImageUrl: string | null; publishedAt: string | null; author: { firstName: string | null; lastName: string | null; avatarUrl: string | null; }; category: { id: string; name: string; slug: string; color: string; } | null; postTags: { id: string; name: string; slug: string; color: string; }[];}
41
41
 
42
- export type BlogPostPreview = { id: string; slug: string; title: string; content: string; excerpt: string | null; featuredImageUrl: string | null; publishedAt: string | null; updatedAt: string; metaTitle: string | null; metaDescription: string | null; author: { id: string; firstName: string | null; lastName: string | null; avatarUrl: string | null; }; category: { id: string; name: string; slug: string; color: string; } | null; postTags: { id: string; name: string; slug: string; color: string; }[]; status: "DRAFT" | "PUBLISHED" | "ARCHIVED"; published: boolean;}
42
+ export type BlogPostPreview = { id: string; slug: string; title: string; content: string; excerpt: string | null; featuredImageUrl: string | null; publishedAt: string | null; updatedAt: string; metaTitle: string | null; metaDescription: string | null; author: { id: string; firstName: string | null; lastName: string | null; avatarUrl: string | null; }; category: { id: string; name: string; slug: string; color: string; } | null; postTags: { id: string; name: string; slug: string; color: string; }[]; status: "DRAFT" | "PUBLISHED" | "ARCHIVED"; published: boolean; seo?: { title: string; } | undefined;}
43
43
 
44
44
  export type BlogSlug = { slug: string; updatedAt: string;}
45
45
 
46
46
  export type BlogTag = { id: string; name: string; slug: string; color: string;}
47
47
 
48
- export type Config = { siteName: string; siteDescription: string | null; language: string | null; contactEmail: string | null; keywords: string[]; businessType: string | null; isSetupComplete: boolean; logoLightExpandedUrl: string | null; logoDarkExpandedUrl: string | null; logoLightSmallUrl: string | null; logoDarkSmallUrl: string | null; ogImageUrl: string | null; owner: { name: string | null; email: string | null; jobTitle: string | null; }; business: { name: string | null; }; address: { street: string | null; city: string | null; region: string | null; postalCode: string | null; country: string | null; telephone: string | null; lat: number | null; lng: number | null; } | null; fiscal: { taxId: string | null; taxIdKind: "NIF" | "CIF" | null; legalName: string | null; registry: { name: string; number: string; } | null; } | null; social: { linkedin: string | null; twitter: string | null; facebook: string | null; instagram: string | null; youtube: string | null; } | null; metadata: unknown; openingHours: { ranges: { days: ("MON" | "TUE" | "WED" | "THU" | "FRI" | "SAT" | "SUN")[]; opens: string; closes: string; }[]; note?: string | undefined; } | null; contactFormMode: "NOT_CONFIGURED" | "DISABLED" | "DB_ONLY" | "WEBHOOK" | "RESEND"; features: Record<string, unknown>;}
48
+ export type Config = { siteName: string; siteDescription: string | null; language: string | null; contactEmail: string | null; keywords: string[]; businessType: string | null; isSetupComplete: boolean; logoLightExpandedUrl: string | null; logoDarkExpandedUrl: string | null; logoLightSmallUrl: string | null; logoDarkSmallUrl: string | null; ogImageUrl: string | null; owner: { name: string | null; email: string | null; jobTitle: string | null; }; business: { name: string | null; }; address: { street: string | null; city: string | null; region: string | null; postalCode: string | null; country: string | null; telephone: string | null; lat: number | null; lng: number | null; } | null; fiscal: { taxId: string | null; taxIdKind: "NIF" | "CIF" | null; legalName: string | null; registry: { name: string; number: string; } | null; } | null; social: { linkedin: string | null; twitter: string | null; facebook: string | null; instagram: string | null; youtube: string | null; } | null; metadata: unknown; openingHours: { ranges: { days: ("MON" | "TUE" | "WED" | "THU" | "FRI" | "SAT" | "SUN")[]; opens: string; closes: string; }[]; note?: string | undefined; } | null; contactFormMode: "NOT_CONFIGURED" | "DISABLED" | "DB_ONLY" | "WEBHOOK" | "RESEND"; features: Record<string, unknown>; seoTitleTemplate?: string | undefined;}
49
49
 
50
50
  export type ConfigAddress = { street: string | null; city: string | null; region: string | null; postalCode: string | null; country: string | null; telephone: string | null; lat: number | null; lng: number | null;}
51
51
 
@@ -81,6 +81,8 @@ export type CustomFieldOption = { value: string; label: string;}
81
81
 
82
82
  export type CustomFieldValueType = "boolean" | "text" | "select" | "multiselect"
83
83
 
84
+ export type EmbedReferenceData = { pageSlug: string; pageId?: string | undefined; categorySlug?: string | null | undefined;}
85
+
84
86
  export type LeadInput = { name: string; email?: string | undefined; phone?: string | undefined; businessName?: string | undefined; message?: string | undefined; source?: string | undefined; metadata?: Record<string, unknown> | undefined;}
85
87
 
86
88
  export type LeadSubmission = { id: string; createdAt: string;}
@@ -89,13 +91,15 @@ export type LegacyPageType = "SERVICE" | "CUSTOM"
89
91
 
90
92
  export type Legal = { privacyPolicy: string | null; termsAndConditions: string | null; cookiePolicy: string | null;}
91
93
 
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; };}
94
+ export type PageAmbiguousSlugError = { error: string; code: "ambiguous_slug"; candidates: { categorySlug: string | null; }[];}
95
+
96
+ 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; pageId?: string | undefined; categorySlug?: string | null | 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: "profile_embed"; data: { pageSlug: string; pageId?: string | undefined; categorySlug?: string | null | 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: "doctor_embed"; data: { pageSlug: string; pageId?: string | undefined; categorySlug?: string | null | 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: "specialty_embed"; data: { pageSlug: string; pageId?: string | undefined; categorySlug?: string | null | undefined; };}
93
97
 
94
98
  export type PageCategoryRef = { name: string; slug: string;}
95
99
 
96
100
  export type PageContentMode = "BLOCKS" | "HTML"
97
101
 
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;}
102
+ 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; pageId?: string | undefined; categorySlug?: string | null | undefined; }; } | { blockType: "profile_embed"; data: { pageSlug: string; pageId?: string | undefined; categorySlug?: string | null | undefined; }; } | { blockType: "doctor_embed"; data: { pageSlug: string; pageId?: string | undefined; categorySlug?: string | null | undefined; }; } | { blockType: "specialty_embed"; data: { pageSlug: string; pageId?: string | undefined; categorySlug?: string | null | undefined; }; }))[]; 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; seo?: { title: string; } | undefined;}
99
103
 
100
104
  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
105
 
@@ -103,7 +107,7 @@ export type PageSection = { id: string; order: number; heading: string
103
107
 
104
108
  export type PageSectionImage = { url: string; alt: string; caption: string | null; order: number;}
105
109
 
106
- export type PageSlug = { slug: string; type: "SERVICE" | "CUSTOM"; updatedAt: string;}
110
+ export type PageSlug = { slug: string; type: "SERVICE" | "CUSTOM"; updatedAt: string; category?: { name: string; slug: string; } | null | undefined;}
107
111
 
108
112
  export type PageType = "custom" | "service" | "treatments" | "specialties" | "team" | "generic"
109
113
 
@@ -133,6 +137,8 @@ export type ResolvedEmbed = { slug: string; title: string; excerpt: str
133
137
 
134
138
  export type SectionLayout = "TEXT" | "TEXT_IMAGE" | "IMAGE_TEXT" | "IMAGE_FULL" | "FEATURE_LIST" | "GALLERY" | "CTA_BLOCK"
135
139
 
140
+ export type Seo = { title: string;}
141
+
136
142
  export type ShopAddressInput = { firstName: string; lastName: string; street: string; city: string; postalCode: string; region?: string | undefined; country?: string | undefined; phone?: string | null | undefined;}
137
143
 
138
144
  export type ShopApplyDiscountInput = { code: string; orderSubtotal: number; customerEmail?: string | undefined;}
@@ -177,7 +183,7 @@ export type ShopProductAttributes = unknown
177
183
 
178
184
  export type ShopProductCategoryRef = { id: string; name: string; slug: string;}
179
185
 
180
- export type ShopProductDetail = { id: string; slug: string; name: string; description: string | null; shortDescription: string | null; price: number; comparePrice: number | null; type: "SERVICE" | "PHYSICAL" | "DIGITAL" | "SERVICE_B2B" | "BUNDLE"; isActive: boolean; sku: string | null; trackStock: boolean; weightGrams: number | null; freeShipping: boolean; metaTitle: string | null; metaDescription: string | null; category: { id: string; name: string; slug: string; } | null; taxRate: { rate: number; type: "IVA" | "IGIC" | "RETENTION" | "OTHER"; isExempt: boolean; } | null; retentionRate: { rate: number; type: "IVA" | "IGIC" | "RETENTION" | "OTHER"; isExempt: boolean; } | null; variants: { id: string; name: string; sku: string | null; price: number | null; attributes: unknown; isActive: boolean; sortOrder: number; }[]; images: { url: string; alt: string | null; isPrimary: boolean; sortOrder: number; }[]; videos: { url: string; title: string | null; isExternal: boolean; thumbnailUrl: string | null; sortOrder: number; }[]; bundleComponents: { quantity: number; component: { id: string; name: string; slug: string; price: number; }; }[]; related: { id: string; slug: string; name: string; price: number; comparePrice: number | null; images: { url: string; alt: string | null; isPrimary: boolean; sortOrder: number; }[]; }[]; taxonomyTerms: { taxonomyKey: string; taxonomyLabel: string; showAsBadge: boolean; slug: string; name: string; imageUrl: string | null; }[]; attributes: unknown; attributeDefinitions: { id: string; entityType: "page" | "product"; key: string; label: string; valueType: "boolean" | "text" | "select" | "multiselect"; options: { value: string; label: string; }[]; isFilterable: boolean; showInDetail: boolean; unit: string | null; sortOrder: number; }[];}
186
+ export type ShopProductDetail = { id: string; slug: string; name: string; description: string | null; shortDescription: string | null; price: number; comparePrice: number | null; type: "SERVICE" | "PHYSICAL" | "DIGITAL" | "SERVICE_B2B" | "BUNDLE"; isActive: boolean; sku: string | null; trackStock: boolean; weightGrams: number | null; freeShipping: boolean; metaTitle: string | null; metaDescription: string | null; category: { id: string; name: string; slug: string; } | null; taxRate: { rate: number; type: "IVA" | "IGIC" | "RETENTION" | "OTHER"; isExempt: boolean; } | null; retentionRate: { rate: number; type: "IVA" | "IGIC" | "RETENTION" | "OTHER"; isExempt: boolean; } | null; variants: { id: string; name: string; sku: string | null; price: number | null; attributes: unknown; isActive: boolean; sortOrder: number; }[]; images: { url: string; alt: string | null; isPrimary: boolean; sortOrder: number; }[]; videos: { url: string; title: string | null; isExternal: boolean; thumbnailUrl: string | null; sortOrder: number; }[]; bundleComponents: { quantity: number; component: { id: string; name: string; slug: string; price: number; }; }[]; related: { id: string; slug: string; name: string; price: number; comparePrice: number | null; images: { url: string; alt: string | null; isPrimary: boolean; sortOrder: number; }[]; }[]; taxonomyTerms: { taxonomyKey: string; taxonomyLabel: string; showAsBadge: boolean; slug: string; name: string; imageUrl: string | null; }[]; attributes: unknown; attributeDefinitions: { id: string; entityType: "page" | "product"; key: string; label: string; valueType: "boolean" | "text" | "select" | "multiselect"; options: { value: string; label: string; }[]; isFilterable: boolean; showInDetail: boolean; unit: string | null; sortOrder: number; }[]; seo?: { title: string; } | undefined;}
181
187
 
182
188
  export type ShopProductImage = { url: string; alt: string | null; isPrimary: boolean; sortOrder: number;}
183
189
 
package/dist/index.d.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  */
6
6
  export type AcademyCategoryPublic = { id: string; name: string; slug: string; sortOrder: number;}
7
7
 
8
- export type AcademyCourseDetail = { id: string; slug: string; title: string; shortDescription: string | null; coverUrl: string | null; priceCents: number; accessMode: "IMMEDIATE" | "DRIP" | "COHORT"; category: { id: string; name: string; slug: string; sortOrder: number; } | null; description: string | null; modules: { id: string; title: string; description: string | null; lessons: { id: string; slug: string; title: string; isFreePreview: boolean; durationSeconds: number | null; hasVideo: boolean; }[]; }[]; instructors: { id: string; firstName: string | null; lastName: string | null; avatarUrl: string | null; }[]; salesEnabled: boolean; requiresValidation: boolean; validationFieldLabel: string | null; validationFields: { key: string; label: string; required: boolean; maxLength?: number | undefined; }[];}
8
+ export type AcademyCourseDetail = { id: string; slug: string; title: string; shortDescription: string | null; coverUrl: string | null; priceCents: number; accessMode: "IMMEDIATE" | "DRIP" | "COHORT"; category: { id: string; name: string; slug: string; sortOrder: number; } | null; description: string | null; modules: { id: string; title: string; description: string | null; lessons: { id: string; slug: string; title: string; isFreePreview: boolean; durationSeconds: number | null; hasVideo: boolean; }[]; }[]; instructors: { id: string; firstName: string | null; lastName: string | null; avatarUrl: string | null; }[]; salesEnabled: boolean; requiresValidation: boolean; validationFieldLabel: string | null; validationFields: { key: string; label: string; required: boolean; maxLength?: number | undefined; }[]; metaTitle?: string | null | undefined; seo?: { title: string; } | undefined;}
9
9
 
10
10
  export type AcademyCourseSort = "price_asc" | "price_desc" | "newest"
11
11
 
@@ -21,11 +21,11 @@ export type AcademyValidationFieldPublic = { key: string; label: string;
21
21
 
22
22
  export type Analytics = { gaId: string | null; clarityId: string | null; recaptchaSiteKey: string | null; contactFormMode: "NOT_CONFIGURED" | "DISABLED" | "DB_ONLY" | "WEBHOOK" | "RESEND"; metaPixelId: string | null; metaVerificationContent: string | null; googleVerificationContent: string | null; consentRequired: boolean; cookiePolicyVersion: string | null; cookieBanner: { enabled: boolean; title: string | null; body: string | null; acceptLabel: string | null; rejectLabel: string | null; manageLabel: string | null; policyUrl: string | null; }; cookieInventory: { vendor: string; category: "necessary" | "analytics" | "marketing"; }[];}
23
23
 
24
- export type Block = { 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; };}
24
+ export type Block = { 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; pageId?: string | undefined; categorySlug?: string | null | undefined; };} | { blockType: "profile_embed"; data: { pageSlug: string; pageId?: string | undefined; categorySlug?: string | null | undefined; };} | { blockType: "doctor_embed"; data: { pageSlug: string; pageId?: string | undefined; categorySlug?: string | null | undefined; };} | { blockType: "specialty_embed"; data: { pageSlug: string; pageId?: string | undefined; categorySlug?: string | null | undefined; };}
25
25
 
26
26
  export type BlockCta = null | { label: string; url: string; isExternal: boolean; variant: string | null;}
27
27
 
28
- export type BlockType = "hero" | "richtext" | "faq" | "stats" | "testimonial" | "cta" | "feature_list" | "gallery" | "page_embed" | "profile_embed" | "doctor_embed" | "specialty_embed"
28
+ export type BlockType = "hero" | "page_embed" | "profile_embed" | "doctor_embed" | "specialty_embed" | "richtext" | "faq" | "stats" | "testimonial" | "cta" | "feature_list" | "gallery"
29
29
 
30
30
  export type BlogAuthor = { firstName: string | null; lastName: string | null; avatarUrl: string | null;}
31
31
 
@@ -35,17 +35,17 @@ export type BlogCategory = { id: string; name: string; slug: string;
35
35
 
36
36
  export type BlogCategoryWithCount = { id: string; name: string; slug: string; color: string; _count: { posts: number; };}
37
37
 
38
- export type BlogPostDetail = { id: string; slug: string; title: string; content: string; excerpt: string | null; featuredImageUrl: string | null; publishedAt: string | null; updatedAt: string; metaTitle: string | null; metaDescription: string | null; author: { id: string; firstName: string | null; lastName: string | null; avatarUrl: string | null; }; category: { id: string; name: string; slug: string; color: string; } | null; postTags: { id: string; name: string; slug: string; color: string; }[];}
38
+ export type BlogPostDetail = { id: string; slug: string; title: string; content: string; excerpt: string | null; featuredImageUrl: string | null; publishedAt: string | null; updatedAt: string; metaTitle: string | null; metaDescription: string | null; author: { id: string; firstName: string | null; lastName: string | null; avatarUrl: string | null; }; category: { id: string; name: string; slug: string; color: string; } | null; postTags: { id: string; name: string; slug: string; color: string; }[]; seo?: { title: string; } | undefined;}
39
39
 
40
40
  export type BlogPostListItem = { id: string; slug: string; title: string; excerpt: string | null; featuredImageUrl: string | null; publishedAt: string | null; author: { firstName: string | null; lastName: string | null; avatarUrl: string | null; }; category: { id: string; name: string; slug: string; color: string; } | null; postTags: { id: string; name: string; slug: string; color: string; }[];}
41
41
 
42
- export type BlogPostPreview = { id: string; slug: string; title: string; content: string; excerpt: string | null; featuredImageUrl: string | null; publishedAt: string | null; updatedAt: string; metaTitle: string | null; metaDescription: string | null; author: { id: string; firstName: string | null; lastName: string | null; avatarUrl: string | null; }; category: { id: string; name: string; slug: string; color: string; } | null; postTags: { id: string; name: string; slug: string; color: string; }[]; status: "DRAFT" | "PUBLISHED" | "ARCHIVED"; published: boolean;}
42
+ export type BlogPostPreview = { id: string; slug: string; title: string; content: string; excerpt: string | null; featuredImageUrl: string | null; publishedAt: string | null; updatedAt: string; metaTitle: string | null; metaDescription: string | null; author: { id: string; firstName: string | null; lastName: string | null; avatarUrl: string | null; }; category: { id: string; name: string; slug: string; color: string; } | null; postTags: { id: string; name: string; slug: string; color: string; }[]; status: "DRAFT" | "PUBLISHED" | "ARCHIVED"; published: boolean; seo?: { title: string; } | undefined;}
43
43
 
44
44
  export type BlogSlug = { slug: string; updatedAt: string;}
45
45
 
46
46
  export type BlogTag = { id: string; name: string; slug: string; color: string;}
47
47
 
48
- export type Config = { siteName: string; siteDescription: string | null; language: string | null; contactEmail: string | null; keywords: string[]; businessType: string | null; isSetupComplete: boolean; logoLightExpandedUrl: string | null; logoDarkExpandedUrl: string | null; logoLightSmallUrl: string | null; logoDarkSmallUrl: string | null; ogImageUrl: string | null; owner: { name: string | null; email: string | null; jobTitle: string | null; }; business: { name: string | null; }; address: { street: string | null; city: string | null; region: string | null; postalCode: string | null; country: string | null; telephone: string | null; lat: number | null; lng: number | null; } | null; fiscal: { taxId: string | null; taxIdKind: "NIF" | "CIF" | null; legalName: string | null; registry: { name: string; number: string; } | null; } | null; social: { linkedin: string | null; twitter: string | null; facebook: string | null; instagram: string | null; youtube: string | null; } | null; metadata: unknown; openingHours: { ranges: { days: ("MON" | "TUE" | "WED" | "THU" | "FRI" | "SAT" | "SUN")[]; opens: string; closes: string; }[]; note?: string | undefined; } | null; contactFormMode: "NOT_CONFIGURED" | "DISABLED" | "DB_ONLY" | "WEBHOOK" | "RESEND"; features: Record<string, unknown>;}
48
+ export type Config = { siteName: string; siteDescription: string | null; language: string | null; contactEmail: string | null; keywords: string[]; businessType: string | null; isSetupComplete: boolean; logoLightExpandedUrl: string | null; logoDarkExpandedUrl: string | null; logoLightSmallUrl: string | null; logoDarkSmallUrl: string | null; ogImageUrl: string | null; owner: { name: string | null; email: string | null; jobTitle: string | null; }; business: { name: string | null; }; address: { street: string | null; city: string | null; region: string | null; postalCode: string | null; country: string | null; telephone: string | null; lat: number | null; lng: number | null; } | null; fiscal: { taxId: string | null; taxIdKind: "NIF" | "CIF" | null; legalName: string | null; registry: { name: string; number: string; } | null; } | null; social: { linkedin: string | null; twitter: string | null; facebook: string | null; instagram: string | null; youtube: string | null; } | null; metadata: unknown; openingHours: { ranges: { days: ("MON" | "TUE" | "WED" | "THU" | "FRI" | "SAT" | "SUN")[]; opens: string; closes: string; }[]; note?: string | undefined; } | null; contactFormMode: "NOT_CONFIGURED" | "DISABLED" | "DB_ONLY" | "WEBHOOK" | "RESEND"; features: Record<string, unknown>; seoTitleTemplate?: string | undefined;}
49
49
 
50
50
  export type ConfigAddress = { street: string | null; city: string | null; region: string | null; postalCode: string | null; country: string | null; telephone: string | null; lat: number | null; lng: number | null;}
51
51
 
@@ -81,6 +81,8 @@ export type CustomFieldOption = { value: string; label: string;}
81
81
 
82
82
  export type CustomFieldValueType = "boolean" | "text" | "select" | "multiselect"
83
83
 
84
+ export type EmbedReferenceData = { pageSlug: string; pageId?: string | undefined; categorySlug?: string | null | undefined;}
85
+
84
86
  export type LeadInput = { name: string; email?: string | undefined; phone?: string | undefined; businessName?: string | undefined; message?: string | undefined; source?: string | undefined; metadata?: Record<string, unknown> | undefined;}
85
87
 
86
88
  export type LeadSubmission = { id: string; createdAt: string;}
@@ -89,13 +91,15 @@ export type LegacyPageType = "SERVICE" | "CUSTOM"
89
91
 
90
92
  export type Legal = { privacyPolicy: string | null; termsAndConditions: string | null; cookiePolicy: string | null;}
91
93
 
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; };}
94
+ export type PageAmbiguousSlugError = { error: string; code: "ambiguous_slug"; candidates: { categorySlug: string | null; }[];}
95
+
96
+ 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; pageId?: string | undefined; categorySlug?: string | null | 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: "profile_embed"; data: { pageSlug: string; pageId?: string | undefined; categorySlug?: string | null | 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: "doctor_embed"; data: { pageSlug: string; pageId?: string | undefined; categorySlug?: string | null | 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: "specialty_embed"; data: { pageSlug: string; pageId?: string | undefined; categorySlug?: string | null | undefined; };}
93
97
 
94
98
  export type PageCategoryRef = { name: string; slug: string;}
95
99
 
96
100
  export type PageContentMode = "BLOCKS" | "HTML"
97
101
 
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;}
102
+ 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; pageId?: string | undefined; categorySlug?: string | null | undefined; }; } | { blockType: "profile_embed"; data: { pageSlug: string; pageId?: string | undefined; categorySlug?: string | null | undefined; }; } | { blockType: "doctor_embed"; data: { pageSlug: string; pageId?: string | undefined; categorySlug?: string | null | undefined; }; } | { blockType: "specialty_embed"; data: { pageSlug: string; pageId?: string | undefined; categorySlug?: string | null | undefined; }; }))[]; 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; seo?: { title: string; } | undefined;}
99
103
 
100
104
  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
105
 
@@ -103,7 +107,7 @@ export type PageSection = { id: string; order: number; heading: string
103
107
 
104
108
  export type PageSectionImage = { url: string; alt: string; caption: string | null; order: number;}
105
109
 
106
- export type PageSlug = { slug: string; type: "SERVICE" | "CUSTOM"; updatedAt: string;}
110
+ export type PageSlug = { slug: string; type: "SERVICE" | "CUSTOM"; updatedAt: string; category?: { name: string; slug: string; } | null | undefined;}
107
111
 
108
112
  export type PageType = "custom" | "service" | "treatments" | "specialties" | "team" | "generic"
109
113
 
@@ -133,6 +137,8 @@ export type ResolvedEmbed = { slug: string; title: string; excerpt: str
133
137
 
134
138
  export type SectionLayout = "TEXT" | "TEXT_IMAGE" | "IMAGE_TEXT" | "IMAGE_FULL" | "FEATURE_LIST" | "GALLERY" | "CTA_BLOCK"
135
139
 
140
+ export type Seo = { title: string;}
141
+
136
142
  export type ShopAddressInput = { firstName: string; lastName: string; street: string; city: string; postalCode: string; region?: string | undefined; country?: string | undefined; phone?: string | null | undefined;}
137
143
 
138
144
  export type ShopApplyDiscountInput = { code: string; orderSubtotal: number; customerEmail?: string | undefined;}
@@ -177,7 +183,7 @@ export type ShopProductAttributes = unknown
177
183
 
178
184
  export type ShopProductCategoryRef = { id: string; name: string; slug: string;}
179
185
 
180
- export type ShopProductDetail = { id: string; slug: string; name: string; description: string | null; shortDescription: string | null; price: number; comparePrice: number | null; type: "SERVICE" | "PHYSICAL" | "DIGITAL" | "SERVICE_B2B" | "BUNDLE"; isActive: boolean; sku: string | null; trackStock: boolean; weightGrams: number | null; freeShipping: boolean; metaTitle: string | null; metaDescription: string | null; category: { id: string; name: string; slug: string; } | null; taxRate: { rate: number; type: "IVA" | "IGIC" | "RETENTION" | "OTHER"; isExempt: boolean; } | null; retentionRate: { rate: number; type: "IVA" | "IGIC" | "RETENTION" | "OTHER"; isExempt: boolean; } | null; variants: { id: string; name: string; sku: string | null; price: number | null; attributes: unknown; isActive: boolean; sortOrder: number; }[]; images: { url: string; alt: string | null; isPrimary: boolean; sortOrder: number; }[]; videos: { url: string; title: string | null; isExternal: boolean; thumbnailUrl: string | null; sortOrder: number; }[]; bundleComponents: { quantity: number; component: { id: string; name: string; slug: string; price: number; }; }[]; related: { id: string; slug: string; name: string; price: number; comparePrice: number | null; images: { url: string; alt: string | null; isPrimary: boolean; sortOrder: number; }[]; }[]; taxonomyTerms: { taxonomyKey: string; taxonomyLabel: string; showAsBadge: boolean; slug: string; name: string; imageUrl: string | null; }[]; attributes: unknown; attributeDefinitions: { id: string; entityType: "page" | "product"; key: string; label: string; valueType: "boolean" | "text" | "select" | "multiselect"; options: { value: string; label: string; }[]; isFilterable: boolean; showInDetail: boolean; unit: string | null; sortOrder: number; }[];}
186
+ export type ShopProductDetail = { id: string; slug: string; name: string; description: string | null; shortDescription: string | null; price: number; comparePrice: number | null; type: "SERVICE" | "PHYSICAL" | "DIGITAL" | "SERVICE_B2B" | "BUNDLE"; isActive: boolean; sku: string | null; trackStock: boolean; weightGrams: number | null; freeShipping: boolean; metaTitle: string | null; metaDescription: string | null; category: { id: string; name: string; slug: string; } | null; taxRate: { rate: number; type: "IVA" | "IGIC" | "RETENTION" | "OTHER"; isExempt: boolean; } | null; retentionRate: { rate: number; type: "IVA" | "IGIC" | "RETENTION" | "OTHER"; isExempt: boolean; } | null; variants: { id: string; name: string; sku: string | null; price: number | null; attributes: unknown; isActive: boolean; sortOrder: number; }[]; images: { url: string; alt: string | null; isPrimary: boolean; sortOrder: number; }[]; videos: { url: string; title: string | null; isExternal: boolean; thumbnailUrl: string | null; sortOrder: number; }[]; bundleComponents: { quantity: number; component: { id: string; name: string; slug: string; price: number; }; }[]; related: { id: string; slug: string; name: string; price: number; comparePrice: number | null; images: { url: string; alt: string | null; isPrimary: boolean; sortOrder: number; }[]; }[]; taxonomyTerms: { taxonomyKey: string; taxonomyLabel: string; showAsBadge: boolean; slug: string; name: string; imageUrl: string | null; }[]; attributes: unknown; attributeDefinitions: { id: string; entityType: "page" | "product"; key: string; label: string; valueType: "boolean" | "text" | "select" | "multiselect"; options: { value: string; label: string; }[]; isFilterable: boolean; showInDetail: boolean; unit: string | null; sortOrder: number; }[]; seo?: { title: string; } | undefined;}
181
187
 
182
188
  export type ShopProductImage = { url: string; alt: string | null; isPrimary: boolean; sortOrder: number;}
183
189
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reblu/site-contracts",
3
- "version": "1.9.0",
3
+ "version": "1.11.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",