@smartsamurai/krapi-sdk
Version:
KRAPI TypeScript SDK - Easy-to-use client SDK for connecting to self-hosted KRAPI servers (like Appwrite SDK)
187 lines (174 loc) • 6.54 kB
text/typescript
/**
* Activity HTTP Client for KRAPI SDK
*
* HTTP-based activity logging for frontend applications.
* Provides activity logging, querying, and statistics.
*
* @module http-clients/activity-http-client
* @example
* const client = new ActivityHttpClient({ baseUrl: 'https://api.example.com' });
* await client.log({ action: 'created', resource_type: 'document' });
*/
import { ActivityLog, ActivityQuery } from "../activity-logger";
import { ApiResponse, PaginatedResponse } from "../core";
import { KrapiError } from "../core/krapi-error";
import { BaseHttpClient } from "./base-http-client";
/**
* Activity HTTP Client
*
* HTTP client for activity logging operations.
*
* @class ActivityHttpClient
* @extends {BaseHttpClient}
*/
export class ActivityHttpClient extends BaseHttpClient {
/**
* Log an activity event
*
* @param {Omit<ActivityLog, "id" | "timestamp">} activityData - Activity data
* @returns {Promise<ApiResponse<ActivityLog>>} Created activity log
*/
async log(
activityData: Omit<ActivityLog, "id" | "timestamp">
): Promise<ApiResponse<ActivityLog>> {
return this.post<ActivityLog>("/activity/log", activityData);
}
/**
* Query activity logs
*
* @param {ActivityQuery} query - Query parameters
* @returns {Promise<PaginatedResponse<ActivityLog>>} Activity logs with pagination
*/
async query(
query: ActivityQuery
): Promise<ApiResponse<PaginatedResponse<ActivityLog>>> {
const params = new URLSearchParams();
if (query.user_id) params.append("user_id", query.user_id);
if (query.project_id) params.append("project_id", query.project_id);
if (query.action) params.append("action", query.action);
if (query.resource_type)
params.append("resource_type", query.resource_type);
if (query.resource_id) params.append("resource_id", query.resource_id);
if (query.severity) params.append("severity", query.severity);
if (query.start_date) {
// Ensure start_date is a Date object before calling toISOString()
const startDate =
query.start_date instanceof Date
? query.start_date
: new Date(query.start_date);
// Validate date is not invalid
if (isNaN(startDate.getTime())) {
throw KrapiError.validationError("Invalid start_date provided to activity query", "start_date");
}
params.append("start_date", startDate.toISOString());
}
if (query.end_date) {
// Ensure end_date is a Date object before calling toISOString()
const endDate =
query.end_date instanceof Date
? query.end_date
: new Date(query.end_date);
// Validate date is not invalid
if (isNaN(endDate.getTime())) {
throw KrapiError.validationError("Invalid end_date provided to activity query", "end_date");
}
params.append("end_date", endDate.toISOString());
}
if (query.limit) params.append("limit", query.limit.toString());
if (query.offset) params.append("offset", query.offset.toString());
// Build URL - handle case where no parameters are provided
const queryString = params.toString();
const endpoint = queryString
? `/activity/query?${queryString}`
: `/activity/query`;
return this.get<PaginatedResponse<ActivityLog>>(endpoint);
}
/**
* Get activity statistics
*
* @param {string} [projectId] - Optional project ID
* @param {number} [days=30] - Number of days to analyze
* @returns {Promise<ApiResponse<{ total_actions: number; actions_by_type: Record<string, number>; actions_by_severity: Record<string, number>; actions_by_user: Record<string, number> }>>} Activity statistics
*/
async getStats(
projectId?: string,
days = 30
): Promise<
ApiResponse<{
total_actions: number;
actions_by_type: Record<string, number>;
actions_by_severity: Record<string, number>;
actions_by_user: Record<string, number>;
}>
> {
const params = new URLSearchParams();
if (projectId) params.append("project_id", projectId);
params.append("days", days.toString());
return this.get(`/activity/stats?${params.toString()}`);
}
/**
* Get recent activity
*
* @param {string} [userId] - Optional user ID
* @param {string} [projectId] - Optional project ID
* @param {number} [limit=50] - Maximum number of results
* @returns {Promise<ApiResponse<ActivityLog[]>>} Recent activity logs
*/
async getRecent(
userId?: string,
projectId?: string,
limit = 50
): Promise<ApiResponse<ActivityLog[]>> {
const params = new URLSearchParams();
if (userId) params.append("user_id", userId);
if (projectId) params.append("project_id", projectId);
params.append("limit", limit.toString());
return this.get<ActivityLog[]>(`/activity/recent?${params.toString()}`);
}
/**
* Get user timeline
*
* @param {string} userId - User ID
* @param {Object} [options] - Query options
* @param {number} [options.limit] - Maximum number of results
* @param {number} [options.offset] - Number of results to skip
* @param {Date} [options.start_date] - Start date filter
* @param {Date} [options.end_date] - End date filter
* @returns {Promise<PaginatedResponse<ActivityLog>>} User activity timeline
*/
async getUserTimeline(
userId: string,
options?: {
limit?: number;
offset?: number;
start_date?: Date;
end_date?: Date;
}
): Promise<ApiResponse<PaginatedResponse<ActivityLog>>> {
const params = new URLSearchParams();
params.append("user_id", userId);
if (options?.limit) params.append("limit", options.limit.toString());
if (options?.offset) params.append("offset", options.offset.toString());
if (options?.start_date)
params.append("start_date", options.start_date.toISOString());
if (options?.end_date)
params.append("end_date", options.end_date.toISOString());
return this.get<PaginatedResponse<ActivityLog>>(
`/activity/users/${userId}/timeline?${params.toString()}`
);
}
/**
* Cleanup old activity logs
*
* @param {number} [daysToKeep=90] - Number of days to keep
* @returns {Promise<ApiResponse<{ success: boolean; deleted_count: number }>>} Cleanup result
*/
async cleanup(
daysToKeep = 90
): Promise<ApiResponse<{ success: boolean; deleted_count: number }>> {
return this.post<{ success: boolean; deleted_count: number }>(
"/activity/cleanup",
{ days_to_keep: daysToKeep }
);
}
}