@cloudillo/base
@cloudillo/base
The @cloudillo/base library is the core SDK for Cloudillo applications. It provides initialization, API client creation, and helpers for real-time features.
Installation
pnpm add @cloudillo/baseCore Functions
init(appName: string): Promise
Initialize your Cloudillo application and get an access token.
For Microfrontends:
When running inside the Cloudillo shell, init() automatically communicates with the shell via postMessage to receive authentication credentials.
For Standalone Apps:
You must manually set cloudillo.accessToken before calling init().
import * as cloudillo from '@cloudillo/base'
// Initialize your app
const token = await cloudillo.init('my-app-name')
console.log('Token:', token)
console.log('User ID:', cloudillo.idTag)
console.log('Tenant ID:', cloudillo.tnId)
console.log('Roles:', cloudillo.roles)Returns: Access token (JWT string)
Side Effects:
- Sets
cloudillo.accessToken - Sets
cloudillo.idTag - Sets
cloudillo.tnId - Sets
cloudillo.roles - Sets
cloudillo.darkMode
createApiClient(opts?: ApiClientOptions): ApiClient
Create a type-safe REST API client.
import * as cloudillo from '@cloudillo/base'
await cloudillo.init('my-app')
const api = cloudillo.createApiClient()
// Now use the API
const profile = await api.me.get()
const posts = await api.action.get({ type: 'POST', _limit: 20 })Options:
interface ApiClientOptions {
baseUrl?: string // Default: current origin
token?: string // Default: cloudillo.accessToken
fetch?: typeof fetch // Custom fetch implementation
}Example with options:
const api = cloudillo.createApiClient({
baseUrl: 'https://api.cloudillo.com',
token: 'custom-token'
})Real-Time Functions
openYDoc(yDoc: Y.Doc, docId: string): Promise
Open a CRDT document for collaborative editing using Yjs.
import * as cloudillo from '@cloudillo/base'
import * as Y from 'yjs'
await cloudillo.init('my-app')
const yDoc = new Y.Doc()
const { provider } = await cloudillo.openYDoc(yDoc, 'my-document-id')
// Use shared types
const yText = yDoc.getText('content')
yText.insert(0, 'Hello, collaborative world!')
// Listen for changes
yText.observe(() => {
console.log('Text changed:', yText.toString())
})
// Access awareness (other users' cursors, selections)
provider.awareness.on('change', () => {
const states = provider.awareness.getStates()
console.log('Connected users:', states.size)
})Returns:
interface DocConnection {
yDoc: Y.Doc
provider: WebsocketProvider
}openCRDT(yDoc: Y.Doc, docId: string, opts?: CrdtOptions): Promise
Lower-level function for opening CRDT connections with custom options.
const provider = await cloudillo.openCRDT(yDoc, 'doc-id', {
url: 'wss://custom-server.com/ws/crdt',
token: 'custom-token'
})Options:
interface CrdtOptions {
url?: string // WebSocket URL
token?: string // Access token
params?: Record<string, string> // Query parameters
}openRTDB(fileId: string, opts?: RtdbOptions): RtdbClient
Open a real-time database connection.
import * as cloudillo from '@cloudillo/base'
await cloudillo.init('my-app')
const rtdb = cloudillo.openRTDB('my-database-file-id')
const todos = rtdb.collection('todos')
todos.onSnapshot(snapshot => {
console.log('Todos:', snapshot)
})See RTDB documentation for full API details.
openMessageBus(opts?: MessageBusOptions): MessageBusClient
Open a message bus connection for pub/sub messaging.
import * as cloudillo from '@cloudillo/base'
await cloudillo.init('my-app')
const bus = cloudillo.openMessageBus()
// Subscribe to a channel
bus.subscribe('notifications', (message) => {
console.log('Notification:', message)
})
// Publish a message
bus.publish('notifications', {
type: 'new-post',
data: { postId: '123' }
})Options:
interface MessageBusOptions {
url?: string // WebSocket URL
token?: string // Access token
channels?: string[] // Auto-subscribe to channels
}Global State
After calling init(), these global variables are available:
cloudillo.accessToken: string
The current access token (JWT).
console.log('Token:', cloudillo.accessToken)
// Manually set token (for standalone apps)
cloudillo.accessToken = 'your-jwt-token'cloudillo.idTag: string
The current user’s identity tag.
console.log('User:', cloudillo.idTag) // e.g., "alice@example.com"
cloudillo.tnId: number
The current tenant ID.
console.log('Tenant:', cloudillo.tnId) // e.g., 12345
cloudillo.roles: string[]
The current user’s roles.
console.log('Roles:', cloudillo.roles) // e.g., ["user", "admin"]
if (cloudillo.roles.includes('admin')) {
console.log('User is an admin')
}cloudillo.darkMode: boolean
The current theme preference (light or dark).
if (cloudillo.darkMode) {
document.body.classList.add('dark-theme')
}Helper Functions
qs(params: Record<string, any>): string
Convert an object to a query string.
import { qs } from '@cloudillo/base'
const query = qs({ type: 'POST', _limit: 20, status: 'A' })
console.log(query) // "type=POST&_limit=20&status=A"
// Use in API calls
const url = `/action?${qs({ type: 'POST', _limit: 20 })}`parseQS(search: string): Record<string, string>
Parse a query string into an object.
import { parseQS } from '@cloudillo/base'
const params = parseQS('?type=POST&_limit=20')
console.log(params) // { type: 'POST', _limit: '20' }
apiFetchHelper(url: string, options?: RequestInit): Promise
Low-level fetch helper with automatic authentication.
import { apiFetchHelper } from '@cloudillo/base'
const response = await apiFetchHelper('/auth/me')
const profile = await response.json()This automatically:
- Adds
Authorization: Bearer <token>header - Uses the current
cloudillo.accessToken - Throws
FetchErroron HTTP errors
Error Handling
FetchError
All API errors are thrown as FetchError instances.
import { FetchError } from '@cloudillo/base'
try {
const api = cloudillo.createApiClient()
const profile = await api.me.get()
} catch (error) {
if (error instanceof FetchError) {
console.error('HTTP Status:', error.status) // 401, 404, etc.
console.error('Error Code:', error.code) // 'E-AUTH-UNAUTH', etc.
console.error('Message:', error.message)
console.error('Response:', error.response) // Full response object
} else {
console.error('Unexpected error:', error)
}
}Properties:
status: number- HTTP status codecode: string- Cloudillo error code (e.g., ‘E-AUTH-UNAUTH’)message: string- Error messageresponse: Response- Full fetch Response object
API Client Structure
The API client provides access to all REST endpoints:
const api = cloudillo.createApiClient()
// Authentication
await api.auth.login.post({ idTag, password })
await api.auth.logout.post()
await api.auth.loginToken.get()
await api.auth.accessToken.get({ idTag, password })
await api.auth.proxyToken.get({ target })
// Profile
await api.me.get()
await api.me.patch({ name: 'New Name' })
await api.profile.get({ idTag: 'alice@example.com' })
await api.profile.list.get({ type: 'person', _limit: 20 })
// Actions
await api.action.get({ type: 'POST', _limit: 20 })
await api.action.post({ type: 'POST', content: { text: 'Hello!' } })
await api.action.id(actionId).get()
await api.action.id(actionId).patch({ content: { text: 'Updated' } })
await api.action.id(actionId).delete()
await api.action.id(actionId).accept.post()
await api.action.id(actionId).reject.post()
await api.action.id(actionId).reaction.post({ type: 'LOVE' })
// Files
await api.file.get({ fileTp: 'BLOB', _limit: 20 })
await api.file.post({ fileTp: 'BLOB', contentType: 'image/png' })
await api.file.id(fileId).get()
await api.file.id(fileId).descriptor.get()
await api.file.id(fileId).patch({ tags: ['important'] })
await api.file.id(fileId).delete()
await api.file.upload.post(formData)
// Settings
await api.settings.get()
await api.settings.name(settingName).get()
await api.settings.name(settingName).put(value)
// References
await api.ref.get()
await api.ref.post({ name: 'Bookmark', url: 'https://example.com' })
await api.ref.id(refId).delete()
// Tags
await api.tag.get({ prefix: 'proj-' })WebSocket Helpers
WebSocketClient
Low-level WebSocket client with automatic reconnection.
import { WebSocketClient } from '@cloudillo/base'
const ws = new WebSocketClient({
url: 'wss://server.com/ws/endpoint',
token: 'your-token',
onMessage: (message) => {
console.log('Received:', message)
},
onConnect: () => {
console.log('Connected')
},
onDisconnect: () => {
console.log('Disconnected')
}
})
// Send a message
ws.send({ type: 'subscribe', channel: 'updates' })
// Close connection
ws.close()Features:
- Automatic reconnection with exponential backoff
- Authentication via query parameter
- JSON message encoding/decoding
- Event handlers for connect/disconnect/message
Advanced Usage
Custom Fetch Implementation
import * as cloudillo from '@cloudillo/base'
// Use a custom fetch implementation (e.g., for testing)
const api = cloudillo.createApiClient({
fetch: async (url, options) => {
console.log('Fetching:', url)
return fetch(url, options)
}
})Multiple API Clients
// Different servers or tokens
const api1 = cloudillo.createApiClient({
baseUrl: 'https://server1.com',
token: 'token1'
})
const api2 = cloudillo.createApiClient({
baseUrl: 'https://server2.com',
token: 'token2'
})Standalone App Pattern
import * as cloudillo from '@cloudillo/base'
// Manual authentication
async function login(idTag: string, password: string) {
const response = await fetch('/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ idTag, password })
})
const data = await response.json()
// Set global state
cloudillo.accessToken = data.data.token
cloudillo.tnId = data.data.tnId
cloudillo.idTag = data.data.idTag
cloudillo.roles = data.data.roles
// Now init() will use these values
await cloudillo.init('my-app')
return data.data
}See Also
- Getting Started - Build your first app
- @cloudillo/react - React integration
- REST API Reference - Complete API documentation
- Authentication - Auth flows and tokens