Jake Shore d3382ec35a Update 6 MCP servers — fieldedge, lightspeed, squarespace, toast, touchbistro, servicetitan — 2026-02-12
=== UPDATES ===
- fieldedge: Added apps, tools, main server entry, full rebuild
- lightspeed: Added complete src/ directory with tools + apps
- squarespace: Full rebuild — new apps, clients, tools, types modules
- toast: Full rebuild — api-client, apps, tools, types
- touchbistro: Full rebuild — api-client, tools, types, gitignore
- servicetitan: Added 4 React UI apps (call-tracking, lead-source-analytics, performance-metrics, schedule-calendar)

All servers restructured from single-file to modular architecture.
2026-02-12 17:58:15 -05:00

529 lines
20 KiB
TypeScript

/**
* Lightspeed API Client
* Supports both Retail (X-Series) and Restaurant (R-Series) APIs
*/
import axios, { AxiosInstance } from 'axios';
import type {
LightspeedConfig,
Product,
ProductInventory,
Customer,
Sale,
Order,
Employee,
Category,
Supplier,
Discount,
LoyaltyProgram,
CustomerLoyalty,
Shop,
Register,
PaymentType,
TaxCategory,
Manufacturer,
ApiResponse
} from '../types/index.js';
export class LightspeedClient {
private client: AxiosInstance;
private config: LightspeedConfig;
constructor(config: LightspeedConfig) {
this.config = config;
const baseUrl = config.baseUrl || 'https://api.lightspeedapp.com/API/V3';
this.client = axios.create({
baseURL: baseUrl,
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${config.apiKey}`
},
timeout: 30000
});
// Add response interceptor for error handling
this.client.interceptors.response.use(
response => response,
error => {
console.error('Lightspeed API Error:', error.response?.data || error.message);
throw error;
}
);
}
private getAccountPath(): string {
return `/Account/${this.config.accountId}`;
}
// ========== PRODUCTS ==========
async getProducts(params?: { limit?: number; offset?: number; categoryID?: string }): Promise<ApiResponse<Product[]>> {
try {
const response = await this.client.get(`${this.getAccountPath()}/Item.json`, { params });
return { success: true, data: response.data.Item || [] };
} catch (error: any) {
return { success: false, error: error.message, details: error.response?.data };
}
}
async getProduct(productID: string): Promise<ApiResponse<Product>> {
try {
const response = await this.client.get(`${this.getAccountPath()}/Item/${productID}.json`);
return { success: true, data: response.data.Item };
} catch (error: any) {
return { success: false, error: error.message, details: error.response?.data };
}
}
async createProduct(product: Partial<Product>): Promise<ApiResponse<Product>> {
try {
const response = await this.client.post(`${this.getAccountPath()}/Item.json`, { Item: product });
return { success: true, data: response.data.Item };
} catch (error: any) {
return { success: false, error: error.message, details: error.response?.data };
}
}
async updateProduct(productID: string, updates: Partial<Product>): Promise<ApiResponse<Product>> {
try {
const response = await this.client.put(`${this.getAccountPath()}/Item/${productID}.json`, { Item: updates });
return { success: true, data: response.data.Item };
} catch (error: any) {
return { success: false, error: error.message, details: error.response?.data };
}
}
async deleteProduct(productID: string): Promise<ApiResponse<boolean>> {
try {
await this.client.delete(`${this.getAccountPath()}/Item/${productID}.json`);
return { success: true, data: true };
} catch (error: any) {
return { success: false, error: error.message, details: error.response?.data };
}
}
async getProductInventory(productID: string, shopID?: string): Promise<ApiResponse<ProductInventory[]>> {
try {
const params = shopID ? { shopID } : {};
const response = await this.client.get(`${this.getAccountPath()}/Item/${productID}/ItemShops.json`, { params });
return { success: true, data: response.data.ItemShop || [] };
} catch (error: any) {
return { success: false, error: error.message, details: error.response?.data };
}
}
async updateInventory(productID: string, shopID: string, qty: number): Promise<ApiResponse<ProductInventory>> {
try {
const response = await this.client.put(
`${this.getAccountPath()}/Item/${productID}/ItemShops/${shopID}.json`,
{ ItemShop: { qty } }
);
return { success: true, data: response.data.ItemShop };
} catch (error: any) {
return { success: false, error: error.message, details: error.response?.data };
}
}
// ========== CUSTOMERS ==========
async getCustomers(params?: { limit?: number; offset?: number; email?: string }): Promise<ApiResponse<Customer[]>> {
try {
const response = await this.client.get(`${this.getAccountPath()}/Customer.json`, { params });
return { success: true, data: response.data.Customer || [] };
} catch (error: any) {
return { success: false, error: error.message, details: error.response?.data };
}
}
async getCustomer(customerID: string): Promise<ApiResponse<Customer>> {
try {
const response = await this.client.get(`${this.getAccountPath()}/Customer/${customerID}.json`);
return { success: true, data: response.data.Customer };
} catch (error: any) {
return { success: false, error: error.message, details: error.response?.data };
}
}
async createCustomer(customer: Partial<Customer>): Promise<ApiResponse<Customer>> {
try {
const response = await this.client.post(`${this.getAccountPath()}/Customer.json`, { Customer: customer });
return { success: true, data: response.data.Customer };
} catch (error: any) {
return { success: false, error: error.message, details: error.response?.data };
}
}
async updateCustomer(customerID: string, updates: Partial<Customer>): Promise<ApiResponse<Customer>> {
try {
const response = await this.client.put(`${this.getAccountPath()}/Customer/${customerID}.json`, { Customer: updates });
return { success: true, data: response.data.Customer };
} catch (error: any) {
return { success: false, error: error.message, details: error.response?.data };
}
}
async deleteCustomer(customerID: string): Promise<ApiResponse<boolean>> {
try {
await this.client.delete(`${this.getAccountPath()}/Customer/${customerID}.json`);
return { success: true, data: true };
} catch (error: any) {
return { success: false, error: error.message, details: error.response?.data };
}
}
// ========== SALES ==========
async getSales(params?: { limit?: number; offset?: number; startDate?: string; endDate?: string }): Promise<ApiResponse<Sale[]>> {
try {
const response = await this.client.get(`${this.getAccountPath()}/Sale.json`, { params });
return { success: true, data: response.data.Sale || [] };
} catch (error: any) {
return { success: false, error: error.message, details: error.response?.data };
}
}
async getSale(saleID: string): Promise<ApiResponse<Sale>> {
try {
const response = await this.client.get(`${this.getAccountPath()}/Sale/${saleID}.json`);
return { success: true, data: response.data.Sale };
} catch (error: any) {
return { success: false, error: error.message, details: error.response?.data };
}
}
async createSale(sale: Partial<Sale>): Promise<ApiResponse<Sale>> {
try {
const response = await this.client.post(`${this.getAccountPath()}/Sale.json`, { Sale: sale });
return { success: true, data: response.data.Sale };
} catch (error: any) {
return { success: false, error: error.message, details: error.response?.data };
}
}
async updateSale(saleID: string, updates: Partial<Sale>): Promise<ApiResponse<Sale>> {
try {
const response = await this.client.put(`${this.getAccountPath()}/Sale/${saleID}.json`, { Sale: updates });
return { success: true, data: response.data.Sale };
} catch (error: any) {
return { success: false, error: error.message, details: error.response?.data };
}
}
async voidSale(saleID: string): Promise<ApiResponse<Sale>> {
try {
const response = await this.client.put(`${this.getAccountPath()}/Sale/${saleID}.json`, { Sale: { voided: true } });
return { success: true, data: response.data.Sale };
} catch (error: any) {
return { success: false, error: error.message, details: error.response?.data };
}
}
// ========== ORDERS ==========
async getOrders(params?: { limit?: number; offset?: number; status?: string }): Promise<ApiResponse<Order[]>> {
try {
const response = await this.client.get(`${this.getAccountPath()}/Order.json`, { params });
return { success: true, data: response.data.Order || [] };
} catch (error: any) {
return { success: false, error: error.message, details: error.response?.data };
}
}
async getOrder(orderID: string): Promise<ApiResponse<Order>> {
try {
const response = await this.client.get(`${this.getAccountPath()}/Order/${orderID}.json`);
return { success: true, data: response.data.Order };
} catch (error: any) {
return { success: false, error: error.message, details: error.response?.data };
}
}
async createOrder(order: Partial<Order>): Promise<ApiResponse<Order>> {
try {
const response = await this.client.post(`${this.getAccountPath()}/Order.json`, { Order: order });
return { success: true, data: response.data.Order };
} catch (error: any) {
return { success: false, error: error.message, details: error.response?.data };
}
}
async updateOrder(orderID: string, updates: Partial<Order>): Promise<ApiResponse<Order>> {
try {
const response = await this.client.put(`${this.getAccountPath()}/Order/${orderID}.json`, { Order: updates });
return { success: true, data: response.data.Order };
} catch (error: any) {
return { success: false, error: error.message, details: error.response?.data };
}
}
async deleteOrder(orderID: string): Promise<ApiResponse<boolean>> {
try {
await this.client.delete(`${this.getAccountPath()}/Order/${orderID}.json`);
return { success: true, data: true };
} catch (error: any) {
return { success: false, error: error.message, details: error.response?.data };
}
}
// ========== EMPLOYEES ==========
async getEmployees(params?: { limit?: number; offset?: number }): Promise<ApiResponse<Employee[]>> {
try {
const response = await this.client.get(`${this.getAccountPath()}/Employee.json`, { params });
return { success: true, data: response.data.Employee || [] };
} catch (error: any) {
return { success: false, error: error.message, details: error.response?.data };
}
}
async getEmployee(employeeID: string): Promise<ApiResponse<Employee>> {
try {
const response = await this.client.get(`${this.getAccountPath()}/Employee/${employeeID}.json`);
return { success: true, data: response.data.Employee };
} catch (error: any) {
return { success: false, error: error.message, details: error.response?.data };
}
}
async createEmployee(employee: Partial<Employee>): Promise<ApiResponse<Employee>> {
try {
const response = await this.client.post(`${this.getAccountPath()}/Employee.json`, { Employee: employee });
return { success: true, data: response.data.Employee };
} catch (error: any) {
return { success: false, error: error.message, details: error.response?.data };
}
}
async updateEmployee(employeeID: string, updates: Partial<Employee>): Promise<ApiResponse<Employee>> {
try {
const response = await this.client.put(`${this.getAccountPath()}/Employee/${employeeID}.json`, { Employee: updates });
return { success: true, data: response.data.Employee };
} catch (error: any) {
return { success: false, error: error.message, details: error.response?.data };
}
}
async deleteEmployee(employeeID: string): Promise<ApiResponse<boolean>> {
try {
await this.client.delete(`${this.getAccountPath()}/Employee/${employeeID}.json`);
return { success: true, data: true };
} catch (error: any) {
return { success: false, error: error.message, details: error.response?.data };
}
}
// ========== CATEGORIES ==========
async getCategories(params?: { limit?: number; offset?: number }): Promise<ApiResponse<Category[]>> {
try {
const response = await this.client.get(`${this.getAccountPath()}/Category.json`, { params });
return { success: true, data: response.data.Category || [] };
} catch (error: any) {
return { success: false, error: error.message, details: error.response?.data };
}
}
async getCategory(categoryID: string): Promise<ApiResponse<Category>> {
try {
const response = await this.client.get(`${this.getAccountPath()}/Category/${categoryID}.json`);
return { success: true, data: response.data.Category };
} catch (error: any) {
return { success: false, error: error.message, details: error.response?.data };
}
}
async createCategory(category: Partial<Category>): Promise<ApiResponse<Category>> {
try {
const response = await this.client.post(`${this.getAccountPath()}/Category.json`, { Category: category });
return { success: true, data: response.data.Category };
} catch (error: any) {
return { success: false, error: error.message, details: error.response?.data };
}
}
async updateCategory(categoryID: string, updates: Partial<Category>): Promise<ApiResponse<Category>> {
try {
const response = await this.client.put(`${this.getAccountPath()}/Category/${categoryID}.json`, { Category: updates });
return { success: true, data: response.data.Category };
} catch (error: any) {
return { success: false, error: error.message, details: error.response?.data };
}
}
async deleteCategory(categoryID: string): Promise<ApiResponse<boolean>> {
try {
await this.client.delete(`${this.getAccountPath()}/Category/${categoryID}.json`);
return { success: true, data: true };
} catch (error: any) {
return { success: false, error: error.message, details: error.response?.data };
}
}
// ========== SUPPLIERS ==========
async getSuppliers(params?: { limit?: number; offset?: number }): Promise<ApiResponse<Supplier[]>> {
try {
const response = await this.client.get(`${this.getAccountPath()}/Vendor.json`, { params });
return { success: true, data: response.data.Vendor || [] };
} catch (error: any) {
return { success: false, error: error.message, details: error.response?.data };
}
}
async getSupplier(supplierID: string): Promise<ApiResponse<Supplier>> {
try {
const response = await this.client.get(`${this.getAccountPath()}/Vendor/${supplierID}.json`);
return { success: true, data: response.data.Vendor };
} catch (error: any) {
return { success: false, error: error.message, details: error.response?.data };
}
}
async createSupplier(supplier: Partial<Supplier>): Promise<ApiResponse<Supplier>> {
try {
const response = await this.client.post(`${this.getAccountPath()}/Vendor.json`, { Vendor: supplier });
return { success: true, data: response.data.Vendor };
} catch (error: any) {
return { success: false, error: error.message, details: error.response?.data };
}
}
async updateSupplier(supplierID: string, updates: Partial<Supplier>): Promise<ApiResponse<Supplier>> {
try {
const response = await this.client.put(`${this.getAccountPath()}/Vendor/${supplierID}.json`, { Vendor: updates });
return { success: true, data: response.data.Vendor };
} catch (error: any) {
return { success: false, error: error.message, details: error.response?.data };
}
}
async deleteSupplier(supplierID: string): Promise<ApiResponse<boolean>> {
try {
await this.client.delete(`${this.getAccountPath()}/Vendor/${supplierID}.json`);
return { success: true, data: true };
} catch (error: any) {
return { success: false, error: error.message, details: error.response?.data };
}
}
// ========== DISCOUNTS ==========
async getDiscounts(params?: { limit?: number; offset?: number }): Promise<ApiResponse<Discount[]>> {
try {
const response = await this.client.get(`${this.getAccountPath()}/Discount.json`, { params });
return { success: true, data: response.data.Discount || [] };
} catch (error: any) {
return { success: false, error: error.message, details: error.response?.data };
}
}
async getDiscount(discountID: string): Promise<ApiResponse<Discount>> {
try {
const response = await this.client.get(`${this.getAccountPath()}/Discount/${discountID}.json`);
return { success: true, data: response.data.Discount };
} catch (error: any) {
return { success: false, error: error.message, details: error.response?.data };
}
}
async createDiscount(discount: Partial<Discount>): Promise<ApiResponse<Discount>> {
try {
const response = await this.client.post(`${this.getAccountPath()}/Discount.json`, { Discount: discount });
return { success: true, data: response.data.Discount };
} catch (error: any) {
return { success: false, error: error.message, details: error.response?.data };
}
}
async updateDiscount(discountID: string, updates: Partial<Discount>): Promise<ApiResponse<Discount>> {
try {
const response = await this.client.put(`${this.getAccountPath()}/Discount/${discountID}.json`, { Discount: updates });
return { success: true, data: response.data.Discount };
} catch (error: any) {
return { success: false, error: error.message, details: error.response?.data };
}
}
async deleteDiscount(discountID: string): Promise<ApiResponse<boolean>> {
try {
await this.client.delete(`${this.getAccountPath()}/Discount/${discountID}.json`);
return { success: true, data: true };
} catch (error: any) {
return { success: false, error: error.message, details: error.response?.data };
}
}
// ========== SHOPS & REGISTERS ==========
async getShops(): Promise<ApiResponse<Shop[]>> {
try {
const response = await this.client.get(`${this.getAccountPath()}/Shop.json`);
return { success: true, data: response.data.Shop || [] };
} catch (error: any) {
return { success: false, error: error.message, details: error.response?.data };
}
}
async getShop(shopID: string): Promise<ApiResponse<Shop>> {
try {
const response = await this.client.get(`${this.getAccountPath()}/Shop/${shopID}.json`);
return { success: true, data: response.data.Shop };
} catch (error: any) {
return { success: false, error: error.message, details: error.response?.data };
}
}
async getRegisters(shopID?: string): Promise<ApiResponse<Register[]>> {
try {
const params = shopID ? { shopID } : {};
const response = await this.client.get(`${this.getAccountPath()}/Register.json`, { params });
return { success: true, data: response.data.Register || [] };
} catch (error: any) {
return { success: false, error: error.message, details: error.response?.data };
}
}
// ========== MANUFACTURERS ==========
async getManufacturers(): Promise<ApiResponse<Manufacturer[]>> {
try {
const response = await this.client.get(`${this.getAccountPath()}/Manufacturer.json`);
return { success: true, data: response.data.Manufacturer || [] };
} catch (error: any) {
return { success: false, error: error.message, details: error.response?.data };
}
}
async createManufacturer(name: string): Promise<ApiResponse<Manufacturer>> {
try {
const response = await this.client.post(`${this.getAccountPath()}/Manufacturer.json`, { Manufacturer: { name } });
return { success: true, data: response.data.Manufacturer };
} catch (error: any) {
return { success: false, error: error.message, details: error.response?.data };
}
}
// ========== TAX CATEGORIES ==========
async getTaxCategories(): Promise<ApiResponse<TaxCategory[]>> {
try {
const response = await this.client.get(`${this.getAccountPath()}/TaxCategory.json`);
return { success: true, data: response.data.TaxCategory || [] };
} catch (error: any) {
return { success: false, error: error.message, details: error.response?.data };
}
}
// ========== PAYMENT TYPES ==========
async getPaymentTypes(): Promise<ApiResponse<PaymentType[]>> {
try {
const response = await this.client.get(`${this.getAccountPath()}/PaymentType.json`);
return { success: true, data: response.data.PaymentType || [] };
} catch (error: any) {
return { success: false, error: error.message, details: error.response?.data };
}
}
}