@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/LICENSE +21 -0
- package/README.md +22 -16
- package/dist/index.d.ts +447 -123
- package/dist/index.js +210 -52
- package/package.json +5 -3
package/dist/index.js
CHANGED
|
@@ -40,50 +40,64 @@ import { blue, dim, green, red, white, yellow } from "kleur/colors";
|
|
|
40
40
|
import { format } from "date-fns";
|
|
41
41
|
import { getTimezoneOffset, toZonedTime } from "date-fns-tz";
|
|
42
42
|
import { ru } from "date-fns/locale";
|
|
43
|
-
|
|
43
|
+
function getZonedTime({ tz = "Europe/London" } = {}) {
|
|
44
44
|
return toZonedTime(/* @__PURE__ */ new Date(), tz);
|
|
45
|
-
}
|
|
46
|
-
|
|
45
|
+
}
|
|
46
|
+
function getUTCOffset(date, tz) {
|
|
47
47
|
const offset = getTimezoneOffset(tz, date) / (60 * 60 * 1e3);
|
|
48
48
|
return `(${offset >= 0 ? "+" : ""}${offset} UTC)`;
|
|
49
|
-
}
|
|
50
|
-
|
|
49
|
+
}
|
|
50
|
+
function getFormattedTime({ tz = "Europe/London" } = {}) {
|
|
51
51
|
const zonedTime = getZonedTime({ tz });
|
|
52
52
|
return `${format(zonedTime, "HH:mm:ss")} ${getUTCOffset(zonedTime, tz)}`;
|
|
53
|
-
}
|
|
54
|
-
|
|
53
|
+
}
|
|
54
|
+
function getFormattedDate({ tz = "Europe/London", withTime = true } = {}) {
|
|
55
55
|
const zonedTime = getZonedTime({ tz });
|
|
56
56
|
const pattern = withTime ? "dd.MM.yyyy HH:mm:ss" : "dd.MM.yyyy";
|
|
57
57
|
const formatted = format(zonedTime, pattern);
|
|
58
58
|
return `${formatted}${withTime ? ` ${getUTCOffset(zonedTime, tz)}` : ""}`;
|
|
59
|
-
}
|
|
60
|
-
|
|
59
|
+
}
|
|
60
|
+
function formatTime(time, { locale = ru, tz = "Europe/London" } = {}) {
|
|
61
61
|
const zonedTime = toZonedTime(time, tz);
|
|
62
62
|
return `${format(zonedTime, "HH:mm:ss, d MMMM yyyy", { locale })} ${getUTCOffset(zonedTime, tz)}`;
|
|
63
|
-
}
|
|
63
|
+
}
|
|
64
64
|
|
|
65
65
|
// src/utilities/logging.utilities.ts
|
|
66
|
+
var HTTP_STATUS_COLORS = [
|
|
67
|
+
{ range: [200, 299], color: green },
|
|
68
|
+
{ range: [400, 499], color: yellow },
|
|
69
|
+
{ range: [500, 599], color: red }
|
|
70
|
+
];
|
|
71
|
+
var LOG_LEVEL_COLORS = { info: blue, warn: yellow, error: red };
|
|
66
72
|
function getColoredHTTPStatus(status) {
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
];
|
|
72
|
-
const statusColor = colorMap.find(({ range: [min, max] }) => status >= min && status <= max);
|
|
73
|
-
return statusColor ? statusColor.colorFn : (text) => text;
|
|
73
|
+
const statusColor = HTTP_STATUS_COLORS.find(({ range: [minimum, maximum] }) => {
|
|
74
|
+
return status >= minimum && status <= maximum;
|
|
75
|
+
});
|
|
76
|
+
return statusColor ? statusColor.color : (text) => text;
|
|
74
77
|
}
|
|
75
78
|
function writeLog(message, level, service = "log", stack) {
|
|
76
|
-
const logColorMap = { info: blue, warn: yellow, error: red };
|
|
77
79
|
const timestamp = dim(getFormattedTime());
|
|
78
|
-
const serviceName =
|
|
80
|
+
const serviceName = LOG_LEVEL_COLORS[level](service.padEnd(12));
|
|
79
81
|
const formattedMessage = white(message);
|
|
80
82
|
console.log(`[${timestamp}] ${serviceName} | ${formattedMessage}`);
|
|
81
83
|
if (stack)
|
|
82
84
|
console.log(`[${timestamp}] ${red("\u21B3 trace").padEnd(18)} | ${dim(stack)}`);
|
|
83
85
|
}
|
|
84
86
|
var log = {
|
|
87
|
+
/**
|
|
88
|
+
* Writes an informational message with an optional service label.
|
|
89
|
+
* Missing service names use the shared `log` fallback label.
|
|
90
|
+
*/
|
|
85
91
|
info: (message, service) => writeLog(message, "info", service),
|
|
92
|
+
/**
|
|
93
|
+
* Writes a warning message with an optional service label.
|
|
94
|
+
* Missing service names use the shared `log` fallback label.
|
|
95
|
+
*/
|
|
86
96
|
warn: (message, service) => writeLog(message, "warn", service),
|
|
97
|
+
/**
|
|
98
|
+
* Writes an error message with optional service and stack trace context.
|
|
99
|
+
* Stack traces are rendered beneath the primary error message when supplied.
|
|
100
|
+
*/
|
|
87
101
|
error: (message, service, stack) => writeLog(message, "error", service, stack)
|
|
88
102
|
};
|
|
89
103
|
|
|
@@ -123,7 +137,7 @@ var honoLoggingHandler = async (c, next) => {
|
|
|
123
137
|
const coloredMethod = bold(blue2(c.req.method.padEnd(4)));
|
|
124
138
|
const coloredStatus = getColoredHTTPStatus(c.res.status)(String(c.res.status).padEnd(4));
|
|
125
139
|
const coloredTime = dim2(`${duration}ms`.padStart(6));
|
|
126
|
-
const coloredPath = white2(c.req.path.padEnd(
|
|
140
|
+
const coloredPath = white2(c.req.path.padEnd(32));
|
|
127
141
|
const coloredSearchParams = searchParams ? dim2(` (${searchParams})`) : "";
|
|
128
142
|
const coloredBody = bodyPreview ? dim2(` ${bodyPreview}`) : "";
|
|
129
143
|
log.info(`${coloredMethod} ${coloredStatus} ${coloredTime} ${coloredPath}${coloredSearchParams}${coloredBody}`, "hono");
|
|
@@ -162,14 +176,131 @@ function createStringEnumRecord(values) {
|
|
|
162
176
|
return Object.freeze(Object.fromEntries(values.map((value) => [value.replace(/\./g, "_").toUpperCase(), value])));
|
|
163
177
|
}
|
|
164
178
|
|
|
179
|
+
// src/upload/upload.enums.ts
|
|
180
|
+
var fileFormatsArray = [
|
|
181
|
+
...["png", "jpg", "webp", "avif", "heic"],
|
|
182
|
+
// Image formats.
|
|
183
|
+
...["pdf", "rtf", "txt"]
|
|
184
|
+
// Text and document formats.
|
|
185
|
+
];
|
|
186
|
+
var fileFormatsRecord = createStringEnumRecord(fileFormatsArray);
|
|
187
|
+
var fileFormat = fileFormatsRecord;
|
|
188
|
+
var uploadValidationErrorsArray = [
|
|
189
|
+
"empty_file",
|
|
190
|
+
"unsupported_file_format",
|
|
191
|
+
"file_size_exceeded",
|
|
192
|
+
"files_count_exceeded"
|
|
193
|
+
];
|
|
194
|
+
var uploadValidationErrorsRecord = createStringEnumRecord(uploadValidationErrorsArray);
|
|
195
|
+
var uploadValidationError = uploadValidationErrorsRecord;
|
|
196
|
+
|
|
197
|
+
// src/upload/upload.constants.ts
|
|
198
|
+
var fileFormatsConfig = {
|
|
199
|
+
// Image formats.
|
|
200
|
+
[fileFormatsRecord.PNG]: { name: "PNG", mimeTypes: ["image/png"], extensions: [".png"] },
|
|
201
|
+
[fileFormatsRecord.JPG]: { name: "JPG", mimeTypes: ["image/jpeg"], extensions: [".jpg", ".jpeg"] },
|
|
202
|
+
[fileFormatsRecord.WEBP]: { name: "WEBP", mimeTypes: ["image/webp"], extensions: [".webp"] },
|
|
203
|
+
[fileFormatsRecord.AVIF]: { name: "AVIF", mimeTypes: ["image/avif"], extensions: [".avif"] },
|
|
204
|
+
[fileFormatsRecord.HEIC]: { name: "HEIC", mimeTypes: ["image/heic", "image/heif"], extensions: [".heic", ".heif"] },
|
|
205
|
+
// Text and document formats.
|
|
206
|
+
[fileFormatsRecord.PDF]: { name: "PDF", mimeTypes: ["application/pdf"], extensions: [".pdf"] },
|
|
207
|
+
[fileFormatsRecord.RTF]: { name: "RTF", mimeTypes: ["application/rtf"], extensions: [".rtf"] },
|
|
208
|
+
[fileFormatsRecord.TXT]: { name: "TXT", mimeTypes: ["text/plain"], extensions: [".txt"] }
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
// src/upload/upload.factory.ts
|
|
212
|
+
function defineUploadPreset(preset) {
|
|
213
|
+
return preset;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// src/upload/upload.presets.ts
|
|
217
|
+
var DEFAULT_UPLOAD_MAX_FILE_SIZE = 20 * 1024 * 1024;
|
|
218
|
+
var imageUploadPreset = defineUploadPreset({
|
|
219
|
+
formats: [fileFormat.PNG, fileFormat.JPG, fileFormat.WEBP, fileFormat.AVIF, fileFormat.HEIC],
|
|
220
|
+
maxFileSize: DEFAULT_UPLOAD_MAX_FILE_SIZE
|
|
221
|
+
});
|
|
222
|
+
var documentUploadPreset = defineUploadPreset({
|
|
223
|
+
formats: [fileFormat.PDF, fileFormat.RTF, fileFormat.TXT],
|
|
224
|
+
maxFileSize: DEFAULT_UPLOAD_MAX_FILE_SIZE
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
// src/upload/upload.schemas.ts
|
|
228
|
+
import { z } from "zod";
|
|
229
|
+
|
|
230
|
+
// src/upload/upload.utilities.ts
|
|
231
|
+
function getFileExtension(fileName) {
|
|
232
|
+
const extensionIndex = fileName.lastIndexOf(".");
|
|
233
|
+
return extensionIndex > 0 && extensionIndex < fileName.length - 1 ? fileName.slice(extensionIndex).toLowerCase() : "";
|
|
234
|
+
}
|
|
235
|
+
function normalizeFileExtension(extension) {
|
|
236
|
+
const normalizedExtension = extension.toLowerCase();
|
|
237
|
+
return normalizedExtension.startsWith(".") ? normalizedExtension : `.${normalizedExtension}`;
|
|
238
|
+
}
|
|
239
|
+
function matchesMimeType(fileMimeType, configuredMimeType) {
|
|
240
|
+
if (configuredMimeType.endsWith("/*"))
|
|
241
|
+
return fileMimeType.startsWith(configuredMimeType.slice(0, -1));
|
|
242
|
+
return fileMimeType === configuredMimeType;
|
|
243
|
+
}
|
|
244
|
+
function isFileMimeTypeSupported(file, formats) {
|
|
245
|
+
return formats.some((format2) => fileFormatsConfig[format2].mimeTypes.some((mimeType) => matchesMimeType(file.type, mimeType)));
|
|
246
|
+
}
|
|
247
|
+
function isFileExtensionSupported(file, formats) {
|
|
248
|
+
const fileExtension = getFileExtension(file.name);
|
|
249
|
+
return formats.some((format2) => fileFormatsConfig[format2].extensions.some((extension) => normalizeFileExtension(extension) === fileExtension));
|
|
250
|
+
}
|
|
251
|
+
function isFileFormatSupported(file, formats) {
|
|
252
|
+
return isFileMimeTypeSupported(file, formats) || isFileExtensionSupported(file, formats);
|
|
253
|
+
}
|
|
254
|
+
function createUploadAccept(formats) {
|
|
255
|
+
const acceptedValues = formats.flatMap((format2) => [
|
|
256
|
+
...fileFormatsConfig[format2].mimeTypes,
|
|
257
|
+
...fileFormatsConfig[format2].extensions
|
|
258
|
+
]);
|
|
259
|
+
return [...new Set(acceptedValues)].join(",");
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// src/upload/upload.schemas.ts
|
|
263
|
+
function zodUploadFileSchema(options) {
|
|
264
|
+
const { formats, maxFileSize, extensionFallback = false } = options;
|
|
265
|
+
return z.file().min(1, uploadValidationError.EMPTY_FILE).max(maxFileSize, uploadValidationError.FILE_SIZE_EXCEEDED).refine((file) => extensionFallback ? isFileFormatSupported(file, formats) : isFileMimeTypeSupported(file, formats), uploadValidationError.UNSUPPORTED_FILE_FORMAT);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// src/upload/upload.validation.ts
|
|
269
|
+
function validateUploadFile(file, formats, maxFileSize) {
|
|
270
|
+
if (file.size === 0)
|
|
271
|
+
return uploadValidationError.EMPTY_FILE;
|
|
272
|
+
if (isFileFormatSupported(file, formats) === false)
|
|
273
|
+
return uploadValidationError.UNSUPPORTED_FILE_FORMAT;
|
|
274
|
+
if (file.size > maxFileSize)
|
|
275
|
+
return uploadValidationError.FILE_SIZE_EXCEEDED;
|
|
276
|
+
return void 0;
|
|
277
|
+
}
|
|
278
|
+
function validateUploadFiles(incomingFiles, options) {
|
|
279
|
+
const { currentFilesCount, formats, maxFileSize, maxFilesCount } = options;
|
|
280
|
+
const availableFilesCount = maxFilesCount === void 0 ? Infinity : maxFilesCount - currentFilesCount;
|
|
281
|
+
const acceptedFiles = [];
|
|
282
|
+
let validationError;
|
|
283
|
+
for (const file of incomingFiles) {
|
|
284
|
+
const fileValidationError = validateUploadFile(file, formats, maxFileSize) ?? // Collection limits apply only after intrinsic file validation succeeds.
|
|
285
|
+
// This preserves remaining slots for supported files from the same batch.
|
|
286
|
+
(acceptedFiles.length >= availableFilesCount ? uploadValidationError.FILES_COUNT_EXCEEDED : void 0);
|
|
287
|
+
if (fileValidationError) {
|
|
288
|
+
validationError = fileValidationError;
|
|
289
|
+
continue;
|
|
290
|
+
}
|
|
291
|
+
acceptedFiles.push(file);
|
|
292
|
+
}
|
|
293
|
+
return { acceptedFiles, validationError };
|
|
294
|
+
}
|
|
295
|
+
|
|
165
296
|
// src/utilities/execution.utilities.ts
|
|
166
297
|
async function safeExecute(fn, onError) {
|
|
167
298
|
try {
|
|
168
299
|
return await fn();
|
|
169
|
-
} catch (
|
|
300
|
+
} catch (error) {
|
|
170
301
|
if (onError)
|
|
171
|
-
return await onError(
|
|
172
|
-
throw
|
|
302
|
+
return await onError(error);
|
|
303
|
+
throw error;
|
|
173
304
|
}
|
|
174
305
|
}
|
|
175
306
|
async function measureExecutionTime(execution) {
|
|
@@ -180,19 +311,19 @@ async function measureExecutionTime(execution) {
|
|
|
180
311
|
}
|
|
181
312
|
|
|
182
313
|
// src/zod-bulk/zod-bulk.schemas.ts
|
|
183
|
-
import { z } from "zod";
|
|
314
|
+
import { z as z2 } from "zod";
|
|
184
315
|
var DEFAULT_ERROR_MESSAGE = "Selection identifiers must be provided.";
|
|
185
|
-
|
|
186
|
-
const identifiersSchema =
|
|
316
|
+
function zodBulkSelectionSchema({ identifierSchema }) {
|
|
317
|
+
const identifiersSchema = z2.array(identifierSchema).refine((identifiers) => new Set(identifiers).size === identifiers.length, {
|
|
187
318
|
message: DEFAULT_ERROR_MESSAGE
|
|
188
319
|
});
|
|
189
|
-
return
|
|
190
|
-
|
|
191
|
-
|
|
320
|
+
return z2.discriminatedUnion("mode", [
|
|
321
|
+
z2.object({ mode: z2.literal("include"), identifiers: identifiersSchema }).strict(),
|
|
322
|
+
z2.object({ mode: z2.literal("exclude"), excludedIdentifiers: identifiersSchema }).strict()
|
|
192
323
|
]);
|
|
193
|
-
}
|
|
324
|
+
}
|
|
194
325
|
|
|
195
|
-
// src/zod-jwt/zod-jwt.
|
|
326
|
+
// src/zod-jwt/zod-jwt.services.ts
|
|
196
327
|
import { decode as decodeJWT, sign as signJWT, verify as verifyJWT } from "hono/jwt";
|
|
197
328
|
var ZodJWTService = class {
|
|
198
329
|
payloadSchema;
|
|
@@ -204,37 +335,41 @@ var ZodJWTService = class {
|
|
|
204
335
|
this.defaultExpirationSeconds = options?.defaultExpirationSeconds ?? 60 * 15;
|
|
205
336
|
}
|
|
206
337
|
/**
|
|
207
|
-
* Signs a
|
|
208
|
-
*
|
|
338
|
+
* Signs a payload using the configured algorithm and expiration settings.
|
|
339
|
+
* Per-call expiration overrides the default configured by the service.
|
|
340
|
+
*
|
|
341
|
+
* @example
|
|
342
|
+
* const token = await jwtService.sign({ userId: '123' }, secret, { expiresInSeconds: 300 });
|
|
209
343
|
*/
|
|
210
344
|
async sign(payload, secret, options) {
|
|
211
345
|
const exp = Math.floor(Date.now() / 1e3) + (options?.expiresInSeconds ?? this.defaultExpirationSeconds);
|
|
212
346
|
return signJWT({ ...payload, exp }, secret, this.algorithm);
|
|
213
347
|
}
|
|
214
348
|
/**
|
|
215
|
-
* Decodes
|
|
216
|
-
*
|
|
349
|
+
* Decodes without authenticating it and parses its payload when a schema exists.
|
|
350
|
+
* Schema validation failures return `null`, while malformed tokens still reject.
|
|
217
351
|
*
|
|
218
|
-
*
|
|
352
|
+
* @example
|
|
353
|
+
* const payload = await jwtService.decode(token);
|
|
219
354
|
*/
|
|
220
355
|
async decode(token) {
|
|
221
356
|
const { payload } = decodeJWT(token);
|
|
222
|
-
if (
|
|
357
|
+
if (this.payloadSchema === void 0) {
|
|
223
358
|
return payload;
|
|
224
359
|
}
|
|
225
360
|
const { success: success2, data } = await this.payloadSchema.safeParseAsync(payload);
|
|
226
361
|
return success2 ? data : null;
|
|
227
362
|
}
|
|
228
363
|
/**
|
|
229
|
-
* Verifies
|
|
230
|
-
*
|
|
364
|
+
* Verifies a token using the configured algorithm and parses its payload.
|
|
365
|
+
* Signature, expiration, and schema validation failures reject the operation.
|
|
231
366
|
*
|
|
232
|
-
*
|
|
233
|
-
*
|
|
367
|
+
* @example
|
|
368
|
+
* const payload = await jwtService.verifyOrThrow(token, secret);
|
|
234
369
|
*/
|
|
235
370
|
async verifyOrThrow(token, secret) {
|
|
236
371
|
const payload = await verifyJWT(token, secret, this.algorithm);
|
|
237
|
-
if (
|
|
372
|
+
if (this.payloadSchema === void 0) {
|
|
238
373
|
return payload;
|
|
239
374
|
}
|
|
240
375
|
return this.payloadSchema.parseAsync(payload);
|
|
@@ -242,23 +377,23 @@ var ZodJWTService = class {
|
|
|
242
377
|
};
|
|
243
378
|
|
|
244
379
|
// src/zod-search/zod-search.pagination.schemas.ts
|
|
245
|
-
import { z as
|
|
246
|
-
var zodPaginationSchema =
|
|
380
|
+
import { z as z3 } from "zod";
|
|
381
|
+
var zodPaginationSchema = z3.object({
|
|
247
382
|
/**
|
|
248
383
|
* Zero-based number of records skipped before collecting a result page.
|
|
249
384
|
* String values are coerced to support validation of URL query input.
|
|
250
385
|
*/
|
|
251
|
-
offset:
|
|
386
|
+
offset: z3.coerce.number().int().nonnegative().default(0),
|
|
252
387
|
/**
|
|
253
388
|
* Positive maximum number of records returned in a single result page.
|
|
254
389
|
* String values are coerced to support validation of URL query input.
|
|
255
390
|
*/
|
|
256
|
-
limit:
|
|
391
|
+
limit: z3.coerce.number().int().positive().default(10)
|
|
257
392
|
});
|
|
258
393
|
var zodPaginationShape = zodPaginationSchema.shape;
|
|
259
394
|
|
|
260
395
|
// src/zod-search/zod-search.schemas.ts
|
|
261
|
-
import { z as
|
|
396
|
+
import { z as z4 } from "zod";
|
|
262
397
|
|
|
263
398
|
// src/zod-validation/zod-validation.refiners.ts
|
|
264
399
|
var DEFAULT_ERROR_MESSAGE2 = "Invalid input. At least one field must be provided.";
|
|
@@ -269,7 +404,7 @@ var zodAtLeastOne = (schema) => schema.superRefine((val, ctx) => {
|
|
|
269
404
|
}).transform((val) => val);
|
|
270
405
|
|
|
271
406
|
// src/zod-search/zod-search.schemas.ts
|
|
272
|
-
var zodSearchQuerySchema =
|
|
407
|
+
var zodSearchQuerySchema = z4.string().trim().min(1).optional();
|
|
273
408
|
var createZodSearchWhereSchema = (filters) => zodAtLeastOne(filters.partial());
|
|
274
409
|
var zodSearchSchema = (options) => {
|
|
275
410
|
const whereSchema = options.filters !== void 0 ? createZodSearchWhereSchema(options.filters) : options.whereSchema;
|
|
@@ -278,11 +413,11 @@ var zodSearchSchema = (options) => {
|
|
|
278
413
|
...options.queryEnabled !== false ? { query: zodSearchQuerySchema } : {},
|
|
279
414
|
...options.paginationEnabled !== false ? { pagination: zodPaginationSchema } : {}
|
|
280
415
|
};
|
|
281
|
-
return
|
|
416
|
+
return z4.object(shape).strict();
|
|
282
417
|
};
|
|
283
418
|
|
|
284
419
|
// src/zod-validation/zod-validation.parsing.ts
|
|
285
|
-
import { z as
|
|
420
|
+
import { z as z5 } from "zod";
|
|
286
421
|
|
|
287
422
|
// src/zod-validation/zod-validation.utilities.ts
|
|
288
423
|
var isPlainObject = (value) => {
|
|
@@ -309,37 +444,60 @@ var parseQueryValue = (value) => {
|
|
|
309
444
|
return Number(normalized);
|
|
310
445
|
return value;
|
|
311
446
|
};
|
|
312
|
-
var asQuery = (schema) =>
|
|
447
|
+
var asQuery = (schema) => z5.preprocess(parseQueryValue, schema);
|
|
313
448
|
export {
|
|
449
|
+
DEFAULT_UPLOAD_MAX_FILE_SIZE,
|
|
314
450
|
EXCEPTION_STATUS_CODES,
|
|
315
451
|
SUCCESS_STATUS_CODES,
|
|
316
452
|
ZodJWTService,
|
|
317
453
|
asQuery,
|
|
318
454
|
createStringEnumRecord,
|
|
455
|
+
createUploadAccept,
|
|
456
|
+
createZodSearchWhereSchema,
|
|
457
|
+
defineUploadPreset,
|
|
458
|
+
documentUploadPreset,
|
|
319
459
|
failure,
|
|
320
460
|
fetchAndThrow,
|
|
321
461
|
fetchSafely,
|
|
462
|
+
fileFormat,
|
|
463
|
+
fileFormatsArray,
|
|
464
|
+
fileFormatsConfig,
|
|
465
|
+
fileFormatsRecord,
|
|
322
466
|
fileRespond,
|
|
323
467
|
formatTime,
|
|
324
468
|
generateRandomString,
|
|
325
469
|
getColoredHTTPStatus,
|
|
470
|
+
getFileExtension,
|
|
326
471
|
getFormattedDate,
|
|
327
472
|
getFormattedTime,
|
|
328
473
|
getUTCOffset,
|
|
329
474
|
getZonedTime,
|
|
330
475
|
honoLoggingHandler,
|
|
476
|
+
imageUploadPreset,
|
|
477
|
+
isFileExtensionSupported,
|
|
478
|
+
isFileFormatSupported,
|
|
479
|
+
isFileMimeTypeSupported,
|
|
331
480
|
isPlainObject,
|
|
332
481
|
log,
|
|
482
|
+
matchesMimeType,
|
|
333
483
|
measureExecutionTime,
|
|
484
|
+
normalizeFileExtension,
|
|
334
485
|
onHandlerError,
|
|
335
486
|
parseQueryValue,
|
|
336
487
|
respond,
|
|
337
488
|
safeExecute,
|
|
338
489
|
sqlWhere,
|
|
339
490
|
success,
|
|
491
|
+
uploadValidationError,
|
|
492
|
+
uploadValidationErrorsArray,
|
|
493
|
+
uploadValidationErrorsRecord,
|
|
494
|
+
validateUploadFile,
|
|
495
|
+
validateUploadFiles,
|
|
340
496
|
zodAtLeastOne,
|
|
341
497
|
zodBulkSelectionSchema,
|
|
342
498
|
zodPaginationSchema,
|
|
343
499
|
zodPaginationShape,
|
|
344
|
-
|
|
500
|
+
zodSearchQuerySchema,
|
|
501
|
+
zodSearchSchema,
|
|
502
|
+
zodUploadFileSchema
|
|
345
503
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kalutskii/foundation",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.10",
|
|
4
4
|
"description": "Typescript collection of most common utilities, schemas and functions among private projects.",
|
|
5
|
+
"license": "MIT",
|
|
5
6
|
"type": "module",
|
|
6
7
|
"repository": {
|
|
7
8
|
"type": "git",
|
|
@@ -12,10 +13,12 @@
|
|
|
12
13
|
},
|
|
13
14
|
"scripts": {
|
|
14
15
|
"build": "tsup",
|
|
16
|
+
"test": "bun test",
|
|
15
17
|
"typecheck": "tsc --noEmit",
|
|
16
18
|
"lint": "eslint . --ext .ts --fix",
|
|
19
|
+
"lint:check": "eslint . --ext .ts",
|
|
17
20
|
"format": "prettier --write .",
|
|
18
|
-
"
|
|
21
|
+
"format:check": "prettier --check ."
|
|
19
22
|
},
|
|
20
23
|
"exports": {
|
|
21
24
|
".": {
|
|
@@ -27,7 +30,6 @@
|
|
|
27
30
|
"dist"
|
|
28
31
|
],
|
|
29
32
|
"peerDependencies": {
|
|
30
|
-
"@hono/zod-validator": "^0.8.0",
|
|
31
33
|
"date-fns": "^4.1.0",
|
|
32
34
|
"date-fns-tz": "^3.2.0",
|
|
33
35
|
"drizzle-orm": "^1.0.0-beta.22",
|