@reblu/site-contracts 1.2.0 → 1.3.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,22 @@
1
1
  # @reblu/site-contracts
2
2
 
3
+ ## 1.3.0
4
+
5
+ ### Minor Changes
6
+
7
+ - baa36cf: Expose each taxonomy axis's selection mode on `ShopFacets` (REB-809).
8
+
9
+ `ShopFacets.taxonomies[].selectionMode` is a new required field: `'single' |
10
+ 'multiple'`, mirroring REB-801's per-axis `TaxonomySelectionMode`. It reflects
11
+ how many terms a PRODUCT may carry on that axis, not how many the SITE
12
+ storefront filter may select at once — `GET /api/site/shop/products`'s
13
+ `taxonomy[<key>]` param still accepts only one term slug per axis regardless
14
+ of this value (see `@reblu/site-blocks`'s `ShopFilters` docs).
15
+
16
+ Additive: a new required field on the existing `ShopFacets` shape, populated
17
+ for every axis. A SITE build that has not migrated its `ShopFacets` type yet
18
+ keeps working unchanged — the extra field is simply ignored at runtime.
19
+
3
20
  ## 1.2.0
4
21
 
5
22
  ### Minor Changes
@@ -20,6 +37,43 @@
20
37
  new exported type. The existing `validationFieldLabel` field is unchanged and
21
38
  still present for a SITE build that has not migrated to the new array yet.
22
39
 
40
+ - 7ff47d7: Add the cookie-consent fields to `Analytics` (REB-642). _Entry added after
41
+ publishing (REB-787): these fields shipped in 1.2.0, but no changeset
42
+ targeted this package, so the generated notes above left them out._
43
+
44
+ `GET /api/site/analytics` now also returns what a SITE needs to run the
45
+ `@reblu/site-next/consent` banner. There is still one request, and the root
46
+ layout already makes it:
47
+ - `consentRequired: boolean`: `true` when the tenant has a valid GA4 or
48
+ Clarity id (computed from the already-validated `gaId`/`clarityId`, so an
49
+ id that fails validation never requires a banner). reCAPTCHA is excluded
50
+ on purpose because it is strictly necessary. `false` means no configured
51
+ vendor needs consent, so the SITE can skip the banner.
52
+ `<ConsentedAnalytics>` does not read this field.
53
+ - `cookiePolicyVersion: string | null`: a content hash of the tenant's cookie
54
+ policy. It is the same algorithm as `cookiePolicyVersion()` in
55
+ `@reblu/site-next/consent-server` on the same text, and a shared test
56
+ vector keeps the two identical. Pass it to
57
+ `<ConsentProvider policyVersion>`. When the tenant edits the policy in
58
+ nexus, the hash changes and visitors are asked again. `null` means no
59
+ policy is stored.
60
+ - `cookieBanner`: the banner copy the tenant edits in nexus:
61
+ `{ enabled, title, body, acceptLabel, rejectLabel, manageLabel, policyUrl }`.
62
+ A `null` text field means the SDK default applies. Map `body` to the
63
+ banner's `description` text and `policyUrl` to `policyHref`. The buttons
64
+ and categories are fixed and have no field here.
65
+ - `cookieInventory`: `{ vendor, category }[]`, where `category` is
66
+ `'necessary' | 'analytics' | 'marketing'`. It lists only the vendors this
67
+ SITE actually loads, and is meant for the cookie-policy table.
68
+
69
+ **Consumer note:** the four fields are required on the `Analytics` type.
70
+ Runtime responses always include them, but code that builds an `Analytics`
71
+ object by hand (for example test fixtures) must now set them. A neutral
72
+ fixture is `consentRequired: false`, `cookiePolicyVersion: null`,
73
+ `cookieBanner: { enabled: true, title: null, body: null, acceptLabel: null,
74
+ rejectLabel: null, manageLabel: null, policyUrl: null }`,
75
+ `cookieInventory: []`.
76
+
23
77
  ## 1.1.0
24
78
 
25
79
  ### Minor Changes
package/dist/index.d.cts CHANGED
@@ -145,7 +145,7 @@ export type ShopDiscountApplication = { valid: boolean; discount: number;
145
145
 
146
146
  export type ShopEmailCheck = { exists: boolean;}
147
147
 
148
- export type ShopFacets = { taxonomies: { key: string; label: string; showAsBadge: boolean; terms: { slug: string; name: string; count: number; }[]; }[]; attributes: { key: string; label: string; valueType: "boolean" | "text" | "select" | "multiselect"; options: { value: string; label: string; count: number; }[]; }[]; price: { min: number; max: number; }; onSale: { count: number; };}
148
+ export type ShopFacets = { taxonomies: { key: string; label: string; showAsBadge: boolean; selectionMode: "single" | "multiple"; terms: { slug: string; name: string; count: number; }[]; }[]; attributes: { key: string; label: string; valueType: "boolean" | "text" | "select" | "multiselect"; options: { value: string; label: string; count: number; }[]; }[]; price: { min: number; max: number; }; onSale: { count: number; };}
149
149
 
150
150
  export type ShopInventoryRef = { stockQuantity: number; reservedQuantity: number; lowStockThreshold: number | null;}
151
151
 
@@ -171,6 +171,8 @@ export type ShopSort = "price_asc" | "price_desc" | "newest" | "on_sale"
171
171
 
172
172
  export type ShopTaxRateRef = { rate: number; type: "IVA" | "IGIC" | "RETENTION" | "OTHER"; isExempt: boolean;}
173
173
 
174
+ export type ShopTaxonomySelectionMode = "single" | "multiple"
175
+
174
176
  export type ShopTaxonomyTermRef = { taxonomyKey: string; taxonomyLabel: string; showAsBadge: boolean; slug: string; name: string; imageUrl: string | null;}
175
177
 
176
178
  export type ShopValidateCartInput = { items: { productId: string; quantity: number; variantId?: string | null | undefined; }[];}
package/dist/index.d.ts CHANGED
@@ -145,7 +145,7 @@ export type ShopDiscountApplication = { valid: boolean; discount: number;
145
145
 
146
146
  export type ShopEmailCheck = { exists: boolean;}
147
147
 
148
- export type ShopFacets = { taxonomies: { key: string; label: string; showAsBadge: boolean; terms: { slug: string; name: string; count: number; }[]; }[]; attributes: { key: string; label: string; valueType: "boolean" | "text" | "select" | "multiselect"; options: { value: string; label: string; count: number; }[]; }[]; price: { min: number; max: number; }; onSale: { count: number; };}
148
+ export type ShopFacets = { taxonomies: { key: string; label: string; showAsBadge: boolean; selectionMode: "single" | "multiple"; terms: { slug: string; name: string; count: number; }[]; }[]; attributes: { key: string; label: string; valueType: "boolean" | "text" | "select" | "multiselect"; options: { value: string; label: string; count: number; }[]; }[]; price: { min: number; max: number; }; onSale: { count: number; };}
149
149
 
150
150
  export type ShopInventoryRef = { stockQuantity: number; reservedQuantity: number; lowStockThreshold: number | null;}
151
151
 
@@ -171,6 +171,8 @@ export type ShopSort = "price_asc" | "price_desc" | "newest" | "on_sale"
171
171
 
172
172
  export type ShopTaxRateRef = { rate: number; type: "IVA" | "IGIC" | "RETENTION" | "OTHER"; isExempt: boolean;}
173
173
 
174
+ export type ShopTaxonomySelectionMode = "single" | "multiple"
175
+
174
176
  export type ShopTaxonomyTermRef = { taxonomyKey: string; taxonomyLabel: string; showAsBadge: boolean; slug: string; name: string; imageUrl: string | null;}
175
177
 
176
178
  export type ShopValidateCartInput = { items: { productId: string; quantity: number; variantId?: string | null | undefined; }[];}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reblu/site-contracts",
3
- "version": "1.2.0",
3
+ "version": "1.3.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",