@freshpointcz/fresh-core 0.0.18 → 0.0.20

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.
package/dist/index.d.mts CHANGED
@@ -1,59 +1,288 @@
1
- import dayjs, { Dayjs } from 'dayjs';
2
1
  import { BaseEntity, ColumnOptions, Repository, EntityTarget, EntityManager, ObjectLiteral, EntitySubscriberInterface, InsertEvent, UpdateEvent, SoftRemoveEvent, TransactionCommitEvent, DataSourceOptions } from 'typeorm';
2
+ import dayjs, { Dayjs } from 'dayjs';
3
3
  import { Job } from 'node-schedule';
4
4
  import * as _eslint_core from '@eslint/core';
5
5
  import * as typescript_eslint_dist_compatibility_types from 'typescript-eslint/dist/compatibility-types';
6
6
 
7
+ declare const AMOUNT_UNIT: {
8
+ readonly 1: {
9
+ readonly symbol: "g";
10
+ readonly translations: {
11
+ readonly en: "gram";
12
+ readonly cs: "gram";
13
+ };
14
+ };
15
+ readonly 2: {
16
+ readonly symbol: "kg";
17
+ readonly translations: {
18
+ readonly en: "kilogram";
19
+ readonly cs: "kilogram";
20
+ };
21
+ };
22
+ readonly 3: {
23
+ readonly symbol: "ml";
24
+ readonly translations: {
25
+ readonly en: "milliliter";
26
+ readonly cs: "mililitr";
27
+ };
28
+ };
29
+ readonly 4: {
30
+ readonly symbol: "l";
31
+ readonly translations: {
32
+ readonly en: "liter";
33
+ readonly cs: "litr";
34
+ };
35
+ };
36
+ };
37
+
38
+ type Status = "ok" | "error" | "not-authorized" | "not-authenticated" | "internal-server-error" | "validation-error";
39
+
40
+ declare class StatusDto {
41
+ /**
42
+ * Call result status
43
+ */
44
+ status: Status;
45
+ /**
46
+ * UTC Timestamp
47
+ * @example "2021-12-01T13:23:39.305Z"
48
+ */
49
+ timestamp: string;
50
+ /**
51
+ * Details (optional)
52
+ */
53
+ details?: string;
54
+ constructor(status: Status, details?: string, timestamp?: string);
55
+ }
56
+
7
57
  /**
8
- * Static DateUtils class
58
+ * Pagination parameters used to describe the current page slice of a query.
59
+ *
60
+ * Construct this object manually or via {@link getPaginationParams} to ensure
61
+ * defaults are applied consistently. Pass it into {@link constructTypeormPagination}
62
+ * when building a TypeORM `findAndCount` call.
63
+ *
64
+ * @example
65
+ * const pagination: PaginationParams = {
66
+ * page: 2,
67
+ * limit: 25,
68
+ * skip: 25, // (page - 1) * limit
69
+ * };
9
70
  */
