@reblu/site-contracts 1.22.0 → 1.24.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,29 @@
1
1
  # @reblu/site-contracts
2
2
 
3
+ ## 1.24.0
4
+
5
+ ### Minor Changes
6
+
7
+ - c7f3a43: Course catalogue filters are tenant config (REB-1234).
8
+ - `@reblu/site-contracts`: new `AcademyConfigPublic` and `AcademyCatalogFiltersPublic` types for `GET /api/site/academy/config`.
9
+ - `@reblu/site-client`: new `client.academy.config()`, returning `{ catalogFilters: { category, instructor, price } }` as switched on in nexus. A filter the tenant never set is `true`.
10
+ - `@reblu/site-blocks`: `CourseCatalogFilters` gains a category filter (`categories` + `hrefs.category`, `active.category`) and an `enabled` prop. Pass `catalogFilters` as `enabled` and only the switched-on filters render; with all off it renders nothing. Without `enabled` and `categories` the output is unchanged.
11
+
12
+ ## 1.23.0
13
+
14
+ ### Minor Changes
15
+
16
+ - f2ed9e2: Single-step checkout backend (REB-1197, REB-1198): delivery choice, pre-payment quote and terms acceptance.
17
+ - `ShopConfig.delivery` (`ShopCheckoutDeliveryConfig`): shipping cost and free-shipping threshold, which lines count toward it (`freeShippingScope`), max order weight and whether it applies to home delivery only (`maxOrderWeightScope`), the estimated delivery text and the pickup points (`ShopPickupLocation`, with opening hours and ready-in text). Optional: absent on older servers.
18
+ - `ShopConfig.delivery.methods` (`{ homeDelivery, pickup }`): the delivery methods the tenant offers (owner, 2-Nov). Render only these; `pickup` needs the switch and at least one active pickup point. A cart with nothing to ship shows no choice.
19
+ - `ShopQuote.blockingReason` (`ORDER_TOO_HEAVY` or `DELIVERY_UNAVAILABLE`, with a message) explains a `canCheckout: false`.
20
+ - New `ShopErrorCode` `DELIVERY_UNAVAILABLE` (422): a cart that ships, with no delivery method offered. A home delivery choice the tenant switched off answers `SHIPPING_UNAVAILABLE`.
21
+ - `ShopConfig.checkout` (`ShopCheckoutCopy`): the resolved checkout copy (button and option labels, line kind labels, terms checkbox label and link, small print under the button, full-invoice label and help text, tax line on/off) and `termsVersion` (`ShopTermsVersionRef`), the published terms version to accept, or `null`.
22
+ - `ShopCheckoutInput` gains `fulfillment` (`ShopFulfillmentInput`: `SHIPPING` or `PICKUP` with `pickupLocationId`), `acceptsTerms` and `termsVersionId`.
23
+ - New `POST /api/site/shop/quote` (`ShopQuoteInput` → `ShopQuote`): lines with kind and kind label, discount (an unusable code is left out and explained in `discountError`), delivery mode, shipping, tax breakdown, weight, delivery term, final total and the small print with the total filled in. The total is exactly what the checkout charges for the same body.
24
+ - New `ShopErrorCode`s: `PICKUP_UNAVAILABLE`, `PICKUP_LOCATION_INVALID`, `SHIPPING_ADDRESS_REQUIRED`, `ORDER_TOO_HEAVY` (all 422) and, when the tenant published terms, `TERMS_NOT_ACCEPTED` (422) and `TERMS_VERSION_CHANGED` (409).
25
+ - `Legal.termsVersion`, and `GET /api/site/legal/terms/{versionId}` (`LegalTermsVersion`): every published terms version stays readable.
26
+
3
27
  ## 1.22.0
4
28
 
