A lightweight JavaScript/TypeScript client library for the Light Framework, providing an easy-to-use API for GraphQL queries/mutations, authentication, file management, user management, and more.
- 🔐 Authentication - Login/logout, password management, OAuth (Google, Facebook, Microsoft), WebAuthn support
- 📊 GraphQL Client - Simplified query and mutation APIs with automatic file upload handling
- 📁 File System - Complete file and folder management operations
- 👥 User Management - CRUD operations for users and roles
- 📧 Email - Send emails via the backend
- 🔄 Token Refresh - Automatic access token refresh with request queuing
- 🌐 Universal - Works in both browser and Node.js environments
npm install @hostlink/lightimport { createClient } from '@hostlink/light';
// Create a client instance
const api = createClient('https://your-api.com/graphql');
// Login
await api.auth.login('username', 'password');
// Query data
const users = await api.query({
app: {
users: {
user_id: true,
username: true,
first_name: true
}
}
});
// Logout
await api.auth.logout();import { createClient } from '@hostlink/light';
const api = createClient('https://your-api.com/graphql');The client provides:
api.auth- Authentication methodsapi.query- GraphQL queriesapi.mutation- GraphQL mutationsapi.users- User managementapi.roles- Role managementapi.mail- Email sendingapi.config- Configuration accessapi.collect- Collection builderapi.list- List builder
// Login with username and password
await api.auth.login('username', 'password');
// Login with 2FA code
await api.auth.login('username', 'password', '123456');
// Logout
await api.auth.logout();const user = await api.auth.getCurrentUser();
// Returns: { user_id, username, first_name, last_name, status }
// With custom fields
const user = await api.auth.getCurrentUser({
user_id: true,
username: true,
email: true
});// Update password
await api.auth.updatePassword('oldPassword', 'newPassword');
// Change expired password
await api.auth.changeExpiredPassword('username', 'oldPassword', 'newPassword');
// Forgot password flow
const jwt = await api.auth.forgetPassword('username', 'email@example.com');
await api.auth.verifyCode(jwt, '123456');
await api.auth.resetPassword(jwt, 'newPassword', '123456');// Google
await api.auth.google.login(credential);
await api.auth.google.register(credential);
await api.auth.google.unlink();
// Facebook
await api.auth.facebook.login(accessToken);
await api.auth.facebook.register(accessToken);
await api.auth.facebook.unlink();
// Microsoft
await api.auth.microsoft.login(accessToken);
await api.auth.microsoft.register(accountId);
await api.auth.microsoft.unlink();import { webAuthn } from '@hostlink/light';
// Register a new passkey
await webAuthn.register();
// Login with passkey
await webAuthn.login();// Check single permission
const canEdit = await api.auth.isGranted('edit_users');
// Check multiple permissions
const rights = await api.auth.grantedRights(['edit_users', 'delete_users']);const result = await api.query({
app: {
users: {
user_id: true,
username: true,
profile: {
avatar: true,
bio: true
}
}
}
});const result = await api.mutation({
createPost: {
__args: {
title: 'Hello World',
content: 'My first post'
}
}
});File uploads are automatically handled in mutations:
// Single file upload
await api.mutation({
uploadAvatar: {
__args: {
file: fileInput.files[0]
}
}
});
// Multiple file upload
await api.mutation({
uploadImages: {
__args: {
files: Array.from(fileInput.files)
}
}
});import { createList } from '@hostlink/light';
// Create a list query
const users = await createList('Users', {
user_id: true,
username: true,
first_name: true
})
.where('status', 1)
.where('role', 'admin')
.sort('-created_at')
.limit(10)
.fetch();
// Get first item
const user = await createList('Users', { user_id: true, username: true })
.where('username', 'john')
.first();list
.where('status', 1) // Exact match
.where('age', '>', 18) // Greater than
.where('age', '>=', 18) // Greater than or equal
.where('age', '<', 65) // Less than
.where('age', '<=', 65) // Less than or equal
.where('status', '!=', 0) // Not equal
.whereIn('role', ['admin', 'moderator']) // In array
.whereContains('name', 'john') // Contains string
.whereBetween('age', 18, 65) // Between rangeimport { createCollection } from '@hostlink/light';
const collection = createCollection('Products', {
id: true,
name: true,
price: true,
category: true
});
// Filter and transform data
const result = await collection
.where('category', '==', 'electronics')
.where('price', '<', 1000)
.sortBy('price')
.map(item => ({ ...item, discounted: item.price * 0.9 }))
.all();
// Aggregations
const avgPrice = await collection.avg('price');
const total = await collection.count();
const maxPrice = await collection.max('price');// List users
const users = await api.users.list();
// Create user
await api.users.create({
username: 'newuser',
first_name: 'John',
last_name: 'Doe',
password: 'securepassword',
join_date: '2024-01-01'
});
// Update user
await api.users.update(userId, {
first_name: 'Jane'
});
// Delete user
await api.users.delete(userId);// List roles
const roles = await api.roles.list();
// Create role with child roles
await api.roles.create('admin', ['editor', 'viewer']);
// Delete role
await api.roles.delete('admin');For direct filesystem access:
import { fs } from '@hostlink/light';
// Create folder
await fs.createFolder('local://path/to/folder');
// Delete folder
await fs.deleteFolder('local://path/to/folder');
// Rename folder
await fs.renameFolder('local://path/to/folder', 'newName');
// Write file
await fs.writeFile('local://path/to/file.txt', 'content');
// Upload file
await fs.uploadFile('local://path/to/destination', file);
// Delete file
await fs.deleteFile('local://path/to/file.txt');
// Check if exists
const exists = await fs.exists('local://path/to/file.txt');
// Move file/folder
await fs.move('local://from/path', 'local://to/path');
// Search files
const results = await fs.find('searchterm', 'document'); // labels: document, image, audio, video, archiveawait api.mail.send(
'recipient@example.com',
'Subject Line',
'Email message body'
);Create reusable model definitions:
import model from '@hostlink/light';
const Product = model('Product', {
id: { name: 'product_id' },
name: { gql: { name: true } },
price: { gql: { price: true, currency: true } }
});
// CRUD operations
await Product.add({ name: 'New Product', price: 99.99 });
await Product.update(1, { price: 89.99 });
await Product.delete(1);
const product = await Product.get({ id: 1 }, { name: true, price: true });
const products = await Product.list({ name: true, price: true }).fetch();import { setApiClient, getApiClient } from '@hostlink/light';
// Set a custom API client
setApiClient(customClient);
// Get the current API client
const client = getApiClient();
// Access the underlying axios instance
const { axios } = getApiClient();The client automatically handles token refresh when receiving TOKEN_EXPIRED errors. Failed requests are queued and retried after the token is refreshed.
This library is written in TypeScript and includes full type definitions.
import type {
UserFields,
CreateUserFields,
QueryUserFieldsUserFields,
RoleFields,
FileFields,
FolderFields,
GraphQLQuery
} from '@hostlink/light';MIT