SemiLayerDocs

Generate Beam

The Beam client is a typed TypeScript module generated from your sl.config.ts. It gives you a fully-typed API surface that matches your exact lens definitions — no casting, no magic strings.


Generate

semilayer generate

This reads your sl.config.ts and writes the generated module to ./generated/semilayer/ by default:

generated/
  semilayer/
    index.ts          ← re-exports Beam + createBeam
    beam.ts           ← Beam class with typed lens accessors
    types.ts          ← generated metadata types per lens

Custom output directory

semilayer generate --out ./src/semilayer

Commit the generated directory to version control. Re-run semilayer generate after every sl.config.ts change.


Initialize the Client

import { createBeam } from './generated/semilayer'

const beam = createBeam({
  baseUrl: 'https://api.semilayer.com',   // or your self-hosted URL
  apiKey: process.env.SEMILAYER_API_KEY!, // sk_ or pk_ key
})

The createBeam factory is lightweight — call it once and reuse the instance.

With a user token (RBAC)

For per-user access rules (e.g. a public pk_ key with row-level restrictions):

const userBeam = beam.withUser(userJwt)
// userBeam is a new instance — original beam is unchanged
const { results } = await userBeam.products.search({ query: 'sneakers' })

Using the Client

The beam instance has one property per lens, each with the full set of operations.

const { results } = await beam.products.search({
  query: 'lightweight running shoes',
  limit: 10,
  mode: 'hybrid',         // 'semantic' | 'keyword' | 'hybrid' (default: 'semantic')
})

for (const result of results) {
  console.log(result.score)           // 0–1 cosine similarity
  console.log(result.metadata.name)   // typed: string
  console.log(result.metadata.price)  // typed: number
}

Similar

const { results } = await beam.products.similar({
  id: '42',     // primary key of the source record
  limit: 5,
})
// results[0].metadata — same shape as search

Query

Direct filtered read from the source. Requires facets.query enabled in the lens config.

const { rows } = await beam.products.query({
  where: { category: 'footwear', inStock: true },
  limit: 20,
})

for (const row of rows) {
  console.log(row.name)   // direct field access — no .metadata wrapper
  console.log(row.price)
}

Results stream as they arrive — useful for large result sets or low-latency UIs:

for await (const result of beam.products.stream.search({ query: 'sneakers' })) {
  render(result) // called for each result as it arrives
}

Live tail

Subscribe to every insert, update, and delete on a lens in real time:

for await (const event of beam.products.stream.subscribe()) {
  console.log(event.kind)    // 'insert' | 'update' | 'delete'
  console.log(event.record)  // typed ProductsMetadata
}

Observe

Watch a single record — get the current state immediately, then receive every subsequent change:

for await (const snapshot of beam.products.observe('42')) {
  setProduct(snapshot) // ProductsMetadata — updates on every change
}

TypeScript Types

The generated types.ts exports one metadata type per lens:

// generated/semilayer/types.ts
export interface ProductsMetadata {
  id: number
  name: string
  description: string
  category: string
  price: number
  inStock: boolean
}

These types are derived directly from your field declarations in sl.config.ts. If you add or rename a field, regenerate and TypeScript will surface everywhere that needs updating.


In a Framework

Next.js (App Router)

// lib/semilayer.ts
import { createBeam } from '@/generated/semilayer'

export const beam = createBeam({
  baseUrl: process.env.SEMILAYER_BASE_URL!,
  apiKey: process.env.SEMILAYER_API_KEY!,
})
// app/search/route.ts
import { beam } from '@/lib/semilayer'

export async function GET(req: Request) {
  const q = new URL(req.url).searchParams.get('q') ?? ''
  const { results } = await beam.products.search({ query: q, limit: 10 })
  return Response.json(results)
}

Client-side (public key)

// Anywhere in browser code — pk_ keys are safe client-side
const beam = createBeam({
  baseUrl: 'https://api.semilayer.com',
  apiKey: process.env.NEXT_PUBLIC_SEMILAYER_KEY!, // pk_live_...
})

Next Steps

  • Querying — deep dive into all query operations
  • Auth & RBAC — per-user access rules with user JWTs
  • Examples — working code examples