@kalutskii/foundation 0.7.8 → 0.7.10

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.ts CHANGED
@@ -1,30 +1,27 @@
1
1
  import { SQL } from 'drizzle-orm';
2
2
  import { ErrorHandler, MiddlewareHandler, Context, TypedResponse } from 'hono';
3
- import { Locale } from 'date-fns';
4
3
  import z$1, { z, ZodObject, ZodRawShape } from 'zod';
4
+ import { Locale } from 'date-fns';
5
5
  import { SymmetricAlgorithm } from 'hono/utils/jwt/jwa';
6
6
 
7
7
  /**
8
- * Builds a Drizzle SQL `where` condition from a plain object.
9
- *
10
- * Maps each `where` entry to `eq(table[key], value)` and combines them with `and`.
11
- * Assumes that `where` was already validated and contains only existing table fields.
8
+ * Builds a Drizzle `WHERE` clause by combining defined object entries with `and`.
9
+ * Expects the supplied keys to be validated against the table beforehand.
12
10
  *
13
- * ```typescript
11
+ * @example
14
12
  * await db.update(usersTable).set(values).where(sqlWhere(usersTable, { id: 1 })).returning();
15
- * ```
16
13
  */
17
14
  declare function sqlWhere(table: unknown, where: Record<string, unknown>): SQL;
18
15
 
19
16
  /**
20
- * Global error handler for Hono framework. Catches all exceptions thrown in route handlers and middlewares.
21
- * Distinguishes between expected HTTPExceptions (mapped to their status codes) and unexpected errors (500).
17
+ * Converts expected `HTTPException` values into shared API error envelopes.
18
+ * Unexpected failures are logged and represented by a traceable generic response.
22
19
  */
23
20
  declare const onHandlerError: ErrorHandler;
24
21
 
25
22
  /**
26
- * Request logging middleware for Hono, providing deeply detailed logs for each incoming request.
27
- * Example log output: [12:12:12 (+4 UTC)] hono | POST 200 123ms /api/v1/users (search=term)
23
+ * Logs request method, response status, duration, URL details, and a body preview.
24
+ * Multipart bodies remain unread to avoid buffering uploaded file content into logs.
28
25
  */
29
26
  declare const honoLoggingHandler: MiddlewareHandler;
30
27
 