5
29
  ### Minor Changes
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"names":[],"mappings":";;;AAkFO,IAAM,kBAAA,GAAqB,OAAO,MAAA,CAAO;AAAA,EAC9C,QAAA;AAAA,EACA,eAAA;AAAA,EACA,SAAA;AAAA,EACA,WAAA;AAAA,EACA,aAAA;AAAA,EACA,aAAA;AAAA,EACA,oBAAA;AAAA,EACA;AACF,CAAU","file":"index.cjs","sourcesContent":["/**\n * `@reblu/site-contracts` — public, dependency-free TypeScript types for the\n * Reblu SITE API (REB-414 / design doc §2).\n *\n * These types are the SDK-facing view of every `/api/site/*` response. They are\n * re-derived (`z.infer`) from the hand-authored response schemas that live in\n * base-api (`apps/base-api/src/lib/contracts/*.contract.ts`) and imported here\n * through the build-time-only `@reblu/base-api-contracts` type alias.\n *\n * Guarantees (enforced by the leakage guard tests):\n * - Everything below is `export type` — the import is erased at build time, so\n * NO Zod and NO Prisma reaches a consumer's runtime or `node_modules` graph.\n * The one exception is `DATA_REQUEST_TYPES` (REB-1005): a plain, import-free\n * array literal, the package's only runtime value.\n * - The published `.d.ts` is flattened and self-contained: the alias and\n * `z.infer` do not survive into the emitted declarations.\n * - Never re-exports an internal / Prisma-generated type — only the public\n * output DTOs base-api explicitly publishes.\n *\n * When base-api adds a new public contract type, add it to the matching group\n * below. The explicit list (over `export type *`) keeps the public surface a\n * reviewed, intentional decision and avoids leaking internal `*Schema` names.\n */\n\n// Envelope / pagination\nexport type { PaginationMeta } from '@reblu/base-api-contracts'\n\n// Analytics + shared contact-form mode\nexport type { Analytics, ContactFormMode } from '@reblu/base-api-contracts'\n\n// REB-845 — the tenant-editable cookie banner copy shape, standalone (not just\n// nested in `Analytics`), so `@reblu/site-next`'s `cookieBannerToConsentTexts`\n// can type its input against the real contract instead of a hand-rolled copy.\nexport type { CookieBanner } from '@reblu/base-api-contracts'\n\n// Site config\nexport type {\n Config,\n ConfigAddress,\n ConfigFiscal,\n ConfigFiscalRegistry,\n ConfigSocial,\n ConfigTaxIdKind,\n // REB-826 — typed opening hours.\n ConfigOpeningHours,\n ConfigOpeningHoursRange,\n ConfigOpeningHoursDay,\n} from '@reblu/base-api-contracts'\n\n// REB-871 — the resolved `seo` block on every detail response (pages, blog\n// posts, shop products, academy courses). `seo.title` is the FINAL page title.\nexport type { Seo } from '@reblu/base-api-contracts'\n\n// Contact form\nexport type { ContactFormSubmission, ContactFormInput } from '@reblu/base-api-contracts'\n// REB-1078 — the raw lead-origin touches a SITE sends in `metadata.attribution`\n// (contact form and `/api/site/leads`); base-api classifies the channel.\nexport type { LeadAttribution, LeadTouch } from '@reblu/base-api-contracts'\n\n// Leads\nexport type { LeadInput, LeadSubmission } from '@reblu/base-api-contracts'\n\n// GDPR data-subject requests (REB-77 endpoint, REB-980 SDK) — the public\n// `/derechos-rgpd` form body and its 72h acknowledgement.\nexport type {\n DataRequestInput,\n DataRequestSubmission,\n DataRequestType,\n} from '@reblu/base-api-contracts'\nimport type { DataRequestType } from '@reblu/base-api-contracts'\n\n/**\n * REB-1005 — every GDPR right a data subject can exercise, in base-api's order.\n * The ONE runtime value this package ships: server code (a SITE's Route\n * Handler, `@reblu/site-next`'s `createDataRequestRoute`) needs the list too,\n * and `@reblu/site-blocks` re-exports it as before.\n *\n * Single source: base-api's `dataRequestTypeSchema`. `satisfies` rejects a\n * member base-api does not know, `MissingDataRequestType` below rejects one it\n * knows and this list lacks, and `tests/unit/data-request-types.test.ts` pins\n * the order. Plain array literal, no import — the runtime stays dependency-free.\n */\nexport const DATA_REQUEST_TYPES = Object.freeze([\n 'ACCESS',\n 'RECTIFICATION',\n 'ERASURE',\n 'OBJECTION',\n 'PORTABILITY',\n 'RESTRICTION',\n 'AUTOMATED_DECISION',\n 'INFORMATION',\n] as const) satisfies readonly DataRequestType[]\n\n/** Compile error when base-api adds a right this list does not carry. */\ntype AssertNoneMissing<T extends never> = T\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\ntype MissingDataRequestType = AssertNoneMissing<\n Exclude<DataRequestType, (typeof DATA_REQUEST_TYPES)[number]>\n>\n\n// Blog\nexport type {\n BlogAuthor,\n BlogAuthorDetail,\n BlogCategory,\n BlogCategoryWithCount,\n BlogTag,\n BlogPostListItem,\n BlogPostDetail,\n BlogPostPreview,\n BlogSlug,\n} from '@reblu/base-api-contracts'\n\n// Pages\nexport type {\n // The flexible pageType (service|custom|treatments|specialties|team|generic)\n // — REB-63: this is what `pages.list`'s `type` filter actually validates\n // against server-side (`pagesListParamsSchema`), not `LegacyPageType`.\n PageType,\n // Legacy DB page type (SERVICE|CUSTOM) — the `type`/`category` fields still\n // carried on each `PageListItem`/`PageDetail` for backward compat during the\n // REB-75 dual-read window. NOT the `pages.list` filter's value space anymore.\n LegacyPageType,\n PageContentMode,\n SectionLayout,\n PageCategoryRef,\n PageListItem,\n PageSectionImage,\n PageSection,\n PageDetail,\n PageSlug,\n // REB-63: `pages.list`'s sort param — same reasoning as AcademyCourseSort\n // below (a typo is a compile error instead of a silent no-op fallback).\n PagesListSort,\n // REB-869 — `pages.list`'s query, incl. `featured` (with `category`: that\n // category's featured pages, max 3, in their stored order).\n PagesListQuery,\n // REB-75 D-D — the typed block registry on `PageDetail.blocks[]`.\n BlockType,\n Block,\n // REB-849 — each block mirrors its parent section's heading/backgroundColor/\n // cta; REB-851 phase 1 — doctor_embed/specialty_embed blocks additionally\n // carry `resolved` (present only on those two block types).\n PageBlock,\n BlockCta,\n ResolvedEmbed,\n // REB-867 — slugs are unique per category: the embed reference shape\n // (`pageId`/`categorySlug`) and the 409 body of an ambiguous `GET /pages/[slug]`.\n EmbedReferenceData,\n PageAmbiguousSlugError,\n} from '@reblu/base-api-contracts'\n\n// Professional profile (REB-63) — pageType='team' only. Sector-agnostic\n// structured CV, same platform-shape/tenant-content split as CustomFieldDefinition.\n// REB-1099: `ProfessionalField` — a tenant-defined field (e.g. a registration\n// number) on the card (`ProfessionalSummary.fields`) and profile.\nexport type {\n ProfessionalField,\n ProfessionalSummary,\n ProfessionalProfile,\n ProfessionalCv,\n ProfessionalCvEntry,\n ProfessionalLanguage,\n ProfessionalLanguageLevel,\n ProfessionalSocialLink,\n ProfessionalSocialPlatform,\n} from '@reblu/base-api-contracts'\n\n// Custom-field registry (REB-475 / REB-75) — entity-agnostic, shared with pages/team\nexport type {\n CustomFieldValueType,\n CustomFieldEntityType,\n CustomFieldOption,\n CustomFieldDefinition,\n} from '@reblu/base-api-contracts'\n\n// Shop\nexport type {\n TaxType,\n ProductType,\n ShopConfig,\n // Store-wide product trust items (REB-858)\n ShopProductTrustIcon,\n ShopProductTrustItem,\n ShopTaxRateRef,\n ShopProductImage,\n ShopProductVideo,\n ShopProductCategoryRef,\n ShopInventoryRef,\n ShopCategory,\n ShopProductListItem,\n ShopProductVariant,\n ShopBundleComponent,\n ShopRelatedProduct,\n ShopProductDetail,\n // Taxonomy + attributes + facets (REB-474/475)\n ShopTaxonomyTermRef,\n ShopProductAttributes,\n // Per-axis selection mode (REB-809/REB-801)\n ShopTaxonomySelectionMode,\n ShopSort,\n ShopProductListParams,\n ShopFacets,\n // Write inputs (REB-438)\n ShopCartItemInput,\n ShopAddressInput,\n ShopBillingInput,\n ShopCheckoutInput,\n ShopValidateCartInput,\n ShopApplyDiscountInput,\n // Write responses (REB-438)\n ShopCheckoutSession,\n ShopCartValidationError,\n ShopCartValidationItem,\n ShopCartValidation,\n ShopDiscountApplication,\n // Automatic staff discount, additive on the write responses (REB-1131)\n ShopStaffAutoDiscount,\n // Order lookup (REB-829)\n ShopOrderItem,\n ShopOrder,\n // The order's invoice reference (REB-73)\n ShopOrderInvoice,\n // Stable, machine-readable write-endpoint error codes (REB-836)\n ShopErrorCode,\n} from '@reblu/base-api-contracts'\n\n// REB-834 — `POST /api/site/shop/check-email` is deprecated: it was an\n// account-enumeration oracle and now always answers `{ exists: false }`.\n// Kept (a minor may only deprecate); removed in the next major.\nexport type {\n /**\n * @deprecated REB-834 — `POST /api/site/shop/check-email` no longer reveals\n * whether an account exists. Do not call it; removed in the next major.\n */\n ShopCheckEmailInput,\n /**\n * @deprecated REB-834 — `exists` is always `false`. Never branch UI on it:\n * the checkout always offers «Iniciar sesión o continuar como invitado» and\n * the server links the order to an existing account after payment. Removed\n * in the next major.\n */\n ShopEmailCheck,\n} from '@reblu/base-api-contracts'\n\n// Academy (REB-507) — public course catalogue. `AcademyCourseSort` is the query\n// contract for the `sort` param, so the SDK can type it as a union instead of a\n// bare string (an unknown key is silently ignored server-side).\nexport type {\n AcademyCourseSort,\n // REB-547 — the documented catalogue query: q, sort, category, instructor\n // (a user id from `GET /api/site/academy/instructors`), free and the price\n // range in integer cents.\n AcademyCourseListQuery,\n AcademyCategoryPublic,\n AcademyLessonPublic,\n AcademyModulePublic,\n AcademyInstructorPublic,\n AcademyCourseSummary,\n AcademyCourseDetail,\n // REB-83 — tenant-configurable validation fields (drives the enrollment CTA form).\n AcademyValidationFieldPublic,\n // REB-1135 — a free-preview lesson, viewable by the public\n // (`GET /api/site/academy/courses/{slug}/lessons/{lessonSlug}`).\n AcademyLessonPreview,\n AcademyLessonPreviewVideo,\n} from '@reblu/base-api-contracts'\n\n// Legal\nexport type { Legal } from '@reblu/base-api-contracts'\n\n// CTAs\nexport type { Cta } from '@reblu/base-api-contracts'\n\n// Trust badges\nexport type { TrustBadge, TrustBadgeType } from '@reblu/base-api-contracts'\n\n// SITE capability manifest (`/.well-known/reblu-site.json`) — REB-777.\n// Direction note (see `site-manifest.contract.ts` in base-api): this is the\n// one contract group a SITE produces and base-api consumes, the opposite of\n// every group above. The TYPE still flows through this same alias so the\n// SDK and nexus never describe two different shapes for it; the real Zod\n// validation stays in base-api only — this package never gains a Zod\n// runtime dependency.\nexport type {\n SiteManifest,\n SiteManifestSurfaceValue,\n SiteCapabilitySurfaceKey,\n} from '@reblu/base-api-contracts'\n"]}
1
+ {"version":3,"sources":["../src/index.ts"],"names":[],"mappings":";;;AAkFO,IAAM,kBAAA,GAAqB,OAAO,MAAA,CAAO;AAAA,EAC9C,QAAA;AAAA,EACA,eAAA;AAAA,EACA,SAAA;AAAA,EACA,WAAA;AAAA,EACA,aAAA;AAAA,EACA,aAAA;AAAA,EACA,oBAAA;AAAA,EACA;AACF,CAAU","file":"index.cjs","sourcesContent":["/**\n * `@reblu/site-contracts` — public, dependency-free TypeScript types for the\n * Reblu SITE API (REB-414 / design doc §2).\n *\n * These types are the SDK-facing view of every `/api/site/*` response. They are\n * re-derived (`z.infer`) from the hand-authored response schemas that live in\n * base-api (`apps/base-api/src/lib/contracts/*.contract.ts`) and imported here\n * through the build-time-only `@reblu/base-api-contracts` type alias.\n *\n * Guarantees (enforced by the leakage guard tests):\n * - Everything below is `export type` — the import is erased at build time, so\n * NO Zod and NO Prisma reaches a consumer's runtime or `node_modules` graph.\n * The one exception is `DATA_REQUEST_TYPES` (REB-1005): a plain, import-free\n * array literal, the package's only runtime value.\n * - The published `.d.ts` is flattened and self-contained: the alias and\n * `z.infer` do not survive into the emitted declarations.\n * - Never re-exports an internal / Prisma-generated type — only the public\n * output DTOs base-api explicitly publishes.\n *\n * When base-api adds a new public contract type, add it to the matching group\n * below. The explicit list (over `export type *`) keeps the public surface a\n * reviewed, intentional decision and avoids leaking internal `*Schema` names.\n */\n\n// Envelope / pagination\nexport type { PaginationMeta } from '@reblu/base-api-contracts'\n\n// Analytics + shared contact-form mode\nexport type { Analytics, ContactFormMode } from '@reblu/base-api-contracts'\n\n// REB-845 — the tenant-editable cookie banner copy shape, standalone (not just\n// nested in `Analytics`), so `@reblu/site-next`'s `cookieBannerToConsentTexts`\n// can type its input against the real contract instead of a hand-rolled copy.\nexport type { CookieBanner } from '@reblu/base-api-contracts'\n\n// Site config\nexport type {\n Config,\n ConfigAddress,\n ConfigFiscal,\n ConfigFiscalRegistry,\n ConfigSocial,\n ConfigTaxIdKind,\n // REB-826 — typed opening hours.\n ConfigOpeningHours,\n ConfigOpeningHoursRange,\n ConfigOpeningHoursDay,\n} from '@reblu/base-api-contracts'\n\n// REB-871 — the resolved `seo` block on every detail response (pages, blog\n// posts, shop products, academy courses). `seo.title` is the FINAL page title.\nexport type { Seo } from '@reblu/base-api-contracts'\n\n// Contact form\nexport type { ContactFormSubmission, ContactFormInput } from '@reblu/base-api-contracts'\n// REB-1078 — the raw lead-origin touches a SITE sends in `metadata.attribution`\n// (contact form and `/api/site/leads`); base-api classifies the channel.\nexport type { LeadAttribution, LeadTouch } from '@reblu/base-api-contracts'\n\n// Leads\nexport type { LeadInput, LeadSubmission } from '@reblu/base-api-contracts'\n\n// GDPR data-subject requests (REB-77 endpoint, REB-980 SDK) — the public\n// `/derechos-rgpd` form body and its 72h acknowledgement.\nexport type {\n DataRequestInput,\n DataRequestSubmission,\n DataRequestType,\n} from '@reblu/base-api-contracts'\nimport type { DataRequestType } from '@reblu/base-api-contracts'\n\n/**\n * REB-1005 — every GDPR right a data subject can exercise, in base-api's order.\n * The ONE runtime value this package ships: server code (a SITE's Route\n * Handler, `@reblu/site-next`'s `createDataRequestRoute`) needs the list too,\n * and `@reblu/site-blocks` re-exports it as before.\n *\n * Single source: base-api's `dataRequestTypeSchema`. `satisfies` rejects a\n * member base-api does not know, `MissingDataRequestType` below rejects one it\n * knows and this list lacks, and `tests/unit/data-request-types.test.ts` pins\n * the order. Plain array literal, no import — the runtime stays dependency-free.\n */\nexport const DATA_REQUEST_TYPES = Object.freeze([\n 'ACCESS',\n 'RECTIFICATION',\n 'ERASURE',\n 'OBJECTION',\n 'PORTABILITY',\n 'RESTRICTION',\n 'AUTOMATED_DECISION',\n 'INFORMATION',\n] as const) satisfies readonly DataRequestType[]\n\n/** Compile error when base-api adds a right this list does not carry. */\ntype AssertNoneMissing<T extends never> = T\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\ntype MissingDataRequestType = AssertNoneMissing<\n Exclude<DataRequestType, (typeof DATA_REQUEST_TYPES)[number]>\n>\n\n// Blog\nexport type {\n BlogAuthor,\n BlogAuthorDetail,\n BlogCategory,\n BlogCategoryWithCount,\n BlogTag,\n BlogPostListItem,\n BlogPostDetail,\n BlogPostPreview,\n BlogSlug,\n} from '@reblu/base-api-contracts'\n\n// Pages\nexport type {\n // The flexible pageType (service|custom|treatments|specialties|team|generic)\n // — REB-63: this is what `pages.list`'s `type` filter actually validates\n // against server-side (`pagesListParamsSchema`), not `LegacyPageType`.\n PageType,\n // Legacy DB page type (SERVICE|CUSTOM) — the `type`/`category` fields still\n // carried on each `PageListItem`/`PageDetail` for backward compat during the\n // REB-75 dual-read window. NOT the `pages.list` filter's value space anymore.\n LegacyPageType,\n PageContentMode,\n SectionLayout,\n PageCategoryRef,\n PageListItem,\n PageSectionImage,\n PageSection,\n PageDetail,\n PageSlug,\n // REB-63: `pages.list`'s sort param — same reasoning as AcademyCourseSort\n // below (a typo is a compile error instead of a silent no-op fallback).\n PagesListSort,\n // REB-869 — `pages.list`'s query, incl. `featured` (with `category`: that\n // category's featured pages, max 3, in their stored order).\n PagesListQuery,\n // REB-75 D-D — the typed block registry on `PageDetail.blocks[]`.\n BlockType,\n Block,\n // REB-849 — each block mirrors its parent section's heading/backgroundColor/\n // cta; REB-851 phase 1 — doctor_embed/specialty_embed blocks additionally\n // carry `resolved` (present only on those two block types).\n PageBlock,\n BlockCta,\n ResolvedEmbed,\n // REB-867 — slugs are unique per category: the embed reference shape\n // (`pageId`/`categorySlug`) and the 409 body of an ambiguous `GET /pages/[slug]`.\n EmbedReferenceData,\n PageAmbiguousSlugError,\n} from '@reblu/base-api-contracts'\n\n// Professional profile (REB-63) — pageType='team' only. Sector-agnostic\n// structured CV, same platform-shape/tenant-content split as CustomFieldDefinition.\n// REB-1099: `ProfessionalField` — a tenant-defined field (e.g. a registration\n// number) on the card (`ProfessionalSummary.fields`) and profile.\nexport type {\n ProfessionalField,\n ProfessionalSummary,\n ProfessionalProfile,\n ProfessionalCv,\n ProfessionalCvEntry,\n ProfessionalLanguage,\n ProfessionalLanguageLevel,\n ProfessionalSocialLink,\n ProfessionalSocialPlatform,\n} from '@reblu/base-api-contracts'\n\n// Custom-field registry (REB-475 / REB-75) — entity-agnostic, shared with pages/team\nexport type {\n CustomFieldValueType,\n CustomFieldEntityType,\n CustomFieldOption,\n CustomFieldDefinition,\n} from '@reblu/base-api-contracts'\n\n// Shop\nexport type {\n TaxType,\n ProductType,\n ShopConfig,\n // Store-wide product trust items (REB-858)\n ShopProductTrustIcon,\n ShopProductTrustItem,\n ShopTaxRateRef,\n ShopProductImage,\n ShopProductVideo,\n ShopProductCategoryRef,\n ShopInventoryRef,\n ShopCategory,\n ShopProductListItem,\n ShopProductVariant,\n ShopBundleComponent,\n ShopRelatedProduct,\n ShopProductDetail,\n // Taxonomy + attributes + facets (REB-474/475)\n ShopTaxonomyTermRef,\n ShopProductAttributes,\n // Per-axis selection mode (REB-809/REB-801)\n ShopTaxonomySelectionMode,\n ShopSort,\n ShopProductListParams,\n ShopFacets,\n // Write inputs (REB-438)\n ShopCartItemInput,\n ShopAddressInput,\n ShopBillingInput,\n ShopCheckoutInput,\n ShopValidateCartInput,\n ShopApplyDiscountInput,\n // Write responses (REB-438)\n ShopCheckoutSession,\n ShopCartValidationError,\n ShopCartValidationItem,\n ShopCartValidation,\n ShopDiscountApplication,\n // Automatic staff discount, additive on the write responses (REB-1131)\n ShopStaffAutoDiscount,\n // Order lookup (REB-829)\n ShopOrderItem,\n ShopOrder,\n // The order's invoice reference (REB-73)\n ShopOrderInvoice,\n // Stable, machine-readable write-endpoint error codes (REB-836)\n ShopErrorCode,\n // Single-step checkout (REB-1197 / REB-1198): delivery rules, pickup\n // points, resolved checkout copy, the terms version to accept, the\n // delivery choice and the pre-payment quote.\n ShopPickupLocation,\n ShopCheckoutDeliveryConfig,\n ShopCheckoutCopy,\n ShopTermsVersionRef,\n ShopFulfillmentInput,\n ShopQuoteInput,\n ShopQuoteLine,\n ShopQuote,\n} from '@reblu/base-api-contracts'\n\n// REB-834 — `POST /api/site/shop/check-email` is deprecated: it was an\n// account-enumeration oracle and now always answers `{ exists: false }`.\n// Kept (a minor may only deprecate); removed in the next major.\nexport type {\n /**\n * @deprecated REB-834 — `POST /api/site/shop/check-email` no longer reveals\n * whether an account exists. Do not call it; removed in the next major.\n */\n ShopCheckEmailInput,\n /**\n * @deprecated REB-834 — `exists` is always `false`. Never branch UI on it:\n * the checkout always offers «Iniciar sesión o continuar como invitado» and\n * the server links the order to an existing account after payment. Removed\n * in the next major.\n */\n ShopEmailCheck,\n} from '@reblu/base-api-contracts'\n\n// Academy (REB-507) — public course catalogue. `AcademyCourseSort` is the query\n// contract for the `sort` param, so the SDK can type it as a union instead of a\n// bare string (an unknown key is silently ignored server-side).\nexport type {\n AcademyCourseSort,\n // REB-547 — the documented catalogue query: q, sort, category, instructor\n // (a user id from `GET /api/site/academy/instructors`), free and the price\n // range in integer cents.\n AcademyCourseListQuery,\n AcademyCategoryPublic,\n AcademyLessonPublic,\n AcademyModulePublic,\n AcademyInstructorPublic,\n AcademyCourseSummary,\n AcademyCourseDetail,\n // REB-83 — tenant-configurable validation fields (drives the enrollment CTA form).\n AcademyValidationFieldPublic,\n // REB-1135 — a free-preview lesson, viewable by the public\n // (`GET /api/site/academy/courses/{slug}/lessons/{lessonSlug}`).\n AcademyLessonPreview,\n AcademyLessonPreviewVideo,\n // REB-1234 — tenant academy settings for the SITE\n // (`GET /api/site/academy/config`): which catalogue filters are switched on.\n AcademyConfigPublic,\n AcademyCatalogFiltersPublic,\n} from '@reblu/base-api-contracts'\n\n// Legal\nexport type { Legal, LegalTermsVersion } from '@reblu/base-api-contracts'\n\n// CTAs\nexport type { Cta } from '@reblu/base-api-contracts'\n\n// Trust badges\nexport type { TrustBadge, TrustBadgeType } from '@reblu/base-api-contracts'\n\n// SITE capability manifest (`/.well-known/reblu-site.json`) — REB-777.\n// Direction note (see `site-manifest.contract.ts` in base-api): this is the\n// one contract group a SITE produces and base-api consumes, the opposite of\n// every group above. The TYPE still flows through this same alias so the\n// SDK and nexus never describe two different shapes for it; the real Zod\n// validation stays in base-api only — this package never gains a Zod\n// runtime dependency.\nexport type {\n SiteManifest,\n SiteManifestSurfaceValue,\n SiteCapabilitySurfaceKey,\n} from '@reblu/base-api-contracts'\n"]}
package/dist/index.d.cts CHANGED
@@ -4,8 +4,12 @@
4
4
  * Source of truth: apps/base-api/src/lib/contracts/*.contract.ts (types)
5
5
  * and src/index.ts (runtime consts such as DATA_REQUEST_TYPES).
6
6
  */
