@kalutskii/foundation 0.6.5 → 0.6.6

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/README.md CHANGED
@@ -5,11 +5,14 @@ Designed for use in Bun/Node.js and Cloudflare Workers environments.
5
5
 
6
6
  ## What this package provides
7
7
 
8
- - Typed API response contracts.
9
- - Response factories for success and failure payloads.
10
- - Safe async resolvers for contract-based fetch functions.
11
- - A Hono helper for typed JSON success responses.
12
- - Utility types/helpers for query parsing and Date serialization.
8
+ - Typed API response contracts with success/failure factories and safe resolvers.
9
+ - Hono helpers: typed JSON responses, global error handler, request logging middleware.
10
+ - Execution utilities: safe async execution and execution time measurement.
11
+ - Datetime utilities: timezone-aware formatting helpers.
12
+ - Logging utility: unified colored log interface.
13
+ - Random string generation utility.
14
+ - JWT service with optional Zod schema validation.
15
+ - Zod helpers for query param coercion, pagination schemas, and type utilities.
13
16
 
14
17
  ## Installation
15
18
 
@@ -32,8 +35,8 @@ Contract shape:
32
35
 
33
36
  Status code groups are exported as constants and used by types:
34
37
 
35
- - `SUCCESS_STATUS_CODES`
36
- - `EXCEPTION_STATUS_CODES`
38
+ - `SUCCESS_STATUS_CODES` — `[200, 201, 202, 307]`
39
+ - `EXCEPTION_STATUS_CODES` — `[400, 401, 403, 404, 405, 409, 500]`
37
40
 
38
41
  ## Usage
39
42
 
@@ -87,34 +90,132 @@ const app = new Hono();
87
90
  app.get('/health', (c) => {
88
91
  return respond(c, {
89
92
  status: 200,
90
- data: { ok: true, now: new Date() },
93
+ data: { ok: true },
91
94
  });
92
95
  });
93
96
  ```
94
97
 
95
- `respond` returns a typed JSON response contract and includes API error type in route output unions.
98
+ `respond` wraps `c.json` with a typed success payload and includes `APIError` in the route's output union.
96
99
 
97
- ### 4. Parse query params with helpers
100
+ ### 4. Wire up Hono error handler and logging middleware
98
101
 
99
102
  ```ts
100
- import { asQueryBoolean, asQueryNumber } from '@kalutskii/foundation';
103
+ import { honoLoggingHandler, onHandlerError } from '@kalutskii/foundation';
104
+ import { Hono } from 'hono';
105
+
106
+ const app = new Hono();
107
+
108
+ app.use('*', honoLoggingHandler);
109
+ app.onError(onHandlerError);
110
+ ```
111
+
112
+ `onHandlerError` catches all thrown errors, maps `HTTPException` (< 500) to their status codes, and returns a generic 500 with a unique error ID for unexpected errors.
113
+
114
+ `honoLoggingHandler` logs each request with method, status, duration, path, and query params.
115
+ Example: `[12:12:12 (+4 UTC)] hono | POST 200 123ms /api/v1/users (search=term)`
116
+
117
+ ### 5. Execute functions safely and measure performance
118
+
119
+ ```ts
120
+ import { measureExecutionTime, safeExecute } from '@kalutskii/foundation';
121
+
122
+ const result = await safeExecute(
123
+ () => fetchData(),
124
+ (error) => console.error(error)
125
+ );
126
+
127
+ const { result: data, executionTime } = await measureExecutionTime(() => fetchData());
128
+ console.log(`Done in ${executionTime}ms`);
129
+ ```
130
+
131
+ ### 6. Parse query params with `asQuery`
132
+
133
+ ```ts
134
+ import { asQuery } from '@kalutskii/foundation';
135
+ import { z } from 'zod';
136
+
137
+ const schema = z.object({
138
+ page: asQuery(z.number().int().positive()),
139
+ isActive: asQuery(z.boolean()),
140
+ });
141
+
142
+ schema.parse({ page: '2', isActive: 'true' }); // { page: 2, isActive: true }
143
+ ```
144
+
145
+ `asQuery` preprocesses string values from query parameters — coercing `'true'`/`'false'` to booleans and numeric strings to numbers — before passing them to the Zod schema for validation.
146
+
147
+ ### 7. Use pagination schema
148
+
149
+ ```ts
150
+ import { refinePagination, zodPaginationSchema, zodPaginationShape } from '@kalutskii/foundation';
151
+ import { z } from 'zod';
152
+
153
+ // Use as a standalone schema
154
+ const options = zodPaginationSchema.parse({ offset: '0', limit: '20' });
155
+ // { offset: 0, limit: 20 }
156
+
157
+ // Spread shape into a larger query schema
158
+ const querySchema = z.object({
159
+ search: z.string().optional(),
160
+ ...zodPaginationShape,
161
+ });
162
+
163
+ // Strip undefined pagination values before passing to a query builder (e.g. Drizzle)
164
+ await db.query.users.findMany({
165
+ ...refinePagination(options),
166
+ });
167
+ ```
168
+
169
+ ### 8. Work with JWT using `ZodJWTService`
170
+
171
+ ```ts
172
+ import { ZodJWTService } from '@kalutskii/foundation';
101
173
  import { z } from 'zod';
