Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.uselayers.com/llms.txt

Use this file to discover all available pages before exploring further.

Controller state

All controllers expose reactive state via a ReadonlySignal<QueryState<T>>:
interface QueryState<T> {
  data: T | null
  error: ClientError | null
  isFetching: boolean
}

Query result

Collection, search, blocks, and image search controllers all return the same base QueryResult shape in data:
interface QueryResult {
  products: Product[]
  totalResults: number
  totalPages: number
  page: number
  facets: Record<string, Record<string, number>>
  priceRange?: PriceRange
  attributionToken?: string
}
priceRange requires { name: 'Price', code: 'variants.price' } in your facets configuration. Without it, priceRange will be undefined.

Blocks result

Blocks results extend QueryResult with block metadata:
interface BlocksResult extends QueryResult {
  block?: BlocksInfo
}

interface BlocksInfo {
  id: string
  label: string
  title: string
  anchor_type: 'product' | 'collection' | 'cart' | 'none'
  strategy_type: 'interaction' | 'collection_interaction' | 'similar_products' | 'manual'
  strategy_key: string
}

Suggestions result

The suggest controller returns a different shape:
interface Suggestions {
  matchedQueries: string[]
  originalQuery: string
  normalizedQuery: string
}

Content search result

The searchContent controller returns articles:
interface SearchContentResult {
  articles: Article[]
  query: string
  contentType: string | null
  totalResults: number
  page: number
  resultsPerPage: number
}

interface Article {
  title: string
  handle: string
  summary: string
  author: string
  tags: string[]
  image: ArticleImage | null
  publishedAt: string
}

interface ArticleImage {
  url: string
  width: number
  height: number
}

Product types

Product

The Product type represents a fully built product returned by the SDK. It extends ProductBase and can be further extended via the transforms.product configuration.
type Product = ProductBase & Record<string, unknown>

interface ProductBase {
  // Identifiers
  id: CommerceBlocksID
  gid: ProductGID
  numericId: number

  // Core
  title: string
  handle: string
  vendor: string
  type: string
  availableForSale: boolean
  tags: string[]

  // Media
  images: Image[]
  featuredMedia: FeaturedMedia | null

  // Pricing
  price: Price
  compareAtPrice: Price | null

  // Options and variants
  options: RichProductOption[]
  selectedOptions: ProductOption[]
  variants: ProductVariant[]
  selectedVariant: ProductVariant | null

  // Metadata
  metafields: Record<string, Record<string, unknown>>
  calculated: Record<string, unknown>

  // Taxonomy
  category: ProductCategory | null

  // Combined listings
  combinedListingParentProductId: number | null
  combinedListingRole: string | null

  // Breakout
  breakoutOptions: ProductOption[]
  breakoutVariantId: number | null
}
CommerceBlocksID is a string in the format layers-{numericId}. ProductGID is a Shopify Global ID string like gid://shopify/Product/123.

ProductVariant

interface ProductVariant {
  id: CommerceBlocksID
  gid: VariantGID
  numericId: number
  title: string
  sku: string | null
  position: number
  availableForSale: boolean
  price: Price
  compareAtPrice: Price | null
  image: Image | null
  selectedOptions: ProductOption[]
  inventoryLevels: Record<string, number>
  inventoryPolicy: 'DENY' | 'CONTINUE' | null
  inStockLocationIds: number[]
  requiresSellingPlan: boolean
  hasSellingPlan: boolean
}
VariantGID is a Shopify Global ID string like gid://shopify/ProductVariant/456.

Price and PriceRange

interface Price {
  amount: number
  currencyCode: string
  formatted: string
}

interface PriceRange {
  min: Price
  max: Price
}
The formatted value is generated by the SDK using the formatPrice function you provide at client init, or a default formatter based on Intl.NumberFormat.

Image and FeaturedMedia

interface Image {
  url: string
  alt: string
  width: number
  height: number
  position: number
  variantIds: number[]
}

interface FeaturedMedia {
  mediaContentType: string | null
  url: string
  alt: string
  width: number
  height: number
}

Options

interface ProductOption {
  name: string
  value: string
}

interface RichProductOption extends ProductOption {
  code: string
  swatch?: Swatch
}
RichProductOption is used for the product’s top-level options array. It includes the attribute code (the internal Layers identifier) and an optional swatch with color or image data if defined for that option.

ProductCategory

interface ProductCategory {
  id: string
  name: string
  fullName: string
  isLeaf: boolean
  isRoot: boolean
}

NamedTag

interface NamedTag {
  name: string
  value: string | number | boolean | string[]
}

Error handling

All methods return { data, error } instead of throwing. Errors are discriminated by _tag:
const result = await collection.execute()