@@ -33,10 +30,10 @@ declare const EXCEPTION_STATUS_CODES: readonly [400, 401, 403, 404, 405, 409, 50
33
30
 
34
31
  type SuccessStatusCode = (typeof SUCCESS_STATUS_CODES)[number];
35
32
  type ExceptionStatusCode = (typeof EXCEPTION_STATUS_CODES)[number];
36
- type APISuccess<T = void> = {
33
+ type APISuccess<TData = void> = {
37
34
  kind: 'data';
38
35
  status: SuccessStatusCode;
39
- data: T;
36
+ data: TData;
40
37
  };
41
38
  type APIError = {
42
39
  kind: 'error';
@@ -46,48 +43,55 @@ type APIError = {
46
43
  type APIContractResult<TData = void> = APISuccess<TData> | APIError;
47
44
  type APIContractData<TResult extends APIContractResult<unknown>> = TResult extends APISuccess<infer TData> ? TData : never;
48
45
  type APIContractError<TResult extends APIContractResult<unknown>> = Extract<TResult, APIError>;
49
- /**
50
- * Discriminated union result of a fetch operation.
51
- * If `error` is set, `data` is null and vice versa.
52
- */
53
- type FetchResult<T> = {
46
+ type FetchResult<TData> = {
54
47
  error: null;
55
- data: T;
48
+ data: TData;
56
49
  } | {
57
50
  error: string;
58
51
  data: null;
59
52
  };
60
53
 
61
54
  /**
62
- * Wraps c.json with a typed success payload / (or void data) & possible APIError response.
63
- * When no data is provided, responds with an empty object {} (purely for type consistency).
55
+ * Options for a typed JSON response wrapped in the shared API success envelope.
56
+ * The status generic preserves the literal code inferred by the route contract.
64
57
  */
65
- declare function respond<T extends object = Record<string, never>, S extends SuccessStatusCode = SuccessStatusCode>(c: Context, options: {
66
- status: S;
67
- data?: T;
68
- }): Response & TypedResponse<APISuccess<T> | APIError, S, 'json'>;
58
+ type HonoRespondOptions<TData extends object, TStatus extends SuccessStatusCode> = {
59
+ status: TStatus;
60
+ data?: TData;
61
+ };
69
62
  /**
70
- * Responds with a file download, setting the appropriate headers for content disposition and type.
71
- * Supports specifying a filename and optional content type, defaulting to 'application/octet-stream'.
63
+ * Options for a downloadable binary response with attachment metadata.
64
+ * The content type remains optional and falls back to a generic binary type.
72
65
  */
73
- declare function fileRespond<S extends SuccessStatusCode>(c: Context, options: {
74
- status: S;
66
+ type HonoFileRespondOptions<TStatus extends SuccessStatusCode> = {
67
+ status: TStatus;
75
68
  content: Uint8Array<ArrayBuffer>;
76
69
  filename: string;
77
70
  contentType?: string;
78
- }): Response;
71
+ };
79
72
 
80
73
  /**
81
- * Factory for creating successful API responses with serializable data.
82
- * Example usage: `success({ status: 200, data: { message: 'Operation successful' } })`
74
+ * Wraps `c.json` in the shared success envelope while preserving its literal status.
75
+ * Missing response data is represented by an empty object for contract consistency.
76
+ */
77
+ declare function respond<T extends object = Record<string, never>, S extends SuccessStatusCode = SuccessStatusCode>(c: Context, options: HonoRespondOptions<T, S>): Response & TypedResponse<APISuccess<T> | APIError, S, 'json'>;
78
+ /**
79
+ * Responds with downloadable binary content and its attachment headers.
80
+ * Unknown/undefined content types default to `application/octet-stream`.
81
+ */
82
+ declare function fileRespond<S extends SuccessStatusCode>(c: Context, options: HonoFileRespondOptions<S>): Response;
83
+
84
+ /**
85
+ * Creates a successful API envelope without cloning its data.
86
+ * Generic inference preserves the exact supplied payload type.
83
87
  */
84
88
  declare function success<T = unknown>({ status, data }: {
85
89
  status: SuccessStatusCode;
86
90
  data: T;
87
91
  }): APISuccess<T>;
88
92
  /**
89
- * Factory for creating API error responses, including the error message.
90
- * Example usage: `failure({ status: 404, error: 'User not found' })`
93
+ * Creates a failed API envelope with one supported exception status.
94
+ * The supplied message remains unchanged for downstream presentation.
91
95
  */
92
96
  declare function failure({ status, error }: {
93
97
  status: ExceptionStatusCode;
@@ -95,132 +99,434 @@ declare function failure({ status, error }: {
95
99
  }): APIError;
96
100
 
97
101
  /**
98
- * Resolves an APIContractResult fetcher into a FetchResult discriminated union.
99
- * Does not throw errors, instead returning them as property of the FetchResult.
100
- * Example usage: const result = await fetchSafely(() => api.fetchUser(userId));
102
+ * Converts an API contract envelope into a mutually exclusive safe result.
103
+ * Only `APIError` values are normalized; rejected fetchers still reject.
101
104
  */
102
105
  declare function fetchSafely<TResult extends APIContractResult<unknown>>(fetcher: () => Promise<TResult>): Promise<FetchResult<APIContractData<TResult>>>;
103
106
  /**
104
- * Resolves an APIContractResult, throwing an error if the result is an APIError.
105
- * Example usage: const data = await fetchAndThrow(() => api.fetchUser(userId));
107
+ * Returns successful API data and throws for an `APIError` envelope.
108
+ * Rejected fetchers propagate their original error without replacement.
106
109
  */
107
110
  declare function fetchAndThrow<TResult extends APIContractResult<unknown>>(fetcher: () => Promise<TResult>): Promise<APIContractData<TResult>>;
108
111
 
109
112
  /**
110
- * Returns the current date and time shifted to the specified timezone.
113
+ * Canonical metadata shared by upload controls and runtime validation.
114
+ * Every supported format defines display, MIME, and extension values.
115
+ */
116
+ declare const fileFormatsConfig: {
117
+ readonly png: {
118
+ readonly name: "PNG";
119
+ readonly mimeTypes: readonly ["image/png"];
120
+ readonly extensions: readonly [".png"];
121
+ };
122
+ readonly jpg: {
123
+ readonly name: "JPG";
124
+ readonly mimeTypes: readonly ["image/jpeg"];
125
+ readonly extensions: readonly [".jpg", ".jpeg"];
126
+ };
127
+ readonly webp: {
128
+ readonly name: "WEBP";
129
+ readonly mimeTypes: readonly ["image/webp"];
130
+ readonly extensions: readonly [".webp"];
131
+ };
132
+ readonly avif: {
133
+ readonly name: "AVIF";
134
+ readonly mimeTypes: readonly ["image/avif"];
135
+ readonly extensions: readonly [".avif"];
136
+ };
137
+ readonly heic: {
138
+ readonly name: "HEIC";
139
+ readonly mimeTypes: readonly ["image/heic", "image/heif"];
140
+ readonly extensions: readonly [".heic", ".heif"];
141
+ };
142
+ readonly pdf: {
143
+ readonly name: "PDF";
144
+ readonly mimeTypes: readonly ["application/pdf"];
145
+ readonly extensions: readonly [".pdf"];
146
+ };
147
+ readonly rtf: {
148
+ readonly name: "RTF";
149
+ readonly mimeTypes: readonly ["application/rtf"];
150
+ readonly extensions: readonly [".rtf"];
151
+ };
152
+ readonly txt: {
153
+ readonly name: "TXT";
154
+ readonly mimeTypes: readonly ["text/plain"];
155
+ readonly extensions: readonly [".txt"];
156
+ };
157
+ };
158
+
159
+ declare const fileFormatsArray: readonly ["png", "jpg", "webp", "avif", "heic", "pdf", "rtf", "txt"];
160
+ type FileFormat = (typeof fileFormatsArray)[number];
161
+ declare const fileFormatsRecord: Readonly<{
162
+ AVIF: "avif";
163
+ JPG: "jpg";
164
+ PDF: "pdf";
165
+ PNG: "png";
166
+ RTF: "rtf";
167
+ TXT: "txt";
168
+ WEBP: "webp";
169
+ HEIC: "heic";
170
+ }>;
171
+ declare const fileFormat: Readonly<{
172
+ AVIF: "avif";
173
+ JPG: "jpg";
174
+ PDF: "pdf";
175
+ PNG: "png";
176
+ RTF: "rtf";
177
+ TXT: "txt";
178
+ WEBP: "webp";
179
+ HEIC: "heic";
180
+ }>;
181
+ declare const uploadValidationErrorsArray: readonly ["empty_file", "unsupported_file_format", "file_size_exceeded", "files_count_exceeded"];
182
+ type UploadValidationError = (typeof uploadValidationErrorsArray)[number];
183
+ declare const uploadValidationErrorsRecord: Readonly<{
184
+ EMPTY_FILE: "empty_file";
185
+ UNSUPPORTED_FILE_FORMAT: "unsupported_file_format";
186
+ FILE_SIZE_EXCEEDED: "file_size_exceeded";
187
+ FILES_COUNT_EXCEEDED: "files_count_exceeded";
188
+ }>;
189
+ declare const uploadValidationError: Readonly<{
190
+ EMPTY_FILE: "empty_file";
191
+ UNSUPPORTED_FILE_FORMAT: "unsupported_file_format";
192
+ FILE_SIZE_EXCEEDED: "file_size_exceeded";
193
+ FILES_COUNT_EXCEEDED: "files_count_exceeded";
194
+ }>;
195
+
196
+ type FileFormatConfig = (typeof fileFormatsConfig)[FileFormat];
197
+ /**
198
+ * Shared upload policy consumed by browser controls and backend validation.
199
+ * One preset keeps format, size, capacity, and fallback rules synchronized.
200
+ */
201
+ type UploadPreset<TFormats extends readonly FileFormat[] = readonly FileFormat[]> = Readonly<{
202
+ /**
203
+ * Supported formats accepted by every consumer of the preset.
204
+ * Const inference preserves the supplied format tuple without widening.
205
+ */
206
+ formats: TFormats;
207
+ /**
208
+ * Maximum accepted size of one uploaded file measured in bytes.
209
+ * Schema and client validation can share this exact numeric boundary.
210
+ */
211
+ maxFileSize: number;
212
+ /**
213
+ * Optional maximum number of files retained by one upload collection.
214
+ * Single-file controls can set this value to `1` for shared capacity rules.
215
+ */
216
+ maxFilesCount?: number;
217
+ /**
218
+ * Allows extensions to compensate for absent or unreliable MIME metadata.
219
+ * The fallback remains disabled when this option is omitted.
220
+ */
221
+ extensionFallback?: boolean;
222
+ }>;
223
+ /**
224
+ * Constraints used to validate an incoming collection of browser files.
225
+ * Existing and incoming counts are combined when enforcing capacity.
226
+ */
227
+ type UploadFilesValidationOptions = Readonly<{
228
+ /**
229
+ * Number of files already retained before the incoming batch is validated.
230
+ * Existing entries reduce the remaining capacity without being revalidated.
231
+ */
232
+ currentFilesCount: number;
233
+ /**
234
+ * Supported formats used to validate every file in the incoming batch.
235
+ * MIME and extension metadata are resolved through the canonical catalog.
236
+ */
237
+ formats: readonly FileFormat[];
238
+ /**
239
+ * Maximum accepted size of one uploaded file measured in bytes.
240
+ * Files exceeding this boundary receive the stable size error key.
241
+ */
242
+ maxFileSize: number;
243
+ /**
244
+ * Optional maximum number of retained files after accepting the batch.
245
+ * Omitting this value leaves collection capacity unrestricted.
246
+ */
247
+ maxFilesCount?: number;
248
+ }>;
249
+ /**
250
+ * Accepted files and the final rejection encountered in one batch.
251
+ * Valid entries remain available when another entry fails validation.
252
+ */
253
+ type UploadFilesValidationResult = Readonly<{
254
+ /**
255
+ * Valid incoming files that fit the remaining collection capacity.
256
+ * Accepted file objects preserve their original identity and ordering.
257
+ */
258
+ acceptedFiles: File[];
259
+ /**
260
+ * Final stable rejection encountered while processing the incoming batch.
261
+ * The field remains absent when every supplied file is accepted.
262
+ */
263
+ validationError?: UploadValidationError;
264
+ }>;
265
+ /**
266
+ * Options used to construct one reusable Zod file schema.
267
+ * Extension fallback is disabled by default to preserve strict MIME checks.
268
+ */
269
+ type ZodUploadFileSchemaOptions = Readonly<{
270
+ /**
271
+ * Supported formats accepted by the generated file schema.
272
+ * Strict MIME validation uses metadata from the canonical format catalog.
273
+ */
274
+ formats: readonly FileFormat[];
275
+ /**
276
+ * Maximum accepted file size measured in bytes for the generated file schema.
277
+ * Empty files remain invalid independently of this configured boundary.
278
+ */
279
+ maxFileSize: number;
280
+ /**
281
+ * Allows a supported extension to compensate for missing MIME metadata.
282
+ * The fallback remains disabled by default to preserve strict validation.
283
+ */
284
+ extensionFallback?: boolean;
285
+ }>;
286
+
287
+ /**
288
+ * Defines one shared upload policy while preserving its literal format tuple.
289
+ * The resulting preset can drive schemas, picker hints, and batch validation.
111
290
  *
112
- * This is useful when the application needs to display "now" from another
113
- * region's point of view instead of relying on the server's local timezone.
291
+ * @example
292
+ * const imageUploadPreset = defineUploadPreset({
293
+ * formats: [fileFormat.JPG, fileFormat.PNG, fileFormat.WEBP],
294
+ * maxFileSize: 8 * 1024 * 1024,
295
+ * maxFilesCount: 1,
296
+ * });
114
297
  */
115
- declare const getZonedTime: ({ tz }?: {
116
- tz?: string;
117
- }) => Date;
298
+ declare function defineUploadPreset<const TFormats extends readonly FileFormat[]>(preset: UploadPreset<TFormats>): UploadPreset<TFormats>;
299
+
300
+ /**
301
+ * Default maximum size of one file accepted by the built-in upload presets.
302
+ * The 20 MiB boundary matches the existing upload component policy.
303
+ */
304
+ declare const DEFAULT_UPLOAD_MAX_FILE_SIZE: number;
305
+ /**
306
+ * Ready-to-use policy for every image format supported by the upload catalog.
307
+ * Each image may occupy up to 20 MiB while collection capacity remains unrestricted.
308
+ */
309
+ declare const imageUploadPreset: Readonly<{
310
+ formats: readonly ["png", "jpg", "webp", "avif", "heic"];
311
+ maxFileSize: number;
312
+ maxFilesCount?: number;
313
+ extensionFallback?: boolean;
314
+ }>;
315
+ /**
316
+ * Ready-to-use policy for every document format supported by the upload catalog.
317
+ * Each document may occupy up to 20 MiB while collection capacity remains unrestricted.
318
+ */
319
+ declare const documentUploadPreset: Readonly<{
320
+ formats: readonly ["pdf", "rtf", "txt"];
321
+ maxFileSize: number;
322
+ maxFilesCount?: number;
323
+ extensionFallback?: boolean;
324
+ }>;
325
+
326
+ /**
327
+ * Builds a reusable Zod schema for one uploaded file with format and size.
328
+ * MIME matching is strict unless extension fallback is explicitly enabled.
329
+ */
330
+ declare function zodUploadFileSchema(options: ZodUploadFileSchemaOptions): z.ZodFile;
331
+
332
+ /**
333
+ * Extracts a normalized trailing extension from a complete file name.
334
+ * Returns an empty string when no valid dot-delimited suffix exists.
335
+ */
336
+ declare function getFileExtension(fileName: string): string;
337
+ /**
338
+ * Normalizes a configured extension to a lowercase dot-prefixed value.
339
+ * Existing prefixes remain intact so repeated normalization is stable.
340
+ */
341
+ declare function normalizeFileExtension(extension: string): string;
342
+ /**
343
+ * Compares a concrete MIME type with an exact or wildcard configuration.
344
+ * Wildcards match every subtype belonging to the configured media group.
345
+ */
346
+ declare function matchesMimeType(fileMimeType: string, configuredMimeType: string): boolean;
347
+ /**
348
+ * Checks whether a file MIME type belongs to one selected format.
349
+ * File names and extensions cannot make an unsupported MIME type valid.
350
+ */
351
+ declare function isFileMimeTypeSupported(file: File, formats: readonly FileFormat[]): boolean;
352
+ /**
353
+ * Checks whether a file extension belongs to one selected format.
354
+ * The comparison is case-insensitive and requires a complete suffix.
355
+ */
356
+ declare function isFileExtensionSupported(file: File, formats: readonly FileFormat[]): boolean;
357
+ /**
358
+ * Checks whether a file matches one configured MIME type or extension.
359
+ * This permissive predicate supports clients where MIME metadata is absent.
360
+ */
361
+ declare function isFileFormatSupported(file: File, formats: readonly FileFormat[]): boolean;
362
+ /**
363
+ * Builds a native file-picker hint from configured MIME types and extensions.
364
+ * Duplicate values are removed while their configuration order is retained.
365
+ */
366
+ declare function createUploadAccept(formats: readonly FileFormat[]): string;
367
+
118
368
  /**
119
- * Returns the UTC offset for the specified timezone at the given date.
369
+ * Validates one file against configured format and size constraints.
370
+ * Returns the first stable error key or nothing for a valid file.
371
+ */
372
+ declare function validateUploadFile(file: File, formats: readonly FileFormat[], maxFileSize: number): UploadValidationError | undefined;
373
+ /**
374
+ * Validates an incoming collection while preserving every accepted file.
375
+ * Returns accepted entries and the final rejection key from the batch.
376
+ */
377
+ declare function validateUploadFiles(incomingFiles: readonly File[], options: UploadFilesValidationOptions): UploadFilesValidationResult;
378
+
379
+ /**
380
+ * Projects the current instant onto the wall-clock fields of another timezone.
381
+ * The timezone defaults to `Europe/London` when no option is provided.
120
382
  *
121
- * The offset is formatted for display next to dates and times, for example
122
- * `(+4 UTC)`, `(0 UTC)`, or `(-5 UTC)`. The date is required because timezone
123
- * offsets may change depending on daylight saving time or historical rules.
383
+ * @example
384
+ * const londonTime = getZonedTime({ tz: 'Europe/London' });
124
385
  */
125
- declare const getUTCOffset: (date: Date, tz: string) => string;
386
+ declare function getZonedTime({ tz }?: {
387
+ tz?: string;
388
+ }): Date;
126
389
  /**
127
- * Returns the current time formatted in the specified timezone.
390
+ * Formats the UTC offset of a timezone at the supplied date.
391
+ * An explicit date preserves daylight-saving and historical offset rules.
128
392
  *
129
- * The result includes both the local time and its UTC offset, making it suitable
130
- * for UI labels, logs, bot messages, and other places where the user should see
131
- * not only the time itself, but also the timezone context behind that value.
393
+ * @example
394
+ * getUTCOffset(date, 'Europe/Moscow'); // `(+3 UTC)`
395
+ */
396
+ declare function getUTCOffset(date: Date, tz: string): string;
397
+ /**
398
+ * Formats the current time and UTC offset in the selected timezone.
399
+ * The timezone defaults to `Europe/London` when no option is provided.
132
400
  *
133
- * Format: `HH:mm:ss (+X UTC)`.
401
+ * @example
402
+ * getFormattedTime({ tz: 'Europe/Moscow' }); // `03:04:05 (+3 UTC)`
134
403
  */
135
- declare const getFormattedTime: ({ tz }?: {
404
+ declare function getFormattedTime({ tz }?: {
136
405
  tz?: string;
137
- }) => string;
406
+ }): string;
138
407
  /**
139
- * Returns the current date formatted in the specified timezone.
140
- *
141
- * By default, the result includes date, time, and UTC offset. This is useful for
142
- * complete timestamps displayed in UI, bot messages, reports, or diagnostics.
408
+ * Formats the current date with optional time and UTC offset components.
409
+ * Time is included by default and uses the selected timezone for display.
143
410
  *
144
- * Format with time: `dd.MM.yyyy HH:mm:ss (+X UTC)`.
145
- * Format without time: `dd.MM.yyyy`.
411
+ * @example
412
+ * getFormattedDate({ tz: 'UTC', withTime: false }); // `02.01.2024`
146
413
  */
147
- declare const getFormattedDate: ({ tz, withTime, }?: {
414
+ declare function getFormattedDate({ tz, withTime, }?: {
148
415
  tz?: string;
149
416
  withTime?: boolean;
150
- }) => string;
417
+ }): string;
151
418
  /**
152
- * Formats the provided date and time in the specified timezone.
153
- *
154
- * Unlike helpers that always use the current moment, this function accepts an
155
- * explicit Date value and formats that exact point in time for another timezone.
419
+ * Formats an explicit instant in another timezone using the selected locale.
420
+ * The result includes localized date text, wall-clock time, and UTC offset.
156
421
  *
157
- * Format: `HH:mm:ss, d MMMM yyyy (+X UTC)`.
422
+ * @example
423
+ * formatTime(date, { locale: ru, tz: 'Europe/Moscow' });
158
424
  */
159
- declare const formatTime: (time: Date, { locale, tz }?: {
425
+ declare function formatTime(time: Date, { locale, tz }?: {
160
426
  locale?: Locale;
161
427
  tz?: string;
162
- }) => string;
428
+ }): string;
163
429
 
164
430
  /**
165
- * Recursively replaces dots in a string with underscores in a type-safe manner.
166
- * Example: `ReplaceDotsWithUnderscores<'foo.bar.baz.ok'>` `'foo_bar_baz_ok'`.
431
+ * Recursively replaces dots in a string literal with underscores.
432
+ * Every other character remains unchanged in the resulting type.
433
+ *
434
+ * @example
435
+ * type Key = ReplaceDotsWithUnderscores<'foo.bar.baz'>; // `foo_bar_baz`
167
436
  */
168
- type ReplaceDotsWithUnderscores<T extends string> = T extends `${infer A}.${infer B}` ? `${A}_${ReplaceDotsWithUnderscores<B>}` : T;
437
+ type ReplaceDotsWithUnderscores<TValue extends string> = TValue extends `${infer Head}.${infer Tail}` ? `${Head}_${ReplaceDotsWithUnderscores<Tail>}` : TValue;
169
438
  /**
170
- * Type-safe record mapping string values to ergonomic enum-like keys.
171
- * Keys are uppercased and dots are replaced with underscores.
439
+ * Maps string literals to immutable uppercase enum-like keys.
440
+ * Dots become underscores while every value preserves its original literal.
441
+ *
442
+ * @example
443
+ * type Statuses = StringEnumRecord<readonly ['review.pending', 'published']>;
172
444
  */
173
- type StringEnumRecord<T extends readonly string[]> = Readonly<{
174
- [Value in T[number] as Uppercase<ReplaceDotsWithUnderscores<Value>>]: Value;
445
+ type StringEnumRecord<TValues extends readonly string[]> = Readonly<{
446
+ [Value in TValues[number] as Uppercase<ReplaceDotsWithUnderscores<Value>>]: Value;
175
447
  }>;
176
448
  /**
177
449
  * Creates an immutable enum-like record from a readonly string array.
178
- * Example: `['foo.s', 'baz'] as const` `{ FOO_S: 'foo.s', BAZ: 'baz' }`.
450
+ * Keys are uppercased and every dot is replaced with an underscore.
451
+ *
452
+ * @example
453
+ * createStringEnumRecord(['foo.s', 'baz'] as const); // `{ FOO_S: 'foo.s', BAZ: 'baz' }`
179
454
  */
180
455
  declare function createStringEnumRecord<const T extends readonly string[]>(values: T): StringEnumRecord<T>;
181
456
 
182
457
  /**
183
- * Safely executes functions and handles errors without using try/catch in the calling code.
184
- * Example usage: `safeExecute(() => fetchData(), (error) => console.error(error))`
458
+ * Resolves synchronous and asynchronous executions through one promise-based contract.
459
+ * Failures use the supplied fallback or propagate unchanged when none is available.
460
+ *
461
+ * @example
462
+ * await safeExecute(() => fetchData(), (error) => console.error(error));
463
+ */
464
+ declare function safeExecute<T, E = never>(fn: () => Promise<T> | T, onError?: (error: unknown) => E | Promise<E>): Promise<T | E>;
465
+ /**
466
+ * Result returned after measuring one successful asynchronous execution.
467
+ * The original value is preserved beside its rounded millisecond duration.
185
468
  */
186
- declare function safeExecute<T, E = never>(fn: () => Promise<T> | T, onError?: (error?: unknown) => E | Promise<E>): Promise<T | E>;
187
469
  type MeasuredExecution<T> = {
188
- /** The result of the executed function. */
470
+ /**
471
+ * Value resolved by the measured execution without cloning or transformation.
472
+ * Its generic type remains identical to the original asynchronous result.
473
+ */
189
474
  result: T;
190
- /** The time taken to execute the function, in milliseconds. */
475
+ /**
476
+ * Rounded wall-clock duration of the measured execution in milliseconds.
477
+ * The value is always collected after the supplied promise resolves.
478
+ */
191
479
  executionTime: number;
192
480
  };
193
481
  /**
194
- * Utility function to measure the execution time of an asynchronous function.
195
- * @returns An object containing the result of the execution and the time taken in milliseconds.
482
+ * Measures an asynchronous execution while preserving its resolved result.
483
+ * Rejected executions propagate unchanged and do not produce a measurement.
196
484
  *
197
- * ```typescript
485
+ * @example
198
486
  * const { result, executionTime } = await measureExecutionTime(async () => {
199
487
  * return await fetchData();
200
488
  * });
201
489
  * console.log(`Execution time: ${executionTime}ms`);
202
- * ```
203
490
  */
204
491
  declare function measureExecutionTime<T>(execution: () => Promise<T>): Promise<MeasuredExecution<T>>;
205
492
 
206
493
  /**
207
- * Creates a random string of the specified length using characters from DEFAULT_CHARACTERS.
208
- * Example usage: `generateRandomString(5) = 'aZ3fG' / generateRandomString() = 'G5kLm2P9sQ'`
494
+ * Creates a cryptographically sourced string from the alphanumeric set.
495
+ * Requested length defaults to `10` characters when omitted.
496
+ *
497
+ * @example
498
+ * generateRandomString(5); // `aZ3fG`
499
+ * generateRandomString(); // `G5kLm2P9sQ`
209
500
  */
210
501
  declare function generateRandomString(length?: number): string;
211
502
 
212
503
  /**
213
- * HTTP status colors for better visual parsing in logs:
214
- * 2xx - green, 4xx - yellow, 5xx - red, others - default color.
504
+ * Selects a terminal color function for one HTTP response status.
505
+ * Successes are green, client errors yellow, and server errors red.
506
+ *
507
+ * @example
508
+ * getColoredHTTPStatus(404)('404');
215
509
  */
216
510
  declare function getColoredHTTPStatus(status: number): (text: string) => string;
217
511
  /**
218
- * Unified logging interface for different levels (info, warn, error)
219
- * with optional service name and stack trace for errors (error level).
512
+ * Shared logging interface for informational, warning, and error messages.
513
+ * Every level supports a service label while errors may include a stack trace.
220
514
  */
221
515
  declare const log: {
516
+ /**
517
+ * Writes an informational message with an optional service label.
518
+ * Missing service names use the shared `log` fallback label.
519
+ */
222
520
  info: (message: string, service?: string) => void;
521
+ /**
522
+ * Writes a warning message with an optional service label.
523
+ * Missing service names use the shared `log` fallback label.
524
+ */
223
525
  warn: (message: string, service?: string) => void;
526
+ /**
527
+ * Writes an error message with optional service and stack trace context.
528
+ * Stack traces are rendered beneath the primary error message when supplied.
529
+ */
224
530
  error: (message: string, service?: string, stack?: string) => void;
225
531
  };
226
532
 
@@ -244,13 +550,13 @@ type Simplify<T> = {
244
550
  * identifierSchema: z.string().min(1),
245
551
  * });
246
552
  */
247
- declare const zodBulkSelectionSchema: <const TIdentifierSchema extends z.ZodType<string | number>>({ identifierSchema, }: {
553
+ declare function zodBulkSelectionSchema<const TIdentifierSchema extends z.ZodType<string | number>>({ identifierSchema, }: {
248
554
  /**
249
555
  * Schema used to validate every included or excluded entity identifier.
250
556
  * Its transforms and exact inferred output are preserved in both branches.
251
557
  */
252
558
  identifierSchema: TIdentifierSchema;
253
- }) => z.ZodDiscriminatedUnion<[z.ZodObject<{
559
+ }): z.ZodDiscriminatedUnion<[z.ZodObject<{
254
560
  mode: z.ZodLiteral<"include">;
255
561
  identifiers: z.ZodArray<TIdentifierSchema>;
256
562
  }, z.core.$strict>, z.ZodObject<{
@@ -278,30 +584,47 @@ type ZodBulkExcludeSelection<TIdentifier extends string | number = string> = Ext
278
584
  mode: 'exclude';
279
585
  }>;
280
586
 
281
- /** Options for configuring the JWT service. */
587
+ /**
588
+ * Configures the algorithm and default expiration used by `ZodJWTService`.
589
+ * Omitted values fall back to `HS256` and fifteen minutes respectively.
590
+ */
282
591
  type JWTServiceOptions = {
283
- /** The algorithm to use for signing and verifying JWTs. Defaults to 'HS256'. */
592
+ /**
593
+ * Symmetric algorithm used to sign and verify every token handled by the service.
594
+ * Defaults to `HS256` when the configuration does not provide another value.
595
+ */
284
596
  algorithm?: SymmetricAlgorithm;
285
- /** The default number of seconds until a signed JWT expires. Defaults to 900 seconds (15 minutes). */
597
+ /**
598
+ * Default lifetime assigned to signed tokens, expressed in seconds.
599
+ * Defaults to `900` seconds, which is equivalent to fifteen minutes.
600
+ */
286
601
  defaultExpirationSeconds?: number;
287
602
  };
288
- /** Options for signing a JWT. */
603
+ /**
604
+ * Configures one JWT signing operation without changing service defaults.
605
+ * A supplied expiration takes precedence over `defaultExpirationSeconds`.
606
+ */
289
607
  type JWTSignOptions = {
290
- /** The number of seconds until the JWT expires. */
608
+ /**
609
+ * Lifetime assigned to the token created by this signing operation.
610
+ * Overrides the service default and remains expressed in seconds.
611
+ */
291
612
  expiresInSeconds?: number;
292
613
  };
293
614
  /**
294
- * Utility types for inferring payload types from Zod schemas.
615
+ * Resolves the parsed payload of a Zod schema or preserves a direct payload type.
616
+ * Schema transforms are reflected in the resulting inferred payload.
295
617
  */
296
618
  type Payload<T> = T extends z$1.ZodType ? z$1.infer<T> : T;
297
619
  /**
298
- * Utility type to extract the payload schema type from a Zod schema.
299
- * */
620
+ * Preserves a Zod payload schema and rejects direct payload types with `never`.
621
+ * The result controls whether runtime payload validation is available.
622
+ */
300
623
  type PayloadSchema<T> = T extends z$1.ZodType ? T : never;
301
624
 
302
625
  /**
303
- * A service class for handling JWT operations with optional Zod schema validation for the payload.
304
- * The class is generic, allowing you to specify the type of the payload or a schema for validation.
626
+ * Signs, decodes, and verifies JWTs with optional Zod payload validation.
627
+ * A supplied schema parses payloads returned by decoding and verification.
305
628
  */
306
629
  declare class ZodJWTService<TPayloadOrSchema> {
307
630
  readonly payloadSchema: PayloadSchema<TPayloadOrSchema> | undefined;
@@ -309,23 +632,27 @@ declare class ZodJWTService<TPayloadOrSchema> {
309
632
  protected readonly defaultExpirationSeconds: number;
310
633
  constructor(payloadSchema?: PayloadSchema<TPayloadOrSchema>, options?: JWTServiceOptions);
311
634
  /**
312
- * Signs a JWT token with the provided payload and secret, using the configured algorithm and expiration settings.
313
- * Example usage: `const accessToken = await JWTServiceInstance.sign({ userId: 123 }, 'my-secret', { expiresInSeconds: 300 });`
635
+ * Signs a payload using the configured algorithm and expiration settings.
636
+ * Per-call expiration overrides the default configured by the service.
637
+ *
638
+ * @example
639
+ * const token = await jwtService.sign({ userId: '123' }, secret, { expiresInSeconds: 300 });
314
640
  */
315
641
  sign(payload: Payload<TPayloadOrSchema>, secret: string, options?: JWTSignOptions): Promise<string>;
316
642
  /**
317
- * Decodes a JWT token, and if a Zod schema is provided, validates the payload against it.
318
- * Returns the decoded payload if valid, or null if invalid or if the token cannot be decoded.
643
+ * Decodes without authenticating it and parses its payload when a schema exists.
644
+ * Schema validation failures return `null`, while malformed tokens still reject.
319
645
  *
320
- * Example usage: `const payload = await JWTServiceInstance.decode(token);`
646
+ * @example
647
+ * const payload = await jwtService.decode(token);
321
648
  */
322
649
  decode(token: string): Promise<Payload<TPayloadOrSchema> | null>;
323
650
  /**
324
- * Verifies and decodes a JWT token using the provided secret and configured algorithm,
325
- * then validates the payload against the Zod schema if one is provided.
651
+ * Verifies a token using the configured algorithm and parses its payload.
652
+ * Signature, expiration, and schema validation failures reject the operation.
326
653
  *
327
- * Throws an error if verification fails or if the payload is invalid according to the schema.
328
- * Example usage: `const payload = await JWTServiceInstance.verifyOrThrow(token, 'my-secret');`
654
+ * @example
655
+ * const payload = await jwtService.verifyOrThrow(token, secret);
329
656
  */
330
657
  verifyOrThrow(token: string, secret: string): Promise<Payload<TPayloadOrSchema>>;
331
658
  }
@@ -462,11 +789,10 @@ type AsQuery<T> = T extends null | undefined ? T : T extends QueryPrimitive ? st
462
789
  * This is useful for scenarios where you want to enforce that at least one
463
790
  * of several optional (nullable) properties must be provided in an object.
464
791
  *
465
- * ```typescript
792
+ * @example
466
793
  * type Example = AtLeastOne<{ a?: string; b?: number; c?: boolean }>;
467
794
  * // Valid: { a: "hello" }, { b: 42 }, { c: true }, { a: "hello", b: 42 }
468
795
  * // Invalid: {}, { a: undefined, b: undefined, c: undefined }
469
- * ```
470
796
  */
471
797
  type AtLeastOne<T, Keys extends keyof T = keyof T> = Keys extends keyof T ? Simplify<Required<Pick<T, Keys>> & Partial<Omit<T, Keys>>> : never;
472
798
 
@@ -476,9 +802,8 @@ type AtLeastOne<T, Keys extends keyof T = keyof T> = Keys extends keyof T ? Simp
476
802
  * 2. A `.transform()` that narrows the output type to `AtLeastOne<T>`,
477
803
  * making it directly assignable to domain `*Select` and `*Update` types without casting.
478
804
  *
479
- * ```typescript
805
+ * @example
480
806
  * zQuery(zodAtLeastOne(userSelectSchema)) // result: UserSelect ✓
481
- * ```
482
807
  */
483
808
  declare const zodAtLeastOne: <T extends ZodObject<ZodRawShape>>(schema: T) => z.ZodPipe<T, z.ZodTransform<Awaited<AtLeastOne<z.core.output<T>>>, z.core.output<T>>>;
484
809
 
@@ -490,7 +815,7 @@ declare const parseQueryValue: (value: unknown) => unknown;
490
815
  * numbers or booleans. This helper converts only clear primitive values, allowing
491
816
  * regular schemas like `z.number()` and `z.boolean()` to validate query input directly.
492
817
  *
493
- * ```typescript
818
+ * @example
494
819
  * const schema = asQuery(z.object({
495
820
  * page: z.number().int().positive(),
496
821
  * isActive: z.boolean(),
@@ -498,7 +823,6 @@ declare const parseQueryValue: (value: unknown) => unknown;
498
823
  *
499
824
  * schema.parse({ page: '2', isActive: 'true' });
500
825
  * // { page: 2, isActive: true }
501
- * ```
502
826
  */
503
827
  declare const asQuery: <T extends z.ZodTypeAny>(schema: T) => z.ZodPreprocess<T>;
504
828
 
@@ -508,4 +832,4 @@ declare const asQuery: <T extends z.ZodTypeAny>(schema: T) => z.ZodPreprocess<T>
508
832
  */
509
833
  declare const isPlainObject: (value: unknown) => value is Record<string, unknown>;
510
834
 
511
- export { type APIContractData, type APIContractError, type APIContractResult, type APIError, type APISuccess, type AsQuery, type AtLeastOne, EXCEPTION_STATUS_CODES, type ExceptionStatusCode, type FetchResult, type JWTServiceOptions, type JWTSignOptions, type MeasuredExecution, type Payload, type PayloadSchema, type ReplaceDotsWithUnderscores, SUCCESS_STATUS_CODES, type Simplify, type StringEnumRecord, type SuccessStatusCode, type ZodBulkExcludeSelection, type ZodBulkIncludeSelection, type ZodBulkSelection, ZodJWTService, type ZodPaginationOptions, type ZodSearchSchemaOptions, asQuery, createStringEnumRecord, failure, fetchAndThrow, fetchSafely, fileRespond, formatTime, generateRandomString, getColoredHTTPStatus, getFormattedDate, getFormattedTime, getUTCOffset, getZonedTime, honoLoggingHandler, isPlainObject, log, measureExecutionTime, onHandlerError, parseQueryValue, respond, safeExecute, sqlWhere, success, zodAtLeastOne, zodBulkSelectionSchema, zodPaginationSchema, zodPaginationShape, zodSearchSchema };
835
+ export { type APIContractData, type APIContractError, type APIContractResult, type APIError, type APISuccess, type AsQuery, type AtLeastOne, DEFAULT_UPLOAD_MAX_FILE_SIZE, EXCEPTION_STATUS_CODES, type ExceptionStatusCode, type FetchResult, type FileFormat, type FileFormatConfig, type HonoFileRespondOptions, type HonoRespondOptions, type JWTServiceOptions, type JWTSignOptions, type MeasuredExecution, type Payload, type PayloadSchema, type ReplaceDotsWithUnderscores, SUCCESS_STATUS_CODES, type Simplify, type StringEnumRecord, type SuccessStatusCode, type UploadFilesValidationOptions, type UploadFilesValidationResult, type UploadPreset, type UploadValidationError, type ZodBulkExcludeSelection, type ZodBulkIncludeSelection, type ZodBulkSelection, ZodJWTService, type ZodPaginationOptions, type ZodSearchSchemaOptions, type ZodUploadFileSchemaOptions, asQuery, createStringEnumRecord, createUploadAccept, createZodSearchWhereSchema, defineUploadPreset, documentUploadPreset, failure, fetchAndThrow, fetchSafely, fileFormat, fileFormatsArray, fileFormatsConfig, fileFormatsRecord, fileRespond, formatTime, generateRandomString, getColoredHTTPStatus, getFileExtension, getFormattedDate, getFormattedTime, getUTCOffset, getZonedTime, honoLoggingHandler, imageUploadPreset, isFileExtensionSupported, isFileFormatSupported, isFileMimeTypeSupported, isPlainObject, log, matchesMimeType, measureExecutionTime, normalizeFileExtension, onHandlerError, parseQueryValue, respond, safeExecute, sqlWhere, success, uploadValidationError, uploadValidationErrorsArray, uploadValidationErrorsRecord, validateUploadFile, validateUploadFiles, zodAtLeastOne, zodBulkSelectionSchema, zodPaginationSchema, zodPaginationShape, zodSearchQuerySchema, zodSearchSchema, zodUploadFileSchema };