@verisure-italy/lp-types
v2.3.2
Published
Types for Landing Page service
Readme
@verisure-italy/lp-types
Domain contracts for landing pages, widgets, presets, SEO metadata, and build manifests.
Installation
pnpm add @verisure-italy/lp-typesMain Exports
- raw catalogs such as
themeNames,layoutVariants,pageStatuses,buildStatuses,deploymentProviders,widgetTypes, andtextFormats - enums for themes, layout variants, page status, build status, deployment provider, widget type, and text format
- shared widget primitives such as
mediaImageRefSchemaandresponsiveMediaImageRefSchema widgetSchemaand the individual widget-property schemaspageSchema,pageWidgetConfigSchema,landingPageFunnelPathDataSchema,landingPageDataSchemabuildSchema,buildManifestSchema, andglobalManifestSchema
What This Package Gives You
- an authoring model for landing pages and widget presets
- a runtime-safe discriminated union for widget rendering
- build and deployment metadata for page publishing flows
- reusable text, media-image reference, and navigation primitives for page composition
Schema Inventory
| Schema | Type alias | Kind | Purpose |
| --------------------------------------- | --------------------------------- | ---------------------- | ------------------------------------------ |
| mediaImageRefSchema | MediaImageRef | object schema | Strong media-library image reference |
| responsiveMediaImageRefSchema | ResponsiveMediaImageRef | object schema | Desktop/mobile media image reference |
| mediaVariantPresetSchema | MediaVariantPreset | enum | Media-library variant preset |
| mediaImageLoadingSchema | MediaImageLoading | enum | Image loading hint |
| themeNameSchema | ThemeName | enum | Page theme |
| layoutVariantSchema | LayoutVariant | enum | Layout variant |
| pageStatusSchema | PageStatus | enum | Publication status |
| buildStatusSchema | BuildStatus | enum | Build status |
| seoMetadataSchema | SeoMetadata | object schema | SEO metadata |
| deploymentProviderSchema | DeploymentProvider | enum | Deployment provider |
| widgetAlignmentSchema | WidgetAlignment | enum | Widget alignment values |
| widgetIconTokenSchema | WidgetIconToken | string schema | Namespaced icon token (provider:name) |
| widgetIconSchema | n/a | nullable string schema | Nullable namespaced icon token |
| widgetTypeSchema | WidgetType | enum | Widget discriminator |
| widgetContentBoxSubTypeSchema | WidgetContentBoxSubType | enum | Content-box variants |
| widgetContentListSubTypeSchema | WidgetContentListSubType | enum | Content-list variants |
| widgetStaticContentSubTypeSchema | WidgetStaticContentSubType | enum | StaticContent variants |
| widgetCostsItemVisibilitySchema | WidgetCostsItemVisibility | enum | Costs-item visibility |
| textFormatSchema | TextFormat | enum | Text formatting mode |
| textContentSchema | TextContent | union | Rich text primitive |
| widgetAnchorIdSchema | WidgetAnchorId | string schema | DOM anchor id without # |
| pageFunnelPathIdSchema | PageFunnelPathId | UUID schema | Funnel path id linked to a page |
| widgetHeroSchema | WidgetHero | object schema | Hero widget |
| widgetProductSliderSchema | WidgetProductSlider | object schema | Product-slider widget |
| widgetCostsSchema | WidgetCosts | object schema | Costs widget |
| widgetContentBoxSchema | WidgetContentBox | object schema | Content-box widget |
| widgetTrustpilotSchema | WidgetTrustpilot | object schema | Trustpilot widget |
| widgetFAQSchema | WidgetFAQ | object schema | FAQ widget |
| widgetStatsSchema | WidgetStats | object schema | Stats widget |
| widgetContentListSchema | WidgetContentList | object schema | Content-list widget |
| widgetStaticContentSchema | WidgetStaticContent | object schema | StaticContent widget |
| widgetFunnelSwitcherSchema | WidgetFunnelSwitcher | object schema | Funnel-switcher widget |
| widgetPropertyTypeSchema | WidgetPropertyType | object schema | Property-type widget |
| widgetAlarmTypeComparisonSchema | WidgetAlarmTypeComparison | object schema | Alarm-comparison widget |
| widgetHeaderMenuLinkSchema | WidgetHeaderMenuLink | discriminated union | Header menu links |
| widgetHeaderSchema | WidgetHeader | object schema | Header widget |
| widgetFooterMenuItemSchema | WidgetFooterMenuItem | object schema | Footer menu item |
| widgetFooterMenuSectionSchema | WidgetFooterMenuSection | object schema | Footer menu section |
| widgetFooterSchema | WidgetFooter | object schema | Footer widget |
| widgetSchema | Widget | discriminated union | Full widget union |
| widgetPresetSchema | WidgetPreset | object schema | Stored widget preset |
| pageWidgetConfigSchema | PageWidgetConfig | discriminated union | Stored page widget config |
| pageSchema | Page | object schema | Persisted page |
| buildManifestPageSchema | BuildManifestPage | object schema | Compact page in build artifacts |
| buildManifestSchema | BuildManifest | object schema | Build manifest |
| globalManifestSchema | GlobalManifest | object schema | Current, previous, and pending manifests |
| landingPageFunnelSummarySchema | LandingPageFunnelSummary | object schema | Static funnel summary in page payloads |
| landingPageFunnelPathDataSchema | LandingPageFunnelPathData | object schema | Static funnel path data in page payloads |
| resolvedLandingPageWidgetConfigSchema | ResolvedLandingPageWidgetConfig | discriminated union | Widget config with resolved widget payload |
| landingPageDataSchema | LandingPageData | object schema | Frontend-ready page payload |
| buildSchema | Build | object schema | Build execution record |
Enum Reference
| Schema | Values |
| ---------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| themeNameSchema | standard, dark |
| layoutVariantSchema | default, marketing |
| pageStatusSchema | draft, published, needs_republish |
| buildStatusSchema | pending, building, completed, failed |
| deploymentProviderSchema | amplify, apprunner, ecs |
| mediaVariantPresetSchema | thumbnail, small, medium, large, xlarge, og, email, funnel-hero-desktop, funnel-hero-mobile, funnel-property-desktop, funnel-property-mobile, funnel-costs-desktop, funnel-costs-mobile, funnel-content-vertical, funnel-content-landscape, funnel-static-card, funnel-static-square, funnel-product-slider, funnel-comparison-image, funnel-key-strengths-image, funnel-switcher-image, funnel-header-promo |
| mediaImageLoadingSchema | lazy, eager |
| widgetAlignmentSchema | left, center, right |
| widgetIconTokenSchema | string matching ^[a-z0-9][a-z0-9-]*:[a-z0-9][a-z0-9-]*$ |
| widgetTypeSchema | hero, productSlider, costs, contentBox, trustpilot, faq, stats, contentList, staticContent, funnelSwitcher, propertyType, alarmTypeComparison, header, footer |
| widgetContentBoxSubTypeSchema | zerovision, videoSurveillance |
| widgetContentListSubTypeSchema | keyStrengths, howItWorks |
| widgetStaticContentSubTypeSchema | fingerSwipe, columnContent |
| widgetCostsItemVisibilitySchema | desktop, mobile |
| textFormatSchema | plain, markdown |
Primitive Schema Reference
Image Contract (Breaking)
LP widget payloads store only strong references to assets in sls-media-library.
They do not store final URLs, derived dimensions, or output formats. Consumers such as
sls-lp, graceful-hub, and funnel-app resolve mediaId + preset through
sls-media-library and decide URL, width, height, and format at render time.
Legacy image payloads like { src, alt, width, height, lazy } are no longer valid.
mediaImageRefSchema
| Field | Type | Required | Notes |
| ---------- | -------------------- | -------- | ------------------------------------------ |
| mediaId | string | Yes | Media-library asset id |
| preset | MediaVariantPreset | Yes | Media-library variant preset |
| alt | string | No | Contextual/editorial alt override |
| loading | 'lazy' \| 'eager' | No | Render-position loading hint |
| priority | boolean | No | Render-position priority hint |
responsiveMediaImageRefSchema
| Field | Type | Required | Notes |
| ---------- | ---------------------------- | -------- | --------------------------------- |
| desktop | MediaImageRef | Yes | Desktop media reference |
| mobile | MediaImageRef \| null | No | Optional mobile media reference |
| alt | string | No | Responsive-level alt override |
| loading | 'lazy' \| 'eager' | No | Responsive-level loading hint |
| priority | boolean | No | Responsive-level priority hint |
widgetIconTokenSchema and widgetIconSchema
| Rule | Value |
| ----------------------- | ----------------------------------------- |
| Token format | provider:name |
| Regex | ^[a-z0-9][a-z0-9-]*:[a-z0-9][a-z0-9-]*$ |
| widgetIconTokenSchema | Required namespaced token |
| widgetIconSchema | Same token, but nullable |
Valid examples:
mui:homemui:shield-outlinedfa:housecustom:my-icon
Invalid examples:
homekeymui:homemui:MUI:home
widgetAnchorIdSchema
| Rule | Value |
| ---------- | -------------------------------------------------------------- |
| Type | string |
| Required | Yes |
| Validation | Must match ^[a-z0-9-]+$ and does not include the leading # |
pageFunnelPathIdSchema
| Rule | Value |
| ---------- | -------------- |
| Type | string |
| Required | Yes |
| Validation | Must be a UUID |
textContentSchema
| Variant | Shape | Notes |
| ------------------ | --------------------------------------- | ------------------------- |
| Plain string | string | Must be non-empty |
| Structured content | { value: string; format: TextFormat } | value must be non-empty |
seoMetadataSchema
| Field | Type | Required | Notes |
| -------------------- | ---------- | -------- | ----------------- |
| title | string | Yes | Min 1, max 60 |
| description | string | Yes | Min 1, max 160 |
| keywords | string[] | Yes | Keyword list |
| canonicalUrl | string | No | Valid URL |
| ogImage | string | No | Valid URL |
| ogTitle | string | No | Optional override |
| ogDescription | string | No | Optional override |
| robots | string | No | Robots directive |
| languageAlternates | array | No | { lang, url }[] |
Page and Build Schemas
widgetPresetSchema
| Field | Type | Required | Notes |
| ----------- | ---------- | -------- | ---------------- |
| id | string | Yes | Preset id |
| name | string | Yes | Preset name |
| tags | string[] | Yes | Tag list |
| widget | Widget | Yes | Widget payload |
| createdAt | number | Yes | Shared timestamp |
| updatedAt | number | Yes | Shared timestamp |
pageWidgetConfigSchema
Common fields:
| Field | Type | Required | Notes |
| ------------ | ---------------------- | -------- | ------------------------- |
| id | string | Yes | Config id |
| pageId | string | Yes | Page id |
| configType | 'preset' \| 'custom' | Yes | Variant discriminator |
| order | number | Yes | Non-negative integer |
| anchorId | string \| null | No | Optional widget anchor id |
| createdAt | number | Yes | Shared timestamp |
| updatedAt | number | Yes | Shared timestamp |
Variant-specific fields:
| Variant | Additional fields |
| -------- | ------------------ |
| preset | presetId: string |
| custom | widget: Widget |
pageSchema
| Field | Type | Required | Notes |
| ----------------- | -------------------- | ------------ | -------------------------- |
| id | string | Yes | Page id |
| slug | string | Yes | Must match ^[a-z0-9-]+$ |
| name | string | Yes | Non-empty |
| description | string | No | Optional |
| funnelPathId | string | Yes | Required Funnel Path UUID |
| widgets | PageWidgetConfig[] | Yes | Widget config list |
| theme | ThemeName | Yes | Theme enum |
| layoutVariant | LayoutVariant | No (default) | Defaults to default |
| seo | SeoMetadata | Yes | SEO metadata |
| status | PageStatus | Yes | Publication state |
| requiresRebuild | boolean | Yes | Build flag |
| version | number | Yes | Positive integer |
| publishedAt | number | No | Optional publish timestamp |
| createdAt | number | Yes | Shared timestamp |
| updatedAt | number | Yes | Shared timestamp |
buildManifestPageSchema
| Field | Type | Required | Notes |
| --------------- | --------------- | ------------ | --------------------- |
| id | string | Yes | Page id |
| slug | string | Yes | Page slug |
| name | string | Yes | Page name |
| theme | ThemeName | Yes | Page theme |
| layoutVariant | LayoutVariant | No (default) | Defaults to default |
buildManifestSchema
| Field | Type | Required | Notes |
| ------------ | --------------------- | -------- | -------------------- |
| buildId | string | Yes | Build id |
| createdAt | string | Yes | ISO timestamp |
| pagesCount | number | Yes | Non-negative integer |
| pages | BuildManifestPage[] | Yes | Included pages |
globalManifestSchema
| Field | Type | Required | Notes |
| ---------- | ----------------------- | -------------- | ------------------------- |
| current | BuildManifest \| null | Yes (nullable) | Current deployment |
| previous | BuildManifest \| null | Yes (nullable) | Previous deployment |
| new | BuildManifest \| null | Yes (nullable) | Pending or new deployment |
resolvedLandingPageWidgetConfigSchema
Same base fields as pageWidgetConfigSchema, but both variants include a widget payload:
| Variant | Additional fields |
| -------- | -------------------- |
| preset | presetId, widget |
| custom | widget |
landingPageDataSchema
landingPageDataSchema is pageSchema with widgets replaced by ResolvedLandingPageWidgetConfig[] and a required static funnelPath payload for frontend rendering.
landingPageFunnelPathDataSchema
| Field | Type | Required | Notes |
| ---------------------- | ---------------- | -------------- | ----------------------------------------- |
| path | string | Yes | Must match ^[a-z0-9-]+$ |
| titleHeader | string \| null | Yes (nullable) | Optional header title from Funnel Path |
| titleSubHeader | string \| null | Yes (nullable) | Optional header subtitle from Funnel Path |
| titleIntroduction | string | Yes | Introduction title |
| subTitleIntroduction | string | Yes | Introduction subtitle |
| funnels | array | Yes | Static funnel list, at least one item |
Each funnels item contains title, slug, and type.
buildSchema
| Field | Type | Required | Notes |
| -------------------- | ---------------------------- | -------------- | --------------------- |
| id | string | Yes | Build id |
| status | BuildStatus | Yes | Build state |
| deploymentProvider | DeploymentProvider \| null | No | Deployment backend |
| deploymentId | string \| null | No | Provider-specific id |
| deploymentRef | string \| null | No | Provider-specific ref |
| deploymentTarget | string \| null | No | Deployment target |
| deploymentStatus | string \| null | No | Provider status |
| amplifyBuildId | string \| null | No | Deprecated field |
| amplifyJobUrl | string \| null | No | Deprecated field |
| startedAt | number \| null | Yes (nullable) | Start timestamp |
| completedAt | number \| null | No | Completion timestamp |
| duration | number \| null | No | Duration |
| pagesCount | number \| null | Yes (nullable) | Number of pages |
| pageIds | string[] | Yes | Included page ids |
| error | string \| null | No | Error message |
| s3BucketPath | string \| null | Yes (nullable) | Artifact path |
| createdAt | number | Yes | Shared timestamp |
| updatedAt | number | Yes | Shared timestamp |
Widget Schemas
widgetSchema
Each widget is exported through widgetSchema with a type discriminator and a properties object.
| type value | properties schema |
| --------------------- | --------------------------------- |
| hero | widgetHeroSchema |
| productSlider | widgetProductSliderSchema |
| costs | widgetCostsSchema |
| contentBox | widgetContentBoxSchema |
| trustpilot | widgetTrustpilotSchema |
| faq | widgetFAQSchema |
| stats | widgetStatsSchema |
| contentList | widgetContentListSchema |
| staticContent | widgetStaticContentSchema |
| funnelSwitcher | widgetFunnelSwitcherSchema |
| propertyType | widgetPropertyTypeSchema |
| alarmTypeComparison | widgetAlarmTypeComparisonSchema |
| header | widgetHeaderSchema |
| footer | widgetFooterSchema |
widgetHeroSchema
| Field | Type | Required | Notes |
| ---------------- | ---------------------- | -------- | ------------------------------------------------ |
| title | TextContent | Yes | String or { value, format } |
| subtitle | TextContent \| null | No | Optional |
| body | TextContent \| null | No | Optional |
| primaryOffer | TextContent \| null | No | Optional |
| secondaryOffer | TextContent \| null | No | Optional |
| cta | object or null | No | Contains label; legacy funnelPath and funnelSlug are optional/deprecated |
| media | ResponsiveMediaImageRef[] | Yes | At least one responsive image reference |
widgetProductSliderSchema
| Field | Type | Required | Notes |
| ------------- | --------------------- | -------------- | -------------------------------------------------------------- |
| title | TextContent | Yes | Title |
| description | TextContent \| null | Yes (nullable) | Description block |
| items | array | Yes | Each item contains image: MediaImageRef, title, description, featured |
widgetCostsSchema
| Field | Type | Required | Notes |
| ------------- | --------------------- | -------------- | --------------------------------------------------------------------------------------------- |
| title | TextContent | Yes | Title |
| subtitle | TextContent \| null | Yes (nullable) | Subtitle |
| description | TextContent \| null | Yes (nullable) | Description |
| items | array | Yes | Each item contains title, description, icon (provider:name or null), visibility[] |
widgetContentBoxSchema
| Field | Type | Required | Notes |
| ------------- | --------------------- | -------------- | ----------------------------------------------------- |
| subType | enum | Yes | zerovision or videoSurveillance |
| title | TextContent | Yes | Title |
| description | TextContent \| null | Yes (nullable) | Description |
| box | object | Yes | Contains title, description, image: ResponsiveMediaImageRef \| null, alignment |
widgetTrustpilotSchema
| Field | Type | Required | Notes |
| ----------------------- | --------------------- | -------------- | ----------- |
| title | TextContent | Yes | Title |
| description | TextContent \| null | Yes (nullable) | Description |
| config.businessUnitId | string | Yes | Non-empty |
| config.templateId | string | Yes | Non-empty |
| config.styleHeight | string | Yes | Non-empty |
| config.styleWidth | string | Yes | Non-empty |
| config.locale | string | Yes | Non-empty |
widgetFAQSchema
| Field | Type | Required | Notes |
| ------------- | --------------------- | -------------- | ------------------------------------------ |
| title | TextContent | Yes | Title |
| description | TextContent \| null | Yes (nullable) | Description |
| items | array | Yes | Each item contains question and answer |
widgetStatsSchema
| Field | Type | Required | Notes |
| ------- | ----- | -------- | ------------------------------------------------------------------------------------ |
| items | array | Yes | Each item contains label, value, and optional icon (provider:name or null) |
widgetContentListSchema
| Field | Type | Required | Notes |
| ------------- | --------------------- | -------------- | --------------------------------------------------------------- |
| subType | enum | Yes | keyStrengths or howItWorks |
| title | TextContent | Yes | Title |
| description | TextContent \| null | Yes (nullable) | Description |
| items | array | Yes | Each item contains title, description, and image: ResponsiveMediaImageRef \| null |
widgetStaticContentSchema
StaticContent widgets are declarative selectors for frontend-rendered static blocks. They carry no HTML and no dynamic content.
| Field | Type | Required | Notes |
| --------- | ---- | -------- | -------------------------------- |
| subType | enum | Yes | fingerSwipe or columnContent |
widgetFunnelSwitcherSchema
| Field | Type | Required | Notes |
| ------------- | --------------------- | -------------- | ------------------------------------------- |
| title | TextContent | Yes | Title |
| subtitle | TextContent \| null | Yes (nullable) | Subtitle |
| description | TextContent \| null | Yes (nullable) | Description |
Funnel-switcher cards are derived by consumers from page-level funnelPath.funnels.
Each card should link to /allarme/<funnelPath.path>/<funnel.slug> and use
funnel.type for frontend asset selection. Legacy items are optional/deprecated.
widgetPropertyTypeSchema
| Field | Type | Required | Notes |
| ------------- | --------------------- | -------------- | -------------------------------------------------------- |
| title | TextContent | Yes | Title |
| description | TextContent \| null | Yes (nullable) | Description |
| tabs | array | Yes | Each tab contains title, description, image: ResponsiveMediaImageRef \| null, and cta.label; legacy cta.link is optional/deprecated |
widgetAlarmTypeComparisonSchema
| Field | Type | Required | Notes |
| ------------- | --------------------- | -------------- | ------------------------------------------------------------------------------------- |
| title | TextContent | Yes | Title |
| description | TextContent \| null | Yes (nullable) | Description |
| tabs | array | Yes | Each tab contains title, description, image: MediaImageRef \| null, icon (provider:name or null) |
| box | object | Yes | Contains title, description, icon (provider:name or null) |
Icon Migration Notes (Breaking)
Legacy non-namespaced icon values are no longer valid.
| Old value | New value |
| ---------- | ----------------- |
| home | mui:home |
| key | mui:key |
| operator | custom:operator |
If an icon is not provided, keep using null where the field is nullable.
Example payload update:
// before (invalid from v2)
{
icon: 'home'
}
// after
{
icon: 'mui:home'
}widgetHeaderMenuLinkSchema
| Variant | Fields |
| -------------- | ----------------------------------------------------------- |
| anchor | label, anchor where anchor must match ^#[a-z0-9-]+$ |
| external | label, url |
| widgetAnchor | label, targetWidgetConfigId |
widgetHeaderSchema
| Field | Type | Required | Notes |
| ---------- | ---------------- | -------- | ----------------------------------------- |
| logo | MediaImageRef | Yes | Logo media reference |
| logoLink | string \| null | No | Optional URL |
| menu | object or null | No | Contains enabled and optional items[] |
widgetFooterMenuItemSchema
| Field | Type | Required | Notes |
| ------- | ------------- | -------- | --------------- |
| label | TextContent | Yes | Menu item label |
| url | string | Yes | Valid URL |
widgetFooterMenuSectionSchema
| Field | Type | Required | Notes |
| ------- | ------------------------ | -------- | ----------------- |
| title | TextContent | Yes | Section title |
| items | WidgetFooterMenuItem[] | Yes | At least one link |
widgetFooterSchema
| Field | Type | Required | Notes |
| --------------------- | ----------------------- | -------- | ------------------------------------------- |
| paragraphs | TextContent[] \| null | No | Optional |
| menuSections | array or null | No | Each section contains title and items[] |
| phone | TextContent \| null | No | Optional |
| address | TextContent \| null | No | Optional |
| copyright | TextContent \| null | No | Optional |
| customerServiceLink | object or null | No | Contains label and url |
Example
import { widgetSchema } from '@verisure-italy/lp-types'
const hero = widgetSchema.parse({
type: 'hero',
properties: {
title: 'Protect your home',
media: [
{
desktop: {
mediaId: 'media-hero-desktop',
preset: 'funnel-hero-desktop',
alt: 'Alarm system',
},
mobile: {
mediaId: 'media-hero-mobile',
preset: 'funnel-hero-mobile',
alt: 'Alarm system',
},
loading: 'eager',
priority: true,
},
],
},
})