@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.
Files changed (54) hide show
  1. package/README.md +8 -2
  2. package/dist/api/logsRouter.d.ts +4 -1
  3. package/dist/api/logsRouter.d.ts.map +1 -1
  4. package/dist/api/logsRouter.js +100 -118
  5. package/dist/api/logsRouter.js.map +1 -1
  6. package/dist/index.d.ts +2 -0
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +2 -0
  9. package/dist/index.js.map +1 -1
  10. package/dist/middleware/validation.d.ts +48 -43
  11. package/dist/middleware/validation.d.ts.map +1 -1
  12. package/dist/middleware/validation.js +48 -43
  13. package/dist/middleware/validation.js.map +1 -1
  14. package/dist/services/emailService.d.ts +146 -0
  15. package/dist/services/emailService.d.ts.map +1 -0
  16. package/dist/services/emailService.js +649 -0
  17. package/dist/services/emailService.js.map +1 -0
  18. package/dist/services/index.d.ts +2 -0
  19. package/dist/services/index.d.ts.map +1 -1
  20. package/dist/services/index.js +2 -0
  21. package/dist/services/index.js.map +1 -1
  22. package/dist/services/websocketServer.d.ts +7 -4
  23. package/dist/services/websocketServer.d.ts.map +1 -1
  24. package/dist/services/websocketServer.js +22 -16
  25. package/dist/services/websocketServer.js.map +1 -1
  26. package/dist/types/index.d.ts +7 -8
  27. package/dist/types/index.d.ts.map +1 -1
  28. package/package.json +11 -2
  29. package/src/api/logsRouter.ts +119 -138
  30. package/src/index.ts +14 -0
  31. package/src/middleware/validation.ts +82 -90
  32. package/src/services/emailService.ts +812 -0
  33. package/src/services/index.ts +14 -0
  34. package/src/services/websocketServer.ts +37 -23
  35. package/src/types/index.ts +7 -8
  36. package/ui/data-table/components/BatchActionsBar.tsx +53 -0
  37. package/ui/data-table/components/ColumnVisibility.tsx +111 -0
  38. package/ui/data-table/components/DataTablePage.tsx +238 -0
  39. package/ui/data-table/components/Pagination.tsx +203 -0
  40. package/ui/data-table/components/PaginationControls.tsx +122 -0
  41. package/ui/data-table/components/TableFilters.tsx +139 -0
  42. package/ui/data-table/components/index.ts +27 -0
  43. package/ui/data-table/hooks/index.ts +17 -0
  44. package/ui/data-table/hooks/useColumnOrder.ts +233 -0
  45. package/ui/data-table/hooks/useColumnVisibility.ts +128 -0
  46. package/ui/data-table/hooks/usePagination.ts +160 -0
  47. package/ui/data-table/hooks/useResizableColumns.ts +280 -0
  48. package/ui/data-table/index.ts +74 -0
  49. package/ui/dist/index.d.mts +207 -5
  50. package/ui/dist/index.d.ts +207 -5
  51. package/ui/dist/index.js +36 -43
  52. package/ui/dist/index.js.map +1 -1
  53. package/ui/dist/index.mjs +36 -43
  54. 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 (_error) {
296
- if (_error instanceof ZodError) {
297
- const errors = formatValidationErrors(_error);
287
+ } catch (error) {
288
+ if (error instanceof ZodError) {
289
+ const errors = formatValidationErrors(error);
298
290
  const message = createErrorMessage(errors, "Invalid request");
299
291
 
300
- return res.status(400).json({
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(_error);
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 (_error) {
335
- if (_error instanceof ZodError) {
336
- const errors = formatValidationErrors(_error);
323
+ } catch (error) {
324
+ if (error instanceof ZodError) {
325
+ const errors = formatValidationErrors(error);
337
326
  const message = createErrorMessage(errors, "Invalid parameters");
338
327
 
339
- return res.status(400).json({
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(_error);
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 (_error) {
374
- if (_error instanceof ZodError) {
375
- const errors = formatValidationErrors(_error);
359
+ } catch (error) {
360
+ if (error instanceof ZodError) {
361
+ const errors = formatValidationErrors(error);
376
362
  const message = createErrorMessage(errors, "Invalid query");
377
363
 
378
- return res.status(400).json({
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(_error);
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
- >(schemas: T, options?: ValidationOptions) {
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 (schemas.body) {
394
+ if (validationSchemas.body) {
412
395
  try {
413
- const value = schemas.body.parse(req.body);
396
+ const value = validationSchemas.body.parse(req.body);
414
397
  if (opts.stripUnknown) {
415
398
  req.body = value;
416
399
  }
417
- } catch (_error) {
418
- if (_error instanceof ZodError) {
419
- errors.push(...formatValidationErrors(_error));
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 (schemas.params) {
408
+ if (validationSchemas.params) {
426
409
  try {
427
- const value = schemas.params.parse(req.params);
410
+ const value = validationSchemas.params.parse(req.params);
428
411
  if (opts.stripUnknown) {
429
412
  req.params = value;
430
413
  }
431
- } catch (_error) {
432
- if (_error instanceof ZodError) {
433
- errors.push(...formatValidationErrors(_error));
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 (schemas.query) {
422
+ if (validationSchemas.query) {
440
423
  try {
441
- const value = schemas.query.parse(req.query);
424
+ const value = validationSchemas.query.parse(req.query);
442
425
  if (opts.stripUnknown) {
443
426
  req.query = value;
444
427
  }
445
- } catch (_error) {
446
- if (_error instanceof ZodError) {
447
- errors.push(...formatValidationErrors(_error));
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
- return res.status(400).json({
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<any>) {
463
+ export function validateAsync(validationFn: (req: Request) => Promise<void>) {
472
464
  return async (
473
465
  req: Request,
474
- res: Response<ApiResponse<any>>,
466
+ res: Response,
475
467
  next: NextFunction,
476
- ) => {
468
+ ): Promise<void> => {
477
469
  try {
478
470
  await validationFn(req);
479
471
  next();
480
- } catch (_error: any) {
481
- const validationError: FieldValidationError = {
482
- field: _error.field || "unknown",
483
- message: _error.message || "Validation failed",
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: _error.message,
490
- errors: [validationError],
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
- return validate(schema, options)(req, res, next);
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<any>>(schema: T) => {
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<any>>(
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: any = {};
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<any>>(
549
+ pick: <T extends z.ZodObject<z.ZodRawShape>>(
560
550
  schema: T,
561
551
  fields: Array<keyof T["shape"]>,
562
552
  ) => {
563
- const picked: any = {};
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<any>>(
565
+ omit: <T extends z.ZodObject<z.ZodRawShape>>(
576
566
  schema: T,
577
567
  fields: Array<keyof T["shape"]>,
578
568
  ) => {
579
- return schema.omit(
580
- fields.reduce((acc, field) => {
581
- acc[field] = true;
569
+ const omitKeys = fields.reduce(
570
+ (acc, field) => {
571
+ acc[field as string] = true;
582
572
  return acc;
583
- }, {} as any),
573
+ },
574
+ {} as Record<string, true>,
584
575
  );
576
+ return schema.omit(omitKeys);
585
577
  },
586
578
  };
587
579