@reblu/site-contracts 1.12.0 → 1.14.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 +13 -0
- package/README.md +17 -0
- package/dist/index.d.cts +13 -1
- package/dist/index.d.ts +13 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# @reblu/site-contracts
|
|
2
2
|
|
|
3
|
+
## 1.14.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 92e0f6f: Add the `header` slot to `Cta['slot']` (`'header' | 'hero' | 'blog-end' | 'services' | 'contact' | 'sticky-mobile' | 'footer'`), so a SITE can drive its persistent header CTA from nexus via `GET /api/site/ctas?slot=header`.
|
|
8
|
+
- b75f066: Deprecate `ShopCheckEmailInput` and `ShopEmailCheck` (REB-834). `POST /api/site/shop/check-email` was an account-enumeration oracle on the tenant's customer list; it now always answers `{ exists: false }`. Never branch UI on `exists`. Both types are removed in the next major.
|
|
9
|
+
|
|
10
|
+
## 1.13.0
|
|
11
|
+
|
|
12
|
+
### Minor Changes
|
|
13
|
+
|
|
14
|
+
- 7a00471: Featured pages per page category (REB-869). `@reblu/site-contracts` adds `PagesListQuery`, the query of `GET /api/site/pages`, including the new `featured` flag. `@reblu/site-client`: `pages.list({ category, featured: true })` returns that category's featured pages (max 3) in the tenant's order, skipping unpublished, deleted or moved pages, and an empty list when nothing is featured; the new `pages.featured(category, { limit?, fallback?, cache? })` helper returns the featured pages, or the category's first `limit` pages in normal order when none are featured, so a landing teaser is never empty. `limit` must be an integer >= 1: above 3 it is clamped to 3; 0, negative, fractional or NaN throw a `RangeError` before any request. Against an API that predates `featured`, the flag is ignored and `pages.featured()` silently degrades to the category's first `limit` pages. `@reblu/site-blocks` adds `PageCardGrid`, the page-card grid `ParentPage` already rendered for its child pages, as a drop-in (`pages`, `pageHref`, `heading`); cards are keyed by category + slug, an empty `heading` renders no `<h2>`. `ParentPage` now renders through it with unchanged markup (including the empty `<h2>` for `childPagesLabel=''`).
|
|
15
|
+
|
|
3
16
|
## 1.12.0
|
|
4
17
|
|
|
5
18
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -30,6 +30,13 @@ 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
|
+
### Editable CTAs — slots
|
|
34
|
+
|
|
35
|
+
`Cta['slot']` is the union of placements a CTA can be configured for in nexus:
|
|
36
|
+
`'header' | 'hero' | 'blog-end' | 'services' | 'contact' | 'sticky-mobile' |
|
|
37
|
+
'footer'`. `GET /api/site/ctas?slot=header` returns the active CTAs of the
|
|
38
|
+
persistent header; `@reblu/site-next`'s `EditableCta` renders them drop-in.
|
|
39
|
+
|
|
33
40
|
### Page blocks — canonical shape (REB-849 / REB-851 / REB-852 / REB-854)
|
|
34
41
|
|
|
35
42
|
`GET /api/site/pages/[slug]` (`PageDetail`) returns BOTH `sections[]` (legacy,
|
|
@@ -132,6 +139,16 @@ may exist in both `tratamientos` and `especialidades`. Consequences for a SITE:
|
|
|
132
139
|
legacy slug-only reference **only when that slug is unique** — otherwise
|
|
133
140
|
`resolved` is `null`. Build the embed's href from `resolved.category`.
|
|
134
141
|
|
|
142
|
+
### Featured pages per category (REB-869)
|
|
143
|
+
|
|
144
|
+
`PagesListQuery` is the query of `GET /api/site/pages`. With `category` set,
|
|
145
|
+
`featured: true` returns that category's featured pages (max 3) in the order
|
|
146
|
+
the tenant chose in nexus, instead of the normal listing. Unpublished,
|
|
147
|
+
deleted or moved pages are skipped; nothing featured → empty `data` (the API
|
|
148
|
+
never falls back). For a teaser that falls back to the category's first pages,
|
|
149
|
+
use `@reblu/site-client`'s `pages.featured(category)` with
|
|
150
|
+
`@reblu/site-blocks`' `PageCardGrid`.
|
|
151
|
+
|
|
135
152
|
### Shop — product trust items (REB-858)
|
|
136
153
|
|
|
137
154
|
`ShopConfig.productTrustItems` is the store-wide list of short trust messages
|
package/dist/index.d.cts
CHANGED
|
@@ -71,7 +71,7 @@ export type ContactFormSubmission = { id: string; createdAt: string;}
|
|
|
71
71
|
|
|
72
72
|
export type CookieBanner = { enabled: boolean; title: string | null; body: string | null; acceptLabel: string | null; rejectLabel: string | null; manageLabel: string | null; policyUrl: string | null;}
|
|
73
73
|
|
|
74
|
-
export type Cta = { id: string; slot: "hero" | "blog-end" | "services" | "contact" | "sticky-mobile" | "footer"; label: string; href: string; sortOrder: number; abVariant: string | null; analyticsId: string;}
|
|
74
|
+
export type Cta = { id: string; slot: "header" | "hero" | "blog-end" | "services" | "contact" | "sticky-mobile" | "footer"; label: string; href: string; sortOrder: number; abVariant: string | null; analyticsId: string;}
|
|
75
75
|
|
|
76
76
|
export type CustomFieldDefinition = { 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;}
|
|
77
77
|
|
|
@@ -111,6 +111,8 @@ export type PageSlug = { slug: string; type: "SERVICE" | "CUSTOM"; upda
|
|
|
111
111
|
|
|
112
112
|
export type PageType = "custom" | "service" | "treatments" | "specialties" | "team" | "generic"
|
|
113
113
|
|
|
114
|
+
export type PagesListQuery = { type?: ("custom" | "service" | "treatments" | "specialties" | "team" | "generic")[] | undefined; category?: string | undefined; page?: unknown; pageSize?: unknown; sort?: "order" | "-publishedAt" | undefined; featured?: boolean | undefined;}
|
|
115
|
+
|
|
114
116
|
export type PagesListSort = "order" | "-publishedAt"
|
|
115
117
|
|
|
116
118
|
export type PaginationMeta = { total?: number | undefined; page?: number | undefined; limit?: number | undefined; pages?: number | undefined;}
|
|
@@ -157,6 +159,10 @@ export type ShopCartValidationItem = { productId: string; name: string;
|
|
|
157
159
|
|
|
158
160
|
export type ShopCategory = { id: string; name: string; slug: string; description: string | null; imageUrl: string | null; parentId: string | null; sortOrder: number;}
|
|
159
161
|
|
|
162
|
+
/**
|
|
163
|
+
* @deprecated REB-834 — `POST /api/site/shop/check-email` no longer reveals
|
|
164
|
+
* whether an account exists. Do not call it; removed in the next major.
|
|
165
|
+
*/
|
|
160
166
|
export type ShopCheckEmailInput = { email: string;}
|
|
161
167
|
|
|
162
168
|
export type ShopCheckoutInput = { items: { productId: string; quantity: number; variantId?: string | null | undefined; }[]; customerEmail: string; customerName: string; successUrl: string; cancelUrl: string; customerPhone?: string | null | undefined; discountCode?: string | undefined; shippingAddress?: { firstName: string; lastName: string; street: string; city: string; postalCode: string; region?: string | undefined; country?: string | undefined; phone?: string | null | undefined; } | undefined; billing?: { billingName: string; billingNif?: string | undefined; billingEmail?: string | undefined; billingAddress?: { firstName: string; lastName: string; street: string; city: string; postalCode: string; region?: string | undefined; country?: string | undefined; phone?: string | null | undefined; } | undefined; } | undefined;}
|
|
@@ -167,6 +173,12 @@ export type ShopConfig = { shopName: string | null; defaultLowStockThresho
|
|
|
167
173
|
|
|
168
174
|
export type ShopDiscountApplication = { valid: boolean; discount: number; type: "PERCENTAGE" | "FIXED" | null; code: string | null; error?: string | undefined;}
|
|
169
175
|
|
|
176
|
+
/**
|
|
177
|
+
* @deprecated REB-834 — `exists` is always `false`. Never branch UI on it:
|
|
178
|
+
* the checkout always offers «Iniciar sesión o continuar como invitado» and
|
|
179
|
+
* the server links the order to an existing account after payment. Removed
|
|
180
|
+
* in the next major.
|
|
181
|
+
*/
|
|
170
182
|
export type ShopEmailCheck = { exists: boolean;}
|
|
171
183
|
|
|
172
184
|
export type ShopErrorCode = "STOCK_CHANGED" | "PRICE_CHANGED" | "PRODUCT_UNAVAILABLE" | "DISCOUNT_INVALID" | "SHIPPING_UNAVAILABLE" | "INVALID_INPUT" | "STORE_DISABLED" | "PAYMENT_PROVIDER_ERROR" | "INTERNAL_ERROR"
|
package/dist/index.d.ts
CHANGED
|
@@ -71,7 +71,7 @@ export type ContactFormSubmission = { id: string; createdAt: string;}
|
|
|
71
71
|
|
|
72
72
|
export type CookieBanner = { enabled: boolean; title: string | null; body: string | null; acceptLabel: string | null; rejectLabel: string | null; manageLabel: string | null; policyUrl: string | null;}
|
|
73
73
|
|
|
74
|
-
export type Cta = { id: string; slot: "hero" | "blog-end" | "services" | "contact" | "sticky-mobile" | "footer"; label: string; href: string; sortOrder: number; abVariant: string | null; analyticsId: string;}
|
|
74
|
+
export type Cta = { id: string; slot: "header" | "hero" | "blog-end" | "services" | "contact" | "sticky-mobile" | "footer"; label: string; href: string; sortOrder: number; abVariant: string | null; analyticsId: string;}
|
|
75
75
|
|
|
76
76
|
export type CustomFieldDefinition = { 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;}
|
|
77
77
|
|
|
@@ -111,6 +111,8 @@ export type PageSlug = { slug: string; type: "SERVICE" | "CUSTOM"; upda
|
|
|
111
111
|
|
|
112
112
|
export type PageType = "custom" | "service" | "treatments" | "specialties" | "team" | "generic"
|
|
113
113
|
|
|
114
|
+
export type PagesListQuery = { type?: ("custom" | "service" | "treatments" | "specialties" | "team" | "generic")[] | undefined; category?: string | undefined; page?: unknown; pageSize?: unknown; sort?: "order" | "-publishedAt" | undefined; featured?: boolean | undefined;}
|
|
115
|
+
|
|
114
116
|
export type PagesListSort = "order" | "-publishedAt"
|
|
115
117
|
|
|
116
118
|
export type PaginationMeta = { total?: number | undefined; page?: number | undefined; limit?: number | undefined; pages?: number | undefined;}
|
|
@@ -157,6 +159,10 @@ export type ShopCartValidationItem = { productId: string; name: string;
|
|
|
157
159
|
|
|
158
160
|
export type ShopCategory = { id: string; name: string; slug: string; description: string | null; imageUrl: string | null; parentId: string | null; sortOrder: number;}
|
|
159
161
|
|
|
162
|
+
/**
|
|
163
|
+
* @deprecated REB-834 — `POST /api/site/shop/check-email` no longer reveals
|
|
164
|
+
* whether an account exists. Do not call it; removed in the next major.
|
|
165
|
+
*/
|
|
160
166
|
export type ShopCheckEmailInput = { email: string;}
|
|
161
167
|
|
|
162
168
|
export type ShopCheckoutInput = { items: { productId: string; quantity: number; variantId?: string | null | undefined; }[]; customerEmail: string; customerName: string; successUrl: string; cancelUrl: string; customerPhone?: string | null | undefined; discountCode?: string | undefined; shippingAddress?: { firstName: string; lastName: string; street: string; city: string; postalCode: string; region?: string | undefined; country?: string | undefined; phone?: string | null | undefined; } | undefined; billing?: { billingName: string; billingNif?: string | undefined; billingEmail?: string | undefined; billingAddress?: { firstName: string; lastName: string; street: string; city: string; postalCode: string; region?: string | undefined; country?: string | undefined; phone?: string | null | undefined; } | undefined; } | undefined;}
|
|
@@ -167,6 +173,12 @@ export type ShopConfig = { shopName: string | null; defaultLowStockThresho
|
|
|
167
173
|
|
|
168
174
|
export type ShopDiscountApplication = { valid: boolean; discount: number; type: "PERCENTAGE" | "FIXED" | null; code: string | null; error?: string | undefined;}
|
|
169
175
|
|
|
176
|
+
/**
|
|
177
|
+
* @deprecated REB-834 — `exists` is always `false`. Never branch UI on it:
|
|
178
|
+
* the checkout always offers «Iniciar sesión o continuar como invitado» and
|
|
179
|
+
* the server links the order to an existing account after payment. Removed
|
|
180
|
+
* in the next major.
|
|
181
|
+
*/
|
|
170
182
|
export type ShopEmailCheck = { exists: boolean;}
|
|
171
183
|
|
|
172
184
|
export type ShopErrorCode = "STOCK_CHANGED" | "PRICE_CHANGED" | "PRODUCT_UNAVAILABLE" | "DISCOUNT_INVALID" | "SHIPPING_UNAVAILABLE" | "INVALID_INPUT" | "STORE_DISABLED" | "PAYMENT_PROVIDER_ERROR" | "INTERNAL_ERROR"
|
package/package.json
CHANGED