102
174
 
103
- const pageSchema = asQueryNumber(z.number().int().min(1));
104
- const enabledSchema = asQueryBoolean(z.boolean());
175
+ const payloadSchema = z.object({ userId: z.string() });
176
+ const jwt = new ZodJWTService(payloadSchema, { defaultExpirationSeconds: 3600 });
177
+
178
+ const token = await jwt.sign({ userId: '42' }, 'secret');
179
+ const payload = await jwt.verifyOrThrow(token, 'secret');
180
+ // payload: { userId: '42', exp: ... }
181
+
182
+ // decode without throwing (returns null on invalid token or schema mismatch)
183
+ const decoded = await jwt.decode(token);
184
+ ```
185
+
186
+ ### 9. Datetime helpers
187
+
188
+ ```ts
189
+ import { formatTime, getFormattedDate, getFormattedTime, getZonedTime } from '@kalutskii/foundation';
190
+
191
+ getFormattedTime({ tz: 'Europe/Moscow' }); // '15:30:00 (+3 UTC)'
192
+ getFormattedDate({ tz: 'Europe/Moscow' }); // '22.06.2026 15:30:00 (+3 UTC)'
193
+ getFormattedDate({ tz: 'Europe/Moscow', withTime: false }); // '22.06.2026'
194
+ formatTime(new Date(), { tz: 'Europe/Moscow' }); // '15:30:00, 22 июня 2026 (+3 UTC)'
195
+ ```
196
+
197
+ ### 10. Logging
198
+
199
+ ```ts
200
+ import { log } from '@kalutskii/foundation';
105
201
 
