ai-app-feedback 0.1.0 → 0.2.1
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/PRODUCT.md +5 -2
- package/README.md +131 -9
- package/dist/core/attachments.d.ts +7 -0
- package/dist/core/types.d.ts +13 -1
- package/dist/core-entry.d.ts +5 -1
- package/dist/core-entry.js +6 -462
- package/dist/index.js +6 -800
- package/dist/next.js +6 -836
- package/dist/react/FeedbackWidget.d.ts +6 -1
- package/dist/server.d.ts +32 -0
- package/dist/server.js +7 -0
- package/dist/style.css +157 -0
- package/package.json +22 -4
package/PRODUCT.md
CHANGED
|
@@ -6,11 +6,11 @@ product
|
|
|
6
6
|
|
|
7
7
|
## Users
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Teams using internal applications. Teammates are already inside a web app when they notice a bug, confusing workflow, broken visual state, or missing behavior. Developers and coding agents receive the report later and need enough context to understand the feedback and decide what to do.
|
|
10
10
|
|
|
11
11
|
## Product Purpose
|
|
12
12
|
|
|
13
|
-
`ai-app-feedback` gives Next.js apps
|
|
13
|
+
`ai-app-feedback` gives Next.js apps a small feedback widget. Teammates choose Problem or Improvement and describe the request. Expected results and work impact are optional. The widget captures recent navigation and browser context, supports screenshots and image uploads, and emails a readable report with attached context for a coding agent. Replies to the notification reach the reporter, keeping follow-up in the team's existing email workflow.
|
|
14
14
|
|
|
15
15
|
## Brand Personality
|
|
16
16
|
|
|
@@ -23,10 +23,13 @@ Avoid marketing-style widgets, decorative motion, chat bubbles that pretend to b
|
|
|
23
23
|
## Design Principles
|
|
24
24
|
|
|
25
25
|
- Capture context silently, ask users only for judgment and details.
|
|
26
|
+
- Use the host application's authenticated session instead of asking signed-in users to identify themselves again.
|
|
26
27
|
- Make privacy boundaries explicit, especially around screenshots and interaction history.
|
|
27
28
|
- Prefer developer-ready structured reports over free-form message blobs.
|
|
28
29
|
- Keep the widget small enough to live in production apps without becoming part of the app's visual identity.
|
|
29
30
|
- Make framework integration thin, so core reporting remains portable and testable.
|
|
31
|
+
- Keep one required text field. Do not require teammates to classify engineering categories, write acceptance criteria, or learn a separate tracking system.
|
|
32
|
+
- Supply the original feedback and captured evidence. The receiving agent decides what to do; the report does not prescribe an implementation, workflow, or reply.
|
|
30
33
|
|
|
31
34
|
## Accessibility & Inclusion
|
|
32
35
|
|
package/README.md
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
# ai-app-feedback
|
|
2
2
|
|
|
3
|
-
A Next.js-ready feedback widget
|
|
3
|
+
A Next.js-ready feedback widget for teams using internal applications. Teammates describe a problem or improvement; the widget captures context and emails a report that can be shared with a coding agent.
|
|
4
|
+
|
|
5
|
+
## Team workflow
|
|
6
|
+
|
|
7
|
+
1. Choose **Problem** or **Improvement** and describe it in one text box.
|
|
8
|
+
2. Optionally expand **Add details** to describe the expected result (a concrete example helps with calculations) and the impact on your work. Attach screenshots or images as needed.
|
|
9
|
+
3. Send. The confirmation includes the report's reference ID.
|
|
10
|
+
4. The recipient gets an email whose subject describes the request. Share the attached `*-context.md`, `*-trace.json`, and images with the receiving agent as context.
|
|
11
|
+
5. The receiving agent decides what to do using that context and its own instructions. Reply to the email to follow up with the reporter.
|
|
12
|
+
|
|
13
|
+
Only the description is required. Email remains the handoff and follow-up channel; this package does not maintain a task inbox or automatically run an agent.
|
|
14
|
+
|
|
15
|
+
Improvements use `category: "feature"`. Existing categories and severity values remain supported by the core API. The stock widget presents two choices and labels severity as work impact. `defaultCategory` still applies to problem reports; set it to `"feature"` to start with an improvement. Draft text survives closing and reopening the widget while it remains mounted, but is not persisted across reloads.
|
|
4
16
|
|
|
5
17
|
## Install
|
|
6
18
|
|
|
@@ -34,19 +46,85 @@ export default function RootLayout({ children }: { children: React.ReactNode })
|
|
|
34
46
|
}
|
|
35
47
|
```
|
|
36
48
|
|
|
37
|
-
|
|
49
|
+
The stock widget does not ask for an email. Pass the current Better Auth user to the provider so the client report is useful immediately; the endpoint below still resolves the session again and treats the server-side identity as authoritative.
|
|
50
|
+
|
|
51
|
+
```tsx
|
|
52
|
+
// components/app-feedback.tsx
|
|
53
|
+
"use client";
|
|
54
|
+
|
|
55
|
+
import { NextFeedbackProvider } from "ai-app-feedback/next";
|
|
56
|
+
import { authClient } from "@/lib/auth-client";
|
|
57
|
+
|
|
58
|
+
export function AppFeedback({ children }: { children: React.ReactNode }) {
|
|
59
|
+
const { data: session } = authClient.useSession();
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<NextFeedbackProvider
|
|
63
|
+
appId="vaster-agent"
|
|
64
|
+
endpoint="/api/feedback"
|
|
65
|
+
user={session?.user
|
|
66
|
+
? {
|
|
67
|
+
id: session.user.id,
|
|
68
|
+
email: session.user.email,
|
|
69
|
+
name: session.user.name,
|
|
70
|
+
}
|
|
71
|
+
: undefined}
|
|
72
|
+
>
|
|
73
|
+
{children}
|
|
74
|
+
</NextFeedbackProvider>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
To show an email field in a public app instead, set `widgetProps={{ showEmailField: true }}`.
|
|
80
|
+
|
|
81
|
+
## Authenticated SES notifications
|
|
82
|
+
|
|
83
|
+
Install the AWS SES v2 client in the host app:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
bun add @aws-sdk/client-sesv2
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Create an authenticated endpoint. This example uses Better Auth directly; if your app wraps session lookup, call that wrapper from `getUser` instead.
|
|
38
90
|
|
|
39
91
|
```ts
|
|
40
92
|
// app/api/feedback/route.ts
|
|
41
|
-
import
|
|
93
|
+
import { auth } from "@/lib/auth";
|
|
94
|
+
import { createFeedbackRouteHandler } from "ai-app-feedback/server";
|
|
95
|
+
|
|
96
|
+
export const runtime = "nodejs";
|
|
42
97
|
|
|
43
|
-
export
|
|
44
|
-
|
|
98
|
+
export const POST = createFeedbackRouteHandler({
|
|
99
|
+
getUser: async (request) => {
|
|
100
|
+
const session = await auth.api.getSession({ headers: request.headers });
|
|
101
|
+
return session?.user ?? null;
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
```
|
|
45
105
|
|
|
46
|
-
|
|
106
|
+
Configure SES with the host's normal AWS credentials:
|
|
47
107
|
|
|
48
|
-
|
|
49
|
-
|
|
108
|
+
```dotenv
|
|
109
|
+
AWS_REGION=us-east-1
|
|
110
|
+
FEEDBACK_EMAIL_FROM="Vaster Feedback <feedback@vaster.com>"
|
|
111
|
+
# Optional. Defaults to dzuloaga@vaster.com.
|
|
112
|
+
FEEDBACK_EMAIL_TO=dzuloaga@vaster.com
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
The route bounds the actual request body even when `Content-Length` is absent or inaccurate, validates nested report fields, rejects signed-out requests, overwrites client-supplied identity with the Better Auth session user, rebuilds the readable context, and sends the report through SES. The email body starts with the request and expected result. A Markdown context report includes the original feedback, browser context, metadata, and recent activity; the JSON attachment retains the structured trace. The captured screenshot and user-uploaded images are attached as viewable image files. Pass the image files alongside the context report: its text does not embed the image contents. Missing SES configuration or a delivery failure returns a non-success response, so the widget never says “Feedback sent” when no notification was delivered.
|
|
116
|
+
|
|
117
|
+
Email subjects now use the request text rather than the route and severity. Update any mailbox rules that depend on the old subject format. Custom integrations that render their own email must adopt the updated formatter or attachment builder to get this handoff.
|
|
118
|
+
|
|
119
|
+
Use `onReport` to persist the authenticated report or forward it to another system in addition to email:
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
export const POST = createFeedbackRouteHandler({
|
|
123
|
+
getUser: async (request) => (await getRequestSession(request))?.user,
|
|
124
|
+
onReport: async (report) => {
|
|
125
|
+
await saveFeedback(report);
|
|
126
|
+
},
|
|
127
|
+
});
|
|
50
128
|
```
|
|
51
129
|
|
|
52
130
|
## Screenshot capture
|
|
@@ -66,6 +144,22 @@ import { createHtml2CanvasCapture } from "ai-app-feedback";
|
|
|
66
144
|
</NextFeedbackProvider>;
|
|
67
145
|
```
|
|
68
146
|
|
|
147
|
+
The widget also accepts up to three PNG, JPEG, WebP, or GIF uploads by default, with a 2 MB limit per image and across all uploads. Configure this through `widgetProps`:
|
|
148
|
+
|
|
149
|
+
```tsx
|
|
150
|
+
<NextFeedbackProvider
|
|
151
|
+
endpoint="/api/feedback"
|
|
152
|
+
widgetProps={{
|
|
153
|
+
allowImageUploads: true,
|
|
154
|
+
maxImageAttachments: 3,
|
|
155
|
+
maxImageBytes: 2_000_000,
|
|
156
|
+
maxTotalImageBytes: 2_000_000,
|
|
157
|
+
}}
|
|
158
|
+
>
|
|
159
|
+
{children}
|
|
160
|
+
</NextFeedbackProvider>
|
|
161
|
+
```
|
|
162
|
+
|
|
69
163
|
## Core API
|
|
70
164
|
|
|
71
165
|
Use the core session outside Next.js or with a custom UI.
|
|
@@ -94,7 +188,7 @@ await session.submit({
|
|
|
94
188
|
- Click tracking stores a small element summary, not full DOM snapshots.
|
|
95
189
|
- Screenshot capture is user-visible and permission-gated unless you provide a custom capture function.
|
|
96
190
|
- URLs are captured in full by default; pass `scrubUrl` to strip query strings or tokens before they are recorded.
|
|
97
|
-
- Reports include `developerPrompt`,
|
|
191
|
+
- Reports include `developerPrompt`, readable context with the original feedback and captured evidence. The existing `developerPrompt` field and `formatFeedbackForAgent` function names are retained for compatibility; their output contains no implementation plan, agent workflow, or suggested reply. User-controlled report fields are kept inside the untrusted-content block.
|
|
98
192
|
|
|
99
193
|
```tsx
|
|
100
194
|
<NextFeedbackProvider
|
|
@@ -112,3 +206,31 @@ bun install
|
|
|
112
206
|
bun test
|
|
113
207
|
bun run build
|
|
114
208
|
```
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
## Publishing
|
|
212
|
+
|
|
213
|
+
The **Publish npm package** GitHub Actions workflow runs from `main`, using the
|
|
214
|
+
`npm` environment restricted to that branch. npm trusts
|
|
215
|
+
`Vastermortgage/ai-app-feedback`, workflow `publish.yml`, environment `npm`.
|
|
216
|
+
It uses OIDC instead of a stored npm token; local npm login is not needed.
|
|
217
|
+
|
|
218
|
+
Validate a release without publishing (the default):
|
|
219
|
+
|
|
220
|
+
```bash
|
|
221
|
+
gh workflow run publish.yml --ref main -f version=0.2.1 -F dry_run=true
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
After committing and pushing a version bump, release that exact version:
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
gh workflow run publish.yml --ref main -f version=0.2.1 -F dry_run=false
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
The workflow checks the requested version against `package.json`, installs the
|
|
231
|
+
frozen lockfile, runs type checks and tests, builds the package, and validates
|
|
232
|
+
its exports and React client boundaries before publishing. GitHub CLI access
|
|
233
|
+
is required to trigger it, or use **Run workflow** in GitHub Actions.
|
|
234
|
+
A dry run verifies the build and package contents; OIDC publishing authentication
|
|
235
|
+
is exercised only by an actual release. This repository is private, so npm does
|
|
236
|
+
not generate public build provenance for its releases.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { FeedbackImageAttachment } from "./types";
|
|
2
|
+
export declare const DEFAULT_IMAGE_MEDIA_TYPES: readonly ["image/jpeg", "image/png", "image/webp", "image/gif"];
|
|
3
|
+
export interface ReadFeedbackImageOptions {
|
|
4
|
+
maxBytes?: number;
|
|
5
|
+
acceptedMediaTypes?: readonly string[];
|
|
6
|
+
}
|
|
7
|
+
export declare function readFeedbackImage(file: File, options?: ReadFeedbackImageOptions): Promise<FeedbackImageAttachment>;
|
package/dist/core/types.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ export type JsonValue = JsonPrimitive | JsonValue[] | {
|
|
|
3
3
|
[key: string]: JsonValue;
|
|
4
4
|
};
|
|
5
5
|
export type FeedbackSeverity = "low" | "medium" | "high" | "blocking";
|
|
6
|
-
export type FeedbackCategory = "bug" | "ux" | "content" | "performance" | "accessibility" | "other";
|
|
6
|
+
export type FeedbackCategory = "bug" | "feature" | "ux" | "content" | "performance" | "accessibility" | "other";
|
|
7
7
|
export interface FeedbackUser {
|
|
8
8
|
id?: string;
|
|
9
9
|
email?: string;
|
|
@@ -66,6 +66,15 @@ export interface FeedbackScreenshot {
|
|
|
66
66
|
capturedAt: string;
|
|
67
67
|
source: "display-media" | "html2canvas" | "custom" | string;
|
|
68
68
|
}
|
|
69
|
+
export interface FeedbackImageAttachment {
|
|
70
|
+
id: string;
|
|
71
|
+
fileName: string;
|
|
72
|
+
mediaType: string;
|
|
73
|
+
size: number;
|
|
74
|
+
dataUrl: string;
|
|
75
|
+
attachedAt: string;
|
|
76
|
+
source: "upload" | string;
|
|
77
|
+
}
|
|
69
78
|
export interface FeedbackDraft {
|
|
70
79
|
message: string;
|
|
71
80
|
expected?: string;
|
|
@@ -73,6 +82,7 @@ export interface FeedbackDraft {
|
|
|
73
82
|
category: FeedbackCategory;
|
|
74
83
|
userEmail?: string;
|
|
75
84
|
includeScreenshot?: boolean;
|
|
85
|
+
attachments?: FeedbackImageAttachment[];
|
|
76
86
|
tags?: string[];
|
|
77
87
|
metadata?: Record<string, JsonValue>;
|
|
78
88
|
}
|
|
@@ -95,7 +105,9 @@ export interface FeedbackReport {
|
|
|
95
105
|
navigation: NavigationEvent[];
|
|
96
106
|
recentActivity: FeedbackTimelineEvent[];
|
|
97
107
|
screenshot?: FeedbackScreenshot;
|
|
108
|
+
attachments?: FeedbackImageAttachment[];
|
|
98
109
|
metadata: Record<string, JsonValue>;
|
|
110
|
+
/** Readable feedback context, without agent task instructions. Legacy field name. */
|
|
99
111
|
developerPrompt: string;
|
|
100
112
|
}
|
|
101
113
|
export interface ScreenshotCaptureContext {
|
package/dist/core-entry.d.ts
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import { formatFeedbackForAgent as formatFeedbackForAgentImpl } from "./core/agent-prompt";
|
|
2
|
+
import { readFeedbackImage as readFeedbackImageImpl } from "./core/attachments";
|
|
2
3
|
import { captureVisibleTabWithDisplayMedia as captureVisibleTabWithDisplayMediaImpl, createHtml2CanvasCapture as createHtml2CanvasCaptureImpl } from "./core/screenshot";
|
|
3
4
|
import { createFeedbackSession as createFeedbackSessionImpl } from "./core/session";
|
|
4
5
|
export declare const captureVisibleTabWithDisplayMedia: typeof captureVisibleTabWithDisplayMediaImpl;
|
|
5
6
|
export declare const createFeedbackSession: typeof createFeedbackSessionImpl;
|
|
6
7
|
export declare const createHtml2CanvasCapture: typeof createHtml2CanvasCaptureImpl;
|
|
7
8
|
export declare const formatFeedbackForAgent: typeof formatFeedbackForAgentImpl;
|
|
9
|
+
export declare const DEFAULT_IMAGE_MEDIA_TYPES: readonly ["image/jpeg", "image/png", "image/webp", "image/gif"];
|
|
10
|
+
export declare const readFeedbackImage: typeof readFeedbackImageImpl;
|
|
8
11
|
export type { FeedbackSession } from "./core/session";
|
|
9
|
-
export type { BrowserContext, ElementSummary, FeedbackCategory, FeedbackDraft, FeedbackReport, FeedbackScreenshot, FeedbackSessionOptions, FeedbackSeverity, FeedbackSubmitHandler, FeedbackTimelineEvent, FeedbackUser, JsonValue, NavigationEvent, RuntimeErrorEvent, ScreenshotCapture, ScreenshotCaptureContext, } from "./core/types";
|
|
12
|
+
export type { BrowserContext, ElementSummary, FeedbackCategory, FeedbackDraft, FeedbackImageAttachment, FeedbackReport, FeedbackScreenshot, FeedbackSessionOptions, FeedbackSeverity, FeedbackSubmitHandler, FeedbackTimelineEvent, FeedbackUser, JsonValue, NavigationEvent, RuntimeErrorEvent, ScreenshotCapture, ScreenshotCaptureContext, } from "./core/types";
|
|
13
|
+
export type { ReadFeedbackImageOptions } from "./core/attachments";
|