@fatagnus/convex-feedback 0.1.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 (78) hide show
  1. package/LICENSE +177 -0
  2. package/README.md +382 -0
  3. package/dist/convex/agents/bugReportAgent.d.ts +30 -0
  4. package/dist/convex/agents/bugReportAgent.d.ts.map +1 -0
  5. package/dist/convex/agents/bugReportAgent.js +243 -0
  6. package/dist/convex/agents/bugReportAgent.js.map +1 -0
  7. package/dist/convex/agents/feedbackAgent.d.ts +29 -0
  8. package/dist/convex/agents/feedbackAgent.d.ts.map +1 -0
  9. package/dist/convex/agents/feedbackAgent.js +232 -0
  10. package/dist/convex/agents/feedbackAgent.js.map +1 -0
  11. package/dist/convex/bugReports.d.ts +49 -0
  12. package/dist/convex/bugReports.d.ts.map +1 -0
  13. package/dist/convex/bugReports.js +321 -0
  14. package/dist/convex/bugReports.js.map +1 -0
  15. package/dist/convex/convex.config.d.ts +3 -0
  16. package/dist/convex/convex.config.d.ts.map +1 -0
  17. package/dist/convex/convex.config.js +6 -0
  18. package/dist/convex/convex.config.js.map +1 -0
  19. package/dist/convex/emails/bugReportEmails.d.ts +16 -0
  20. package/dist/convex/emails/bugReportEmails.d.ts.map +1 -0
  21. package/dist/convex/emails/bugReportEmails.js +403 -0
  22. package/dist/convex/emails/bugReportEmails.js.map +1 -0
  23. package/dist/convex/emails/feedbackEmails.d.ts +16 -0
  24. package/dist/convex/emails/feedbackEmails.d.ts.map +1 -0
  25. package/dist/convex/emails/feedbackEmails.js +389 -0
  26. package/dist/convex/emails/feedbackEmails.js.map +1 -0
  27. package/dist/convex/feedback.d.ts +49 -0
  28. package/dist/convex/feedback.d.ts.map +1 -0
  29. package/dist/convex/feedback.js +327 -0
  30. package/dist/convex/feedback.js.map +1 -0
  31. package/dist/convex/index.d.ts +10 -0
  32. package/dist/convex/index.d.ts.map +1 -0
  33. package/dist/convex/index.js +12 -0
  34. package/dist/convex/index.js.map +1 -0
  35. package/dist/convex/schema.d.ts +200 -0
  36. package/dist/convex/schema.d.ts.map +1 -0
  37. package/dist/convex/schema.js +150 -0
  38. package/dist/convex/schema.js.map +1 -0
  39. package/dist/convex/supportTeams.d.ts +29 -0
  40. package/dist/convex/supportTeams.d.ts.map +1 -0
  41. package/dist/convex/supportTeams.js +159 -0
  42. package/dist/convex/supportTeams.js.map +1 -0
  43. package/dist/index.d.ts +70 -0
  44. package/dist/index.d.ts.map +1 -0
  45. package/dist/index.js +63 -0
  46. package/dist/index.js.map +1 -0
  47. package/dist/react/BugReportButton.d.ts +70 -0
  48. package/dist/react/BugReportButton.d.ts.map +1 -0
  49. package/dist/react/BugReportButton.js +371 -0
  50. package/dist/react/BugReportButton.js.map +1 -0
  51. package/dist/react/BugReportContext.d.ts +59 -0
  52. package/dist/react/BugReportContext.d.ts.map +1 -0
  53. package/dist/react/BugReportContext.js +107 -0
  54. package/dist/react/BugReportContext.js.map +1 -0
  55. package/dist/react/index.d.ts +36 -0
  56. package/dist/react/index.d.ts.map +1 -0
  57. package/dist/react/index.js +36 -0
  58. package/dist/react/index.js.map +1 -0
  59. package/dist/types.d.ts +89 -0
  60. package/dist/types.d.ts.map +1 -0
  61. package/dist/types.js +5 -0
  62. package/dist/types.js.map +1 -0
  63. package/package.json +101 -0
  64. package/src/convex/agents/bugReportAgent.ts +277 -0
  65. package/src/convex/agents/feedbackAgent.ts +264 -0
  66. package/src/convex/bugReports.ts +350 -0
  67. package/src/convex/convex.config.ts +7 -0
  68. package/src/convex/emails/bugReportEmails.ts +479 -0
  69. package/src/convex/emails/feedbackEmails.ts +465 -0
  70. package/src/convex/feedback.ts +356 -0
  71. package/src/convex/index.ts +28 -0
  72. package/src/convex/schema.ts +207 -0
  73. package/src/convex/supportTeams.ts +179 -0
  74. package/src/index.ts +77 -0
  75. package/src/react/BugReportButton.tsx +755 -0
  76. package/src/react/BugReportContext.tsx +146 -0
  77. package/src/react/index.ts +46 -0
  78. package/src/types.ts +93 -0
