@mysteryinfosolutions/api-core 1.9.0 → 1.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -286,7 +286,7 @@ const sortObjectToString = (sortItems) => {
286
286
  /**
287
287
  * Converts a filter object into a URL query string.
288
288
  *
289
- * @param filter Filter object with query parameters
289
+ * @param filter Filter object with query parameters (any object type)
290
290
  * @returns URL query string with '?' prefix, or empty string if no parameters
291
291
  *
292
292
  * @remarks
@@ -294,6 +294,7 @@ const sortObjectToString = (sortItems) => {
294
294
  * - Encodes all values for URL safety
295
295
  * - Filters out undefined and null values
296
296
  * - Arrays are encoded as comma-separated values in brackets
297
+ * - Works with any object type, including custom filter interfaces
297
298
  *
298
299
  * @example
299
300
  * const filter = {
@@ -305,11 +306,22 @@ const sortObjectToString = (sortItems) => {
305
306
  * };
306
307
  * const queryString = jsonToQueryString(filter);
307
308
  * // Returns: "?page=1&pageLength=25&search=John%20Doe&roles=[admin,user]&sort=name:ASC"
309
+ *
310
+ * @example
311
+ * // Works with custom filter interfaces
312
+ * interface StockFilter extends Filter {
313
+ * itemVariantIds?: number[];
314
+ * }
315
+ * const stockFilter: StockFilter = {
316
+ * page: 1,
317
+ * itemVariantIds: [1, 2, 3]
318
+ * };
319
+ * jsonToQueryString(stockFilter); // ✅ Works!
308
320
  */
309
321
  const jsonToQueryString = (filter) => {
310
322
  if (!filter || typeof filter !== 'object')
311
323
  return '';
312
- // Clone to avoid mutating original
324
+ // Clone to avoid mutating original - cast to any to handle any object type
313
325
  const params = { ...filter };
314
326
  // Convert sort array to string format
315
327
  if ('sort' in params && Array.isArray(params['sort'])) {
@@ -332,7 +344,7 @@ const jsonToQueryString = (filter) => {
332
344
  /**
333
345
  * Checks if an object is empty (has no own properties).
334
346
  *
335
- * @param obj Object to check
347
+ * @param obj Object to check (any object type, null, or undefined)
336
348
  * @returns True if object is null, undefined, or has no properties
337
349
  *
338
350
  * @example
@@ -341,9 +353,23 @@ const jsonToQueryString = (filter) => {
341
353
  * isEmpty(undefined); // true
342
354
  * isEmpty({ page: 1 }); // false
343
355
  * isEmpty([]); // true (arrays with no length)
356
+ *
357
+ * @example
358
+ * // Works with any object type
359
+ * interface MyType { id: number; name: string; }
360
+ * const myObj: MyType = { id: 1, name: 'test' };
361
+ * isEmpty(myObj); // false
344
362
  */
345
363
  const isEmpty = (obj) => {
346
- return !obj || Object.keys(obj).length === 0;
364
+ if (obj === null || obj === undefined) {
365
+ return true;
366
+ }
367
+ // Check if it's an array
368
+ if (Array.isArray(obj)) {
369
+ return obj.length === 0;
370
+ }
371
+ // Check if it's an object with no own properties
372
+ return Object.keys(obj).length === 0;
347
373
  };
348
374
 
349
375
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"mysteryinfosolutions-api-core.mjs","sources":["../../../projects/api-core/src/lib/configs/base-resource-config.ts","../../../projects/api-core/src/lib/configs/api-core-config.ts","../../../projects/api-core/src/lib/api-core.ts","../../../projects/api-core/src/lib/enums/selectmodes.enum.ts","../../../projects/api-core/src/lib/utils/permission.util.ts","../../../projects/api-core/src/lib/utils/query-utils.ts","../../../projects/api-core/src/lib/models/filter.model.ts","../../../projects/api-core/src/lib/models/sort.model.ts","../../../projects/api-core/src/lib/types/permission.type.ts","../../../projects/api-core/src/lib/services/base-state.service.ts","../../../projects/api-core/src/lib/services/base.service.ts","../../../projects/api-core/src/lib/services/api-error-handler.service.ts","../../../projects/api-core/src/lib/interceptors/api-error.interceptor.ts","../../../projects/api-core/src/public-api.ts","../../../projects/api-core/src/mysteryinfosolutions-api-core.ts"],"sourcesContent":["// base-resource-config.ts\nimport { TableColumn } from \"../models\";\nimport { StandardPermission } from \"../types\";\n\n/**\n * BaseResourceConfig<T>\n *\n * A generic configuration class to standardize table-based resource UIs.\n * Extend this in feature modules (e.g., Users, Roles, Genders) to reuse core settings.\n */\nexport abstract class BaseResourceConfig<T> {\n /**\n * Table columns definition for the resource.\n */\n columns: TableColumn<T>[] = [];\n\n /**\n * The column used for date-range filtering (e.g., in filters or reporting).\n */\n dateRangeColumn: keyof T | string = 'updated_at';\n\n /**\n * Default column used to sort the table data.\n */\n defaultSortColumn: keyof T | string | null = 'updated_at';\n\n /**\n * Default sorting order (ASC or DESC).\n */\n defaultSortOrder: 'ASC' | 'DESC' = 'DESC';\n\n /**\n * Page size options for the table paginator.\n */\n pageLengthOptions: number[] = [10, 25, 50, 100];\n\n /**\n * Default page size.\n */\n defaultPageLength: number = 10;\n\n /**\n * Keys (fields) to apply search filter on.\n */\n searchColumns: (keyof T | string)[] = [];\n\n /**\n * Modal configuration: size for the create/update (modify) modal.\n */\n modifyModalSize: 'sm' | 'md' | 'lg' | 'xl' | string = 'md';\n\n /**\n * Modal configuration: fullscreen setting for modify modal.\n */\n modifyModalFullscreen: 'sm' | 'md' | 'lg' | 'xl' | 'xxl' | boolean | string = false;\n\n /**\n * Modal configuration: size for the view/summary modal.\n */\n summaryModalSize: 'sm' | 'lg' | 'xl' | string = 'md';\n\n /**\n * Modal configuration: fullscreen setting for summary modal.\n */\n summaryModalFullscreen: 'sm' | 'md' | 'lg' | 'xl' | 'xxl' | boolean | string = false;\n\n /**\n * Determines the default view when viewing details of a record.\n * 'overview' = navigates to a new page\n * 'summary' = opens a modal with summary component\n */\n defaultDetailView: 'overview' | 'summary' = 'summary';\n\n /**\n * Permissions map generated from the resource name.\n * Override in child class or call helper in constructor.\n */\n permissions!: Record<StandardPermission | string, string>;\n}\n","import { InjectionToken } from '@angular/core';\n\n/**\n * Configuration options for the api-core library.\n * \n * @example\n * // In your app.config.ts or module providers\n * import { API_CORE_CONFIG, ApiCoreConfig } from '@mysteryinfosolutions/api-core';\n * \n * export const appConfig: ApplicationConfig = {\n * providers: [\n * {\n * provide: API_CORE_CONFIG,\n * useValue: {\n * pagination: {\n * defaultPage: 1,\n * defaultPageLength: 25,\n * pageLengthOptions: [25, 50, 100]\n * },\n * api: {\n * dateFormat: 'iso',\n * includeCredentials: true\n * }\n * } as ApiCoreConfig\n * }\n * ]\n * };\n */\nexport interface ApiCoreConfig {\n /**\n * Pagination configuration defaults\n */\n pagination?: {\n /** Default page number (1-based) */\n defaultPage?: number;\n \n /** Default number of items per page */\n defaultPageLength?: number;\n \n /** Available page length options for user selection */\n pageLengthOptions?: number[];\n \n /** Maximum allowed page length (to prevent large requests) */\n maxPageLength?: number;\n };\n\n /**\n * API request/response configuration\n */\n api?: {\n /** Date format for API requests ('iso' | 'timestamp' | 'custom') */\n dateFormat?: 'iso' | 'timestamp' | 'custom';\n \n /** Custom date formatter function (if dateFormat is 'custom') */\n dateFormatter?: (date: Date) => string;\n \n /** Whether to include credentials in requests */\n includeCredentials?: boolean;\n \n /** Default headers to include in all requests */\n defaultHeaders?: Record<string, string>;\n \n /** Request timeout in milliseconds */\n timeout?: number;\n };\n\n /**\n * Query string formatting options\n */\n queryString?: {\n /** Format for array parameters ('brackets' | 'comma' | 'repeat') */\n arrayFormat?: 'brackets' | 'comma' | 'repeat';\n \n /** Custom array formatter function */\n arrayFormatter?: (key: string, values: unknown[]) => string;\n \n /** Whether to encode query parameters */\n encode?: boolean;\n \n /** Custom encoder function */\n encoder?: (value: string) => string;\n };\n\n /**\n * Sort configuration\n */\n sort?: {\n /** Default sort order */\n defaultOrder?: 'ASC' | 'DESC';\n \n /** Separator between field and order in query string */\n separator?: string;\n \n /** Whether to allow multi-column sorting */\n allowMultiSort?: boolean;\n };\n\n /**\n * Error handling configuration\n */\n errorHandling?: {\n /** Whether to log errors to console */\n logErrors?: boolean;\n \n /** Whether to show user-friendly error messages */\n showUserMessages?: boolean;\n \n /** Global error handler function */\n onError?: (error: unknown) => void;\n };\n\n /**\n * Loading state configuration\n */\n loading?: {\n /** Minimum loading time in ms (prevents flash of loading state) */\n minLoadingTime?: number;\n \n /** Whether to show loading indicators by default */\n showLoadingByDefault?: boolean;\n };\n}\n\n/**\n * Default configuration values for the api-core library.\n */\nexport const DEFAULT_API_CORE_CONFIG: Required<ApiCoreConfig> = {\n pagination: {\n defaultPage: 1,\n defaultPageLength: 10,\n pageLengthOptions: [10, 25, 50, 100],\n maxPageLength: 1000\n },\n api: {\n dateFormat: 'iso',\n dateFormatter: (date: Date) => date.toISOString(),\n includeCredentials: false,\n defaultHeaders: {},\n timeout: 30000 // 30 seconds\n },\n queryString: {\n arrayFormat: 'brackets',\n arrayFormatter: (key: string, values: unknown[]) => `${key}=[${values.join(',')}]`,\n encode: true,\n encoder: (value: string) => encodeURIComponent(value)\n },\n sort: {\n defaultOrder: 'ASC',\n separator: ':',\n allowMultiSort: true\n },\n errorHandling: {\n logErrors: true,\n showUserMessages: true,\n onError: (error: unknown) => console.error('API Error:', error)\n },\n loading: {\n minLoadingTime: 0,\n showLoadingByDefault: true\n }\n};\n\n/**\n * Injection token for api-core configuration.\n * \n * @example\n * // Provide custom configuration\n * providers: [\n * {\n * provide: API_CORE_CONFIG,\n * useValue: {\n * pagination: { defaultPageLength: 25 }\n * } as ApiCoreConfig\n * }\n * ]\n * \n * @example\n * // Inject in service\n * constructor(@Inject(API_CORE_CONFIG) private config: ApiCoreConfig) {}\n */\nexport const API_CORE_CONFIG = new InjectionToken<ApiCoreConfig>(\n 'api-core.config',\n {\n providedIn: 'root',\n factory: () => DEFAULT_API_CORE_CONFIG\n }\n);\n\n/**\n * Merges user-provided configuration with default values.\n * \n * @param userConfig User-provided configuration\n * @returns Merged configuration with defaults\n * \n * @example\n * const config = mergeConfig({\n * pagination: { defaultPageLength: 25 }\n * });\n * // Returns full config with defaultPageLength: 25 and all other defaults\n */\nexport function mergeConfig(userConfig?: ApiCoreConfig): Required<ApiCoreConfig> {\n if (!userConfig) {\n return DEFAULT_API_CORE_CONFIG;\n }\n\n return {\n pagination: { ...DEFAULT_API_CORE_CONFIG.pagination, ...userConfig.pagination },\n api: { ...DEFAULT_API_CORE_CONFIG.api, ...userConfig.api },\n queryString: { ...DEFAULT_API_CORE_CONFIG.queryString, ...userConfig.queryString },\n sort: { ...DEFAULT_API_CORE_CONFIG.sort, ...userConfig.sort },\n errorHandling: { ...DEFAULT_API_CORE_CONFIG.errorHandling, ...userConfig.errorHandling },\n loading: { ...DEFAULT_API_CORE_CONFIG.loading, ...userConfig.loading }\n };\n}\n\n\n","import { Component } from '@angular/core';\n\n@Component({\n selector: 'lib-api-core',\n imports: [],\n template: `\n <p>\n api-core works!\n </p>\n `,\n styles: ``\n})\nexport class ApiCore {\n\n}\n","/**\n * Enum defining column selection modes for API queries.\n * \n * @remarks\n * Used to control which columns are returned in API responses,\n * useful for optimizing payload size and performance.\n * \n * @example\n * const filter = {\n * selectMode: SELECT_MODE.ONLYCOLUMNS,\n * selectColumns: 'id,name,email'\n * };\n */\nexport enum SELECT_MODE {\n /** Return all columns (default behavior) */\n ALL = 1,\n \n /** Return only specified columns via selectColumns parameter */\n ONLYCOLUMNS = 2,\n}\n","import { StandardPermission } from \"../types\";\n\n/**\n * Generates a permission mapping object for a given resource.\n *\n * @template T - Additional custom permissions (optional).\n * @param resource - The base resource name (e.g., 'brand', 'user').\n * @param extra - An optional array of additional/custom permissions to include.\n * @returns A record mapping each permission key (e.g., 'view') to a namespaced string (e.g., 'brand.view').\n *\n * @example\n * generatePermissions('brand')\n * // {\n * // view: 'brand.view',\n * // create: 'brand.create',\n * // update: 'brand.update',\n * // ...\n * // }\n */\nexport function generatePermissions<\n T extends string = StandardPermission\n>(\n resource: string,\n extra: T[] = [] as T[]\n): Record<T | StandardPermission, string> {\n const base = resource.toLowerCase();\n\n // Core standard permissions extended with advanced actions\n const standard: StandardPermission[] = [\n // Common\n '*', // All permissions\n 'superAdmin',\n 'manage', // Manage the record (CRUD)\n 'access', // Access the record (view, edit, delete)\n 'own', // Own the record (create, update, delete)\n\n // CRUD\n 'view',\n 'list',\n 'create',\n 'update',\n 'delete',\n\n // Deletion handling\n 'restore',\n 'forceDelete',\n\n // Import/export\n 'export',\n 'import',\n\n // Workflow/status\n 'approve',\n 'reject',\n 'archive',\n 'unarchive',\n 'changeStatus',\n\n // UI & actions\n 'duplicate',\n 'share',\n 'assign',\n 'print',\n 'preview',\n 'reorder',\n 'toggleVisibility',\n\n // Content lifecycle\n 'publish',\n 'unpublish',\n\n // External integration\n 'sync',\n\n // Auditing & metadata\n 'audit',\n 'comment',\n 'favorite',\n\n // Permissions/admin\n 'managePermissions',\n 'assignRole',\n 'configure',\n ];\n\n const all = [...standard, ...extra];\n\n return all.reduce((acc, action) => {\n acc[action as T | StandardPermission] = `${base}.${action}`;\n return acc;\n }, {} as Record<T | StandardPermission, string>);\n}\n","import { SortItem } from '../models';\n\n/**\n * Converts an array of SortItem objects into a comma-separated sort string.\n * \n * @param sortItems Array of sort configurations\n * @returns Formatted sort string (e.g., \"name:ASC,createdAt:DESC\") or empty string\n * \n * @example\n * const sorts = [\n * new SortItem('name', 'ASC'),\n * new SortItem('createdAt', 'DESC')\n * ];\n * const sortString = sortObjectToString(sorts);\n * // Returns: \"name:ASC,createdAt:DESC\"\n */\nexport const sortObjectToString = (sortItems: SortItem[]): string => {\n if (!Array.isArray(sortItems) || sortItems.length === 0) return '';\n return sortItems.map(s => `${s.field}:${s.order}`).join(',');\n};\n\n/**\n * Converts a filter object into a URL query string.\n * \n * @param filter Filter object with query parameters\n * @returns URL query string with '?' prefix, or empty string if no parameters\n * \n * @remarks\n * - Automatically converts SortItem arrays to sort strings\n * - Encodes all values for URL safety\n * - Filters out undefined and null values\n * - Arrays are encoded as comma-separated values in brackets\n * \n * @example\n * const filter = {\n * page: 1,\n * pageLength: 25,\n * search: 'John Doe',\n * roles: ['admin', 'user'],\n * sort: [new SortItem('name', 'ASC')]\n * };\n * const queryString = jsonToQueryString(filter);\n * // Returns: \"?page=1&pageLength=25&search=John%20Doe&roles=[admin,user]&sort=name:ASC\"\n */\nexport const jsonToQueryString = (filter: Record<string, unknown>): string => {\n if (!filter || typeof filter !== 'object') return '';\n\n // Clone to avoid mutating original\n const params = { ...filter };\n\n // Convert sort array to string format\n if ('sort' in params && Array.isArray(params['sort'])) {\n params['sort'] = sortObjectToString(params['sort'] as SortItem[]);\n }\n\n const queryArray = Object.keys(params)\n .filter(key => params[key] !== undefined && params[key] !== null && params[key] !== '')\n .map(key => {\n const value = params[key];\n \n if (Array.isArray(value)) {\n // Encode arrays as [item1,item2,item3]\n return `${encodeURIComponent(key)}=${encodeURIComponent('[' + value.toString() + ']')}`;\n } else {\n return `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`;\n }\n });\n\n return queryArray.length > 0 ? `?${queryArray.join('&')}` : '';\n};\n\n/**\n * Checks if an object is empty (has no own properties).\n * \n * @param obj Object to check\n * @returns True if object is null, undefined, or has no properties\n * \n * @example\n * isEmpty({}); // true\n * isEmpty(null); // true\n * isEmpty(undefined); // true\n * isEmpty({ page: 1 }); // false\n * isEmpty([]); // true (arrays with no length)\n */\nexport const isEmpty = (obj: Record<string, unknown> | null | undefined): boolean => {\n return !obj || Object.keys(obj).length === 0;\n};\n","import { SortItem } from './';\nimport { SELECT_MODE } from '../enums';\n\n/**\n * Base filter class providing common filtering, pagination, and sorting capabilities.\n * \n * @remarks\n * Extend this class in your custom filter types to add domain-specific filter properties.\n * The base filter handles pagination, sorting, searching, and date range filtering.\n * \n * @example\n * interface UserFilter extends Filter {\n * role?: string;\n * isActive?: boolean;\n * departmentId?: number;\n * }\n * \n * const filter: UserFilter = {\n * page: 1,\n * pageLength: 25,\n * search: 'john',\n * role: 'admin',\n * sort: [new SortItem('name', 'ASC')]\n * };\n */\nexport abstract class Filter {\n /** Array of specific IDs to filter by */\n ids?: number[];\n \n /** Column name to use for date range filtering */\n dateRangeColumn?: string;\n \n /** Start date for date range filter (ISO format) */\n dateRangeFrom?: string;\n \n /** End date for date range filter (ISO format) */\n dateRangeTo?: string;\n\n /** Current page number (1-based) */\n page?: number;\n \n /** Number of records per page */\n pageLength?: number;\n\n /** Array of sort configurations */\n sort?: SortItem[];\n\n /** Search query string */\n search?: string;\n \n /** Comma-separated list of columns to search in */\n searchColumns?: string;\n \n /** Comma-separated list of columns to select/return */\n selectColumns?: string;\n \n /** Mode for column selection */\n selectMode?: SELECT_MODE;\n}","/**\n * Represents a single sort configuration for a field.\n * \n * @remarks\n * Used in filter objects to specify sorting criteria.\n * Multiple SortItem instances can be combined for multi-column sorting.\n * \n * @example\n * // Single sort\n * const sort = new SortItem('name', 'ASC');\n * \n * @example\n * // Multi-column sort\n * const sorts = [\n * new SortItem('priority', 'DESC'),\n * new SortItem('createdAt', 'DESC'),\n * new SortItem('name', 'ASC')\n * ];\n * \n * const filter = {\n * page: 1,\n * pageLength: 25,\n * sort: sorts\n * };\n */\nexport class SortItem {\n /**\n * Creates a sort configuration.\n * \n * @param field The field/column name to sort by\n * @param order Sort direction: 'ASC' (ascending) or 'DESC' (descending)\n */\n constructor(\n public field: string,\n public order: 'ASC' | 'DESC'\n ) {}\n}\n\n","\nexport type StandardPermission =\n // Common\n | '*' // All permissions\n | 'superAdmin' // Super admin permissions\n | 'manage' // Manage the record (CRUD)\n | 'access' // Access the record (view, edit, delete)\n | 'own' // Own the record (create, update, delete)\n\n // Basic CRUD\n | 'view' // View a single record\n | 'list' // View a list of records\n | 'create' // Create a new record\n | 'update' // Update an existing record\n | 'delete' // Soft-delete a record (not permanent)\n\n // Deletion Handling\n | 'restore' // Restore a soft-deleted record\n | 'forceDelete' // Permanently delete a record\n\n // Data Import/Export\n | 'export' // Export data (CSV, Excel, etc.)\n | 'import' // Import data into the system\n\n // Workflow & Status\n | 'approve' // Approve a pending record or request\n | 'reject' // Reject a record or request\n | 'archive' // Archive a record (typically hides it from normal views)\n | 'unarchive' // Unarchive a previously archived record\n\n // Duplication & Sharing\n | 'duplicate' // Duplicate or clone a record\n | 'share' // Share the record with others (e.g., link, team)\n\n // Assignment & Ownership\n | 'assign' // Assign the record to a user or group\n | 'changeStatus' // Change the record’s custom status (if not approve/reject)\n\n // Output and Preview\n | 'print' // Generate a printable version\n | 'preview' // Preview before saving or publishing\n\n // Content Lifecycle\n | 'publish' // Make the record public/visible\n | 'unpublish' // Revert the record back to draft/private\n\n // External Integration\n | 'sync' // Synchronize data with an external system\n\n // Auditing & Monitoring\n | 'audit' // View audit log/history of a record\n\n // Communication & Metadata\n | 'comment' // Add or view comments on a record\n | 'favorite' // Mark the record as favorite/bookmarked\n\n // UI-Specific\n | 'reorder' // Change the order (drag & drop, sequence)\n | 'toggleVisibility' // Enable/disable visibility (e.g., toggle switch)\n\n // Admin/Permission Management\n | 'managePermissions' // Manage permissions for this resource\n | 'assignRole' // Assign roles related to the resource\n | 'configure'; // Modify configuration/settings for the resource\n;\n","import { BehaviorSubject, map, Observable, distinctUntilChanged, shareReplay } from \"rxjs\";\nimport { Filter, IMultiresult, IMultiresultMetaData, SortItem } from \"../models\";\n\n/**\n * Generic reactive state management service for data-driven features.\n * \n * @template TRecord The type of record/entity being managed\n * @template TFilter Filter type extending Partial<TRecord> & Filter\n * \n * @remarks\n * BaseStateService provides comprehensive state management for list-based views including:\n * - Filter state with pagination and sorting\n * - Records collection with CRUD helpers\n * - Loading states (with context keys)\n * - Error handling\n * - Record selection\n * - Pagination metadata\n * \n * All state is reactive using RxJS BehaviorSubjects, making it easy to integrate\n * with Angular templates using the async pipe.\n * \n * @example\n * // Basic setup in component\n * @Component({\n * selector: 'app-users',\n * providers: [BaseStateService] // Component-level instance\n * })\n * export class UsersComponent implements OnInit, OnDestroy {\n * state = new BaseStateService<User, UserFilter>();\n * \n * constructor(private userService: UserService) {}\n * \n * ngOnInit() {\n * // Subscribe to filter changes\n * this.state.filter$.subscribe(filter => {\n * this.loadUsers(filter);\n * });\n * \n * // Set initial filter\n * this.state.setFilter({ page: 1, pageLength: 25 });\n * }\n * \n * loadUsers(filter: UserFilter) {\n * this.state.setLoading('list', true);\n * \n * this.userService.getAll(filter).subscribe({\n * next: (response) => {\n * if (response.data) {\n * this.state.setApiResponse(response.data);\n * }\n * this.state.setLoading('list', false);\n * },\n * error: (err) => {\n * this.state.setError('Failed to load users');\n * this.state.setLoading('list', false);\n * }\n * });\n * }\n * \n * ngOnDestroy() {\n * this.state.destroy();\n * }\n * }\n * \n * @example\n * // Using in template\n * <div *ngIf=\"state.isLoading$('list') | async\">Loading...</div>\n * <div *ngIf=\"state.error$ | async as error\">{{ error }}</div>\n * \n * <div *ngFor=\"let user of state.records$ | async\">\n * {{ user.name }}\n * </div>\n * \n * <div *ngIf=\"state.pager$ | async as pager\">\n * Page {{ pager.currentPage }} of {{ pager.lastPage }}\n * </div>\n */\nexport class BaseStateService<\n TRecord,\n TFilter extends Partial<TRecord> & Filter = Partial<TRecord> & Filter\n> {\n private readonly filterSubject = new BehaviorSubject<TFilter>({ page: 1, pageLength: 10 } as TFilter);\n private readonly recordsSubject = new BehaviorSubject<TRecord[]>([]);\n private readonly pagerSubject = new BehaviorSubject<IMultiresultMetaData | null>(null);\n private readonly selectedSubject = new BehaviorSubject<TRecord | null>(null);\n private readonly loadingMapSubject = new BehaviorSubject<Record<string, boolean>>({});\n private readonly errorSubject = new BehaviorSubject<string | null>(null);\n\n /** \n * Observable stream of current filter.\n * Optimized with distinctUntilChanged to prevent duplicate emissions.\n */\n filter$ = this.filterSubject.asObservable().pipe(\n distinctUntilChanged((prev, curr) => JSON.stringify(prev) === JSON.stringify(curr)),\n shareReplay({ bufferSize: 1, refCount: true })\n );\n\n /** \n * Observable stream of current records.\n * Optimized with distinctUntilChanged for reference equality.\n */\n records$ = this.recordsSubject.asObservable().pipe(\n distinctUntilChanged(),\n shareReplay({ bufferSize: 1, refCount: true })\n );\n\n /** \n * Observable stream of current pager metadata.\n * Optimized with distinctUntilChanged for deep equality.\n */\n pager$ = this.pagerSubject.asObservable().pipe(\n distinctUntilChanged((prev, curr) => JSON.stringify(prev) === JSON.stringify(curr)),\n shareReplay({ bufferSize: 1, refCount: true })\n );\n\n /** \n * Observable stream of the currently selected record.\n * Optimized with distinctUntilChanged for reference equality.\n */\n selected$ = this.selectedSubject.asObservable().pipe(\n distinctUntilChanged(),\n shareReplay({ bufferSize: 1, refCount: true })\n );\n\n /** \n * Observable stream of loading state.\n * Optimized with distinctUntilChanged for deep equality.\n */\n loading$ = this.loadingMapSubject.asObservable().pipe(\n distinctUntilChanged((prev, curr) => JSON.stringify(prev) === JSON.stringify(curr)),\n shareReplay({ bufferSize: 1, refCount: true })\n );\n\n /** \n * Observable stream of current error message.\n * Optimized with distinctUntilChanged for value equality.\n */\n error$ = this.errorSubject.asObservable().pipe(\n distinctUntilChanged(),\n shareReplay({ bufferSize: 1, refCount: true })\n );\n\n /** Returns the current filter. */\n get currentFilter(): TFilter {\n return this.filterSubject.value;\n }\n\n /** Returns the currently loaded records. */\n get currentRecords(): TRecord[] {\n return this.recordsSubject.value;\n }\n\n /** Returns the currently selected record, if any. */\n get selected(): TRecord | null {\n return this.selectedSubject.value;\n }\n\n /**\n * Updates the current filter with new values.\n * @param update Partial filter to merge.\n */\n setFilter(update: Partial<TFilter>) {\n const current = this.filterSubject.value;\n this.filterSubject.next({ ...current, ...update });\n }\n\n /**\n * Replaces all records in the current state.\n * @param records Array of new records.\n */\n setRecords(records: TRecord[]) {\n this.recordsSubject.next(records);\n }\n\n /**\n * Appends records to the current record list.\n * @param records Records to add.\n */\n appendRecords(records: TRecord[]) {\n this.recordsSubject.next([...this.currentRecords, ...records]);\n }\n\n /**\n * Sets the pagination metadata.\n * @param pager Metadata to use.\n */\n setPager(pager: IMultiresultMetaData) {\n this.pagerSubject.next(pager);\n }\n\n /**\n * Sets records and pager data from API response.\n * @param response API response containing records and pager.\n */\n setApiResponse(response: IMultiresult<TRecord>) {\n this.setRecords(response.records);\n this.setPager(response.pager);\n }\n\n /**\n * Updates the sort order in the current filter.\n * Toggles order if column already exists and no explicit sort is provided, or adds it otherwise.\n * \n * @param column Column name to sort by\n * @param sort Optional sort order. If not provided and column exists, toggles between ASC/DESC.\n * If not provided and column doesn't exist, defaults to ASC.\n * \n * @example\n * // Add new sort (defaults to ASC)\n * state.setSort('name');\n * \n * @example\n * // Toggle existing sort\n * state.setSort('name'); // If already ASC, becomes DESC; if DESC, becomes ASC\n * \n * @example\n * // Explicitly set sort order\n * state.setSort('name', 'DESC'); // Always sets to DESC\n */\n setSort(column: string, sort?: \"ASC\" | \"DESC\") {\n const current = this.filterSubject.value;\n let sortItems = [...(current.sort ?? [])];\n const index = sortItems.findIndex(item => item.field === column);\n\n if (index !== -1) {\n // Column already exists in sort\n if (sort !== undefined) {\n // Explicit sort provided - use it\n sortItems[index] = new SortItem(sortItems[index].field, sort);\n } else {\n // No explicit sort - toggle the order\n const currentOrder = sortItems[index].order;\n const newOrder = currentOrder === 'ASC' ? 'DESC' : 'ASC';\n sortItems[index] = new SortItem(sortItems[index].field, newOrder);\n }\n } else {\n // Column doesn't exist - add it (default to ASC if not specified)\n sortItems.push(new SortItem(column, sort ?? 'ASC'));\n }\n\n this.filterSubject.next({\n ...current,\n sort: sortItems\n });\n }\n\n /**\n * Removes a specific column from the current sort.\n * @param column Column name to remove from sorting.\n */\n removeSort(column: string) {\n const current = this.filterSubject.value;\n const sortItems = [...(current.sort ?? [])].filter(item => item.field !== column);\n\n this.filterSubject.next({\n ...current,\n sort: sortItems\n });\n }\n\n /**\n * Clears all sorting from the current filter.\n */\n clearSort() {\n const current = this.filterSubject.value;\n\n this.filterSubject.next({\n ...current,\n sort: []\n });\n }\n\n /**\n * Returns an observable boolean for a specific loading key.\n * Useful for tracking loading state in a specific view or feature.\n *\n * @param key A unique key representing the loading context (e.g., \"list\", \"detail\")\n * @returns Observable emitting `true` if the given context is loading, `false` otherwise.\n * \n * @remarks\n * Optimized with distinctUntilChanged to prevent duplicate emissions\n * and shareReplay to share subscriptions.\n */\n isLoading$(key: string): Observable<boolean> {\n return this.loading$.pipe(\n map(state => !!state[key]),\n distinctUntilChanged(),\n shareReplay({ bufferSize: 1, refCount: true })\n );\n }\n\n /**\n * Sets the loading state for a specific key.\n * This allows you to control multiple concurrent loading states independently.\n *\n * @param key The loading context name (e.g., \"list\", \"form\", \"detail\")\n * @param value The loading status (`true` for loading, `false` for done)\n */\n setLoading(key: string, value: boolean): void {\n const current = this.loadingMapSubject.value;\n this.loadingMapSubject.next({ ...current, [key]: value });\n }\n\n /**\n * Sets the error state.\n * @param error Error message or null.\n */\n setError(error: string | null) {\n this.errorSubject.next(error);\n }\n\n /**\n * Selects a record.\n * @param record The record to select.\n */\n select(record: TRecord) {\n this.selectedSubject.next(record);\n }\n\n /** Clears the current selection. */\n clearSelection() {\n this.selectedSubject.next(null);\n }\n\n /**\n * Clears the loading state for a specific key or all keys if none is provided.\n *\n * @param key Optional. If provided, only that loading key is cleared. If omitted, all are cleared.\n */\n clearLoading(key?: string): void {\n if (key) {\n const { [key]: _, ...rest } = this.loadingMapSubject.value;\n this.loadingMapSubject.next(rest);\n } else {\n this.loadingMapSubject.next({});\n }\n }\n\n /** Resets the entire state to initial values. */\n reset() {\n this.recordsSubject.next([]);\n this.pagerSubject.next(null);\n this.selectedSubject.next(null);\n this.setFilter({ page: 1, pageLength: 10 } as Partial<TFilter>);\n this.clearLoading();\n this.setError(null);\n }\n\n /**\n * Removes a record by its ID field.\n * @param id The ID to remove.\n * @param idKey The record property key used as ID (default: 'id').\n */\n removeRecordById(id: number | string, idKey: keyof TRecord = 'id' as keyof TRecord) {\n this.recordsSubject.next(this.currentRecords.filter(r => r[idKey] !== id));\n }\n\n /**\n * Replaces a record by matching its ID field.\n * @param updated The updated record.\n * @param idKey The record property key used as ID (default: 'id').\n */\n replaceRecord(updated: TRecord, idKey: keyof TRecord = 'id' as keyof TRecord) {\n this.recordsSubject.next(\n this.currentRecords.map(r => r[idKey] === updated[idKey] ? updated : r)\n );\n }\n\n /**\n * Checks if a specific record is currently selected.\n * @param record Record to check.\n * @param idKey Key to use for comparison (default: 'id').\n */\n isSelected(record: TRecord, idKey: keyof TRecord = 'id' as keyof TRecord): boolean {\n const selected = this.selectedSubject.value;\n return selected ? selected[idKey] === record[idKey] : false;\n }\n\n /**\n * Updates the current page number in the filter.\n * @param page Page number.\n */\n setPage(page: number) {\n this.setFilter({ page } as Partial<TFilter>);\n }\n\n /**\n * Updates the page length in the filter.\n * @param pageLength Number of records per page.\n */\n setPageLength(pageLength: number) {\n this.setFilter({ pageLength } as Partial<TFilter>);\n }\n\n /**\n * Resets the filter to default values.\n * @param defaults Default filter values.\n */\n resetFilter(defaults: Partial<TFilter> = { page: 1, pageLength: 10 } as Partial<TFilter>) {\n this.filterSubject.next(defaults as TFilter);\n }\n\n /** Returns true if there are more pages after the current one. */\n hasMorePages(): boolean {\n const pager = this.pagerSubject.value;\n return !!pager && pager.currentPage! < pager.lastPage!;\n }\n\n /** Returns true if a previous page exists. */\n hasPreviousPage(): boolean {\n const pager = this.pagerSubject.value;\n return !!pager && pager.currentPage! > 0;\n }\n\n /** Resets and clears all managed state. */\n destroy() {\n this.reset();\n this.destroySubscriptions();\n }\n\n /**\n * Completes specified subjects managed by this service.\n * If no argument is provided, completes all subjects.\n * @param subjects Array of subject names to complete (e.g., ['filterSubject', 'recordsSubject'])\n */\n destroySubscriptions(subjects?: Array<'filterSubject' | 'recordsSubject' | 'pagerSubject' | 'selectedSubject' | 'loadingMapSubject' | 'errorSubject'>) {\n const allSubjects = {\n filterSubject: this.filterSubject,\n recordsSubject: this.recordsSubject,\n pagerSubject: this.pagerSubject,\n selectedSubject: this.selectedSubject,\n loadingMapSubject: this.loadingMapSubject,\n errorSubject: this.errorSubject,\n };\n\n const toComplete = subjects ?? Object.keys(allSubjects) as Array<keyof typeof allSubjects>;\n toComplete.forEach(key => allSubjects[key].complete());\n }\n\n}\n","import { HttpClient } from '@angular/common/http';\nimport { Observable } from 'rxjs';\nimport { jsonToQueryString, isEmpty } from '../utils/query-utils';\nimport { IMultiresult, IResponse, Filter } from '../models';\n\n/**\n * Abstract base service providing standard CRUD operations for REST APIs.\n * \n * @template T The full model type representing your entity\n * @template TFilter Filter type extending Partial<T> & Filter for query parameters\n * @template TCreate DTO type for creating new records (defaults to Partial<T>)\n * @template TUpdate DTO type for updating records (defaults to Partial<T>)\n * \n * @remarks\n * Extend this class in your feature services to get type-safe CRUD operations\n * with minimal boilerplate. The service automatically handles:\n * - Query string generation from filters\n * - Pagination and sorting\n * - Standardized response/error handling\n * - Type safety throughout the request/response cycle\n * \n * @example\n * // Define your model\n * interface User {\n * id: number;\n * name: string;\n * email: string;\n * role: string;\n * }\n * \n * // Define custom filter\n * interface UserFilter extends Filter {\n * role?: string;\n * isActive?: boolean;\n * }\n * \n * // Create service\n * @Injectable({ providedIn: 'root' })\n * export class UserService extends BaseService<User, UserFilter> {\n * constructor(http: HttpClient) {\n * super(http, '/api/users');\n * }\n * \n * // Add custom methods\n * activateUser(id: number): Observable<IResponse<User>> {\n * return this.http.post<IResponse<User>>(`${this.baseUrl}/${id}/activate`, {});\n * }\n * }\n * \n * @example\n * // With separate DTOs for create/update\n * interface CreateUserDto {\n * name: string;\n * email: string;\n * password: string;\n * }\n * \n * interface UpdateUserDto {\n * name?: string;\n * email?: string;\n * // Note: password excluded\n * }\n * \n * @Injectable({ providedIn: 'root' })\n * export class UserService extends BaseService<\n * User,\n * UserFilter,\n * CreateUserDto,\n * UpdateUserDto\n * > {\n * constructor(http: HttpClient) {\n * super(http, '/api/users');\n * }\n * }\n */\nexport abstract class BaseService<\n T, // Full model type\n TFilter extends Partial<T> & Filter = Partial<T> & Filter, // Filter: model fields + pagination/sorting\n TCreate = Partial<T>, // DTO for create\n TUpdate = Partial<T> // DTO for update\n> {\n /**\n * Creates an instance of BaseService.\n * \n * @param http Angular HttpClient for making HTTP requests\n * @param baseUrl Base URL for the resource API endpoint (e.g., '/api/users')\n */\n constructor(\n protected http: HttpClient,\n protected baseUrl: string\n ) { }\n\n /**\n * Fetches a paginated list of records with optional filtering and sorting.\n * \n * @param filter Optional filter object containing pagination, sorting, and search criteria\n * @returns Observable of response containing records array and pagination metadata\n * \n * @example\n * // Basic usage\n * userService.getAll().subscribe(response => {\n * console.log(response.data?.records);\n * console.log(response.data?.pager.totalRecords);\n * });\n * \n * @example\n * // With filters\n * userService.getAll({\n * page: 2,\n * pageLength: 25,\n * search: 'john',\n * role: 'admin',\n * sort: [new SortItem('name', 'ASC')]\n * }).subscribe(response => {\n * // Handle response\n * });\n */\n getAll(filter: TFilter = {} as TFilter): Observable<IResponse<IMultiresult<T>>> {\n const clonedFilter = structuredClone(filter);\n const query = !isEmpty(filter) ? jsonToQueryString(clonedFilter) : '';\n return this.http.get<IResponse<IMultiresult<T>>>(`${this.baseUrl}${query}`);\n }\n\n /**\n * Fetches a single record by its ID.\n * \n * @param id The unique identifier of the record\n * @returns Observable of response containing the single record\n * \n * @example\n * userService.getDetails(123).subscribe(response => {\n * if (response.data) {\n * console.log('User:', response.data);\n * }\n * });\n */\n getDetails(id: number): Observable<IResponse<T>> {\n return this.http.get<IResponse<T>>(`${this.baseUrl}/${id}`);\n }\n\n /**\n * Creates a new record.\n * \n * @param data Data transfer object containing fields for the new record\n * @returns Observable of response containing the created record (usually with generated ID)\n * \n * @example\n * userService.create({\n * name: 'John Doe',\n * email: 'john@example.com',\n * password: 'secure123'\n * }).subscribe(response => {\n * if (response.data) {\n * console.log('Created user:', response.data);\n * }\n * });\n */\n create(data: TCreate): Observable<IResponse<T>> {\n return this.http.post<IResponse<T>>(this.baseUrl, data);\n }\n\n /**\n * Updates an existing record.\n * \n * @param id The unique identifier of the record to update\n * @param data Data transfer object containing fields to update (partial update supported)\n * @returns Observable of response containing the updated record\n * \n * @example\n * userService.update(123, {\n * name: 'Jane Doe',\n * email: 'jane@example.com'\n * }).subscribe(response => {\n * if (response.data) {\n * console.log('Updated user:', response.data);\n * }\n * });\n */\n update(id: number, data: TUpdate): Observable<IResponse<T>> {\n return this.http.put<IResponse<T>>(`${this.baseUrl}/${id}`, data);\n }\n\n /**\n * Deletes a record (soft or hard delete).\n * \n * @param id The unique identifier of the record to delete\n * @param method Deletion method: 'soft' (mark as deleted, reversible) or 'hard' (permanent removal)\n * @returns Observable of response confirming deletion\n * \n * @remarks\n * - Soft delete: Record is marked as deleted but can be restored later\n * - Hard delete: Record is permanently removed from the database\n * - Default is 'soft' for safety\n * \n * @example\n * // Soft delete (default)\n * userService.delete(123).subscribe(() => {\n * console.log('User soft deleted');\n * });\n * \n * @example\n * // Hard delete (permanent)\n * userService.delete(123, 'hard').subscribe(() => {\n * console.log('User permanently deleted');\n * });\n */\n delete(id: number, method: 'soft' | 'hard' = 'soft'): Observable<IResponse<unknown>> {\n const methodQuery = `?method=${method}`;\n return this.http.delete<IResponse<unknown>>(`${this.baseUrl}/${id}${methodQuery}`);\n }\n}\n","import { Injectable } from '@angular/core';\nimport { HttpErrorResponse } from '@angular/common/http';\nimport { IMisError } from '../models';\n\n/**\n * Configuration options for the ApiErrorHandler.\n */\nexport interface ApiErrorHandlerConfig {\n /** Whether to log errors to console (default: true in dev, false in prod) */\n logErrors?: boolean;\n \n /** Custom error message transformer */\n errorMessageTransformer?: (error: HttpErrorResponse) => string;\n \n /** Callback to be called when an error occurs */\n onError?: (error: ProcessedError) => void;\n}\n\n/**\n * Processed error information with additional context.\n */\nexport interface ProcessedError {\n /** HTTP status code */\n status: number;\n \n /** User-friendly error message */\n message: string;\n \n /** Technical error details */\n details?: string;\n \n /** Error code from API */\n code?: string;\n \n /** Original HTTP error response */\n originalError: HttpErrorResponse;\n \n /** Whether this error should be shown to user */\n showToUser: boolean;\n \n /** Error type classification */\n type: 'network' | 'client' | 'server' | 'unknown';\n}\n\n/**\n * Service for handling and processing API errors consistently.\n * \n * @example\n * // Basic usage in a service\n * constructor(private errorHandler: ApiErrorHandler) {}\n * \n * loadData() {\n * this.http.get('/api/data').subscribe({\n * error: (err: HttpErrorResponse) => {\n * const processed = this.errorHandler.handleError(err);\n * this.showErrorToUser(processed.message);\n * }\n * });\n * }\n * \n * @example\n * // Configure globally\n * providers: [\n * {\n * provide: ApiErrorHandler,\n * useFactory: () => {\n * const handler = new ApiErrorHandler();\n * handler.configure({\n * logErrors: true,\n * onError: (error) => {\n * // Send to logging service\n * loggingService.logError(error);\n * }\n * });\n * return handler;\n * }\n * }\n * ]\n */\n@Injectable({ providedIn: 'root' })\nexport class ApiErrorHandler {\n private config: ApiErrorHandlerConfig = {\n logErrors: true\n };\n\n /**\n * Configure the error handler.\n * \n * @param config Configuration options\n */\n configure(config: ApiErrorHandlerConfig): void {\n this.config = { ...this.config, ...config };\n }\n\n /**\n * Process an HTTP error and return structured error information.\n * \n * @param error The HTTP error response\n * @returns Processed error with user-friendly message and metadata\n */\n handleError(error: HttpErrorResponse): ProcessedError {\n const processed = this.processError(error);\n\n if (this.config.logErrors) {\n this.logError(processed);\n }\n\n if (this.config.onError) {\n this.config.onError(processed);\n }\n\n return processed;\n }\n\n /**\n * Extract error message from various error formats.\n * \n * @param error The HTTP error response\n * @returns User-friendly error message\n */\n extractErrorMessage(error: HttpErrorResponse): string {\n if (this.config.errorMessageTransformer) {\n return this.config.errorMessageTransformer(error);\n }\n\n // Try to extract from API response\n if (error.error && typeof error.error === 'object') {\n const apiError = error.error as Partial<{ error: IMisError; message: string }>;\n \n // Check for nested error object\n if (apiError.error?.message) {\n return apiError.error.message;\n }\n \n // Check for direct message\n if (apiError.message) {\n return apiError.message;\n }\n }\n\n // Fallback to status-based messages\n return this.getDefaultMessageForStatus(error.status);\n }\n\n /**\n * Get default error message based on HTTP status code.\n * \n * @param status HTTP status code\n * @returns Default error message\n */\n private getDefaultMessageForStatus(status: number): string {\n switch (status) {\n case 0:\n return 'Unable to connect to the server. Please check your internet connection.';\n case 400:\n return 'Invalid request. Please check your input and try again.';\n case 401:\n return 'You are not authorized. Please log in and try again.';\n case 403:\n return 'You do not have permission to perform this action.';\n case 404:\n return 'The requested resource was not found.';\n case 408:\n return 'Request timeout. Please try again.';\n case 409:\n return 'This action conflicts with the current state. Please refresh and try again.';\n case 422:\n return 'Validation failed. Please check your input.';\n case 429:\n return 'Too many requests. Please wait a moment and try again.';\n case 500:\n return 'An internal server error occurred. Please try again later.';\n case 502:\n return 'Bad gateway. The server is temporarily unavailable.';\n case 503:\n return 'Service unavailable. Please try again later.';\n case 504:\n return 'Gateway timeout. The server took too long to respond.';\n default:\n if (status >= 400 && status < 500) {\n return 'Client error occurred. Please check your request.';\n } else if (status >= 500) {\n return 'Server error occurred. Please try again later.';\n }\n return 'An unexpected error occurred. Please try again.';\n }\n }\n\n /**\n * Classify error type based on status code.\n * \n * @param status HTTP status code\n * @returns Error type classification\n */\n private getErrorType(status: number): ProcessedError['type'] {\n if (status === 0) {\n return 'network';\n } else if (status >= 400 && status < 500) {\n return 'client';\n } else if (status >= 500) {\n return 'server';\n }\n return 'unknown';\n }\n\n /**\n * Determine if error should be shown to user.\n * \n * @param error HTTP error response\n * @returns Whether to show error to user\n */\n private shouldShowToUser(error: HttpErrorResponse): boolean {\n // Check if API explicitly set showMessageToUser flag\n if (error.error?.error?.showMessageToUser !== undefined) {\n return error.error.error.showMessageToUser;\n }\n\n // By default, show client errors (4xx) but not server errors (5xx)\n // unless it's a network error (0)\n const status = error.status;\n return status === 0 || (status >= 400 && status < 500);\n }\n\n /**\n * Process the error into a structured format.\n * \n * @param error HTTP error response\n * @returns Processed error object\n */\n private processError(error: HttpErrorResponse): ProcessedError {\n const message = this.extractErrorMessage(error);\n const type = this.getErrorType(error.status);\n const showToUser = this.shouldShowToUser(error);\n\n let details: string | undefined;\n let code: string | undefined;\n\n // Extract additional details if available\n if (error.error && typeof error.error === 'object') {\n const apiError = error.error as Partial<{ error: IMisError }>;\n if (apiError.error) {\n details = apiError.error.details;\n code = apiError.error.code;\n }\n }\n\n return {\n status: error.status,\n message,\n details,\n code,\n originalError: error,\n showToUser,\n type\n };\n }\n\n /**\n * Log error to console (in dev mode).\n * \n * @param error Processed error\n */\n private logError(error: ProcessedError): void {\n const style = 'color: #ff6b6b; font-weight: bold;';\n \n console.group('%c🔥 API Error', style);\n console.log('Status:', error.status);\n console.log('Type:', error.type);\n console.log('Message:', error.message);\n \n if (error.code) {\n console.log('Code:', error.code);\n }\n \n if (error.details) {\n console.log('Details:', error.details);\n }\n \n console.log('URL:', error.originalError.url);\n console.log('Method:', error.originalError.error?.method || 'Unknown');\n console.log('Original Error:', error.originalError);\n console.groupEnd();\n }\n}\n\n\n","import { HttpInterceptorFn, HttpErrorResponse } from '@angular/common/http';\nimport { inject } from '@angular/core';\nimport { catchError, throwError } from 'rxjs';\nimport { ApiErrorHandler } from '../services/api-error-handler.service';\n\n/**\n * HTTP Interceptor that catches errors and processes them through the ApiErrorHandler.\n * \n * @example\n * // In your app.config.ts or main provider:\n * export const appConfig: ApplicationConfig = {\n * providers: [\n * provideHttpClient(\n * withInterceptors([apiErrorInterceptor])\n * )\n * ]\n * };\n */\nexport const apiErrorInterceptor: HttpInterceptorFn = (req, next) => {\n const errorHandler = inject(ApiErrorHandler);\n\n return next(req).pipe(\n catchError((error: HttpErrorResponse) => {\n const handledError = errorHandler.handleError(error);\n return throwError(() => handledError);\n })\n );\n};\n\n\n","/*\n * Public API Surface of api-core\n */\n\nexport * from './lib/configs';\nexport * from './lib/api-core';\nexport * from './lib/enums';\nexport * from './lib/utils';\nexport * from './lib/models';\nexport * from './lib/types';\nexport * from './lib/services';\nexport * from './lib/interceptors';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;AAIA;;;;;AAKG;MACmB,kBAAkB,CAAA;AACpC;;AAEG;IACH,OAAO,GAAqB,EAAE;AAE9B;;AAEG;IACH,eAAe,GAAqB,YAAY;AAEhD;;AAEG;IACH,iBAAiB,GAA4B,YAAY;AAEzD;;AAEG;IACH,gBAAgB,GAAmB,MAAM;AAEzC;;AAEG;IACH,iBAAiB,GAAa,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;AAE/C;;AAEG;IACH,iBAAiB,GAAW,EAAE;AAE9B;;AAEG;IACH,aAAa,GAAyB,EAAE;AAExC;;AAEG;IACH,eAAe,GAAuC,IAAI;AAE1D;;AAEG;IACH,qBAAqB,GAAyD,KAAK;AAEnF;;AAEG;IACH,gBAAgB,GAAgC,IAAI;AAEpD;;AAEG;IACH,sBAAsB,GAAyD,KAAK;AAEpF;;;;AAIG;IACH,iBAAiB,GAA2B,SAAS;AAErD;;;AAGG;AACH,IAAA,WAAW;AACd;;AC6CD;;AAEG;AACU,MAAA,uBAAuB,GAA4B;AAC9D,IAAA,UAAU,EAAE;AACV,QAAA,WAAW,EAAE,CAAC;AACd,QAAA,iBAAiB,EAAE,EAAE;QACrB,iBAAiB,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;AACpC,QAAA,aAAa,EAAE;AAChB,KAAA;AACD,IAAA,GAAG,EAAE;AACH,QAAA,UAAU,EAAE,KAAK;QACjB,aAAa,EAAE,CAAC,IAAU,KAAK,IAAI,CAAC,WAAW,EAAE;AACjD,QAAA,kBAAkB,EAAE,KAAK;AACzB,QAAA,cAAc,EAAE,EAAE;QAClB,OAAO,EAAE,KAAK;AACf,KAAA;AACD,IAAA,WAAW,EAAE;AACX,QAAA,WAAW,EAAE,UAAU;AACvB,QAAA,cAAc,EAAE,CAAC,GAAW,EAAE,MAAiB,KAAK,CAAG,EAAA,GAAG,KAAK,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAG,CAAA,CAAA;AAClF,QAAA,MAAM,EAAE,IAAI;QACZ,OAAO,EAAE,CAAC,KAAa,KAAK,kBAAkB,CAAC,KAAK;AACrD,KAAA;AACD,IAAA,IAAI,EAAE;AACJ,QAAA,YAAY,EAAE,KAAK;AACnB,QAAA,SAAS,EAAE,GAAG;AACd,QAAA,cAAc,EAAE;AACjB,KAAA;AACD,IAAA,aAAa,EAAE;AACb,QAAA,SAAS,EAAE,IAAI;AACf,QAAA,gBAAgB,EAAE,IAAI;AACtB,QAAA,OAAO,EAAE,CAAC,KAAc,KAAK,OAAO,CAAC,KAAK,CAAC,YAAY,EAAE,KAAK;AAC/D,KAAA;AACD,IAAA,OAAO,EAAE;AACP,QAAA,cAAc,EAAE,CAAC;AACjB,QAAA,oBAAoB,EAAE;AACvB;;AAGH;;;;;;;;;;;;;;;;;AAiBG;MACU,eAAe,GAAG,IAAI,cAAc,CAC/C,iBAAiB,EACjB;AACE,IAAA,UAAU,EAAE,MAAM;AAClB,IAAA,OAAO,EAAE,MAAM;AAChB,CAAA;AAGH;;;;;;;;;;;AAWG;AACG,SAAU,WAAW,CAAC,UAA0B,EAAA;IACpD,IAAI,CAAC,UAAU,EAAE;AACf,QAAA,OAAO,uBAAuB;;IAGhC,OAAO;QACL,UAAU,EAAE,EAAE,GAAG,uBAAuB,CAAC,UAAU,EAAE,GAAG,UAAU,CAAC,UAAU,EAAE;QAC/E,GAAG,EAAE,EAAE,GAAG,uBAAuB,CAAC,GAAG,EAAE,GAAG,UAAU,CAAC,GAAG,EAAE;QAC1D,WAAW,EAAE,EAAE,GAAG,uBAAuB,CAAC,WAAW,EAAE,GAAG,UAAU,CAAC,WAAW,EAAE;QAClF,IAAI,EAAE,EAAE,GAAG,uBAAuB,CAAC,IAAI,EAAE,GAAG,UAAU,CAAC,IAAI,EAAE;QAC7D,aAAa,EAAE,EAAE,GAAG,uBAAuB,CAAC,aAAa,EAAE,GAAG,UAAU,CAAC,aAAa,EAAE;QACxF,OAAO,EAAE,EAAE,GAAG,uBAAuB,CAAC,OAAO,EAAE,GAAG,UAAU,CAAC,OAAO;KACrE;AACH;;MCzMa,OAAO,CAAA;uGAAP,OAAO,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAP,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,OAAO,EAPR,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,cAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EAAA;;;;AAIT,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,EAAA,CAAA,EAAA,CAAA;;2FAGU,OAAO,EAAA,UAAA,EAAA,CAAA;kBAVnB,SAAS;+BACE,cAAc,EAAA,OAAA,EACf,EAAE,EACD,QAAA,EAAA;;;;AAIT,EAAA,CAAA,EAAA;;;ACTH;;;;;;;;;;;;AAYG;IACS;AAAZ,CAAA,UAAY,WAAW,EAAA;;AAErB,IAAA,WAAA,CAAA,WAAA,CAAA,KAAA,CAAA,GAAA,CAAA,CAAA,GAAA,KAAO;;AAGP,IAAA,WAAA,CAAA,WAAA,CAAA,aAAA,CAAA,GAAA,CAAA,CAAA,GAAA,aAAe;AACjB,CAAC,EANW,WAAW,KAAX,WAAW,GAMtB,EAAA,CAAA,CAAA;;ACjBD;;;;;;;;;;;;;;;;AAgBG;SACa,mBAAmB,CAG/B,QAAgB,EAChB,QAAa,EAAS,EAAA;AAEtB,IAAA,MAAM,IAAI,GAAG,QAAQ,CAAC,WAAW,EAAE;;AAGnC,IAAA,MAAM,QAAQ,GAAyB;;AAEnC,QAAA,GAAG;QACH,YAAY;AACZ,QAAA,QAAQ;AACR,QAAA,QAAQ;AACR,QAAA,KAAK;;QAGL,MAAM;QACN,MAAM;QACN,QAAQ;QACR,QAAQ;QACR,QAAQ;;QAGR,SAAS;QACT,aAAa;;QAGb,QAAQ;QACR,QAAQ;;QAGR,SAAS;QACT,QAAQ;QACR,SAAS;QACT,WAAW;QACX,cAAc;;QAGd,WAAW;QACX,OAAO;QACP,QAAQ;QACR,OAAO;QACP,SAAS;QACT,SAAS;QACT,kBAAkB;;QAGlB,SAAS;QACT,WAAW;;QAGX,MAAM;;QAGN,OAAO;QACP,SAAS;QACT,UAAU;;QAGV,mBAAmB;QACnB,YAAY;QACZ,WAAW;KACd;IAED,MAAM,GAAG,GAAG,CAAC,GAAG,QAAQ,EAAE,GAAG,KAAK,CAAC;IAEnC,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,MAAM,KAAI;QAC9B,GAAG,CAAC,MAAgC,CAAC,GAAG,GAAG,IAAI,CAAA,CAAA,EAAI,MAAM,CAAA,CAAE;AAC3D,QAAA,OAAO,GAAG;KACb,EAAE,EAA4C,CAAC;AACpD;;ACzFA;;;;;;;;;;;;;AAaG;AACU,MAAA,kBAAkB,GAAG,CAAC,SAAqB,KAAY;AAChE,IAAA,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;AAAE,QAAA,OAAO,EAAE;IAClE,OAAO,SAAS,CAAC,GAAG,CAAC,CAAC,IAAI,CAAA,EAAG,CAAC,CAAC,KAAK,CAAI,CAAA,EAAA,CAAC,CAAC,KAAK,CAAE,CAAA,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;AAChE;AAEA;;;;;;;;;;;;;;;;;;;;;;AAsBG;AACU,MAAA,iBAAiB,GAAG,CAAC,MAA+B,KAAY;AACzE,IAAA,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ;AAAE,QAAA,OAAO,EAAE;;AAGpD,IAAA,MAAM,MAAM,GAAG,EAAE,GAAG,MAAM,EAAE;;AAG5B,IAAA,IAAI,MAAM,IAAI,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE;QACnD,MAAM,CAAC,MAAM,CAAC,GAAG,kBAAkB,CAAC,MAAM,CAAC,MAAM,CAAe,CAAC;;AAGrE,IAAA,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM;SAChC,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,GAAG,CAAC,KAAK,SAAS,IAAI,MAAM,CAAC,GAAG,CAAC,KAAK,IAAI,IAAI,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE;SACrF,GAAG,CAAC,GAAG,IAAG;AACP,QAAA,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC;AAEzB,QAAA,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;;AAEtB,YAAA,OAAO,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAA,CAAA,EAAI,kBAAkB,CAAC,GAAG,GAAG,KAAK,CAAC,QAAQ,EAAE,GAAG,GAAG,CAAC,EAAE;;aACpF;AACH,YAAA,OAAO,CAAG,EAAA,kBAAkB,CAAC,GAAG,CAAC,CAAI,CAAA,EAAA,kBAAkB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE;;AAEhF,KAAC,CAAC;IAEN,OAAO,UAAU,CAAC,MAAM,GAAG,CAAC,GAAG,CAAI,CAAA,EAAA,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA,CAAE,GAAG,EAAE;AAClE;AAEA;;;;;;;;;;;;AAYG;AACU,MAAA,OAAO,GAAG,CAAC,GAA+C,KAAa;AAChF,IAAA,OAAO,CAAC,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,KAAK,CAAC;AAChD;;ACnFA;;;;;;;;;;;;;;;;;;;;;AAqBG;MACmB,MAAM,CAAA;;AAExB,IAAA,GAAG;;AAGH,IAAA,eAAe;;AAGf,IAAA,aAAa;;AAGb,IAAA,WAAW;;AAGX,IAAA,IAAI;;AAGJ,IAAA,UAAU;;AAGV,IAAA,IAAI;;AAGJ,IAAA,MAAM;;AAGN,IAAA,aAAa;;AAGb,IAAA,aAAa;;AAGb,IAAA,UAAU;AACb;;AC1DD;;;;;;;;;;;;;;;;;;;;;;;;AAwBG;MACU,QAAQ,CAAA;AAQV,IAAA,KAAA;AACA,IAAA,KAAA;AART;;;;;AAKG;IACH,WACS,CAAA,KAAa,EACb,KAAqB,EAAA;QADrB,IAAK,CAAA,KAAA,GAAL,KAAK;QACL,IAAK,CAAA,KAAA,GAAL,KAAK;;AAEf;;AC4BD;;AC7DA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyEG;MACU,gBAAgB,CAAA;AAIR,IAAA,aAAa,GAAG,IAAI,eAAe,CAAU,EAAE,IAAI,EAAE,CAAC,EAAE,UAAU,EAAE,EAAE,EAAa,CAAC;AACpF,IAAA,cAAc,GAAG,IAAI,eAAe,CAAY,EAAE,CAAC;AACnD,IAAA,YAAY,GAAG,IAAI,eAAe,CAA8B,IAAI,CAAC;AACrE,IAAA,eAAe,GAAG,IAAI,eAAe,CAAiB,IAAI,CAAC;AAC3D,IAAA,iBAAiB,GAAG,IAAI,eAAe,CAA0B,EAAE,CAAC;AACpE,IAAA,YAAY,GAAG,IAAI,eAAe,CAAgB,IAAI,CAAC;AAExE;;;AAGG;IACH,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,YAAY,EAAE,CAAC,IAAI,CAC5C,oBAAoB,CAAC,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,EACnF,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CACjD;AAED;;;AAGG;IACH,QAAQ,GAAG,IAAI,CAAC,cAAc,CAAC,YAAY,EAAE,CAAC,IAAI,CAC9C,oBAAoB,EAAE,EACtB,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CACjD;AAED;;;AAGG;IACH,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,YAAY,EAAE,CAAC,IAAI,CAC1C,oBAAoB,CAAC,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,EACnF,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CACjD;AAED;;;AAGG;IACH,SAAS,GAAG,IAAI,CAAC,eAAe,CAAC,YAAY,EAAE,CAAC,IAAI,CAChD,oBAAoB,EAAE,EACtB,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CACjD;AAED;;;AAGG;IACH,QAAQ,GAAG,IAAI,CAAC,iBAAiB,CAAC,YAAY,EAAE,CAAC,IAAI,CACjD,oBAAoB,CAAC,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,EACnF,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CACjD;AAED;;;AAGG;IACH,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,YAAY,EAAE,CAAC,IAAI,CAC1C,oBAAoB,EAAE,EACtB,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CACjD;;AAGD,IAAA,IAAI,aAAa,GAAA;AACb,QAAA,OAAO,IAAI,CAAC,aAAa,CAAC,KAAK;;;AAInC,IAAA,IAAI,cAAc,GAAA;AACd,QAAA,OAAO,IAAI,CAAC,cAAc,CAAC,KAAK;;;AAIpC,IAAA,IAAI,QAAQ,GAAA;AACR,QAAA,OAAO,IAAI,CAAC,eAAe,CAAC,KAAK;;AAGrC;;;AAGG;AACH,IAAA,SAAS,CAAC,MAAwB,EAAA;AAC9B,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,KAAK;AACxC,QAAA,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,GAAG,OAAO,EAAE,GAAG,MAAM,EAAE,CAAC;;AAGtD;;;AAGG;AACH,IAAA,UAAU,CAAC,OAAkB,EAAA;AACzB,QAAA,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC;;AAGrC;;;AAGG;AACH,IAAA,aAAa,CAAC,OAAkB,EAAA;AAC5B,QAAA,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,cAAc,EAAE,GAAG,OAAO,CAAC,CAAC;;AAGlE;;;AAGG;AACH,IAAA,QAAQ,CAAC,KAA2B,EAAA;AAChC,QAAA,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC;;AAGjC;;;AAGG;AACH,IAAA,cAAc,CAAC,QAA+B,EAAA;AAC1C,QAAA,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC;AACjC,QAAA,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC;;AAGjC;;;;;;;;;;;;;;;;;;;AAmBG;IACH,OAAO,CAAC,MAAc,EAAE,IAAqB,EAAA;AACzC,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,KAAK;AACxC,QAAA,IAAI,SAAS,GAAG,CAAC,IAAI,OAAO,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;AACzC,QAAA,MAAM,KAAK,GAAG,SAAS,CAAC,SAAS,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,KAAK,MAAM,CAAC;AAEhE,QAAA,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE;;AAEd,YAAA,IAAI,IAAI,KAAK,SAAS,EAAE;;AAEpB,gBAAA,SAAS,CAAC,KAAK,CAAC,GAAG,IAAI,QAAQ,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC;;iBAC1D;;gBAEH,MAAM,YAAY,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,KAAK;AAC3C,gBAAA,MAAM,QAAQ,GAAG,YAAY,KAAK,KAAK,GAAG,MAAM,GAAG,KAAK;AACxD,gBAAA,SAAS,CAAC,KAAK,CAAC,GAAG,IAAI,QAAQ,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,QAAQ,CAAC;;;aAElE;;AAEH,YAAA,SAAS,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,MAAM,EAAE,IAAI,IAAI,KAAK,CAAC,CAAC;;AAGvD,QAAA,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC;AACpB,YAAA,GAAG,OAAO;AACV,YAAA,IAAI,EAAE;AACT,SAAA,CAAC;;AAGN;;;AAGG;AACH,IAAA,UAAU,CAAC,MAAc,EAAA;AACrB,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,KAAK;QACxC,MAAM,SAAS,GAAG,CAAC,IAAI,OAAO,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,KAAK,MAAM,CAAC;AAEjF,QAAA,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC;AACpB,YAAA,GAAG,OAAO;AACV,YAAA,IAAI,EAAE;AACT,SAAA,CAAC;;AAGN;;AAEG;IACH,SAAS,GAAA;AACL,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,KAAK;AAExC,QAAA,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC;AACpB,YAAA,GAAG,OAAO;AACV,YAAA,IAAI,EAAE;AACT,SAAA,CAAC;;AAGN;;;;;;;;;;AAUG;AACH,IAAA,UAAU,CAAC,GAAW,EAAA;AAClB,QAAA,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CACrB,GAAG,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,EAC1B,oBAAoB,EAAE,EACtB,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CACjD;;AAGL;;;;;;AAMG;IACH,UAAU,CAAC,GAAW,EAAE,KAAc,EAAA;AAClC,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,iBAAiB,CAAC,KAAK;AAC5C,QAAA,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,EAAE,GAAG,OAAO,EAAE,CAAC,GAAG,GAAG,KAAK,EAAE,CAAC;;AAG7D;;;AAGG;AACH,IAAA,QAAQ,CAAC,KAAoB,EAAA;AACzB,QAAA,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC;;AAGjC;;;AAGG;AACH,IAAA,MAAM,CAAC,MAAe,EAAA;AAClB,QAAA,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC;;;IAIrC,cAAc,GAAA;AACV,QAAA,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC;;AAGnC;;;;AAIC;AACD,IAAA,YAAY,CAAC,GAAY,EAAA;QACrB,IAAI,GAAG,EAAE;AACL,YAAA,MAAM,EAAE,CAAC,GAAG,GAAG,CAAC,EAAE,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC,iBAAiB,CAAC,KAAK;AAC1D,YAAA,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC;;aAC9B;AACH,YAAA,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,EAAE,CAAC;;;;IAKvC,KAAK,GAAA;AACD,QAAA,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC;AAC5B,QAAA,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC;AAC5B,QAAA,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC;AAC/B,QAAA,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,UAAU,EAAE,EAAE,EAAsB,CAAC;QAC/D,IAAI,CAAC,YAAY,EAAE;AACnB,QAAA,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;;AAGvB;;;;AAIG;AACH,IAAA,gBAAgB,CAAC,EAAmB,EAAE,KAAA,GAAuB,IAAqB,EAAA;QAC9E,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC;;AAG9E;;;;AAIG;AACH,IAAA,aAAa,CAAC,OAAgB,EAAE,KAAA,GAAuB,IAAqB,EAAA;AACxE,QAAA,IAAI,CAAC,cAAc,CAAC,IAAI,CACpB,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,KAAK,OAAO,CAAC,KAAK,CAAC,GAAG,OAAO,GAAG,CAAC,CAAC,CAC1E;;AAGL;;;;AAIG;AACH,IAAA,UAAU,CAAC,MAAe,EAAE,KAAA,GAAuB,IAAqB,EAAA;AACpE,QAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,eAAe,CAAC,KAAK;AAC3C,QAAA,OAAO,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,KAAK,MAAM,CAAC,KAAK,CAAC,GAAG,KAAK;;AAG/D;;;AAGG;AACH,IAAA,OAAO,CAAC,IAAY,EAAA;AAChB,QAAA,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAsB,CAAC;;AAGhD;;;AAGG;AACH,IAAA,aAAa,CAAC,UAAkB,EAAA;AAC5B,QAAA,IAAI,CAAC,SAAS,CAAC,EAAE,UAAU,EAAsB,CAAC;;AAGtD;;;AAGG;IACH,WAAW,CAAC,QAA6B,GAAA,EAAE,IAAI,EAAE,CAAC,EAAE,UAAU,EAAE,EAAE,EAAsB,EAAA;AACpF,QAAA,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,QAAmB,CAAC;;;IAIhD,YAAY,GAAA;AACR,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK;QACrC,OAAO,CAAC,CAAC,KAAK,IAAI,KAAK,CAAC,WAAY,GAAG,KAAK,CAAC,QAAS;;;IAI1D,eAAe,GAAA;AACX,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK;QACrC,OAAO,CAAC,CAAC,KAAK,IAAI,KAAK,CAAC,WAAY,GAAG,CAAC;;;IAI5C,OAAO,GAAA;QACH,IAAI,CAAC,KAAK,EAAE;QACZ,IAAI,CAAC,oBAAoB,EAAE;;AAG/B;;;;AAIG;AACH,IAAA,oBAAoB,CAAC,QAAgI,EAAA;AACjJ,QAAA,MAAM,WAAW,GAAG;YAChB,aAAa,EAAE,IAAI,CAAC,aAAa;YACjC,cAAc,EAAE,IAAI,CAAC,cAAc;YACnC,YAAY,EAAE,IAAI,CAAC,YAAY;YAC/B,eAAe,EAAE,IAAI,CAAC,eAAe;YACrC,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;YACzC,YAAY,EAAE,IAAI,CAAC,YAAY;SAClC;QAED,MAAM,UAAU,GAAG,QAAQ,IAAI,MAAM,CAAC,IAAI,CAAC,WAAW,CAAoC;AAC1F,QAAA,UAAU,CAAC,OAAO,CAAC,GAAG,IAAI,WAAW,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,CAAC;;AAG7D;;AClbD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqEG;MACmB,WAAW,CAAA;AAaf,IAAA,IAAA;AACA,IAAA,OAAA;AARd;;;;;AAKG;IACH,WACc,CAAA,IAAgB,EAChB,OAAe,EAAA;QADf,IAAI,CAAA,IAAA,GAAJ,IAAI;QACJ,IAAO,CAAA,OAAA,GAAP,OAAO;;AAGrB;;;;;;;;;;;;;;;;;;;;;;;;AAwBG;IACH,MAAM,CAAC,SAAkB,EAAa,EAAA;AAClC,QAAA,MAAM,YAAY,GAAG,eAAe,CAAC,MAAM,CAAC;AAC5C,QAAA,MAAM,KAAK,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,iBAAiB,CAAC,YAAY,CAAC,GAAG,EAAE;AACrE,QAAA,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAA6B,CAAA,EAAG,IAAI,CAAC,OAAO,CAAA,EAAG,KAAK,CAAA,CAAE,CAAC;;AAG/E;;;;;;;;;;;;AAYG;AACH,IAAA,UAAU,CAAC,EAAU,EAAA;AACjB,QAAA,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAe,CAAA,EAAG,IAAI,CAAC,OAAO,CAAA,CAAA,EAAI,EAAE,CAAA,CAAE,CAAC;;AAG/D;;;;;;;;;;;;;;;;AAgBG;AACH,IAAA,MAAM,CAAC,IAAa,EAAA;AAChB,QAAA,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAe,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC;;AAG3D;;;;;;;;;;;;;;;;AAgBG;IACH,MAAM,CAAC,EAAU,EAAE,IAAa,EAAA;AAC5B,QAAA,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAe,CAAG,EAAA,IAAI,CAAC,OAAO,IAAI,EAAE,CAAA,CAAE,EAAE,IAAI,CAAC;;AAGrE;;;;;;;;;;;;;;;;;;;;;;;AAuBG;AACH,IAAA,MAAM,CAAC,EAAU,EAAE,MAAA,GAA0B,MAAM,EAAA;AAC/C,QAAA,MAAM,WAAW,GAAG,CAAW,QAAA,EAAA,MAAM,EAAE;AACvC,QAAA,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,CAAqB,CAAG,EAAA,IAAI,CAAC,OAAO,IAAI,EAAE,CAAA,EAAG,WAAW,CAAA,CAAE,CAAC;;AAEzF;;ACtKD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkCG;MAEU,eAAe,CAAA;AAClB,IAAA,MAAM,GAA0B;AACtC,QAAA,SAAS,EAAE;KACZ;AAED;;;;AAIG;AACH,IAAA,SAAS,CAAC,MAA6B,EAAA;AACrC,QAAA,IAAI,CAAC,MAAM,GAAG,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,MAAM,EAAE;;AAG7C;;;;;AAKG;AACH,IAAA,WAAW,CAAC,KAAwB,EAAA;QAClC,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC;AAE1C,QAAA,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE;AACzB,YAAA,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC;;AAG1B,QAAA,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE;AACvB,YAAA,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC;;AAGhC,QAAA,OAAO,SAAS;;AAGlB;;;;;AAKG;AACH,IAAA,mBAAmB,CAAC,KAAwB,EAAA;AAC1C,QAAA,IAAI,IAAI,CAAC,MAAM,CAAC,uBAAuB,EAAE;YACvC,OAAO,IAAI,CAAC,MAAM,CAAC,uBAAuB,CAAC,KAAK,CAAC;;;QAInD,IAAI,KAAK,CAAC,KAAK,IAAI,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ,EAAE;AAClD,YAAA,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAuD;;AAG9E,YAAA,IAAI,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE;AAC3B,gBAAA,OAAO,QAAQ,CAAC,KAAK,CAAC,OAAO;;;AAI/B,YAAA,IAAI,QAAQ,CAAC,OAAO,EAAE;gBACpB,OAAO,QAAQ,CAAC,OAAO;;;;QAK3B,OAAO,IAAI,CAAC,0BAA0B,CAAC,KAAK,CAAC,MAAM,CAAC;;AAGtD;;;;;AAKG;AACK,IAAA,0BAA0B,CAAC,MAAc,EAAA;QAC/C,QAAQ,MAAM;AACZ,YAAA,KAAK,CAAC;AACJ,gBAAA,OAAO,yEAAyE;AAClF,YAAA,KAAK,GAAG;AACN,gBAAA,OAAO,yDAAyD;AAClE,YAAA,KAAK,GAAG;AACN,gBAAA,OAAO,sDAAsD;AAC/D,YAAA,KAAK,GAAG;AACN,gBAAA,OAAO,oDAAoD;AAC7D,YAAA,KAAK,GAAG;AACN,gBAAA,OAAO,uCAAuC;AAChD,YAAA,KAAK,GAAG;AACN,gBAAA,OAAO,oCAAoC;AAC7C,YAAA,KAAK,GAAG;AACN,gBAAA,OAAO,6EAA6E;AACtF,YAAA,KAAK,GAAG;AACN,gBAAA,OAAO,6CAA6C;AACtD,YAAA,KAAK,GAAG;AACN,gBAAA,OAAO,wDAAwD;AACjE,YAAA,KAAK,GAAG;AACN,gBAAA,OAAO,4DAA4D;AACrE,YAAA,KAAK,GAAG;AACN,gBAAA,OAAO,qDAAqD;AAC9D,YAAA,KAAK,GAAG;AACN,gBAAA,OAAO,8CAA8C;AACvD,YAAA,KAAK,GAAG;AACN,gBAAA,OAAO,uDAAuD;AAChE,YAAA;gBACE,IAAI,MAAM,IAAI,GAAG,IAAI,MAAM,GAAG,GAAG,EAAE;AACjC,oBAAA,OAAO,mDAAmD;;AACrD,qBAAA,IAAI,MAAM,IAAI,GAAG,EAAE;AACxB,oBAAA,OAAO,gDAAgD;;AAEzD,gBAAA,OAAO,iDAAiD;;;AAI9D;;;;;AAKG;AACK,IAAA,YAAY,CAAC,MAAc,EAAA;AACjC,QAAA,IAAI,MAAM,KAAK,CAAC,EAAE;AAChB,YAAA,OAAO,SAAS;;aACX,IAAI,MAAM,IAAI,GAAG,IAAI,MAAM,GAAG,GAAG,EAAE;AACxC,YAAA,OAAO,QAAQ;;AACV,aAAA,IAAI,MAAM,IAAI,GAAG,EAAE;AACxB,YAAA,OAAO,QAAQ;;AAEjB,QAAA,OAAO,SAAS;;AAGlB;;;;;AAKG;AACK,IAAA,gBAAgB,CAAC,KAAwB,EAAA;;QAE/C,IAAI,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,iBAAiB,KAAK,SAAS,EAAE;AACvD,YAAA,OAAO,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,iBAAiB;;;;AAK5C,QAAA,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM;AAC3B,QAAA,OAAO,MAAM,KAAK,CAAC,KAAK,MAAM,IAAI,GAAG,IAAI,MAAM,GAAG,GAAG,CAAC;;AAGxD;;;;;AAKG;AACK,IAAA,YAAY,CAAC,KAAwB,EAAA;QAC3C,MAAM,OAAO,GAAG,IAAI,CAAC,mBAAmB,CAAC,KAAK,CAAC;QAC/C,MAAM,IAAI,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,MAAM,CAAC;QAC5C,MAAM,UAAU,GAAG,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC;AAE/C,QAAA,IAAI,OAA2B;AAC/B,QAAA,IAAI,IAAwB;;QAG5B,IAAI,KAAK,CAAC,KAAK,IAAI,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ,EAAE;AAClD,YAAA,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAsC;AAC7D,YAAA,IAAI,QAAQ,CAAC,KAAK,EAAE;AAClB,gBAAA,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,OAAO;AAChC,gBAAA,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI;;;QAI9B,OAAO;YACL,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,OAAO;YACP,OAAO;YACP,IAAI;AACJ,YAAA,aAAa,EAAE,KAAK;YACpB,UAAU;YACV;SACD;;AAGH;;;;AAIG;AACK,IAAA,QAAQ,CAAC,KAAqB,EAAA;QACpC,MAAM,KAAK,GAAG,oCAAoC;AAElD,QAAA,OAAO,CAAC,KAAK,CAAC,gBAAgB,EAAE,KAAK,CAAC;QACtC,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,CAAC,MAAM,CAAC;QACpC,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC;QAChC,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,KAAK,CAAC,OAAO,CAAC;AAEtC,QAAA,IAAI,KAAK,CAAC,IAAI,EAAE;YACd,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC;;AAGlC,QAAA,IAAI,KAAK,CAAC,OAAO,EAAE;YACjB,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,KAAK,CAAC,OAAO,CAAC;;QAGxC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC;AAC5C,QAAA,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,CAAC,aAAa,CAAC,KAAK,EAAE,MAAM,IAAI,SAAS,CAAC;QACtE,OAAO,CAAC,GAAG,CAAC,iBAAiB,EAAE,KAAK,CAAC,aAAa,CAAC;QACnD,OAAO,CAAC,QAAQ,EAAE;;uGAzMT,eAAe,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;AAAf,IAAA,OAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,eAAe,cADF,MAAM,EAAA,CAAA;;2FACnB,eAAe,EAAA,UAAA,EAAA,CAAA;kBAD3B,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE;;;AC1ElC;;;;;;;;;;;;AAYG;MACU,mBAAmB,GAAsB,CAAC,GAAG,EAAE,IAAI,KAAI;AAClE,IAAA,MAAM,YAAY,GAAG,MAAM,CAAC,eAAe,CAAC;AAE5C,IAAA,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CACnB,UAAU,CAAC,CAAC,KAAwB,KAAI;QACtC,MAAM,YAAY,GAAG,YAAY,CAAC,WAAW,CAAC,KAAK,CAAC;AACpD,QAAA,OAAO,UAAU,CAAC,MAAM,YAAY,CAAC;KACtC,CAAC,CACH;AACH;;AC3BA;;AAEG;;ACFH;;AAEG;;;;"}
1
+ {"version":3,"file":"mysteryinfosolutions-api-core.mjs","sources":["../../../projects/api-core/src/lib/configs/base-resource-config.ts","../../../projects/api-core/src/lib/configs/api-core-config.ts","../../../projects/api-core/src/lib/api-core.ts","../../../projects/api-core/src/lib/enums/selectmodes.enum.ts","../../../projects/api-core/src/lib/utils/permission.util.ts","../../../projects/api-core/src/lib/utils/query-utils.ts","../../../projects/api-core/src/lib/models/filter.model.ts","../../../projects/api-core/src/lib/models/sort.model.ts","../../../projects/api-core/src/lib/types/permission.type.ts","../../../projects/api-core/src/lib/services/base-state.service.ts","../../../projects/api-core/src/lib/services/base.service.ts","../../../projects/api-core/src/lib/services/api-error-handler.service.ts","../../../projects/api-core/src/lib/interceptors/api-error.interceptor.ts","../../../projects/api-core/src/public-api.ts","../../../projects/api-core/src/mysteryinfosolutions-api-core.ts"],"sourcesContent":["// base-resource-config.ts\nimport { TableColumn } from \"../models\";\nimport { StandardPermission } from \"../types\";\n\n/**\n * BaseResourceConfig<T>\n *\n * A generic configuration class to standardize table-based resource UIs.\n * Extend this in feature modules (e.g., Users, Roles, Genders) to reuse core settings.\n */\nexport abstract class BaseResourceConfig<T> {\n /**\n * Table columns definition for the resource.\n */\n columns: TableColumn<T>[] = [];\n\n /**\n * The column used for date-range filtering (e.g., in filters or reporting).\n */\n dateRangeColumn: keyof T | string = 'updated_at';\n\n /**\n * Default column used to sort the table data.\n */\n defaultSortColumn: keyof T | string | null = 'updated_at';\n\n /**\n * Default sorting order (ASC or DESC).\n */\n defaultSortOrder: 'ASC' | 'DESC' = 'DESC';\n\n /**\n * Page size options for the table paginator.\n */\n pageLengthOptions: number[] = [10, 25, 50, 100];\n\n /**\n * Default page size.\n */\n defaultPageLength: number = 10;\n\n /**\n * Keys (fields) to apply search filter on.\n */\n searchColumns: (keyof T | string)[] = [];\n\n /**\n * Modal configuration: size for the create/update (modify) modal.\n */\n modifyModalSize: 'sm' | 'md' | 'lg' | 'xl' | string = 'md';\n\n /**\n * Modal configuration: fullscreen setting for modify modal.\n */\n modifyModalFullscreen: 'sm' | 'md' | 'lg' | 'xl' | 'xxl' | boolean | string = false;\n\n /**\n * Modal configuration: size for the view/summary modal.\n */\n summaryModalSize: 'sm' | 'lg' | 'xl' | string = 'md';\n\n /**\n * Modal configuration: fullscreen setting for summary modal.\n */\n summaryModalFullscreen: 'sm' | 'md' | 'lg' | 'xl' | 'xxl' | boolean | string = false;\n\n /**\n * Determines the default view when viewing details of a record.\n * 'overview' = navigates to a new page\n * 'summary' = opens a modal with summary component\n */\n defaultDetailView: 'overview' | 'summary' = 'summary';\n\n /**\n * Permissions map generated from the resource name.\n * Override in child class or call helper in constructor.\n */\n permissions!: Record<StandardPermission | string, string>;\n}\n","import { InjectionToken } from '@angular/core';\n\n/**\n * Configuration options for the api-core library.\n * \n * @example\n * // In your app.config.ts or module providers\n * import { API_CORE_CONFIG, ApiCoreConfig } from '@mysteryinfosolutions/api-core';\n * \n * export const appConfig: ApplicationConfig = {\n * providers: [\n * {\n * provide: API_CORE_CONFIG,\n * useValue: {\n * pagination: {\n * defaultPage: 1,\n * defaultPageLength: 25,\n * pageLengthOptions: [25, 50, 100]\n * },\n * api: {\n * dateFormat: 'iso',\n * includeCredentials: true\n * }\n * } as ApiCoreConfig\n * }\n * ]\n * };\n */\nexport interface ApiCoreConfig {\n /**\n * Pagination configuration defaults\n */\n pagination?: {\n /** Default page number (1-based) */\n defaultPage?: number;\n \n /** Default number of items per page */\n defaultPageLength?: number;\n \n /** Available page length options for user selection */\n pageLengthOptions?: number[];\n \n /** Maximum allowed page length (to prevent large requests) */\n maxPageLength?: number;\n };\n\n /**\n * API request/response configuration\n */\n api?: {\n /** Date format for API requests ('iso' | 'timestamp' | 'custom') */\n dateFormat?: 'iso' | 'timestamp' | 'custom';\n \n /** Custom date formatter function (if dateFormat is 'custom') */\n dateFormatter?: (date: Date) => string;\n \n /** Whether to include credentials in requests */\n includeCredentials?: boolean;\n \n /** Default headers to include in all requests */\n defaultHeaders?: Record<string, string>;\n \n /** Request timeout in milliseconds */\n timeout?: number;\n };\n\n /**\n * Query string formatting options\n */\n queryString?: {\n /** Format for array parameters ('brackets' | 'comma' | 'repeat') */\n arrayFormat?: 'brackets' | 'comma' | 'repeat';\n \n /** Custom array formatter function */\n arrayFormatter?: (key: string, values: unknown[]) => string;\n \n /** Whether to encode query parameters */\n encode?: boolean;\n \n /** Custom encoder function */\n encoder?: (value: string) => string;\n };\n\n /**\n * Sort configuration\n */\n sort?: {\n /** Default sort order */\n defaultOrder?: 'ASC' | 'DESC';\n \n /** Separator between field and order in query string */\n separator?: string;\n \n /** Whether to allow multi-column sorting */\n allowMultiSort?: boolean;\n };\n\n /**\n * Error handling configuration\n */\n errorHandling?: {\n /** Whether to log errors to console */\n logErrors?: boolean;\n \n /** Whether to show user-friendly error messages */\n showUserMessages?: boolean;\n \n /** Global error handler function */\n onError?: (error: unknown) => void;\n };\n\n /**\n * Loading state configuration\n */\n loading?: {\n /** Minimum loading time in ms (prevents flash of loading state) */\n minLoadingTime?: number;\n \n /** Whether to show loading indicators by default */\n showLoadingByDefault?: boolean;\n };\n}\n\n/**\n * Default configuration values for the api-core library.\n */\nexport const DEFAULT_API_CORE_CONFIG: Required<ApiCoreConfig> = {\n pagination: {\n defaultPage: 1,\n defaultPageLength: 10,\n pageLengthOptions: [10, 25, 50, 100],\n maxPageLength: 1000\n },\n api: {\n dateFormat: 'iso',\n dateFormatter: (date: Date) => date.toISOString(),\n includeCredentials: false,\n defaultHeaders: {},\n timeout: 30000 // 30 seconds\n },\n queryString: {\n arrayFormat: 'brackets',\n arrayFormatter: (key: string, values: unknown[]) => `${key}=[${values.join(',')}]`,\n encode: true,\n encoder: (value: string) => encodeURIComponent(value)\n },\n sort: {\n defaultOrder: 'ASC',\n separator: ':',\n allowMultiSort: true\n },\n errorHandling: {\n logErrors: true,\n showUserMessages: true,\n onError: (error: unknown) => console.error('API Error:', error)\n },\n loading: {\n minLoadingTime: 0,\n showLoadingByDefault: true\n }\n};\n\n/**\n * Injection token for api-core configuration.\n * \n * @example\n * // Provide custom configuration\n * providers: [\n * {\n * provide: API_CORE_CONFIG,\n * useValue: {\n * pagination: { defaultPageLength: 25 }\n * } as ApiCoreConfig\n * }\n * ]\n * \n * @example\n * // Inject in service\n * constructor(@Inject(API_CORE_CONFIG) private config: ApiCoreConfig) {}\n */\nexport const API_CORE_CONFIG = new InjectionToken<ApiCoreConfig>(\n 'api-core.config',\n {\n providedIn: 'root',\n factory: () => DEFAULT_API_CORE_CONFIG\n }\n);\n\n/**\n * Merges user-provided configuration with default values.\n * \n * @param userConfig User-provided configuration\n * @returns Merged configuration with defaults\n * \n * @example\n * const config = mergeConfig({\n * pagination: { defaultPageLength: 25 }\n * });\n * // Returns full config with defaultPageLength: 25 and all other defaults\n */\nexport function mergeConfig(userConfig?: ApiCoreConfig): Required<ApiCoreConfig> {\n if (!userConfig) {\n return DEFAULT_API_CORE_CONFIG;\n }\n\n return {\n pagination: { ...DEFAULT_API_CORE_CONFIG.pagination, ...userConfig.pagination },\n api: { ...DEFAULT_API_CORE_CONFIG.api, ...userConfig.api },\n queryString: { ...DEFAULT_API_CORE_CONFIG.queryString, ...userConfig.queryString },\n sort: { ...DEFAULT_API_CORE_CONFIG.sort, ...userConfig.sort },\n errorHandling: { ...DEFAULT_API_CORE_CONFIG.errorHandling, ...userConfig.errorHandling },\n loading: { ...DEFAULT_API_CORE_CONFIG.loading, ...userConfig.loading }\n };\n}\n\n\n","import { Component } from '@angular/core';\n\n@Component({\n selector: 'lib-api-core',\n imports: [],\n template: `\n <p>\n api-core works!\n </p>\n `,\n styles: ``\n})\nexport class ApiCore {\n\n}\n","/**\n * Enum defining column selection modes for API queries.\n * \n * @remarks\n * Used to control which columns are returned in API responses,\n * useful for optimizing payload size and performance.\n * \n * @example\n * const filter = {\n * selectMode: SELECT_MODE.ONLYCOLUMNS,\n * selectColumns: 'id,name,email'\n * };\n */\nexport enum SELECT_MODE {\n /** Return all columns (default behavior) */\n ALL = 1,\n \n /** Return only specified columns via selectColumns parameter */\n ONLYCOLUMNS = 2,\n}\n","import { StandardPermission } from \"../types\";\n\n/**\n * Generates a permission mapping object for a given resource.\n *\n * @template T - Additional custom permissions (optional).\n * @param resource - The base resource name (e.g., 'brand', 'user').\n * @param extra - An optional array of additional/custom permissions to include.\n * @returns A record mapping each permission key (e.g., 'view') to a namespaced string (e.g., 'brand.view').\n *\n * @example\n * generatePermissions('brand')\n * // {\n * // view: 'brand.view',\n * // create: 'brand.create',\n * // update: 'brand.update',\n * // ...\n * // }\n */\nexport function generatePermissions<\n T extends string = StandardPermission\n>(\n resource: string,\n extra: T[] = [] as T[]\n): Record<T | StandardPermission, string> {\n const base = resource.toLowerCase();\n\n // Core standard permissions extended with advanced actions\n const standard: StandardPermission[] = [\n // Common\n '*', // All permissions\n 'superAdmin',\n 'manage', // Manage the record (CRUD)\n 'access', // Access the record (view, edit, delete)\n 'own', // Own the record (create, update, delete)\n\n // CRUD\n 'view',\n 'list',\n 'create',\n 'update',\n 'delete',\n\n // Deletion handling\n 'restore',\n 'forceDelete',\n\n // Import/export\n 'export',\n 'import',\n\n // Workflow/status\n 'approve',\n 'reject',\n 'archive',\n 'unarchive',\n 'changeStatus',\n\n // UI & actions\n 'duplicate',\n 'share',\n 'assign',\n 'print',\n 'preview',\n 'reorder',\n 'toggleVisibility',\n\n // Content lifecycle\n 'publish',\n 'unpublish',\n\n // External integration\n 'sync',\n\n // Auditing & metadata\n 'audit',\n 'comment',\n 'favorite',\n\n // Permissions/admin\n 'managePermissions',\n 'assignRole',\n 'configure',\n ];\n\n const all = [...standard, ...extra];\n\n return all.reduce((acc, action) => {\n acc[action as T | StandardPermission] = `${base}.${action}`;\n return acc;\n }, {} as Record<T | StandardPermission, string>);\n}\n","import { SortItem } from '../models';\n\n/**\n * Converts an array of SortItem objects into a comma-separated sort string.\n * \n * @param sortItems Array of sort configurations\n * @returns Formatted sort string (e.g., \"name:ASC,createdAt:DESC\") or empty string\n * \n * @example\n * const sorts = [\n * new SortItem('name', 'ASC'),\n * new SortItem('createdAt', 'DESC')\n * ];\n * const sortString = sortObjectToString(sorts);\n * // Returns: \"name:ASC,createdAt:DESC\"\n */\nexport const sortObjectToString = (sortItems: SortItem[]): string => {\n if (!Array.isArray(sortItems) || sortItems.length === 0) return '';\n return sortItems.map(s => `${s.field}:${s.order}`).join(',');\n};\n\n/**\n * Converts a filter object into a URL query string.\n * \n * @param filter Filter object with query parameters (any object type)\n * @returns URL query string with '?' prefix, or empty string if no parameters\n * \n * @remarks\n * - Automatically converts SortItem arrays to sort strings\n * - Encodes all values for URL safety\n * - Filters out undefined and null values\n * - Arrays are encoded as comma-separated values in brackets\n * - Works with any object type, including custom filter interfaces\n * \n * @example\n * const filter = {\n * page: 1,\n * pageLength: 25,\n * search: 'John Doe',\n * roles: ['admin', 'user'],\n * sort: [new SortItem('name', 'ASC')]\n * };\n * const queryString = jsonToQueryString(filter);\n * // Returns: \"?page=1&pageLength=25&search=John%20Doe&roles=[admin,user]&sort=name:ASC\"\n * \n * @example\n * // Works with custom filter interfaces\n * interface StockFilter extends Filter {\n * itemVariantIds?: number[];\n * }\n * const stockFilter: StockFilter = {\n * page: 1,\n * itemVariantIds: [1, 2, 3]\n * };\n * jsonToQueryString(stockFilter); // ✅ Works!\n */\nexport const jsonToQueryString = (filter: object | null | undefined): string => {\n if (!filter || typeof filter !== 'object') return '';\n\n // Clone to avoid mutating original - cast to any to handle any object type\n const params: Record<string, unknown> = { ...filter as Record<string, unknown> };\n\n // Convert sort array to string format\n if ('sort' in params && Array.isArray(params['sort'])) {\n params['sort'] = sortObjectToString(params['sort'] as SortItem[]);\n }\n\n const queryArray = Object.keys(params)\n .filter(key => params[key] !== undefined && params[key] !== null && params[key] !== '')\n .map(key => {\n const value = params[key];\n \n if (Array.isArray(value)) {\n // Encode arrays as [item1,item2,item3]\n return `${encodeURIComponent(key)}=${encodeURIComponent('[' + value.toString() + ']')}`;\n } else {\n return `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`;\n }\n });\n\n return queryArray.length > 0 ? `?${queryArray.join('&')}` : '';\n};\n\n/**\n * Checks if an object is empty (has no own properties).\n * \n * @param obj Object to check (any object type, null, or undefined)\n * @returns True if object is null, undefined, or has no properties\n * \n * @example\n * isEmpty({}); // true\n * isEmpty(null); // true\n * isEmpty(undefined); // true\n * isEmpty({ page: 1 }); // false\n * isEmpty([]); // true (arrays with no length)\n * \n * @example\n * // Works with any object type\n * interface MyType { id: number; name: string; }\n * const myObj: MyType = { id: 1, name: 'test' };\n * isEmpty(myObj); // false\n */\nexport const isEmpty = (obj: object | null | undefined): boolean => {\n if (obj === null || obj === undefined) {\n return true;\n }\n // Check if it's an array\n if (Array.isArray(obj)) {\n return obj.length === 0;\n }\n // Check if it's an object with no own properties\n return Object.keys(obj).length === 0;\n};\n","import { SortItem } from './';\nimport { SELECT_MODE } from '../enums';\n\n/**\n * Base filter class providing common filtering, pagination, and sorting capabilities.\n * \n * @remarks\n * Extend this class in your custom filter types to add domain-specific filter properties.\n * The base filter handles pagination, sorting, searching, and date range filtering.\n * \n * @example\n * interface UserFilter extends Filter {\n * role?: string;\n * isActive?: boolean;\n * departmentId?: number;\n * }\n * \n * const filter: UserFilter = {\n * page: 1,\n * pageLength: 25,\n * search: 'john',\n * role: 'admin',\n * sort: [new SortItem('name', 'ASC')]\n * };\n */\nexport abstract class Filter {\n /** Array of specific IDs to filter by */\n ids?: number[];\n \n /** Column name to use for date range filtering */\n dateRangeColumn?: string;\n \n /** Start date for date range filter (ISO format) */\n dateRangeFrom?: string;\n \n /** End date for date range filter (ISO format) */\n dateRangeTo?: string;\n\n /** Current page number (1-based) */\n page?: number;\n \n /** Number of records per page */\n pageLength?: number;\n\n /** Array of sort configurations */\n sort?: SortItem[];\n\n /** Search query string */\n search?: string;\n \n /** Comma-separated list of columns to search in */\n searchColumns?: string;\n \n /** Comma-separated list of columns to select/return */\n selectColumns?: string;\n \n /** Mode for column selection */\n selectMode?: SELECT_MODE;\n}","/**\n * Represents a single sort configuration for a field.\n * \n * @remarks\n * Used in filter objects to specify sorting criteria.\n * Multiple SortItem instances can be combined for multi-column sorting.\n * \n * @example\n * // Single sort\n * const sort = new SortItem('name', 'ASC');\n * \n * @example\n * // Multi-column sort\n * const sorts = [\n * new SortItem('priority', 'DESC'),\n * new SortItem('createdAt', 'DESC'),\n * new SortItem('name', 'ASC')\n * ];\n * \n * const filter = {\n * page: 1,\n * pageLength: 25,\n * sort: sorts\n * };\n */\nexport class SortItem {\n /**\n * Creates a sort configuration.\n * \n * @param field The field/column name to sort by\n * @param order Sort direction: 'ASC' (ascending) or 'DESC' (descending)\n */\n constructor(\n public field: string,\n public order: 'ASC' | 'DESC'\n ) {}\n}\n\n","\nexport type StandardPermission =\n // Common\n | '*' // All permissions\n | 'superAdmin' // Super admin permissions\n | 'manage' // Manage the record (CRUD)\n | 'access' // Access the record (view, edit, delete)\n | 'own' // Own the record (create, update, delete)\n\n // Basic CRUD\n | 'view' // View a single record\n | 'list' // View a list of records\n | 'create' // Create a new record\n | 'update' // Update an existing record\n | 'delete' // Soft-delete a record (not permanent)\n\n // Deletion Handling\n | 'restore' // Restore a soft-deleted record\n | 'forceDelete' // Permanently delete a record\n\n // Data Import/Export\n | 'export' // Export data (CSV, Excel, etc.)\n | 'import' // Import data into the system\n\n // Workflow & Status\n | 'approve' // Approve a pending record or request\n | 'reject' // Reject a record or request\n | 'archive' // Archive a record (typically hides it from normal views)\n | 'unarchive' // Unarchive a previously archived record\n\n // Duplication & Sharing\n | 'duplicate' // Duplicate or clone a record\n | 'share' // Share the record with others (e.g., link, team)\n\n // Assignment & Ownership\n | 'assign' // Assign the record to a user or group\n | 'changeStatus' // Change the record’s custom status (if not approve/reject)\n\n // Output and Preview\n | 'print' // Generate a printable version\n | 'preview' // Preview before saving or publishing\n\n // Content Lifecycle\n | 'publish' // Make the record public/visible\n | 'unpublish' // Revert the record back to draft/private\n\n // External Integration\n | 'sync' // Synchronize data with an external system\n\n // Auditing & Monitoring\n | 'audit' // View audit log/history of a record\n\n // Communication & Metadata\n | 'comment' // Add or view comments on a record\n | 'favorite' // Mark the record as favorite/bookmarked\n\n // UI-Specific\n | 'reorder' // Change the order (drag & drop, sequence)\n | 'toggleVisibility' // Enable/disable visibility (e.g., toggle switch)\n\n // Admin/Permission Management\n | 'managePermissions' // Manage permissions for this resource\n | 'assignRole' // Assign roles related to the resource\n | 'configure'; // Modify configuration/settings for the resource\n;\n","import { BehaviorSubject, map, Observable, distinctUntilChanged, shareReplay } from \"rxjs\";\nimport { Filter, IMultiresult, IMultiresultMetaData, SortItem } from \"../models\";\n\n/**\n * Generic reactive state management service for data-driven features.\n * \n * @template TRecord The type of record/entity being managed\n * @template TFilter Filter type extending Partial<TRecord> & Filter\n * \n * @remarks\n * BaseStateService provides comprehensive state management for list-based views including:\n * - Filter state with pagination and sorting\n * - Records collection with CRUD helpers\n * - Loading states (with context keys)\n * - Error handling\n * - Record selection\n * - Pagination metadata\n * \n * All state is reactive using RxJS BehaviorSubjects, making it easy to integrate\n * with Angular templates using the async pipe.\n * \n * @example\n * // Basic setup in component\n * @Component({\n * selector: 'app-users',\n * providers: [BaseStateService] // Component-level instance\n * })\n * export class UsersComponent implements OnInit, OnDestroy {\n * state = new BaseStateService<User, UserFilter>();\n * \n * constructor(private userService: UserService) {}\n * \n * ngOnInit() {\n * // Subscribe to filter changes\n * this.state.filter$.subscribe(filter => {\n * this.loadUsers(filter);\n * });\n * \n * // Set initial filter\n * this.state.setFilter({ page: 1, pageLength: 25 });\n * }\n * \n * loadUsers(filter: UserFilter) {\n * this.state.setLoading('list', true);\n * \n * this.userService.getAll(filter).subscribe({\n * next: (response) => {\n * if (response.data) {\n * this.state.setApiResponse(response.data);\n * }\n * this.state.setLoading('list', false);\n * },\n * error: (err) => {\n * this.state.setError('Failed to load users');\n * this.state.setLoading('list', false);\n * }\n * });\n * }\n * \n * ngOnDestroy() {\n * this.state.destroy();\n * }\n * }\n * \n * @example\n * // Using in template\n * <div *ngIf=\"state.isLoading$('list') | async\">Loading...</div>\n * <div *ngIf=\"state.error$ | async as error\">{{ error }}</div>\n * \n * <div *ngFor=\"let user of state.records$ | async\">\n * {{ user.name }}\n * </div>\n * \n * <div *ngIf=\"state.pager$ | async as pager\">\n * Page {{ pager.currentPage }} of {{ pager.lastPage }}\n * </div>\n */\nexport class BaseStateService<\n TRecord,\n TFilter extends Partial<TRecord> & Filter = Partial<TRecord> & Filter\n> {\n private readonly filterSubject = new BehaviorSubject<TFilter>({ page: 1, pageLength: 10 } as TFilter);\n private readonly recordsSubject = new BehaviorSubject<TRecord[]>([]);\n private readonly pagerSubject = new BehaviorSubject<IMultiresultMetaData | null>(null);\n private readonly selectedSubject = new BehaviorSubject<TRecord | null>(null);\n private readonly loadingMapSubject = new BehaviorSubject<Record<string, boolean>>({});\n private readonly errorSubject = new BehaviorSubject<string | null>(null);\n\n /** \n * Observable stream of current filter.\n * Optimized with distinctUntilChanged to prevent duplicate emissions.\n */\n filter$ = this.filterSubject.asObservable().pipe(\n distinctUntilChanged((prev, curr) => JSON.stringify(prev) === JSON.stringify(curr)),\n shareReplay({ bufferSize: 1, refCount: true })\n );\n\n /** \n * Observable stream of current records.\n * Optimized with distinctUntilChanged for reference equality.\n */\n records$ = this.recordsSubject.asObservable().pipe(\n distinctUntilChanged(),\n shareReplay({ bufferSize: 1, refCount: true })\n );\n\n /** \n * Observable stream of current pager metadata.\n * Optimized with distinctUntilChanged for deep equality.\n */\n pager$ = this.pagerSubject.asObservable().pipe(\n distinctUntilChanged((prev, curr) => JSON.stringify(prev) === JSON.stringify(curr)),\n shareReplay({ bufferSize: 1, refCount: true })\n );\n\n /** \n * Observable stream of the currently selected record.\n * Optimized with distinctUntilChanged for reference equality.\n */\n selected$ = this.selectedSubject.asObservable().pipe(\n distinctUntilChanged(),\n shareReplay({ bufferSize: 1, refCount: true })\n );\n\n /** \n * Observable stream of loading state.\n * Optimized with distinctUntilChanged for deep equality.\n */\n loading$ = this.loadingMapSubject.asObservable().pipe(\n distinctUntilChanged((prev, curr) => JSON.stringify(prev) === JSON.stringify(curr)),\n shareReplay({ bufferSize: 1, refCount: true })\n );\n\n /** \n * Observable stream of current error message.\n * Optimized with distinctUntilChanged for value equality.\n */\n error$ = this.errorSubject.asObservable().pipe(\n distinctUntilChanged(),\n shareReplay({ bufferSize: 1, refCount: true })\n );\n\n /** Returns the current filter. */\n get currentFilter(): TFilter {\n return this.filterSubject.value;\n }\n\n /** Returns the currently loaded records. */\n get currentRecords(): TRecord[] {\n return this.recordsSubject.value;\n }\n\n /** Returns the currently selected record, if any. */\n get selected(): TRecord | null {\n return this.selectedSubject.value;\n }\n\n /**\n * Updates the current filter with new values.\n * @param update Partial filter to merge.\n */\n setFilter(update: Partial<TFilter>) {\n const current = this.filterSubject.value;\n this.filterSubject.next({ ...current, ...update });\n }\n\n /**\n * Replaces all records in the current state.\n * @param records Array of new records.\n */\n setRecords(records: TRecord[]) {\n this.recordsSubject.next(records);\n }\n\n /**\n * Appends records to the current record list.\n * @param records Records to add.\n */\n appendRecords(records: TRecord[]) {\n this.recordsSubject.next([...this.currentRecords, ...records]);\n }\n\n /**\n * Sets the pagination metadata.\n * @param pager Metadata to use.\n */\n setPager(pager: IMultiresultMetaData) {\n this.pagerSubject.next(pager);\n }\n\n /**\n * Sets records and pager data from API response.\n * @param response API response containing records and pager.\n */\n setApiResponse(response: IMultiresult<TRecord>) {\n this.setRecords(response.records);\n this.setPager(response.pager);\n }\n\n /**\n * Updates the sort order in the current filter.\n * Toggles order if column already exists and no explicit sort is provided, or adds it otherwise.\n * \n * @param column Column name to sort by\n * @param sort Optional sort order. If not provided and column exists, toggles between ASC/DESC.\n * If not provided and column doesn't exist, defaults to ASC.\n * \n * @example\n * // Add new sort (defaults to ASC)\n * state.setSort('name');\n * \n * @example\n * // Toggle existing sort\n * state.setSort('name'); // If already ASC, becomes DESC; if DESC, becomes ASC\n * \n * @example\n * // Explicitly set sort order\n * state.setSort('name', 'DESC'); // Always sets to DESC\n */\n setSort(column: string, sort?: \"ASC\" | \"DESC\") {\n const current = this.filterSubject.value;\n let sortItems = [...(current.sort ?? [])];\n const index = sortItems.findIndex(item => item.field === column);\n\n if (index !== -1) {\n // Column already exists in sort\n if (sort !== undefined) {\n // Explicit sort provided - use it\n sortItems[index] = new SortItem(sortItems[index].field, sort);\n } else {\n // No explicit sort - toggle the order\n const currentOrder = sortItems[index].order;\n const newOrder = currentOrder === 'ASC' ? 'DESC' : 'ASC';\n sortItems[index] = new SortItem(sortItems[index].field, newOrder);\n }\n } else {\n // Column doesn't exist - add it (default to ASC if not specified)\n sortItems.push(new SortItem(column, sort ?? 'ASC'));\n }\n\n this.filterSubject.next({\n ...current,\n sort: sortItems\n });\n }\n\n /**\n * Removes a specific column from the current sort.\n * @param column Column name to remove from sorting.\n */\n removeSort(column: string) {\n const current = this.filterSubject.value;\n const sortItems = [...(current.sort ?? [])].filter(item => item.field !== column);\n\n this.filterSubject.next({\n ...current,\n sort: sortItems\n });\n }\n\n /**\n * Clears all sorting from the current filter.\n */\n clearSort() {\n const current = this.filterSubject.value;\n\n this.filterSubject.next({\n ...current,\n sort: []\n });\n }\n\n /**\n * Returns an observable boolean for a specific loading key.\n * Useful for tracking loading state in a specific view or feature.\n *\n * @param key A unique key representing the loading context (e.g., \"list\", \"detail\")\n * @returns Observable emitting `true` if the given context is loading, `false` otherwise.\n * \n * @remarks\n * Optimized with distinctUntilChanged to prevent duplicate emissions\n * and shareReplay to share subscriptions.\n */\n isLoading$(key: string): Observable<boolean> {\n return this.loading$.pipe(\n map(state => !!state[key]),\n distinctUntilChanged(),\n shareReplay({ bufferSize: 1, refCount: true })\n );\n }\n\n /**\n * Sets the loading state for a specific key.\n * This allows you to control multiple concurrent loading states independently.\n *\n * @param key The loading context name (e.g., \"list\", \"form\", \"detail\")\n * @param value The loading status (`true` for loading, `false` for done)\n */\n setLoading(key: string, value: boolean): void {\n const current = this.loadingMapSubject.value;\n this.loadingMapSubject.next({ ...current, [key]: value });\n }\n\n /**\n * Sets the error state.\n * @param error Error message or null.\n */\n setError(error: string | null) {\n this.errorSubject.next(error);\n }\n\n /**\n * Selects a record.\n * @param record The record to select.\n */\n select(record: TRecord) {\n this.selectedSubject.next(record);\n }\n\n /** Clears the current selection. */\n clearSelection() {\n this.selectedSubject.next(null);\n }\n\n /**\n * Clears the loading state for a specific key or all keys if none is provided.\n *\n * @param key Optional. If provided, only that loading key is cleared. If omitted, all are cleared.\n */\n clearLoading(key?: string): void {\n if (key) {\n const { [key]: _, ...rest } = this.loadingMapSubject.value;\n this.loadingMapSubject.next(rest);\n } else {\n this.loadingMapSubject.next({});\n }\n }\n\n /** Resets the entire state to initial values. */\n reset() {\n this.recordsSubject.next([]);\n this.pagerSubject.next(null);\n this.selectedSubject.next(null);\n this.setFilter({ page: 1, pageLength: 10 } as Partial<TFilter>);\n this.clearLoading();\n this.setError(null);\n }\n\n /**\n * Removes a record by its ID field.\n * @param id The ID to remove.\n * @param idKey The record property key used as ID (default: 'id').\n */\n removeRecordById(id: number | string, idKey: keyof TRecord = 'id' as keyof TRecord) {\n this.recordsSubject.next(this.currentRecords.filter(r => r[idKey] !== id));\n }\n\n /**\n * Replaces a record by matching its ID field.\n * @param updated The updated record.\n * @param idKey The record property key used as ID (default: 'id').\n */\n replaceRecord(updated: TRecord, idKey: keyof TRecord = 'id' as keyof TRecord) {\n this.recordsSubject.next(\n this.currentRecords.map(r => r[idKey] === updated[idKey] ? updated : r)\n );\n }\n\n /**\n * Checks if a specific record is currently selected.\n * @param record Record to check.\n * @param idKey Key to use for comparison (default: 'id').\n */\n isSelected(record: TRecord, idKey: keyof TRecord = 'id' as keyof TRecord): boolean {\n const selected = this.selectedSubject.value;\n return selected ? selected[idKey] === record[idKey] : false;\n }\n\n /**\n * Updates the current page number in the filter.\n * @param page Page number.\n */\n setPage(page: number) {\n this.setFilter({ page } as Partial<TFilter>);\n }\n\n /**\n * Updates the page length in the filter.\n * @param pageLength Number of records per page.\n */\n setPageLength(pageLength: number) {\n this.setFilter({ pageLength } as Partial<TFilter>);\n }\n\n /**\n * Resets the filter to default values.\n * @param defaults Default filter values.\n */\n resetFilter(defaults: Partial<TFilter> = { page: 1, pageLength: 10 } as Partial<TFilter>) {\n this.filterSubject.next(defaults as TFilter);\n }\n\n /** Returns true if there are more pages after the current one. */\n hasMorePages(): boolean {\n const pager = this.pagerSubject.value;\n return !!pager && pager.currentPage! < pager.lastPage!;\n }\n\n /** Returns true if a previous page exists. */\n hasPreviousPage(): boolean {\n const pager = this.pagerSubject.value;\n return !!pager && pager.currentPage! > 0;\n }\n\n /** Resets and clears all managed state. */\n destroy() {\n this.reset();\n this.destroySubscriptions();\n }\n\n /**\n * Completes specified subjects managed by this service.\n * If no argument is provided, completes all subjects.\n * @param subjects Array of subject names to complete (e.g., ['filterSubject', 'recordsSubject'])\n */\n destroySubscriptions(subjects?: Array<'filterSubject' | 'recordsSubject' | 'pagerSubject' | 'selectedSubject' | 'loadingMapSubject' | 'errorSubject'>) {\n const allSubjects = {\n filterSubject: this.filterSubject,\n recordsSubject: this.recordsSubject,\n pagerSubject: this.pagerSubject,\n selectedSubject: this.selectedSubject,\n loadingMapSubject: this.loadingMapSubject,\n errorSubject: this.errorSubject,\n };\n\n const toComplete = subjects ?? Object.keys(allSubjects) as Array<keyof typeof allSubjects>;\n toComplete.forEach(key => allSubjects[key].complete());\n }\n\n}\n","import { HttpClient } from '@angular/common/http';\nimport { Observable } from 'rxjs';\nimport { jsonToQueryString, isEmpty } from '../utils/query-utils';\nimport { IMultiresult, IResponse, Filter } from '../models';\n\n/**\n * Abstract base service providing standard CRUD operations for REST APIs.\n * \n * @template T The full model type representing your entity\n * @template TFilter Filter type extending Partial<T> & Filter for query parameters\n * @template TCreate DTO type for creating new records (defaults to Partial<T>)\n * @template TUpdate DTO type for updating records (defaults to Partial<T>)\n * \n * @remarks\n * Extend this class in your feature services to get type-safe CRUD operations\n * with minimal boilerplate. The service automatically handles:\n * - Query string generation from filters\n * - Pagination and sorting\n * - Standardized response/error handling\n * - Type safety throughout the request/response cycle\n * \n * @example\n * // Define your model\n * interface User {\n * id: number;\n * name: string;\n * email: string;\n * role: string;\n * }\n * \n * // Define custom filter\n * interface UserFilter extends Filter {\n * role?: string;\n * isActive?: boolean;\n * }\n * \n * // Create service\n * @Injectable({ providedIn: 'root' })\n * export class UserService extends BaseService<User, UserFilter> {\n * constructor(http: HttpClient) {\n * super(http, '/api/users');\n * }\n * \n * // Add custom methods\n * activateUser(id: number): Observable<IResponse<User>> {\n * return this.http.post<IResponse<User>>(`${this.baseUrl}/${id}/activate`, {});\n * }\n * }\n * \n * @example\n * // With separate DTOs for create/update\n * interface CreateUserDto {\n * name: string;\n * email: string;\n * password: string;\n * }\n * \n * interface UpdateUserDto {\n * name?: string;\n * email?: string;\n * // Note: password excluded\n * }\n * \n * @Injectable({ providedIn: 'root' })\n * export class UserService extends BaseService<\n * User,\n * UserFilter,\n * CreateUserDto,\n * UpdateUserDto\n * > {\n * constructor(http: HttpClient) {\n * super(http, '/api/users');\n * }\n * }\n */\nexport abstract class BaseService<\n T, // Full model type\n TFilter extends Partial<T> & Filter = Partial<T> & Filter, // Filter: model fields + pagination/sorting\n TCreate = Partial<T>, // DTO for create\n TUpdate = Partial<T> // DTO for update\n> {\n /**\n * Creates an instance of BaseService.\n * \n * @param http Angular HttpClient for making HTTP requests\n * @param baseUrl Base URL for the resource API endpoint (e.g., '/api/users')\n */\n constructor(\n protected http: HttpClient,\n protected baseUrl: string\n ) { }\n\n /**\n * Fetches a paginated list of records with optional filtering and sorting.\n * \n * @param filter Optional filter object containing pagination, sorting, and search criteria\n * @returns Observable of response containing records array and pagination metadata\n * \n * @example\n * // Basic usage\n * userService.getAll().subscribe(response => {\n * console.log(response.data?.records);\n * console.log(response.data?.pager.totalRecords);\n * });\n * \n * @example\n * // With filters\n * userService.getAll({\n * page: 2,\n * pageLength: 25,\n * search: 'john',\n * role: 'admin',\n * sort: [new SortItem('name', 'ASC')]\n * }).subscribe(response => {\n * // Handle response\n * });\n */\n getAll(filter: TFilter = {} as TFilter): Observable<IResponse<IMultiresult<T>>> {\n const clonedFilter = structuredClone(filter);\n const query = !isEmpty(filter) ? jsonToQueryString(clonedFilter) : '';\n return this.http.get<IResponse<IMultiresult<T>>>(`${this.baseUrl}${query}`);\n }\n\n /**\n * Fetches a single record by its ID.\n * \n * @param id The unique identifier of the record\n * @returns Observable of response containing the single record\n * \n * @example\n * userService.getDetails(123).subscribe(response => {\n * if (response.data) {\n * console.log('User:', response.data);\n * }\n * });\n */\n getDetails(id: number): Observable<IResponse<T>> {\n return this.http.get<IResponse<T>>(`${this.baseUrl}/${id}`);\n }\n\n /**\n * Creates a new record.\n * \n * @param data Data transfer object containing fields for the new record\n * @returns Observable of response containing the created record (usually with generated ID)\n * \n * @example\n * userService.create({\n * name: 'John Doe',\n * email: 'john@example.com',\n * password: 'secure123'\n * }).subscribe(response => {\n * if (response.data) {\n * console.log('Created user:', response.data);\n * }\n * });\n */\n create(data: TCreate): Observable<IResponse<T>> {\n return this.http.post<IResponse<T>>(this.baseUrl, data);\n }\n\n /**\n * Updates an existing record.\n * \n * @param id The unique identifier of the record to update\n * @param data Data transfer object containing fields to update (partial update supported)\n * @returns Observable of response containing the updated record\n * \n * @example\n * userService.update(123, {\n * name: 'Jane Doe',\n * email: 'jane@example.com'\n * }).subscribe(response => {\n * if (response.data) {\n * console.log('Updated user:', response.data);\n * }\n * });\n */\n update(id: number, data: TUpdate): Observable<IResponse<T>> {\n return this.http.put<IResponse<T>>(`${this.baseUrl}/${id}`, data);\n }\n\n /**\n * Deletes a record (soft or hard delete).\n * \n * @param id The unique identifier of the record to delete\n * @param method Deletion method: 'soft' (mark as deleted, reversible) or 'hard' (permanent removal)\n * @returns Observable of response confirming deletion\n * \n * @remarks\n * - Soft delete: Record is marked as deleted but can be restored later\n * - Hard delete: Record is permanently removed from the database\n * - Default is 'soft' for safety\n * \n * @example\n * // Soft delete (default)\n * userService.delete(123).subscribe(() => {\n * console.log('User soft deleted');\n * });\n * \n * @example\n * // Hard delete (permanent)\n * userService.delete(123, 'hard').subscribe(() => {\n * console.log('User permanently deleted');\n * });\n */\n delete(id: number, method: 'soft' | 'hard' = 'soft'): Observable<IResponse<unknown>> {\n const methodQuery = `?method=${method}`;\n return this.http.delete<IResponse<unknown>>(`${this.baseUrl}/${id}${methodQuery}`);\n }\n}\n","import { Injectable } from '@angular/core';\nimport { HttpErrorResponse } from '@angular/common/http';\nimport { IMisError } from '../models';\n\n/**\n * Configuration options for the ApiErrorHandler.\n */\nexport interface ApiErrorHandlerConfig {\n /** Whether to log errors to console (default: true in dev, false in prod) */\n logErrors?: boolean;\n \n /** Custom error message transformer */\n errorMessageTransformer?: (error: HttpErrorResponse) => string;\n \n /** Callback to be called when an error occurs */\n onError?: (error: ProcessedError) => void;\n}\n\n/**\n * Processed error information with additional context.\n */\nexport interface ProcessedError {\n /** HTTP status code */\n status: number;\n \n /** User-friendly error message */\n message: string;\n \n /** Technical error details */\n details?: string;\n \n /** Error code from API */\n code?: string;\n \n /** Original HTTP error response */\n originalError: HttpErrorResponse;\n \n /** Whether this error should be shown to user */\n showToUser: boolean;\n \n /** Error type classification */\n type: 'network' | 'client' | 'server' | 'unknown';\n}\n\n/**\n * Service for handling and processing API errors consistently.\n * \n * @example\n * // Basic usage in a service\n * constructor(private errorHandler: ApiErrorHandler) {}\n * \n * loadData() {\n * this.http.get('/api/data').subscribe({\n * error: (err: HttpErrorResponse) => {\n * const processed = this.errorHandler.handleError(err);\n * this.showErrorToUser(processed.message);\n * }\n * });\n * }\n * \n * @example\n * // Configure globally\n * providers: [\n * {\n * provide: ApiErrorHandler,\n * useFactory: () => {\n * const handler = new ApiErrorHandler();\n * handler.configure({\n * logErrors: true,\n * onError: (error) => {\n * // Send to logging service\n * loggingService.logError(error);\n * }\n * });\n * return handler;\n * }\n * }\n * ]\n */\n@Injectable({ providedIn: 'root' })\nexport class ApiErrorHandler {\n private config: ApiErrorHandlerConfig = {\n logErrors: true\n };\n\n /**\n * Configure the error handler.\n * \n * @param config Configuration options\n */\n configure(config: ApiErrorHandlerConfig): void {\n this.config = { ...this.config, ...config };\n }\n\n /**\n * Process an HTTP error and return structured error information.\n * \n * @param error The HTTP error response\n * @returns Processed error with user-friendly message and metadata\n */\n handleError(error: HttpErrorResponse): ProcessedError {\n const processed = this.processError(error);\n\n if (this.config.logErrors) {\n this.logError(processed);\n }\n\n if (this.config.onError) {\n this.config.onError(processed);\n }\n\n return processed;\n }\n\n /**\n * Extract error message from various error formats.\n * \n * @param error The HTTP error response\n * @returns User-friendly error message\n */\n extractErrorMessage(error: HttpErrorResponse): string {\n if (this.config.errorMessageTransformer) {\n return this.config.errorMessageTransformer(error);\n }\n\n // Try to extract from API response\n if (error.error && typeof error.error === 'object') {\n const apiError = error.error as Partial<{ error: IMisError; message: string }>;\n \n // Check for nested error object\n if (apiError.error?.message) {\n return apiError.error.message;\n }\n \n // Check for direct message\n if (apiError.message) {\n return apiError.message;\n }\n }\n\n // Fallback to status-based messages\n return this.getDefaultMessageForStatus(error.status);\n }\n\n /**\n * Get default error message based on HTTP status code.\n * \n * @param status HTTP status code\n * @returns Default error message\n */\n private getDefaultMessageForStatus(status: number): string {\n switch (status) {\n case 0:\n return 'Unable to connect to the server. Please check your internet connection.';\n case 400:\n return 'Invalid request. Please check your input and try again.';\n case 401:\n return 'You are not authorized. Please log in and try again.';\n case 403:\n return 'You do not have permission to perform this action.';\n case 404:\n return 'The requested resource was not found.';\n case 408:\n return 'Request timeout. Please try again.';\n case 409:\n return 'This action conflicts with the current state. Please refresh and try again.';\n case 422:\n return 'Validation failed. Please check your input.';\n case 429:\n return 'Too many requests. Please wait a moment and try again.';\n case 500:\n return 'An internal server error occurred. Please try again later.';\n case 502:\n return 'Bad gateway. The server is temporarily unavailable.';\n case 503:\n return 'Service unavailable. Please try again later.';\n case 504:\n return 'Gateway timeout. The server took too long to respond.';\n default:\n if (status >= 400 && status < 500) {\n return 'Client error occurred. Please check your request.';\n } else if (status >= 500) {\n return 'Server error occurred. Please try again later.';\n }\n return 'An unexpected error occurred. Please try again.';\n }\n }\n\n /**\n * Classify error type based on status code.\n * \n * @param status HTTP status code\n * @returns Error type classification\n */\n private getErrorType(status: number): ProcessedError['type'] {\n if (status === 0) {\n return 'network';\n } else if (status >= 400 && status < 500) {\n return 'client';\n } else if (status >= 500) {\n return 'server';\n }\n return 'unknown';\n }\n\n /**\n * Determine if error should be shown to user.\n * \n * @param error HTTP error response\n * @returns Whether to show error to user\n */\n private shouldShowToUser(error: HttpErrorResponse): boolean {\n // Check if API explicitly set showMessageToUser flag\n if (error.error?.error?.showMessageToUser !== undefined) {\n return error.error.error.showMessageToUser;\n }\n\n // By default, show client errors (4xx) but not server errors (5xx)\n // unless it's a network error (0)\n const status = error.status;\n return status === 0 || (status >= 400 && status < 500);\n }\n\n /**\n * Process the error into a structured format.\n * \n * @param error HTTP error response\n * @returns Processed error object\n */\n private processError(error: HttpErrorResponse): ProcessedError {\n const message = this.extractErrorMessage(error);\n const type = this.getErrorType(error.status);\n const showToUser = this.shouldShowToUser(error);\n\n let details: string | undefined;\n let code: string | undefined;\n\n // Extract additional details if available\n if (error.error && typeof error.error === 'object') {\n const apiError = error.error as Partial<{ error: IMisError }>;\n if (apiError.error) {\n details = apiError.error.details;\n code = apiError.error.code;\n }\n }\n\n return {\n status: error.status,\n message,\n details,\n code,\n originalError: error,\n showToUser,\n type\n };\n }\n\n /**\n * Log error to console (in dev mode).\n * \n * @param error Processed error\n */\n private logError(error: ProcessedError): void {\n const style = 'color: #ff6b6b; font-weight: bold;';\n \n console.group('%c🔥 API Error', style);\n console.log('Status:', error.status);\n console.log('Type:', error.type);\n console.log('Message:', error.message);\n \n if (error.code) {\n console.log('Code:', error.code);\n }\n \n if (error.details) {\n console.log('Details:', error.details);\n }\n \n console.log('URL:', error.originalError.url);\n console.log('Method:', error.originalError.error?.method || 'Unknown');\n console.log('Original Error:', error.originalError);\n console.groupEnd();\n }\n}\n\n\n","import { HttpInterceptorFn, HttpErrorResponse } from '@angular/common/http';\nimport { inject } from '@angular/core';\nimport { catchError, throwError } from 'rxjs';\nimport { ApiErrorHandler } from '../services/api-error-handler.service';\n\n/**\n * HTTP Interceptor that catches errors and processes them through the ApiErrorHandler.\n * \n * @example\n * // In your app.config.ts or main provider:\n * export const appConfig: ApplicationConfig = {\n * providers: [\n * provideHttpClient(\n * withInterceptors([apiErrorInterceptor])\n * )\n * ]\n * };\n */\nexport const apiErrorInterceptor: HttpInterceptorFn = (req, next) => {\n const errorHandler = inject(ApiErrorHandler);\n\n return next(req).pipe(\n catchError((error: HttpErrorResponse) => {\n const handledError = errorHandler.handleError(error);\n return throwError(() => handledError);\n })\n );\n};\n\n\n","/*\n * Public API Surface of api-core\n */\n\nexport * from './lib/configs';\nexport * from './lib/api-core';\nexport * from './lib/enums';\nexport * from './lib/utils';\nexport * from './lib/models';\nexport * from './lib/types';\nexport * from './lib/services';\nexport * from './lib/interceptors';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
package/index.d.ts CHANGED
@@ -535,7 +535,7 @@ declare const sortObjectToString: (sortItems: SortItem[]) => string;
535
535
  /**
536
536
  * Converts a filter object into a URL query string.
537
537
  *
538
- * @param filter Filter object with query parameters
538
+ * @param filter Filter object with query parameters (any object type)
539
539
  * @returns URL query string with '?' prefix, or empty string if no parameters
540
540
  *
541
541
  * @remarks
@@ -543,6 +543,7 @@ declare const sortObjectToString: (sortItems: SortItem[]) => string;
543
543
  * - Encodes all values for URL safety
544
544
  * - Filters out undefined and null values
545
545
  * - Arrays are encoded as comma-separated values in brackets
546
+ * - Works with any object type, including custom filter interfaces
546
547
  *
547
548
  * @example
548
549
  * const filter = {
@@ -554,12 +555,23 @@ declare const sortObjectToString: (sortItems: SortItem[]) => string;
554
555
  * };
555
556
  * const queryString = jsonToQueryString(filter);
556
557
  * // Returns: "?page=1&pageLength=25&search=John%20Doe&roles=[admin,user]&sort=name:ASC"
558
+ *
559
+ * @example
560
+ * // Works with custom filter interfaces
561
+ * interface StockFilter extends Filter {
562
+ * itemVariantIds?: number[];
563
+ * }
564
+ * const stockFilter: StockFilter = {
565
+ * page: 1,
566
+ * itemVariantIds: [1, 2, 3]
567
+ * };
568
+ * jsonToQueryString(stockFilter); // ✅ Works!
557
569
  */
558
- declare const jsonToQueryString: (filter: Record<string, unknown>) => string;
570
+ declare const jsonToQueryString: (filter: object | null | undefined) => string;
559
571
  /**
560
572
  * Checks if an object is empty (has no own properties).
561
573
  *
562
- * @param obj Object to check
574
+ * @param obj Object to check (any object type, null, or undefined)
563
575
  * @returns True if object is null, undefined, or has no properties
564
576
  *
565
577
  * @example
@@ -568,8 +580,14 @@ declare const jsonToQueryString: (filter: Record<string, unknown>) => string;
568
580
  * isEmpty(undefined); // true
569
581
  * isEmpty({ page: 1 }); // false
570
582
  * isEmpty([]); // true (arrays with no length)
583
+ *
584
+ * @example
585
+ * // Works with any object type
586
+ * interface MyType { id: number; name: string; }
587
+ * const myObj: MyType = { id: 1, name: 'test' };
588
+ * isEmpty(myObj); // false
571
589
  */
572
- declare const isEmpty: (obj: Record<string, unknown> | null | undefined) => boolean;
590
+ declare const isEmpty: (obj: object | null | undefined) => boolean;
573
591
 
574
592
  /**
575
593
  * Generic reactive state management service for data-driven features.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mysteryinfosolutions/api-core",
3
- "version": "1.9.0",
3
+ "version": "1.9.2",
4
4
  "peerDependencies": {
5
5
  "@angular/common": "^20.0.0",
6
6
  "@angular/core": "^20.0.0",