7
+ export type AcademyCatalogFiltersPublic = { category: boolean; instructor: boolean; price: boolean;}
8
+
7
9
  export type AcademyCategoryPublic = { id: string; name: string; slug: string; sortOrder: number;}
8
10
 
11
+ export type AcademyConfigPublic = { catalogFilters: { category: boolean; instructor: boolean; price: boolean; };}
12
+
9
13
  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;}
10
14
 
11
15
  export type AcademyCourseListQuery = { page?: number | undefined; limit?: number | undefined; q?: string | undefined; sort?: "price_asc" | "price_desc" | "newest" | undefined; category?: string | undefined; instructor?: string | undefined; free?: boolean | undefined; priceMin?: number | undefined; priceMax?: number | undefined;}
@@ -106,7 +110,9 @@ export type LeadTouch = { utm?: { source?: string | undefined;
106
110
 
107
111
  export type LegacyPageType = "SERVICE" | "CUSTOM"
108
112
 
109
- export type Legal = { privacyPolicy: string | null; termsAndConditions: string | null; cookiePolicy: string | null;}
113
+ export type Legal = { privacyPolicy: string | null; termsAndConditions: string | null; cookiePolicy: string | null; termsVersion?: { id: string; version: number; publishedAt: string; } | null | undefined;}
114
+
115
+ export type LegalTermsVersion = { id: string; version: number; publishedAt: string; content: string; contentHash: string;}
110
116
 
111
117
  export type PageAmbiguousSlugError = { error: string; code: "ambiguous_slug"; candidates: { categorySlug: string | null; }[];}
112
118
 
@@ -184,11 +190,15 @@ export type ShopCategory = { id: string; name: string; slug: string;
184
190
  */
185
191
  export type ShopCheckEmailInput = { email: string;}
186
192
 
187
- 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; billingIdType?: "NIF" | "02" | "03" | "04" | "05" | "06" | undefined; billingIdCountry?: 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; wantsFullInvoice?: boolean | undefined;}
193
+ export type ShopCheckoutCopy = { tenantName: string; continueToPaymentLabel: string; shippingOptionLabel: string; pickupOptionLabel: string; emptyCartText: string; lineKindLabels: Record<string, string>; isTaxLineVisible: boolean; termsCheckboxLabel: string; termsLinkText: string; termsLinkUrl: string | null; isTermsLinkNewTab: boolean; payNotice: string; fullInvoiceCheckboxLabel: string; fullInvoiceHelpText: string; termsVersion: { id: string; version: number; publishedAt: string; } | null;}
194
+
195
+ export type ShopCheckoutDeliveryConfig = { methods: { homeDelivery: boolean; pickup: boolean; }; shippingEnabled: boolean; defaultShippingCost: number | null; freeShippingThreshold: number | null; freeShippingScope: "SHIPPABLE_ONLY" | "WHOLE_CART"; maxOrderWeightGrams: number | null; maxOrderWeightScope: "SHIPPING_ONLY" | "ALL_ORDERS"; estimatedDeliveryText: string | null; pickupLocations: { id: string; name: string; address: string; city: string; postalCode: string; region: string | null; country: string; phone: string | null; email: string | null; openingHoursText: string | null; pickupReadyText: string | null; }[];}
196
+
197
+ 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; billingIdType?: "NIF" | "02" | "03" | "04" | "05" | "06" | undefined; billingIdCountry?: 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; wantsFullInvoice?: boolean | undefined; fulfillment?: { type: "SHIPPING" | "PICKUP"; pickupLocationId?: string | undefined; } | undefined; acceptsTerms?: boolean | undefined; termsVersionId?: string | undefined;}
188
198
 
189
199
  export type ShopCheckoutSession = { url: string; sessionId: string; autoDiscount?: { code: string; label: string; amount: number; } | undefined;}
190
200
 
191
- export type ShopConfig = { shopName: string | null; defaultLowStockThreshold: number; currencyCode: string; stripePublishableKey: string | null; stripeTestPublishableKey: string | null; stripeTestMode: boolean; shippingEnabled: boolean; pickupEnabled: boolean; taxEnabled: boolean; taxIncludedInPrice: boolean; simplifiedInvoiceCapCents?: number | null | undefined; productTrustItems?: { [x: string]: unknown; icon: (string & {}) | "shipping" | "returns" | "secure-payment" | "support" | "gift" | "pickup" | "warranty" | "quality"; text: string; }[] | null | undefined;}
201
+ export type ShopConfig = { shopName: string | null; defaultLowStockThreshold: number; currencyCode: string; stripePublishableKey: string | null; stripeTestPublishableKey: string | null; stripeTestMode: boolean; shippingEnabled: boolean; pickupEnabled: boolean; taxEnabled: boolean; taxIncludedInPrice: boolean; simplifiedInvoiceCapCents?: number | null | undefined; productTrustItems?: { [x: string]: unknown; icon: (string & {}) | "shipping" | "returns" | "secure-payment" | "support" | "gift" | "pickup" | "warranty" | "quality"; text: string; }[] | null | undefined; delivery?: { methods: { homeDelivery: boolean; pickup: boolean; }; shippingEnabled: boolean; defaultShippingCost: number | null; freeShippingThreshold: number | null; freeShippingScope: "SHIPPABLE_ONLY" | "WHOLE_CART"; maxOrderWeightGrams: number | null; maxOrderWeightScope: "SHIPPING_ONLY" | "ALL_ORDERS"; estimatedDeliveryText: string | null; pickupLocations: { id: string; name: string; address: string; city: string; postalCode: string; region: string | null; country: string; phone: string | null; email: string | null; openingHoursText: string | null; pickupReadyText: string | null; }[]; } | undefined; checkout?: { tenantName: string; continueToPaymentLabel: string; shippingOptionLabel: string; pickupOptionLabel: string; emptyCartText: string; lineKindLabels: Record<string, string>; isTaxLineVisible: boolean; termsCheckboxLabel: string; termsLinkText: string; termsLinkUrl: string | null; isTermsLinkNewTab: boolean; payNotice: string; fullInvoiceCheckboxLabel: string; fullInvoiceHelpText: string; termsVersion: { id: string; version: number; publishedAt: string; } | null; } | undefined;}
192
202
 
193
203
  export type ShopDiscountApplication = { valid: boolean; discount: number; type: "PERCENTAGE" | "FIXED" | null; code: string | null; error?: string | undefined; autoDiscount?: { code: string; label: string; amount: number; } | undefined;}
194
204
 
@@ -200,10 +210,12 @@ export type ShopDiscountApplication = { valid: boolean; discount: number;
200
210
  */
201
211
  export type ShopEmailCheck = { exists: boolean;}
202
212
 
203
- export type ShopErrorCode = "STOCK_CHANGED" | "PRICE_CHANGED" | "PRODUCT_UNAVAILABLE" | "DISCOUNT_INVALID" | "SHIPPING_UNAVAILABLE" | "INVALID_INPUT" | "STORE_DISABLED" | "PAYMENT_PROVIDER_ERROR" | "INTERNAL_ERROR" | "BILLING_DATA_REQUIRED" | "INVOICING_NOT_READY" | "FULL_INVOICE_UNAVAILABLE" | "DISCOUNT_LIMIT_REACHED"
213
+ export type ShopErrorCode = "STOCK_CHANGED" | "PRICE_CHANGED" | "PRODUCT_UNAVAILABLE" | "DISCOUNT_INVALID" | "SHIPPING_UNAVAILABLE" | "INVALID_INPUT" | "STORE_DISABLED" | "PAYMENT_PROVIDER_ERROR" | "INTERNAL_ERROR" | "BILLING_DATA_REQUIRED" | "INVOICING_NOT_READY" | "FULL_INVOICE_UNAVAILABLE" | "DISCOUNT_LIMIT_REACHED" | "PICKUP_UNAVAILABLE" | "PICKUP_LOCATION_INVALID" | "SHIPPING_ADDRESS_REQUIRED" | "ORDER_TOO_HEAVY" | "TERMS_NOT_ACCEPTED" | "TERMS_VERSION_CHANGED" | "DELIVERY_UNAVAILABLE"
204
214
 
205
215
  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; };}
