SemiLayerDocs

Config Schema

The sl.config.ts file declares your entire SemiLayer setup. The defineConfig helper provides type-safety and IDE autocomplete.

Top-Level Shape

import { defineConfig } from '@semilayer/core'

export default defineConfig({
  stack: 'my-app',    // unique stack identifier — used in generated code
  sources: { ... },
  lenses: { ... },
  auth?: { ... },
})

Sources

sources: {
  [name: string]: {
    bridge: string       // required — npm package name of the bridge
    // Any additional fields are passed through to the bridge constructor.
    // For bridge-postgres, only the connection URL is needed — the service
    // resolves the stored credentials at ingest time.
  }
}

Example:

sources: {
  'main-db': {
    bridge: '@semilayer/bridge-postgres',
  },
}

Lenses

lenses: {
  [name: string]: {
    source: string          // source name from sources{}
    table: string           // target name (table, collection, endpoint, ...)
    primaryKey?: string     // primary key field name (auto-detected if omitted)

    fields: {
      [fieldName: string]: FieldConfig
    }

    facets?: {
      search?:  FacetConfig
      similar?: FacetConfig
      query?:   QueryFacetConfig
    }

    syncInterval?: SyncInterval   // periodic incremental sync cadence
    changeTrackingColumn?: string // column for incremental detection (default: updated_at)

    rules?: AccessRules
  }
}

FieldConfig

interface FieldConfig {
  type: 'text' | 'number' | 'boolean' | 'date' | 'json' | 'enum' | 'relation'

  searchable?: boolean | { weight: number }  // include in vector embeddings
  primaryKey?: boolean                        // mark this field as the PK

  from?: string          // source column name if different from field name
  transform?: TransformSpec | TransformSpec[] // value transform chain
}

TransformSpec

TransformOptionsDescription
lowercaseConvert to lowercase
uppercaseConvert to uppercase
trimStrip leading/trailing whitespace
truncate{ length: number }Truncate string to N characters
slugifyConvert to URL-safe slug
round{ decimals?: number }Round number
floorFloor number
ceilCeil number
multiply{ by: number }Multiply number
divide{ by: number }Divide number
default{ value: unknown }Use value if source is null/undefined
prefix{ value: string }Prepend string
suffix{ value: string }Append string
replace{ from: string; to: string }String replace

Chain multiple transforms as an array:

price: {
  type: 'number',
  from: 'price_cents',
  transform: [
    { type: 'divide', by: 100 },
    { type: 'round', decimals: 2 },
  ],
},

FacetConfig

interface FacetConfig {
  fields: string[]    // field names from this lens to use for embedding
}
facets: {
  search:  { fields: ['name', 'description', 'tags'] },
  similar: { fields: ['name', 'description'] },
}

SyncInterval

'1m' | '5m' | '15m' | '30m' | '1h' | '6h' | '24h'

AccessRules

interface AccessRules {
  search?:    RuleConfig
  similar?:   RuleConfig
  query?:     RuleConfig | false   // false = query disabled
  subscribe?: RuleConfig

  allowOrigins?: string[]          // CORS origins for pk_ keys
}

interface RuleConfig {
  allowPublicKey?: boolean         // allow pk_ keys (default: true for search/similar)
  userClaim?: string               // require this JWT claim to be present
  userClaimValue?: unknown         // require claim to equal this value
}

Auth

auth?: {
  jwksUrl?: string      // JWKS endpoint for user JWT verification
  issuer?: string       // Expected iss claim
  audience?: string     // Expected aud claim
}

Used when passing user JWTs (X-User-Token header) for per-user access rules.


Full Example

import { defineConfig } from '@semilayer/core'

export default defineConfig({
  stack: 'my-store',

  sources: {
    'main-db': {
      bridge: '@semilayer/bridge-postgres',
    },
  },

  lenses: {
    products: {
      source: 'main-db',
      table: 'public.products',
      primaryKey: 'id',

      fields: {
        id:          { type: 'number', primaryKey: true },
        name:        { type: 'text', searchable: { weight: 3 } },
        description: { type: 'text', searchable: true },
        category:    { type: 'text' },
        price:       { type: 'number' },
        inStock:     { type: 'boolean', from: 'in_stock' },
        slug:        { type: 'text', from: 'name', transform: { type: 'slugify' } },
      },

      facets: {
        search:  { fields: ['name', 'description'] },
        similar: { fields: ['name', 'description'] },
      },

      syncInterval: '15m',
      changeTrackingColumn: 'updated_at',

      rules: {
        search:  { allowPublicKey: true },
        similar: { allowPublicKey: true },
        query:   { allowPublicKey: false },   // backend only
      },
    },
  },

  auth: {
    jwksUrl: 'https://your-auth-provider.com/.well-known/jwks.json',
    issuer: 'https://your-auth-provider.com/',
    audience: 'your-api-audience',
  },
})