if (result.error) {
  switch (result.error._tag) {
    case 'NetworkError':
      break
    case 'ApiError':
      break
    case 'ValidationError':
      break
    case 'ConfigError':
      break
  }
}

Error types

type ClientError = NetworkError | ApiError | ValidationError | ConfigError

NetworkError

Raised when a request fails before receiving a response.
interface NetworkError {
  readonly _tag: 'NetworkError'
  readonly code: NetworkErrorCode
  readonly message: string
  readonly retryAfterMs?: number
  readonly cause?: unknown
}

type NetworkErrorCode =
  | 'TIMEOUT'
  | 'CONNECTION_FAILED'
  | 'DNS_FAILED'
  | 'SSL_ERROR'
  | 'ABORTED'
  | 'OFFLINE'

ApiError

Raised when the Layers API returns an error response.
interface ApiError {
  readonly _tag: 'ApiError'
  readonly code: ApiErrorCode
  readonly source: 'layers'
  readonly message: string
  readonly status?: number
  readonly retryAfterMs?: number
  readonly cause?: unknown
}

type ApiErrorCode =
  | 'UNAUTHORIZED'
  | 'FORBIDDEN'
  | 'NOT_FOUND'
  | 'NOT_READY'
  | 'RATE_LIMITED'
  | 'SERVICE_UNAVAILABLE'
  | 'PARSE_ERROR'
  | 'UNKNOWN'

ValidationError

Raised when pre-request validation fails (for example, a required parameter is missing or out of range).
interface ValidationError {
  readonly _tag: 'ValidationError'
  readonly code: 'VALIDATION_FAILED'
  readonly message: string
  readonly operation: string
  readonly fields: ValidationFieldError[]
  readonly input?: unknown
}

interface ValidationFieldError {
  readonly field: string
  readonly code: 'REQUIRED_FIELD' | 'OUT_OF_RANGE'
  readonly message: string
  readonly value?: unknown
  readonly constraints?: { min?: number; max?: number }
}

ConfigError

Raised during createClient() when the SDK is misconfigured.
interface ConfigError {
  readonly _tag: 'ConfigError'
  readonly code: 'MISSING_CONFIG' | 'INVALID_CONFIG'
  readonly message: string
  readonly field: string
  readonly value?: unknown
  readonly expected?: string
}

Retry helpers

isRetryable classifies errors by tag, code, and status. Use it standalone or as a shouldRetry predicate:
import { isRetryable } from '@commerce-blocks/sdk'

if (result.error && isRetryable(result.error)) {
  const delay = result.error.retryAfterMs ?? 1000
  setTimeout(() => collection.execute(), delay)
}
Retryable errors include NetworkError with code TIMEOUT, CONNECTION_FAILED, or DNS_FAILED, and ApiError with code RATE_LIMITED or SERVICE_UNAVAILABLE.

Error type guard

isClientError can be used to check whether an unknown value is one of the SDK error types:
import { isClientError } from '@commerce-blocks/sdk'

try {
  // external code that may throw
} catch (e) {
  if (isClientError(e)) {
    console.error(e._tag, e.message)
  }
}

Exported types

The SDK exports all types from @commerce-blocks/sdk:
import type {
  // Client
  Client,
  ClientConfig,
  CreateClientResult,

  // Controllers
  Controller,
  CollectionController,
  CollectionOptions,
  CollectionQuery,
  CollectionResult,
  SearchController,
  SearchQuery,
  SearchResult,
  SearchPrepareResult,
  SuggestController,
  SuggestOptions,
  BlocksController,
  BlocksOptions,
  BlocksQuery,
  BlocksResult,
  UploadImageController,
  UploadImageOptions,
  UploadImageResult,
  SearchByImageController,
  SearchByImageQuery,
  SearchContentController,
  SearchContentQuery,
  SearchContentResult,
  Article,

  // Product card
  ProductCardController,
  ProductCardOptions,
  ProductCardState,
  OptionGroup,
  OptionValue,
  OptionStatus,
  PriceData,
  PriceRangeData,

  // Product
  Product,
  ProductBase,
  ProductVariant,
  Image,
  Price,
  PriceRange,
  ProductOption,
  RichProductOption,
  Swatch,

  // State
  QueryState,
  QueryParams,
  RequestTransformer,
  Unsubscribe,

  // Errors
  ClientError,
  NetworkError,
  ApiError,
  ValidationError,
  ConfigError,

  // Filters
  FilterGroup,
  FilterExpression,

  // Signals
  Signal,
  ReadonlySignal,

  // Storage
  StorageAdapter,
  CacheOptions,

  // Fetch
  CustomFetch,
} from '@commerce-blocks/sdk'

Next steps