206
216
 
217
+ export type ShopFulfillmentInput = { type: "SHIPPING" | "PICKUP"; pickupLocationId?: string | undefined;}
218
+
207
219
  export type ShopInventoryRef = { stockQuantity: number; reservedQuantity: number; lowStockThreshold: number | null;}
208
220
 
209
221
  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; }[]; invoice?: { number: string; url: string; } | null | undefined;}
@@ -212,6 +224,8 @@ export type ShopOrderInvoice = { number: string; url: string;}
212
224
 
213
225
  export type ShopOrderItem = { product: { id: string; name: string; slug: string; }; quantity: number; unitPrice: number; total: number; variant?: { id: string; name: string; } | null | undefined;}
214
226
 
227
+ export type ShopPickupLocation = { id: string; name: string; address: string; city: string; postalCode: string; region: string | null; country: string; phone: string | null; email: string | null; openingHoursText: string | null; pickupReadyText: string | null;}
228
+
215
229
  export type ShopProductAttributes = unknown
216
230
 
217
231
  export type ShopProductCategoryRef = { id: string; name: string; slug: string;}
@@ -232,6 +246,12 @@ export type ShopProductVariant = { id: string; name: string; sku: strin
232
246
 
233
247
  export type ShopProductVideo = { url: string; title: string | null; isExternal: boolean; thumbnailUrl: string | null; sortOrder: number;}
234
248
 
249
+ export type ShopQuote = { lines: { productId: string; variantId: string | null; name: string; variantName: string | null; imageUrl: string | null; kind: string | null; kindLabel: string | null; quantity: number; unitPrice: number; total: number; isShippable: boolean; unitWeightGrams: number | null; }[]; subtotal: number; discount: { code: string; amount: number; isAutomatic: boolean; label: string | null; } | null; discountError: { code: "DISCOUNT_INVALID" | "DISCOUNT_LIMIT_REACHED"; message: string; } | null; fulfillment: { type: "SHIPPING" | "PICKUP" | null; label: string | null; pickupLocation: { id: string; name: string; address: string; city: string; postalCode: string; region: string | null; country: string; phone: string | null; email: string | null; openingHoursText: string | null; pickupReadyText: string | null; } | null; }; shipping: { cost: number; isFree: boolean; freeShippingThreshold: number | null; freeShippingScope: "SHIPPABLE_ONLY" | "WHOLE_CART"; remainingForFree: number | null; }; tax: { isIncluded: boolean; amount: number; isLineVisible: boolean; breakdown: { label: string; amount: number; }[]; }; weight: { totalGrams: number; maxGrams: number | null; scope: "SHIPPING_ONLY" | "ALL_ORDERS"; exceeded: boolean; }; deliveryEstimateText: string | null; total: number; payNotice: string; canCheckout: boolean; blockingReason: { code: "ORDER_TOO_HEAVY" | "DELIVERY_UNAVAILABLE"; message: string; } | null;}
250
+
251
+ export type ShopQuoteInput = { items: { productId: string; quantity: number; variantId?: string | null | undefined; }[]; discountCode?: string | undefined; customerEmail?: string | undefined; fulfillment?: { type: "SHIPPING" | "PICKUP"; pickupLocationId?: string | undefined; } | undefined;}
252
+
253
+ export type ShopQuoteLine = { productId: string; variantId: string | null; name: string; variantName: string | null; imageUrl: string | null; kind: string | null; kindLabel: string | null; quantity: number; unitPrice: number; total: number; isShippable: boolean; unitWeightGrams: number | null;}
254
+
235
255
  export type ShopRelatedProduct = { id: string; slug: string; name: string; price: number; comparePrice: number | null; images: { url: string; alt: string | null; isPrimary: boolean; sortOrder: number; }[];}
236
256
 
237
257
  export type ShopSort = "price_asc" | "price_desc" | "newest" | "on_sale"
@@ -244,6 +264,8 @@ export type ShopTaxonomySelectionMode = "single" | "multiple"
244
264
 
245
265
  export type ShopTaxonomyTermRef = { taxonomyKey: string; taxonomyLabel: string; showAsBadge: boolean; slug: string; name: string; imageUrl: string | null;}
246
266
 
267
+ export type ShopTermsVersionRef = { id: string; version: number; publishedAt: string;}
268
+
247
269
  export type ShopValidateCartInput = { items: { productId: string; quantity: number; variantId?: string | null | undefined; }[];}
248
270
 
249
271
  export type SiteCapabilitySurfaceKey = "academy.enrollment" | "academy.catalogue" | "auth.login" | "consent.banner" | "legal.cookies"
package/dist/index.d.ts CHANGED
@@ -4,8 +4,12 @@
4
4
  * Source of truth: apps/base-api/src/lib/contracts/*.contract.ts (types)
5
5
  * and src/index.ts (runtime consts such as DATA_REQUEST_TYPES).
6
6
  */
7
+ export type AcademyCatalogFiltersPublic = { category: boolean; instructor: boolean; price: boolean;}
8
+
7
9
  export type AcademyCategoryPublic = { id: string; name: string; slug: string; sortOrder: number;}
8
10
 
11
+ export type AcademyConfigPublic = { catalogFilters: { category: boolean; instructor: boolean; price: boolean; };}
12
+
9
13
  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;}
