zdata-client
Version:
TypeScript client library for zdata backend API with authentication and full CRUD operations
557 lines (538 loc) • 20.1 kB
text/typescript
import { z, ZodSchema } from 'zod';
declare const ApiConfigSchema: z.ZodObject<{
baseUrl: z.ZodString;
workspaceId: z.ZodString;
timeout: z.ZodOptional<z.ZodNumber>;
headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
}, z.core.$strip>;
declare const LoginRequestSchema: z.ZodObject<{
email: z.ZodString;
password: z.ZodString;
}, z.core.$strip>;
declare const RegisterRequestSchema: z.ZodObject<{
name: z.ZodString;
email: z.ZodString;
password: z.ZodString;
}, z.core.$strip>;
declare const FindRecordsParamsSchema: z.ZodObject<{
resourceName: z.ZodString;
search: z.ZodOptional<z.ZodString>;
page: z.ZodOptional<z.ZodNumber>;
limit: z.ZodOptional<z.ZodNumber>;
}, z.core.$strip>;
declare const BaseEntitySchema: z.ZodObject<{
id: z.ZodString;
created_at: z.ZodString;
updated_at: z.ZodString;
}, z.core.$strip>;
declare const PaginationMetaSchema: z.ZodObject<{
activePageNumber: z.ZodNumber;
limit: z.ZodNumber;
totalRecords: z.ZodNumber;
totalPages: z.ZodNumber;
hasNext: z.ZodBoolean;
hasPrev: z.ZodBoolean;
}, z.core.$strip>;
declare const AuthResponseSchema: z.ZodObject<{
access_token: z.ZodString;
expires_in: z.ZodNumber;
token_type: z.ZodString;
user: z.ZodObject<{
id: z.ZodString;
email: z.ZodString;
name: z.ZodString;
}, z.core.$strip>;
}, z.core.$strip>;
declare const UserSchema: z.ZodObject<{
id: z.ZodString;
email: z.ZodString;
name: z.ZodString;
}, z.core.$strip>;
declare const ApiErrorSchema: z.ZodObject<{
message: z.ZodString;
errors: z.ZodOptional<z.ZodArray<z.ZodObject<{
field: z.ZodString;
message: z.ZodString;
}, z.core.$strip>>>;
}, z.core.$strip>;
declare const LoggedUserSchema: z.ZodObject<{
id: z.ZodString;
name: z.ZodString;
email: z.ZodString;
settings: z.ZodObject<{
themeMode: z.ZodEnum<{
light: "light";
dark: "dark";
}>;
}, z.core.$strip>;
}, z.core.$strip>;
declare const UpdateLoggedUserSchema: z.ZodObject<{
name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
themeMode: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
light: "light";
dark: "dark";
}>>>;
}, z.core.$strip>;
type ApiConfig = z.infer<typeof ApiConfigSchema>;
type LoginRequest = z.infer<typeof LoginRequestSchema>;
type RegisterRequest = z.infer<typeof RegisterRequestSchema>;
type FindRecordsParams = z.infer<typeof FindRecordsParamsSchema>;
type BaseEntity = z.infer<typeof BaseEntitySchema>;
type PaginationMeta = z.infer<typeof PaginationMetaSchema>;
type AuthResponse = z.infer<typeof AuthResponseSchema>;
type User = z.infer<typeof UserSchema>;
type ApiError = z.infer<typeof ApiErrorSchema>;
type LoggedUser = z.infer<typeof LoggedUserSchema>;
type UpdateLoggedUser = z.infer<typeof UpdateLoggedUserSchema>;
declare const MetricsResponseSchema: z.ZodObject<{
entity: z.ZodString;
workspace: z.ZodString;
metrics: z.ZodRecord<z.ZodString, z.ZodObject<{
type: z.ZodString;
title: z.ZodOptional<z.ZodString>;
description: z.ZodOptional<z.ZodString>;
stats: z.ZodUnion<readonly [z.ZodObject<{
sum: z.ZodNumber;
average: z.ZodNumber;
minimum: z.ZodNumber;
maximum: z.ZodNumber;
count: z.ZodNumber;
totalRecords: z.ZodNumber;
standardDeviation: z.ZodNumber;
nullCount: z.ZodNumber;
}, z.core.$strip>, z.ZodObject<{
distribution: z.ZodArray<z.ZodObject<{
value: z.ZodString;
count: z.ZodNumber;
percentage: z.ZodNumber;
}, z.core.$strip>>;
totalRecords: z.ZodNumber;
nonNullRecords: z.ZodNumber;
nullCount: z.ZodNumber;
uniqueValues: z.ZodNumber;
mostCommon: z.ZodString;
}, z.core.$strip>, z.ZodObject<{
distribution: z.ZodArray<z.ZodObject<{
value: z.ZodString;
count: z.ZodNumber;
percentage: z.ZodNumber;
}, z.core.$strip>>;
trueCount: z.ZodNumber;
falseCount: z.ZodNumber;
nullCount: z.ZodNumber;
totalRecords: z.ZodNumber;
truePercentage: z.ZodNumber;
falsePercentage: z.ZodNumber;
nullPercentage: z.ZodNumber;
}, z.core.$strip>, z.ZodObject<{
earliest: z.ZodString;
latest: z.ZodString;
count: z.ZodNumber;
totalRecords: z.ZodNumber;
nullCount: z.ZodNumber;
yearDistribution: z.ZodArray<z.ZodObject<{
year: z.ZodNumber;
count: z.ZodNumber;
}, z.core.$strip>>;
mostActiveYear: z.ZodNumber;
}, z.core.$strip>, z.ZodObject<{
message: z.ZodString;
}, z.core.$strip>]>;
}, z.core.$strip>>;
}, z.core.$strip>;
type MetricsResponse = z.infer<typeof MetricsResponseSchema>;
declare function login(baseUrl: string, workspaceId: string, credentials: LoginRequest, timeout?: number): Promise<AuthResponse>;
declare function register(baseUrl: string, workspaceId: string, userData: RegisterRequest, timeout?: number): Promise<AuthResponse>;
interface Cache {
get<T>(key: string): T | null;
set<T>(key: string, value: T, ttlMs: number): void;
delete(key: string): void;
clear(): void;
has(key: string): boolean;
}
interface CacheConfig {
readonly defaultTtlMs: number;
readonly maxSize?: number;
}
declare enum CacheStrategy {
MEMORY = "memory",
LOCAL_STORAGE = "localStorage",
SESSION_STORAGE = "sessionStorage"
}
interface PaginatedResponse<T> {
readonly records: readonly T[];
readonly meta: {
readonly activePageNumber: number;
readonly limit: number;
readonly totalRecords: number;
readonly totalPages: number;
readonly hasNext: boolean;
readonly hasPrev: boolean;
};
}
declare class ResourceRepository {
private readonly cache?;
private static readonly CACHE_TTL_MS;
private static readonly DEFAULT_PAGE_SIZE;
private readonly httpClient;
private readonly accessToken;
constructor(baseUrl: string, workspaceId: string, accessToken: string, timeout?: number, cache?: Cache | undefined);
createRecord<T>(resourceName: string, data: unknown): Promise<T & {
id: string;
created_at: string;
updated_at: string;
}>;
updateRecord<T>(resourceName: string, id: string, data: unknown): Promise<T & {
id: string;
created_at: string;
updated_at: string;
}>;
deleteRecord(resourceName: string, id: string): Promise<void>;
findRecordById<T>(resourceName: string, id: string): Promise<T & {
id: string;
created_at: string;
updated_at: string;
}>;
findRecords<T>(params: FindRecordsParams): Promise<PaginatedResponse<T & {
id: string;
created_at: string;
updated_at: string;
}>>;
private validateResourceName;
private validateId;
private buildSearchParams;
private handleError;
private getCacheKey;
private invalidateCacheForResource;
private invalidateCacheForRecord;
getMetrics(resourceName: string, fields?: string[]): Promise<MetricsResponse>;
private getAuthHeader;
}
declare class LoggedUserClient {
private readonly httpClient;
private readonly accessToken;
constructor(baseUrl: string, workspaceId: string, accessToken: string, timeout?: number);
getProfile(): Promise<LoggedUser>;
updateProfile(data: UpdateLoggedUser): Promise<LoggedUser>;
private handleError;
private getAuthHeader;
}
/**
* @fileoverview Base client for creating custom data sources using the refactored architecture
*/
/**
* Utility type to create entity input without base fields
*/
type CreateEntity<T> = Omit<T, 'id' | 'created_at' | 'updated_at'>;
/**
* Utility type to represent entity with base fields
*/
type EntityWithBase<T> = T & BaseEntity;
/**
* Abstract base class for creating custom data source clients
*
* This class wraps ResourceRepository and provides a foundation for creating
* type-safe data access layers for specific entities. It allows developers
* to create strongly-typed wrappers around the generic CRUD operations.
*
* @template T - The entity type this client manages
*
* @example
* ```typescript
* interface Payment {
* amount: number;
* description: string;
* userId: string;
* }
*
* class PaymentClient extends BaseDataSourceClient<Payment> {
* constructor(baseUrl: string, workspaceId: string, accessToken: string) {
* super(baseUrl, workspaceId, accessToken, 'pagamentos');
* }
*
* // Optional: Add custom business logic methods
* async findPaymentsByUser(userId: string) {
* return this.find({
* search: `user:${userId}`,
* });
* }
* }
* ```
*/
declare abstract class BaseDataSourceClient<T> {
protected readonly repository: ResourceRepository;
protected readonly resourceName: string;
/**
* Create a new data source client instance
*
* @param baseUrl - API base URL
* @param workspaceId - Workspace ID
* @param accessToken - Access token for authentication
* @param resourceName - The name of the resource/endpoint (e.g., 'users', 'payments')
* @param timeout - Request timeout in milliseconds
*/
constructor(baseUrl: string, workspaceId: string, accessToken: string, resourceName: string, timeout?: number);
/**
* Create a new record of type T
*
* @param data - Record data without base fields
* @returns Promise resolving to created record with base fields
*/
create(data: CreateEntity<T>): Promise<EntityWithBase<T>>;
/**
* Find a record by its ID
*
* @param id - Record ID
* @returns Promise resolving to the record or null if not found
*/
findById(id: string): Promise<EntityWithBase<T> | null>;
/**
* Find records with pagination and search
*
* @param params - Search and pagination parameters
* @returns Promise resolving to paginated results
*/
find(params?: Omit<FindRecordsParams, 'resourceName'>): Promise<PaginatedResponse<EntityWithBase<T>>>;
/**
* Update a record by its ID
*
* @param id - Record ID
* @param data - Partial data to update
* @returns Promise resolving to updated record
*/
update(id: string, data: Partial<CreateEntity<T>>): Promise<EntityWithBase<T>>;
/**
* Delete a record by its ID
*
* @param id - Record ID
* @returns Promise resolving when record is deleted
*/
delete(id: string): Promise<void>;
/**
* Get metrics for this resource
*
* @param fields - Optional array of field names to analyze. If not provided, analyzes all fields
* @returns Promise resolving to metrics data
*/
getMetrics(fields?: (keyof T)[]): Promise<MetricsResponse>;
/**
* Get the resource name for this client
*
* @returns The resource name
*/
getResourceName(): string;
}
/**
* Concrete implementation of BaseDataSourceClient for easy instantiation
*
* This class provides a ready-to-use implementation without requiring
* inheritance. Useful for simple cases where you don't need custom methods.
*
* @template T - The entity type this client manages
*
* @example
* ```typescript
* interface User {
* name: string;
* email: string;
* }
*
* const userClient = new DataSourceClient<User>(
* 'https://api.example.com',
* 'workspace-1',
* 'access-token',
* 'users'
* );
* const users = await userClient.find({ page: 1, limit: 10 });
* ```
*/
declare class DataSourceClient<T> extends BaseDataSourceClient<T> {
/**
* Create a new data source client instance
*
* @param baseUrl - API base URL
* @param workspaceId - Workspace ID
* @param accessToken - Access token for authentication
* @param resourceName - The name of the resource/endpoint
* @param timeout - Request timeout in milliseconds
*/
constructor(baseUrl: string, workspaceId: string, accessToken: string, resourceName: string, timeout?: number);
}
interface ValidationErrorDetail {
readonly code: string;
readonly path: readonly string[];
readonly message: string;
}
declare class InvalidCredentialsError extends Error {
readonly name = "InvalidCredentialsError";
constructor(message?: string);
}
declare class ValidationError extends Error {
readonly name = "ValidationError";
readonly errors: readonly ValidationErrorDetail[];
constructor(message?: string, errors?: readonly ValidationErrorDetail[]);
}
declare class ApiClientError extends Error {
readonly name = "ApiClientError";
readonly statusCode?: number;
constructor(message: string, statusCode?: number);
}
declare function isInvalidCredentialsError(error: unknown): error is InvalidCredentialsError;
declare function isValidationError(error: unknown): error is ValidationError;
declare function isApiClientError(error: unknown): error is ApiClientError;
interface HttpRequest {
readonly url: string;
readonly method: 'GET' | 'POST' | 'PUT' | 'DELETE';
readonly headers?: Record<string, string>;
readonly data?: unknown;
readonly params?: Record<string, string>;
readonly timeout?: number;
}
interface HttpResponse<T = unknown> {
readonly data: T;
readonly status: number;
readonly headers: Record<string, string>;
}
interface HttpClient {
request<T = unknown>(request: HttpRequest): Promise<HttpResponse<T>>;
}
declare class AxiosHttpClient implements HttpClient {
private readonly instance;
constructor(baseURL: string, defaultTimeout?: number);
request<T = unknown>(request: HttpRequest): Promise<HttpResponse<T>>;
private handleError;
}
declare class MemoryCache implements Cache {
private readonly cache;
private readonly defaultTtlMs;
private readonly maxSize?;
constructor(config: CacheConfig);
get<T>(key: string): T | null;
set<T>(key: string, value: T, ttlMs?: number): void;
delete(key: string): void;
clear(): void;
has(key: string): boolean;
size(): number;
cleanup(): void;
}
declare class Validator {
static validate<T>(schema: ZodSchema<T>, data: unknown): T;
static validateSafely<T>(schema: ZodSchema<T>, data: unknown): {
success: true;
data: T;
} | {
success: false;
error: ValidationError;
};
private static mapZodErrorsToValidationDetails;
}
interface RetryConfig {
readonly maxAttempts: number;
readonly baseDelayMs: number;
readonly maxDelayMs: number;
readonly backoffMultiplier: number;
readonly jitterMs: number;
}
declare class RetryPolicy {
private readonly config;
constructor(config?: RetryConfig);
execute<T>(operation: () => Promise<T>): Promise<T>;
private shouldRetry;
private isRetryableStatusCode;
private calculateDelay;
private delay;
}
/**
* @fileoverview Interface defining the contract for the API client
*/
/**
* Interface defining the contract for the API client
* Provides authentication and CRUD operations for the zdata backend
*/
interface IApiClient {
/**
* Authenticate user with email and password
* @param credentials - User login credentials
* @returns Promise resolving to authentication response
* @throws {InvalidCredentialsError} When credentials are invalid
* @throws {ApiClientError} When API request fails
*/
login(credentials: LoginRequest): Promise<AuthResponse>;
/**
* Register a new user account
* @param userData - User registration data
* @returns Promise resolving to authentication response
* @throws {ValidationError} When registration data is invalid
* @throws {ApiClientError} When API request fails
*/
register(userData: RegisterRequest): Promise<AuthResponse>;
/**
* Clear authentication token and log out user
*/
logout(): void;
/**
* Check if user is currently authenticated
* @returns True if user has a valid access token
*/
isAuthenticated(): boolean;
/**
* Create a new record in the specified resource
* @template T - The entity type to create
* @param resourceName - Name of the resource
* @param data - Record data to create
* @returns Promise resolving to the created record with base entity fields
* @throws {ValidationError} When record data is invalid
* @throws {ApiClientError} When API request fails
*/
createRecord<T = unknown>(resourceName: string, data: CreateEntity<T>): Promise<EntityWithBase<T>>;
/**
* Find a single record by its ID
* @template T - The entity type to retrieve
* @param resourceName - Name of the resource
* @param id - Record ID to find
* @returns Promise resolving to the record
* @throws {ApiClientError} When record is not found or API request fails
*/
findRecordById<T = unknown>(resourceName: string, id: string): Promise<EntityWithBase<T>>;
/**
* Find multiple records with pagination and search
* @template T - The entity type to retrieve
* @param params - Search and pagination parameters
* @returns Promise resolving to paginated results
* @throws {ValidationError} When query parameters are invalid
* @throws {ApiClientError} When API request fails
*/
findRecords<T = unknown>(params: FindRecordsParams): Promise<PaginatedResponse<EntityWithBase<T>>>;
/**
* Update an existing record
* @template T - The entity type to update
* @param resourceName - Name of the resource
* @param id - Record ID to update
* @param data - Partial data to update
* @returns Promise resolving to the updated record
* @throws {ValidationError} When update data is invalid
* @throws {ApiClientError} When record is not found or API request fails
*/
updateRecord<T = unknown>(resourceName: string, id: string, data: Partial<CreateEntity<T>>): Promise<EntityWithBase<T>>;
/**
* Delete a record by its ID
* @param resourceName - Name of the resource
* @param id - Record ID to delete
* @returns Promise resolving when record is deleted
* @throws {ApiClientError} When record is not found or API request fails
*/
deleteRecord(resourceName: string, id: string): Promise<void>;
/**
* Set the access token for authentication
* @param token - JWT access token
*/
setAccessToken(token: string): void;
/**
* Get the current access token
* @returns Current access token or null if not set
*/
getAccessToken(): string | null;
}
declare function createRepository(baseUrl: string, workspaceId: string, accessToken: string, timeout?: number): ResourceRepository;
declare const VERSION = "2.0.0";
export { ApiClientError, type ApiConfig, ApiConfigSchema, type ApiError, ApiErrorSchema, type AuthResponse, AuthResponseSchema, AxiosHttpClient, BaseDataSourceClient, type BaseEntity, BaseEntitySchema, type Cache, type CacheConfig, CacheStrategy, type CreateEntity, DataSourceClient, type EntityWithBase, type FindRecordsParams, FindRecordsParamsSchema, type HttpClient, type HttpRequest, type HttpResponse, type IApiClient, InvalidCredentialsError, type LoggedUser, LoggedUserClient, LoggedUserSchema, type LoginRequest, LoginRequestSchema, MemoryCache, type PaginatedResponse, type PaginationMeta, PaginationMetaSchema, type RegisterRequest, RegisterRequestSchema, ResourceRepository, type RetryConfig, RetryPolicy, type UpdateLoggedUser, UpdateLoggedUserSchema, type User, UserSchema, VERSION, ValidationError, type ValidationErrorDetail, Validator, createRepository, ResourceRepository as default, isApiClientError, isInvalidCredentialsError, isValidationError, login, register };