@reblu/site-contracts 1.4.0 → 1.6.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,27 @@
1
1
  # @reblu/site-contracts
2
2
 
3
+ ## 1.6.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 21feec3: REB-836 — checkout hardening: Stripe redirect-origin check + stable checkout error codes.
8
+ - `@reblu/site-contracts`: re-exports the new `ShopErrorCode` type (type-only, `z.infer` from base-api's `shopErrorCodeSchema`, no Zod reaches the published `.d.ts`) — nine values: `STOCK_CHANGED`, `PRICE_CHANGED`, `PRODUCT_UNAVAILABLE`, `DISCOUNT_INVALID`, `SHIPPING_UNAVAILABLE`, `INVALID_INPUT`, `STORE_DISABLED`, `PAYMENT_PROVIDER_ERROR`, and `INTERNAL_ERROR` (added in a native-review follow-up to distinguish an unexpected, non-Stripe failure — reported as HTTP 500 — from a Stripe failure, reported as 400 or, for a transient/5xx Stripe error, 503). This is the shop write endpoints' (`checkout`/`validateCart`/`applyDiscount`) new optional error-body `code` field.
9
+ - `@reblu/site-client`: (1) `shop.checkout()` now validates the returned Stripe Checkout URL is `https:` on an allowed host (default `checkout.stripe.com`, injectable via the new `RebluClientConfig.checkoutRedirectHosts`) before ever returning it, throwing the new `UnsafeCheckoutRedirectError` otherwise — exported alongside `isSafeCheckoutRedirectUrl` and `DEFAULT_CHECKOUT_REDIRECT_HOSTS`. (2) `ApiError.body` (`ApiErrorBody`/`ApiErrorDetails`) gains the optional `code` and `details.productIds` fields.
10
+ - `@reblu/site-next`: (1) `createShopCheckoutRoute` re-checks the Checkout URL server-side before responding to the browser (502 `unsafe_redirect` when it fails the check) — new `ShopCheckoutRouteOptions.allowedRedirectHosts`/`unsafeRedirectMessage`. (2) Native-review follow-up: that same route now strips `content-encoding`/`content-length`/`transfer-encoding` from its re-serialized response instead of forwarding them from the upstream proxy response, fixing a "browser tries to gunzip already-decoded JSON" failure mode.
11
+ - `@reblu/site-blocks`: adds `DEFAULT_SHOP_ERROR_MESSAGES` (a default Spanish message per `ShopErrorCode`, including `INTERNAL_ERROR`'s "Ha ocurrido un error inesperado. Inténtalo de nuevo en unos minutos.") and `getShopErrorMessage(code, overrides?, fallback?)`, which a SITE can override per code without restating the others.
12
+
13
+ All new fields/exports are additive and optional (REB-788) — a SITE that ignores `code`/`checkoutRedirectHosts` keeps working unchanged. The base-api side of this change (the `ShopErrorCode` schema itself, `checkout.service.ts`'s Stripe-vs-internal error classification, and `apiError()`'s options-object signature) is unpublished — it ships with the next base-api deploy, not through these changesets.
14
+
15
+ ## 1.5.0
16
+
17
+ ### Minor Changes
18
+
19
+ - 74a94ff: Add the order-lookup contract (REB-829). `ShopOrder`/`ShopOrderItem` type the
20
+ `GET /api/site/shop/order/[sessionId]` response — the order-confirmation
21
+ flow's missing piece: every SITE previously hand-rolled a local type for it
22
+ (demo-site's own comment: "base-api /api/site/shop/order is not yet in the
23
+ SDK surface"). `@reblu/site-client`'s `shop.order(sessionId)` reads it.
24
+
3
25
  ## 1.4.0
4
26
 
5
27
  ### Minor Changes
package/dist/index.d.cts CHANGED
@@ -151,10 +151,16 @@ export type ShopDiscountApplication = { valid: boolean; discount: number;
151
151
 
152
152
  export type ShopEmailCheck = { exists: boolean;}
153
153
 
154
+ export type ShopErrorCode = "STOCK_CHANGED" | "PRICE_CHANGED" | "PRODUCT_UNAVAILABLE" | "DISCOUNT_INVALID" | "SHIPPING_UNAVAILABLE" | "INVALID_INPUT" | "STORE_DISABLED" | "PAYMENT_PROVIDER_ERROR" | "INTERNAL_ERROR"
155
+
154
156
  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; };}
155
157
 
156
158
  export type ShopInventoryRef = { stockQuantity: number; reservedQuantity: number; lowStockThreshold: number | null;}
157
159
 
160
+ export type ShopOrder = { id: string; orderNumber: string; status: "PENDING" | "CONFIRMED" | "PROCESSING" | "SHIPPED" | "DELIVERED" | "CANCELLED" | "REFUNDED"; paymentStatus: "PENDING" | "REFUNDED" | "PAID" | "FAILED" | "PARTIALLY_REFUNDED"; customerEmail: string; total: number; items: { product: { id: string; name: string; slug: string; }; quantity: number; unitPrice: number; total: number; variant?: { id: string; name: string; } | null | undefined; }[];}
161
+
162
+ export type ShopOrderItem = { product: { id: string; name: string; slug: string; }; quantity: number; unitPrice: number; total: number; variant?: { id: string; name: string; } | null | undefined;}
163
+
158
164
  export type ShopProductAttributes = unknown
159
165
 
160
166
  export type ShopProductCategoryRef = { id: string; name: string; slug: string;}
package/dist/index.d.ts CHANGED
@@ -151,10 +151,16 @@ export type ShopDiscountApplication = { valid: boolean; discount: number;
151
151
 
152
152
  export type ShopEmailCheck = { exists: boolean;}
153
153
 
154
+ export type ShopErrorCode = "STOCK_CHANGED" | "PRICE_CHANGED" | "PRODUCT_UNAVAILABLE" | "DISCOUNT_INVALID" | "SHIPPING_UNAVAILABLE" | "INVALID_INPUT" | "STORE_DISABLED" | "PAYMENT_PROVIDER_ERROR" | "INTERNAL_ERROR"
155
+
154
156
  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; };}
155
157
 
156
158
  export type ShopInventoryRef = { stockQuantity: number; reservedQuantity: number; lowStockThreshold: number | null;}
157
159
 
160
+ export type ShopOrder = { id: string; orderNumber: string; status: "PENDING" | "CONFIRMED" | "PROCESSING" | "SHIPPED" | "DELIVERED" | "CANCELLED" | "REFUNDED"; paymentStatus: "PENDING" | "REFUNDED" | "PAID" | "FAILED" | "PARTIALLY_REFUNDED"; customerEmail: string; total: number; items: { product: { id: string; name: string; slug: string; }; quantity: number; unitPrice: number; total: number; variant?: { id: string; name: string; } | null | undefined; }[];}
161
+
162
+ export type ShopOrderItem = { product: { id: string; name: string; slug: string; }; quantity: number; unitPrice: number; total: number; variant?: { id: string; name: string; } | null | undefined;}
163
+
158
164
  export type ShopProductAttributes = unknown
159
165
 
160
166
  export type ShopProductCategoryRef = { id: string; name: string; slug: string;}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reblu/site-contracts",
3
- "version": "1.4.0",
3
+ "version": "1.6.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",