10
14
 
11
15
  export type AcademyCourseListQuery = { page?: number | undefined; limit?: number | undefined; q?: string | undefined; sort?: "price_asc" | "price_desc" | "newest" | undefined; category?: string | undefined; instructor?: string | undefined; free?: boolean | undefined; priceMin?: number | undefined; priceMax?: number | undefined;}
@@ -106,7 +110,9 @@ export type LeadTouch = { utm?: { source?: string | undefined;
106
110
 
107
111
  export type LegacyPageType = "SERVICE" | "CUSTOM"
108
112
 
109
- export type Legal = { privacyPolicy: string | null; termsAndConditions: string | null; cookiePolicy: string | null;}
113
+ export type Legal = { privacyPolicy: string | null; termsAndConditions: string | null; cookiePolicy: string | null; termsVersion?: { id: string; version: number; publishedAt: string; } | null | undefined;}
114
+
115
+ export type LegalTermsVersion = { id: string; version: number; publishedAt: string; content: string; contentHash: string;}
110
116
 
111
117
  export type PageAmbiguousSlugError = { error: string; code: "ambiguous_slug"; candidates: { categorySlug: string | null; }[];}
112
118
 
@@ -184,11 +190,15 @@ export type ShopCategory = { id: string; name: string; slug: string;
184
190
  */
185
191
  export type ShopCheckEmailInput = { email: string;}
186
192
 
187
- 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; billingIdType?: "NIF" | "02" | "03" | "04" | "05" | "06" | undefined; billingIdCountry?: 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; wantsFullInvoice?: boolean | undefined;}
193
+ export type ShopCheckoutCopy = { tenantName: string; continueToPaymentLabel: string; shippingOptionLabel: string; pickupOptionLabel: string; emptyCartText: string; lineKindLabels: Record<string, string>; isTaxLineVisible: boolean; termsCheckboxLabel: string; termsLinkText: string; termsLinkUrl: string | null; isTermsLinkNewTab: boolean; payNotice: string; fullInvoiceCheckboxLabel: string; fullInvoiceHelpText: string; termsVersion: { id: string; version: number; publishedAt: string; } | null;}
194
+
195
+ export type ShopCheckoutDeliveryConfig = { methods: { homeDelivery: boolean; pickup: boolean; }; shippingEnabled: boolean; defaultShippingCost: number | null; freeShippingThreshold: number | null; freeShippingScope: "SHIPPABLE_ONLY" | "WHOLE_CART"; maxOrderWeightGrams: number | null; maxOrderWeightScope: "SHIPPING_ONLY" | "ALL_ORDERS"; estimatedDeliveryText: string | null; pickupLocations: { id: string; name: string; address: string; city: string; postalCode: string; region: string | null; country: string; phone: string | null; email: string | null; openingHoursText: string | null; pickupReadyText: string | null; }[];}
196
+
197
+ 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; billingIdType?: "NIF" | "02" | "03" | "04" | "05" | "06" | undefined; billingIdCountry?: 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; wantsFullInvoice?: boolean | undefined; fulfillment?: { type: "SHIPPING" | "PICKUP"; pickupLocationId?: string | undefined; } | undefined; acceptsTerms?: boolean | undefined; termsVersionId?: string | undefined;}
188
198
 
189
199
  export type ShopCheckoutSession = { url: string; sessionId: string; autoDiscount?: { code: string; label: string; amount: number; } | undefined;}
190
200
 
191
- export type ShopConfig = { shopName: string | null; defaultLowStockThreshold: number; currencyCode: string; stripePublishableKey: string | null; stripeTestPublishableKey: string | null; stripeTestMode: boolean; shippingEnabled: boolean; pickupEnabled: boolean; taxEnabled: boolean; taxIncludedInPrice: boolean; simplifiedInvoiceCapCents?: number | null | undefined; productTrustItems?: { [x: string]: unknown; icon: (string & {}) | "shipping" | "returns" | "secure-payment" | "support" | "gift" | "pickup" | "warranty" | "quality"; text: string; }[] | null | undefined;}
201
+ export type ShopConfig = { shopName: string | null; defaultLowStockThreshold: number; currencyCode: string; stripePublishableKey: string | null; stripeTestPublishableKey: string | null; stripeTestMode: boolean; shippingEnabled: boolean; pickupEnabled: boolean; taxEnabled: boolean; taxIncludedInPrice: boolean; simplifiedInvoiceCapCents?: number | null | undefined; productTrustItems?: { [x: string]: unknown; icon: (string & {}) | "shipping" | "returns" | "secure-payment" | "support" | "gift" | "pickup" | "warranty" | "quality"; text: string; }[] | null | undefined; delivery?: { methods: { homeDelivery: boolean; pickup: boolean; }; shippingEnabled: boolean; defaultShippingCost: number | null; freeShippingThreshold: number | null; freeShippingScope: "SHIPPABLE_ONLY" | "WHOLE_CART"; maxOrderWeightGrams: number | null; maxOrderWeightScope: "SHIPPING_ONLY" | "ALL_ORDERS"; estimatedDeliveryText: string | null; pickupLocations: { id: string; name: string; address: string; city: string; postalCode: string; region: string | null; country: string; phone: string | null; email: string | null; openingHoursText: string | null; pickupReadyText: string | null; }[]; } | undefined; checkout?: { tenantName: string; continueToPaymentLabel: string; shippingOptionLabel: string; pickupOptionLabel: string; emptyCartText: string; lineKindLabels: Record<string, string>; isTaxLineVisible: boolean; termsCheckboxLabel: string; termsLinkText: string; termsLinkUrl: string | null; isTermsLinkNewTab: boolean; payNotice: string; fullInvoiceCheckboxLabel: string; fullInvoiceHelpText: string; termsVersion: { id: string; version: number; publishedAt: string; } | null; } | undefined;}
192
202
 
193
203
  export type ShopDiscountApplication = { valid: boolean; discount: number; type: "PERCENTAGE" | "FIXED" | null; code: string | null; error?: string | undefined; autoDiscount?: { code: string; label: string; amount: number; } | undefined;}
194
204
 
@@ -200,10 +210,12 @@ export type ShopDiscountApplication = { valid: boolean; discount: number;
200
210
  */
201
211
  export type ShopEmailCheck = { exists: boolean;}
202
212
 
203
- export type ShopErrorCode = "STOCK_CHANGED" | "PRICE_CHANGED" | "PRODUCT_UNAVAILABLE" | "DISCOUNT_INVALID" | "SHIPPING_UNAVAILABLE" | "INVALID_INPUT" | "STORE_DISABLED" | "PAYMENT_PROVIDER_ERROR" | "INTERNAL_ERROR" | "BILLING_DATA_REQUIRED" | "INVOICING_NOT_READY" | "FULL_INVOICE_UNAVAILABLE" | "DISCOUNT_LIMIT_REACHED"
213
+ export type ShopErrorCode = "STOCK_CHANGED" | "PRICE_CHANGED" | "PRODUCT_UNAVAILABLE" | "DISCOUNT_INVALID" | "SHIPPING_UNAVAILABLE" | "INVALID_INPUT" | "STORE_DISABLED" | "PAYMENT_PROVIDER_ERROR" | "INTERNAL_ERROR" | "BILLING_DATA_REQUIRED" | "INVOICING_NOT_READY" | "FULL_INVOICE_UNAVAILABLE" | "DISCOUNT_LIMIT_REACHED" | "PICKUP_UNAVAILABLE" | "PICKUP_LOCATION_INVALID" | "SHIPPING_ADDRESS_REQUIRED" | "ORDER_TOO_HEAVY" | "TERMS_NOT_ACCEPTED" | "TERMS_VERSION_CHANGED" | "DELIVERY_UNAVAILABLE"
204
214
 
205
215
  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; };}
