docs
    agency-site-kit: Types
    v0.11.1.md

    Types

    Every shape the kit hands you is typed, from a list item to each section's data. This page covers where to import the types from and what the main ones hold. The declarations in the package are the full reference; this is the map.

    Where to import them

    FromYou get
    @sonordev/agency-site-kit/portfolioThe case study types: items, sections, each section's data, KPIs, metrics, ProofRecord and PORTFOLIO_SECTION_TYPES, plus HeadlineKpi, SoloDeviceInput, PortfolioJsonLdOptions and ResolvedPortfolioImage
    @sonordev/agency-site-kitAll of the above, plus the item-level types inside sections (PortfolioChallengeItem, PortfolioResultItem, PortfolioGalleryImage and so on), BrandConfig, SanityImageRef and PortfolioConfigResponse
    @sonordev/agency-site-kit/layoutAgencySiteKitLayoutProps
    @sonordev/agency-site-kit/portfolio/serverPortfolioSitemapEntry
    @sonordev/agency-site-kit/revalidateCreateRevalidateHandlerOptions
    @sonordev/agency-site-kit/previewPortfolioPreviewHandlerOptions

    The root entry is server only, but a type import is erased at build time, so import type { PortfolioResultItem } from '@sonordev/agency-site-kit' is fine in a client component.

    Case studies

    PortfolioItem

    A published case study as the list returns it.

    FieldTypeWhat it is
    id, slug, title, subtitlestring
    descriptionstring
    categorystringStored as a slug. Print it with formatCategoryLabel.
    industry_tagsstring[], optionalIndustry categories for industry pages, primary first
    servicesstring[]Service tags. Print them with formatServiceTag.
    hero_image, hero_image_altstring
    hero_screenshots{ desktop?, tablet?, mobile? } or nullDevice screenshots, as URLs
    showcase_sitesarray or null, optionalOne entry per site when the case study covers several (see Sections and devices)
    live_urlstring or null
    kpisPortfolioKPI[]The headline numbers
    detailsPortfolioDetailsData or nullIndustry, location, website, timeline, launch date, budget range
    seoPortfolioSeoData or nullMeta title, meta description, keywords
    featuredboolean
    ordernumber, optional
    published_atstring or nullISO timestamp
    project_idstring or nullThe Sonor project it was built from, if any
    baseline_metrics, current_metricsMetricsSnapshot or nullSearch, Core Web Vitals, analytics and page counts, before and now
    metrics_last_refreshed_atstring or nullWhen the live metrics last updated

    PortfolioItemFull

    What getPortfolioItem returns: a PortfolioItem plus

    FieldTypeWhat it is
    sectionsPortfolioSection[]The case study's content (see below)
    metricsDeltaMetricsDelta[]Live analytics changes. Run them through gateMetricsDeltas before showing any.
    sectionsOrderedboolean, optionalTrue once someone reordered the sections in the dashboard. orderedSections reads it.

    PortfolioListResponse

    { items: PortfolioItem[]; total: number; limit: number; offset: number }, from getPortfolioItems.

    Numbers

    PortfolioKPI

    interface PortfolioKPI {
      label: string;
      value: number;
      suffix: string;
      prefix?: string;
      description: string;
      source: MetricSource;            // 'measured' | 'reported' | 'estimated'
      reportedBy?: MetricAttribution;  // required when source is 'reported'
    }

    A results card (PortfolioResultItem) carries the same source and reportedBy, with its figure in metric: { value, suffix, prefix? }. MetricAttribution is { name, role?, organization, date }, with date as YYYY-MM-DD. Proof and provenance covers what each source may claim.

    MetricsDelta

    interface MetricsDelta {
      metric: string;
      baseline: number;
      current: number;
      delta: number;
      deltaPercent: number;
      direction: 'up' | 'down' | 'flat'; // 'up' means improved, even for lower-is-better metrics
      timespan: string;
    }

    MetricsSnapshot

    Four groups of optional numbers: seo (clicks_28d, impressions_28d, avg_position, ctr), cwv (lcp_ms, inp_ms, cls, performance_score), analytics (sessions_28d, page_views_28d, conversion_rate, bounce_rate) and pages (total_indexed, total_crawled, total_pages).

    Sections

    PortfolioSection<T> is { sectionType, displayName, data }, where data is typed by PortfolioSectionDataMap[sectionType]. PortfolioSectionType is the union of the names in PORTFOLIO_SECTION_TYPES, and PortfolioSectionData is the union of every data shape.

    sectionTypeData typeMain fields
    portfolioHeroPortfolioHeroDataheadline, subheadline, description, category, services, liveUrl?, screenshots, kpis
    portfolioChallengesPortfolioChallengesDataitems: { title, description, solution, result?, icon? }
    portfolioStrategyPortfolioStrategyDataphases: { number, title, description, deliverables?, icon?, timeline? }
    portfolioResultsPortfolioResultsDataitems: PortfolioResultItem
    portfolioTechStackPortfolioTechStackDatatechnologies: { name, category, icon?, description? }
    portfolioServicesPortfolioServicesDataitems: { title, description, features, icon? }
    portfolioTestimonialPortfolioTestimonialDataquote, author, title, company, avatar?, rating?
    portfolioGalleryPortfolioGalleryDataimages: { image, caption?, type? }, layout?
    portfolioVideoPortfolioVideoDataurl?, embedUrl?, thumbnail, title, duration?, platform?
    portfolioTeamPortfolioTeamDatamembers: { name, role, avatar? }
    portfolioFeatureSpotlightPortfolioFeatureSpotlightDataimage, title, description, layout, annotations
    portfolioBeforeAfterPortfolioBeforeAfterDatabefore, after, beforeUrl?, afterUrl?, beforeLabel?, afterLabel?, archiveUrl?, defaultPosition?
    portfolioMetricsTimelinePortfolioMetricsTimelineDatadataPoints, baselineDate, title?, description?
    portfolioConversionFunnelPortfolioConversionFunnelDatastages: { label, value, icon?, color? }
    portfolioPerformancePortfolioPerformanceDatabefore?, after? (Lighthouse scores), cwv?, formFactor?, method?, measuredAt?, measuredUrl?, beforeMethod?
    portfolioDetailsPortfolioDetailsDataindustry, location?, website?, timeline?, launchDate?, budgetRange?
    portfolioSeoPortfolioSeoDatametaTitle, metaDescription, keywords, ogImage?
    portfolioCTAPortfolioCTADataheadline, description, buttonText, buttonUrl, style?

    portfolioSpeedComparison, portfolioSiteArchitecture and portfolioDesignSystem have no data type yet.

    A few notes that save a bug:

    • Image fields carry URLs. avatar, image, thumbnail, before, after and ogImage are typed as SanityImageRef, the older image object, but hold plain URL strings at runtime. Pass them to resolvePortfolioImage, which takes either. The type stays so existing code keeps compiling.
    • Performance captions. PortfolioPerformanceData's formFactor, method, measuredAt and measuredUrl say how the scores were taken. State them in the section's caption when they're present (print measuredAt with formatIsoDate, and show only the host of measuredUrl). beforeMethod belongs next to before-and-after scores.
    • Before and after. Prefer beforeUrl and afterUrl when they're set. beforeLabel says where the old image came from (for example an archive capture) and belongs in its badge and alt text.

    Evidence: ProofRecord

    What getProofRecords returns, one per published piece of evidence.

    FieldTypeWhat it is
    idstring
    sitestringThe site the record is published on
    case_slugstringThe case study it belongs to
    metric, definitionstringWhat was counted, and how it's defined
    result_value, unitnumber, stringThe result
    window_start, window_endstringThe period it covers
    baseline_value, baseline_start, baseline_endnumber / string, or nullWhat it's compared against, when there's a baseline
    source_url, source_labelstringWhere it came from. A client-reported figure names who reported it in source_label.
    limitationsstringWhat it doesn't prove
    reviewed_atstringWhen it was last reviewed

    Brand

    BrandConfig is the agency brand AgencySiteKitLayout turns into CSS variables: primary, secondary, background, backgroundElevated, surface, surfaceHover, surfaceBorder, textPrimary, textSecondary, textTertiary, fontHeading and fontBody, plus optional logoUrl, logoAlt, radius ({ sm, md, lg }) and darkMode (colour overrides for dark mode). See Brand layout.

    PortfolioConfigResponse is the raw brand endpoint's answer: { brand: BrandConfig; orgName: string; orgSlug: string }.

    Helper types

    TypeUsed by
    HeadlineKpiheadlineKpi()'s result: { value, label, source, credit, kpi }
    SoloDeviceInputshouldRenderSoloDevice() and resolveSoloScreenshot(): { category?, screenshots?, heroImage? }
    PortfolioJsonLdOptionsbuildPortfolioJsonLd()'s options: { url, publisher? }
    ResolvedPortfolioImageresolvePortfolioImage()'s result: { url, width?, height? }
    PortfolioSitemapEntrygeneratePortfolioSitemapEntries()'s entries
    AgencySiteKitLayoutPropsBrand layout
    CreateRevalidateHandlerOptions, PortfolioPreviewHandlerOptionsLive updates and preview