FLXBL SDK
Type-safe client for your FLXBL instance. Zero dependencies, native fetch, works in Node.js 18+, Deno, Bun, and edge runtimes.
Installation
npm install @flxbl-dev/clientQuick Start
import { FlxblClient } from '@flxbl-dev/client';
const client = new FlxblClient({
instanceUrl: 'https://api.flxbl.dev',
apiKey: 'flxbl_your_api_key',
});
// Create a record
const product = await client.request('POST', '/api/v1/dynamic/Product', {
name: 'Wireless Headphones',
price: 299.99,
inStock: true,
});
console.log(product); // { id: 'node_abc123', name: '...', ... }Authentication
The SDK supports two authentication methods. Use API keys for server-side applications and access tokens (JWTs) for client-side or per-user sessions.
import { FlxblClient } from '@flxbl-dev/client';
// Option 1: API key (recommended for server-side)
const client = new FlxblClient({
instanceUrl: 'https://api.flxbl.dev',
apiKey: 'flxbl_your_api_key',
});
// Option 2: Access token (for client-side / user sessions)
const client2 = new FlxblClient({
instanceUrl: 'https://api.flxbl.dev',
accessToken: 'eyJhbGciOiJIUzI1NiIs...',
});
// You can also set or update the token dynamically
client2.setAccessToken('new_jwt_token_here');Collections
The generated client (from flxbl generate) provides typed collection accessors
with CRUD, query, and batch helpers. Vector search helpers are generated for
entities with VECTOR fields, and relationship helpers are generated
from schema relationships. Collections are typed as
createCollection<T, TCreate, TUpdate>() with helpers like:
| Method | Description |
|---|---|
query(options?) | Query records with filters, search, sorting, pagination, counts, and traversals |
findMany(options?) | Alias-style list helper for paginated record queries |
findFirst(options?) | Return the first record matching the query options |
create(data) | Create a new record |
update(id, data) | Partial update of a record |
delete(id) | Delete a record by ID |
count(where?) | Count records matching an optional filter |
exists(where?) | Check whether any record matches an optional filter |
batchCreate(data[]) | Create multiple records in one request |
batchUpdate(items[]) | Update multiple records by ID in one request |
batchDelete(ids[]) | Delete multiple records by ID in one request |
// With the generated typed client (from `flxbl generate`):
import { createFlxblClient } from './flxbl/_generated';
const db = createFlxblClient({
instanceUrl: 'https://api.flxbl.dev',
apiKey: 'flxbl_your_api_key',
});
// Typed CRUD operations
const products = await db.products.query({
where: { inStock: { $eq: true } },
search: 'wireless',
select: ['id', 'name', 'price'],
orderBy: 'price',
orderDirection: 'DESC',
limit: 20,
});
const product = await db.products.findFirst({
where: { id: { $eq: 'node_abc123' } },
});
const newProduct = await db.products.create({
name: 'New Widget',
price: 49.99,
inStock: true,
});
const updated = await db.products.update('node_abc123', {
price: 39.99,
});
await db.products.delete('node_abc123');Query Options
The query and findMany methods accept a
QueryOptions<T> object with the following fields:
| Field | Type | Description |
|---|---|---|
where | object | Filter conditions using query operators |
search | string | Full-text search string for searchable fields |
select | string[] | Fields to include in the response |
orderBy | string | Field name to sort by |
orderDirection | 'ASC' | 'DESC' | Sort direction |
offset | number | Number of items to skip |
limit | number | Maximum items to return |
includeCount | boolean | Include total count in response |
traverse | object[] | Relationship traversals (relationship, direction, select, where) |
const results = await db.products.query({
// Filter conditions
where: {
status: { $eq: 'active' },
price: { $lte: 100 },
tags: { $contains: 'renewal' },
},
// Full-text search across searchable fields
search: 'contract renewal',
// Field selection
select: ['name', 'price', 'description'],
// Sorting
orderBy: 'price',
orderDirection: 'ASC',
// Pagination
offset: 0,
limit: 20,
includeCount: true,
// Graph traversal
traverse: [
{
relationship: 'BELONGS_TO',
direction: 'out',
select: ['name', 'slug'],
},
],
});
console.log(results.items); // Product[]
console.log(results.count); // Total matching countFilter Operators
Use these operators in where conditions:
| Operator | Description | Example |
|---|---|---|
$eq | Equal | { status: { $eq: 'active' } } |
$neq | Not equal | { status: { $neq: 'archived' } } |
$gt | Greater than | { price: { $gt: 100 } } |
$gte | Greater than or equal | { price: { $gte: 100 } } |
$lt | Less than | { price: { $lt: 50 } } |
$lte | Less than or equal | { price: { $lte: 50 } } |
$in | In array | { status: { $in: ['a', 'b'] } } |
$notIn | Not in array | { status: { $notIn: ['x'] } } |
$isNull | Is null | { deletedAt: { $isNull: true } } |
$contains | String contains | { name: { $contains: 'phone' } } |
$startsWith | String starts with | { name: { $startsWith: 'Pro' } } |
$endsWith | String ends with | { email: { $endsWith: '.com' } } |
$and | Logical AND | Combine multiple conditions |
$or | Logical OR | Match any condition |
Vector Search
Search entities by vector similarity using generated collection helpers or
the base client.vectorSearch(). This requires a VECTOR
field on the target entity and a query vector from your embedding model.
import { FlxblClient } from '@flxbl-dev/client';
// Semantic search using vector embeddings
const generatedResults = await db.documents.vectorSearch({
field: 'embedding',
vector: [0.1, 0.2, 0.3, /* ...1536 dimensions */],
topK: 5,
where: { status: { $eq: 'published' } },
select: ['id', 'title', 'summary'],
});
const client = new FlxblClient({
instanceUrl: 'https://api.flxbl.dev',
apiKey: 'flxbl_your_api_key',
});
const baseResults = await client.vectorSearch<Document>('Document', {
field: 'embedding',
vector: [0.1, 0.2, 0.3, /* ...1536 dimensions */],
topK: 5,
where: { status: { $eq: 'published' } },
select: ['id', 'title', 'summary'],
});
for (const result of generatedResults) {
console.log(result.data.title); // Document title
console.log(result.score); // Cosine similarity (0-1)
}
Option Type Description field string Name of the VECTOR field (required) vector number[] Query vector — must match the field's dimensions (required) topK number Max results, 1–100 (default: 10) where object Optional filter conditions select string[] Optional fields to include
GraphQL
Execute raw GraphQL queries against your tenant's GraphQL endpoint:
// Execute raw GraphQL queries
const tenantId = 'your_tenant_id';
const result = await client.graphql<{
products: Array<{ id: string; name: string; price: number }>;
}>(tenantId, `
query {
products(where: { inStock: { equals: true } }, limit: 10) {
id
name
price
}
}
`);
console.log(result.data?.products);
Relationships
Manage graph relationships between entities using client.relationships():
// Manage relationships between entities
const rel = client.relationships('Worker', 'worker_123');
// Create a relationship
await rel.create('ASSIGNED_TO', 'project_456', {
role: 'lead',
allocatedHours: 24,
});
// List relationships with node and edge filters
const assignments = await rel.list('ASSIGNED_TO', {
direction: 'out',
where: { status: { $eq: 'active' } },
edgeWhere: { role: { $eq: 'lead' } },
orderBy: 'createdAt',
orderDirection: 'DESC',
limit: 20,
offset: 0,
});
const relationshipId = assignments.items[0]._relationship.id;
// Update relationship properties by target id
await rel.update('ASSIGNED_TO', 'project_456', {
role: 'reviewer',
});
// Update the exact relationship edge by id
await rel.updateById('ASSIGNED_TO', relationshipId, {
role: 'owner',
});
// Delete a relationship by target id
await rel.delete('ASSIGNED_TO', 'project_456');
// Delete the exact relationship edge by id
await rel.deleteById('ASSIGNED_TO', relationshipId);
// Generated relationship helper
const workerRelationships = db.workers.relationships('worker_123');
const assignedTo = workerRelationships.assignedTo;
const workerAssignments = await assignedTo.list({
where: { status: { $eq: 'active' } },
edgeWhere: { role: { $eq: 'lead' } },
limit: 10,
});
await assignedTo.updateById(relationshipId, {
role: 'owner',
});
await assignedTo.deleteById(relationshipId);
console.log(assignments.items, workerAssignments.items);
List option Description direction Relationship traversal direction, out, in, or both where Filter related target-node fields edgeWhere Filter relationship properties orderBy Sort related target nodes by field orderDirection Sort direction, ASC or DESC limit Maximum relationships to return offset Number of relationships to skip
Error Handling
The SDK throws typed errors for different failure scenarios. All errors extend
FlxblApiError:
Error Class Status When FlxblValidationError 400 Invalid input — includes field-level validationErrors FlxblAuthError 401 Missing or invalid credentials FlxblNotFoundError 404 Entity or record not found FlxblApiError * Any other API error (403, 429, 500, etc.)
import {
FlxblApiError,
FlxblAuthError,
FlxblValidationError,
FlxblNotFoundError,
} from '@flxbl-dev/client';
try {
await db.products.create({ name: '' });
} catch (error) {
if (error instanceof FlxblValidationError) {
// 400 — field-level validation errors
console.log(error.validationErrors);
// [{ field: 'name', message: 'Name is required' }]
} else if (error instanceof FlxblAuthError) {
// 401 — invalid or missing credentials
console.log(error.message);
} else if (error instanceof FlxblNotFoundError) {
// 404 — entity or record not found
console.log(error.message);
} else if (error instanceof FlxblApiError) {
// Other API errors (403, 429, 500, etc.)
console.log(error.statusCode, error.message);
}
}
Code Generation
The SDK works best with a generated typed client. Use the FLXBL CLI
to generate TypeScript interfaces and a typed client factory from your active schema:
# Generate a typed client
npm install -g @flxbl-dev/cli
flxbl generate
The generated client includes entity types, create/update input types, query option helpers,
and a createFlxblClient() factory with typed collection accessors for every entity
in your schema.
Next Steps
- CLI - Generate typed clients, manage schemas, and query data
- API Reference - Complete REST and GraphQL documentation
- Query DSL - Deep dive into filter operators and traversals
- Schema Design - Define entities, fields, and relationships