turbowrap-issue-widget 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/README.md ADDED
@@ -0,0 +1,116 @@
1
+ # @turbowrap/issue-widget
2
+
3
+ Embeddable chatbot widget for collecting issues via TurboWrap.
4
+
5
+ ## Installation
6
+
7
+ ### Script Tag (CDN)
8
+
9
+ ```html
10
+ <script>
11
+ window.IssueWidgetConfig = {
12
+ apiUrl: 'https://your-api.turbowrap.io',
13
+ apiKey: 'your_api_key',
14
+ teamId: 'your-linear-team-uuid'
15
+ };
16
+ </script>
17
+ <script src="https://cdn.jsdelivr.net/npm/@turbowrap/issue-widget@latest/dist/issue-widget.min.js" async></script>
18
+ ```
19
+
20
+ ### npm
21
+
22
+ ```bash
23
+ npm install @turbowrap/issue-widget
24
+ ```
25
+
26
+ ```javascript
27
+ import { IssueWidget } from '@turbowrap/issue-widget';
28
+
29
+ const widget = new IssueWidget({
30
+ apiUrl: 'https://your-api.turbowrap.io',
31
+ apiKey: 'your_api_key',
32
+ teamId: 'your-linear-team-uuid'
33
+ });
34
+ ```
35
+
36
+ ## Configuration
37
+
38
+ | Option | Type | Required | Default | Description |
39
+ |--------|------|----------|---------|-------------|
40
+ | `apiUrl` | string | Yes | - | TurboWrap API URL |
41
+ | `apiKey` | string | Yes | - | Widget API key |
42
+ | `teamId` | string | Yes | - | Linear team UUID |
43
+ | `position` | string | No | `'bottom-right'` | Button position: `'bottom-right'` or `'bottom-left'` |
44
+ | `theme` | string | No | `'auto'` | Theme: `'light'`, `'dark'`, or `'auto'` |
45
+ | `buttonText` | string | No | `'Report Issue'` | Floating button text |
46
+ | `accentColor` | string | No | `'#6366f1'` | Primary accent color (hex) |
47
+ | `autoScreenshot` | boolean | No | `false` | Auto-capture on widget open |
48
+ | `screenshotMethod` | string | No | `'auto'` | `'display-media'`, `'html2canvas'`, or `'auto'` |
49
+
50
+ ## Callbacks
51
+
52
+ ```javascript
53
+ window.IssueWidgetConfig = {
54
+ // ... required options ...
55
+
56
+ onOpen: () => {
57
+ console.log('Widget opened');
58
+ },
59
+
60
+ onClose: () => {
61
+ console.log('Widget closed');
62
+ },
63
+
64
+ onIssueCreated: (issue) => {
65
+ console.log('Issue created:', issue);
66
+ // issue: { id, identifier, url }
67
+ },
68
+
69
+ onError: (error) => {
70
+ console.error('Widget error:', error);
71
+ }
72
+ };
73
+ ```
74
+
75
+ ## Features
76
+
77
+ - **Screen Capture**: Uses `getDisplayMedia` API with `html2canvas` fallback
78
+ - **AI Analysis**: Gemini Vision analyzes screenshots, Claude generates clarifying questions
79
+ - **Linear Integration**: Creates issues directly in your Linear workspace
80
+ - **Shadow DOM**: Styles are isolated, no conflicts with host site CSS
81
+ - **Responsive**: Works on mobile and desktop
82
+ - **Dark Mode**: Automatic theme detection
83
+
84
+ ## Development
85
+
86
+ ```bash
87
+ # Install dependencies
88
+ npm install
89
+
90
+ # Development server
91
+ npm run dev
92
+
93
+ # Build for production
94
+ npm run build
95
+
96
+ # Type check
97
+ npm run typecheck
98
+ ```
99
+
100
+ ## Backend Configuration
101
+
102
+ The widget requires CORS enabled on your TurboWrap backend. Set the environment variable:
103
+
104
+ ```bash
105
+ TURBOWRAP_SERVER_CORS_ORIGINS=["https://your-customer-site.com"]
106
+ ```
107
+
108
+ Or for development (allow all):
109
+
110
+ ```bash
111
+ TURBOWRAP_SERVER_CORS_ORIGINS=["*"]
112
+ ```
113
+
114
+ ## License
115
+
116
+ MIT
@@ -0,0 +1,10 @@
1
+ import { WidgetConfig, AnalyzeRequest, AnalyzeResult, FinalizeRequest, IssueCreatedResult } from './types';
2
+ export declare class IssueAPIClient {
3
+ private baseUrl;
4
+ private apiKey;
5
+ private teamId;
6
+ constructor(config: WidgetConfig);
7
+ analyzeIssue(data: AnalyzeRequest, onProgress: (msg: string) => void, onComplete: (result: AnalyzeResult) => void, onError: (error: string) => void): Promise<void>;
8
+ finalizeIssue(data: FinalizeRequest, onProgress: (msg: string) => void, onComplete: (result: IssueCreatedResult) => void, onError: (error: string) => void): Promise<void>;
9
+ private parseSSEStream;
10
+ }
@@ -0,0 +1,51 @@
1
+ export interface WidgetConfig {
2
+ apiUrl: string;
3
+ apiKey: string;
4
+ teamId: string;
5
+ position?: 'bottom-right' | 'bottom-left';
6
+ theme?: 'light' | 'dark' | 'auto';
7
+ buttonText?: string;
8
+ accentColor?: string;
9
+ autoScreenshot?: boolean;
10
+ screenshotMethod?: 'display-media' | 'html2canvas' | 'auto';
11
+ onOpen?: () => void;
12
+ onClose?: () => void;
13
+ onIssueCreated?: (issue: IssueCreatedResult) => void;
14
+ onError?: (error: Error) => void;
15
+ }
16
+ export interface AnalyzeRequest {
17
+ title: string;
18
+ description: string;
19
+ screenshots: Blob[];
20
+ figmaLink?: string;
21
+ websiteLink?: string;
22
+ }
23
+ export interface Question {
24
+ id: number;
25
+ question: string;
26
+ why: string;
27
+ }
28
+ export interface AnalyzeResult {
29
+ questions: Question[];
30
+ geminiInsights: string;
31
+ tempSessionId: string;
32
+ }
33
+ export interface FinalizeRequest {
34
+ title: string;
35
+ description: string;
36
+ userAnswers: Record<number, string>;
37
+ geminiInsights: string;
38
+ teamId: string;
39
+ figmaLink?: string;
40
+ websiteLink?: string;
41
+ }
42
+ export interface IssueCreatedResult {
43
+ id: string;
44
+ identifier: string;
45
+ url: string;
46
+ }
47
+ export type SSEEventType = 'progress' | 'log' | 'complete' | 'error';
48
+ export interface SSEEvent {
49
+ event: SSEEventType;
50
+ data: unknown;
51
+ }
@@ -0,0 +1,5 @@
1
+ export type CaptureMethod = 'display-media' | 'html2canvas' | 'auto';
2
+ export declare function captureScreen(method?: CaptureMethod): Promise<Blob>;
3
+ export declare function supportsDisplayMedia(): boolean;
4
+ export declare function compressImage(blob: Blob, maxWidth?: number): Promise<Blob>;
5
+ export declare function blobToDataUrl(blob: Blob): Promise<string>;
@@ -0,0 +1,11 @@
1
+ import { IssueWidget } from './widget';
2
+ import { WidgetConfig } from './api/types';
3
+ export { IssueWidget };
4
+ export type { WidgetConfig };
5
+ export type { AnalyzeRequest, AnalyzeResult, FinalizeRequest, IssueCreatedResult, Question, } from './api/types';
6
+ declare global {
7
+ interface Window {
8
+ IssueWidgetConfig?: WidgetConfig;
9
+ IssueWidget?: IssueWidget;
10
+ }
11
+ }