@reblu/site-contracts 1.16.0 → 1.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @reblu/site-contracts
2
2
 
3
+ ## 1.18.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 7a6f8c1: Lead origin (REB-1078). New types `LeadTouch` and `LeadAttribution`, and `ContactFormInput.metadata.attribution?: LeadAttribution`: the RAW inputs of the visit that brought the visitor (`utm` params, click-id NAMES such as `gclid`/`fbclid`, `referrer`, `landingPath`, `at`), as `{ first?, last? }`. base-api classifies the channel (campaign, search, social, referral, direct, email) — a channel sent by the SITE is ignored — and a malformed value is dropped, never a 400. `LeadInput.metadata` reserves the same `attribution` key on `/api/site/leads`: this narrows the previously opaque `metadata` record, so a SITE that already used its own `metadata.attribution` must rename it — base-api classifies that key and no longer stores it raw in `metadata`. `ContactFormInput.metadata.leadSource` is now optional and deprecated: a body without `attribution` still works as before, but the old `'organic'` default is no longer stored as the lead's source.
8
+
9
+ ## 1.17.0
10
+
11
+ ### Minor Changes
12
+
13
+ - af425de: REB-1005: export `DATA_REQUEST_TYPES`, the list of GDPR rights in base-api's order — the package's first (and only) runtime value, so server code can use it without importing a `'use client'` entry. A compile-time check and a unit test tie it to base-api's `dataRequestTypeSchema`. Also documents the data-request types with a README snippet (REB-1003).
14
+
3
15
  ## 1.16.0
4
16
 
5
17
  ### Minor Changes