106
- pageSchema.parse('2'); // 2
107
- enabledSchema.parse('yes'); // true
108
- enabledSchema.parse('off'); // false
202
+ log.info('Server started', 'app');
203
+ log.warn('Deprecated call', 'auth');
204
+ log.error('Something failed', 'db', error.stack);
205
+ // [15:30:00 (+3 UTC)] app | Server started
109
206
  ```
110
207
 
111
208
  ## Exports
112
209
 
113
210
  The package exports all public APIs from a single entrypoint:
114
211
 
115
- - HTTP constants, schemas, factories, and resolvers.
116
- - Hono `respond` helper.
117
- - Serialization/query utilities, including `SerializeDates`.
212
+ - **HTTP**: `success`, `failure`, `fetchSafely`, `fetchAndThrow`, constants, schemas.
213
+ - **Hono**: `respond`, `onHandlerError`, `honoLoggingHandler`.
214
+ - **Utilities**: `safeExecute`, `measureExecutionTime`, `generateRandomString`, `log`, `getColoredHTTPStatus`, datetime helpers.
215
+ - **Zod JWT**: `ZodJWTService`.
216
+ - **Zod Pagination**: `zodPaginationSchema`, `zodPaginationShape`, `refinePagination`, `ZodPaginationOptions`.
217
+ - **Zod Validation**: `asQuery`, `AsQuery`, `AtLeastOne`.
218
+ - **Type Utilities**: `Simplify`.
118
219
 
119
220
  ## Development
120
221
 
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { ErrorHandler, MiddlewareHandler, Context, TypedResponse } from 'hono';
2
- import z from 'zod';
3
2
  import { Locale } from 'date-fns';
4
3
  import { SymmetricAlgorithm } from 'hono/utils/jwt/jwa';
4
+ import z from 'zod';
5
5
 
6
6
  /**
7
7
  * Global error handler for Hono framework. Catches all exceptions thrown in route handlers and middlewares.
@@ -33,7 +33,10 @@ type APIError = {
33
33
  type APIContractResult<TData = void> = APISuccess<TData> | APIError;
34
34
  type APIContractData<TResult extends APIContractResult<unknown>> = TResult extends APISuccess<infer TData> ? TData : never;
35
35
  type APIContractError<TResult extends APIContractResult<unknown>> = Extract<TResult, APIError>;
36
- /** Discriminated union result of a fetch operation. If `error` is set, `data` is null and vice versa. */
36
+ /**
37
+ * Discriminated union result of a fetch operation.
38
+ * If `error` is set, `data` is null and vice versa.
39
+ */
37
40
  type FetchResult<T> = {
38
41
  error: null;
39
42
  data: T;
@@ -42,15 +45,36 @@ type FetchResult<T> = {
42
45
  data: null;
43
46
  };
44
47
 
48
+ /**
49
+ * Utility type that simplifies a given type T by flattening its structure.
50
+ * This is particularly useful for improving the readability of complex types.
51
+ */
52
+ type Simplify<T> = {
53
+ [K in keyof T]: T[K];
54
+ } & {};
55
+
45
56
  type QueryPrimitive = string | number | boolean | bigint | Date | null | undefined;
46
57
  /**
47
58
  * Type utility that recursively transforms all fields to string, as well as handling arrays and objects.
48
59
  * This is useful for serializing complex data structures into query parameters, which must be strings.
49
- * Example usage: `AsQuery<{ id: number; name: string; tags: string[] }>` = `{ id: string; name: string; tags: string[] }`
50
60
  */
51
61
  type AsQuery<T> = T extends QueryPrimitive ? string : T extends readonly (infer Item)[] ? AsQuery<Item>[] : T extends object ? {
52
62
  [Key in keyof T]: AsQuery<T[Key]>;
53
63
  } : string;
64
+ /**
65
+ * Utility type that ensures at least one property from the specified
66
+ * keys of a given type T is required, while the rest remain optional.
67
+ *
68
+ * This is useful for scenarios where you want to enforce that at least one
69
+ * of several optional (nullable) properties must be provided in an object.
70
+ *
71
+ * ```ts
72
+ * type Example = AtLeastOne<{ a?: string; b?: number; c?: boolean }>;
73
+ * // Valid: { a: "hello" }, { b: 42 }, { c: true }, { a: "hello", b: 42 }
74
+ * // Invalid: {}, { a: undefined, b: undefined, c: undefined }
75
+ * ```
76
+ */
77
+ type AtLeastOne<T, Keys extends keyof T = keyof T> = Keys extends keyof T ? Simplify<Required<Pick<T, Keys>> & Partial<Omit<T, Keys>>> : never;
54
78
 
55
79
  /**
56
80
  * Wraps c.json with a typed success payload / (or void data) & possible APIError response.
@@ -80,86 +104,65 @@ declare function failure({ status, error }: {
80
104
 
81
105
  /**
82
106
  * Resolves an APIContractResult fetcher into a FetchResult discriminated union.
83
- * Does not throw errors, instead returning them in the error property of the FetchResult.
107
+ * Does not throw errors, instead returning them as property of the FetchResult.
84
108
  * Example usage: const result = await fetchSafely(() => api.fetchUser(userId));
85
109
  */
86
110
  declare function fetchSafely<TResult extends APIContractResult<unknown>>(fetcher: () => Promise<TResult>): Promise<FetchResult<APIContractData<TResult>>>;
87
111
  /**
88
- * Resolves an APIContractResult fetcher, throwing an error if the result is an APIError.
112
+ * Resolves an APIContractResult, throwing an error if the result is an APIError.
89
113
  * Example usage: const data = await fetchAndThrow(() => api.fetchUser(userId));
90
114
  */
91
115
  declare function fetchAndThrow<TResult extends APIContractResult<unknown>>(fetcher: () => Promise<TResult>): Promise<APIContractData<TResult>>;
92
116
 
93
117
  /**
94
- * A Zod schema for validating pagination options, specifically the `offset` and `limit` parameters.
95
- * - `offset`: An optional non-negative integer representing the starting point for pagination.
96
- * - `limit`: An optional positive integer representing the maximum number of items to return.
118
+ * Returns the current date and time shifted to the specified timezone.
97
119
  *
98
- * This schema can be used to inject in other Zod schemas for validating pagination options:
99
- *
100
- * ```ts
101
- * const mySchema = paginationSchema.extend({
102
- * // other fields here
103
- * });
104
- * ```
105
- */
106
- declare const paginationSchema: z.ZodObject<{
107
- offset: z.ZodOptional<z.ZodPreprocess<z.ZodNumber>>;
108
- limit: z.ZodOptional<z.ZodPreprocess<z.ZodNumber>>;
109
- }, z.core.$strip>;
110
- /**
111
- * A TypeScript type representing the pagination options validated by the `paginationSchema`.
112
- * Read documentation for `paginationSchema` for more details on the structure and usage of this type.
113
- */
114
- type PaginationOptions = z.infer<typeof paginationSchema>;
115
-
116
- /**
117
- * A utility function that extracts pagination options from the provided input.
118
- * It returns an object containing the `offset` and `limit` properties if they are defined.
119
- * If the input is undefined or does not contain these properties, it returns an empty object.
120
- *
121
- * ```ts
122
- * await db.query.someTable.findMany({
123
- * ...refinePagination(options),
124
- * });
125
- * ```
126
- */
127
- declare const refinePagination: (options?: PaginationOptions) => {
128
- offset?: number | undefined;
129
- limit?: number | undefined;
130
- };
131
-
132
- /**
133
- * Returns the current time in the specified timezone.
134
- * Example usage: `getZonedTime({ tz: 'America/New_York' }) = new Date('2026-03-15T12:00:00Z')`
120
+ * This is useful when the application needs to display "now" from another
121
+ * region's point of view instead of relying on the server's local timezone.
135
122
  */
136
123
  declare const getZonedTime: ({ tz }?: {
137
124
  tz?: string;
138
125
  }) => Date;
139
126
  /**
140
- * Returns the timezone offset in the format (+4 UTC) / (-5 UTC).
141
- * Example usage: `getUTCOffset(new Date('2026-03-15T12:00:00Z'), 'America/New_York') = '(-4 UTC)'`
127
+ * Returns the UTC offset for the specified timezone at the given date.
128
+ *
129
+ * The offset is formatted for display next to dates and times, for example
130
+ * `(+4 UTC)`, `(0 UTC)`, or `(-5 UTC)`. The date is required because timezone
131
+ * offsets may change depending on daylight saving time or historical rules.
142
132
  */
143
133
  declare const getUTCOffset: (date: Date, tz: string) => string;
144
134
  /**
145
- * Returns the current time in the specified timezone, formatted as HH:mm:ss (+X UTC).
146
- * Example usage: `getFormattedTime({ tz: 'America/New_York' }) = '12:00:00 (-4 UTC)'`
135
+ * Returns the current time formatted in the specified timezone.
136
+ *
137
+ * The result includes both the local time and its UTC offset, making it suitable
138
+ * for UI labels, logs, bot messages, and other places where the user should see
139
+ * not only the time itself, but also the timezone context behind that value.
140
+ *
141
+ * Format: `HH:mm:ss (+X UTC)`.
147
142
  */
148
143
  declare const getFormattedTime: ({ tz }?: {
149
144
  tz?: string;
150
145
  }) => string;
151
146
  /**
152
- * Returns the current date in the specified timezone, formatted as dd.MM.yyyy.
153
- * By default, it also includes time (HH:mm:ss) and timezone offset.
154
- * Example usage: `getFormattedDate({ tz: 'America/New_York' }) = '03.15.2026 12:00:00 (-4 UTC)'`
147
+ * Returns the current date formatted in the specified timezone.
148
+ *
149
+ * By default, the result includes date, time, and UTC offset. This is useful for
150
+ * complete timestamps displayed in UI, bot messages, reports, or diagnostics.
151
+ *
152
+ * Format with time: `dd.MM.yyyy HH:mm:ss (+X UTC)`.
153
+ * Format without time: `dd.MM.yyyy`.
155
154
  */
156
155
  declare const getFormattedDate: ({ tz, withTime, }?: {
157
156
  tz?: string;
158
157
  withTime?: boolean;
159
158
  }) => string;
160
159
  /**
161
- * Formats the given time in the specified timezone, using the provided locale for date formatting.
162
- * Example usage: `formatTime(new Date('2026-03-15T12:00:00Z'), { tz: 'America/New_York' }) = '12:00:00, March 15, 2026 (-4 UTC)'`
160
+ * Formats the provided date and time in the specified timezone.
161
+ *
162
+ * Unlike helpers that always use the current moment, this function accepts an
163
+ * explicit Date value and formats that exact point in time for another timezone.
164
+ *
165
+ * Format: `HH:mm:ss, d MMMM yyyy (+X UTC)`.
163
166
  */
164
167
  declare const formatTime: (time: Date, { locale, tz }?: {
165
168
  locale?: Locale;
@@ -211,55 +214,6 @@ declare const log: {
211
214
  error: (message: string, service?: string, stack?: string) => void;
212
215
  };
213
216
 
214
- /**
215
- * Utility type that simplifies a given type T by flattening its structure.
216
- * This is particularly useful for improving the readability of complex types.
217
- */
218
- type Simplify<T> = {
219
- [K in keyof T]: T[K];
220
- } & {};
221
-
222
- /**
223
- * Transforms a string to a number (when passing query parameters).
224
- * Example usage: `asQueryNumber(z.number())('123') = 123`
225
- */
226
- declare const asQueryNumber: <T extends z.ZodTypeAny>(schema: T) => z.ZodPreprocess<T>;
227
- /**
228
- * Transforms various string representations of boolean values into actual booleans.
229
- * See POSITIVE_VALUES and NEGATIVE_VALUES arrays below for supported inputs.
230
- */
231
- declare const asQueryBoolean: <T extends z.ZodTypeAny>(schema: T) => z.ZodPreprocess<T>;
232
-
233
- /**
234
- * A utility type that represents a value that can be of type T or null.
235
- * Commonly used for optional fields in data models or function return types.
236
- *
237
- * ```ts
238
- * export type ObjectSelect = XOR<
239
- * Pick<Object, 'id'>,
240
- * Pick<Object, 'anotherUniqueField'>
241
- * >;
242
- */
243
- type XOR<T, U> = Simplify<T & {
244
- [K in keyof U]?: never;
245
- }> | Simplify<U & {
246
- [K in keyof T]?: never;
247
- }>;
248
- /**
249
- * Utility type that ensures at least one property from the specified
250
- * keys of a given type T is required, while the rest remain optional.
251
- *
252
- * This is useful for scenarios where you want to enforce that at least one
253
- * of several optional (nullable) properties must be provided in an object.
254
- *
255
- * ```ts
256
- * type Example = AtLeastOne<{ a?: string; b?: number; c?: boolean }>;
257
- * // Valid: { a: "hello" }, { b: 42 }, { c: true }, { a: "hello", b: 42 }
258
- * // Invalid: {}, { a: undefined, b: undefined, c: undefined }
259
- * ```
260
- */
261
- type AtLeastOne<T, Keys extends keyof T = keyof T> = Keys extends keyof T ? Simplify<Required<Pick<T, Keys>> & Partial<Omit<T, Keys>>> : never;
262
-
263
217
  /** Options for configuring the JWT service. */