206
216
 
217
+ export type ShopFulfillmentInput = { type: "SHIPPING" | "PICKUP"; pickupLocationId?: string | undefined;}
218
+
207
219
  export type ShopInventoryRef = { stockQuantity: number; reservedQuantity: number; lowStockThreshold: number | null;}
208
220
 
209
221
  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; }[]; invoice?: { number: string; url: string; } | null | undefined;}
@@ -212,6 +224,8 @@ export type ShopOrderInvoice = { number: string; url: string;}
212
224
 
213
225
  export type ShopOrderItem = { product: { id: string; name: string; slug: string; }; quantity: number; unitPrice: number; total: number; variant?: { id: string; name: string; } | null | undefined;}
214
226
 
227
+ export type ShopPickupLocation = { id: string; name: string; address: string; city: string; postalCode: string; region: string | null; country: string; phone: string | null; email: string | null; openingHoursText: string | null; pickupReadyText: string | null;}
228
+
215
229
  export type ShopProductAttributes = unknown
216
230
 
217
231
  export type ShopProductCategoryRef = { id: string; name: string; slug: string;}
@@ -232,6 +246,12 @@ export type ShopProductVariant = { id: string; name: string; sku: strin
232
246
 
233
247
  export type ShopProductVideo = { url: string; title: string | null; isExternal: boolean; thumbnailUrl: string | null; sortOrder: number;}
234
248
 
249
+ export type ShopQuote = { lines: { productId: string; variantId: string | null; name: string; variantName: string | null; imageUrl: string | null; kind: string | null; kindLabel: string | null; quantity: number; unitPrice: number; total: number; isShippable: boolean; unitWeightGrams: number | null; }[]; subtotal: number; discount: { code: string; amount: number; isAutomatic: boolean; label: string | null; } | null; discountError: { code: "DISCOUNT_INVALID" | "DISCOUNT_LIMIT_REACHED"; message: string; } | null; fulfillment: { type: "SHIPPING" | "PICKUP" | null; label: string | null; pickupLocation: { id: string; name: string; address: string; city: string; postalCode: string; region: string | null; country: string; phone: string | null; email: string | null; openingHoursText: string | null; pickupReadyText: string | null; } | null; }; shipping: { cost: number; isFree: boolean; freeShippingThreshold: number | null; freeShippingScope: "SHIPPABLE_ONLY" | "WHOLE_CART"; remainingForFree: number | null; }; tax: { isIncluded: boolean; amount: number; isLineVisible: boolean; breakdown: { label: string; amount: number; }[]; }; weight: { totalGrams: number; maxGrams: number | null; scope: "SHIPPING_ONLY" | "ALL_ORDERS"; exceeded: boolean; }; deliveryEstimateText: string | null; total: number; payNotice: string; canCheckout: boolean; blockingReason: { code: "ORDER_TOO_HEAVY" | "DELIVERY_UNAVAILABLE"; message: string; } | null;}
250
+
251
+ export type ShopQuoteInput = { items: { productId: string; quantity: number; variantId?: string | null | undefined; }[]; discountCode?: string | undefined; customerEmail?: string | undefined; fulfillment?: { type: "SHIPPING" | "PICKUP"; pickupLocationId?: string | undefined; } | undefined;}
252
+
253
+ export type ShopQuoteLine = { productId: string; variantId: string | null; name: string; variantName: string | null; imageUrl: string | null; kind: string | null; kindLabel: string | null; quantity: number; unitPrice: number; total: number; isShippable: boolean; unitWeightGrams: number | null;}
254
+
235
255
  export type ShopRelatedProduct = { id: string; slug: string; name: string; price: number; comparePrice: number | null; images: { url: string; alt: string | null; isPrimary: boolean; sortOrder: number; }[];}
236
256
 
237
257
  export type ShopSort = "price_asc" | "price_desc" | "newest" | "on_sale"
@@ -244,6 +264,8 @@ export type ShopTaxonomySelectionMode = "single" | "multiple"
244
264
 
245
265
  export type ShopTaxonomyTermRef = { taxonomyKey: string; taxonomyLabel: string; showAsBadge: boolean; slug: string; name: string; imageUrl: string | null;}
246
266
 
267
+ export type ShopTermsVersionRef = { id: string; version: number; publishedAt: string;}
268
+
247
269
  export type ShopValidateCartInput = { items: { productId: string; quantity: number; variantId?: string | null | undefined; }[];}
248
270
 
249
271
  export type SiteCapabilitySurfaceKey = "academy.enrollment" | "academy.catalogue" | "auth.login" | "consent.banner" | "legal.cookies"
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"names":[],"mappings":";AAkFO,IAAM,kBAAA,GAAqB,OAAO,MAAA,CAAO;AAAA,EAC9C,QAAA;AAAA,EACA,eAAA;AAAA,EACA,SAAA;AAAA,EACA,WAAA;AAAA,EACA,aAAA;AAAA,EACA,aAAA;AAAA,EACA,oBAAA;AAAA,EACA;AACF,CAAU","file":"index.js","sourcesContent":["/**\n * `@reblu/site-contracts` — public, dependency-free TypeScript types for the\n * Reblu SITE API (REB-414 / design doc §2).\n *\n * These types are the SDK-facing view of every `/api/site/*` response. They are\n * re-derived (`z.infer`) from the hand-authored response schemas that live in\n * base-api (`apps/base-api/src/lib/contracts/*.contract.ts`) and imported here\n * through the build-time-only `@reblu/base-api-contracts` type alias.\n *\n * Guarantees (enforced by the leakage guard tests):\n * - Everything below is `export type` — the import is erased at build time, so\n * NO Zod and NO Prisma reaches a consumer's runtime or `node_modules` graph.\n * The one exception is `DATA_REQUEST_TYPES` (REB-1005): a plain, import-free\n * array literal, the package's only runtime value.\n * - The published `.d.ts` is flattened and self-contained: the alias and\n * `z.infer` do not survive into the emitted declarations.\n * - Never re-exports an internal / Prisma-generated type — only the public\n * output DTOs base-api explicitly publishes.\n *\n * When base-api adds a new public contract type, add it to the matching group\n * below. The explicit list (over `export type *`) keeps the public surface a\n * reviewed, intentional decision and avoids leaking internal `*Schema` names.\n */\n\n// Envelope / pagination\nexport type { PaginationMeta } from '@reblu/base-api-contracts'\n\n// Analytics + shared contact-form mode\nexport type { Analytics, ContactFormMode } from '@reblu/base-api-contracts'\n\n// REB-845 — the tenant-editable cookie banner copy shape, standalone (not just\n// nested in `Analytics`), so `@reblu/site-next`'s `cookieBannerToConsentTexts`\n// can type its input against the real contract instead of a hand-rolled copy.\nexport type { CookieBanner } from '@reblu/base-api-contracts'\n\n// Site config\nexport type {\n Config,\n ConfigAddress,\n ConfigFiscal,\n ConfigFiscalRegistry,\n ConfigSocial,\n ConfigTaxIdKind,\n // REB-826 — typed opening hours.\n ConfigOpeningHours,\n ConfigOpeningHoursRange,\n ConfigOpeningHoursDay,\n} from '@reblu/base-api-contracts'\n\n// REB-871 — the resolved `seo` block on every detail response (pages, blog\n// posts, shop products, academy courses). `seo.title` is the FINAL page title.\nexport type { Seo } from '@reblu/base-api-contracts'\n\n// Contact form\nexport type { ContactFormSubmission, ContactFormInput } from '@reblu/base-api-contracts'\n// REB-1078 — the raw lead-origin touches a SITE sends in `metadata.attribution`\n// (contact form and `/api/site/leads`); base-api classifies the channel.\nexport type { LeadAttribution, LeadTouch } from '@reblu/base-api-contracts'\n\n// Leads\nexport type { LeadInput, LeadSubmission } from '@reblu/base-api-contracts'\n\n// GDPR data-subject requests (REB-77 endpoint, REB-980 SDK) — the public\n// `/derechos-rgpd` form body and its 72h acknowledgement.\nexport type {\n DataRequestInput,\n DataRequestSubmission,\n DataRequestType,\n} from '@reblu/base-api-contracts'\nimport type { DataRequestType } from '@reblu/base-api-contracts'\n\n/**\n * REB-1005 — every GDPR right a data subject can exercise, in base-api's order.\n * The ONE runtime value this package ships: server code (a SITE's Route\n * Handler, `@reblu/site-next`'s `createDataRequestRoute`) needs the list too,\n * and `@reblu/site-blocks` re-exports it as before.\n *\n * Single source: base-api's `dataRequestTypeSchema`. `satisfies` rejects a\n * member base-api does not know, `MissingDataRequestType` below rejects one it\n * knows and this list lacks, and `tests/unit/data-request-types.test.ts` pins\n * the order. Plain array literal, no import — the runtime stays dependency-free.\n */\nexport const DATA_REQUEST_TYPES = Object.freeze([\n 'ACCESS',\n 'RECTIFICATION',\n 'ERASURE',\n 'OBJECTION',\n 'PORTABILITY',\n 'RESTRICTION',\n 'AUTOMATED_DECISION',\n 'INFORMATION',\n] as const) satisfies readonly DataRequestType[]\n\n/** Compile error when base-api adds a right this list does not carry. */\ntype AssertNoneMissing<T extends never> = T\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\ntype MissingDataRequestType = AssertNoneMissing<\n Exclude<DataRequestType, (typeof DATA_REQUEST_TYPES)[number]>\n>\n\n// Blog\nexport type {\n BlogAuthor,\n BlogAuthorDetail,\n BlogCategory,\n BlogCategoryWithCount,\n BlogTag,\n BlogPostListItem,\n BlogPostDetail,\n BlogPostPreview,\n BlogSlug,\n} from '@reblu/base-api-contracts'\n\n// Pages\nexport type {\n // The flexible pageType (service|custom|treatments|specialties|team|generic)\n // — REB-63: this is what `pages.list`'s `type` filter actually validates\n // against server-side (`pagesListParamsSchema`), not `LegacyPageType`.\n PageType,\n // Legacy DB page type (SERVICE|CUSTOM) — the `type`/`category` fields still\n // carried on each `PageListItem`/`PageDetail` for backward compat during the\n // REB-75 dual-read window. NOT the `pages.list` filter's value space anymore.\n LegacyPageType,\n PageContentMode,\n SectionLayout,\n PageCategoryRef,\n PageListItem,\n PageSectionImage,\n PageSection,\n PageDetail,\n PageSlug,\n // REB-63: `pages.list`'s sort param — same reasoning as AcademyCourseSort\n // below (a typo is a compile error instead of a silent no-op fallback).\n PagesListSort,\n // REB-869 — `pages.list`'s query, incl. `featured` (with `category`: that\n // category's featured pages, max 3, in their stored order).\n PagesListQuery,\n // REB-75 D-D — the typed block registry on `PageDetail.blocks[]`.\n BlockType,\n Block,\n // REB-849 — each block mirrors its parent section's heading/backgroundColor/\n // cta; REB-851 phase 1 — doctor_embed/specialty_embed blocks additionally\n // carry `resolved` (present only on those two block types).\n PageBlock,\n BlockCta,\n ResolvedEmbed,\n // REB-867 — slugs are unique per category: the embed reference shape\n // (`pageId`/`categorySlug`) and the 409 body of an ambiguous `GET /pages/[slug]`.\n EmbedReferenceData,\n PageAmbiguousSlugError,\n} from '@reblu/base-api-contracts'\n\n// Professional profile (REB-63) — pageType='team' only. Sector-agnostic\n// structured CV, same platform-shape/tenant-content split as CustomFieldDefinition.\n// REB-1099: `ProfessionalField` — a tenant-defined field (e.g. a registration\n// number) on the card (`ProfessionalSummary.fields`) and profile.\nexport type {\n ProfessionalField,\n ProfessionalSummary,\n ProfessionalProfile,\n ProfessionalCv,\n ProfessionalCvEntry,\n ProfessionalLanguage,\n ProfessionalLanguageLevel,\n ProfessionalSocialLink,\n ProfessionalSocialPlatform,\n} from '@reblu/base-api-contracts'\n\n// Custom-field registry (REB-475 / REB-75) — entity-agnostic, shared with pages/team\nexport type {\n CustomFieldValueType,\n CustomFieldEntityType,\n CustomFieldOption,\n CustomFieldDefinition,\n} from '@reblu/base-api-contracts'\n\n// Shop\nexport type {\n TaxType,\n ProductType,\n ShopConfig,\n // Store-wide product trust items (REB-858)\n ShopProductTrustIcon,\n ShopProductTrustItem,\n ShopTaxRateRef,\n ShopProductImage,\n ShopProductVideo,\n ShopProductCategoryRef,\n ShopInventoryRef,\n ShopCategory,\n ShopProductListItem,\n ShopProductVariant,\n ShopBundleComponent,\n ShopRelatedProduct,\n ShopProductDetail,\n // Taxonomy + attributes + facets (REB-474/475)\n ShopTaxonomyTermRef,\n ShopProductAttributes,\n // Per-axis selection mode (REB-809/REB-801)\n ShopTaxonomySelectionMode,\n ShopSort,\n ShopProductListParams,\n ShopFacets,\n // Write inputs (REB-438)\n ShopCartItemInput,\n ShopAddressInput,\n ShopBillingInput,\n ShopCheckoutInput,\n ShopValidateCartInput,\n ShopApplyDiscountInput,\n // Write responses (REB-438)\n ShopCheckoutSession,\n ShopCartValidationError,\n ShopCartValidationItem,\n ShopCartValidation,\n ShopDiscountApplication,\n // Automatic staff discount, additive on the write responses (REB-1131)\n ShopStaffAutoDiscount,\n // Order lookup (REB-829)\n ShopOrderItem,\n ShopOrder,\n // The order's invoice reference (REB-73)\n ShopOrderInvoice,\n // Stable, machine-readable write-endpoint error codes (REB-836)\n ShopErrorCode,\n} from '@reblu/base-api-contracts'\n\n// REB-834 — `POST /api/site/shop/check-email` is deprecated: it was an\n// account-enumeration oracle and now always answers `{ exists: false }`.\n// Kept (a minor may only deprecate); removed in the next major.\nexport type {\n /**\n * @deprecated REB-834 — `POST /api/site/shop/check-email` no longer reveals\n * whether an account exists. Do not call it; removed in the next major.\n */\n ShopCheckEmailInput,\n /**\n * @deprecated REB-834 — `exists` is always `false`. Never branch UI on it:\n * the checkout always offers «Iniciar sesión o continuar como invitado» and\n * the server links the order to an existing account after payment. Removed\n * in the next major.\n */\n ShopEmailCheck,\n} from '@reblu/base-api-contracts'\n\n// Academy (REB-507) — public course catalogue. `AcademyCourseSort` is the query\n// contract for the `sort` param, so the SDK can type it as a union instead of a\n// bare string (an unknown key is silently ignored server-side).\nexport type {\n AcademyCourseSort,\n // REB-547 — the documented catalogue query: q, sort, category, instructor\n // (a user id from `GET /api/site/academy/instructors`), free and the price\n // range in integer cents.\n AcademyCourseListQuery,\n AcademyCategoryPublic,\n AcademyLessonPublic,\n AcademyModulePublic,\n AcademyInstructorPublic,\n AcademyCourseSummary,\n AcademyCourseDetail,\n // REB-83 — tenant-configurable validation fields (drives the enrollment CTA form).\n AcademyValidationFieldPublic,\n // REB-1135 — a free-preview lesson, viewable by the public\n // (`GET /api/site/academy/courses/{slug}/lessons/{lessonSlug}`).\n AcademyLessonPreview,\n AcademyLessonPreviewVideo,\n} from '@reblu/base-api-contracts'\n\n// Legal\nexport type { Legal } from '@reblu/base-api-contracts'\n\n// CTAs\nexport type { Cta } from '@reblu/base-api-contracts'\n\n// Trust badges\nexport type { TrustBadge, TrustBadgeType } from '@reblu/base-api-contracts'\n\n// SITE capability manifest (`/.well-known/reblu-site.json`) — REB-777.\n// Direction note (see `site-manifest.contract.ts` in base-api): this is the\n// one contract group a SITE produces and base-api consumes, the opposite of\n// every group above. The TYPE still flows through this same alias so the\n// SDK and nexus never describe two different shapes for it; the real Zod\n// validation stays in base-api only — this package never gains a Zod\n// runtime dependency.\nexport type {\n SiteManifest,\n SiteManifestSurfaceValue,\n SiteCapabilitySurfaceKey,\n} from '@reblu/base-api-contracts'\n"]}
1
+ {"version":3,"sources":["../src/index.ts"],"names":[],"mappings":";AAkFO,IAAM,kBAAA,GAAqB,OAAO,MAAA,CAAO;AAAA,EAC9C,QAAA;AAAA,EACA,eAAA;AAAA,EACA,SAAA;AAAA,EACA,WAAA;AAAA,EACA,aAAA;AAAA,EACA,aAAA;AAAA,EACA,oBAAA;AAAA,EACA;AACF,CAAU","file":"index.js","sourcesContent":["/**\n * `@reblu/site-contracts` — public, dependency-free TypeScript types for the\n * Reblu SITE API (REB-414 / design doc §2).\n *\n * These types are the SDK-facing view of every `/api/site/*` response. They are\n * re-derived (`z.infer`) from the hand-authored response schemas that live in\n * base-api (`apps/base-api/src/lib/contracts/*.contract.ts`) and imported here\n * through the build-time-only `@reblu/base-api-contracts` type alias.\n *\n * Guarantees (enforced by the leakage guard tests):\n * - Everything below is `export type` — the import is erased at build time, so\n * NO Zod and NO Prisma reaches a consumer's runtime or `node_modules` graph.\n * The one exception is `DATA_REQUEST_TYPES` (REB-1005): a plain, import-free\n * array literal, the package's only runtime value.\n * - The published `.d.ts` is flattened and self-contained: the alias and\n * `z.infer` do not survive into the emitted declarations.\n * - Never re-exports an internal / Prisma-generated type — only the public\n * output DTOs base-api explicitly publishes.\n *\n * When base-api adds a new public contract type, add it to the matching group\n * below. The explicit list (over `export type *`) keeps the public surface a\n * reviewed, intentional decision and avoids leaking internal `*Schema` names.\n */\n\n// Envelope / pagination\nexport type { PaginationMeta } from '@reblu/base-api-contracts'\n\n// Analytics + shared contact-form mode\nexport type { Analytics, ContactFormMode } from '@reblu/base-api-contracts'\n\n// REB-845 — the tenant-editable cookie banner copy shape, standalone (not just\n// nested in `Analytics`), so `@reblu/site-next`'s `cookieBannerToConsentTexts`\n// can type its input against the real contract instead of a hand-rolled copy.\nexport type { CookieBanner } from '@reblu/base-api-contracts'\n\n// Site config\nexport type {\n Config,\n ConfigAddress,\n ConfigFiscal,\n ConfigFiscalRegistry,\n ConfigSocial,\n ConfigTaxIdKind,\n // REB-826 — typed opening hours.\n ConfigOpeningHours,\n ConfigOpeningHoursRange,\n ConfigOpeningHoursDay,\n} from '@reblu/base-api-contracts'\n\n// REB-871 — the resolved `seo` block on every detail response (pages, blog\n// posts, shop products, academy courses). `seo.title` is the FINAL page title.\nexport type { Seo } from '@reblu/base-api-contracts'\n\n// Contact form\nexport type { ContactFormSubmission, ContactFormInput } from '@reblu/base-api-contracts'\n// REB-1078 — the raw lead-origin touches a SITE sends in `metadata.attribution`\n// (contact form and `/api/site/leads`); base-api classifies the channel.\nexport type { LeadAttribution, LeadTouch } from '@reblu/base-api-contracts'\n\n// Leads\nexport type { LeadInput, LeadSubmission } from '@reblu/base-api-contracts'\n\n// GDPR data-subject requests (REB-77 endpoint, REB-980 SDK) — the public\n// `/derechos-rgpd` form body and its 72h acknowledgement.\nexport type {\n DataRequestInput,\n DataRequestSubmission,\n DataRequestType,\n} from '@reblu/base-api-contracts'\nimport type { DataRequestType } from '@reblu/base-api-contracts'\n\n/**\n * REB-1005 — every GDPR right a data subject can exercise, in base-api's order.\n * The ONE runtime value this package ships: server code (a SITE's Route\n * Handler, `@reblu/site-next`'s `createDataRequestRoute`) needs the list too,\n * and `@reblu/site-blocks` re-exports it as before.\n *\n * Single source: base-api's `dataRequestTypeSchema`. `satisfies` rejects a\n * member base-api does not know, `MissingDataRequestType` below rejects one it\n * knows and this list lacks, and `tests/unit/data-request-types.test.ts` pins\n * the order. Plain array literal, no import — the runtime stays dependency-free.\n */\nexport const DATA_REQUEST_TYPES = Object.freeze([\n 'ACCESS',\n 'RECTIFICATION',\n 'ERASURE',\n 'OBJECTION',\n 'PORTABILITY',\n 'RESTRICTION',\n 'AUTOMATED_DECISION',\n 'INFORMATION',\n] as const) satisfies readonly DataRequestType[]\n\n/** Compile error when base-api adds a right this list does not carry. */\ntype AssertNoneMissing<T extends never> = T\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\ntype MissingDataRequestType = AssertNoneMissing<\n Exclude<DataRequestType, (typeof DATA_REQUEST_TYPES)[number]>\n>\n\n// Blog\nexport type {\n BlogAuthor,\n BlogAuthorDetail,\n BlogCategory,\n BlogCategoryWithCount,\n BlogTag,\n BlogPostListItem,\n BlogPostDetail,\n BlogPostPreview,\n BlogSlug,\n} from '@reblu/base-api-contracts'\n\n// Pages\nexport type {\n // The flexible pageType (service|custom|treatments|specialties|team|generic)\n // — REB-63: this is what `pages.list`'s `type` filter actually validates\n // against server-side (`pagesListParamsSchema`), not `LegacyPageType`.\n PageType,\n // Legacy DB page type (SERVICE|CUSTOM) — the `type`/`category` fields still\n // carried on each `PageListItem`/`PageDetail` for backward compat during the\n // REB-75 dual-read window. NOT the `pages.list` filter's value space anymore.\n LegacyPageType,\n PageContentMode,\n SectionLayout,\n PageCategoryRef,\n PageListItem,\n PageSectionImage,\n PageSection,\n PageDetail,\n PageSlug,\n // REB-63: `pages.list`'s sort param — same reasoning as AcademyCourseSort\n // below (a typo is a compile error instead of a silent no-op fallback).\n PagesListSort,\n // REB-869 — `pages.list`'s query, incl. `featured` (with `category`: that\n // category's featured pages, max 3, in their stored order).\n PagesListQuery,\n // REB-75 D-D — the typed block registry on `PageDetail.blocks[]`.\n BlockType,\n Block,\n // REB-849 — each block mirrors its parent section's heading/backgroundColor/\n // cta; REB-851 phase 1 — doctor_embed/specialty_embed blocks additionally\n // carry `resolved` (present only on those two block types).\n PageBlock,\n BlockCta,\n ResolvedEmbed,\n // REB-867 — slugs are unique per category: the embed reference shape\n // (`pageId`/`categorySlug`) and the 409 body of an ambiguous `GET /pages/[slug]`.\n EmbedReferenceData,\n PageAmbiguousSlugError,\n} from '@reblu/base-api-contracts'\n\n// Professional profile (REB-63) — pageType='team' only. Sector-agnostic\n// structured CV, same platform-shape/tenant-content split as CustomFieldDefinition.\n// REB-1099: `ProfessionalField` — a tenant-defined field (e.g. a registration\n// number) on the card (`ProfessionalSummary.fields`) and profile.\nexport type {\n ProfessionalField,\n ProfessionalSummary,\n ProfessionalProfile,\n ProfessionalCv,\n ProfessionalCvEntry,\n ProfessionalLanguage,\n ProfessionalLanguageLevel,\n ProfessionalSocialLink,\n ProfessionalSocialPlatform,\n} from '@reblu/base-api-contracts'\n\n// Custom-field registry (REB-475 / REB-75) — entity-agnostic, shared with pages/team\nexport type {\n CustomFieldValueType,\n CustomFieldEntityType,\n CustomFieldOption,\n CustomFieldDefinition,\n} from '@reblu/base-api-contracts'\n\n// Shop\nexport type {\n TaxType,\n ProductType,\n ShopConfig,\n // Store-wide product trust items (REB-858)\n ShopProductTrustIcon,\n ShopProductTrustItem,\n ShopTaxRateRef,\n ShopProductImage,\n ShopProductVideo,\n ShopProductCategoryRef,\n ShopInventoryRef,\n ShopCategory,\n ShopProductListItem,\n ShopProductVariant,\n ShopBundleComponent,\n ShopRelatedProduct,\n ShopProductDetail,\n // Taxonomy + attributes + facets (REB-474/475)\n ShopTaxonomyTermRef,\n ShopProductAttributes,\n // Per-axis selection mode (REB-809/REB-801)\n ShopTaxonomySelectionMode,\n ShopSort,\n ShopProductListParams,\n ShopFacets,\n // Write inputs (REB-438)\n ShopCartItemInput,\n ShopAddressInput,\n ShopBillingInput,\n ShopCheckoutInput,\n ShopValidateCartInput,\n ShopApplyDiscountInput,\n // Write responses (REB-438)\n ShopCheckoutSession,\n ShopCartValidationError,\n ShopCartValidationItem,\n ShopCartValidation,\n ShopDiscountApplication,\n // Automatic staff discount, additive on the write responses (REB-1131)\n ShopStaffAutoDiscount,\n // Order lookup (REB-829)\n ShopOrderItem,\n ShopOrder,\n // The order's invoice reference (REB-73)\n ShopOrderInvoice,\n // Stable, machine-readable write-endpoint error codes (REB-836)\n ShopErrorCode,\n // Single-step checkout (REB-1197 / REB-1198): delivery rules, pickup\n // points, resolved checkout copy, the terms version to accept, the\n // delivery choice and the pre-payment quote.\n ShopPickupLocation,\n ShopCheckoutDeliveryConfig,\n ShopCheckoutCopy,\n ShopTermsVersionRef,\n ShopFulfillmentInput,\n ShopQuoteInput,\n ShopQuoteLine,\n ShopQuote,\n} from '@reblu/base-api-contracts'\n\n// REB-834 — `POST /api/site/shop/check-email` is deprecated: it was an\n// account-enumeration oracle and now always answers `{ exists: false }`.\n// Kept (a minor may only deprecate); removed in the next major.\nexport type {\n /**\n * @deprecated REB-834 — `POST /api/site/shop/check-email` no longer reveals\n * whether an account exists. Do not call it; removed in the next major.\n */\n ShopCheckEmailInput,\n /**\n * @deprecated REB-834 — `exists` is always `false`. Never branch UI on it:\n * the checkout always offers «Iniciar sesión o continuar como invitado» and\n * the server links the order to an existing account after payment. Removed\n * in the next major.\n */\n ShopEmailCheck,\n} from '@reblu/base-api-contracts'\n\n// Academy (REB-507) — public course catalogue. `AcademyCourseSort` is the query\n// contract for the `sort` param, so the SDK can type it as a union instead of a\n// bare string (an unknown key is silently ignored server-side).\nexport type {\n AcademyCourseSort,\n // REB-547 — the documented catalogue query: q, sort, category, instructor\n // (a user id from `GET /api/site/academy/instructors`), free and the price\n // range in integer cents.\n AcademyCourseListQuery,\n AcademyCategoryPublic,\n AcademyLessonPublic,\n AcademyModulePublic,\n AcademyInstructorPublic,\n AcademyCourseSummary,\n AcademyCourseDetail,\n // REB-83 — tenant-configurable validation fields (drives the enrollment CTA form).\n AcademyValidationFieldPublic,\n // REB-1135 — a free-preview lesson, viewable by the public\n // (`GET /api/site/academy/courses/{slug}/lessons/{lessonSlug}`).\n AcademyLessonPreview,\n AcademyLessonPreviewVideo,\n // REB-1234 — tenant academy settings for the SITE\n // (`GET /api/site/academy/config`): which catalogue filters are switched on.\n AcademyConfigPublic,\n AcademyCatalogFiltersPublic,\n} from '@reblu/base-api-contracts'\n\n// Legal\nexport type { Legal, LegalTermsVersion } from '@reblu/base-api-contracts'\n\n// CTAs\nexport type { Cta } from '@reblu/base-api-contracts'\n\n// Trust badges\nexport type { TrustBadge, TrustBadgeType } from '@reblu/base-api-contracts'\n\n// SITE capability manifest (`/.well-known/reblu-site.json`) — REB-777.\n// Direction note (see `site-manifest.contract.ts` in base-api): this is the\n// one contract group a SITE produces and base-api consumes, the opposite of\n// every group above. The TYPE still flows through this same alias so the\n// SDK and nexus never describe two different shapes for it; the real Zod\n// validation stays in base-api only — this package never gains a Zod\n// runtime dependency.\nexport type {\n SiteManifest,\n SiteManifestSurfaceValue,\n SiteCapabilitySurfaceKey,\n} from '@reblu/base-api-contracts'\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reblu/site-contracts",
3
- "version": "1.22.0",
3
+ "version": "1.24.0",
4
4
  "private": false,
5
5
  "description": "Public, dependency-free TypeScript types for the Reblu SITE API (no Zod, no Prisma at runtime; one runtime value: DATA_REQUEST_TYPES).",
6
6
  "license": "Apache-2.0",