UNPKG

@fluentity/core

Version:

Fluentity is a fluent, model-oriented, typed HTTP client for TypeScript and framework agnostic.

284 lines (283 loc) 8.48 kB
import { DefaultAdapter } from './adapters/DefaultAdapter'; import { QueryBuilder } from './QueryBuilder'; /** * Interface for adapters that handle API communication. * Adapters must implement methods for making HTTP requests and configuration. * * @interface * @example * ```typescript * class CustomAdapter implements AdapterInterface { * async call(queryBuilder: QueryBuilder): Promise<AdapterResponse> { * // Make HTTP request * } * configure(options: Partial<AdapterOptions>): void { * // Configure adapter * } * } * ``` */ export interface AdapterInterface { /** * The options for the adapter. * Contains configuration settings specific to the adapter implementation. */ options: AdapterOptions; /** * Makes an API request using the adapter's implementation. * * @param queryBuilder - The query builder containing request details * @returns Promise resolving to the API response * @throws {Error} If the request fails */ call(queryBuilder: QueryBuilder): Promise<AdapterResponse>; /** * Configures the adapter with additional options. * * @param options - The configuration options to apply * @example * ```typescript * adapter.configure({ * baseURL: 'https://api.example.com', * timeout: 5000 * }); * ``` */ configure(options: Partial<AdapterOptions>): void; } /** * Base interface for adapter request options. * Can be extended with additional properties by specific adapters. * * @interface * @example * ```typescript * interface CustomAdapterOptions extends AdapterOptions { * apiKey: string; * retryCount: number; * } * ``` */ export type AdapterOptions = Record<string, unknown>; /** * Interface for adapter request data. * Represents the request structure that adapters use internally. * Can be extended by specific adapters to include additional request properties. * * @interface * @example * ```typescript * interface CustomAdapterRequest extends AdapterRequest { * headers: Record<string, string>; * timeout: number; * } * ``` */ export interface AdapterRequest { } /** * Interface for adapter responses. * Contains the response data from the API. * * @interface * @example * ```typescript * // For a single object response * const response: AdapterResponse<User> = { * data: { id: 1, name: 'John' } * }; * * // For an array response * const response: AdapterResponse<User[]> = { * data: [{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }] * }; * ``` */ export type AdapterResponse<T = unknown | any> = { /** The response data from the API */ data: T; }; /** * Configuration options for initializing Fluentity. * * @interface * @template A - The type of adapter to use * @example * ```typescript * const options: FluentityOptions<RestAdapter> = { * adapter: new RestAdapter() * }; * ``` */ export interface FluentityOptions<A extends AdapterInterface> { /** The adapter instance to use for API communication */ adapter?: A; } /** * Main Fluentity class that manages API communication. * Implements the singleton pattern to ensure a single instance is used throughout the application. * Handles adapter management and provides a central point for API communication. * * @class * @template A - The type of adapter being used * @example * ```typescript * // Initialize with custom adapter * Fluentity.initialize({ * adapter: new RestAdapter() * }); * * // Get instance * const fluentity = Fluentity.getInstance(); * * // Use the adapter * const response = await fluentity.adapter.call(queryBuilder); * ``` */ export declare class Fluentity<A extends AdapterInterface = DefaultAdapter> { #private; /** * Singleton instance of Fluentity. * @private */ private static instance; /** * Creates a new Fluentity instance. * Private constructor to enforce singleton pattern. * * @param {FluentityOptions<A>} [options] - Configuration options for Fluentity * @throws {Error} If a Fluentity instance already exists * @private */ private constructor(); /** * Configures the Fluentity instance with new options. * Updates the adapter and options for the singleton instance. * Must be called after initialization. * * @param options - Configuration options to apply * @throws {Error} If Fluentity has not been initialized * @example * ```typescript * // Configure with new adapter * fluentity.configure({ * adapter: new RestAdapter({ * baseURL: 'https://new-api.example.com' * }) * }); * * // Configure with error handling * try { * fluentity.configure({ adapter: new CustomAdapter() }); * console.log('Fluentity configured successfully'); * } catch (error) { * console.error('Configuration failed:', error); * } * ``` */ configure(options?: FluentityOptions<A>): void; /** * Gets the adapter instance used for API communication. * * @returns {A} The configured adapter instance * @public * @readonly */ get adapter(): A; /** * Initializes the Fluentity singleton instance. * Must be called before using any other Fluentity functionality. * * @param {FluentityOptions<A>} [options] - Configuration options for Fluentity * @returns {Fluentity<A>} The initialized Fluentity instance * @throws {Error} If Fluentity has already been initialized * @example * ```typescript * // Initialize with default adapter * Fluentity.initialize(); * * // Initialize with custom adapter * Fluentity.initialize({ * adapter: new RestAdapter({ * baseURL: 'https://api.example.com' * }) * }); * ``` */ static initialize<A extends AdapterInterface>(options?: FluentityOptions<A>): Fluentity<A>; /** * Resets the Fluentity singleton instance. * Clears the singleton instance, allowing for re-initialization. * Useful for testing or when you need to change the adapter completely. * * @example * ```typescript * // Reset for testing * Fluentity.reset(); * * // Re-initialize with different adapter * Fluentity.initialize({ * adapter: new TestAdapter() * }); * * // Reset in cleanup * afterEach(() => { * Fluentity.reset(); * }); * ``` */ static reset(): void; /** * Gets the Fluentity singleton instance. * * @returns {Fluentity<A>} The Fluentity instance * @throws {Error} If Fluentity has not been initialized * @example * ```typescript * // Get the instance after initialization * const fluentity = Fluentity.getInstance<CustomAdapter>(); * * // The adapter type is automatically inferred * const adapter = fluentity.adapter; * ``` */ static getInstance<A extends AdapterInterface = DefaultAdapter>(): Fluentity<A>; /** * Calls the adapter with the given query builder. * @param queryBuilder - The query builder to use * @returns The adapter response * @public */ call(queryBuilder: QueryBuilder): Promise<AdapterResponse>; /** * Calls the adapter with the given query builder using the singleton instance. * Static convenience method that automatically gets the singleton instance. * * @param queryBuilder - The query builder to use for the request * @returns Promise resolving to the adapter response * @throws {Error} If Fluentity has not been initialized * @example * ```typescript * // Make a direct call * const response = await Fluentity.call(queryBuilder); * * // Use in custom methods * async function customQuery() { * const query = new QueryBuilder() * .where({ status: 'active' }) * .limit(10); * return await Fluentity.call(query); * } * * // Call with error handling * try { * const response = await Fluentity.call(queryBuilder); * console.log('Request successful:', response.data); * } catch (error) { * console.error('Request failed:', error); * } * ``` */ static call(queryBuilder: QueryBuilder): Promise<AdapterResponse>; } export type { QueryBuilder } from './QueryBuilder';