jat-feedback 3.4.2 → 3.5.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jat-feedback",
3
- "version": "3.4.2",
3
+ "version": "3.5.0",
4
4
  "description": "Embeddable feedback widget for bug reports and feature requests. Captures screenshots, console logs, and user context as a web component.",
5
5
  "type": "module",
6
6
  "main": "dist/jat-feedback.js",
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Widget comments API — consumer route template.
3
+ * Copy to: src/routes/api/tasks/[id]/comments/+server.ts
4
+ *
5
+ * Requires jat-feedback v3.5.0 migration (external column on project_tasks_comments).
6
+ *
7
+ * GET ?external=true → external comments for a task (for widget thread view)
8
+ * POST → reporter posts a reply comment (always external=true)
9
+ */
10
+ import { json } from '@sveltejs/kit'
11
+ import type { RequestHandler } from './$types'
12
+
13
+ export const GET: RequestHandler = async ({ params, locals, url }) => {
14
+ const { id } = params
15
+ const externalOnly = url.searchParams.get('external') === 'true'
16
+
17
+ // Verify task exists
18
+ const { data: task, error: taskErr } = await locals.supabaseServiceRole
19
+ .from('project_tasks')
20
+ .select('id')
21
+ .eq('id', id)
22
+ .single()
23
+
24
+ if (taskErr || !task) {
25
+ return json({ error: 'Task not found' }, { status: 404 })
26
+ }
27
+
28
+ let query = locals.supabaseServiceRole
29
+ .from('project_tasks_comments')
30
+ .select('id, text, author, author_type, comment_type, external, created_at, metadata')
31
+ .eq('task_id', id)
32
+ .order('created_at', { ascending: true })
33
+
34
+ if (externalOnly) {
35
+ query = (query as any).eq('external', true)
36
+ }
37
+
38
+ const { data, error } = await query
39
+
40
+ if (error) {
41
+ return json({ error: error.message }, { status: 500 })
42
+ }
43
+
44
+ const comments = (data || []).map((c: any) => ({
45
+ ...c,
46
+ metadata: c.metadata ? safeParse(c.metadata) : null,
47
+ external: c.external !== false,
48
+ }))
49
+
50
+ return json({ comments })
51
+ }
52
+
53
+ export const POST: RequestHandler = async ({ params, request, locals }) => {
54
+ const { id } = params
55
+
56
+ let body: Record<string, unknown>
57
+ try {
58
+ body = await request.json()
59
+ } catch {
60
+ return json({ error: 'Invalid JSON body' }, { status: 400 })
61
+ }
62
+
63
+ const { text, author, author_email, author_type, comment_type, metadata } = body
64
+
65
+ if (!text || typeof text !== 'string' || !text.trim()) {
66
+ return json({ error: 'text is required' }, { status: 400 })
67
+ }
68
+ if (!author || typeof author !== 'string') {
69
+ return json({ error: 'author is required' }, { status: 400 })
70
+ }
71
+
72
+ // Verify task exists
73
+ const { data: task, error: taskErr } = await locals.supabaseServiceRole
74
+ .from('project_tasks')
75
+ .select('id')
76
+ .eq('id', id)
77
+ .single()
78
+
79
+ if (taskErr || !task) {
80
+ return json({ error: 'Task not found' }, { status: 404 })
81
+ }
82
+
83
+ const { data: comment, error } = await locals.supabaseServiceRole
84
+ .from('project_tasks_comments')
85
+ .insert({
86
+ task_id: id,
87
+ text: (text as string).trim(),
88
+ author,
89
+ author_type: author_type ?? 'user',
90
+ comment_type: comment_type ?? 'note',
91
+ external: true,
92
+ metadata: metadata != null ? JSON.stringify(metadata) : null,
93
+ })
94
+ .select('id, text, author, author_type, comment_type, external, created_at, metadata')
95
+ .single()
96
+
97
+ if (error) {
98
+ return json({ error: error.message }, { status: 500 })
99
+ }
100
+
101
+ return json({ comment: { ...comment, external: true } }, { status: 201 })
102
+ }
103
+
104
+ function safeParse(s: unknown) {
105
+ if (typeof s !== 'string') return s
106
+ try { return JSON.parse(s) } catch { return s }
107
+ }
@@ -0,0 +1,30 @@
1
+ -- jat-feedback v3.5.0 — Extended comments schema
2
+ --
3
+ -- Adds first-class fields for agent question/answer threads:
4
+ -- author_type TEXT -- 'agent' | 'user' | 'system'
5
+ -- comment_type TEXT -- 'question' | 'answer' | 'note' | 'event'
6
+ -- session_id TEXT -- agent session to resume on answer (NULL = human thread)
7
+ -- metadata TEXT -- JSON blob, extensible
8
+ -- external BOOLEAN -- true = visible to client; false = internal agent/team thread
9
+ --
10
+ -- All columns are additive and nullable-safe (IF NOT EXISTS guards).
11
+ -- Existing rows get external=true, preserving current behaviour where every
12
+ -- comment was visible everywhere.
13
+ --
14
+ -- Apply to each consuming project:
15
+ -- cp node_modules/jat-feedback/supabase/migrations/3.5.0_extend_comments_schema.sql \
16
+ -- supabase/migrations/$(date +%Y%m%d%H%M%S)_feedback_3_5_0.sql
17
+ -- supabase db push
18
+
19
+ ALTER TABLE project_tasks_comments
20
+ ADD COLUMN IF NOT EXISTS author_type TEXT,
21
+ ADD COLUMN IF NOT EXISTS comment_type TEXT,
22
+ ADD COLUMN IF NOT EXISTS session_id TEXT,
23
+ ADD COLUMN IF NOT EXISTS metadata TEXT,
24
+ ADD COLUMN IF NOT EXISTS external BOOLEAN NOT NULL DEFAULT true;
25
+
26
+ CREATE INDEX IF NOT EXISTS idx_project_tasks_comments_type
27
+ ON project_tasks_comments(task_id, comment_type);
28
+
29
+ CREATE INDEX IF NOT EXISTS idx_project_tasks_comments_external
30
+ ON project_tasks_comments(task_id, external);