@superdangerous/app-framework 4.9.2 → 4.15.0
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 +8 -2
- package/dist/api/logsRouter.d.ts +4 -1
- package/dist/api/logsRouter.d.ts.map +1 -1
- package/dist/api/logsRouter.js +100 -118
- package/dist/api/logsRouter.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/middleware/validation.d.ts +48 -43
- package/dist/middleware/validation.d.ts.map +1 -1
- package/dist/middleware/validation.js +48 -43
- package/dist/middleware/validation.js.map +1 -1
- package/dist/services/emailService.d.ts +146 -0
- package/dist/services/emailService.d.ts.map +1 -0
- package/dist/services/emailService.js +649 -0
- package/dist/services/emailService.js.map +1 -0
- package/dist/services/index.d.ts +2 -0
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/index.js +2 -0
- package/dist/services/index.js.map +1 -1
- package/dist/services/websocketServer.d.ts +7 -4
- package/dist/services/websocketServer.d.ts.map +1 -1
- package/dist/services/websocketServer.js +22 -16
- package/dist/services/websocketServer.js.map +1 -1
- package/dist/types/index.d.ts +7 -8
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +11 -2
- package/src/api/logsRouter.ts +119 -138
- package/src/index.ts +14 -0
- package/src/middleware/validation.ts +82 -90
- package/src/services/emailService.ts +812 -0
- package/src/services/index.ts +14 -0
- package/src/services/websocketServer.ts +37 -23
- package/src/types/index.ts +7 -8
- package/ui/data-table/components/BatchActionsBar.tsx +53 -0
- package/ui/data-table/components/ColumnVisibility.tsx +111 -0
- package/ui/data-table/components/DataTablePage.tsx +238 -0
- package/ui/data-table/components/Pagination.tsx +203 -0
- package/ui/data-table/components/PaginationControls.tsx +122 -0
- package/ui/data-table/components/TableFilters.tsx +139 -0
- package/ui/data-table/components/index.ts +27 -0
- package/ui/data-table/hooks/index.ts +17 -0
- package/ui/data-table/hooks/useColumnOrder.ts +233 -0
- package/ui/data-table/hooks/useColumnVisibility.ts +128 -0
- package/ui/data-table/hooks/usePagination.ts +160 -0
- package/ui/data-table/hooks/useResizableColumns.ts +280 -0
- package/ui/data-table/index.ts +74 -0
- package/ui/dist/index.d.mts +207 -5
- package/ui/dist/index.d.ts +207 -5
- package/ui/dist/index.js +36 -43
- package/ui/dist/index.js.map +1 -1
- package/ui/dist/index.mjs +36 -43
- package/ui/dist/index.mjs.map +1 -1
|
@@ -19,12 +19,10 @@ import { ApiResponse, FieldValidationError } from "../types/index.js";
|
|
|
19
19
|
* Validation options for middleware
|
|
20
20
|
*/
|
|
21
21
|
export interface ValidationOptions {
|
|
22
|
+
/** Whether to stop on first error (not used with Zod) */
|
|
22
23
|
abortEarly?: boolean;
|
|
24
|
+
/** Whether to strip unknown properties from validated data */
|
|
23
25
|
stripUnknown?: boolean;
|
|
24
|
-
convert?: boolean;
|
|
25
|
-
presence?: "optional" | "required" | "forbidden";
|
|
26
|
-
context?: Record<string, any>;
|
|
27
|
-
allowUnknown?: boolean;
|
|
28
26
|
}
|
|
29
27
|
|
|
30
28
|
/**
|
|
@@ -33,8 +31,6 @@ export interface ValidationOptions {
|
|
|
33
31
|
const defaultOptions: ValidationOptions = {
|
|
34
32
|
abortEarly: false,
|
|
35
33
|
stripUnknown: true,
|
|
36
|
-
convert: true,
|
|
37
|
-
allowUnknown: false,
|
|
38
34
|
};
|
|
39
35
|
|
|
40
36
|
/**
|
|
@@ -279,11 +275,7 @@ export function validate<T extends ZodSchema>(
|
|
|
279
275
|
) {
|
|
280
276
|
const opts = { ...defaultOptions, ...options };
|
|
281
277
|
|
|
282
|
-
return (
|
|
283
|
-
req: Request,
|
|
284
|
-
res: Response<ApiResponse<any>>,
|
|
285
|
-
next: NextFunction,
|
|
286
|
-
): any => {
|
|
278
|
+
return (req: Request, res: Response, next: NextFunction): void => {
|
|
287
279
|
try {
|
|
288
280
|
const value = schema.parse(req.body);
|
|
289
281
|
|
|
@@ -292,20 +284,21 @@ export function validate<T extends ZodSchema>(
|
|
|
292
284
|
req.body = value;
|
|
293
285
|
}
|
|
294
286
|
next();
|
|
295
|
-
} catch (
|
|
296
|
-
if (
|
|
297
|
-
const errors = formatValidationErrors(
|
|
287
|
+
} catch (error) {
|
|
288
|
+
if (error instanceof ZodError) {
|
|
289
|
+
const errors = formatValidationErrors(error);
|
|
298
290
|
const message = createErrorMessage(errors, "Invalid request");
|
|
299
291
|
|
|
300
|
-
|
|
292
|
+
res.status(400).json({
|
|
301
293
|
success: false,
|
|
302
294
|
error: "Validation failed",
|
|
303
295
|
message,
|
|
304
296
|
errors,
|
|
305
297
|
timestamp: new Date().toISOString(),
|
|
306
|
-
});
|
|
298
|
+
} satisfies ApiResponse<never>);
|
|
299
|
+
return;
|
|
307
300
|
}
|
|
308
|
-
next(
|
|
301
|
+
next(error);
|
|
309
302
|
}
|
|
310
303
|
};
|
|
311
304
|
}
|
|
@@ -319,11 +312,7 @@ export function validateParams<T extends ZodSchema>(
|
|
|
319
312
|
) {
|
|
320
313
|
const opts = { ...defaultOptions, ...options };
|
|
321
314
|
|
|
322
|
-
return (
|
|
323
|
-
req: Request,
|
|
324
|
-
res: Response<ApiResponse<any>>,
|
|
325
|
-
next: NextFunction,
|
|
326
|
-
): any => {
|
|
315
|
+
return (req: Request, res: Response, next: NextFunction): void => {
|
|
327
316
|
try {
|
|
328
317
|
const value = schema.parse(req.params);
|
|
329
318
|
|
|
@@ -331,20 +320,21 @@ export function validateParams<T extends ZodSchema>(
|
|
|
331
320
|
req.params = value;
|
|
332
321
|
}
|
|
333
322
|
next();
|
|
334
|
-
} catch (
|
|
335
|
-
if (
|
|
336
|
-
const errors = formatValidationErrors(
|
|
323
|
+
} catch (error) {
|
|
324
|
+
if (error instanceof ZodError) {
|
|
325
|
+
const errors = formatValidationErrors(error);
|
|
337
326
|
const message = createErrorMessage(errors, "Invalid parameters");
|
|
338
327
|
|
|
339
|
-
|
|
328
|
+
res.status(400).json({
|
|
340
329
|
success: false,
|
|
341
330
|
error: "Invalid parameters",
|
|
342
331
|
message,
|
|
343
332
|
errors,
|
|
344
333
|
timestamp: new Date().toISOString(),
|
|
345
|
-
});
|
|
334
|
+
} satisfies ApiResponse<never>);
|
|
335
|
+
return;
|
|
346
336
|
}
|
|
347
|
-
next(
|
|
337
|
+
next(error);
|
|
348
338
|
}
|
|
349
339
|
};
|
|
350
340
|
}
|
|
@@ -358,11 +348,7 @@ export function validateQuery<T extends ZodSchema>(
|
|
|
358
348
|
) {
|
|
359
349
|
const opts = { ...defaultOptions, ...options };
|
|
360
350
|
|
|
361
|
-
return (
|
|
362
|
-
req: Request,
|
|
363
|
-
res: Response<ApiResponse<any>>,
|
|
364
|
-
next: NextFunction,
|
|
365
|
-
): any => {
|
|
351
|
+
return (req: Request, res: Response, next: NextFunction): void => {
|
|
366
352
|
try {
|
|
367
353
|
const value = schema.parse(req.query);
|
|
368
354
|
|
|
@@ -370,20 +356,21 @@ export function validateQuery<T extends ZodSchema>(
|
|
|
370
356
|
req.query = value;
|
|
371
357
|
}
|
|
372
358
|
next();
|
|
373
|
-
} catch (
|
|
374
|
-
if (
|
|
375
|
-
const errors = formatValidationErrors(
|
|
359
|
+
} catch (error) {
|
|
360
|
+
if (error instanceof ZodError) {
|
|
361
|
+
const errors = formatValidationErrors(error);
|
|
376
362
|
const message = createErrorMessage(errors, "Invalid query");
|
|
377
363
|
|
|
378
|
-
|
|
364
|
+
res.status(400).json({
|
|
379
365
|
success: false,
|
|
380
366
|
error: "Invalid query parameters",
|
|
381
367
|
message,
|
|
382
368
|
errors,
|
|
383
369
|
timestamp: new Date().toISOString(),
|
|
384
|
-
});
|
|
370
|
+
} satisfies ApiResponse<never>);
|
|
371
|
+
return;
|
|
385
372
|
}
|
|
386
|
-
next(
|
|
373
|
+
next(error);
|
|
387
374
|
}
|
|
388
375
|
};
|
|
389
376
|
}
|
|
@@ -397,54 +384,50 @@ export function validateRequest<
|
|
|
397
384
|
params?: ZodSchema;
|
|
398
385
|
query?: ZodSchema;
|
|
399
386
|
},
|
|
400
|
-
>(
|
|
387
|
+
>(validationSchemas: T, options?: ValidationOptions) {
|
|
401
388
|
const opts = { ...defaultOptions, ...options };
|
|
402
389
|
|
|
403
|
-
return (
|
|
404
|
-
req: Request,
|
|
405
|
-
res: Response<ApiResponse<any>>,
|
|
406
|
-
next: NextFunction,
|
|
407
|
-
): any => {
|
|
390
|
+
return (req: Request, res: Response, next: NextFunction): void => {
|
|
408
391
|
const errors: FieldValidationError[] = [];
|
|
409
392
|
|
|
410
393
|
// Validate body
|
|
411
|
-
if (
|
|
394
|
+
if (validationSchemas.body) {
|
|
412
395
|
try {
|
|
413
|
-
const value =
|
|
396
|
+
const value = validationSchemas.body.parse(req.body);
|
|
414
397
|
if (opts.stripUnknown) {
|
|
415
398
|
req.body = value;
|
|
416
399
|
}
|
|
417
|
-
} catch (
|
|
418
|
-
if (
|
|
419
|
-
errors.push(...formatValidationErrors(
|
|
400
|
+
} catch (error) {
|
|
401
|
+
if (error instanceof ZodError) {
|
|
402
|
+
errors.push(...formatValidationErrors(error));
|
|
420
403
|
}
|
|
421
404
|
}
|
|
422
405
|
}
|
|
423
406
|
|
|
424
407
|
// Validate params
|
|
425
|
-
if (
|
|
408
|
+
if (validationSchemas.params) {
|
|
426
409
|
try {
|
|
427
|
-
const value =
|
|
410
|
+
const value = validationSchemas.params.parse(req.params);
|
|
428
411
|
if (opts.stripUnknown) {
|
|
429
412
|
req.params = value;
|
|
430
413
|
}
|
|
431
|
-
} catch (
|
|
432
|
-
if (
|
|
433
|
-
errors.push(...formatValidationErrors(
|
|
414
|
+
} catch (error) {
|
|
415
|
+
if (error instanceof ZodError) {
|
|
416
|
+
errors.push(...formatValidationErrors(error));
|
|
434
417
|
}
|
|
435
418
|
}
|
|
436
419
|
}
|
|
437
420
|
|
|
438
421
|
// Validate query
|
|
439
|
-
if (
|
|
422
|
+
if (validationSchemas.query) {
|
|
440
423
|
try {
|
|
441
|
-
const value =
|
|
424
|
+
const value = validationSchemas.query.parse(req.query);
|
|
442
425
|
if (opts.stripUnknown) {
|
|
443
426
|
req.query = value;
|
|
444
427
|
}
|
|
445
|
-
} catch (
|
|
446
|
-
if (
|
|
447
|
-
errors.push(...formatValidationErrors(
|
|
428
|
+
} catch (error) {
|
|
429
|
+
if (error instanceof ZodError) {
|
|
430
|
+
errors.push(...formatValidationErrors(error));
|
|
448
431
|
}
|
|
449
432
|
}
|
|
450
433
|
}
|
|
@@ -452,44 +435,54 @@ export function validateRequest<
|
|
|
452
435
|
if (errors.length > 0) {
|
|
453
436
|
const message = createErrorMessage(errors, "Request validation failed");
|
|
454
437
|
|
|
455
|
-
|
|
438
|
+
res.status(400).json({
|
|
456
439
|
success: false,
|
|
457
440
|
error: "Validation failed",
|
|
458
441
|
message,
|
|
459
442
|
errors,
|
|
460
443
|
timestamp: new Date().toISOString(),
|
|
461
|
-
});
|
|
444
|
+
} satisfies ApiResponse<never>);
|
|
445
|
+
return;
|
|
462
446
|
}
|
|
463
447
|
|
|
464
448
|
next();
|
|
465
449
|
};
|
|
466
450
|
}
|
|
467
451
|
|
|
452
|
+
/**
|
|
453
|
+
* Error type for async validation
|
|
454
|
+
*/
|
|
455
|
+
interface AsyncValidationError {
|
|
456
|
+
field?: string;
|
|
457
|
+
message?: string;
|
|
458
|
+
}
|
|
459
|
+
|
|
468
460
|
/**
|
|
469
461
|
* Async validation wrapper for custom validation logic
|
|
470
462
|
*/
|
|
471
|
-
export function validateAsync(validationFn: (req: Request) => Promise<
|
|
463
|
+
export function validateAsync(validationFn: (req: Request) => Promise<void>) {
|
|
472
464
|
return async (
|
|
473
465
|
req: Request,
|
|
474
|
-
res: Response
|
|
466
|
+
res: Response,
|
|
475
467
|
next: NextFunction,
|
|
476
|
-
) => {
|
|
468
|
+
): Promise<void> => {
|
|
477
469
|
try {
|
|
478
470
|
await validationFn(req);
|
|
479
471
|
next();
|
|
480
|
-
} catch (
|
|
481
|
-
const validationError
|
|
482
|
-
|
|
483
|
-
|
|
472
|
+
} catch (error: unknown) {
|
|
473
|
+
const validationError = error as AsyncValidationError;
|
|
474
|
+
const fieldError: FieldValidationError = {
|
|
475
|
+
field: validationError.field || "unknown",
|
|
476
|
+
message: validationError.message || "Validation failed",
|
|
484
477
|
};
|
|
485
478
|
|
|
486
479
|
res.status(400).json({
|
|
487
480
|
success: false,
|
|
488
481
|
error: "Validation failed",
|
|
489
|
-
message:
|
|
490
|
-
errors: [
|
|
482
|
+
message: fieldError.message,
|
|
483
|
+
errors: [fieldError],
|
|
491
484
|
timestamp: new Date().toISOString(),
|
|
492
|
-
});
|
|
485
|
+
} satisfies ApiResponse<never>);
|
|
493
486
|
}
|
|
494
487
|
};
|
|
495
488
|
}
|
|
@@ -502,13 +495,10 @@ export function validateIf<T extends ZodSchema>(
|
|
|
502
495
|
schema: T,
|
|
503
496
|
options?: ValidationOptions,
|
|
504
497
|
) {
|
|
505
|
-
return (
|
|
506
|
-
req: Request,
|
|
507
|
-
res: Response<ApiResponse<any>>,
|
|
508
|
-
next: NextFunction,
|
|
509
|
-
): any => {
|
|
498
|
+
return (req: Request, res: Response, next: NextFunction): void => {
|
|
510
499
|
if (condition(req)) {
|
|
511
|
-
|
|
500
|
+
validate(schema, options)(req, res, next);
|
|
501
|
+
return;
|
|
512
502
|
}
|
|
513
503
|
next();
|
|
514
504
|
};
|
|
@@ -531,23 +521,23 @@ export const compose = {
|
|
|
531
521
|
/**
|
|
532
522
|
* Make all fields optional
|
|
533
523
|
*/
|
|
534
|
-
partial: <T extends z.ZodObject<
|
|
524
|
+
partial: <T extends z.ZodObject<z.ZodRawShape>>(schema: T) => {
|
|
535
525
|
return schema.partial();
|
|
536
526
|
},
|
|
537
527
|
|
|
538
528
|
/**
|
|
539
529
|
* Make specific fields required
|
|
540
530
|
*/
|
|
541
|
-
require: <T extends z.ZodObject<
|
|
531
|
+
require: <T extends z.ZodObject<z.ZodRawShape>>(
|
|
542
532
|
schema: T,
|
|
543
533
|
fields: Array<keyof T["shape"]>,
|
|
544
534
|
) => {
|
|
545
535
|
const partialSchema = schema.partial();
|
|
546
|
-
const requiredOverrides:
|
|
536
|
+
const requiredOverrides: Record<string, z.ZodTypeAny> = {};
|
|
547
537
|
fields.forEach((field) => {
|
|
548
538
|
const fieldSchema = schema.shape[field as string];
|
|
549
539
|
if (fieldSchema) {
|
|
550
|
-
requiredOverrides[field] = fieldSchema;
|
|
540
|
+
requiredOverrides[field as string] = fieldSchema;
|
|
551
541
|
}
|
|
552
542
|
});
|
|
553
543
|
return partialSchema.extend(requiredOverrides);
|
|
@@ -556,14 +546,14 @@ export const compose = {
|
|
|
556
546
|
/**
|
|
557
547
|
* Pick specific fields from a schema
|
|
558
548
|
*/
|
|
559
|
-
pick: <T extends z.ZodObject<
|
|
549
|
+
pick: <T extends z.ZodObject<z.ZodRawShape>>(
|
|
560
550
|
schema: T,
|
|
561
551
|
fields: Array<keyof T["shape"]>,
|
|
562
552
|
) => {
|
|
563
|
-
const picked:
|
|
553
|
+
const picked: Record<string, z.ZodTypeAny> = {};
|
|
564
554
|
fields.forEach((field) => {
|
|
565
555
|
if (schema.shape[field as string]) {
|
|
566
|
-
picked[field] = schema.shape[field as string];
|
|
556
|
+
picked[field as string] = schema.shape[field as string];
|
|
567
557
|
}
|
|
568
558
|
});
|
|
569
559
|
return z.object(picked);
|
|
@@ -572,16 +562,18 @@ export const compose = {
|
|
|
572
562
|
/**
|
|
573
563
|
* Omit specific fields from a schema
|
|
574
564
|
*/
|
|
575
|
-
omit: <T extends z.ZodObject<
|
|
565
|
+
omit: <T extends z.ZodObject<z.ZodRawShape>>(
|
|
576
566
|
schema: T,
|
|
577
567
|
fields: Array<keyof T["shape"]>,
|
|
578
568
|
) => {
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
acc[field] = true;
|
|
569
|
+
const omitKeys = fields.reduce(
|
|
570
|
+
(acc, field) => {
|
|
571
|
+
acc[field as string] = true;
|
|
582
572
|
return acc;
|
|
583
|
-
},
|
|
573
|
+
},
|
|
574
|
+
{} as Record<string, true>,
|
|
584
575
|
);
|
|
576
|
+
return schema.omit(omitKeys);
|
|
585
577
|
},
|
|
586
578
|
};
|
|
587
579
|
|