264
218
  type JWTServiceOptions = {
265
219
  /** The algorithm to use for signing and verifying JWTs. Defaults to 'HS256'. */
@@ -272,9 +226,13 @@ type JWTSignOptions = {
272
226
  /** The number of seconds until the JWT expires. */
273
227
  expiresInSeconds?: number;
274
228
  };
275
- /** Utility types for inferring payload types from Zod schemas. */
229
+ /**
230
+ * Utility types for inferring payload types from Zod schemas.
231
+ */
276
232
  type Payload<T> = T extends z.ZodType ? z.infer<T> : T;
277
- /** Utility type to extract the payload schema type from a Zod schema. */
233
+ /**
234
+ * Utility type to extract the payload schema type from a Zod schema.
235
+ * */
278
236
  type PayloadSchema<T> = T extends z.ZodType ? T : never;
279
237
 
280
238
  /**
@@ -308,4 +266,59 @@ declare class ZodJWTService<TPayloadOrSchema> {
308
266
  verifyOrThrow(token: string, secret: string): Promise<Payload<TPayloadOrSchema>>;
309
267
  }
310
268
 
311
- 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 PaginationOptions, type Payload, type PayloadSchema, SUCCESS_STATUS_CODES, type Simplify, type SuccessStatusCode, type XOR, ZodJWTService, asQueryBoolean, asQueryNumber, failure, fetchAndThrow, fetchSafely, formatTime, generateRandomString, getColoredHTTPStatus, getFormattedDate, getFormattedTime, getUTCOffset, getZonedTime, honoLoggingHandler, log, measureExecutionTime, onHandlerError, paginationSchema, refinePagination, respond, safeExecute, success };
269
+ declare const zodPaginationSchema: z.ZodObject<{
270
+ offset: z.ZodOptional<z.ZodPreprocess<z.ZodNumber>>;
271
+ limit: z.ZodOptional<z.ZodPreprocess<z.ZodNumber>>;
272
+ }, z.core.$strip>;
273
+ /**
274
+ * Reusable pagination fields for flat query schemas, allowing for
275
+ * consistent validation of pagination parameters across different endpoints.
276
+ *
277
+ * Spread into another `z.object(...)` when composing a larger query schema,
278
+ * or use `zodPaginationSchema.extend(...)` when building directly from the schema.
279
+ */
280
+ declare const zodPaginationShape: {
281
+ offset: z.ZodOptional<z.ZodPreprocess<z.ZodNumber>>;
282
+ limit: z.ZodOptional<z.ZodPreprocess<z.ZodNumber>>;
283
+ };
284
+ /**
285
+ * TypeScript type representing the pagination options validated by the `zodPaginationSchema`.
286
+ * Read documentation for `zodPaginationSchema` for more details on the structure and usage of this type.
287
+ */
288
+ type ZodPaginationOptions = z.infer<typeof zodPaginationSchema>;
289
+
290
+ /**
291
+ * Extracts defined pagination options from a query object.
292
+ *
293
+ * This keeps query builder calls clean by omitting undefined values while
294
+ * preserving valid pagination values like `0`, useful when spreading pagination
295
+ * options into APIs that expect only explicitly provided fields (e.g., Drizzle).
296
+ *
297
+ * ```ts
298
+ * await db.query.someTable.findMany({
299
+ * ...refinePagination(options),
300
+ * });
301
+ * ```
302
+ */
303
+ declare const refinePagination: (options?: ZodPaginationOptions) => ZodPaginationOptions;
304
+
305
+ /**
306
+ * Query parameters always arrive as strings, even when they semantically represent numbers
307
+ * or booleans, so we preprocess them to convert to the appropriate types before validation.
308
+ *
309
+ * ```ts
310
+ * const schema = z.object({
311
+ * page: z.number().int().positive(),
312
+ * isActive: z.boolean(),
313
+ * });
314
+ *
315
+ * const queryParams = { page: '2', isActive: 'true' };
316
+ * const result = schema.parse(queryParams); // { page: 2, isActive: true }
317
+ * ```
318
+ *
319
+ * @param schema - The Zod schema to validate the query parameters against.
320
+ * @returns A new Zod schema that preprocesses query parameter values before validation.
321
+ */
322
+ declare const asQuery: <T extends z.ZodTypeAny>(schema: T) => z.ZodPreprocess<T>;
323
+
324
+ 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, SUCCESS_STATUS_CODES, type Simplify, type SuccessStatusCode, ZodJWTService, type ZodPaginationOptions, asQuery, failure, fetchAndThrow, fetchSafely, formatTime, generateRandomString, getColoredHTTPStatus, getFormattedDate, getFormattedTime, getUTCOffset, getZonedTime, honoLoggingHandler, log, measureExecutionTime, onHandlerError, refinePagination, respond, safeExecute, success, zodPaginationSchema, zodPaginationShape };
package/dist/index.js CHANGED
@@ -130,53 +130,6 @@ async function fetchAndThrow(fetcher) {
130
130
  return response.data;
131
131
  }
