Overview
The @brainbox/client package provides the client-side sync engine, database layer, and data operations for Brainbox. It handles local SQLite storage, WebSocket synchronization, and optimistic updates.
Installation
npm install @brainbox/client
Package Exports
The package provides multiple entry points:
import { openDatabase } from '@brainbox/client/databases';
import { queryNodes } from '@brainbox/client/queries';
import { createSpace } from '@brainbox/client/mutations';
import { SyncEngine } from '@brainbox/client/services';
Databases
Local SQLite database management using Kysely.
openDatabase
Opens or creates a workspace database.
import { openDatabase } from '@brainbox/client/databases';
const db = await openDatabase(workspaceId);
Database Exports
export { openDatabase } from './app';
export { getEmojiDatabase } from './emojis';
export { getIconDatabase } from './icons';
export { getWorkspaceDatabase } from './workspace';
Queries
Type-safe queries for fetching data from local database.
QueryMap Interface
interface QueryMap {
'node.get': {
input: NodeGetQueryInput;
output: LocalNode | null;
};
'node.search': {
input: NodeSearchQueryInput;
output: LocalNode[];
};
'workspace.get': {
input: WorkspaceGetQueryInput;
output: LocalWorkspace | null;
};
// ... 40+ query types
}
Node Queries
node.get
Fetches a single node by ID.
The node or null if not found
import { queryNode } from '@brainbox/client/queries';
const node = await queryNode({
type: 'node.get',
nodeId: '01j1234567890abcdefghnd',
accountId,
workspaceId,
});
node.search
Searches nodes by text content.
Maximum results (default: 50)
const results = await queryNode({
type: 'node.search',
query: 'meeting notes',
workspaceId,
accountId,
limit: 20,
});
node.children.get
Fetches children of a node.
const children = await queryNode({
type: 'node.children.get',
nodeId: parentId,
accountId,
workspaceId,
});
Database Queries
database.list
Lists all databases in a workspace.
const databases = await queryNode({
type: 'database.list',
workspaceId,
accountId,
});
record.list
Lists records in a database.
const records = await queryNode({
type: 'record.list',
databaseId,
workspaceId,
accountId,
limit: 100,
offset: 0,
});
File Queries
file.list
Lists files in workspace.
const files = await queryNode({
type: 'file.list',
workspaceId,
accountId,
limit: 50,
});
Message Queries
message.list
Lists messages in a channel or chat.
const messages = await queryNode({
type: 'message.list',
channelId,
workspaceId,
accountId,
limit: 100,
before: lastMessageId,
});
User Queries
user.search
Searches users in workspace.
const users = await queryNode({
type: 'user.search',
query: 'john',
workspaceId,
accountId,
});
QueryError
class QueryError extends Error {
constructor(public code: QueryErrorCode, message: string);
}
enum QueryErrorCode {
Unknown = 'unknown',
AccountNotFound = 'account_not_found',
WorkspaceNotFound = 'workspace_not_found',
ApiError = 'api_error',
}
Mutations
Type-safe mutations for creating, updating, and deleting data.
MutationMap Interface
interface MutationMap {
'space.create': {
input: SpaceCreateMutationInput;
output: SpaceCreateMutationOutput;
};
'page.create': {
input: PageCreateMutationInput;
output: PageCreateMutationOutput;
};
'node.reaction.create': {
input: NodeReactionCreateMutationInput;
output: NodeReactionCreateMutationOutput;
};
// ... 70+ mutation types
}
Node Mutations
page.create
Creates a new page.
Fractional index for ordering
import { mutate } from '@brainbox/client/mutations';
const result = await mutate({
type: 'page.create',
accountId,
workspaceId,
parentId: spaceId,
name: 'New Page',
});
if (result.success) {
console.log('Created page:', result.output.nodeId);
}
page.update
Updates page attributes.
const result = await mutate({
type: 'page.update',
accountId,
workspaceId,
nodeId: pageId,
name: 'Updated Name',
emoji: '📄',
});
page.delete
Deletes a page.
const result = await mutate({
type: 'page.delete',
accountId,
workspaceId,
nodeId: pageId,
});
Database Mutations
database.create
Creates a new database.
const result = await mutate({
type: 'database.create',
accountId,
workspaceId,
parentId: spaceId,
name: 'Tasks',
});
field.create
Adds a field to a database.
const result = await mutate({
type: 'field.create',
accountId,
workspaceId,
databaseId,
name: 'Status',
fieldType: 'select',
});
record.create
Creates a record in a database.
const result = await mutate({
type: 'record.create',
accountId,
workspaceId,
databaseId,
index: '0',
});
record.field-value.set
Sets a field value on a record.
const result = await mutate({
type: 'record.field-value.set',
accountId,
workspaceId,
recordId,
fieldId,
value: 'In Progress',
});
Reaction Mutations
node.reaction.create
Adds a reaction to a node.
type
'node.reaction.create'
required
Mutation type
const result = await mutate({
type: 'node.reaction.create',
accountId,
workspaceId,
nodeId: pageId,
reaction: '👍',
});
File Mutations
file.create
Uploads a file.
const result = await mutate({
type: 'file.create',
accountId,
workspaceId,
parentId: folderId,
file: fileBlob,
name: 'document.pdf',
});
Authentication Mutations
email.login
Login with email and password.
const result = await mutate({
type: 'email.login',
email: '[email protected]',
password: 'password123',
});
email.register
Register new account.
const result = await mutate({
type: 'email.register',
email: '[email protected]',
password: 'password123',
name: 'John Doe',
});
MutationResult
type MutationResult<T extends MutationInput> =
| SuccessMutationResult<T>
| ErrorMutationResult;
type SuccessMutationResult<T> = {
success: true;
output: MutationMap[T['type']]['output'];
};
type ErrorMutationResult = {
success: false;
error: {
code: MutationErrorCode;
message: string;
};
};
MutationError
class MutationError extends Error {
constructor(public code: MutationErrorCode, message: string);
}
enum MutationErrorCode {
Unknown = 'unknown',
ApiError = 'api_error',
AccountNotFound = 'account_not_found',
NodeNotFound = 'node_not_found',
SpaceCreateForbidden = 'space_create_forbidden',
FileInvalid = 'file_invalid',
StorageLimitExceeded = 'storage_limit_exceeded',
// ... 50+ error codes
}
Services
Core services for sync, metadata, and file management.
SyncEngine
Manages real-time synchronization over WebSocket.
import { SyncEngine } from '@brainbox/client/services';
const syncEngine = new SyncEngine({
workspaceId,
accountId,
serverUrl: 'wss://api.brainbox.ai',
});
await syncEngine.connect();
syncEngine.subscribe('nodes.updates', { rootId: spaceId });
await syncEngine.disconnect();
Manages app-specific metadata.
import { MetadataService } from '@brainbox/client/services';
const metadata = new MetadataService(accountId);
await metadata.set('lastWorkspace', workspaceId);
const lastWorkspace = await metadata.get('lastWorkspace');
FileSystem
Abstract filesystem for web and desktop.
import { FileSystem } from '@brainbox/client/services';
const fs = new FileSystem();
await fs.writeFile(path, data);
const data = await fs.readFile(path);
AssetService
Manages file uploads and downloads.
import { AssetService } from '@brainbox/client/services';
const assets = new AssetService(workspaceId);
await assets.upload(file);
const url = await assets.getUrl(fileId);
Handlers
Sync handlers for processing server updates.
export { handleNodesUpdates } from './nodes-updates';
export { handleDocumentUpdates } from './document-updates';
export { handleUsers } from './users';
export { handleNodeReactions } from './node-reactions';
export { handleNodeInteractions } from './node-interactions';
export { handleCollaborations } from './collaborations';
Types
LocalNode
type LocalNode = {
id: string;
type: NodeType;
parentId: string;
rootId: string;
attributes: NodeAttributes;
createdAt: string;
createdBy: string;
updatedAt: string | null;
updatedBy: string | null;
};
LocalWorkspace
type LocalWorkspace = {
id: string;
name: string;
avatar: string | null;
createdAt: string;
role: WorkspaceRole;
};