@goodcraft/feedback-widget-nextjs
v1.2.0
Published
Next.js server utilities for the feedback widget (API routes, Linear integration)
Maintainers
Readme
@goodcraft/feedback-widget-nextjs
Server-side handler for Next.js API routes. Validates feedback submissions, uploads screenshots to Bunny CDN, and creates Linear issues.
Install
pnpm add @goodcraft/feedback-widget-nextjsPeer dependency: next >= 13
Quick Start
// app/api/feedback/route.ts
import { NextResponse } from 'next/server';
import {
createFeedbackHandler,
validateSubmission,
type FeedbackSubmission,
} from '@goodcraft/feedback-widget-nextjs';
const handleFeedback = createFeedbackHandler({
linear: {
apiKey: process.env.LINEAR_API_KEY!,
teamId: process.env.LINEAR_TEAM_ID!,
},
});
export async function POST(request: Request) {
const body = await request.json();
if (!validateSubmission(body)) {
return NextResponse.json({ success: false, message: 'Invalid submission' }, { status: 400 });
}
const result = await handleFeedback(body as FeedbackSubmission);
return NextResponse.json(result, { status: result.success ? 200 : 500 });
}createFeedbackHandler(config)
Creates a handler function that processes feedback submissions. Call it once at module scope, then use the returned function in your route handler.
const handleFeedback = createFeedbackHandler(config);
const result = await handleFeedback(submission);FeedbackHandlerConfig
| Property | Type | Required | Description |
|----------|------|----------|-------------|
| linear | LinearConfig | Yes | Linear API configuration |
| bunny | BunnyConfig | No | Bunny CDN configuration for screenshot uploads |
| onBeforeCreate | (submission, issueInput) => issueInput | No | Modify the Linear issue before creation |
| onAfterCreate | (submission, issueUrl, issueId) => void | No | Callback after successful issue creation |
LinearConfig
| Property | Type | Required | Description |
|----------|------|----------|-------------|
| apiKey | string | Yes | Linear API key |
| teamId | string | Yes | Team ID for issue creation |
| bugLabelId | string | No | Label applied to bug reports |
| featureLabelId | string | No | Label applied to feature requests |
| widgetLabelId | string | No | Label applied to all widget submissions |
| defaultProjectId | string | No | Default project ID |
| projectMapping | Record<string, string> | No | Map of projectSlug to Linear project IDs |
BunnyConfig
| Property | Type | Required | Description |
|----------|------|----------|-------------|
| apiKey | string | Yes | Bunny.net storage API key |
| storageZone | string | Yes | Storage zone name |
| cdnHostname | string | Yes | CDN hostname for public URLs |
validateSubmission(body)
Type guard that checks whether a request body is a valid FeedbackSubmission. Returns true if:
typeis'bug'or'feature'titleis a non-empty stringprojectSlugis a stringsystemInfois an objectconsoleErrorsis an array
if (!validateSubmission(body)) {
return NextResponse.json({ success: false, message: 'Invalid' }, { status: 400 });
}Full Configuration Example
const handleFeedback = createFeedbackHandler({
linear: {
apiKey: process.env.LINEAR_API_KEY!,
teamId: process.env.LINEAR_TEAM_ID!,
bugLabelId: process.env.LINEAR_BUG_LABEL_ID,
featureLabelId: process.env.LINEAR_FEATURE_LABEL_ID,
widgetLabelId: process.env.LINEAR_WIDGET_LABEL_ID,
defaultProjectId: process.env.LINEAR_PROJECT_ID,
projectMapping: {
'app': 'linear-project-id-1',
'marketing': 'linear-project-id-2',
},
},
bunny: {
apiKey: process.env.BUNNY_API_KEY!,
storageZone: process.env.BUNNY_STORAGE_ZONE!,
cdnHostname: process.env.BUNNY_CDN_HOSTNAME!,
},
onBeforeCreate: (submission, issueInput) => ({
...issueInput,
priority: submission.type === 'bug' ? 2 : 4,
}),
onAfterCreate: async (submission, issueUrl) => {
console.log(`Created issue: ${issueUrl}`);
},
});Exported Utilities
| Export | Description |
|--------|-------------|
| createFeedbackHandler | Creates the main handler function |
| validateSubmission | Type guard for request body validation |
| createLinearIssue | Low-level Linear issue creation |
| buildIssueDescription | Builds markdown description from submission data |
| uploadToBunny | Uploads a base64 image to Bunny CDN |
Environment Variables
| Variable | Required | Description |
|----------|----------|-------------|
| LINEAR_API_KEY | Yes | Linear API key |
| LINEAR_TEAM_ID | Yes | Linear team ID |
| LINEAR_BUG_LABEL_ID | No | Label for bug reports |
| LINEAR_FEATURE_LABEL_ID | No | Label for feature requests |
| LINEAR_WIDGET_LABEL_ID | No | Label for all submissions |
| LINEAR_PROJECT_ID | No | Default project ID |
| BUNNY_API_KEY | No | Bunny.net API key |
| BUNNY_STORAGE_ZONE | No | Bunny.net storage zone |
| BUNNY_CDN_HOSTNAME | No | Bunny.net CDN hostname |
License
MIT