132
132
 
133
- // src/pagination/pagination.schemas.ts
134
- import z2 from "zod";
135
-
136
- // src/validation/validation.refiners.ts
137
- import z from "zod";
138
- var asQueryNumber = (schema) => z.preprocess((value) => {
139
- if (typeof value !== "string")
140
- return value;
141
- if (value.trim() === "")
142
- return value;
143
- return Number(value);
144
- }, schema);
145
- var asQueryBoolean = (schema) => {
146
- const POSITIVE_VALUES = ["1", "true", "yes", "y", "on"];
147
- const NEGATIVE_VALUES = ["0", "false", "no", "n", "off"];
148
- return z.preprocess((value) => {
149
- if (typeof value === "boolean")
150
- return value;
151
- if (typeof value === "string") {
152
- const normalized = value.trim().toLowerCase();
153
- if (POSITIVE_VALUES.includes(normalized))
154
- return true;
155
- if (NEGATIVE_VALUES.includes(normalized))
156
- return false;
157
- }
158
- return value;
159
- }, schema);
160
- };
161
-
162
- // src/pagination/pagination.schemas.ts
163
- var paginationSchema = z2.object({
164
- offset: asQueryNumber(z2.number().int().nonnegative()).optional(),
165
- limit: asQueryNumber(z2.number().int().positive()).optional()
166
- });
167
-
168
- // src/pagination/pagination.refiners.ts
169
- var refinePagination = (options) => {
170
- const pagination = {};
171
- if (options?.offset !== void 0) {
172
- pagination.offset = options.offset;
173
- }
174
- if (options?.limit !== void 0) {
175
- pagination.limit = options.limit;
176
- }
177
- return pagination;
178
- };
179
-
180
133
  // src/utilities/execution.utilities.ts
