@kalutskii/foundation 0.6.22 → 0.6.24
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 +51 -16
- package/dist/index.d.ts +153 -11
- package/dist/index.js +49 -12
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -144,7 +144,7 @@ schema.parse({ page: '2', isActive: 'true' }); // { page: 2, isActive: true }
|
|
|
144
144
|
|
|
145
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
146
|
|
|
147
|
-
###
|
|
147
|
+
### 7. Build flat query schemas from nested objects
|
|
148
148
|
|
|
149
149
|
```typescript
|
|
150
150
|
import { asQuerySchema } from '@kalutskii/foundation';
|
|
@@ -171,29 +171,62 @@ schema.parse({ sort: { field: 'name', order: 'asc' } }); // throws
|
|
|
171
171
|
|
|
172
172
|
`asQuerySchema` flattens nested `z.object(...)` fields to the top level, making it suitable for flat query parameter validation. Nested object fields are lifted, while optionality is preserved: required parents keep their fields required, optional parents make all promoted fields optional. The result is a strict schema (unknown keys are rejected).
|
|
173
173
|
|
|
174
|
-
### 8.
|
|
174
|
+
### 8. Build reusable search schemas
|
|
175
175
|
|
|
176
176
|
```typescript
|
|
177
|
-
import {
|
|
177
|
+
import { zodPaginationSchema, zodSearchSchema } from '@kalutskii/foundation';
|
|
178
178
|
import { z } from 'zod';
|
|
179
179
|
|
|
180
|
-
|
|
181
|
-
|
|
180
|
+
const assetSchema = z.object({
|
|
181
|
+
status: z.enum(['active', 'archived']),
|
|
182
|
+
categoryId: z.number(),
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
const assetSearchSchema = zodSearchSchema({
|
|
186
|
+
filters: assetSchema.pick({ status: true, categoryId: true }),
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
type AssetSearch = z.infer<typeof assetSearchSchema>;
|
|
190
|
+
|
|
191
|
+
assetSearchSchema.parse({
|
|
192
|
+
where: { status: 'active' },
|
|
193
|
+
query: 'asset name',
|
|
194
|
+
pagination: { offset: 0, limit: 20 },
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
// Pagination remains available as a standalone reusable schema.
|
|
198
|
+
zodPaginationSchema.parse({ offset: '0', limit: '20' });
|
|
182
199
|
// { offset: 0, limit: 20 }
|
|
200
|
+
```
|
|
183
201
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
202
|
+
### 9. Share bulk selection between frontend and backend
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
import { zodBulkSelectionSchema, zodSearchSchema } from '@kalutskii/foundation';
|
|
206
|
+
import { z } from 'zod';
|
|
207
|
+
|
|
208
|
+
const assetBulkSelectionSchema = zodBulkSelectionSchema({
|
|
209
|
+
identifierSchema: z.string().min(1),
|
|
188
210
|
});
|
|
189
211
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
212
|
+
const assetBulkFilterSchema = zodSearchSchema({
|
|
213
|
+
filters: assetSchema.pick({ status: true, categoryId: true }),
|
|
214
|
+
paginationEnabled: false,
|
|
193
215
|
});
|
|
216
|
+
|
|
217
|
+
const assetBulkRequestSchema = z
|
|
218
|
+
.object({
|
|
219
|
+
selection: assetBulkSelectionSchema,
|
|
220
|
+
filter: assetBulkFilterSchema,
|
|
221
|
+
})
|
|
222
|
+
.strict();
|
|
223
|
+
|
|
224
|
+
type AssetBulkRequest = z.infer<typeof assetBulkRequestSchema>;
|
|
194
225
|
```
|
|
195
226
|
|
|
196
|
-
|
|
227
|
+
In `include` mode, the backend targets only `identifiers`. In `exclude` mode, it resolves all entities matching the same filter snapshot and removes `excludedIdentifiers` from that operation.
|
|
228
|
+
|
|
229
|
+
### 10. Work with JWT using `ZodJWTService`
|
|
197
230
|
|
|
198
231
|
```typescript
|
|
199
232
|
import { ZodJWTService } from '@kalutskii/foundation';
|
|
@@ -210,7 +243,7 @@ const payload = await jwt.verifyOrThrow(token, 'secret');
|
|
|
210
243
|
const decoded = await jwt.decode(token);
|
|
211
244
|
```
|
|
212
245
|
|
|
213
|
-
###
|
|
246
|
+
### 11. Datetime helpers
|
|
214
247
|
|
|
215
248
|
```typescript
|
|
216
249
|
import { formatTime, getFormattedDate, getFormattedTime, getZonedTime } from '@kalutskii/foundation';
|
|
@@ -221,7 +254,7 @@ getFormattedDate({ tz: 'Europe/Moscow', withTime: false }); // '22.06.2026'
|
|
|
221
254
|
formatTime(new Date(), { tz: 'Europe/Moscow' }); // '15:30:00, 22 июня 2026 (+3 UTC)'
|
|
222
255
|
```
|
|
223
256
|
|
|
224
|
-
###
|
|
257
|
+
### 12. Logging
|
|
225
258
|
|
|
226
259
|
```typescript
|
|
227
260
|
import { log } from '@kalutskii/foundation';
|
|
@@ -239,8 +272,10 @@ The package exports all public APIs from a single entrypoint:
|
|
|
239
272
|
- **HTTP**: `success`, `failure`, `fetchSafely`, `fetchAndThrow`, constants, schemas.
|
|
240
273
|
- **Hono**: `respond`, `onHandlerError`, `honoLoggingHandler`.
|
|
241
274
|
- **Utilities**: `safeExecute`, `measureExecutionTime`, `generateRandomString`, `log`, `getColoredHTTPStatus`, datetime helpers.
|
|
275
|
+
- **Zod Bulk**: `zodBulkSelectionSchema`, `ZodBulkSelection`, `ZodBulkIncludeSelection`, `ZodBulkExcludeSelection`.
|
|
242
276
|
- **Zod JWT**: `ZodJWTService`.
|
|
243
|
-
- **Zod
|
|
277
|
+
- **Zod Search**: `zodSearchSchema`, `ZodSearchSchemaOptions`.
|
|
278
|
+
- **Zod Pagination**: `zodPaginationSchema`, `zodPaginationShape`, `ZodPaginationOptions`.
|
|
244
279
|
- **Zod Flatten**: `asQuerySchema`, `flattenZodShape`, `isZodObject`, `isZodOptional`, `unwrapOptional`, `FlattenZodShape`.
|
|
245
280
|
- **Zod Validation**: `asQuery`, `AsQuery`, `AtLeastOne`.
|
|
246
281
|
- **Type Utilities**: `Simplify`.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { SQL
|
|
1
|
+
import { SQL } from 'drizzle-orm';
|
|
2
2
|
import { ErrorHandler, MiddlewareHandler, Context, TypedResponse } from 'hono';
|
|
3
3
|
import { Locale } from 'date-fns';
|
|
4
|
-
import { SymmetricAlgorithm } from 'hono/utils/jwt/jwa';
|
|
5
4
|
import z, { ZodObject, ZodRawShape, z as z$1 } from 'zod';
|
|
5
|
+
import { SymmetricAlgorithm } from 'hono/utils/jwt/jwa';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Builds a Drizzle SQL `where` condition from a plain object.
|
|
@@ -222,6 +222,52 @@ type Simplify<T> = {
|
|
|
222
222
|
[K in keyof T]: T[K];
|
|
223
223
|
} & {};
|
|
224
224
|
|
|
225
|
+
/**
|
|
226
|
+
* Builds a strict selection contract for bulk operations across paginated data.
|
|
227
|
+
* The identifier schema is shared by explicit and all-matching selection modes.
|
|
228
|
+
*
|
|
229
|
+
* `include` targets only identifiers listed by the client. `exclude` targets every
|
|
230
|
+
* item matching the accompanying search snapshot except excluded identifiers.
|
|
231
|
+
*
|
|
232
|
+
* @example
|
|
233
|
+
* const assetBulkSelectionSchema = zodBulkSelectionSchema({
|
|
234
|
+
* identifierSchema: z.string().min(1),
|
|
235
|
+
* });
|
|
236
|
+
*/
|
|
237
|
+
declare const zodBulkSelectionSchema: <const TIdentifierSchema extends z.ZodType<string | number>>({ identifierSchema, }: {
|
|
238
|
+
/**
|
|
239
|
+
* Schema used to validate every included or excluded entity identifier.
|
|
240
|
+
* Its transforms and exact inferred output are preserved in both branches.
|
|
241
|
+
*/
|
|
242
|
+
identifierSchema: TIdentifierSchema;
|
|
243
|
+
}) => z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
244
|
+
mode: z.ZodLiteral<"include">;
|
|
245
|
+
identifiers: z.ZodArray<TIdentifierSchema>;
|
|
246
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
247
|
+
mode: z.ZodLiteral<"exclude">;
|
|
248
|
+
excludedIdentifiers: z.ZodArray<TIdentifierSchema>;
|
|
249
|
+
}, z.core.$strict>], "mode">;
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Shared bulk-selection payload produced by `zodBulkSelectionSchema`.
|
|
253
|
+
* String identifiers are used by default for frontend table integrations.
|
|
254
|
+
*/
|
|
255
|
+
type ZodBulkSelection<TIdentifier extends string | number = string> = z.infer<ReturnType<typeof zodBulkSelectionSchema<z.ZodType<TIdentifier>>>>;
|
|
256
|
+
/**
|
|
257
|
+
* Explicit bulk selection containing only identifiers chosen by the client.
|
|
258
|
+
* This branch does not require resolving an all-matching search snapshot.
|
|
259
|
+
*/
|
|
260
|
+
type ZodBulkIncludeSelection<TIdentifier extends string | number = string> = Extract<ZodBulkSelection<TIdentifier>, {
|
|
261
|
+
mode: 'include';
|
|
262
|
+
}>;
|
|
263
|
+
/**
|
|
264
|
+
* All-matching bulk selection containing identifiers excluded by the client.
|
|
265
|
+
* Backend handlers must resolve targets from the same search snapshot.
|
|
266
|
+
*/
|
|
267
|
+
type ZodBulkExcludeSelection<TIdentifier extends string | number = string> = Extract<ZodBulkSelection<TIdentifier>, {
|
|
268
|
+
mode: 'exclude';
|
|
269
|
+
}>;
|
|
270
|
+
|
|
225
271
|
/** Options for configuring the JWT service. */
|
|
226
272
|
type JWTServiceOptions = {
|
|
227
273
|
/** The algorithm to use for signing and verifying JWTs. Defaults to 'HS256'. */
|
|
@@ -274,26 +320,122 @@ declare class ZodJWTService<TPayloadOrSchema> {
|
|
|
274
320
|
verifyOrThrow(token: string, secret: string): Promise<Payload<TPayloadOrSchema>>;
|
|
275
321
|
}
|
|
276
322
|
|
|
323
|
+
/**
|
|
324
|
+
* Validates offset-based pagination shared by search request contracts.
|
|
325
|
+
* Missing fields inside the required object receive predictable defaults.
|
|
326
|
+
*/
|
|
277
327
|
declare const zodPaginationSchema: z.ZodObject<{
|
|
278
328
|
offset: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
279
329
|
limit: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
280
330
|
}, z.core.$strip>;
|
|
281
331
|
/**
|
|
282
|
-
*
|
|
283
|
-
*
|
|
284
|
-
*
|
|
285
|
-
* Spread into another `z.object(...)` when composing a larger query schema,
|
|
286
|
-
* or use `zodPaginationSchema.extend(...)` when building directly from the schema.
|
|
332
|
+
* Exposes pagination fields for composition into other object schemas.
|
|
333
|
+
* The shape stays derived from the schema to prevent contract divergence.
|
|
287
334
|
*/
|
|
288
335
|
declare const zodPaginationShape: {
|
|
289
336
|
offset: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
290
337
|
limit: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
291
338
|
};
|
|
339
|
+
|
|
292
340
|
/**
|
|
293
|
-
* TypeScript
|
|
294
|
-
*
|
|
341
|
+
* TypeScript output produced after successful pagination validation.
|
|
342
|
+
* Defaulted fields are represented as required numeric properties.
|
|
295
343
|
*/
|
|
296
344
|
type ZodPaginationOptions = z.infer<typeof zodPaginationSchema>;
|
|
345
|
+
/**
|
|
346
|
+
* Feature flags shared by both supported search schema composition modes.
|
|
347
|
+
* Literal values are preserved in the resulting runtime and static shapes.
|
|
348
|
+
*/
|
|
349
|
+
type ZodSearchFeatureOptions<TQueryEnabled extends boolean, TPaginationEnabled extends boolean> = {
|
|
350
|
+
/**
|
|
351
|
+
* Controls whether an optional non-empty `query` field is generated.
|
|
352
|
+
* The field is enabled when this option is omitted from the call.
|
|
353
|
+
*/
|
|
354
|
+
queryEnabled?: TQueryEnabled;
|
|
355
|
+
/**
|
|
356
|
+
* Controls whether a required `pagination` object is generated.
|
|
357
|
+
* The field is enabled when this option is omitted from the call.
|
|
358
|
+
*/
|
|
359
|
+
paginationEnabled?: TPaginationEnabled;
|
|
360
|
+
};
|
|
361
|
+
/**
|
|
362
|
+
* Configuration used to compose a reusable search request schema.
|
|
363
|
+
* Exactly one source must be provided for the resulting `where` field.
|
|
364
|
+
*
|
|
365
|
+
* `filters` is the concise mode that applies partial and non-empty rules.
|
|
366
|
+
* `whereSchema` accepts a fully prepared schema with custom Zod effects.
|
|
367
|
+
*/
|
|
368
|
+
type ZodSearchSchemaOptions<TShape extends z.ZodRawShape = never, TWhereSchema extends z.ZodType<Record<string, unknown>> = never, TQueryEnabled extends boolean = true, TPaginationEnabled extends boolean = true> = ZodSearchFeatureOptions<TQueryEnabled, TPaginationEnabled> & ({
|
|
369
|
+
/**
|
|
370
|
+
* Object schema whose fields become optional filters inside `where`.
|
|
371
|
+
* The factory requires one defined value whenever `where` is present.
|
|
372
|
+
*/
|
|
373
|
+
filters: z.ZodObject<TShape>;
|
|
374
|
+
/** Prevents combining automatic filters with a prepared schema. */
|
|
375
|
+
whereSchema?: never;
|
|
376
|
+
} | {
|
|
377
|
+
/** Prevents combining a prepared schema with automatic filters. */
|
|
378
|
+
filters?: never;
|
|
379
|
+
/**
|
|
380
|
+
* Prepared schema used directly to validate the `where` object.
|
|
381
|
+
* Its refinements, transforms, and inferred output are preserved.
|
|
382
|
+
*/
|
|
383
|
+
whereSchema: TWhereSchema;
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Optional text query shared by search request contracts.
|
|
388
|
+
* Provided values are trimmed and must contain visible text.
|
|
389
|
+
*/
|
|
390
|
+
declare const zodSearchQuerySchema: z.ZodOptional<z.ZodString>;
|
|
391
|
+
/**
|
|
392
|
+
* Makes every supplied filter optional while requiring one defined value.
|
|
393
|
+
* Top-level optionality is added later for both composition modes equally.
|
|
394
|
+
*/
|
|
395
|
+
declare const createZodSearchWhereSchema: <TShape extends z.ZodRawShape>(filters: z.ZodObject<TShape>) => z.ZodPipe<z.ZodObject<{ -readonly [k in keyof TShape]: z.ZodOptional<TShape[k]>; }, z.core.$strip>, z.ZodTransform<Awaited<AtLeastOne<z.core.$InferObjectOutput<{ -readonly [k in keyof TShape]: z.ZodOptional<TShape[k]>; }, {}>, keyof z.core.$InferObjectOutput<{ -readonly [k in keyof TShape]: z.ZodOptional<TShape[k]>; }, {}>>>, z.core.$InferObjectOutput<{ -readonly [k in keyof TShape]: z.ZodOptional<TShape[k]>; }, {}>>>;
|
|
396
|
+
/**
|
|
397
|
+
* Empty schema shape used when a search feature is explicitly disabled.
|
|
398
|
+
* Intersections remove disabled fields without widening enabled branches.
|
|
399
|
+
*/
|
|
400
|
+
type ZodDisabledSearchShape = Record<never, never>;
|
|
401
|
+
/**
|
|
402
|
+
* Resolves the schema used by `where` from the selected composition mode.
|
|
403
|
+
* Prepared schemas remain untouched, including their effects and output.
|
|
404
|
+
*/
|
|
405
|
+
type ZodSearchWhereSchema<TShape extends z.ZodRawShape, TWhereSchema extends z.ZodType<Record<string, unknown>>> = [
|
|
406
|
+
TWhereSchema
|
|
407
|
+
] extends [never] ? ReturnType<typeof createZodSearchWhereSchema<TShape>> : TWhereSchema;
|
|
408
|
+
/**
|
|
409
|
+
* Schema-level shape assembled from the selected source and feature flags.
|
|
410
|
+
* Keeping Zod schemas here makes runtime composition the contract source.
|
|
411
|
+
*/
|
|
412
|
+
type ZodSearchShape<TShape extends z.ZodRawShape, TWhereSchema extends z.ZodType<Record<string, unknown>>, TQueryEnabled extends boolean, TPaginationEnabled extends boolean> = {
|
|
413
|
+
where: z.ZodOptional<ZodSearchWhereSchema<TShape, TWhereSchema>>;
|
|
414
|
+
} & (TQueryEnabled extends false ? ZodDisabledSearchShape : {
|
|
415
|
+
query: typeof zodSearchQuerySchema;
|
|
416
|
+
}) & (TPaginationEnabled extends false ? ZodDisabledSearchShape : {
|
|
417
|
+
pagination: typeof zodPaginationSchema;
|
|
418
|
+
});
|
|
419
|
+
/**
|
|
420
|
+
* Builds a strict schema for reusable search request contracts.
|
|
421
|
+
* The optional `where` object must contain one defined filter.
|
|
422
|
+
*
|
|
423
|
+
* Query is optional and non-empty; pagination is required by default.
|
|
424
|
+
* Literal feature flags update both runtime and inferred static shapes.
|
|
425
|
+
*
|
|
426
|
+
* Pass `filters` for automatic partial and non-empty validation, or use
|
|
427
|
+
* `whereSchema` to preserve a prepared schema with custom Zod effects.
|
|
428
|
+
*
|
|
429
|
+
* @example
|
|
430
|
+
* const assetSearchSchema = zodSearchSchema({
|
|
431
|
+
* filters: assetSchema.pick({ status: true }),
|
|
432
|
+
* });
|
|
433
|
+
*
|
|
434
|
+
* const refinedAssetSearchSchema = zodSearchSchema({
|
|
435
|
+
* whereSchema: zodAtLeastOne(assetSchema.pick({ status: true }).partial()),
|
|
436
|
+
* });
|
|
437
|
+
*/
|
|
438
|
+
declare const zodSearchSchema: <const TShape extends z.ZodRawShape = never, const TWhereSchema extends z.ZodType<Record<string, unknown>> = never, const TQueryEnabled extends boolean = true, const TPaginationEnabled extends boolean = true>(options: ZodSearchSchemaOptions<TShape, TWhereSchema, TQueryEnabled, TPaginationEnabled>) => z.ZodObject<ZodSearchShape<TShape, TWhereSchema, TQueryEnabled, TPaginationEnabled> extends infer T ? { -readonly [P in keyof T]: T[P]; } : never, z.core.$strict>;
|
|
297
439
|
|
|
298
440
|
type QueryPrimitive = string | number | boolean | bigint | Date;
|
|
299
441
|
/**
|
|
@@ -316,7 +458,7 @@ type AsQuery<T> = T extends null | undefined ? T : T extends QueryPrimitive ? st
|
|
|
316
458
|
* // Invalid: {}, { a: undefined, b: undefined, c: undefined }
|
|
317
459
|
* ```
|
|
318
460
|
*/
|
|
319
|
-
type AtLeastOne<T, Keys extends keyof T = keyof T> = Keys extends keyof T ? Simplify
|
|
461
|
+
type AtLeastOne<T, Keys extends keyof T = keyof T> = Keys extends keyof T ? Simplify<Required<Pick<T, Keys>> & Partial<Omit<T, Keys>>> : never;
|
|
320
462
|
|
|
321
463
|
/**
|
|
322
464
|
* Wraps a partial Zod object schema with:
|
|
@@ -356,4 +498,4 @@ declare const asQuery: <T extends z.ZodTypeAny>(schema: T) => z.ZodPreprocess<T>
|
|
|
356
498
|
*/
|
|
357
499
|
declare const isPlainObject: (value: unknown) => value is Record<string, unknown>;
|
|
358
500
|
|
|
359
|
-
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, ZodJWTService, type ZodPaginationOptions, asQuery, createStringEnumRecord, failure, fetchAndThrow, fetchSafely, formatTime, generateRandomString, getColoredHTTPStatus, getFormattedDate, getFormattedTime, getUTCOffset, getZonedTime, honoLoggingHandler, isPlainObject, log, measureExecutionTime, onHandlerError, parseQueryValue, respond, safeExecute, sqlWhere, success, zodAtLeastOne, zodPaginationSchema, zodPaginationShape };
|
|
501
|
+
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, formatTime, generateRandomString, getColoredHTTPStatus, getFormattedDate, getFormattedTime, getUTCOffset, getZonedTime, honoLoggingHandler, isPlainObject, log, measureExecutionTime, onHandlerError, parseQueryValue, respond, safeExecute, sqlWhere, success, zodAtLeastOne, zodBulkSelectionSchema, zodPaginationSchema, zodPaginationShape, zodSearchSchema };
|
package/dist/index.js
CHANGED
|
@@ -164,6 +164,19 @@ async function measureExecutionTime(execution) {
|
|
|
164
164
|
return { result, executionTime: Math.round(executionTime) };
|
|
165
165
|
}
|
|
166
166
|
|
|
167
|
+
// src/zod-bulk/zod-bulk.schemas.ts
|
|
168
|
+
import z from "zod";
|
|
169
|
+
var DEFAULT_ERROR_MESSAGE = "Selection identifiers must be provided.";
|
|
170
|
+
var zodBulkSelectionSchema = ({ identifierSchema }) => {
|
|
171
|
+
const identifiersSchema = z.array(identifierSchema).refine((identifiers) => new Set(identifiers).size === identifiers.length, {
|
|
172
|
+
message: DEFAULT_ERROR_MESSAGE
|
|
173
|
+
});
|
|
174
|
+
return z.discriminatedUnion("mode", [
|
|
175
|
+
z.object({ mode: z.literal("include"), identifiers: identifiersSchema }).strict(),
|
|
176
|
+
z.object({ mode: z.literal("exclude"), excludedIdentifiers: identifiersSchema }).strict()
|
|
177
|
+
]);
|
|
178
|
+
};
|
|
179
|
+
|
|
167
180
|
// src/zod-jwt/zod-jwt.schemas.ts
|
|
168
181
|
import { decode as decodeJWT, sign as signJWT, verify as verifyJWT } from "hono/jwt";
|
|
169
182
|
var ZodJWTService = class {
|
|
@@ -213,26 +226,48 @@ var ZodJWTService = class {
|
|
|
213
226
|
}
|
|
214
227
|
};
|
|
215
228
|
|
|
216
|
-
// src/zod-
|
|
217
|
-
import
|
|
218
|
-
var zodPaginationSchema =
|
|
219
|
-
/**
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
229
|
+
// src/zod-search/zod-search.pagination.schemas.ts
|
|
230
|
+
import z2 from "zod";
|
|
231
|
+
var zodPaginationSchema = z2.object({
|
|
232
|
+
/**
|
|
233
|
+
* Zero-based number of records skipped before collecting a result page.
|
|
234
|
+
* String values are coerced to support validation of URL query input.
|
|
235
|
+
*/
|
|
236
|
+
offset: z2.coerce.number().int().nonnegative().default(0),
|
|
237
|
+
/**
|
|
238
|
+
* Positive maximum number of records returned in a single result page.
|
|
239
|
+
* String values are coerced to support validation of URL query input.
|
|
240
|
+
*/
|
|
241
|
+
limit: z2.coerce.number().int().positive().default(10)
|
|
223
242
|
});
|
|
224
243
|
var zodPaginationShape = zodPaginationSchema.shape;
|
|
225
244
|
|
|
245
|
+
// src/zod-search/zod-search.schemas.ts
|
|
246
|
+
import z3 from "zod";
|
|
247
|
+
|
|
226
248
|
// src/zod-validation/zod-validation.refiners.ts
|
|
227
|
-
var
|
|
249
|
+
var DEFAULT_ERROR_MESSAGE2 = "Invalid input. At least one field must be provided.";
|
|
228
250
|
var zodAtLeastOne = (schema) => schema.superRefine((val, ctx) => {
|
|
229
251
|
const hasValue = Object.values(val).some((v) => v !== void 0);
|
|
230
252
|
if (!hasValue)
|
|
231
|
-
ctx.addIssue({ code: "custom", message:
|
|
253
|
+
ctx.addIssue({ code: "custom", message: DEFAULT_ERROR_MESSAGE2 });
|
|
232
254
|
}).transform((val) => val);
|
|
233
255
|
|
|
256
|
+
// src/zod-search/zod-search.schemas.ts
|
|
257
|
+
var zodSearchQuerySchema = z3.string().trim().min(1).optional();
|
|
258
|
+
var createZodSearchWhereSchema = (filters) => zodAtLeastOne(filters.partial());
|
|
259
|
+
var zodSearchSchema = (options) => {
|
|
260
|
+
const whereSchema = options.filters !== void 0 ? createZodSearchWhereSchema(options.filters) : options.whereSchema;
|
|
261
|
+
const shape = {
|
|
262
|
+
where: whereSchema.optional(),
|
|
263
|
+
...options.queryEnabled !== false ? { query: zodSearchQuerySchema } : {},
|
|
264
|
+
...options.paginationEnabled !== false ? { pagination: zodPaginationSchema } : {}
|
|
265
|
+
};
|
|
266
|
+
return z3.object(shape).strict();
|
|
267
|
+
};
|
|
268
|
+
|
|
234
269
|
// src/zod-validation/zod-validation.parsing.ts
|
|
235
|
-
import
|
|
270
|
+
import z4 from "zod";
|
|
236
271
|
|
|
237
272
|
// src/zod-validation/zod-validation.utilities.ts
|
|
238
273
|
var isPlainObject = (value) => {
|
|
@@ -259,7 +294,7 @@ var parseQueryValue = (value) => {
|
|
|
259
294
|
return Number(normalized);
|
|
260
295
|
return value;
|
|
261
296
|
};
|
|
262
|
-
var asQuery = (schema) =>
|
|
297
|
+
var asQuery = (schema) => z4.preprocess(parseQueryValue, schema);
|
|
263
298
|
export {
|
|
264
299
|
EXCEPTION_STATUS_CODES,
|
|
265
300
|
SUCCESS_STATUS_CODES,
|
|
@@ -287,6 +322,8 @@ export {
|
|
|
287
322
|
sqlWhere,
|
|
288
323
|
success,
|
|
289
324
|
zodAtLeastOne,
|
|
325
|
+
zodBulkSelectionSchema,
|
|
290
326
|
zodPaginationSchema,
|
|
291
|
-
zodPaginationShape
|
|
327
|
+
zodPaginationShape,
|
|
328
|
+
zodSearchSchema
|
|
292
329
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kalutskii/foundation",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.24",
|
|
4
4
|
"description": "Typescript collection of most common utilities, schemas and functions among private projects.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
"build": "tsup",
|
|
15
15
|
"lint": "eslint . --ext .ts --fix",
|
|
16
16
|
"format": "prettier --write .",
|
|
17
|
+
"test": "bun test",
|
|
17
18
|
"typecheck": "tsc --noEmit"
|
|
18
19
|
},
|
|
19
20
|
"exports": {
|