10
- declare class DateUtils {
11
- /** Holidays 2025-2030 as YYYY-MM-DD strings */
12
- static HOLIDAYS_STR: readonly string[];
13
- /** Holidays 2025-2030 as UTC timestamps */
14
- static HOLIDAYS: readonly number[];
15
- static fromISOtoSQLtimestamp(ts?: string): string;
16
- static toSQLtimestamp(ts: Dayjs): string;
17
- static fromSQLtimestamp(mysqlDate: string): Dayjs;
18
- static getSqlTimestampFromNowCzech(): string;
19
- static fromISO(isoDate: string): Dayjs;
20
- static getDate(ts: string): dayjs.Dayjs;
21
- static getNow(): Dayjs;
22
- static getNowCzech(): Dayjs;
23
- static clone(ts: Dayjs): Dayjs;
24
- static getLastSunday(weeksOffset?: number): Dayjs;
25
- static dayInWeek(ts?: Dayjs): 1 | 2 | 3 | 4 | 5 | 6 | 7;
26
- static isWorkdayDay(ts: Dayjs): boolean;
27
- static getDiffInMinutesWithNow(inputTime: Dayjs): number;
28
- static isInLastDays(numOfDays: number, timestampInput: string | Dayjs): boolean;
71
+ interface PaginationParams {
72
+ /** 1-based page number. */
73
+ page: number;
74
+ /**
75
+ * Maximum number of items to return in a single page.
76
+ *
77
+ * @remarks Do NOT exceed 1000 — large limits can cause memory pressure and
78
+ * slow queries. Use {@link listAll} for bulk data retrieval instead.
79
+ */
80
+ limit: number;
81
+ /**
82
+ * Number of records to skip before returning results.
83
+ *
84
+ * @remarks Always derived as `(page - 1) * limit`. Do not set this
85
+ * independently; keep it in sync with `page` and `limit`.
86
+ */
87
+ skip: number;
29
88
  }
89
+ /**
90
+ * Merges caller-supplied pagination overrides with {@link DEFAULT_PAGINATION_PARAMS}.
91
+ *
92
+ * Use this at the DAO or service layer to normalize an optional `PaginationParams`
93
+ * argument before passing it to {@link constructTypeormPagination}.
94
+ *
95
+ * @param params - Partial pagination parameters to merge. Any omitted fields
96
+ * fall back to the defaults defined in {@link DEFAULT_PAGINATION_PARAMS}.
97
+ * @returns A complete {@link PaginationParams} object with all fields populated.
98
+ *
99
+ * @example
100
+ * // No args — returns the default params
101
+ * getPaginationParams();
102
+ * // → { page: 1, limit: 1000, skip: 0 }
103
+ *
104
+ * // Partial override — only limit is customized
105
+ * getPaginationParams({ page: 3, limit: 50, skip: 100 });
106
+ * // → { page: 3, limit: 50, skip: 100 }
107
+ */
108
+ declare function getPaginationParams(params?: Partial<PaginationParams>): PaginationParams;
109
+ /**
110
+ * Default pagination parameters applied when no overrides are provided.
111
+ *
112
+ * - `page`: `1` (first page)
113
+ * - `limit`: `1000` (fetch-all default; suited for internal batch operations)
114
+ * - `skip`: `0`
115
+ *
116
+ * @remarks
117
+ * This high default limit is intentional for internal/service-layer usage.
118
+ * Controller layer endpoints should always supply explicit, lower limits
119
+ * (e.g. 20–100) to avoid returning unbounded result sets to API consumers.
120
+ *
121
+ * @see {@link getPaginationParams} for applying these defaults with optional overrides.
122
+ */
123
+ declare const DEFAULT_PAGINATION_PARAMS: PaginationParams;
30
124
 
31
- type Deferred<T> = {
32
- promise: Promise<T>;
33
- resolve: (value: T) => void;
34
- reject: (err: any) => void;
125
+ /**
126
+ * Converts {@link PaginationParams} into the `take`/`skip` shape expected by
127
+ * TypeORM's `find`, `findAndCount`, and `findOne` options.
128
+ *
129
+ * @param params - A fully-populated {@link PaginationParams} object (use
130
+ * {@link getPaginationParams} to guarantee all fields are set).
131
+ * @returns An object with `take` and `skip` keys ready to spread into a TypeORM
132
+ * `FindManyOptions`.
133
+ *
134
+ * @example
135
+ * const pagination = getPaginationParams({ page: 2, limit: 25, skip: 25 });
136
+ *
137
+ * const [data, total] = await repo.findAndCount({
138
+ * where: { isActive: true },
139
+ * ...constructTypeormPagination(pagination),
140
+ * });
141
+ *
142
+ * @see {@link https://typeorm.io/find-options | TypeORM Find Options}
143
+ */
144
+ declare function constructTypeormPagination(params: PaginationParams): {
145
+ take: number;
146
+ skip: number;
35
147
  };
36
148
  /**
37
- * Deferred promise is like "fake" which is used to manually resolve/reject later on with different promise
38
- * With resolve and reject outside for easier change of promise
39
- * is used as placeholder untill real promise is assigned
149
+ * Parses pagination parameters from a {@link URLSearchParams} instance.
150
+ *
151
+ * Intended for use in contexts where query parameters arrive as a raw URL
152
+ * string (e.g. middleware, edge functions, or fetch-based handlers) rather
153
+ * than through a framework that deserialises them automatically.
154
+ *
155
+ * **Clamping rules applied automatically:**
156
+ * - `page` is clamped to a minimum of `1`.
157
+ * - `limit` is clamped between `1` and `100` (inclusive).
158
+ * - `skip` is derived as `(page - 1) * limit`.
159
+ *
160
+ * @param searchParams - A `URLSearchParams` instance, typically obtained from
161
+ * `new URL(request.url).searchParams`.
162
+ * @returns A fully-populated {@link PaginationParams} object.
163
+ *
164
+ * @example
165
+ * const url = new URL("https://api.example.com/items?page=3&limit=50");
166
+ * const pagination = parsePaginationFromURL(url.searchParams);
167
+ * // → { page: 3, limit: 50, skip: 100 }
168
+ *
169
+ * @example
170
+ * // Missing params fall back to sensible defaults
171
+ * const url = new URL("https://api.example.com/items");
172
+ * const pagination = parsePaginationFromURL(url.searchParams);
173
+ * // → { page: 1, limit: 20, skip: 0 }
174
+ *
175
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams | MDN: URLSearchParams}
40
176
  */
41
- declare function createDeferred<T>(): Deferred<T>;
177
+ declare function parsePaginationFromURL(searchParams: URLSearchParams): PaginationParams;
42
178
 
43
179
  /**
44
- * Experimental class to maintain just one promise for some process flow.
45
- * Currently is in singleton design, so can be used only in one proces. (currently: all-product-availability-per-day)
180
+ * Metadata returned alongside a paginated result set.
181
+ *
182
+ * Populated automatically by {@link getPaginationMeta}.
183
+ *
184
+ * @example
185
+ * // Example meta for page 2 of 3, 25 items per page, 70 total items:
186
+ * const meta: PaginationMeta = {
187
+ * total: 70,
188
+ * page: 2,
189
+ * limit: 25,
190
+ * totalPages: 3,
191
+ * };
46
192
  */
47
- declare class SinglePromiseWaiter<T = any> {
48
- private static _instance;
49
- static getInstance<T = any>(): SinglePromiseWaiter<any>;
50
- private _promise;
51
- get promise(): Promise<T> | null;
52
- set promise(promise: Promise<T> | null);
53
- get hasPromise(): boolean;
193
+ interface PaginationMeta {
194
+ /** Total number of records across all pages. */
195
+ total: number;
196
+ /** Current 1-based page number. */
197
+ page: number;
198
+ /** Maximum number of items per page that was requested. */
199
+ limit: number;
200
+ /**
201
+ * Total number of pages available given the current `limit`.
202
+ *
203
+ * Computed as `Math.ceil(total / limit)`. Returns `0` when `total` is `0`.
204
+ */
205
+ totalPages: number;
54
206
  }
207
+ /**
208
+ * Constructs a {@link PaginationMeta} object from raw query result data.
209
+ *
210
+ * Call this after a `findAndCount` (or equivalent) to build the `meta` field
211
+ * of a {@link PaginatedList} response.
212
+ *
213
+ * @param total - Total number of records matching the query (the second element
214
+ * returned by TypeORM's `findAndCount`).
215
+ * @param page - The 1-based page number that was requested.
216
+ * @param limit - The page size that was requested.
217
+ * @returns A {@link PaginationMeta} object ready to include in a {@link PaginatedList}.
218
+ *
219
+ * @example
220
+ * const [data, total] = await repo.findAndCount({ take: 25, skip: 25 });
221
+ *
222
+ * return {
223
+ * data,
224
+ * meta: getPaginationMeta(total, 2, 25),
225
+ * // → { total: 70, page: 2, limit: 25, totalPages: 3 }
226
+ * };
227
+ */
228
+ declare function getPaginationMeta(total: number, page: number, limit: number): PaginationMeta;
55
229
 
56
- declare function isValidCron(expr: string): boolean;
230
+ /**
231
+ * A generic wrapper for a single page of query results combined with its
232
+ * pagination metadata.
233
+ *
234
+ * Returned by DAO `findMany` methods and exposed directly from API endpoints.
235
+ *
236
+ * @typeParam T - The entity or DTO type contained in the `data` array.
237
+ *
238
+ * @example
239
+ * const result: PaginatedList<UserEntity> = {
240
+ * data: [{ id: 1, name: "Alice" }, { id: 2, name: "Bob" }],
241
+ * meta: { total: 42, page: 1, limit: 20, totalPages: 3 },
242
+ * };
243
+ */
244
+ interface PaginatedList<T> {
245
+ /** The records for the current page. */
246
+ data: T[];
247
+ /** Pagination metadata describing the full result set. */
248
+ meta: PaginationMeta;
249
+ }
250
+
251
+ /**
252
+ * Exhaustively fetches all records by iterating through pages until the last
253
+ * page is reached.
254
+ *
255
+ * Use this utility when you need the full result set for an operation that
256
+ * does not support streaming (e.g. bulk exports, aggregations, seeding).
257
+ * For large datasets, prefer a streaming or cursor-based approach where possible.
258
+ *
259
+ * @typeParam T - The entity or DTO type returned by `fetchPage`.
260
+ *
261
+ * @param fetchPage - An async function that accepts a {@link PaginationParams}
262
+ * and returns a {@link PaginatedList}. Typically, a bound DAO method.
263
+ * @param batchSize - Number of records to fetch per page. Defaults to `1000`.
264
+ * Do not exceed `1000` to avoid memory pressure.
265
+ * @returns A promise resolving to a flat array of all matching records.
266
+ *
267
+ * @remarks
268
+ * - Iteration stops when `page >= meta.totalPages`.
269
+ * - If the underlying data changes during iteration, results may be inconsistent.
270
+ * For consistency guarantees, wrap the call in a database transaction.
271
+ *
272
+ * @example
273
+ * // Fetch all active users without worrying about pagination
274
+ * const allUsers = await listAll(
275
+ * (pagination) => userDao.findMany({ where: { isActive: true }, pagination }),
276
+ * );
277
+ *
278
+ * @example
279
+ * // Use a smaller batch size to reduce memory footprint
280
+ * const allOrders = await listAll(
281
+ * (pagination) => orderDao.findMany({ pagination }),
282
+ * 200,
283
+ * );
284
+ */
285
+ declare function listAll<T>(fetchPage: (pagination: PaginationParams) => Promise<PaginatedList<T>>, batchSize?: number): Promise<T[]>;
57
286
 
58
287
  /**
59
288
  * Abstract base class implementing a per-subclass Singleton pattern.
@@ -113,56 +342,31 @@ declare abstract class Singleton {
113
342
  protected abstract onInit(): void | Promise<void>;
114
343
  }
115
344
 
116
- type Status = "ok" | "error" | "not-authorized" | "not-authenticated" | "internal-server-error" | "validation-error";
345
+ type Deferred<T> = {
346
+ promise: Promise<T>;
347
+ resolve: (value: T) => void;
348
+ reject: (err: any) => void;
349
+ };
350
+ /**
351
+ * Deferred promise is like "fake" which is used to manually resolve/reject later on with different promise
352
+ * With resolve and reject outside for easier change of promise
353
+ * is used as placeholder untill real promise is assigned
354
+ */
355
+ declare function createDeferred<T>(): Deferred<T>;
117
356
 
118
- declare class StatusDto {
119
- /**
120
- * Call result status
121
- */
122
- status: Status;
123
- /**
124
- * UTC Timestamp
125
- * @example "2021-12-01T13:23:39.305Z"
126
- */
127
- timestamp: string;
128
- /**
129
- * Details (optional)
130
- */
131
- details?: string;
132
- constructor(status: Status, details?: string, timestamp?: string);
357
+ /**
358
+ * Experimental class to maintain just one promise for some process flow.
359
+ * Currently is in singleton design, so can be used only in one proces. (currently: all-product-availability-per-day)
360
+ */
361
+ declare class SinglePromiseWaiter<T = any> {
362
+ private static _instance;
363
+ static getInstance<T = any>(): SinglePromiseWaiter<any>;
364
+ private _promise;
365
+ get promise(): Promise<T> | null;
366
+ set promise(promise: Promise<T> | null);
367
+ get hasPromise(): boolean;
133
368
  }
134
369
 
135
- declare const AMOUNT_UNIT: {
136
- readonly 1: {
137
- readonly symbol: "g";
138
- readonly translations: {
139
- readonly en: "gram";
140
- readonly cs: "gram";
141
- };
142
- };
143
- readonly 2: {
144
- readonly symbol: "kg";
145
- readonly translations: {
146
- readonly en: "kilogram";
147
- readonly cs: "kilogram";
148
- };
149
- };
150
- readonly 3: {
151
- readonly symbol: "ml";
152
- readonly translations: {
153
- readonly en: "milliliter";
154
- readonly cs: "mililitr";
155
- };
156
- };
157
- readonly 4: {
158
- readonly symbol: "l";
159
- readonly translations: {
160
- readonly en: "liter";
161
- readonly cs: "litr";
162
- };
163
- };
164
- };
165
-
166
370
  /**
167
371
  * Default Entity with needed columns for every basic entity `id`, `uuid`, `created_at`, `updated_at` and `deleted_at`;
168
372
  */
@@ -404,6 +608,137 @@ declare class Product extends FreshEntity {
404
608
  declare class Subcategory extends FreshEntity {
405
609
  }
406
610
 
611
+ /**
612
+ * Formats a number to a database-safe decimal string.
613
+ * @param num - The number to format
614
+ * @param precision - Total number of significant digits allowed (e.g., 9)
615
+ * @param scale - Number of digits after the decimal point (e.g., 2)
616
+ * @returns string formatted for database insertion of decimal type
617
+ */
618
+ declare function toDecimal(num: number, precision?: number, scale?: number): string;
619
+ /**
620
+ * Options for {@link isDecimal}.
621
+ */
622
+ interface IsDecimalOptions {
623
+ /**
624
+ * Restrict accepted JavaScript type.
625
+ *
626
+ * - `"number"` — only JS `number` values pass (strings are rejected).
627
+ * - `"string"` — only JS `string` values pass (numbers are rejected).
628
+ * - omitted — both `number` and `string` are accepted.
629
+ *
630
+ * @example
631
+ * isDecimal("3.14", { allowedType: "number" }); // false — wrong JS type
632
+ * isDecimal(3.14, { allowedType: "number" }); // true
633
+ * isDecimal(3.14, { allowedType: "string" }); // false — wrong JS type
634
+ * isDecimal("3.14", { allowedType: "string" }); // true
635
+ */
636
+ allowedType?: "number" | "string";
637
+ /**
638
+ * The decimal separator character to accept for string values.
639
+ * Has no effect on `number` inputs (JS numbers always use `.` internally).
640
+ *
641
+ * Defaults to `"."`.
642
+ *
643
+ * @example
644
+ * isDecimal("3,14", { decimalPoint: "," }); // true
645
+ * isDecimal("3.14", { decimalPoint: "," }); // false — wrong separator
646
+ */
647
+ decimalPoint?: "." | ",";
648
+ /**
649
+ * Maximum total number of significant digits (integer digits + fractional digits combined).
650
+ *
651
+ * @example
652
+ * isDecimal("12345.67", { precision: 7 }); // true — 5 + 2 = 7 digits
653
+ * isDecimal("12345.67", { precision: 6 }); // false — 5 + 2 = 7 > 6
654
+ */
655
+ precision?: number;
656
+ /**
657
+ * Maximum number of digits allowed after the decimal point.
658
+ *
659
+ * @example
660
+ * isDecimal("3.14", { scale: 2 }); // true
661
+ * isDecimal("3.145", { scale: 2 }); // false — 3 fractional digits > 2
662
+ * isDecimal("3", { scale: 2 }); // true — 0 fractional digits ≤ 2
663
+ */
664
+ scale?: number;
665
+ }
666
+ /**
667
+ * Narrows `v` to `number` when `allowedType` is `"number"`.
668
+ * @param v - Value to test.
669
+ * @param options - Must include `allowedType: "number"`.
670
+ */
671
+ declare function isDecimal(v: unknown, options: IsDecimalOptions & {
672
+ allowedType: "number";
673
+ }): v is number;
674
+ /**
675
+ * Narrows `v` to `string` when `allowedType` is `"string"`.
676
+ * @param v - Value to test.
677
+ * @param options - Must include `allowedType: "string"`.
678
+ */
679
+ declare function isDecimal(v: unknown, options: IsDecimalOptions & {
680
+ allowedType: "string";
681
+ }): v is string;
682
+ /**
683
+ * Returns `true` when `v` is a valid decimal value (number or string).
684
+ *
685
+ * Validates that the input represents a finite decimal number. Accepts both
686
+ * JS `number` primitives and decimal strings. Optionally restricts the accepted
687
+ * JS type, the decimal separator character, and enforces precision/scale bounds.
688
+ *
689
+ * **Type narrowing via overloads:**
690
+ * When `allowedType` is specified the return type is narrowed accordingly —
691
+ * `v is number` for `"number"` and `v is string` for `"string"`.
692
+ *
693
+ * **Behaviour per input type:**
694
+ * - `number` — must be finite and non-NaN. Scientific notation (e.g. `1e20`) is
695
+ * rejected because it has no standard decimal representation.
696
+ * - `string` — must match `^-?\d+([.,]\d+)?$` using the configured separator.
697
+ * Leading/trailing whitespace is not trimmed; pass `.trim()` yourself if needed.
698
+ *
699
+ * @param v - Value to test. Anything other than `number` or `string` returns `false`.
700
+ * @param options - Optional validation constraints.
701
+ * @returns `true` when `v` is a valid decimal within the specified constraints.
702
+ *
703
+ * @example
704
+ * // Basic usage — accepts both number and string
705
+ * isDecimal(3.14); // true
706
+ * isDecimal("3.14"); // true
707
+ * isDecimal("abc"); // false
708
+ * isDecimal(Infinity); // false
709
+ * isDecimal(NaN); // false
710
+ * isDecimal(null); // false
711
+ *
712
+ * @example
713
+ * // Restrict to a single JS type
714
+ * isDecimal(3.14, { allowedType: "number" }); // true
715
+ * isDecimal("3.14", { allowedType: "number" }); // false — string rejected
716
+ * isDecimal("3.14", { allowedType: "string" }); // true
717
+ * isDecimal(3.14, { allowedType: "string" }); // false — number rejected
718
+ *
719
+ * @example
720
+ * // Comma as decimal separator (e.g. European locale strings)
721
+ * isDecimal("3,14", { decimalPoint: "," }); // true
722
+ * isDecimal("3.14", { decimalPoint: "," }); // false
723
+ *
724
+ * @example
725
+ * // Precision and scale constraints (matching SQL decimal(9, 2))
726
+ * isDecimal("1234567.89", { precision: 9, scale: 2 }); // true — 7+2=9 digits
727
+ * isDecimal("12345678.9", { precision: 9, scale: 2 }); // false — 8+1=9 but scale violated? no — true, 1≤2
728
+ * isDecimal("3.145", { scale: 2 }); // false — 3 fractional digits
729
+ * isDecimal("3", { scale: 2 }); // true — 0 fractional digits
730
+ *
731
+ * @example
732
+ * // Type narrowing in practice
733
+ * function process(raw: unknown) {
734
+ * if (isDecimal(raw, { allowedType: "string" })) {
735
+ * raw; // narrowed to string here
736
+ * console.log(raw.toUpperCase());
737
+ * }
738
+ * }
739
+ */
740
+ declare function isDecimal(v: unknown, options?: IsDecimalOptions): v is number | string;
741
+
407
742
  /**
408
743
  * Runtime validation for enum values.
409
744
  * If a runtime enum object is provided, the value must match one of its values
@@ -503,6 +838,29 @@ declare const TO_BINARY_FLAG: (v: number | boolean | null | undefined) => Binary
503
838
  */
504
839
  declare function runWithConcurrency<T>(items: T[], concurrency: number, worker: (item: T) => Promise<void>): Promise<void>;
505
840
 
841
+ /**
842
+ * Resolves a path parameter ID string to either a numeric ID or a UUID (any version).
843
+ *
844
+ * tsoa always provides path parameters as strings, so this utility determines
845
+ * the intended type by checking whether the value is purely numeric.
846
+ *
847
+ * @param id - Raw path parameter string
848
+ * @returns Parsed `number` if the value is numeric, otherwise the original `string`.
849
+ *
850
+ * @example
851
+ * resolvePathParameterId("42") // → 42
852
+ * resolvePathParameterId("550e8400-e29b-41d4-a716-446655440000") // → "550e8400-..."
853
+ *
854
+ * // Typical tsoa usage:
855
+ * \@Get("{id}")
856
+ * public async getUserById(\@Request() req: ExRequest, \@Path() id: string) {
857
+ * const userId = resolvePathParameterId(id); // number | string
858
+ * }
859
+ */
860
+ declare function resolvePathParameterId(id: string): string | number;
861
+
862
+ declare function isValidCron(expr: string): boolean;
863
+
506
864
  type TransformMap<TIn, TOut, K extends keyof TIn & keyof TOut> = Partial<{
507
865
  [P in K]: (val: TIn[P]) => TOut[P];
508
866
  }>;
@@ -515,34 +873,28 @@ type TransformMap<TIn, TOut, K extends keyof TIn & keyof TOut> = Partial<{
515
873
  */
516
874
  declare function buildPatch<TOut extends Record<string, any>, TIn extends Record<string, any>, K extends keyof TIn & keyof TOut = keyof TIn & keyof TOut>(data: Partial<TIn>, keys: readonly K[], transforms?: TransformMap<TIn, TOut, K>): Partial<Pick<TOut, K>>;
517
875
 
518
- type Maybe<T> = T | null;
519
876
  /**
520
- * Validates a value that may be `null` or given type
521
- *
522
- * WARNING:
523
- * `undefined` is NOT accepted by this function.
524
- * If you need `undefined` support, it must be handled
525
- * before calling this guard or explicitly allowed elsewhere.
526
- *
527
- * @typeParam T - The underlying non-nullable type
528
- * @param v - Value to validate
529
- * @param inner - Typeguard function for the underlying type `T`
530
- *
531
- * @returns `true` if the value is `null` or satisfies the inner typeguard
877
+ * Static DateUtils class
532
878
  */
533
- declare function isMaybe<T>(v: unknown, inner: (x: unknown) => x is T): v is Maybe<T>;
534
-
535
- declare abstract class DataHelper<T> {
536
- private _data?;
537
- private _dataPromise;
538
- protected deviceIds: Promise<number[]>;
539
- constructor(startDataRetrieve: boolean | undefined, deviceIds: Promise<number[]>);
540
- protected get data(): Maybe<T> | undefined;
541
- protected set data(value: Maybe<T>);
542
- protected get dataPromise(): Maybe<Promise<Maybe<T>>>;
543
- protected set dataPromise(value: Maybe<Promise<Maybe<T>>>);
544
- getData(): Promise<Maybe<T>>;
545
- abstract startDataRetrieval(): Promise<Maybe<T>>;
879
+ declare class DateUtils {
880
+ /** Holidays 2025-2030 as YYYY-MM-DD strings */
881
+ static HOLIDAYS_STR: readonly string[];
882
+ /** Holidays 2025-2030 as UTC timestamps */
883
+ static HOLIDAYS: readonly number[];
884
+ static fromISOtoSQLtimestamp(ts?: string): string;
885
+ static toSQLtimestamp(ts: Dayjs): string;
886
+ static fromSQLtimestamp(mysqlDate: string): Dayjs;
887
+ static getSqlTimestampFromNowCzech(): string;
888
+ static fromISO(isoDate: string): Dayjs;
889
+ static getDate(ts: string): dayjs.Dayjs;
890
+ static getNow(): Dayjs;
891
+ static getNowCzech(): Dayjs;
892
+ static clone(ts: Dayjs): Dayjs;
893
+ static getLastSunday(weeksOffset?: number): Dayjs;
894
+ static dayInWeek(ts?: Dayjs): 1 | 2 | 3 | 4 | 5 | 6 | 7;
895
+ static isWorkdayDay(ts: Dayjs): boolean;
896
+ static getDiffInMinutesWithNow(inputTime: Dayjs): number;
897
+ static isInLastDays(numOfDays: number, timestampInput: string | Dayjs): boolean;
546
898
  }
547
899
 
548
900
  /**
@@ -635,8 +987,26 @@ declare abstract class FreshJob<T = void> extends Singleton {
635
987
  abstract invoke(): T | Promise<T>;
636
988
  }
637
989
 
990
+ type Maybe<T> = T | null;
991
+ /**
992
+ * Validates a value that may be `null` or given type
993
+ *
994
+ * WARNING:
995
+ * `undefined` is NOT accepted by this function.
996
+ * If you need `undefined` support, it must be handled
997
+ * before calling this guard or explicitly allowed elsewhere.
998
+ *
999
+ * @typeParam T - The underlying non-nullable type
1000
+ * @param v - Value to validate
1001
+ * @param inner - Typeguard function for the underlying type `T`
1002
+ *
1003
+ * @returns `true` if the value is `null` or satisfies the inner typeguard
1004
+ */
1005
+ declare function isMaybe<T>(v: unknown, inner: (x: unknown) => x is T): v is Maybe<T>;
1006
+
638
1007
  type CardNumber = `${number}${number}${number}${number}`;
639
1008
 
1009
+ /** @deprecated use {@link FreshError} instead */
640
1010
  declare class ApiError extends Error {
641
1011
  private _statusCode;
642
1012
  get statusCode(): number;
@@ -657,6 +1027,219 @@ declare class BusinessWarning extends Error {
657
1027
  constructor(code: string, message: string);
658
1028
  }
659
1029
 
1030
+ /**
1031
+ * Options for {@link FreshError} and its subclasses.
1032
+ */
1033
+ interface FreshErrorOptions {
1034
+ /**
1035
+ * The original error that caused this one.
1036
+ * Preserved for error chaining and accessible via `error.cause`.
1037
+ */
1038
+ cause?: unknown;
1039
+ }
1040
+ /**
1041
+ * Base class for all application HTTP errors.
1042
+ *
1043
+ * Extend this class to create typed, status-specific errors with a hardcoded
1044
+ * HTTP status code and status string. Direct instantiation is allowed but
1045
+ * subclasses are preferred for consistent error identity.
1046
+ *
1047
+ * `error.name` is automatically set to the subclass name, so stack traces
1048
+ * and logs show `UnauthorizedError` instead of the generic `Error`.
1049
+ *
1050
+ * @example
1051
+ * // Without cause
1052
+ * throw new FreshError(HttpStatus.NOT_FOUND, "error", "User not found");
1053
+ *
1054
+ * // With cause — preserves the original error for logging/debugging
1055
+ * try {
1056
+ * await db.findUser(id);
1057
+ * } catch (err) {
1058
+ * throw new FreshError(HttpStatus.INTERNAL_SERVER_ERROR, "internal-server-error", "DB query failed", { cause: err });
1059
+ * }
1060
+ */
1061
+ declare class FreshError extends Error {
1062
+ /** HTTP status code sent in the response. */
1063
+ readonly statusCode: number;
1064
+ /** Structured response body describing the error. */
1065
+ readonly statusDto: StatusDto;
1066
+ constructor(statusCode: HttpStatus, status: Status, detail?: string, options?: FreshErrorOptions);
1067
+ }
1068
+
1069
+ /** 400 — The request is malformed or contains invalid parameters. */
1070
+ declare class BadRequestError extends FreshError {
1071
+ constructor(detail?: string, options?: FreshErrorOptions);
1072
+ }
1073
+ /** 401 — Authentication is required or the provided credentials are invalid. */
1074
+ declare class UnauthorizedError extends FreshError {
1075
+ constructor(detail?: string, options?: FreshErrorOptions);
1076
+ }
1077
+ /** 402 — Payment is required to access the requested resource. */
1078
+ declare class PaymentRequiredError extends FreshError {
1079
+ constructor(detail?: string, options?: FreshErrorOptions);
1080
+ }
1081
+ /** 403 — The caller is authenticated but lacks permission to access the resource. */
1082
+ declare class ForbiddenError extends FreshError {
1083
+ constructor(detail?: string, options?: FreshErrorOptions);
1084
+ }
1085
+ /** 404 — The requested resource does not exist. */
1086
+ declare class NotFoundError extends FreshError {
1087
+ constructor(detail?: string, options?: FreshErrorOptions);
1088
+ }
1089
+ /** 405 — The HTTP method is not supported for this endpoint. */
1090
+ declare class MethodNotAllowedError extends FreshError {
1091
+ constructor(detail?: string, options?: FreshErrorOptions);
1092
+ }
1093
+ /** 406 — The server cannot produce a response matching the client's `Accept` headers. */
1094
+ declare class NotAcceptableError extends FreshError {
1095
+ constructor(detail?: string, options?: FreshErrorOptions);
1096
+ }
1097
+ /** 407 — Authentication with the proxy is required before the request can proceed. */
1098
+ declare class ProxyAuthenticationRequiredError extends FreshError {
1099
+ constructor(detail?: string, options?: FreshErrorOptions);
1100
+ }
1101
+ /** 408 — The server timed out waiting for the client to complete the request. */
1102
+ declare class RequestTimeoutError extends FreshError {
1103
+ constructor(detail?: string, options?: FreshErrorOptions);
1104
+ }
1105
+ /** 409 — The request conflicts with the current state of the resource. */
1106
+ declare class ConflictError extends FreshError {
1107
+ constructor(detail?: string, options?: FreshErrorOptions);
1108
+ }
1109
+ /** 410 — The resource has been permanently removed and will not return. */
1110
+ declare class GoneError extends FreshError {
1111
+ constructor(detail?: string, options?: FreshErrorOptions);
1112
+ }
1113
+ /** 411 — The request must include a `Content-Length` header. */
1114
+ declare class LengthRequiredError extends FreshError {
1115
+ constructor(detail?: string, options?: FreshErrorOptions);
1116
+ }
1117
+ /** 412 — A precondition in the request headers was not met. */
1118
+ declare class PreconditionFailedError extends FreshError {
1119
+ constructor(detail?: string, options?: FreshErrorOptions);
1120
+ }
1121
+ /** 413 — The request body exceeds the server's size limit. */
1122
+ declare class PayloadTooLargeError extends FreshError {
1123
+ constructor(detail?: string, options?: FreshErrorOptions);
1124
+ }
1125
+ /** 414 — The request URI is longer than the server is willing to process. */
1126
+ declare class UriTooLongError extends FreshError {
1127
+ constructor(detail?: string, options?: FreshErrorOptions);
1128
+ }
1129
+ /** 415 — The request's `Content-Type` is not supported by the server. */
1130
+ declare class UnsupportedMediaTypeError extends FreshError {
1131
+ constructor(detail?: string, options?: FreshErrorOptions);
1132
+ }
1133
+ /** 416 — The `Range` header in the request cannot be satisfied by the resource. */
1134
+ declare class RangeNotSatisfiableError extends FreshError {
1135
+ constructor(detail?: string, options?: FreshErrorOptions);
1136
+ }
1137
+ /** 417 — The expectation in the `Expect` request header could not be met. */
1138
+ declare class ExpectationFailedError extends FreshError {
1139
+ constructor(detail?: string, options?: FreshErrorOptions);
1140
+ }
1141
+ /** 418 — The server refuses to brew coffee because it is, permanently, a teapot. */
1142
+ declare class ImATeapotError extends FreshError {
1143
+ constructor(detail?: string, options?: FreshErrorOptions);
1144
+ }
1145
+ /** 421 — The request was directed at a server that cannot produce a response. */
1146
+ declare class MisdirectedRequestError extends FreshError {
1147
+ constructor(detail?: string, options?: FreshErrorOptions);
1148
+ }
1149
+ /** 422 — The request is well-formed but contains semantic errors. */
1150
+ declare class UnprocessableEntityError extends FreshError {
1151
+ constructor(detail?: string, options?: FreshErrorOptions);
1152
+ }
1153
+ /** 423 — The resource is locked and cannot be accessed. */
1154
+ declare class LockedError extends FreshError {
1155
+ constructor(detail?: string, options?: FreshErrorOptions);
1156
+ }
1157
+ /** 424 — The request failed because a dependency it relies on also failed. */
1158
+ declare class FailedDependencyError extends FreshError {
1159
+ constructor(detail?: string, options?: FreshErrorOptions);
1160
+ }
1161
+ /** 425 — The server is unwilling to process a request that may be replayed. */
1162
+ declare class TooEarlyError extends FreshError {
1163
+ constructor(detail?: string, options?: FreshErrorOptions);
1164
+ }
1165
+ /** 426 — The client must switch to a different protocol to proceed. */
1166
+ declare class UpgradeRequiredError extends FreshError {
1167
+ constructor(detail?: string, options?: FreshErrorOptions);
1168
+ }
1169
+ /** 428 — The request must be conditional (e.g. missing `If-Match` header). */
1170
+ declare class PreconditionRequiredError extends FreshError {
1171
+ constructor(detail?: string, options?: FreshErrorOptions);
1172
+ }
1173
+ /** 429 — The client has sent too many requests in a given time window. */
1174
+ declare class TooManyRequestsError extends FreshError {
1175
+ constructor(detail?: string, options?: FreshErrorOptions);
1176
+ }
1177
+ /** 431 — The request headers are too large for the server to process. */
1178
+ declare class RequestHeaderFieldsTooLargeError extends FreshError {
1179
+ constructor(detail?: string, options?: FreshErrorOptions);
1180
+ }
1181
+ /** 451 — The resource is unavailable due to legal restrictions. */
1182
+ declare class UnavailableForLegalReasonsError extends FreshError {
1183
+ constructor(detail?: string, options?: FreshErrorOptions);
1184
+ }
1185
+ /** 500 — The server encountered an unexpected condition. */
1186
+ declare class InternalServerError extends FreshError {
1187
+ constructor(detail?: string, options?: FreshErrorOptions);
1188
+ }
1189
+ /** 501 — The server does not support the functionality required to fulfil the request. */
1190
+ declare class NotImplementedError extends FreshError {
1191
+ constructor(detail?: string, options?: FreshErrorOptions);
1192
+ }
1193
+ /** 502 — The upstream server returned an invalid response. */
1194
+ declare class BadGatewayError extends FreshError {
1195
+ constructor(detail?: string, options?: FreshErrorOptions);
1196
+ }
1197
+ /** 503 — The server is temporarily unavailable, usually due to maintenance or overload. */
1198
+ declare class ServiceUnavailableError extends FreshError {
1199
+ constructor(detail?: string, options?: FreshErrorOptions);
1200
+ }
1201
+ /** 504 — The upstream server did not respond in time. */
1202
+ declare class GatewayTimeoutError extends FreshError {
1203
+ constructor(detail?: string, options?: FreshErrorOptions);
1204
+ }
1205
+ /** 505 — The HTTP version used in the request is not supported by the server. */
1206
+ declare class HttpVersionNotSupportedError extends FreshError {
1207
+ constructor(detail?: string, options?: FreshErrorOptions);
1208
+ }
1209
+ /** 506 — The server has a configuration error resulting in circular content negotiation. */
1210
+ declare class VariantAlsoNegotiatesError extends FreshError {
1211
+ constructor(detail?: string, options?: FreshErrorOptions);
1212
+ }
1213
+ /** 507 — The server cannot store the representation needed to complete the request. */
1214
+ declare class InsufficientStorageError extends FreshError {
1215
+ constructor(detail?: string, options?: FreshErrorOptions);
1216
+ }
1217
+ /** 508 — The server detected an infinite loop while processing the request. */
1218
+ declare class LoopDetectedError extends FreshError {
1219
+ constructor(detail?: string, options?: FreshErrorOptions);
1220
+ }
1221
+ /** 510 — Further extensions to the request are required for the server to fulfil it. */
1222
+ declare class NotExtendedError extends FreshError {
1223
+ constructor(detail?: string, options?: FreshErrorOptions);
1224
+ }
1225
+ /** 511 — The client must authenticate to gain network access (e.g. captive portal). */
1226
+ declare class NetworkAuthenticationRequiredError extends FreshError {
1227
+ constructor(detail?: string, options?: FreshErrorOptions);
1228
+ }
1229
+
1230
+ declare abstract class DataHelper<T> {
1231
+ private _data?;
1232
+ private _dataPromise;
1233
+ protected deviceIds: Promise<number[]>;
1234
+ constructor(startDataRetrieve: boolean | undefined, deviceIds: Promise<number[]>);
1235
+ protected get data(): Maybe<T> | undefined;
1236
+ protected set data(value: Maybe<T>);
1237
+ protected get dataPromise(): Maybe<Promise<Maybe<T>>>;
1238
+ protected set dataPromise(value: Maybe<Promise<Maybe<T>>>);
1239
+ getData(): Promise<Maybe<T>>;
1240
+ abstract startDataRetrieval(): Promise<Maybe<T>>;
1241
+ }
1242
+
660
1243
  declare const FRESH_ESLINT_CONFIG: {
661
1244
  files: string[];
662
1245
  ignores: string[];
@@ -734,4 +1317,4 @@ interface HealthCheckResult {
734
1317
  };
735
1318
  }
736
1319
 
737
- export { AMOUNT_UNIT, ActionCommandCode, ApiError, BaseEntityChangeSubscriber, type BinaryFlag, BusinessWarning, type CardNumber, Category, DataHelper, DateUtils, type Deferred, DepotPoolStatus, Device, type EntityChangeEvent, FreshDao, FreshEntity, FreshHyperEntity, FreshJob, FreshTranslationBase, type HealthCheckResult, HttpStatus, LanguageCode, Manufacturer, type Maybe, PaymentMethod, PG_DATA_SOURCE_OPTIONS as PgDataSourceOptions, Product, SinglePromiseWaiter, Singleton, type Status, StatusDto, Subcategory, TO_BINARY_FLAG, TimestampColumn, TransactionType, buildPatch, createDeferred, FRESH_ESLINT_CONFIG as freshEslintConfig, hasOwn, isEnumValue, isFlag01, isMaybe, isNumber, isNumberInRange, isObject, isString, isValidCron, runWithConcurrency };
1320
+ export { AMOUNT_UNIT, ActionCommandCode, ApiError, BadGatewayError, BadRequestError, BaseEntityChangeSubscriber, type BinaryFlag, BusinessWarning, type CardNumber, Category, ConflictError, DEFAULT_PAGINATION_PARAMS, DataHelper, DateUtils, type Deferred, DepotPoolStatus, Device, type EntityChangeEvent, ExpectationFailedError, FailedDependencyError, ForbiddenError, FreshDao, FreshEntity, FreshError, type FreshErrorOptions, FreshHyperEntity, FreshJob, FreshTranslationBase, GatewayTimeoutError, GoneError, type HealthCheckResult, HttpStatus, HttpVersionNotSupportedError, ImATeapotError, InsufficientStorageError, InternalServerError, type IsDecimalOptions, LanguageCode, LengthRequiredError, LockedError, LoopDetectedError, Manufacturer, type Maybe, MethodNotAllowedError, MisdirectedRequestError, NetworkAuthenticationRequiredError, NotAcceptableError, NotExtendedError, NotFoundError, NotImplementedError, type PaginatedList, type PaginationMeta, type PaginationParams, PayloadTooLargeError, PaymentMethod, PaymentRequiredError, PG_DATA_SOURCE_OPTIONS as PgDataSourceOptions, PreconditionFailedError, PreconditionRequiredError, Product, ProxyAuthenticationRequiredError, RangeNotSatisfiableError, RequestHeaderFieldsTooLargeError, RequestTimeoutError, ServiceUnavailableError, SinglePromiseWaiter, Singleton, type Status, StatusDto, Subcategory, TO_BINARY_FLAG, TimestampColumn, TooEarlyError, TooManyRequestsError, TransactionType, UnauthorizedError, UnavailableForLegalReasonsError, UnprocessableEntityError, UnsupportedMediaTypeError, UpgradeRequiredError, UriTooLongError, VariantAlsoNegotiatesError, buildPatch, constructTypeormPagination, createDeferred, FRESH_ESLINT_CONFIG as freshEslintConfig, getPaginationMeta, getPaginationParams, hasOwn, isDecimal, isEnumValue, isFlag01, isMaybe, isNumber, isNumberInRange, isObject, isString, isValidCron, listAll, parsePaginationFromURL, resolvePathParameterId, runWithConcurrency, toDecimal };