181
134
  async function safeExecute(fn, onError) {
182
135
  try {
@@ -242,12 +195,49 @@ var ZodJWTService = class {
242
195
  return this.payloadSchema.parseAsync(payload);
243
196
  }
244
197
  };
198
+
199
+ // src/zod-pagination/zod-pagination.refiners.ts
200
+ var refinePagination = (options) => ({
201
+ ...options?.offset !== void 0 ? { offset: options.offset } : {},
202
+ ...options?.limit !== void 0 ? { limit: options.limit } : {}
203
+ });
204
+
205
+ // src/zod-pagination/zod-pagination.schemas.ts
206
+ import z2 from "zod";
207
+
208
+ // src/zod-validation/zod-validation.refiners.ts
209
+ import z from "zod";
210
+ var parseQueryValue = (value) => {
211
+ if (Array.isArray(value))
212
+ return value.map(parseQueryValue);
213
+ if (typeof value !== "string")
214
+ return value;
215
+ const normalized = value.trim().toLowerCase();
216
+ if (normalized === "")
217
+ return value;
218
+ if (normalized === "true")
219
+ return true;
220
+ if (normalized === "false")
221
+ return false;
222
+ if (/^[+-]?(?:\d+\.?\d*|\.\d+)(?:e[+-]?\d+)?$/i.test(normalized))
223
+ return Number(normalized);
224
+ return value;
225
+ };
226
+ var asQuery = (schema) => z.preprocess(parseQueryValue, schema);
227
+
228
+ // src/zod-pagination/zod-pagination.schemas.ts
229
+ var zodPaginationSchema = z2.object({
230
+ /** Integer representing the starting point for pagination. */
231
+ offset: asQuery(z2.number().int().nonnegative()).optional(),
232
+ /** Integer representing the maximum number of items to return. */
233
+ limit: asQuery(z2.number().int().positive()).optional()
234
+ });
235
+ var zodPaginationShape = zodPaginationSchema.shape;
245
236
  export {
246
237
  EXCEPTION_STATUS_CODES,
247
238
  SUCCESS_STATUS_CODES,
248
239
  ZodJWTService,
249
- asQueryBoolean,
250
- asQueryNumber,
240
+ asQuery,
251
241
  failure,
252
242
  fetchAndThrow,
253
243
  fetchSafely,
@@ -262,9 +252,10 @@ export {
262
252
  log,
263
253
  measureExecutionTime,
264
254
  onHandlerError,
265
- paginationSchema,
266
255
  refinePagination,
267
256
  respond,
268
257
  safeExecute,
269
- success
258
+ success,
259
+ zodPaginationSchema,
260
+ zodPaginationShape
270
261
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kalutskii/foundation",
3
- "version": "0.6.5",
3
+ "version": "0.6.6",
4
4
  "description": "Typescript collection of most common utilities, schemas and functions among private projects.",
5
5
  "type": "module",
6
6
  "repository": {
@@ -12,7 +12,8 @@
12
12
  },
13
13
  "scripts": {
14
14
  "build": "tsup",
15
- "lint": "eslint .",
15
+ "lint": "eslint . --ext .ts",
16
+ "format": "prettier --write .",
16
17
  "typecheck": "tsc --noEmit"
17
18
  },
18
19
  "exports": {