@@ -0,0 +1,146 @@
1
+ import { createContext, useContext, useEffect, useRef, ReactNode } from 'react';
2
+
3
+ /**
4
+ * Captured console error with metadata
5
+ */
6
+ export interface ConsoleError {
7
+ message: string;
8
+ source?: string;
9
+ lineno?: number;
10
+ colno?: number;
11
+ timestamp: number;
12
+ }
13
+
14
+ /**
15
+ * Context value for bug report error capture
16
+ */
17
+ export interface BugReportContextValue {
18
+ /** Get all captured console errors */
19
+ getConsoleErrors: () => ConsoleError[];
20
+ /** Clear all captured console errors */
21
+ clearConsoleErrors: () => void;
22
+ }
23
+
24
+ const BugReportContext = createContext<BugReportContextValue | null>(null);
25
+
26
+ /** Maximum number of errors to retain */
27
+ const MAX_ERRORS = 20;
28
+
29
+ export interface BugReportProviderProps {
30
+ children: ReactNode;
31
+ /** Maximum number of errors to capture (default: 20) */
32
+ maxErrors?: number;
33
+ }
34
+
35
+ /**
36
+ * Provider component that captures console errors for bug reports.
37
+ * Wrap your app with this provider to enable error capture.
38
+ *
39
+ * @example
40
+ * ```tsx
41
+ * import { BugReportProvider } from '@convex-dev/feedback/react';
42
+ *
43
+ * function App() {
44
+ * return (
45
+ * <BugReportProvider>
46
+ * <YourApp />
47
+ * </BugReportProvider>
48
+ * );
49
+ * }
50
+ * ```
51
+ */
52
+ export function BugReportProvider({ children, maxErrors = MAX_ERRORS }: BugReportProviderProps) {
53
+ const errorsRef = useRef<ConsoleError[]>([]);
54
+
55
+ useEffect(() => {
56
+ // Capture window.onerror
57
+ const originalOnError = window.onerror;
58
+ window.onerror = (message, source, lineno, colno, error) => {
59
+ errorsRef.current.push({
60
+ message: String(message),
61
+ source,
62
+ lineno: lineno ?? undefined,
63
+ colno: colno ?? undefined,
64
+ timestamp: Date.now(),
65
+ });
66
+ // Keep only last N errors
67
+ if (errorsRef.current.length > maxErrors) {
68
+ errorsRef.current = errorsRef.current.slice(-maxErrors);
69
+ }
70
+ // Call original handler if exists
71
+ if (originalOnError) {
72
+ return originalOnError(message, source, lineno, colno, error);
73
+ }
74
+ return false;
75
+ };
76
+
77
+ // Capture unhandled promise rejections
78
+ const handleUnhandledRejection = (event: PromiseRejectionEvent) => {
79
+ errorsRef.current.push({
80
+ message: `Unhandled Promise Rejection: ${String(event.reason)}`,
81
+ timestamp: Date.now(),
82
+ });
83
+ if (errorsRef.current.length > maxErrors) {
84
+ errorsRef.current = errorsRef.current.slice(-maxErrors);
85
+ }
86
+ };
87
+ window.addEventListener('unhandledrejection', handleUnhandledRejection);
88
+
89
+ // Override console.error
90
+ const originalConsoleError = console.error;
91
+ console.error = (...args) => {
92
+ errorsRef.current.push({
93
+ message: args.map((arg) => {
94
+ if (arg instanceof Error) {
95
+ return `${arg.name}: ${arg.message}`;
96
+ }
97
+ return String(arg);
98
+ }).join(' '),
99
+ timestamp: Date.now(),
100
+ });
101
+ if (errorsRef.current.length > maxErrors) {
102
+ errorsRef.current = errorsRef.current.slice(-maxErrors);
103
+ }
104
+ originalConsoleError.apply(console, args);
105
+ };
106
+
107
+ return () => {
108
+ window.onerror = originalOnError;
109
+ window.removeEventListener('unhandledrejection', handleUnhandledRejection);
110
+ console.error = originalConsoleError;
111
+ };
112
+ }, [maxErrors]);
113
+
114
+ const getConsoleErrors = () => [...errorsRef.current];
115
+ const clearConsoleErrors = () => {
116
+ errorsRef.current = [];
117
+ };
118
+
119
+ return (
120
+ <BugReportContext.Provider value={{ getConsoleErrors, clearConsoleErrors }}>
121
+ {children}
122
+ </BugReportContext.Provider>
123
+ );
124
+ }
125
+
126
+ /**
127
+ * Hook to access bug report context for error capture.
128
+ * Must be used within a BugReportProvider.
129
+ *
130
+ * @example
131
+ * ```tsx
132
+ * import { useBugReportContext } from '@convex-dev/feedback/react';
133
+ *
134
+ * function MyComponent() {
135
+ * const { getConsoleErrors, clearConsoleErrors } = useBugReportContext();
136
+ * // ...
137
+ * }
138
+ * ```
139
+ */
140
+ export function useBugReportContext(): BugReportContextValue {
141
+ const context = useContext(BugReportContext);
142
+ if (!context) {
143
+ throw new Error('useBugReportContext must be used within a BugReportProvider');
144
+ }
145
+ return context;
146
+ }
@@ -0,0 +1,46 @@
1
+ /**
2
+ * @convex-dev/feedback - React Components
3
+ *
4
+ * React components for bug reports and feedback collection.
5
+ *
6
+ * @example
7
+ * ```tsx
8
+ * import { BugReportProvider, BugReportButton } from '@convex-dev/feedback/react';
9
+ * import { api } from './convex/_generated/api';
10
+ *
11
+ * function App() {
12
+ * return (
13
+ * <BugReportProvider>
14
+ * <YourApp />
15
+ * <BugReportButton
16
+ * reporterType="staff"
17
+ * reporterId={user.id}
18
+ * reporterEmail={user.email}
19
+ * reporterName={user.name}
20
+ * bugReportApi={{
21
+ * create: api.feedback.bugReports.create,
22
+ * generateUploadUrl: api.feedback.bugReports.generateUploadUrl,
23
+ * }}
24
+ * feedbackApi={{
25
+ * create: api.feedback.feedback.create,
26
+ * generateUploadUrl: api.feedback.feedback.generateUploadUrl,
27
+ * }}
28
+ * />
29
+ * </BugReportProvider>
30
+ * );
31
+ * }
32
+ * ```
33
+ */
34
+
35
+ export {
36
+ BugReportProvider,
37
+ useBugReportContext,
38
+ type BugReportProviderProps,
39
+ type BugReportContextValue,
40
+ type ConsoleError,
41
+ } from './BugReportContext';
42
+
43
+ export {
44
+ BugReportButton,
45
+ type BugReportButtonProps,
46
+ } from './BugReportButton';
package/src/types.ts ADDED
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Shared types for @convex-dev/feedback
3
+ */
4
+
5
+ /**
6
+ * Bug report document type
7
+ * Note: _id is typed as string for portability. Use your app's Id type for full typing.
8
+ */
9
+ export interface BugReport {
10
+ _id: string;
11
+ _creationTime: number;
12
+ title: string;
13
+ description: string;
14
+ severity: 'low' | 'medium' | 'high' | 'critical';
15
+ status: 'open' | 'in-progress' | 'resolved' | 'closed';
16
+ isArchived?: boolean;
17
+ reporterType: 'staff' | 'customer';
18
+ reporterId: string;
19
+ reporterEmail: string;
20
+ reporterName: string;
21
+ url: string;
22
+ route?: string;
23
+ browserInfo: string;
24
+ consoleErrors?: string;
25
+ screenshotStorageId?: string;
26
+ viewportWidth: number;
27
+ viewportHeight: number;
28
+ networkState: string;
29
+ // AI Analysis
30
+ aiSummary?: string;
31
+ aiRootCauseAnalysis?: string;
32
+ aiReproductionSteps?: string[];
33
+ aiSuggestedFix?: string;
34
+ aiEstimatedEffort?: 'low' | 'medium' | 'high';
35
+ aiSuggestedSeverity?: 'low' | 'medium' | 'high' | 'critical';
36
+ aiAnalyzedAt?: number;
37
+ aiThreadId?: string;
38
+ notificationsSentAt?: number;
39
+ createdAt: number;
40
+ updatedAt: number;
41
+ }
42
+
43
+ /**
44
+ * Feedback document type
45
+ */
46
+ export interface Feedback {
47
+ _id: string;
48
+ _creationTime: number;
49
+ type: 'feature_request' | 'change_request' | 'general';
50
+ title: string;
51
+ description: string;
52
+ priority: 'nice_to_have' | 'important' | 'critical';
53
+ status: 'open' | 'under_review' | 'planned' | 'in_progress' | 'completed' | 'declined';
54
+ isArchived?: boolean;
55
+ reporterType: 'staff' | 'customer';
56
+ reporterId: string;
57
+ reporterEmail: string;
58
+ reporterName: string;
59
+ url: string;
60
+ route?: string;
61
+ browserInfo: string;
62
+ consoleErrors?: string;
63
+ screenshotStorageId?: string;
64
+ viewportWidth: number;
65
+ viewportHeight: number;
66
+ networkState: string;
67
+ // AI Analysis
68
+ aiSummary?: string;
69
+ aiImpactAnalysis?: string;
70
+ aiActionItems?: string[];
71
+ aiEstimatedEffort?: 'low' | 'medium' | 'high';
72
+ aiSuggestedPriority?: 'nice_to_have' | 'important' | 'critical';
73
+ aiAnalyzedAt?: number;
74
+ aiThreadId?: string;
75
+ notificationsSentAt?: number;
76
+ createdAt: number;
77
+ updatedAt: number;
78
+ }
79
+
80
+ /**
81
+ * Support team document type
82
+ */
83
+ export interface SupportTeam {
84
+ _id: string;
85
+ _creationTime: number;
86
+ teamName: string;
87
+ memberEmails: string[];
88
+ feedbackTypes: ('feature_request' | 'change_request' | 'general')[];
89
+ bugReportSeverities: ('low' | 'medium' | 'high' | 'critical')[];
90
+ isActive: boolean;
91
+ createdAt: number;
92
+ updatedAt: number;
93
+ }