@reforgium/statum 1.0.0

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.
@@ -0,0 +1,852 @@
1
+ import { AnyDict, AnyType, RestMethods, PageableRequest, Query, PageableResponse } from '@reforgium/internal';
2
+ import * as _angular_core from '@angular/core';
3
+ import { InjectionToken, Signal, WritableSignal } from '@angular/core';
4
+
5
+ /**
6
+ * List of supported primitive and composite data types
7
+ * that can be serialized/deserialized.
8
+ *
9
+ * Used in field serialization configuration.
10
+ */
11
+ type Types = 'string' | 'number' | 'boolean' | 'array' | 'object' | 'date' | 'period' | 'nullable';
12
+ /**
13
+ * Allowed "flat" values after serialization.
14
+ * Such values are safe to pass in a query string or JSON.
15
+ */
16
+ type SerializedPrimitives = string | number | boolean | null;
17
+ type SerializedTypeType = SerializedPrimitives | SerializedPrimitives[];
18
+ type DatePeriod = [Date | null, Date | null];
19
+ /**
20
+ * Generic configuration shape to define `parse`/`format`
21
+ * for converting a value from/to a serialized form.
22
+ *
23
+ * @template TypeFrom — domain type before serialization
24
+ * @template TypeTo — serialized type (by default a primitive/array of primitives)
25
+ */
26
+ type ParseFormatConfig<TypeFrom, TypeTo = SerializedTypeType> = {
27
+ parse?: (val: TypeTo) => TypeFrom;
28
+ format?: (val: TypeFrom) => TypeTo;
29
+ };
30
+ /**
31
+ * Simplified configuration when only `format` is needed.
32
+ */
33
+ type FormatConfig<TypeFrom, TypeTo = SerializedTypeType> = {
34
+ format?: (val: TypeFrom) => TypeTo;
35
+ };
36
+ type FieldConfig = {
37
+ type: Types;
38
+ } | FieldsTypeConfig<DataType, AnyType>;
39
+ type FieldsTypeConfig<EntityType extends DataType, TypeFrom, TypeTo = SerializedTypeType> = {
40
+ parse: (val: TypeTo, data: SerializedType) => TypeFrom;
41
+ format: (val: TypeFrom, data: EntityType) => TypeTo;
42
+ };
43
+ type PeriodSplitMode = {
44
+ mode: 'split';
45
+ dateFromKeyPostfix: string;
46
+ dateToKeyPostfix: string;
47
+ };
48
+ type PeriodJoinMode = {
49
+ mode: 'join';
50
+ concat: string;
51
+ };
52
+ type SerializerConfig = {
53
+ mapString: {
54
+ trim?: boolean;
55
+ } & ParseFormatConfig<string>;
56
+ mapNumber: {
57
+ fromString?: boolean;
58
+ } & ParseFormatConfig<number>;
59
+ mapBoolean: {
60
+ true?: string;
61
+ false?: string;
62
+ } & ParseFormatConfig<boolean>;
63
+ mapDate: {
64
+ dateFormat?: string;
65
+ } & ParseFormatConfig<Date>;
66
+ /**
67
+ * Settings for date period transformation.
68
+ * Allows choosing a mode:
69
+ * - split: split the period into two keys (e.g., createdFrom/createdTo)
70
+ * - join: join into a string using a delimiter
71
+ * And set the date format.
72
+ */
73
+ mapPeriod: {
74
+ transformMode?: PeriodSplitMode | PeriodJoinMode;
75
+ dateFormat?: string;
76
+ } & ParseFormatConfig<DatePeriod>;
77
+ /**
78
+ * Settings for handling "empty" values.
79
+ * - remove: remove the field from the result;
80
+ * - replaceWith: replace with a fixed value;
81
+ * - includeEmptyString: treat an empty string as "nullable".
82
+ */
83
+ mapNullable: {
84
+ remove?: boolean;
85
+ replaceWith?: string;
86
+ includeEmptyString?: boolean;
87
+ } & ParseFormatConfig<null | undefined>;
88
+ /**
89
+ * Array settings:
90
+ * - concatType: serialization strategy (`comma` | `multi` | `json`);
91
+ * - removeNullable: remove empty items;
92
+ * - format: custom array formatter.
93
+ */
94
+ mapArray: {
95
+ concatType: 'comma' | 'multi' | 'json';
96
+ removeNullable?: boolean;
97
+ } & FormatConfig<AnyType[]>;
98
+ /**
99
+ * Object settings:
100
+ * - deep: deep (recursive) serialization or treat as JSON string;
101
+ * - format: custom object formatter.
102
+ */
103
+ mapObject: {
104
+ deep: boolean;
105
+ } & FormatConfig<DataType>;
106
+ /**
107
+ * Per-field overrides by key.
108
+ */
109
+ mapFields?: Record<string, FieldConfig>;
110
+ };
111
+ /**
112
+ * Flat serialization result: dictionary key → primitive(s).
113
+ */
114
+ type SerializedType = Record<string, SerializedTypeType>;
115
+ /**
116
+ * Generic dictionary of domain data.
117
+ */
118
+ type DataType = AnyDict;
119
+
120
+ /**
121
+ * Universal serializer/deserializer for values used in forms, filters, and DTOs.
122
+ *
123
+ * Supports types: `string | number | boolean | Date | [Date, Date] (period) | array | object | nullable`.
124
+ * Capabilities:
125
+ * - normalize values according to config (trim strings, parse numbers from strings, boolean strings, etc.),
126
+ * - transform date periods into paired keys (`from/to`) or a single joined string,
127
+ * - build/parse a query string (or JSON) to and from an object.
128
+ *
129
+ * Example:
130
+ * ```ts
131
+ * type Filters = { q?: string; active?: boolean; created?: [Date, Date] | null };
132
+ * const s = new Serializer<Filters>({
133
+ * mapPeriod: { transformMode: { mode: 'split', dateFromKeyPostfix: 'From', dateToKeyPostfix: 'To' } }
134
+ * });
135
+ *
136
+ * // -> { q: 'john', createdFrom: '2025-01-01', createdTo: '2025-01-31' }
137
+ * const plain = s.serialize({
138
+ * q: ' john ',
139
+ * active: undefined,
140
+ * created: [new Date('2025-01-01'), new Date('2025-01-31')]
141
+ * });
142
+ *
143
+ * // -> 'q=john&createdFrom=2025-01-01&createdTo=2025-01-31'
144
+ * const qs = s.toQuery({ q: 'john', created: [new Date('2025-01-01'), new Date('2025-01-31')] });
145
+ *
146
+ * // <- { q: 'john', created: [Date, Date] }
147
+ * const parsed = s.deserialize('q=john&createdFrom=2025-01-01&createdTo=2025-01-31');
148
+ * ```
149
+ */
150
+ declare class Serializer<EntityType extends DataType> {
151
+ readonly config: SerializerConfig;
152
+ /**
153
+ * Creates a serializer with a partially overridden configuration.
154
+ * Provide only the options you want to change (the rest are taken from defaults).
155
+ *
156
+ * @param config partial transformation configuration
157
+ */
158
+ constructor(config: Partial<SerializerConfig>);
159
+ /**
160
+ * Converts a domain object into a flat serialized representation
161
+ * (ready to send to an API or build a query string).
162
+ *
163
+ * Rules are taken from `config`:
164
+ * — strings can be trimmed (if enabled),
165
+ * — numbers can be converted from strings/numbers,
166
+ * — boolean supports custom true/false representations,
167
+ * — dates are formatted by `dateFormat`,
168
+ * — date periods can be split/joined,
169
+ * — `nullable` can be removed from the result (`remove`) or formatted.
170
+ *
171
+ * @param obj source object
172
+ * @returns a flat dictionary with string/primitive values
173
+ */
174
+ serialize(obj: EntityType): SerializedType;
175
+ /**
176
+ * Parse serialized data into a domain object.
177
+ *
178
+ * Source can be:
179
+ * — a query string (`key=value&arr=1,2`) or `JSON.stringify(obj)`,
180
+ * — an already prepared flat object.
181
+ *
182
+ * Transformations are reverse of `serialize`: strings → number/boolean/Date/period,
183
+ * arrays are collected according to strategy (`comma`/`pipe`/`multi`), objects — deeply or as JSON.
184
+ *
185
+ * @param val query string or object
186
+ * @returns a domain object of the specified type
187
+ */
188
+ deserialize: (val: string | AnyDict) => EntityType;
189
+ /**
190
+ * Build a query string from a domain object using `serialize` rules
191
+ * and the array joining strategy (`concatType`).
192
+ *
193
+ * @param val domain object
194
+ * @returns query string (suitable for URL or history API)
195
+ */
196
+ toQuery: (val: EntityType) => string;
197
+ /**
198
+ * Returns a new serializer instance with a merged configuration.
199
+ * Useful for ad-hoc overrides for a specific call.
200
+ *
201
+ * @param config partial config changes
202
+ * @returns new `Serializer` with the provided `config` applied
203
+ */
204
+ withConfig(config: Partial<SerializerConfig>): Serializer<EntityType>;
205
+ private serializeElement;
206
+ private deserializeElement;
207
+ private parseQuery;
208
+ }
209
+
210
+ declare const SERIALIZER_CONFIG: InjectionToken<Partial<SerializerConfig>>;
211
+
212
+ type StorageStrategy = 'memory' | 'lru' | 'session' | 'persist';
213
+
214
+ type StorageInterface<Key, Type> = {
215
+ get(key: Key): Type | null;
216
+ set(key: Key, value: Type): void;
217
+ remove(key: Key): void;
218
+ clear(): void;
219
+ get length(): number;
220
+ };
221
+
222
+ declare class LruCache<KeyT, ValueT> implements StorageInterface<KeyT, ValueT> {
223
+ limit: number;
224
+ private map;
225
+ constructor(limit?: number);
226
+ get length(): number;
227
+ get(key: KeyT): NonNullable<ValueT> | null;
228
+ set(key: KeyT, value: ValueT): void;
229
+ remove(key: KeyT): boolean;
230
+ clear(): void;
231
+ has(key: KeyT): boolean;
232
+ keys(): KeyT[];
233
+ values(): ValueT[];
234
+ toArray(): ValueT[];
235
+ fromArray(entries: [KeyT, ValueT][]): void;
236
+ }
237
+
238
+ /**
239
+ * Factory for data storage strategies.
240
+ *
241
+ * Returns a `StorageInterface` implementation depending on the selected strategy:
242
+ * - `'memory'` — in-memory storage (for the session lifetime);
243
+ * - `'session'` — `sessionStorage`, lives until the tab is closed;
244
+ * - `'persist'` — `localStorage`, persists between sessions;
245
+ * - `'lru'` — size-limited cache (Least Recently Used).
246
+ *
247
+ * Used to choose an appropriate storage implementation
248
+ * depending on the scenario: temporary data, long-term, cache, etc.
249
+ *
250
+ * @param strategy storage strategy type (`memory`, `session`, `persist`, `lru`)
251
+ * @returns instance implementing `StorageInterface<Key, Type>`
252
+ */
253
+ declare const storageStrategy: <Key = string, Type extends AnyType = AnyDict>(strategy: StorageStrategy) => StorageInterface<Key, Type>;
254
+
255
+ /**
256
+ * Object for request body (payload).
257
+ * Commonly used with POST/PUT/PATCH/DELETE.
258
+ */
259
+ type PayloadData = AnyDict;
260
+ /**
261
+ * Simple parameters dictionary (string/number).
262
+ * Suitable for path params and query.
263
+ */
264
+ type SimpleDict = Record<string, string | number>;
265
+ /**
266
+ * Resource status in `ResourceStore`:
267
+ * - `idle` — not loaded yet
268
+ * - `loading` — request in progress
269
+ * - `success` — data successfully received
270
+ * - `error` — request failed
271
+ * - `stale` — showing cached data while background revalidation runs
272
+ */
273
+ type ResourceStatus = 'idle' | 'loading' | 'success' | 'error' | 'stale';
274
+ /**
275
+ * Delay mode for executing a request:
276
+ * - `debounce` — delay until silence
277
+ * - `throttle` — limit frequency
278
+ */
279
+ type DelayMode = 'debounce' | 'throttle';
280
+ /**
281
+ * Cache strategy for GET:
282
+ * - `network-first` — network preferred, cache as fallback
283
+ * - `cache-first` — cache preferred, network if needed
284
+ * - `network-only` — always network
285
+ * - `cache-only` — cache only, throws `CacheMissError` if missing
286
+ */
287
+ type CacheStrategy = 'network-first' | 'cache-first' | 'network-only' | 'cache-only';
288
+ /**
289
+ * Map of route templates by HTTP methods.
290
+ * Example: `{ GET: '/users/:id', POST: '/users' }`
291
+ */
292
+ type ResourceRoutesMap = Partial<Record<RestMethods, string>>;
293
+ /**
294
+ * Global options for `ResourceStore`.
295
+ */
296
+ type ResourceStoreOptions = {
297
+ /** Base URL for all requests (e.g., `/api`). */
298
+ baseUrl?: string;
299
+ /** Values automatically merged into each call's payload. */
300
+ presetPayload?: AnyDict;
301
+ /** Values automatically merged into each call's query. */
302
+ presetQueries?: AnyDict;
303
+ /** Delay before executing a request (ms). */
304
+ delay?: number;
305
+ /** Delay mode (`debounce`/`throttle`). */
306
+ delayMode?: DelayMode;
307
+ /** Cache freshness window (ms) for `cache-*` strategies. */
308
+ ttlMs?: number;
309
+ };
310
+ /**
311
+ * API call arguments.
312
+ * - `params` — path parameters for the route template
313
+ * - `query` — query string parameters
314
+ * - `payload` — request body (for mutations)
315
+ */
316
+ type CallArgs<Params extends SimpleDict = SimpleDict, Query extends SimpleDict = SimpleDict, Payload extends PayloadData = PayloadData> = {
317
+ params?: Params;
318
+ query?: Query;
319
+ payload?: Payload;
320
+ };
321
+ /**
322
+ * Common call configuration.
323
+ */
324
+ type CallConfig<Response, Type> = {
325
+ /** Delay before execution (ms). */
326
+ delay?: number;
327
+ /** Delay mode (`debounce`/`throttle`). */
328
+ delayMode?: DelayMode;
329
+ /** Deduplicate concurrent identical requests. */
330
+ dedupe?: boolean;
331
+ /**
332
+ * Whether to promote the result to the "current" store (value/status/error).
333
+ * If `false`, the record remains only in the cache.
334
+ */
335
+ promote?: boolean;
336
+ /**
337
+ * Optional property to define the expected response data type.
338
+ *
339
+ * Possible values:
340
+ * - 'json' - response interpreted as JSON
341
+ * - 'text' - response interpreted as plain text
342
+ * - 'blob' - response as a Blob
343
+ * - 'arraybuffer' - response as an ArrayBuffer
344
+ */
345
+ responseType?: 'json' | 'text' | 'blob' | 'arraybuffer';
346
+ /**
347
+ * Custom response parser.
348
+ * Allows converting server `Response` to the domain type `Type`.
349
+ */
350
+ parseResponse?: ParseFn<Response, Type>;
351
+ };
352
+ /**
353
+ * Function that parses server response into the domain model.
354
+ */
355
+ type ParseFn<Response, Type> = (data: Response) => Type;
356
+ /**
357
+ * Special settings for GET requests.
358
+ */
359
+ type GetCallConfig<Response, Type> = CallConfig<Response, Type> & {
360
+ strategy?: CacheStrategy;
361
+ revalidate?: boolean;
362
+ ttlMs?: number;
363
+ };
364
+
365
+ /**
366
+ * Store for REST resources with caching and request deduplication.
367
+ *
368
+ * Provides reactive access to current value, status, and error;
369
+ * supports cache strategies (cache-first / cache-only / network-first),
370
+ * TTL, delays (debounce/throttle), request cancellation, and auto-serialization of query/payload.
371
+ *
372
+ * Example:
373
+ * ```ts
374
+ * const store = new ResourceStore({ GET: '/users/:id' }, { baseUrl: '/api', ttlMs: 30_000 });
375
+ *
376
+ * effect(() => {
377
+ * if (store.loading()) showSpinner();
378
+ * if (store.error()) showError(store.error());
379
+ * const user = store.value();
380
+ * });
381
+ *
382
+ * await store.get({ params: { id: '42' }, query: { expand: ['roles'] } }, { strategy: 'cache-first', dedupe: true });
383
+ * ```
384
+ */
385
+ declare class ResourceStore<Data> {
386
+ #private;
387
+ private readonly http;
388
+ private readonly serializer;
389
+ /**
390
+ * Current resource value.
391
+ * Returns `null` if no data yet or the request failed.
392
+ */
393
+ value: Signal<Data | null>;
394
+ /**
395
+ * Current loading status of the resource: `idle | loading | stale | success | error`.
396
+ */
397
+ status: Signal<ResourceStatus>;
398
+ /**
399
+ * Last error (if any). Otherwise `null`.
400
+ */
401
+ error: Signal<unknown | null>;
402
+ /**
403
+ * Convenience loading flag: `true` when `loading` or `stale`.
404
+ * Useful for spinners and disabling buttons.
405
+ */
406
+ loading: Signal<boolean>;
407
+ private readonly routes;
408
+ private readonly opts;
409
+ private readonly entries;
410
+ private readonly scheduler;
411
+ /**
412
+ * @param routes Map of path templates for methods (`GET/POST/...` → `/users/:id`)
413
+ * @param opts Global options (baseUrl, ttlMs, delay, delayMode, presetQueries/payload, etc.)
414
+ */
415
+ constructor(routes: ResourceRoutesMap, opts?: ResourceStoreOptions);
416
+ /**
417
+ * Perform a GET request.
418
+ *
419
+ * Supports cache strategies (`strategy`), TTL (`ttlMs`), revalidation,
420
+ * deduplication (`dedupe`), and response parsing (`parseResponse`).
421
+ *
422
+ * @param args { params, query }
423
+ * @param cfg Call settings (strategy, ttlMs, revalidate, parseResponse, delay, delayMode, dedupe, promote)
424
+ * @returns Deserialized `Data`
425
+ */
426
+ get<Param extends SimpleDict = SimpleDict, Query extends PayloadData = PayloadData, Response extends AnyType = Data>(args: CallArgs<Param, Query, never>, cfg?: GetCallConfig<Response, Data>): Promise<Data>;
427
+ /**
428
+ * POST request.
429
+ *
430
+ * @param args { params, query, payload }
431
+ * @param cfg Call settings (parseResponse, delay, delayMode, dedupe, promote)
432
+ * @returns API response (by default — as returned by the server)
433
+ */
434
+ post<Param extends SimpleDict = SimpleDict, Payload extends PayloadData = PayloadData, Query extends PayloadData = PayloadData, Response extends AnyType = AnyType>(args: CallArgs<Param, Query, Payload>, cfg?: CallConfig<Response, Response>): Promise<Response>;
435
+ /**
436
+ * PUT request (full resource update).
437
+ *
438
+ * @param args { params, query, payload }
439
+ * @param cfg Call settings (parseResponse, delay, delayMode, dedupe, promote)
440
+ * @returns API response (by default — as returned by the server)
441
+ */
442
+ put<Param extends SimpleDict = SimpleDict, Payload extends PayloadData = PayloadData, Query extends SimpleDict = SimpleDict, Response extends AnyType = AnyType>(args: CallArgs<Param, Query, Partial<Payload>>, cfg?: CallConfig<Response, Response>): Promise<Response>;
443
+ /**
444
+ * PATCH request (partial update).
445
+ *
446
+ * @param args { params, query, payload }
447
+ * @param cfg Call settings (parseResponse, delay, delayMode, dedupe, promote)
448
+ * @returns API response (by default — as returned by the server)
449
+ */
450
+ patch<Param extends SimpleDict = SimpleDict, Payload extends PayloadData = PayloadData, Query extends SimpleDict = SimpleDict, Response extends AnyType = AnyType>(args: CallArgs<Param, Query, Partial<Payload>>, cfg?: CallConfig<Response, Response>): Promise<Response>;
451
+ /**
452
+ * DELETE request.
453
+ *
454
+ * @param args { params, query, payload }
455
+ * @param cfg Call settings (parseResponse, delay, delayMode, dedupe, promote)
456
+ * @returns API response (by default — as returned by the server)
457
+ */
458
+ delete<Param extends SimpleDict = SimpleDict, Payload extends PayloadData = PayloadData, Query extends SimpleDict = SimpleDict, Response extends AnyType = AnyType>(args: CallArgs<Param, Query, Payload>, cfg?: CallConfig<Response, Response>): Promise<Response>;
459
+ /**
460
+ * Cancel scheduled/running requests for a specific call.
461
+ *
462
+ * @param method HTTP method
463
+ * @param args Arguments used to build the URL (params, query)
464
+ * @param reason Cancellation reason (optional)
465
+ */
466
+ abort<Param extends SimpleDict = SimpleDict, Query extends PayloadData = PayloadData>(method: RestMethods, args: CallArgs<Param, Query>, reason?: string | Error): void;
467
+ /**
468
+ * Cancel all scheduled/running requests for this store.
469
+ *
470
+ * @param reason Cancellation reason (optional)
471
+ */
472
+ abortAll(reason?: string | Error): void;
473
+ private ensureEntry;
474
+ private callApi;
475
+ private buildUrl;
476
+ private prepareQuery;
477
+ private exec$;
478
+ private promoteCurrent;
479
+ }
480
+
481
+ /**
482
+ * Error thrown when requested data is missing in the cache.
483
+ *
484
+ * Used by the `cache-only` strategy when data is not found
485
+ * and a network request is not allowed.
486
+ *
487
+ * Example:
488
+ * ```ts
489
+ * try {
490
+ * await store.get({ query }, { strategy: 'cache-only' });
491
+ * } catch (e) {
492
+ * if (e instanceof CacheMissError) console.warn(e.key, 'not found in cache');
493
+ * }
494
+ * ```
495
+ */
496
+ declare class CacheMissError extends Error {
497
+ readonly key: string;
498
+ constructor(key: string);
499
+ }
500
+ /**
501
+ * Error indicating an aborted (canceled) request.
502
+ *
503
+ * May be thrown by `abort()` or `abortAll()` in `ResourceStore`.
504
+ * Usually does not require handling as an error — used to ignore canceled operations.
505
+ */
506
+ declare class AbortError extends Error {
507
+ constructor(message?: string);
508
+ }
509
+ /**
510
+ * Checks whether the exception is an `AbortError` (including compatible objects).
511
+ *
512
+ * @param e — any value that may be an error
513
+ * @returns `true` if it's an `AbortError`
514
+ */
515
+ declare function isAbort(e: unknown): e is AbortError;
516
+
517
+ /**
518
+ * Configuration for the paginated data store.
519
+ *
520
+ * Controls request method, page cache, debounce delay, and
521
+ * request/response transformations.
522
+ */
523
+ type PaginatedDataConfig<ItemsType extends object, FilterType = unknown> = {
524
+ /** Transport HTTP method: `GET`/`POST`/`PATCH`/`PUT`/`DELETE`. Defaults to global config or `POST`. */
525
+ method?: RestMethods;
526
+ /** Enable LRU cache for pages. */
527
+ hasCache?: boolean;
528
+ /** LRU cache size (number of pages). Defaults to global config. */
529
+ cacheSize?: number;
530
+ /** Debounce delay before request (ms). Useful for frequent filter changes. */
531
+ debounceTime?: number;
532
+ /** Initial pagination/sort params. `page` is required. */
533
+ presetQuery?: {
534
+ page: number;
535
+ pageSize?: number;
536
+ sort?: string;
537
+ };
538
+ /** Initial filters. Will be sent with the first request. */
539
+ presetFilters?: Partial<FilterType>;
540
+ /**
541
+ * Custom transformation of request data into a query object.
542
+ * Useful for mapping `page/pageSize/sort` → API-specific keys.
543
+ */
544
+ parseRequest?: (data: PageableRequest) => Query;
545
+ /**
546
+ * Custom parser of API response into unified `PageableResponse<ItemsType>`.
547
+ * Use if the server returns an array or a "non-standard" structure.
548
+ */
549
+ parseResponse?: (data: AnyType) => PageableResponse<ItemsType>;
550
+ };
551
+ /**
552
+ * Global defaults for `PaginatedDataStore`.
553
+ * Can be provided via DI to avoid duplicating config in each store.
554
+ */
555
+ interface PaginatedDataStoreConfig {
556
+ /** Default method for all stores (if not overridden locally). */
557
+ defaultMethod?: RestMethods;
558
+ /** Default base `page/pageSize/sort`. */
559
+ defaultQuery?: PaginatedDataConfig<object>['presetQuery'];
560
+ /** Global `parseRequest` — maps pagination/sort into a query object. */
561
+ defaultParseRequest?: PaginatedDataConfig<object>['parseRequest'];
562
+ /** Whether to enable page cache by default. */
563
+ defaultHasCache?: boolean;
564
+ /** Default LRU page cache size. */
565
+ defaultCacheSize?: number;
566
+ }
567
+
568
+ declare const PDS_CONFIG: InjectionToken<PaginatedDataStoreConfig>;
569
+
570
+ type PaginationType = {
571
+ page?: number;
572
+ first?: number | null;
573
+ rows?: number | null;
574
+ sortField?: string | string[] | null;
575
+ sortOrder?: number | null;
576
+ };
577
+ /**
578
+ * Store for paginated data (tables/lists) with per-page cache and unified requests.
579
+ *
580
+ * Provides:
581
+ * - reactive signals: `items`, `loading`, `cached`;
582
+ * - methods to control page/size/filters/sorting;
583
+ * - optional LRU cache by pages;
584
+ * - configurable transport (GET/POST/PATCH/…).
585
+ *
586
+ * Example:
587
+ * ```ts
588
+ * const ds = new PaginatedDataStore<User>('/users', { method: 'GET', hasCache: true });
589
+ * await ds.updatePage(0); // load the first page
590
+ * effect(() => console.log(ds.items(), ds.loading()));
591
+ * ```
592
+ */
593
+ declare class PaginatedDataStore<ItemsType extends object, FilterType = unknown> {
594
+ #private;
595
+ private route;
596
+ config: PaginatedDataConfig<ItemsType, FilterType>;
597
+ private readonly defaultConfig;
598
+ /** Current page data (reactive). */
599
+ items: WritableSignal<ItemsType[]>;
600
+ /** Merged cache of pages (flat list) — handy for search/export. */
601
+ cached: WritableSignal<ItemsType[]>;
602
+ /** Loading flag of the current operation. */
603
+ loading: WritableSignal<boolean>;
604
+ /** Current filters (applied to requests). */
605
+ filters: Partial<FilterType>;
606
+ /** Current sorting (`field,asc|desc`). */
607
+ sort?: string | ReadonlyArray<string>;
608
+ /** Current page index (0-based). */
609
+ page: number;
610
+ /** Default page size. */
611
+ pageSize: number;
612
+ /** Total number of elements reported by the server. */
613
+ totalElements: number;
614
+ /**
615
+ * @param route Resource URL pattern (e.g., `'/users'`)
616
+ * @param config Store behavior: method, cache, request/response parsers, debounce, presets, etc.
617
+ */
618
+ constructor(route: string, config?: PaginatedDataConfig<ItemsType, FilterType>);
619
+ /** Force reload current data (with the same page/filters/sort). */
620
+ refresh(): Promise<ItemsType[] | undefined>;
621
+ /**
622
+ * Switch page with a request.
623
+ * If cache is enabled and the page is present in LRU — returns it from cache.
624
+ * @param page page index (0-based)
625
+ * @param ignoreCache ignore cache and fetch from network
626
+ */
627
+ updatePage: (page?: number, ignoreCache?: boolean) => Promise<ItemsType[] | undefined>;
628
+ /**
629
+ * Change page size (will go to the first page) and fetch.
630
+ * @param size new size (rows per page)
631
+ */
632
+ updatePageSize: (size?: number) => Promise<ItemsType[] | undefined>;
633
+ /**
634
+ * Update filters (goes to the first page) and fetch.
635
+ * Previous cache is cleared.
636
+ */
637
+ updateFilters: (filters: Partial<FilterType>) => Promise<ItemsType[] | undefined>;
638
+ /**
639
+ * Update state from table events (PrimeNG, etc.) and fetch.
640
+ * Supports `page/first/rows/sortField/sortOrder`.
641
+ */
642
+ updateQuery: ({ page: pageNum, first, rows, sortOrder, sortField }: PaginationType) => Promise<ItemsType[] | undefined>;
643
+ /**
644
+ * Set filters from scratch (goes to the first page and resets sorting) and fetch.
645
+ * Useful for quick presets.
646
+ */
647
+ setFilters: (filters?: Partial<FilterType>) => Promise<ItemsType[] | undefined>;
648
+ /**
649
+ * Change resource route (resets page, cache, and presets) without fetching.
650
+ * Useful when one store should work with different endpoints.
651
+ */
652
+ updateRoute: (route: string) => void;
653
+ /**
654
+ * Update store config on the fly (without re-creation).
655
+ * Does not trigger loading automatically.
656
+ */
657
+ updateConfig: (config: PaginatedDataConfig<ItemsType>) => void;
658
+ /**
659
+ * Copy configuration and presets from another store of the same type.
660
+ */
661
+ copy(helper: PaginatedDataStore<ItemsType, FilterType>): void;
662
+ /** Clean up resources and cancel active requests. Called automatically onDestroy. */
663
+ destroy(): void;
664
+ private initTransport;
665
+ private runTransport;
666
+ private parseQuery;
667
+ private parseResponseData;
668
+ private updateCache;
669
+ private parseFlatArray;
670
+ private applyConfig;
671
+ private applyPresetMeta;
672
+ }
673
+
674
+ /**
675
+ * `DictStore` configuration (dictionary for select/options).
676
+ *
677
+ * Configures cache strategy, autoload, request/response parsers,
678
+ * search mode (local/server) and label/value fields.
679
+ */
680
+ type DictStoreConfig<ItemsType extends object> = {
681
+ /**
682
+ * Cache strategy for options:
683
+ * - 'memory' — in-memory only,
684
+ * - 'session' — sessionStorage,
685
+ * - 'persist' — localStorage.
686
+ * ('lru' is excluded: used internally for inner structures)
687
+ */
688
+ cacheStrategy?: Omit<StorageStrategy, 'lru'>;
689
+ /** Initial filters (added to the first request/filtering). */
690
+ presetFilters?: Record<string, string>;
691
+ /** Autoload data on initialization (`true` by default). */
692
+ autoLoad?: boolean;
693
+ /**
694
+ * Custom mapper of pagination/sort request into query params.
695
+ * Useful if the API expects non-standard field names.
696
+ */
697
+ parseRequest?: (data: PageableRequest) => AnyDict;
698
+ /**
699
+ * Custom parser of server response into a unified PageableResponse.
700
+ * Needed if the API returns an array or a "non-standard" structure.
701
+ */
702
+ parseResponse?: (data: AnyType) => PageableResponse<ItemsType>;
703
+ /** Transport method for fetching the dictionary. Defaults to 'POST'. */
704
+ method?: 'GET' | 'POST';
705
+ /** Debounce delay before request (ms) — for frequent input/search. */
706
+ debounceTime?: number;
707
+ /** Maximum number of options exposed (truncates `options`). */
708
+ maxOptionsSize?: number;
709
+ /** Field key for label in a dictionary item. Defaults to `'name'`. */
710
+ labelKey?: keyof ItemsType & string;
711
+ /** Field key for value in a dictionary item. Defaults to `'code'`. */
712
+ valueKey?: keyof ItemsType & string;
713
+ /**
714
+ * Search mode:
715
+ * - `true` — local (filters cache by label),
716
+ * - `false` — server (calls API by `name`).
717
+ * Defaults to `true`.
718
+ */
719
+ fixed?: boolean;
720
+ };
721
+ type DictLocalConfig<ItemsType extends object> = {
722
+ /** Maximum number of options exposed (truncates `options`). */
723
+ maxOptionsSize?: number;
724
+ /** Field key for label in a dictionary item. Defaults to `'name'`. */
725
+ labelKey?: keyof ItemsType & string;
726
+ /** Field key for value in a dictionary item. Defaults to `'code'`. */
727
+ valueKey?: keyof ItemsType & string;
728
+ };
729
+ type ValueType = string[] | string | number | null | undefined;
730
+
731
+ /**
732
+ * Dictionary store (select/options) with local LRU cache and optional persistence.
733
+ *
734
+ * Provides:
735
+ * - reactive `items` (current list) and `options` (label/value),
736
+ * - local cache filtering (`fixed: true`) or server-side search by name (`fixed: false`),
737
+ * - preload and restore cache from `storage` (`localStorage/session/LRU`),
738
+ * - smooth integration with `PaginatedDataStore` for server fetching.
739
+ *
740
+ * Example:
741
+ * ```ts
742
+ * const dict = new DictStore<Country>('/countries', 'countries', { labelKey: 'name', valueKey: 'code' });
743
+ * dict.search('ki'); // filters locally (fixed=true) or goes to server (fixed=false)
744
+ * effect(() => console.log(dict.options())); // [{label:'Kyrgyzstan', value:'KG'}, ...]
745
+ * ```
746
+ */
747
+ declare class DictStore<Type extends AnyDict> {
748
+ #private;
749
+ private apiUrl;
750
+ private storageKey;
751
+ static readonly MAX_CACHE_SIZE = 400;
752
+ private readonly fixed;
753
+ private readonly labelKey;
754
+ private readonly valueKey;
755
+ private readonly maxOptionsSize?;
756
+ private readonly storage?;
757
+ /**
758
+ * Search text.
759
+ * With `fixed: true` filters the local cache; with `fixed: false` triggers server search.
760
+ */
761
+ searchText: _angular_core.WritableSignal<string>;
762
+ /**
763
+ * Additional filters for server request (or presets).
764
+ */
765
+ filters: _angular_core.WritableSignal<AnyDict>;
766
+ private cachedItems;
767
+ /**
768
+ * Current list of dictionary items.
769
+ * Source — local cache (fixed=true) or data from `PaginatedDataStore`.
770
+ */
771
+ items: _angular_core.Signal<readonly Type[]>;
772
+ /**
773
+ * Ready-to-use dropdown options: `{ label, value }`.
774
+ * Respects `maxOptionsSize` for truncating the list.
775
+ */
776
+ options: _angular_core.Signal<{
777
+ label: string;
778
+ value: Type[keyof Type & string];
779
+ }[]>;
780
+ private _lastPromise;
781
+ private _armed;
782
+ /**
783
+ * @param apiUrl dictionary endpoint (e.g., `'/api/dicts/countries'`)
784
+ * @param storageKey key for saving cache in the selected strategy
785
+ * @param cfg behavior (fixed/search, parsers, label/value keys, cache strategy, etc.)
786
+ */
787
+ constructor(apiUrl: string, storageKey: string, { method, autoLoad, presetFilters, parseResponse, parseRequest, debounceTime, fixed, maxOptionsSize, labelKey, valueKey, cacheStrategy, }: DictStoreConfig<Type>);
788
+ /** Восстановить кэш из выбранного хранилища (`persist`/`session`/`lru`/`memory`). */
789
+ restoreCache(): void;
790
+ /**
791
+ * Установить запрос и фильтры.
792
+ * При `fixed: false` инициирует серверный поиск; при `fixed: true` — локальную фильтрацию.
793
+ */
794
+ search: (name?: string, filters?: AnyDict) => void;
795
+ /**
796
+ * Найти отображаемую метку по значению (обычно для обратного биндинга).
797
+ * @returns строка метки или `undefined`, если не найдено
798
+ */
799
+ findLabel: (value: ValueType) => string | undefined;
800
+ /**
801
+ * Предзагрузить элементы словаря в локальный кэш.
802
+ * Удобно для SSR/статических списков/быстрых пресетов.
803
+ *
804
+ * @param items список элементов
805
+ * @param opts `{ replace?: true }` — полностью заменить текущий кэш
806
+ */
807
+ preload: (items: readonly Type[], opts?: {
808
+ replace?: boolean;
809
+ }) => void;
810
+ /** Освободить ресурсы и остановить внутренние эффекты. */
811
+ dispose(): void;
812
+ /** Синтаксический сахар для `using`/`Symbol.dispose`. */
813
+ [Symbol.dispose](): void;
814
+ private mergeIntoCache;
815
+ private restoreFromStorage;
816
+ private filterLocal;
817
+ private keyOf;
818
+ }
819
+
820
+ declare class DictLocalStore<Type extends AnyDict> {
821
+ #private;
822
+ items: _angular_core.WritableSignal<readonly Type[]>;
823
+ /**
824
+ * Ready-to-use options for dropdowns: `{ label, value }`.
825
+ * Respects `maxOptionsSize` to truncate the list.
826
+ */
827
+ options: _angular_core.Signal<{
828
+ label: string;
829
+ value: Type[keyof Type & string];
830
+ }[]>;
831
+ private readonly labelKey;
832
+ private readonly valueKey;
833
+ private readonly maxOptionsSize?;
834
+ constructor(items: Type[], config?: DictLocalConfig<Type>);
835
+ /**
836
+ * No-op method for API compatibility with DictStore.
837
+ */
838
+ restoreCache(): void;
839
+ /**
840
+ * Find display label by value (usually for reverse binding).
841
+ * @returns label string or `undefined` if not found
842
+ */
843
+ findLabel: (value: ValueType) => string | undefined;
844
+ search: (name?: string) => void;
845
+ preload: (items: readonly Type[], opts?: {
846
+ replace?: boolean;
847
+ }) => void;
848
+ }
849
+
850
+ export { AbortError, CacheMissError, DictLocalStore, DictStore, LruCache, PDS_CONFIG, PaginatedDataStore, ResourceStore, SERIALIZER_CONFIG, Serializer, isAbort, storageStrategy };
851
+ export type { DataType, DictLocalConfig, DictStoreConfig, FieldConfig, PaginatedDataConfig, PaginatedDataStoreConfig, ResourceRoutesMap, ResourceStatus, ResourceStoreOptions, SerializedType, SerializerConfig, StorageInterface, StorageStrategy, Types };
852
+ //# sourceMappingURL=reforgium-statum.d.ts.map