@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.
- package/LICENSE +177 -0
- package/README.md +382 -0
- package/dist/convex/agents/bugReportAgent.d.ts +30 -0
- package/dist/convex/agents/bugReportAgent.d.ts.map +1 -0
- package/dist/convex/agents/bugReportAgent.js +243 -0
- package/dist/convex/agents/bugReportAgent.js.map +1 -0
- package/dist/convex/agents/feedbackAgent.d.ts +29 -0
- package/dist/convex/agents/feedbackAgent.d.ts.map +1 -0
- package/dist/convex/agents/feedbackAgent.js +232 -0
- package/dist/convex/agents/feedbackAgent.js.map +1 -0
- package/dist/convex/bugReports.d.ts +49 -0
- package/dist/convex/bugReports.d.ts.map +1 -0
- package/dist/convex/bugReports.js +321 -0
- package/dist/convex/bugReports.js.map +1 -0
- package/dist/convex/convex.config.d.ts +3 -0
- package/dist/convex/convex.config.d.ts.map +1 -0
- package/dist/convex/convex.config.js +6 -0
- package/dist/convex/convex.config.js.map +1 -0
- package/dist/convex/emails/bugReportEmails.d.ts +16 -0
- package/dist/convex/emails/bugReportEmails.d.ts.map +1 -0
- package/dist/convex/emails/bugReportEmails.js +403 -0
- package/dist/convex/emails/bugReportEmails.js.map +1 -0
- package/dist/convex/emails/feedbackEmails.d.ts +16 -0
- package/dist/convex/emails/feedbackEmails.d.ts.map +1 -0
- package/dist/convex/emails/feedbackEmails.js +389 -0
- package/dist/convex/emails/feedbackEmails.js.map +1 -0
- package/dist/convex/feedback.d.ts +49 -0
- package/dist/convex/feedback.d.ts.map +1 -0
- package/dist/convex/feedback.js +327 -0
- package/dist/convex/feedback.js.map +1 -0
- package/dist/convex/index.d.ts +10 -0
- package/dist/convex/index.d.ts.map +1 -0
- package/dist/convex/index.js +12 -0
- package/dist/convex/index.js.map +1 -0
- package/dist/convex/schema.d.ts +200 -0
- package/dist/convex/schema.d.ts.map +1 -0
- package/dist/convex/schema.js +150 -0
- package/dist/convex/schema.js.map +1 -0
- package/dist/convex/supportTeams.d.ts +29 -0
- package/dist/convex/supportTeams.d.ts.map +1 -0
- package/dist/convex/supportTeams.js +159 -0
- package/dist/convex/supportTeams.js.map +1 -0
- package/dist/index.d.ts +70 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +63 -0
- package/dist/index.js.map +1 -0
- package/dist/react/BugReportButton.d.ts +70 -0
- package/dist/react/BugReportButton.d.ts.map +1 -0
- package/dist/react/BugReportButton.js +371 -0
- package/dist/react/BugReportButton.js.map +1 -0
- package/dist/react/BugReportContext.d.ts +59 -0
- package/dist/react/BugReportContext.d.ts.map +1 -0
- package/dist/react/BugReportContext.js +107 -0
- package/dist/react/BugReportContext.js.map +1 -0
- package/dist/react/index.d.ts +36 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +36 -0
- package/dist/react/index.js.map +1 -0
- package/dist/types.d.ts +89 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/package.json +101 -0
- package/src/convex/agents/bugReportAgent.ts +277 -0
- package/src/convex/agents/feedbackAgent.ts +264 -0
- package/src/convex/bugReports.ts +350 -0
- package/src/convex/convex.config.ts +7 -0
- package/src/convex/emails/bugReportEmails.ts +479 -0
- package/src/convex/emails/feedbackEmails.ts +465 -0
- package/src/convex/feedback.ts +356 -0
- package/src/convex/index.ts +28 -0
- package/src/convex/schema.ts +207 -0
- package/src/convex/supportTeams.ts +179 -0
- package/src/index.ts +77 -0
- package/src/react/BugReportButton.tsx +755 -0
- package/src/react/BugReportContext.tsx +146 -0
- package/src/react/index.ts +46 -0
- 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
|
+
}
|