dce-reactkit 3.2.0-beta.3 → 3.2.0-beta.5
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/.vscode/settings.json +5 -0
- package/dist/cjs/index.js +160 -76
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/types/index.d.ts +2 -1
- package/dist/cjs/types/types/LogBuiltInCategory.d.ts +10 -0
- package/dist/esm/index.js +160 -77
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/types/index.d.ts +2 -1
- package/dist/esm/types/types/LogBuiltInCategory.d.ts +10 -0
- package/dist/index.d.ts +11 -1
- package/package.json +1 -1
- package/src/helpers/genRouteHandler.ts +187 -99
- package/src/helpers/logClientEvent.tsx +9 -2
- package/src/index.ts +2 -0
- package/src/types/LogBuiltInCategory.ts +11 -0
|
@@ -23,6 +23,7 @@ import LogSource from '../types/LogSource';
|
|
|
23
23
|
import LogTypeSpecificInfo from '../types/Log/LogTypeSpecificInfo';
|
|
24
24
|
import LogMainInfo from '../types/Log/LogMainInfo';
|
|
25
25
|
import LogSourceSpecificInfo from '../types/Log/LogSourceSpecificInfo';
|
|
26
|
+
import LogBuiltInCategory from '../types/LogBuiltInCategory';
|
|
26
27
|
|
|
27
28
|
/**
|
|
28
29
|
* Generate an express API route handler
|
|
@@ -469,109 +470,172 @@ const genRouteHandler = (
|
|
|
469
470
|
// that indicates that this is actually a client event, but we don't
|
|
470
471
|
// include that in the LogFunction type because this is internal and
|
|
471
472
|
// hidden from users
|
|
473
|
+
try {
|
|
474
|
+
// Parse user agent
|
|
475
|
+
const {
|
|
476
|
+
browser,
|
|
477
|
+
device,
|
|
478
|
+
} = parseUserAgent(req.headers['user-agent']);
|
|
479
|
+
|
|
480
|
+
// Get time info in ET
|
|
481
|
+
const {
|
|
482
|
+
timestamp,
|
|
483
|
+
year,
|
|
484
|
+
month,
|
|
485
|
+
day,
|
|
486
|
+
hour,
|
|
487
|
+
minute,
|
|
488
|
+
} = getTimeInfoInET();
|
|
489
|
+
|
|
490
|
+
// Main log info
|
|
491
|
+
const mainLogInfo: LogMainInfo = {
|
|
492
|
+
id: `${launchInfo.userId}-${Date.now()}-${Math.floor(Math.random() * 100000)}-${Math.floor(Math.random() * 100000)}`,
|
|
493
|
+
userFirstName: launchInfo.userFirstName,
|
|
494
|
+
userLastName: launchInfo.userLastName,
|
|
495
|
+
userEmail: launchInfo.userEmail,
|
|
496
|
+
userId: launchInfo.userId,
|
|
497
|
+
isLearner: !!launchInfo.isLearner,
|
|
498
|
+
isAdmin: !!launchInfo.isAdmin,
|
|
499
|
+
isTTM: !!launchInfo.isTTM,
|
|
500
|
+
courseId: launchInfo.courseId,
|
|
501
|
+
courseName: launchInfo.courseName,
|
|
502
|
+
browser,
|
|
503
|
+
device,
|
|
504
|
+
year,
|
|
505
|
+
month,
|
|
506
|
+
day,
|
|
507
|
+
hour,
|
|
508
|
+
minute,
|
|
509
|
+
timestamp,
|
|
510
|
+
category: (
|
|
511
|
+
typeof opts.category === 'string'
|
|
512
|
+
? opts.category
|
|
513
|
+
: (
|
|
514
|
+
((opts.category as any) ?? {})._
|
|
515
|
+
?? LogBuiltInCategory.Uncategorized
|
|
516
|
+
)
|
|
517
|
+
),
|
|
518
|
+
subcategory: (
|
|
519
|
+
typeof opts.category === 'string'
|
|
520
|
+
? opts.subcategory
|
|
521
|
+
: (
|
|
522
|
+
((opts.subcategory as any) ?? {})._
|
|
523
|
+
?? LogBuiltInCategory.Uncategorized
|
|
524
|
+
)
|
|
525
|
+
),
|
|
526
|
+
tags: opts.tags ?? [],
|
|
527
|
+
metadata: opts.metadata ?? {},
|
|
528
|
+
};
|
|
529
|
+
|
|
530
|
+
// Type-specific info
|
|
531
|
+
const typeSpecificInfo: LogTypeSpecificInfo = (
|
|
532
|
+
('error' in opts && opts.error)
|
|
533
|
+
? {
|
|
534
|
+
type: LogType.Error,
|
|
535
|
+
errorMessage: opts.error.message ?? 'Unknown message',
|
|
536
|
+
errorCode: opts.error.code ?? ReactKitErrorCode.NoCode,
|
|
537
|
+
errorStack: opts.error.stack ?? 'No stack',
|
|
538
|
+
}
|
|
539
|
+
: {
|
|
540
|
+
type: LogType.Action,
|
|
541
|
+
target: (opts as any).target ?? 'Unknown',
|
|
542
|
+
action: (opts as any).action ?? 'Unknown'
|
|
543
|
+
}
|
|
544
|
+
);
|
|
472
545
|
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
hour,
|
|
486
|
-
minute,
|
|
487
|
-
} = getTimeInfoInET();
|
|
488
|
-
|
|
489
|
-
// Main log info
|
|
490
|
-
const mainLogInfo: LogMainInfo = {
|
|
491
|
-
id: `${launchInfo.userId}-${Date.now()}-${Math.floor(Math.random() * 100000)}-${Math.floor(Math.random() * 100000)}`,
|
|
492
|
-
userFirstName: launchInfo.userFirstName,
|
|
493
|
-
userLastName: launchInfo.userLastName,
|
|
494
|
-
userEmail: launchInfo.userEmail,
|
|
495
|
-
userId: launchInfo.userId,
|
|
496
|
-
isLearner: !!launchInfo.isLearner,
|
|
497
|
-
isAdmin: !!launchInfo.isAdmin,
|
|
498
|
-
isTTM: !!launchInfo.isTTM,
|
|
499
|
-
courseId: launchInfo.courseId,
|
|
500
|
-
courseName: launchInfo.courseName,
|
|
501
|
-
browser,
|
|
502
|
-
device,
|
|
503
|
-
year,
|
|
504
|
-
month,
|
|
505
|
-
day,
|
|
506
|
-
hour,
|
|
507
|
-
minute,
|
|
508
|
-
timestamp,
|
|
509
|
-
category: (
|
|
510
|
-
typeof opts.category === 'string'
|
|
511
|
-
? opts.category
|
|
512
|
-
: opts.category.name
|
|
513
|
-
),
|
|
514
|
-
subcategory: (
|
|
515
|
-
typeof opts.category === 'string'
|
|
516
|
-
? opts.subcategory
|
|
517
|
-
: ((opts.subcategory as any) ?? { name: 'none' }).name
|
|
518
|
-
),
|
|
519
|
-
tags: opts.tags ?? [],
|
|
520
|
-
metadata: opts.metadata ?? {},
|
|
521
|
-
};
|
|
522
|
-
|
|
523
|
-
// Type-specific info
|
|
524
|
-
const typeSpecificInfo: LogTypeSpecificInfo = (
|
|
525
|
-
('error' in opts && opts.error)
|
|
526
|
-
? {
|
|
527
|
-
type: LogType.Error,
|
|
528
|
-
errorMessage: opts.error.message ?? 'Unknown message',
|
|
529
|
-
errorCode: opts.error.code ?? ReactKitErrorCode.NoCode,
|
|
530
|
-
errorStack: opts.error.stack ?? 'No stack',
|
|
531
|
-
}
|
|
532
|
-
: {
|
|
533
|
-
type: LogType.Action,
|
|
534
|
-
target: (opts as any).target ?? 'Unknown',
|
|
535
|
-
action: (opts as any).action ?? 'Unknown'
|
|
536
|
-
}
|
|
537
|
-
);
|
|
538
|
-
|
|
539
|
-
// Source-specific info
|
|
540
|
-
const sourceSpecificInfo: LogSourceSpecificInfo = (
|
|
541
|
-
(opts as any).overrideAsClientEvent
|
|
542
|
-
? {
|
|
543
|
-
source: LogSource.Client,
|
|
544
|
-
}
|
|
545
|
-
: {
|
|
546
|
-
source: LogSource.Server,
|
|
547
|
-
routePath: req.path,
|
|
548
|
-
routeTemplate: req.route.path,
|
|
549
|
-
}
|
|
550
|
-
);
|
|
546
|
+
// Source-specific info
|
|
547
|
+
const sourceSpecificInfo: LogSourceSpecificInfo = (
|
|
548
|
+
(opts as any).overrideAsClientEvent
|
|
549
|
+
? {
|
|
550
|
+
source: LogSource.Client,
|
|
551
|
+
}
|
|
552
|
+
: {
|
|
553
|
+
source: LogSource.Server,
|
|
554
|
+
routePath: req.path,
|
|
555
|
+
routeTemplate: req.route.path,
|
|
556
|
+
}
|
|
557
|
+
);
|
|
551
558
|
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
} else {
|
|
565
|
-
// Print to console
|
|
566
|
-
if (log.type === LogType.Error) {
|
|
567
|
-
console.error('dce-reactkit error log:', log);
|
|
559
|
+
// Build log event
|
|
560
|
+
const log: Log = {
|
|
561
|
+
...mainLogInfo,
|
|
562
|
+
...typeSpecificInfo,
|
|
563
|
+
...sourceSpecificInfo,
|
|
564
|
+
};
|
|
565
|
+
|
|
566
|
+
// Either print to console or save to db
|
|
567
|
+
const logCollection = internalGetLogCollection();
|
|
568
|
+
if (logCollection) {
|
|
569
|
+
// Store to the log collection
|
|
570
|
+
await logCollection.insert(log);
|
|
568
571
|
} else {
|
|
569
|
-
|
|
572
|
+
// Print to console
|
|
573
|
+
if (log.type === LogType.Error) {
|
|
574
|
+
console.error('dce-reactkit error log:', log);
|
|
575
|
+
} else {
|
|
576
|
+
console.log('dce-reactkit action log:', log);
|
|
577
|
+
}
|
|
570
578
|
}
|
|
571
|
-
}
|
|
572
579
|
|
|
573
|
-
|
|
574
|
-
|
|
580
|
+
// Return log entry
|
|
581
|
+
return log;
|
|
582
|
+
} catch (err) {
|
|
583
|
+
// Print because we cannot store the error
|
|
584
|
+
console.error('Could not log the following:', opts);
|
|
585
|
+
|
|
586
|
+
// Create a dummy log to return
|
|
587
|
+
const dummyMainInfo: LogMainInfo = {
|
|
588
|
+
id: '-1',
|
|
589
|
+
userFirstName: 'Unknown',
|
|
590
|
+
userLastName: 'Unknown',
|
|
591
|
+
userEmail: 'unknown@harvard.edu',
|
|
592
|
+
userId: 1,
|
|
593
|
+
isLearner: false,
|
|
594
|
+
isAdmin: false,
|
|
595
|
+
isTTM: false,
|
|
596
|
+
courseId: 1,
|
|
597
|
+
courseName: 'Unknown',
|
|
598
|
+
browser: {
|
|
599
|
+
name: 'Unknown',
|
|
600
|
+
version: 'Unknown',
|
|
601
|
+
},
|
|
602
|
+
device: {
|
|
603
|
+
isMobile: false,
|
|
604
|
+
os: 'Unknown',
|
|
605
|
+
},
|
|
606
|
+
year: 1,
|
|
607
|
+
month: 1,
|
|
608
|
+
day: 1,
|
|
609
|
+
hour: 1,
|
|
610
|
+
minute: 1,
|
|
611
|
+
timestamp: Date.now(),
|
|
612
|
+
tags: [],
|
|
613
|
+
metadata: {},
|
|
614
|
+
category: LogBuiltInCategory.Uncategorized,
|
|
615
|
+
subcategory: LogBuiltInCategory.Uncategorized,
|
|
616
|
+
};
|
|
617
|
+
|
|
618
|
+
const dummyTypeSpecificInfo: LogTypeSpecificInfo = {
|
|
619
|
+
type: LogType.Error,
|
|
620
|
+
errorMessage: 'Unknown',
|
|
621
|
+
errorCode: 'Unknown',
|
|
622
|
+
errorStack: 'No Stack',
|
|
623
|
+
};
|
|
624
|
+
|
|
625
|
+
const dummySourceSpecificInfo: LogSourceSpecificInfo = {
|
|
626
|
+
source: LogSource.Server,
|
|
627
|
+
routePath: req.path,
|
|
628
|
+
routeTemplate: req.route.path,
|
|
629
|
+
};
|
|
630
|
+
|
|
631
|
+
const log: Log = {
|
|
632
|
+
...dummyMainInfo,
|
|
633
|
+
...dummyTypeSpecificInfo,
|
|
634
|
+
...dummySourceSpecificInfo,
|
|
635
|
+
};
|
|
636
|
+
|
|
637
|
+
return log;
|
|
638
|
+
}
|
|
575
639
|
};
|
|
576
640
|
|
|
577
641
|
/*------------------------------------------------------------------------*/
|
|
@@ -625,6 +689,22 @@ const genRouteHandler = (
|
|
|
625
689
|
) => {
|
|
626
690
|
const html = genErrorPage(opts);
|
|
627
691
|
send(html, opts.status ?? 500);
|
|
692
|
+
|
|
693
|
+
// Log
|
|
694
|
+
logServerEvent({
|
|
695
|
+
category: LogBuiltInCategory.ServerRenderedErrorPage,
|
|
696
|
+
error: {
|
|
697
|
+
message: `${opts.title}: ${opts.description}`,
|
|
698
|
+
code: opts.code,
|
|
699
|
+
},
|
|
700
|
+
metadata: {
|
|
701
|
+
title: opts.title,
|
|
702
|
+
description: opts.description,
|
|
703
|
+
code: opts.code,
|
|
704
|
+
pageTitle: opts.pageTitle,
|
|
705
|
+
status: opts.status ?? 500,
|
|
706
|
+
},
|
|
707
|
+
});
|
|
628
708
|
};
|
|
629
709
|
|
|
630
710
|
// Call the handler
|
|
@@ -649,7 +729,15 @@ const genRouteHandler = (
|
|
|
649
729
|
} catch (err) {
|
|
650
730
|
// Send error to client (only if next wasn't called)
|
|
651
731
|
if (!responseSent) {
|
|
652
|
-
|
|
732
|
+
handleError(res, err);
|
|
733
|
+
|
|
734
|
+
// Log server-side error
|
|
735
|
+
logServerEvent({
|
|
736
|
+
category: LogBuiltInCategory.ServerEndpointError,
|
|
737
|
+
error: err,
|
|
738
|
+
});
|
|
739
|
+
|
|
740
|
+
return;
|
|
653
741
|
}
|
|
654
742
|
|
|
655
743
|
// Log error that was not responded with
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// Import shared types
|
|
2
2
|
import LOG_ROUTE_PATH from '../constants/LOG_ROUTE_PATH';
|
|
3
|
+
import LogBuiltInCategory from '../types/LogBuiltInCategory';
|
|
3
4
|
import LogFunction from '../types/LogFunction';
|
|
4
5
|
|
|
5
6
|
// Import shared functions
|
|
@@ -17,12 +18,18 @@ const logClientEvent: LogFunction = async (opts) => {
|
|
|
17
18
|
category: (
|
|
18
19
|
typeof opts.category === 'string'
|
|
19
20
|
? opts.category
|
|
20
|
-
:
|
|
21
|
+
: (
|
|
22
|
+
((opts.category as any) ?? {})._
|
|
23
|
+
?? LogBuiltInCategory.Uncategorized
|
|
24
|
+
)
|
|
21
25
|
),
|
|
22
26
|
subcategory: (
|
|
23
27
|
typeof opts.category === 'string'
|
|
24
28
|
? opts.subcategory
|
|
25
|
-
: (
|
|
29
|
+
: (
|
|
30
|
+
((opts.subcategory as any) ?? {})._
|
|
31
|
+
?? LogBuiltInCategory.Uncategorized
|
|
32
|
+
)
|
|
26
33
|
),
|
|
27
34
|
tags: JSON.stringify(opts.tags),
|
|
28
35
|
metadata: JSON.stringify(opts.metadata ?? {}),
|
package/src/index.ts
CHANGED
|
@@ -63,6 +63,7 @@ import Log from './types/Log';
|
|
|
63
63
|
import LogType from './types/LogType';
|
|
64
64
|
import LogSource from './types/LogSource';
|
|
65
65
|
import LogAction from './types/LogAction';
|
|
66
|
+
import LogBuiltInCategory from './types/LogBuiltInCategory';
|
|
66
67
|
|
|
67
68
|
// Component-specific-types
|
|
68
69
|
import PickableItem from './components/ItemPicker/types/PickableItem';
|
|
@@ -135,6 +136,7 @@ export {
|
|
|
135
136
|
LogType,
|
|
136
137
|
LogSource,
|
|
137
138
|
LogAction,
|
|
139
|
+
LogBuiltInCategory,
|
|
138
140
|
// Component-specific-types
|
|
139
141
|
PickableItem,
|
|
140
142
|
// Server types
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Built-in categories for logs
|
|
3
|
+
* @author Gabe Abrams
|
|
4
|
+
*/
|
|
5
|
+
enum LogBuiltInCategory {
|
|
6
|
+
Uncategorized = 'n/a',
|
|
7
|
+
ServerRenderedErrorPage = '_server-rendered-error-page',
|
|
8
|
+
ServerEndpointError = '_server-endpoint-error',
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export default LogBuiltInCategory;
|