package/README.md CHANGED
@@ -5,8 +5,8 @@ Public, dependency-free TypeScript types for the **Reblu SITE API** (`/api/site/
5
5
  These are the SDK-facing types for every SITE API response. They are the single
6
6
  source of truth a Reblu-powered site uses to type the data it fetches — with
7
7
  **zero runtime dependencies**: no Zod, no Prisma, nothing in your `node_modules`
8
- graph. The package ships only flattened `.d.ts` declarations plus an empty
9
- ESM/CJS runtime stub so bare `import`/`require` resolve cleanly.
8
+ graph. The package ships flattened `.d.ts` declarations plus a tiny ESM/CJS
9
+ runtime carrying exactly one value, `DATA_REQUEST_TYPES` (below).
10
10
 
11
11
  ## Install
12
12
 
@@ -201,6 +201,41 @@ They are served raw (`null` = never set). `buildMetadata({ config, home: true })
201
201
  from `@reblu/site-next/seo` applies the fallbacks for you. All three are
202
202
  optional in the types so the minor stays additive.
203
203
 
204
+ ### GDPR data-subject requests (REB-980 / REB-1005)
205
+
206
+ `DataRequestInput` is the body of `POST /api/site/data-requests` (a SITE's
207
+ public rights form); `DataRequestSubmission` is its acknowledgement with the
208
+ 72h deadline. `DATA_REQUEST_TYPES` is the list of rights, in base-api's order —
209
+ the package's one runtime value, so server code (a Route Handler, a sitemap)
210
+ can use it without a `'use client'` import. Import it as a regular
211
+ `dependency` (not `--save-dev`) when you use the value:
212
+
213
+ ```ts
214
+ import {
215
+ DATA_REQUEST_TYPES,
216
+ type DataRequestInput,
217
+ type DataRequestSubmission,
218
+ type DataRequestType,
219
+ } from '@reblu/site-contracts'
220
+
221
+ // ['ACCESS', 'RECTIFICATION', 'ERASURE', 'OBJECTION', 'PORTABILITY',
222
+ // 'RESTRICTION', 'AUTOMATED_DECISION', 'INFORMATION']
223
+ const isRight = (value: string): value is DataRequestType =>
224
+ (DATA_REQUEST_TYPES as readonly string[]).includes(value)
225
+
226
+ const body: DataRequestInput = {
227
+ requestType: 'ACCESS',
228
+ email: 'ada@example.com', // ≤ 320
229
+ name: 'Ada', // optional, ≤ 200
230
+ details: '…', // optional, ≤ 5000
231
+ captcha: token, // reCAPTCHA v3 — required
232
+ }
233
+ const deadline = (ack: DataRequestSubmission) => ack.slaDueAt
234
+ ```
235
+
236
+ The list is base-api's `dataRequestTypeSchema`: a compile-time check and a unit
237
+ test fail the build if the two ever disagree.
238
+
204
239
  ## How the types stay correct
205
240
 
206
241
  The types are re-derived from the response schemas that live in the Reblu API
package/dist/index.cjs CHANGED
@@ -1,4 +1,17 @@
1
1
  'use strict';
2
2
 
3
+ // src/index.ts
4
+ var DATA_REQUEST_TYPES = Object.freeze([
5
+ "ACCESS",
6
+ "RECTIFICATION",
7
+ "ERASURE",
8
+ "OBJECTION",
9
+ "PORTABILITY",
10
+ "RESTRICTION",
11
+ "AUTOMATED_DECISION",
12
+ "INFORMATION"
13
+ ]);
14
+
15
+ exports.DATA_REQUEST_TYPES = DATA_REQUEST_TYPES;
3
16
  //# sourceMappingURL=index.cjs.map
4
17
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"index.cjs"}
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.\nexport type {\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 // 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 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} 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"]}
package/dist/index.d.cts CHANGED
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * GENERATED by scripts/generate-dts.ts — DO NOT EDIT.
3
3
  * Flattened structural types for the Reblu SITE API (REB-414).
4
- * Source of truth: apps/base-api/src/lib/contracts/*.contract.ts.
4
+ * Source of truth: apps/base-api/src/lib/contracts/*.contract.ts (types)
5
+ * and src/index.ts (runtime consts such as DATA_REQUEST_TYPES).
5
6
  */
6
7
  export type AcademyCategoryPublic = { id: string; name: string; slug: string; sortOrder: number;}
7
8
 
@@ -63,7 +64,7 @@ export type ConfigSocial = { linkedin: string | null; twitter: string | nu
63
64
 
64
65
  export type ConfigTaxIdKind = "NIF" | "CIF"
65
66
 
66
- export type ContactFormInput = { name: string; email: string; phone: string; message: string; agreement: boolean; captcha: string; metadata: { fromPage: string; timestamp: string; currentUrl: string; leadSource: { platform: string; }; }; surname?: string | undefined; businessName?: string | undefined;}
67
+ export type ContactFormInput = { name: string; email: string; phone: string; message: string; agreement: boolean; captcha: string; metadata: { fromPage: string; timestamp: string; currentUrl: string; leadSource?: { platform: string; } | undefined; attribution?: { first?: { utm?: { source?: string | undefined; medium?: string | undefined; campaign?: string | undefined; content?: string | undefined; term?: string | undefined; } | undefined; clickIds?: string[] | undefined; referrer?: string | undefined; landingPath?: string | undefined; at?: string | undefined; } | undefined; last?: { utm?: { source?: string | undefined; medium?: string | undefined; campaign?: string | undefined; content?: string | undefined; term?: string | undefined; } | undefined; clickIds?: string[] | undefined; referrer?: string | undefined; landingPath?: string | undefined; at?: string | undefined; } | undefined; } | undefined; }; surname?: string | undefined; businessName?: string | undefined;}
67
68
 
68
69
  export type ContactFormMode = "NOT_CONFIGURED" | "DISABLED" | "DB_ONLY" | "WEBHOOK" | "RESEND"
69
70
 
@@ -89,10 +90,14 @@ export type DataRequestType = "ACCESS" | "RECTIFICATION" | "ERASURE" | "OBJECTIO
89
90
 
90
91
  export type EmbedReferenceData = { pageSlug: string; pageId?: string | undefined; categorySlug?: string | null | undefined;}
91
92
 
92
- export type LeadInput = { name: string; email?: string | undefined; phone?: string | undefined; businessName?: string | undefined; message?: string | undefined; source?: string | undefined; metadata?: Record<string, unknown> | undefined;}
93
+ export type LeadAttribution = { first?: { utm?: { source?: string | undefined; medium?: string | undefined; campaign?: string | undefined; content?: string | undefined; term?: string | undefined; } | undefined; clickIds?: string[] | undefined; referrer?: string | undefined; landingPath?: string | undefined; at?: string | undefined; } | undefined; last?: { utm?: { source?: string | undefined; medium?: string | undefined; campaign?: string | undefined; content?: string | undefined; term?: string | undefined; } | undefined; clickIds?: string[] | undefined; referrer?: string | undefined; landingPath?: string | undefined; at?: string | undefined; } | undefined;}
94
+
95
+ export type LeadInput = { name: string; email?: string | undefined; phone?: string | undefined; businessName?: string | undefined; message?: string | undefined; source?: string | undefined; metadata?: { [x: string]: unknown; attribution?: { first?: { utm?: { source?: string | undefined; medium?: string | undefined; campaign?: string | undefined; content?: string | undefined; term?: string | undefined; } | undefined; clickIds?: string[] | undefined; referrer?: string | undefined; landingPath?: string | undefined; at?: string | undefined; } | undefined; last?: { utm?: { source?: string | undefined; medium?: string | undefined; campaign?: string | undefined; content?: string | undefined; term?: string | undefined; } | undefined; clickIds?: string[] | undefined; referrer?: string | undefined; landingPath?: string | undefined; at?: string | undefined; } | undefined; } | undefined; } | undefined;}
93
96
 
94
97
  export type LeadSubmission = { id: string; createdAt: string;}
95
98
 
99
+ export type LeadTouch = { utm?: { source?: string | undefined; medium?: string | undefined; campaign?: string | undefined; content?: string | undefined; term?: string | undefined; } | undefined; clickIds?: string[] | undefined; referrer?: string | undefined; landingPath?: string | undefined; at?: string | undefined;}
100
+
96
101
  export type LegacyPageType = "SERVICE" | "CUSTOM"
97
102
 
98
103
  export type Legal = { privacyPolicy: string | null; termsAndConditions: string | null; cookiePolicy: string | null;}
@@ -242,3 +247,16 @@ export type TaxType = "IVA" | "IGIC" | "RETENTION" | "OTHER"
242
247
  export type TrustBadge = { id: string; name: string; logoUrl: string | null; url: string | null; type: "PARTNER" | "INSURANCE" | "SUBVENTION" | "CERTIFICATION" | "AWARD"; sortOrder: number;}
243
248
 
244
249
  export type TrustBadgeType = "PARTNER" | "INSURANCE" | "SUBVENTION" | "CERTIFICATION" | "AWARD"
250
+
251
+ /**
252
+ * REB-1005 — every GDPR right a data subject can exercise, in base-api's order.
253
+ * The ONE runtime value this package ships: server code (a SITE's Route
254
+ * Handler, `@reblu/site-next`'s `createDataRequestRoute`) needs the list too,
255
+ * and `@reblu/site-blocks` re-exports it as before.
256
+ *
257
+ * Single source: base-api's `dataRequestTypeSchema`. `satisfies` rejects a
258
+ * member base-api does not know, `MissingDataRequestType` below rejects one it
259
+ * knows and this list lacks, and `tests/unit/data-request-types.test.ts` pins
260
+ * the order. Plain array literal, no import — the runtime stays dependency-free.
261
+ */
262
+ export declare const DATA_REQUEST_TYPES: readonly ["ACCESS", "RECTIFICATION", "ERASURE", "OBJECTION", "PORTABILITY", "RESTRICTION", "AUTOMATED_DECISION", "INFORMATION"]
package/dist/index.d.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * GENERATED by scripts/generate-dts.ts — DO NOT EDIT.
3
3
  * Flattened structural types for the Reblu SITE API (REB-414).
4
- * Source of truth: apps/base-api/src/lib/contracts/*.contract.ts.
4
+ * Source of truth: apps/base-api/src/lib/contracts/*.contract.ts (types)
5
+ * and src/index.ts (runtime consts such as DATA_REQUEST_TYPES).
5
6
  */
6
7
  export type AcademyCategoryPublic = { id: string; name: string; slug: string; sortOrder: number;}
7
8
 
@@ -63,7 +64,7 @@ export type ConfigSocial = { linkedin: string | null; twitter: string | nu
63
64
 
64
65
  export type ConfigTaxIdKind = "NIF" | "CIF"
65
66
 
66
- export type ContactFormInput = { name: string; email: string; phone: string; message: string; agreement: boolean; captcha: string; metadata: { fromPage: string; timestamp: string; currentUrl: string; leadSource: { platform: string; }; }; surname?: string | undefined; businessName?: string | undefined;}
67
+ export type ContactFormInput = { name: string; email: string; phone: string; message: string; agreement: boolean; captcha: string; metadata: { fromPage: string; timestamp: string; currentUrl: string; leadSource?: { platform: string; } | undefined; attribution?: { first?: { utm?: { source?: string | undefined; medium?: string | undefined; campaign?: string | undefined; content?: string | undefined; term?: string | undefined; } | undefined; clickIds?: string[] | undefined; referrer?: string | undefined; landingPath?: string | undefined; at?: string | undefined; } | undefined; last?: { utm?: { source?: string | undefined; medium?: string | undefined; campaign?: string | undefined; content?: string | undefined; term?: string | undefined; } | undefined; clickIds?: string[] | undefined; referrer?: string | undefined; landingPath?: string | undefined; at?: string | undefined; } | undefined; } | undefined; }; surname?: string | undefined; businessName?: string | undefined;}
67
68
 
68
69
  export type ContactFormMode = "NOT_CONFIGURED" | "DISABLED" | "DB_ONLY" | "WEBHOOK" | "RESEND"
69
70
 
@@ -89,10 +90,14 @@ export type DataRequestType = "ACCESS" | "RECTIFICATION" | "ERASURE" | "OBJECTIO
89
90
 
90
91
  export type EmbedReferenceData = { pageSlug: string; pageId?: string | undefined; categorySlug?: string | null | undefined;}
91
92
 
92
- export type LeadInput = { name: string; email?: string | undefined; phone?: string | undefined; businessName?: string | undefined; message?: string | undefined; source?: string | undefined; metadata?: Record<string, unknown> | undefined;}
93
+ export type LeadAttribution = { first?: { utm?: { source?: string | undefined; medium?: string | undefined; campaign?: string | undefined; content?: string | undefined; term?: string | undefined; } | undefined; clickIds?: string[] | undefined; referrer?: string | undefined; landingPath?: string | undefined; at?: string | undefined; } | undefined; last?: { utm?: { source?: string | undefined; medium?: string | undefined; campaign?: string | undefined; content?: string | undefined; term?: string | undefined; } | undefined; clickIds?: string[] | undefined; referrer?: string | undefined; landingPath?: string | undefined; at?: string | undefined; } | undefined;}
94
+
95
+ export type LeadInput = { name: string; email?: string | undefined; phone?: string | undefined; businessName?: string | undefined; message?: string | undefined; source?: string | undefined; metadata?: { [x: string]: unknown; attribution?: { first?: { utm?: { source?: string | undefined; medium?: string | undefined; campaign?: string | undefined; content?: string | undefined; term?: string | undefined; } | undefined; clickIds?: string[] | undefined; referrer?: string | undefined; landingPath?: string | undefined; at?: string | undefined; } | undefined; last?: { utm?: { source?: string | undefined; medium?: string | undefined; campaign?: string | undefined; content?: string | undefined; term?: string | undefined; } | undefined; clickIds?: string[] | undefined; referrer?: string | undefined; landingPath?: string | undefined; at?: string | undefined; } | undefined; } | undefined; } | undefined;}
93
96
 
94
97
  export type LeadSubmission = { id: string; createdAt: string;}
95
98
 
99
+ export type LeadTouch = { utm?: { source?: string | undefined; medium?: string | undefined; campaign?: string | undefined; content?: string | undefined; term?: string | undefined; } | undefined; clickIds?: string[] | undefined; referrer?: string | undefined; landingPath?: string | undefined; at?: string | undefined;}
100
+
96
101
  export type LegacyPageType = "SERVICE" | "CUSTOM"
97
102
 
98
103
  export type Legal = { privacyPolicy: string | null; termsAndConditions: string | null; cookiePolicy: string | null;}
@@ -242,3 +247,16 @@ export type TaxType = "IVA" | "IGIC" | "RETENTION" | "OTHER"
242
247
  export type TrustBadge = { id: string; name: string; logoUrl: string | null; url: string | null; type: "PARTNER" | "INSURANCE" | "SUBVENTION" | "CERTIFICATION" | "AWARD"; sortOrder: number;}
243
248
 
244
249
  export type TrustBadgeType = "PARTNER" | "INSURANCE" | "SUBVENTION" | "CERTIFICATION" | "AWARD"
250
+
251
+ /**
252
+ * REB-1005 — every GDPR right a data subject can exercise, in base-api's order.
253
+ * The ONE runtime value this package ships: server code (a SITE's Route
254
+ * Handler, `@reblu/site-next`'s `createDataRequestRoute`) needs the list too,
255
+ * and `@reblu/site-blocks` re-exports it as before.
256
+ *
257
+ * Single source: base-api's `dataRequestTypeSchema`. `satisfies` rejects a
258
+ * member base-api does not know, `MissingDataRequestType` below rejects one it
259
+ * knows and this list lacks, and `tests/unit/data-request-types.test.ts` pins
260
+ * the order. Plain array literal, no import — the runtime stays dependency-free.
261
+ */
262
+ export declare const DATA_REQUEST_TYPES: readonly ["ACCESS", "RECTIFICATION", "ERASURE", "OBJECTION", "PORTABILITY", "RESTRICTION", "AUTOMATED_DECISION", "INFORMATION"]
package/dist/index.js CHANGED
@@ -1,3 +1,15 @@
1
+ // src/index.ts
2
+ var DATA_REQUEST_TYPES = Object.freeze([
3
+ "ACCESS",
4
+ "RECTIFICATION",
5
+ "ERASURE",
6
+ "OBJECTION",
7
+ "PORTABILITY",
8
+ "RESTRICTION",
9
+ "AUTOMATED_DECISION",
10
+ "INFORMATION"
11
+ ]);
1
12
 
13
+ export { DATA_REQUEST_TYPES };
2
14
  //# sourceMappingURL=index.js.map
3
15
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
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.\nexport type {\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 // 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 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} 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"]}
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@reblu/site-contracts",
3
- "version": "1.16.0",
3
+ "version": "1.18.0",
4
4
  "private": false,
5
- "description": "Public, dependency-free TypeScript types for the Reblu SITE API (types only — no Zod, no Prisma at runtime).",
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",
7
7
  "author": "Reblu — Adolfo Unturbe",
8
8
  "homepage": "https://reblu.app",