// cronozen-client.ts
import axios, { AxiosInstance } from 'axios';
interface CronozenConfig {
baseUrl?: string;
token?: string;
}
interface LoginParams {
email: string;
password: string;
centerDomain?: string;
}
interface AuthResponse {
accessToken: string;
refreshToken: string;
expiresIn: number;
actor: {
id: string;
email: string;
name: string;
role: 'ADMIN' | 'INSTRUCTOR' | 'PARENT' | 'CHILD';
};
center: {
id: number;
name: string;
domain: string;
};
}
interface DPURecord {
id: string;
content: string;
evidenceLevel: 'DRAFT' | 'DOCUMENTED' | 'AUDIT_READY';
chainHash: string;
chainIndex: number;
createdAt: string;
}
class CronozenClient {
private http: AxiosInstance;
private token: string | null = null;
constructor(config: CronozenConfig = {}) {
this.http = axios.create({
baseURL: config.baseUrl || 'https://cronozen.com/api',
headers: { 'Content-Type': 'application/json' },
});
if (config.token) {
this.setToken(config.token);
}
// Auto-refresh on 401
this.http.interceptors.response.use(
(res) => res,
async (err) => {
if (err.response?.status === 401 && this.token) {
// Token expired — caller should handle refresh
throw new Error('Token expired. Call client.auth.refresh()');
}
throw err;
}
);
}
setToken(token: string) {
this.token = token;
this.http.defaults.headers.common['Authorization'] = `Bearer ${token}`;
}
// ── Auth ────────────────────────────────────────
auth = {
login: async (params: LoginParams): Promise<AuthResponse> => {
const { data } = await this.http.post('/auth/login', params);
if (data.success) {
this.setToken(data.data.accessToken);
}
return data.data;
},
me: async () => {
const { data } = await this.http.get('/auth/me');
return data.data;
},
switchCenter: async (centerId: number): Promise<AuthResponse> => {
const { data } = await this.http.post('/auth/switch-center', { centerId });
if (data.success) {
this.setToken(data.data.accessToken);
}
return data.data;
},
refresh: async (refreshToken: string): Promise<AuthResponse> => {
const { data } = await this.http.post('/auth/refresh-token', { refreshToken });
if (data.success) {
this.setToken(data.data.accessToken);
}
return data.data;
},
ssoToken: async (targetApp: 'lms' | 'cms' | 'erp') => {
const { data } = await this.http.post('/auth/sso/token', { targetApp });
return data.data;
},
};
// ── Centers ─────────────────────────────────────
centers = {
get: async (domain: string) => {
const { data } = await this.http.get(`/centers/${domain}`);
return data.data;
},
info: async (domain: string) => {
const { data } = await this.http.get(`/centers/${domain}/info`);
return data.data;
},
instructors: async (domain: string) => {
const { data } = await this.http.get(`/centers/${domain}/instructors`);
return data.data;
},
search: async (query: string, vertical?: string) => {
const { data } = await this.http.post('/centers/search', { query, vertical });
return data.data;
},
availableSlots: async (domain: string, date: string, instructorId?: string) => {
const params = new URLSearchParams({ date });
if (instructorId) params.set('instructorId', instructorId);
const { data } = await this.http.get(`/centers/${domain}/available-slots?${params}`);
return data.data;
},
};
// ── DPU ─────────────────────────────────────────
dpu = {
get: async (id: string): Promise<DPURecord> => {
const { data } = await this.http.get(`/dpu/${id}`);
return data.data;
},
create: async (params: {
content: string;
referenceType: string;
referenceId?: string;
tags?: string[];
}): Promise<DPURecord> => {
const { data } = await this.http.post('/dpu/demo', params);
return data.data;
},
verify: async (id: string) => {
const { data } = await this.http.get(`/dpu/${id}/verify`);
return data.data;
},
export: async (id: string) => {
const { data } = await this.http.get(`/dpu/${id}/export`);
return data.data;
},
stats: async () => {
const { data } = await this.http.get('/dpu/stats');
return data.data;
},
};
// ── Partner ─────────────────────────────────────
partner = {
centers: async (page = 1, limit = 50) => {
const { data } = await this.http.get(`/partner/centers?page=${page}&limit=${limit}`);
return data;
},
createCenter: async (params: {
name: string;
tenantType: string;
vertical: string;
adminEmail: string;
}) => {
const { data } = await this.http.post('/partner/centers', params);
return data.data;
},
dashboard: async () => {
const { data } = await this.http.get('/partner/stats/dashboard');
return data.data;
},
audit: async (page = 1) => {
const { data } = await this.http.get(`/partner/audit?page=${page}`);
return data;
},
members: async (page = 1) => {
const { data } = await this.http.get(`/partner/members?page=${page}`);
return data;
},
};
}
export { CronozenClient };
export type { CronozenConfig, LoginParams, AuthResponse, DPURecord };