@uncaughtdev/core 0.1.2 → 0.2.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.
Files changed (53) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +44 -3
  3. package/dist/chunk-2YXXFGBV.js +2 -0
  4. package/dist/chunk-2YXXFGBV.js.map +1 -0
  5. package/dist/chunk-3FCDO7OR.mjs +23 -0
  6. package/dist/chunk-3FCDO7OR.mjs.map +1 -0
  7. package/dist/chunk-A6GKDPT3.mjs +2 -0
  8. package/dist/chunk-A6GKDPT3.mjs.map +1 -0
  9. package/dist/chunk-BXMN7NW4.mjs +2 -0
  10. package/dist/chunk-BXMN7NW4.mjs.map +1 -0
  11. package/dist/chunk-HANXURHX.mjs +59 -0
  12. package/dist/chunk-HANXURHX.mjs.map +1 -0
  13. package/dist/chunk-MSUAXLMV.js +2 -0
  14. package/dist/chunk-MSUAXLMV.js.map +1 -0
  15. package/dist/chunk-VQXSHR3C.js +59 -0
  16. package/dist/chunk-VQXSHR3C.js.map +1 -0
  17. package/dist/chunk-WZBG5VLB.js +23 -0
  18. package/dist/chunk-WZBG5VLB.js.map +1 -0
  19. package/dist/index.d.mts +64 -3
  20. package/dist/index.d.ts +64 -3
  21. package/dist/index.js +7 -26
  22. package/dist/index.js.map +1 -1
  23. package/dist/index.mjs +7 -26
  24. package/dist/index.mjs.map +1 -1
  25. package/dist/local-api-handler-pages.js +1 -1
  26. package/dist/local-api-handler-pages.js.map +1 -1
  27. package/dist/local-api-handler-pages.mjs +1 -1
  28. package/dist/local-api-handler-pages.mjs.map +1 -1
  29. package/dist/local-api-handler.d.mts +1 -1
  30. package/dist/local-api-handler.d.ts +1 -1
  31. package/dist/local-api-handler.js +1 -1
  32. package/dist/local-api-handler.mjs +1 -1
  33. package/dist/local-viewer.js +422 -41
  34. package/dist/local-viewer.js.map +1 -1
  35. package/dist/local-viewer.mjs +422 -41
  36. package/dist/local-viewer.mjs.map +1 -1
  37. package/dist/mcp-server.d.mts +1 -0
  38. package/dist/mcp-server.d.ts +1 -0
  39. package/dist/mcp-server.js +22 -0
  40. package/dist/mcp-server.js.map +1 -0
  41. package/dist/mcp-server.mjs +22 -0
  42. package/dist/mcp-server.mjs.map +1 -0
  43. package/dist/sqlite-store-4FTNST7O.js +2 -0
  44. package/dist/sqlite-store-4FTNST7O.js.map +1 -0
  45. package/dist/sqlite-store-TEXDAAOM.mjs +2 -0
  46. package/dist/sqlite-store-TEXDAAOM.mjs.map +1 -0
  47. package/dist/{types-CjgYXVc_.d.mts → types-D1Fw4k-D.d.mts} +12 -1
  48. package/dist/{types-CjgYXVc_.d.ts → types-D1Fw4k-D.d.ts} +12 -1
  49. package/package.json +16 -9
  50. package/dist/chunk-FFHQ452Q.js +0 -2
  51. package/dist/chunk-FFHQ452Q.js.map +0 -1
  52. package/dist/chunk-JALIO2BZ.mjs +0 -2
  53. package/dist/chunk-JALIO2BZ.mjs.map +0 -1
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Uncaught Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -5,7 +5,7 @@ Core engine for [Uncaught](https://github.com/AjeeshDevops/uncaught) error monit
5
5
  ## Install
6
6
 
7
7
  ```bash
8
- npx uncaught init
8
+ npx uncaughtdev init
9
9
  ```
10
10
 
11
11
  Or manually:
@@ -21,8 +21,49 @@ npm install @uncaughtdev/core
21
21
  - PII sanitization
22
22
  - AI-ready fix prompt generation
23
23
  - Transport layer (console, local file, remote)
24
- - CLI viewer (`npx uncaught`)
25
- - Auto-setup command (`npx uncaught init`)
24
+ - SQLite storage backend with web dashboard
25
+ - Source map resolution for production stack traces
26
+ - Node.js process-level error handlers (`setupNodeHandlers`)
27
+ - Express error middleware (`expressErrorHandler`)
28
+ - Fastify error handler plugin (`fastifyErrorPlugin`)
29
+ - Webhook notifications for new error fingerprints
30
+ - Release tracking and environment filtering
31
+ - User feedback API (`submitFeedback`)
32
+ - MCP server for AI coding assistants (Cursor, Claude Code, Windsurf)
33
+ - CLI viewer (`npx uncaughtdev`)
34
+ - Auto-setup command (`npx uncaughtdev init`)
35
+
36
+ ## MCP Server
37
+
38
+ Exposes error data to AI coding assistants via Model Context Protocol:
39
+
40
+ ```bash
41
+ # Add to Cursor (~/.cursor/mcp.json):
42
+ { "mcpServers": { "uncaught": { "command": "npx", "args": ["-y", "@uncaughtdev/core", "uncaught-mcp"] } } }
43
+
44
+ # Add to Claude Code:
45
+ claude mcp add uncaught -- npx -y @uncaughtdev/core uncaught-mcp
46
+ ```
47
+
48
+ Tools: `setup_uncaught`, `list_errors`, `get_error`, `get_fix_prompt`, `get_stats`, `resolve_error`, `search_errors`
49
+
50
+ ## Server-Side Usage
51
+
52
+ ```typescript
53
+ import { initUncaught, setupNodeHandlers, expressErrorHandler } from '@uncaughtdev/core';
54
+
55
+ const client = initUncaught({
56
+ projectKey: 'my-api',
57
+ environment: 'production',
58
+ release: '1.2.0',
59
+ });
60
+
61
+ // Capture uncaughtException and unhandledRejection
62
+ setupNodeHandlers(client);
63
+
64
+ // Express error middleware (register after all routes)
65
+ app.use(expressErrorHandler(client));
66
+ ```
26
67
 
27
68
  ## License
28
69
 
@@ -0,0 +1,2 @@
1
+ 'use strict';var d=(a=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(a,{get:(b,c)=>(typeof require<"u"?require:b)[c]}):a)(function(a){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+a+'" is not supported')});exports.a=d;//# sourceMappingURL=chunk-2YXXFGBV.js.map
2
+ //# sourceMappingURL=chunk-2YXXFGBV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"chunk-2YXXFGBV.js"}
@@ -0,0 +1,23 @@
1
+ function f(r){let n=[];if(n.push(`I have a production bug in my application that I need help diagnosing and fixing.
2
+ `),r.error){let o=i(r.error.stack),t=["## Error",""];t.push(`- **Type:** ${r.error.type||"Error"}`),t.push(`- **Message:** ${r.error.message||"(no message)"}`),o&&t.push(`- **Location:** ${o}`),n.push(t.join(`
3
+ `));}let s=r.error?.resolvedStack??r.error?.stack;if(s){let o=s.split(`
4
+ `).slice(0,15).map(e=>e.trimEnd()).join(`
5
+ `),t=r.error?.resolvedStack?"Stack Trace (source-mapped)":"Stack Trace";n.push(`## ${t}
6
+
7
+ \`\`\`
8
+ ${o}
9
+ \`\`\``);}return r.operation&&n.push(a(r.operation)),r.request&&n.push(u(r.request)),r.breadcrumbs&&r.breadcrumbs.length>0&&n.push(c(r.breadcrumbs)),r.environment&&n.push(m(r.environment)),r.error?.componentStack&&n.push(`## React Component Stack
10
+
11
+ \`\`\`
12
+ ${r.error.componentStack.trim()}
13
+ \`\`\``),n.push(["## What I need","","1. **Root cause analysis** \u2014 explain why this error is occurring.","2. **A fix** \u2014 provide the corrected code with an explanation of the changes.","3. **Prevention** \u2014 suggest any guards or tests to prevent this from happening again."].join(`
14
+ `)),n.join(`
15
+
16
+ `)+`
17
+ `}function i(r){if(r)for(let n of r.split(`
18
+ `)){let s=n.trim(),o=s.match(/at\s+(?:.+?\s+\()?(.+?:\d+:\d+)\)?/);if(o)return o[1];let t=s.match(/@(.+?:\d+:\d+)/);if(t)return t[1]}}function a(r){let n=["## Failed Operation",""];return n.push(`- **Provider:** ${r.provider}`),n.push(`- **Type:** ${r.type}`),n.push(`- **Method:** ${r.method}`),r.params&&(n.push("- **Params:**"),n.push("```json"),n.push(JSON.stringify(r.params,null,2)),n.push("```")),r.errorCode&&n.push(`- **Error Code:** ${r.errorCode}`),r.errorDetails&&n.push(`- **Error Details:** ${r.errorDetails}`),n.join(`
19
+ `)}function u(r){let n=["## HTTP Request Context",""];return r.method&&n.push(`- **Method:** ${r.method}`),r.url&&n.push(`- **URL:** ${r.url}`),r.body&&(n.push("- **Body:**"),n.push("```json"),n.push(typeof r.body=="string"?r.body:JSON.stringify(r.body,null,2)),n.push("```")),n.join(`
20
+ `)}function c(r){let n=r.slice(-5),s=["## User Session",""];for(let o of n){let t=p(o.timestamp);s.push(`- \`${t}\` **[${o.type}]** ${o.message}`);}return s.join(`
21
+ `)}function p(r){try{let n=new Date(r),s=String(n.getHours()).padStart(2,"0"),o=String(n.getMinutes()).padStart(2,"0"),t=String(n.getSeconds()).padStart(2,"0");return `${s}:${o}:${t}`}catch{return r}}function m(r){let n=["## Environment",""],s=[["Deploy Environment",r.deploy],["Framework",r.framework],["Framework Version",r.frameworkVersion],["Runtime",r.runtime],["Runtime Version",r.runtimeVersion],["Platform",r.platform],["Browser",r.browser?`${r.browser} ${r.browserVersion??""}`.trim():void 0],["OS",r.os],["Device",r.deviceType],["Locale",r.locale],["Timezone",r.timezone],["URL",r.url]];for(let[o,t]of s)t&&n.push(`- **${o}:** ${t}`);return n.join(`
22
+ `)}export{f as a};//# sourceMappingURL=chunk-3FCDO7OR.mjs.map
23
+ //# sourceMappingURL=chunk-3FCDO7OR.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/prompt-builder.ts"],"names":["buildFixPrompt","event","sections","location","extractLocation","lines","stackSource","frames","l","label","formatOperation","formatRequest","formatBreadcrumbs","formatEnvironment","stack","line","trimmed","v8","sm","op","req","crumbs","recent","crumb","time","formatTime","iso","d","h","m","s","env","entries","value"],"mappings":"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","file":"chunk-3FCDO7OR.mjs","sourcesContent":["// ---------------------------------------------------------------------------\n// @uncaughtdev/core — fix-prompt builder\n// ---------------------------------------------------------------------------\n\nimport type { UncaughtEvent, Breadcrumb, EnvironmentInfo, OperationInfo, RequestInfo } from './types';\n\n/**\n * Build a structured Markdown prompt that can be pasted into an AI assistant\n * to diagnose and fix the production error described by `event`.\n *\n * Empty sections are omitted to keep the prompt concise.\n */\nexport function buildFixPrompt(event: Partial<UncaughtEvent>): string {\n const sections: string[] = [];\n\n // ----- Intro -------------------------------------------------------------\n sections.push(\n 'I have a production bug in my application that I need help diagnosing and fixing.\\n'\n );\n\n // ----- Error -------------------------------------------------------------\n if (event.error) {\n const location = extractLocation(event.error.stack);\n const lines: string[] = ['## Error', ''];\n lines.push(`- **Type:** ${event.error.type || 'Error'}`);\n lines.push(`- **Message:** ${event.error.message || '(no message)'}`);\n if (location) {\n lines.push(`- **Location:** ${location}`);\n }\n sections.push(lines.join('\\n'));\n }\n\n // ----- Stack Trace -------------------------------------------------------\n const stackSource = event.error?.resolvedStack ?? event.error?.stack;\n if (stackSource) {\n const frames = stackSource\n .split('\\n')\n .slice(0, 15)\n .map((l) => l.trimEnd())\n .join('\\n');\n const label = event.error?.resolvedStack ? 'Stack Trace (source-mapped)' : 'Stack Trace';\n sections.push(`## ${label}\\n\\n\\`\\`\\`\\n${frames}\\n\\`\\`\\``);\n }\n\n // ----- Failed Operation --------------------------------------------------\n if (event.operation) {\n sections.push(formatOperation(event.operation));\n }\n\n // ----- HTTP Request Context ----------------------------------------------\n if (event.request) {\n sections.push(formatRequest(event.request));\n }\n\n // ----- User Session (last 5 breadcrumbs) ---------------------------------\n if (event.breadcrumbs && event.breadcrumbs.length > 0) {\n sections.push(formatBreadcrumbs(event.breadcrumbs));\n }\n\n // ----- Environment -------------------------------------------------------\n if (event.environment) {\n sections.push(formatEnvironment(event.environment));\n }\n\n // ----- React Component Stack ---------------------------------------------\n if (event.error?.componentStack) {\n sections.push(\n `## React Component Stack\\n\\n\\`\\`\\`\\n${event.error.componentStack.trim()}\\n\\`\\`\\``\n );\n }\n\n // ----- What I need -------------------------------------------------------\n sections.push(\n [\n '## What I need',\n '',\n '1. **Root cause analysis** — explain why this error is occurring.',\n '2. **A fix** — provide the corrected code with an explanation of the changes.',\n '3. **Prevention** — suggest any guards or tests to prevent this from happening again.',\n ].join('\\n')\n );\n\n return sections.join('\\n\\n') + '\\n';\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Extract the top-most location (file:line:col) from a stack trace string.\n */\nfunction extractLocation(stack?: string): string | undefined {\n if (!stack) return undefined;\n\n for (const line of stack.split('\\n')) {\n const trimmed = line.trim();\n\n // V8: \" at fn (file:line:col)\"\n const v8 = trimmed.match(/at\\s+(?:.+?\\s+\\()?(.+?:\\d+:\\d+)\\)?/);\n if (v8) return v8[1];\n\n // SpiderMonkey / JSC: \"fn@file:line:col\"\n const sm = trimmed.match(/@(.+?:\\d+:\\d+)/);\n if (sm) return sm[1];\n }\n\n return undefined;\n}\n\nfunction formatOperation(op: OperationInfo): string {\n const lines: string[] = ['## Failed Operation', ''];\n lines.push(`- **Provider:** ${op.provider}`);\n lines.push(`- **Type:** ${op.type}`);\n lines.push(`- **Method:** ${op.method}`);\n if (op.params) {\n lines.push(`- **Params:**`);\n lines.push('```json');\n lines.push(JSON.stringify(op.params, null, 2));\n lines.push('```');\n }\n if (op.errorCode) {\n lines.push(`- **Error Code:** ${op.errorCode}`);\n }\n if (op.errorDetails) {\n lines.push(`- **Error Details:** ${op.errorDetails}`);\n }\n return lines.join('\\n');\n}\n\nfunction formatRequest(req: RequestInfo): string {\n const lines: string[] = ['## HTTP Request Context', ''];\n if (req.method) lines.push(`- **Method:** ${req.method}`);\n if (req.url) lines.push(`- **URL:** ${req.url}`);\n if (req.body) {\n lines.push(`- **Body:**`);\n lines.push('```json');\n lines.push(\n typeof req.body === 'string'\n ? req.body\n : JSON.stringify(req.body, null, 2)\n );\n lines.push('```');\n }\n return lines.join('\\n');\n}\n\nfunction formatBreadcrumbs(crumbs: Breadcrumb[]): string {\n // Take the last 5 breadcrumbs\n const recent = crumbs.slice(-5);\n const lines: string[] = ['## User Session', ''];\n\n for (const crumb of recent) {\n const time = formatTime(crumb.timestamp);\n lines.push(`- \\`${time}\\` **[${crumb.type}]** ${crumb.message}`);\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Extract HH:MM:SS from an ISO timestamp.\n */\nfunction formatTime(iso: string): string {\n try {\n const d = new Date(iso);\n const h = String(d.getHours()).padStart(2, '0');\n const m = String(d.getMinutes()).padStart(2, '0');\n const s = String(d.getSeconds()).padStart(2, '0');\n return `${h}:${m}:${s}`;\n } catch {\n return iso;\n }\n}\n\nfunction formatEnvironment(env: EnvironmentInfo): string {\n const lines: string[] = ['## Environment', ''];\n const entries: Array<[string, string | undefined]> = [\n ['Deploy Environment', env.deploy],\n ['Framework', env.framework],\n ['Framework Version', env.frameworkVersion],\n ['Runtime', env.runtime],\n ['Runtime Version', env.runtimeVersion],\n ['Platform', env.platform],\n ['Browser', env.browser ? `${env.browser} ${env.browserVersion ?? ''}`.trim() : undefined],\n ['OS', env.os],\n ['Device', env.deviceType],\n ['Locale', env.locale],\n ['Timezone', env.timezone],\n ['URL', env.url],\n ];\n\n for (const [label, value] of entries) {\n if (value) {\n lines.push(`- **${label}:** ${value}`);\n }\n }\n\n return lines.join('\\n');\n}\n"]}
@@ -0,0 +1,2 @@
1
+ var d=(a=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(a,{get:(b,c)=>(typeof require<"u"?require:b)[c]}):a)(function(a){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+a+'" is not supported')});export{d as a};//# sourceMappingURL=chunk-A6GKDPT3.mjs.map
2
+ //# sourceMappingURL=chunk-A6GKDPT3.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"chunk-A6GKDPT3.mjs"}
@@ -0,0 +1,2 @@
1
+ import {b}from'./chunk-P6JRN5CN.mjs';async function N(a){try{if(typeof process<"u"&&process.env.NODE_ENV==="production"&&process.env.UNCAUGHT_LOCAL_IN_PROD!=="true")return new Response(JSON.stringify({error:"Local handler is disabled in production"}),{status:403,headers:{"Content-Type":"application/json"}});let t;try{t=await a.json();}catch{return new Response(JSON.stringify({error:"Invalid JSON body"}),{status:400,headers:{"Content-Type":"application/json"}})}if(!t||typeof t!="object"||!Array.isArray(t.events))return new Response(JSON.stringify({error:'Payload must contain an "events" array'}),{status:400,headers:{"Content-Type":"application/json"}});let n=t.events;return n.length===0?new Response(JSON.stringify({accepted:0}),{status:202,headers:{"Content-Type":"application/json"}}):(await O(n),new Response(JSON.stringify({accepted:n.length}),{status:202,headers:{"Content-Type":"application/json"}}))}catch(t){let n=t instanceof Error?t.message:"Internal server error";return new Response(JSON.stringify({error:n}),{status:500,headers:{"Content-Type":"application/json"}})}}async function O(a){let t=await import('fs/promises'),n=await import('path'),i=n.resolve(process.cwd(),".uncaught");await t.mkdir(n.join(i,"events"),{recursive:true}),await t.mkdir(n.join(i,"fix-prompts"),{recursive:true});let c=n.join(i,"issues.json"),p=[];try{let e=await t.readFile(c,"utf-8");p=JSON.parse(e);}catch{}for(let e of a){let r=e.fingerprint;if(!r)continue;let o=n.join(i,"events",r);await t.mkdir(o,{recursive:true});let f=`event-${(e.timestamp??new Date().toISOString()).replace(/[:.]/g,"-")}.json`,y=n.join(o,f),g=y+".tmp";await t.writeFile(g,b(e),"utf-8"),await t.rename(g,y);let v=n.join(o,"latest.json"),h=v+".tmp";await t.writeFile(h,b(e),"utf-8"),await t.rename(h,v);let m=`${r}.md`,S=n.join(i,"fix-prompts",m),j=S+".tmp";await t.writeFile(j,e.fixPrompt??"","utf-8"),await t.rename(j,S);let d=e.user?.id??e.user?.email??"anonymous",s=p.find(E=>E.fingerprint===r);s?(s.count+=1,s.lastSeen=e.timestamp,s.latestEventFile=f,s.fixPromptFile=m,s.affectedUsers.includes(String(d))||s.affectedUsers.push(String(d)),s.status==="resolved"&&(s.status="open")):p.push({fingerprint:r,title:e.error?.message??"Unknown error",errorType:e.error?.type??"Error",count:1,affectedUsers:[String(d)],firstSeen:e.timestamp,lastSeen:e.timestamp,status:"open",fixPromptFile:m,latestEventFile:f});}let w=c+".tmp";await t.writeFile(w,JSON.stringify(p,null,2),"utf-8"),await t.rename(w,c);try{let{openStore:e}=await import('./sqlite-store-TEXDAAOM.mjs'),r=n.join(i,"uncaught.db"),o=e(r);for(let u of a)u.fingerprint&&o.insertEvent(u);o.close();}catch{}}export{N as a,O as b};//# sourceMappingURL=chunk-BXMN7NW4.mjs.map
2
+ //# sourceMappingURL=chunk-BXMN7NW4.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/local-api-handler.ts"],"names":["POST","request","body","events","writeEvents","err","message","fs","path","baseDir","indexPath","issues","raw","event","fp","eventDir","eventFile","eventPath","tmpEvent","safeStringify","latestPath","tmpLatest","promptFile","promptPath","tmpPrompt","userId","existing","i","tmpIndex","openStore","dbPath","store"],"mappings":"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","file":"chunk-BXMN7NW4.mjs","sourcesContent":["// ---------------------------------------------------------------------------\n// @uncaughtdev/core — Next.js App Router local API handler\n// ---------------------------------------------------------------------------\n//\n// Usage:\n// // app/api/uncaught/local/route.ts\n// export { POST } from '@uncaughtdev/core/local-api-handler';\n//\n// ---------------------------------------------------------------------------\n\nimport type { UncaughtEvent, IssueEntry } from './types';\nimport { safeStringify } from './utils';\n\n/**\n * Next.js App Router POST handler.\n * Accepts `{ events: UncaughtEvent[] }` and writes them to `.uncaught/`.\n *\n * Blocked in production unless `UNCAUGHT_LOCAL_IN_PROD=true` is set.\n */\nexport async function POST(request: Request): Promise<Response> {\n try {\n // --- Production guard --------------------------------------------------\n if (\n typeof process !== 'undefined' &&\n process.env.NODE_ENV === 'production' &&\n process.env.UNCAUGHT_LOCAL_IN_PROD !== 'true'\n ) {\n return new Response(\n JSON.stringify({ error: 'Local handler is disabled in production' }),\n { status: 403, headers: { 'Content-Type': 'application/json' } }\n );\n }\n\n // --- Parse body --------------------------------------------------------\n let body: unknown;\n try {\n body = await request.json();\n } catch {\n return new Response(\n JSON.stringify({ error: 'Invalid JSON body' }),\n { status: 400, headers: { 'Content-Type': 'application/json' } }\n );\n }\n\n if (\n !body ||\n typeof body !== 'object' ||\n !Array.isArray((body as Record<string, unknown>).events)\n ) {\n return new Response(\n JSON.stringify({ error: 'Payload must contain an \"events\" array' }),\n { status: 400, headers: { 'Content-Type': 'application/json' } }\n );\n }\n\n const events = (body as { events: UncaughtEvent[] }).events;\n\n if (events.length === 0) {\n return new Response(\n JSON.stringify({ accepted: 0 }),\n { status: 202, headers: { 'Content-Type': 'application/json' } }\n );\n }\n\n // --- Write events to disk ----------------------------------------------\n await writeEvents(events);\n\n return new Response(\n JSON.stringify({ accepted: events.length }),\n { status: 202, headers: { 'Content-Type': 'application/json' } }\n );\n } catch (err) {\n const message =\n err instanceof Error ? err.message : 'Internal server error';\n return new Response(\n JSON.stringify({ error: message }),\n { status: 500, headers: { 'Content-Type': 'application/json' } }\n );\n }\n}\n\n// ---------------------------------------------------------------------------\n// Shared disk-writing logic\n// ---------------------------------------------------------------------------\n\nexport async function writeEvents(events: UncaughtEvent[]): Promise<void> {\n const fs = await import('fs/promises');\n const path = await import('path');\n\n const baseDir = path.resolve(process.cwd(), '.uncaught');\n await fs.mkdir(path.join(baseDir, 'events'), { recursive: true });\n await fs.mkdir(path.join(baseDir, 'fix-prompts'), { recursive: true });\n\n // Load existing issues index\n const indexPath = path.join(baseDir, 'issues.json');\n let issues: IssueEntry[] = [];\n try {\n const raw = await fs.readFile(indexPath, 'utf-8');\n issues = JSON.parse(raw) as IssueEntry[];\n } catch {\n // Start fresh.\n }\n\n for (const event of events) {\n const fp = event.fingerprint;\n if (!fp) continue;\n\n const eventDir = path.join(baseDir, 'events', fp);\n await fs.mkdir(eventDir, { recursive: true });\n\n // Timestamped event file\n const ts = (event.timestamp ?? new Date().toISOString()).replace(\n /[:.]/g,\n '-'\n );\n const eventFile = `event-${ts}.json`;\n const eventPath = path.join(eventDir, eventFile);\n const tmpEvent = eventPath + '.tmp';\n await fs.writeFile(tmpEvent, safeStringify(event), 'utf-8');\n await fs.rename(tmpEvent, eventPath);\n\n // latest.json\n const latestPath = path.join(eventDir, 'latest.json');\n const tmpLatest = latestPath + '.tmp';\n await fs.writeFile(tmpLatest, safeStringify(event), 'utf-8');\n await fs.rename(tmpLatest, latestPath);\n\n // Fix-prompt markdown\n const promptFile = `${fp}.md`;\n const promptPath = path.join(baseDir, 'fix-prompts', promptFile);\n const tmpPrompt = promptPath + '.tmp';\n await fs.writeFile(tmpPrompt, event.fixPrompt ?? '', 'utf-8');\n await fs.rename(tmpPrompt, promptPath);\n\n // Update issues index\n const userId =\n (event.user as Record<string, unknown> | undefined)?.id ??\n (event.user as Record<string, unknown> | undefined)?.email ??\n 'anonymous';\n\n const existing = issues.find((i) => i.fingerprint === fp);\n if (existing) {\n existing.count += 1;\n existing.lastSeen = event.timestamp;\n existing.latestEventFile = eventFile;\n existing.fixPromptFile = promptFile;\n if (!existing.affectedUsers.includes(String(userId))) {\n existing.affectedUsers.push(String(userId));\n }\n if (existing.status === 'resolved') {\n existing.status = 'open';\n }\n } else {\n issues.push({\n fingerprint: fp,\n title: event.error?.message ?? 'Unknown error',\n errorType: event.error?.type ?? 'Error',\n count: 1,\n affectedUsers: [String(userId)],\n firstSeen: event.timestamp,\n lastSeen: event.timestamp,\n status: 'open',\n fixPromptFile: promptFile,\n latestEventFile: eventFile,\n });\n }\n }\n\n // Write updated index atomically\n const tmpIndex = indexPath + '.tmp';\n await fs.writeFile(tmpIndex, JSON.stringify(issues, null, 2), 'utf-8');\n await fs.rename(tmpIndex, indexPath);\n\n // Also write to SQLite\n try {\n const { openStore } = await import('./sqlite-store');\n const dbPath = path.join(baseDir, 'uncaught.db');\n const store = openStore(dbPath);\n for (const event of events) {\n if (!event.fingerprint) continue;\n store.insertEvent(event);\n }\n store.close();\n } catch {\n // SQLite is best-effort — flat files are the primary store\n }\n}\n"]}
@@ -0,0 +1,59 @@
1
+ import {a}from'./chunk-A6GKDPT3.mjs';import G from'better-sqlite3';var W=`
2
+ CREATE TABLE IF NOT EXISTS issues (
3
+ fingerprint TEXT PRIMARY KEY,
4
+ title TEXT NOT NULL,
5
+ error_type TEXT NOT NULL,
6
+ count INTEGER NOT NULL DEFAULT 1,
7
+ affected_users TEXT NOT NULL DEFAULT '[]',
8
+ first_seen TEXT NOT NULL,
9
+ last_seen TEXT NOT NULL,
10
+ status TEXT NOT NULL DEFAULT 'open',
11
+ fix_prompt_file TEXT NOT NULL DEFAULT '',
12
+ latest_event_file TEXT NOT NULL DEFAULT '',
13
+ release TEXT NOT NULL DEFAULT '',
14
+ environment TEXT NOT NULL DEFAULT ''
15
+ );
16
+
17
+ CREATE INDEX IF NOT EXISTS idx_issues_status ON issues(status);
18
+ CREATE INDEX IF NOT EXISTS idx_issues_last_seen ON issues(last_seen);
19
+
20
+ CREATE TABLE IF NOT EXISTS events (
21
+ event_id TEXT PRIMARY KEY,
22
+ fingerprint TEXT NOT NULL,
23
+ timestamp TEXT NOT NULL,
24
+ level TEXT NOT NULL DEFAULT 'error',
25
+ fix_prompt TEXT NOT NULL DEFAULT '',
26
+ payload TEXT NOT NULL,
27
+ FOREIGN KEY (fingerprint) REFERENCES issues(fingerprint)
28
+ );
29
+
30
+ CREATE INDEX IF NOT EXISTS idx_events_fingerprint ON events(fingerprint);
31
+ CREATE INDEX IF NOT EXISTS idx_events_timestamp ON events(timestamp);
32
+
33
+ CREATE TABLE IF NOT EXISTS _meta (
34
+ key TEXT PRIMARY KEY,
35
+ value TEXT NOT NULL
36
+ );
37
+ `,Y=`
38
+ ALTER TABLE issues ADD COLUMN release TEXT NOT NULL DEFAULT '';
39
+ ALTER TABLE issues ADD COLUMN environment TEXT NOT NULL DEFAULT '';
40
+ `;function H(I){let t=new G(I);t.pragma("journal_mode = WAL"),t.pragma("foreign_keys = ON"),t.exec(W);try{for(let e of Y.trim().split(";").filter(Boolean))try{t.exec(e+";");}catch{}}catch{}let p=t.prepare(`
41
+ INSERT INTO issues (fingerprint, title, error_type, count, affected_users, first_seen, last_seen, status, fix_prompt_file, latest_event_file, release, environment)
42
+ VALUES (@fingerprint, @title, @error_type, @count, @affected_users, @first_seen, @last_seen, @status, @fix_prompt_file, @latest_event_file, @release, @environment)
43
+ ON CONFLICT(fingerprint) DO UPDATE SET
44
+ title = @title,
45
+ error_type = @error_type,
46
+ count = @count,
47
+ affected_users = @affected_users,
48
+ first_seen = @first_seen,
49
+ last_seen = @last_seen,
50
+ status = @status,
51
+ fix_prompt_file = @fix_prompt_file,
52
+ latest_event_file = @latest_event_file,
53
+ release = @release,
54
+ environment = @environment
55
+ `),O=t.prepare("SELECT * FROM issues ORDER BY last_seen DESC"),R=t.prepare("SELECT * FROM issues WHERE status = ? ORDER BY last_seen DESC"),U=t.prepare("SELECT * FROM issues WHERE environment = ? ORDER BY last_seen DESC"),F=t.prepare("SELECT * FROM issues WHERE status = ? AND environment = ? ORDER BY last_seen DESC"),d=t.prepare("SELECT * FROM issues WHERE fingerprint = ?"),A=t.prepare("UPDATE issues SET status = ? WHERE fingerprint = ?"),y=t.prepare("DELETE FROM issues"),C=t.prepare("DELETE FROM events"),S=t.prepare(`
56
+ INSERT OR IGNORE INTO events (event_id, fingerprint, timestamp, level, fix_prompt, payload)
57
+ VALUES (@event_id, @fingerprint, @timestamp, @level, @fix_prompt, @payload)
58
+ `),D=t.prepare("SELECT * FROM events WHERE fingerprint = ? ORDER BY timestamp DESC LIMIT ? OFFSET ?"),X=t.prepare("SELECT * FROM events WHERE fingerprint = ? ORDER BY timestamp DESC LIMIT 1"),x=t.prepare("SELECT COUNT(*) as cnt FROM events WHERE fingerprint = ?"),M=t.prepare("SELECT value FROM _meta WHERE key = ?"),b=t.prepare("INSERT OR REPLACE INTO _meta (key, value) VALUES (?, ?)"),h=t.prepare("SELECT COUNT(*) as cnt FROM issues"),m=t.prepare("SELECT COUNT(*) as cnt FROM issues WHERE status = ?"),B=t.prepare("SELECT COUNT(*) as cnt FROM events");function T(e){return {fingerprint:e.fingerprint,title:e.title,errorType:e.error_type,count:e.count,affectedUsers:JSON.parse(e.affected_users),firstSeen:e.first_seen,lastSeen:e.last_seen,status:e.status,fixPromptFile:e.fix_prompt_file,latestEventFile:e.latest_event_file,release:e.release||void 0,environment:e.environment||void 0}}function l(e){return {fingerprint:e.fingerprint,title:e.title,error_type:e.errorType,count:e.count,affected_users:JSON.stringify(e.affectedUsers),first_seen:e.firstSeen,last_seen:e.lastSeen,status:e.status,fix_prompt_file:e.fixPromptFile,latest_event_file:e.latestEventFile,release:e.release??"",environment:e.environment??""}}function _(e){return JSON.parse(e.payload)}let P=t.transaction((e,s,a)=>{let i=e.fingerprint,r=e.user?.id??e.user?.email??"anonymous";S.run({event_id:e.eventId,fingerprint:i,timestamp:e.timestamp,level:e.level,fix_prompt:e.fixPrompt??"",payload:JSON.stringify(e)});let o=d.get(i);if(o){let n=T(o);n.count+=1,n.lastSeen=e.timestamp,n.latestEventFile=s,n.fixPromptFile=a,n.release=e.release??n.release,n.environment=e.environment?.deploy??n.environment,n.affectedUsers.includes(String(r))||n.affectedUsers.push(String(r)),n.status==="resolved"&&(n.status="open"),p.run(l(n));}else p.run(l({fingerprint:i,title:e.error?.message??"Unknown error",errorType:e.error?.type??"Error",count:1,affectedUsers:[String(r)],firstSeen:e.timestamp,lastSeen:e.timestamp,status:"open",fixPromptFile:a,latestEventFile:s,release:e.release,environment:e.environment?.deploy}));});return {upsertIssue(e){p.run(l(e));},getIssues(e){let s;return e?.status&&e?.environment?s=F.all(e.status,e.environment):e?.status?s=R.all(e.status):e?.environment?s=U.all(e.environment):s=O.all(),s.map(T)},getIssue(e){let s=d.get(e);return s?T(s):void 0},updateIssueStatus(e,s){A.run(s,e);},deleteAllIssues(){C.run(),y.run();},insertEvent(e){let a=`event-${(e.timestamp??new Date().toISOString()).replace(/[:.]/g,"-")}.json`,i=`${e.fingerprint}.md`;P(e,a,i);},getEvents(e,s){let a=s?.limit??50,i=s?.offset??0;return D.all(e,a,i).map(_)},getLatestEvent(e){let s=X.get(e);return s?_(s):void 0},getEventCount(e){return x.get(e).cnt},getStats(){return {total:h.get().cnt,open:m.get("open").cnt,resolved:m.get("resolved").cnt,ignored:m.get("ignored").cnt,totalEvents:B.get().cnt}},importFromFiles(e){if(M.get("migrated")?.value==="true")return {issues:0,events:0};let a$1=0,i=0;try{let r=a("fs"),o=a("path"),n=o.join(e,"issues.json");if(r.existsSync(n)){let g=r.readFileSync(n,"utf-8"),v=JSON.parse(g);for(let u of v)p.run(l(u)),a$1++;}let c=o.join(e,"events");if(r.existsSync(c)){let g=r.readdirSync(c);for(let v of g){let u=o.join(c,v);if(!r.statSync(u).isDirectory())continue;let k=r.readdirSync(u).filter(f=>f.startsWith("event-")&&f.endsWith(".json"));for(let f of k)try{let L=r.readFileSync(o.join(u,f),"utf-8"),E=JSON.parse(L);S.run({event_id:E.eventId,fingerprint:E.fingerprint,timestamp:E.timestamp,level:E.level,fix_prompt:E.fixPrompt??"",payload:L}),i++;}catch{}}}}catch{}return b.run("migrated","true"),{issues:a$1,events:i}},close(){t.close();}}}export{H as a};//# sourceMappingURL=chunk-HANXURHX.mjs.map
59
+ //# sourceMappingURL=chunk-HANXURHX.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/sqlite-store.ts"],"names":["SCHEMA_SQL","MIGRATION_SQL","openStore","dbPath","db","Database","stmt","stmtUpsertIssue","stmtGetIssues","stmtGetIssuesByStatus","stmtGetIssuesByEnv","stmtGetIssuesByStatusAndEnv","stmtGetIssue","stmtUpdateStatus","stmtDeleteAllIssues","stmtDeleteAllEvents","stmtInsertEvent","stmtGetEvents","stmtGetLatestEvent","stmtGetEventCount","stmtGetMeta","stmtSetMeta","stmtCountAll","stmtCountByStatus","stmtCountEvents","rowToIssue","row","issueToParams","entry","rowToEvent","insertEventAndUpsert","event","eventFile","promptFile","fp","userId","existingRow","existing","filter","rows","fingerprint","status","opts","limit","offset","baseDir","issueCount","eventCount","fsSync","N","pathMod","issuesPath","raw","issues","issue","eventsDir","fps","fpDir","files","file","eventRaw"],"mappings":"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","file":"chunk-HANXURHX.mjs","sourcesContent":["// ---------------------------------------------------------------------------\n// @uncaughtdev/core — SQLite storage layer\n// ---------------------------------------------------------------------------\n\nimport Database from 'better-sqlite3';\nimport type { IssueEntry, IssueStatus, UncaughtEvent } from './types';\n\n// ---------------------------------------------------------------------------\n// Schema\n// ---------------------------------------------------------------------------\n\nconst SCHEMA_SQL = `\nCREATE TABLE IF NOT EXISTS issues (\n fingerprint TEXT PRIMARY KEY,\n title TEXT NOT NULL,\n error_type TEXT NOT NULL,\n count INTEGER NOT NULL DEFAULT 1,\n affected_users TEXT NOT NULL DEFAULT '[]',\n first_seen TEXT NOT NULL,\n last_seen TEXT NOT NULL,\n status TEXT NOT NULL DEFAULT 'open',\n fix_prompt_file TEXT NOT NULL DEFAULT '',\n latest_event_file TEXT NOT NULL DEFAULT '',\n release TEXT NOT NULL DEFAULT '',\n environment TEXT NOT NULL DEFAULT ''\n);\n\nCREATE INDEX IF NOT EXISTS idx_issues_status ON issues(status);\nCREATE INDEX IF NOT EXISTS idx_issues_last_seen ON issues(last_seen);\n\nCREATE TABLE IF NOT EXISTS events (\n event_id TEXT PRIMARY KEY,\n fingerprint TEXT NOT NULL,\n timestamp TEXT NOT NULL,\n level TEXT NOT NULL DEFAULT 'error',\n fix_prompt TEXT NOT NULL DEFAULT '',\n payload TEXT NOT NULL,\n FOREIGN KEY (fingerprint) REFERENCES issues(fingerprint)\n);\n\nCREATE INDEX IF NOT EXISTS idx_events_fingerprint ON events(fingerprint);\nCREATE INDEX IF NOT EXISTS idx_events_timestamp ON events(timestamp);\n\nCREATE TABLE IF NOT EXISTS _meta (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL\n);\n`;\n\n// Migrate existing databases that lack new columns\nconst MIGRATION_SQL = `\nALTER TABLE issues ADD COLUMN release TEXT NOT NULL DEFAULT '';\nALTER TABLE issues ADD COLUMN environment TEXT NOT NULL DEFAULT '';\n`;\n\n// ---------------------------------------------------------------------------\n// Public interface\n// ---------------------------------------------------------------------------\n\nexport interface SqliteStore {\n upsertIssue(entry: IssueEntry): void;\n getIssues(filter?: { status?: IssueStatus; environment?: string }): IssueEntry[];\n getIssue(fingerprint: string): IssueEntry | undefined;\n updateIssueStatus(fingerprint: string, status: IssueStatus): void;\n deleteAllIssues(): void;\n\n insertEvent(event: UncaughtEvent): void;\n getEvents(fingerprint: string, opts?: { limit?: number; offset?: number }): UncaughtEvent[];\n getLatestEvent(fingerprint: string): UncaughtEvent | undefined;\n getEventCount(fingerprint: string): number;\n\n getStats(): { total: number; open: number; resolved: number; ignored: number; totalEvents: number };\n\n importFromFiles(baseDir: string): { issues: number; events: number };\n\n close(): void;\n}\n\n// ---------------------------------------------------------------------------\n// Implementation\n// ---------------------------------------------------------------------------\n\nexport function openStore(dbPath: string): SqliteStore {\n const db = new Database(dbPath);\n db.pragma('journal_mode = WAL');\n db.pragma('foreign_keys = ON');\n db.exec(SCHEMA_SQL);\n\n // Run migrations for existing databases\n try {\n for (const stmt of MIGRATION_SQL.trim().split(';').filter(Boolean)) {\n try { db.exec(stmt + ';'); } catch { /* column already exists */ }\n }\n } catch { /* migration best-effort */ }\n\n // Prepared statements\n const stmtUpsertIssue = db.prepare(`\n INSERT INTO issues (fingerprint, title, error_type, count, affected_users, first_seen, last_seen, status, fix_prompt_file, latest_event_file, release, environment)\n VALUES (@fingerprint, @title, @error_type, @count, @affected_users, @first_seen, @last_seen, @status, @fix_prompt_file, @latest_event_file, @release, @environment)\n ON CONFLICT(fingerprint) DO UPDATE SET\n title = @title,\n error_type = @error_type,\n count = @count,\n affected_users = @affected_users,\n first_seen = @first_seen,\n last_seen = @last_seen,\n status = @status,\n fix_prompt_file = @fix_prompt_file,\n latest_event_file = @latest_event_file,\n release = @release,\n environment = @environment\n `);\n\n const stmtGetIssues = db.prepare('SELECT * FROM issues ORDER BY last_seen DESC');\n const stmtGetIssuesByStatus = db.prepare('SELECT * FROM issues WHERE status = ? ORDER BY last_seen DESC');\n const stmtGetIssuesByEnv = db.prepare('SELECT * FROM issues WHERE environment = ? ORDER BY last_seen DESC');\n const stmtGetIssuesByStatusAndEnv = db.prepare('SELECT * FROM issues WHERE status = ? AND environment = ? ORDER BY last_seen DESC');\n const stmtGetIssue = db.prepare('SELECT * FROM issues WHERE fingerprint = ?');\n const stmtUpdateStatus = db.prepare('UPDATE issues SET status = ? WHERE fingerprint = ?');\n const stmtDeleteAllIssues = db.prepare('DELETE FROM issues');\n const stmtDeleteAllEvents = db.prepare('DELETE FROM events');\n\n const stmtInsertEvent = db.prepare(`\n INSERT OR IGNORE INTO events (event_id, fingerprint, timestamp, level, fix_prompt, payload)\n VALUES (@event_id, @fingerprint, @timestamp, @level, @fix_prompt, @payload)\n `);\n\n const stmtGetEvents = db.prepare('SELECT * FROM events WHERE fingerprint = ? ORDER BY timestamp DESC LIMIT ? OFFSET ?');\n const stmtGetLatestEvent = db.prepare('SELECT * FROM events WHERE fingerprint = ? ORDER BY timestamp DESC LIMIT 1');\n const stmtGetEventCount = db.prepare('SELECT COUNT(*) as cnt FROM events WHERE fingerprint = ?');\n\n const stmtGetMeta = db.prepare('SELECT value FROM _meta WHERE key = ?');\n const stmtSetMeta = db.prepare('INSERT OR REPLACE INTO _meta (key, value) VALUES (?, ?)');\n\n const stmtCountAll = db.prepare('SELECT COUNT(*) as cnt FROM issues');\n const stmtCountByStatus = db.prepare('SELECT COUNT(*) as cnt FROM issues WHERE status = ?');\n const stmtCountEvents = db.prepare('SELECT COUNT(*) as cnt FROM events');\n\n // Row → IssueEntry mapper\n function rowToIssue(row: Record<string, unknown>): IssueEntry {\n return {\n fingerprint: row.fingerprint as string,\n title: row.title as string,\n errorType: row.error_type as string,\n count: row.count as number,\n affectedUsers: JSON.parse(row.affected_users as string),\n firstSeen: row.first_seen as string,\n lastSeen: row.last_seen as string,\n status: row.status as IssueStatus,\n fixPromptFile: row.fix_prompt_file as string,\n latestEventFile: row.latest_event_file as string,\n release: (row.release as string) || undefined,\n environment: (row.environment as string) || undefined,\n };\n }\n\n // IssueEntry → row params mapper\n function issueToParams(entry: IssueEntry) {\n return {\n fingerprint: entry.fingerprint,\n title: entry.title,\n error_type: entry.errorType,\n count: entry.count,\n affected_users: JSON.stringify(entry.affectedUsers),\n first_seen: entry.firstSeen,\n last_seen: entry.lastSeen,\n status: entry.status,\n fix_prompt_file: entry.fixPromptFile,\n latest_event_file: entry.latestEventFile,\n release: entry.release ?? '',\n environment: entry.environment ?? '',\n };\n }\n\n // Row → UncaughtEvent mapper\n function rowToEvent(row: Record<string, unknown>): UncaughtEvent {\n return JSON.parse(row.payload as string) as UncaughtEvent;\n }\n\n // Insert event + upsert issue atomically\n const insertEventAndUpsert = db.transaction((event: UncaughtEvent, eventFile: string, promptFile: string) => {\n const fp = event.fingerprint;\n const userId = event.user?.id ?? event.user?.email ?? 'anonymous';\n\n // Insert event row\n stmtInsertEvent.run({\n event_id: event.eventId,\n fingerprint: fp,\n timestamp: event.timestamp,\n level: event.level,\n fix_prompt: event.fixPrompt ?? '',\n payload: JSON.stringify(event),\n });\n\n // Upsert issue\n const existingRow = stmtGetIssue.get(fp) as Record<string, unknown> | undefined;\n if (existingRow) {\n const existing = rowToIssue(existingRow);\n existing.count += 1;\n existing.lastSeen = event.timestamp;\n existing.latestEventFile = eventFile;\n existing.fixPromptFile = promptFile;\n existing.release = event.release ?? existing.release;\n existing.environment = event.environment?.deploy ?? existing.environment;\n if (!existing.affectedUsers.includes(String(userId))) {\n existing.affectedUsers.push(String(userId));\n }\n if (existing.status === 'resolved') {\n existing.status = 'open';\n }\n stmtUpsertIssue.run(issueToParams(existing));\n } else {\n stmtUpsertIssue.run(issueToParams({\n fingerprint: fp,\n title: event.error?.message ?? 'Unknown error',\n errorType: event.error?.type ?? 'Error',\n count: 1,\n affectedUsers: [String(userId)],\n firstSeen: event.timestamp,\n lastSeen: event.timestamp,\n status: 'open',\n fixPromptFile: promptFile,\n latestEventFile: eventFile,\n release: event.release,\n environment: event.environment?.deploy,\n }));\n }\n });\n\n return {\n upsertIssue(entry: IssueEntry): void {\n stmtUpsertIssue.run(issueToParams(entry));\n },\n\n getIssues(filter?: { status?: IssueStatus; environment?: string }): IssueEntry[] {\n let rows: unknown[];\n if (filter?.status && filter?.environment) {\n rows = stmtGetIssuesByStatusAndEnv.all(filter.status, filter.environment);\n } else if (filter?.status) {\n rows = stmtGetIssuesByStatus.all(filter.status);\n } else if (filter?.environment) {\n rows = stmtGetIssuesByEnv.all(filter.environment);\n } else {\n rows = stmtGetIssues.all();\n }\n return (rows as Record<string, unknown>[]).map(rowToIssue);\n },\n\n getIssue(fingerprint: string): IssueEntry | undefined {\n const row = stmtGetIssue.get(fingerprint) as Record<string, unknown> | undefined;\n return row ? rowToIssue(row) : undefined;\n },\n\n updateIssueStatus(fingerprint: string, status: IssueStatus): void {\n stmtUpdateStatus.run(status, fingerprint);\n },\n\n deleteAllIssues(): void {\n stmtDeleteAllEvents.run();\n stmtDeleteAllIssues.run();\n },\n\n insertEvent(event: UncaughtEvent): void {\n const ts = (event.timestamp ?? new Date().toISOString()).replace(/[:.]/g, '-');\n const eventFile = `event-${ts}.json`;\n const promptFile = `${event.fingerprint}.md`;\n insertEventAndUpsert(event, eventFile, promptFile);\n },\n\n getEvents(fingerprint: string, opts?: { limit?: number; offset?: number }): UncaughtEvent[] {\n const limit = opts?.limit ?? 50;\n const offset = opts?.offset ?? 0;\n const rows = stmtGetEvents.all(fingerprint, limit, offset);\n return (rows as Record<string, unknown>[]).map(rowToEvent);\n },\n\n getLatestEvent(fingerprint: string): UncaughtEvent | undefined {\n const row = stmtGetLatestEvent.get(fingerprint) as Record<string, unknown> | undefined;\n return row ? rowToEvent(row) : undefined;\n },\n\n getEventCount(fingerprint: string): number {\n const row = stmtGetEventCount.get(fingerprint) as { cnt: number };\n return row.cnt;\n },\n\n getStats() {\n return {\n total: (stmtCountAll.get() as { cnt: number }).cnt,\n open: (stmtCountByStatus.get('open') as { cnt: number }).cnt,\n resolved: (stmtCountByStatus.get('resolved') as { cnt: number }).cnt,\n ignored: (stmtCountByStatus.get('ignored') as { cnt: number }).cnt,\n totalEvents: (stmtCountEvents.get() as { cnt: number }).cnt,\n };\n },\n\n importFromFiles(baseDir: string): { issues: number; events: number } {\n const meta = stmtGetMeta.get('migrated') as { value: string } | undefined;\n if (meta?.value === 'true') return { issues: 0, events: 0 };\n\n let issueCount = 0;\n let eventCount = 0;\n\n try {\n const fsSync = require('fs');\n const pathMod = require('path');\n\n // Import issues.json\n const issuesPath = pathMod.join(baseDir, 'issues.json');\n if (fsSync.existsSync(issuesPath)) {\n const raw = fsSync.readFileSync(issuesPath, 'utf-8');\n const issues = JSON.parse(raw) as IssueEntry[];\n for (const issue of issues) {\n stmtUpsertIssue.run(issueToParams(issue));\n issueCount++;\n }\n }\n\n // Import event files\n const eventsDir = pathMod.join(baseDir, 'events');\n if (fsSync.existsSync(eventsDir)) {\n const fps = fsSync.readdirSync(eventsDir);\n for (const fp of fps) {\n const fpDir = pathMod.join(eventsDir, fp);\n if (!fsSync.statSync(fpDir).isDirectory()) continue;\n\n const files = fsSync.readdirSync(fpDir).filter((f: string) => f.startsWith('event-') && f.endsWith('.json'));\n for (const file of files) {\n try {\n const eventRaw = fsSync.readFileSync(pathMod.join(fpDir, file), 'utf-8');\n const event = JSON.parse(eventRaw) as UncaughtEvent;\n stmtInsertEvent.run({\n event_id: event.eventId,\n fingerprint: event.fingerprint,\n timestamp: event.timestamp,\n level: event.level,\n fix_prompt: event.fixPrompt ?? '',\n payload: eventRaw,\n });\n eventCount++;\n } catch {\n // Skip malformed event files\n }\n }\n }\n }\n } catch {\n // Migration is best-effort\n }\n\n stmtSetMeta.run('migrated', 'true');\n return { issues: issueCount, events: eventCount };\n },\n\n close(): void {\n db.close();\n },\n };\n}\n"]}
@@ -0,0 +1,2 @@
1
+ 'use strict';var chunkE76GW6KF_js=require('./chunk-E76GW6KF.js');async function N(a){try{if(typeof process<"u"&&process.env.NODE_ENV==="production"&&process.env.UNCAUGHT_LOCAL_IN_PROD!=="true")return new Response(JSON.stringify({error:"Local handler is disabled in production"}),{status:403,headers:{"Content-Type":"application/json"}});let t;try{t=await a.json();}catch{return new Response(JSON.stringify({error:"Invalid JSON body"}),{status:400,headers:{"Content-Type":"application/json"}})}if(!t||typeof t!="object"||!Array.isArray(t.events))return new Response(JSON.stringify({error:'Payload must contain an "events" array'}),{status:400,headers:{"Content-Type":"application/json"}});let n=t.events;return n.length===0?new Response(JSON.stringify({accepted:0}),{status:202,headers:{"Content-Type":"application/json"}}):(await O(n),new Response(JSON.stringify({accepted:n.length}),{status:202,headers:{"Content-Type":"application/json"}}))}catch(t){let n=t instanceof Error?t.message:"Internal server error";return new Response(JSON.stringify({error:n}),{status:500,headers:{"Content-Type":"application/json"}})}}async function O(a){let t=await import('fs/promises'),n=await import('path'),i=n.resolve(process.cwd(),".uncaught");await t.mkdir(n.join(i,"events"),{recursive:true}),await t.mkdir(n.join(i,"fix-prompts"),{recursive:true});let c=n.join(i,"issues.json"),p=[];try{let e=await t.readFile(c,"utf-8");p=JSON.parse(e);}catch{}for(let e of a){let r=e.fingerprint;if(!r)continue;let o=n.join(i,"events",r);await t.mkdir(o,{recursive:true});let f=`event-${(e.timestamp??new Date().toISOString()).replace(/[:.]/g,"-")}.json`,y=n.join(o,f),g=y+".tmp";await t.writeFile(g,chunkE76GW6KF_js.b(e),"utf-8"),await t.rename(g,y);let v=n.join(o,"latest.json"),h=v+".tmp";await t.writeFile(h,chunkE76GW6KF_js.b(e),"utf-8"),await t.rename(h,v);let m=`${r}.md`,S=n.join(i,"fix-prompts",m),j=S+".tmp";await t.writeFile(j,e.fixPrompt??"","utf-8"),await t.rename(j,S);let d=e.user?.id??e.user?.email??"anonymous",s=p.find(E=>E.fingerprint===r);s?(s.count+=1,s.lastSeen=e.timestamp,s.latestEventFile=f,s.fixPromptFile=m,s.affectedUsers.includes(String(d))||s.affectedUsers.push(String(d)),s.status==="resolved"&&(s.status="open")):p.push({fingerprint:r,title:e.error?.message??"Unknown error",errorType:e.error?.type??"Error",count:1,affectedUsers:[String(d)],firstSeen:e.timestamp,lastSeen:e.timestamp,status:"open",fixPromptFile:m,latestEventFile:f});}let w=c+".tmp";await t.writeFile(w,JSON.stringify(p,null,2),"utf-8"),await t.rename(w,c);try{let{openStore:e}=await import('./sqlite-store-4FTNST7O.js'),r=n.join(i,"uncaught.db"),o=e(r);for(let u of a)u.fingerprint&&o.insertEvent(u);o.close();}catch{}}exports.a=N;exports.b=O;//# sourceMappingURL=chunk-MSUAXLMV.js.map
2
+ //# sourceMappingURL=chunk-MSUAXLMV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/local-api-handler.ts"],"names":["POST","request","body","events","writeEvents","err","message","fs","path","baseDir","indexPath","issues","raw","event","fp","eventDir","eventFile","eventPath","tmpEvent","safeStringify","latestPath","tmpLatest","promptFile","promptPath","tmpPrompt","userId","existing","i","tmpIndex","openStore","dbPath","store"],"mappings":"iEAmBA,eAAsBA,CAAAA,CAAKC,CAAAA,CAAqC,CAC9D,GAAI,CAEF,GACE,OAAO,OAAA,CAAY,GAAA,EACnB,OAAA,CAAQ,GAAA,CAAI,QAAA,GAAa,YAAA,EACzB,OAAA,CAAQ,GAAA,CAAI,sBAAA,GAA2B,MAAA,CAEvC,OAAO,IAAI,QAAA,CACT,IAAA,CAAK,SAAA,CAAU,CAAE,KAAA,CAAO,yCAA0C,CAAC,CAAA,CACnE,CAAE,OAAQ,GAAA,CAAK,OAAA,CAAS,CAAE,cAAA,CAAgB,kBAAmB,CAAE,CACjE,CAAA,CAIF,IAAIC,CAAAA,CACJ,GAAI,CACFA,CAAAA,CAAO,MAAMD,CAAAA,CAAQ,IAAA,GACvB,CAAA,KAAQ,CACN,OAAO,IAAI,QAAA,CACT,IAAA,CAAK,SAAA,CAAU,CAAE,KAAA,CAAO,mBAAoB,CAAC,CAAA,CAC7C,CAAE,MAAA,CAAQ,GAAA,CAAK,QAAS,CAAE,cAAA,CAAgB,kBAAmB,CAAE,CACjE,CACF,CAEA,GACE,CAACC,CAAAA,EACD,OAAOA,CAAAA,EAAS,QAAA,EAChB,CAAC,KAAA,CAAM,OAAA,CAASA,CAAAA,CAAiC,MAAM,CAAA,CAEvD,OAAO,IAAI,QAAA,CACT,IAAA,CAAK,SAAA,CAAU,CAAE,KAAA,CAAO,wCAAyC,CAAC,CAAA,CAClE,CAAE,MAAA,CAAQ,GAAA,CAAK,QAAS,CAAE,cAAA,CAAgB,kBAAmB,CAAE,CACjE,CAAA,CAGF,IAAMC,CAAAA,CAAUD,CAAAA,CAAqC,MAAA,CAErD,OAAIC,CAAAA,CAAO,MAAA,GAAW,CAAA,CACb,IAAI,QAAA,CACT,KAAK,SAAA,CAAU,CAAE,QAAA,CAAU,CAAE,CAAC,CAAA,CAC9B,CAAE,MAAA,CAAQ,GAAA,CAAK,OAAA,CAAS,CAAE,cAAA,CAAgB,kBAAmB,CAAE,CACjE,CAAA,EAIF,MAAMC,CAAAA,CAAYD,CAAM,CAAA,CAEjB,IAAI,QAAA,CACT,IAAA,CAAK,SAAA,CAAU,CAAE,QAAA,CAAUA,CAAAA,CAAO,MAAO,CAAC,CAAA,CAC1C,CAAE,MAAA,CAAQ,GAAA,CAAK,OAAA,CAAS,CAAE,cAAA,CAAgB,kBAAmB,CAAE,CACjE,CAAA,CACF,CAAA,MAASE,CAAAA,CAAK,CACZ,IAAMC,CAAAA,CACJD,CAAAA,YAAe,KAAA,CAAQA,CAAAA,CAAI,OAAA,CAAU,wBACvC,OAAO,IAAI,QAAA,CACT,IAAA,CAAK,SAAA,CAAU,CAAE,KAAA,CAAOC,CAAQ,CAAC,CAAA,CACjC,CAAE,MAAA,CAAQ,GAAA,CAAK,OAAA,CAAS,CAAE,cAAA,CAAgB,kBAAmB,CAAE,CACjE,CACF,CACF,CAMA,eAAsBF,CAAAA,CAAYD,CAAAA,CAAwC,CACxE,IAAMI,CAAAA,CAAK,MAAM,OAAO,aAAa,CAAA,CAC/BC,CAAAA,CAAO,MAAM,OAAO,MAAM,CAAA,CAE1BC,CAAAA,CAAUD,CAAAA,CAAK,OAAA,CAAQ,OAAA,CAAQ,GAAA,EAAI,CAAG,WAAW,CAAA,CACvD,MAAMD,CAAAA,CAAG,KAAA,CAAMC,CAAAA,CAAK,IAAA,CAAKC,CAAAA,CAAS,QAAQ,CAAA,CAAG,CAAE,SAAA,CAAW,IAAK,CAAC,CAAA,CAChE,MAAMF,CAAAA,CAAG,KAAA,CAAMC,CAAAA,CAAK,IAAA,CAAKC,CAAAA,CAAS,aAAa,CAAA,CAAG,CAAE,SAAA,CAAW,IAAK,CAAC,CAAA,CAGrE,IAAMC,CAAAA,CAAYF,CAAAA,CAAK,IAAA,CAAKC,CAAAA,CAAS,aAAa,CAAA,CAC9CE,CAAAA,CAAuB,EAAC,CAC5B,GAAI,CACF,IAAMC,CAAAA,CAAM,MAAML,CAAAA,CAAG,QAAA,CAASG,CAAAA,CAAW,OAAO,CAAA,CAChDC,CAAAA,CAAS,IAAA,CAAK,KAAA,CAAMC,CAAG,EACzB,CAAA,KAAQ,CAER,CAEA,IAAA,IAAWC,KAASV,CAAAA,CAAQ,CAC1B,IAAMW,CAAAA,CAAKD,CAAAA,CAAM,WAAA,CACjB,GAAI,CAACC,CAAAA,CAAI,SAET,IAAMC,CAAAA,CAAWP,CAAAA,CAAK,IAAA,CAAKC,CAAAA,CAAS,QAAA,CAAUK,CAAE,CAAA,CAChD,MAAMP,CAAAA,CAAG,KAAA,CAAMQ,CAAAA,CAAU,CAAE,SAAA,CAAW,IAAK,CAAC,CAAA,CAO5C,IAAMC,CAAAA,CAAY,CAAA,MAAA,EAAA,CAJNH,CAAAA,CAAM,SAAA,EAAa,IAAI,IAAA,EAAK,CAAE,WAAA,EAAY,EAAG,OAAA,CACvD,OAAA,CACA,GACF,CAC6B,CAAA,KAAA,CAAA,CACvBI,CAAAA,CAAYT,CAAAA,CAAK,IAAA,CAAKO,CAAAA,CAAUC,CAAS,CAAA,CACzCE,CAAAA,CAAWD,CAAAA,CAAY,MAAA,CAC7B,MAAMV,CAAAA,CAAG,SAAA,CAAUW,CAAAA,CAAUC,kBAAAA,CAAcN,CAAK,CAAA,CAAG,OAAO,CAAA,CAC1D,MAAMN,CAAAA,CAAG,MAAA,CAAOW,CAAAA,CAAUD,CAAS,EAGnC,IAAMG,CAAAA,CAAaZ,CAAAA,CAAK,IAAA,CAAKO,CAAAA,CAAU,aAAa,CAAA,CAC9CM,CAAAA,CAAYD,CAAAA,CAAa,MAAA,CAC/B,MAAMb,CAAAA,CAAG,SAAA,CAAUc,CAAAA,CAAWF,kBAAAA,CAAcN,CAAK,CAAA,CAAG,OAAO,CAAA,CAC3D,MAAMN,CAAAA,CAAG,MAAA,CAAOc,CAAAA,CAAWD,CAAU,CAAA,CAGrC,IAAME,CAAAA,CAAa,CAAA,EAAGR,CAAE,CAAA,GAAA,CAAA,CAClBS,CAAAA,CAAaf,CAAAA,CAAK,KAAKC,CAAAA,CAAS,aAAA,CAAea,CAAU,CAAA,CACzDE,CAAAA,CAAYD,CAAAA,CAAa,MAAA,CAC/B,MAAMhB,CAAAA,CAAG,SAAA,CAAUiB,CAAAA,CAAWX,CAAAA,CAAM,SAAA,EAAa,EAAA,CAAI,OAAO,CAAA,CAC5D,MAAMN,CAAAA,CAAG,MAAA,CAAOiB,CAAAA,CAAWD,CAAU,CAAA,CAGrC,IAAME,CAAAA,CACHZ,CAAAA,CAAM,IAAA,EAA8C,EAAA,EACpDA,CAAAA,CAAM,IAAA,EAA8C,KAAA,EACrD,WAAA,CAEIa,CAAAA,CAAWf,CAAAA,CAAO,KAAMgB,CAAAA,EAAMA,CAAAA,CAAE,WAAA,GAAgBb,CAAE,CAAA,CACpDY,CAAAA,EACFA,CAAAA,CAAS,KAAA,EAAS,CAAA,CAClBA,CAAAA,CAAS,QAAA,CAAWb,CAAAA,CAAM,SAAA,CAC1Ba,CAAAA,CAAS,eAAA,CAAkBV,CAAAA,CAC3BU,CAAAA,CAAS,aAAA,CAAgBJ,CAAAA,CACpBI,CAAAA,CAAS,aAAA,CAAc,QAAA,CAAS,MAAA,CAAOD,CAAM,CAAC,CAAA,EACjDC,CAAAA,CAAS,aAAA,CAAc,IAAA,CAAK,MAAA,CAAOD,CAAM,CAAC,EAExCC,CAAAA,CAAS,MAAA,GAAW,UAAA,GACtBA,CAAAA,CAAS,MAAA,CAAS,MAAA,CAAA,EAGpBf,CAAAA,CAAO,IAAA,CAAK,CACV,WAAA,CAAaG,CAAAA,CACb,KAAA,CAAOD,CAAAA,CAAM,KAAA,EAAO,OAAA,EAAW,eAAA,CAC/B,UAAWA,CAAAA,CAAM,KAAA,EAAO,IAAA,EAAQ,OAAA,CAChC,KAAA,CAAO,CAAA,CACP,aAAA,CAAe,CAAC,MAAA,CAAOY,CAAM,CAAC,CAAA,CAC9B,SAAA,CAAWZ,CAAAA,CAAM,SAAA,CACjB,QAAA,CAAUA,EAAM,SAAA,CAChB,MAAA,CAAQ,MAAA,CACR,aAAA,CAAeS,CAAAA,CACf,eAAA,CAAiBN,CACnB,CAAC,EAEL,CAGA,IAAMY,CAAAA,CAAWlB,CAAAA,CAAY,MAAA,CAC7B,MAAMH,CAAAA,CAAG,SAAA,CAAUqB,CAAAA,CAAU,IAAA,CAAK,SAAA,CAAUjB,CAAAA,CAAQ,IAAA,CAAM,CAAC,CAAA,CAAG,OAAO,CAAA,CACrE,MAAMJ,CAAAA,CAAG,MAAA,CAAOqB,CAAAA,CAAUlB,CAAS,CAAA,CAGnC,GAAI,CACF,GAAM,CAAE,SAAA,CAAAmB,CAAU,CAAA,CAAI,MAAM,OAAO,4BAAgB,CAAA,CAC7CC,CAAAA,CAAStB,CAAAA,CAAK,IAAA,CAAKC,CAAAA,CAAS,aAAa,CAAA,CACzCsB,EAAQF,CAAAA,CAAUC,CAAM,CAAA,CAC9B,IAAA,IAAWjB,CAAAA,IAASV,CAAAA,CACbU,CAAAA,CAAM,WAAA,EACXkB,CAAAA,CAAM,WAAA,CAAYlB,CAAK,CAAA,CAEzBkB,CAAAA,CAAM,KAAA,GACR,CAAA,KAAQ,CAER,CACF","file":"chunk-MSUAXLMV.js","sourcesContent":["// ---------------------------------------------------------------------------\n// @uncaughtdev/core — Next.js App Router local API handler\n// ---------------------------------------------------------------------------\n//\n// Usage:\n// // app/api/uncaught/local/route.ts\n// export { POST } from '@uncaughtdev/core/local-api-handler';\n//\n// ---------------------------------------------------------------------------\n\nimport type { UncaughtEvent, IssueEntry } from './types';\nimport { safeStringify } from './utils';\n\n/**\n * Next.js App Router POST handler.\n * Accepts `{ events: UncaughtEvent[] }` and writes them to `.uncaught/`.\n *\n * Blocked in production unless `UNCAUGHT_LOCAL_IN_PROD=true` is set.\n */\nexport async function POST(request: Request): Promise<Response> {\n try {\n // --- Production guard --------------------------------------------------\n if (\n typeof process !== 'undefined' &&\n process.env.NODE_ENV === 'production' &&\n process.env.UNCAUGHT_LOCAL_IN_PROD !== 'true'\n ) {\n return new Response(\n JSON.stringify({ error: 'Local handler is disabled in production' }),\n { status: 403, headers: { 'Content-Type': 'application/json' } }\n );\n }\n\n // --- Parse body --------------------------------------------------------\n let body: unknown;\n try {\n body = await request.json();\n } catch {\n return new Response(\n JSON.stringify({ error: 'Invalid JSON body' }),\n { status: 400, headers: { 'Content-Type': 'application/json' } }\n );\n }\n\n if (\n !body ||\n typeof body !== 'object' ||\n !Array.isArray((body as Record<string, unknown>).events)\n ) {\n return new Response(\n JSON.stringify({ error: 'Payload must contain an \"events\" array' }),\n { status: 400, headers: { 'Content-Type': 'application/json' } }\n );\n }\n\n const events = (body as { events: UncaughtEvent[] }).events;\n\n if (events.length === 0) {\n return new Response(\n JSON.stringify({ accepted: 0 }),\n { status: 202, headers: { 'Content-Type': 'application/json' } }\n );\n }\n\n // --- Write events to disk ----------------------------------------------\n await writeEvents(events);\n\n return new Response(\n JSON.stringify({ accepted: events.length }),\n { status: 202, headers: { 'Content-Type': 'application/json' } }\n );\n } catch (err) {\n const message =\n err instanceof Error ? err.message : 'Internal server error';\n return new Response(\n JSON.stringify({ error: message }),\n { status: 500, headers: { 'Content-Type': 'application/json' } }\n );\n }\n}\n\n// ---------------------------------------------------------------------------\n// Shared disk-writing logic\n// ---------------------------------------------------------------------------\n\nexport async function writeEvents(events: UncaughtEvent[]): Promise<void> {\n const fs = await import('fs/promises');\n const path = await import('path');\n\n const baseDir = path.resolve(process.cwd(), '.uncaught');\n await fs.mkdir(path.join(baseDir, 'events'), { recursive: true });\n await fs.mkdir(path.join(baseDir, 'fix-prompts'), { recursive: true });\n\n // Load existing issues index\n const indexPath = path.join(baseDir, 'issues.json');\n let issues: IssueEntry[] = [];\n try {\n const raw = await fs.readFile(indexPath, 'utf-8');\n issues = JSON.parse(raw) as IssueEntry[];\n } catch {\n // Start fresh.\n }\n\n for (const event of events) {\n const fp = event.fingerprint;\n if (!fp) continue;\n\n const eventDir = path.join(baseDir, 'events', fp);\n await fs.mkdir(eventDir, { recursive: true });\n\n // Timestamped event file\n const ts = (event.timestamp ?? new Date().toISOString()).replace(\n /[:.]/g,\n '-'\n );\n const eventFile = `event-${ts}.json`;\n const eventPath = path.join(eventDir, eventFile);\n const tmpEvent = eventPath + '.tmp';\n await fs.writeFile(tmpEvent, safeStringify(event), 'utf-8');\n await fs.rename(tmpEvent, eventPath);\n\n // latest.json\n const latestPath = path.join(eventDir, 'latest.json');\n const tmpLatest = latestPath + '.tmp';\n await fs.writeFile(tmpLatest, safeStringify(event), 'utf-8');\n await fs.rename(tmpLatest, latestPath);\n\n // Fix-prompt markdown\n const promptFile = `${fp}.md`;\n const promptPath = path.join(baseDir, 'fix-prompts', promptFile);\n const tmpPrompt = promptPath + '.tmp';\n await fs.writeFile(tmpPrompt, event.fixPrompt ?? '', 'utf-8');\n await fs.rename(tmpPrompt, promptPath);\n\n // Update issues index\n const userId =\n (event.user as Record<string, unknown> | undefined)?.id ??\n (event.user as Record<string, unknown> | undefined)?.email ??\n 'anonymous';\n\n const existing = issues.find((i) => i.fingerprint === fp);\n if (existing) {\n existing.count += 1;\n existing.lastSeen = event.timestamp;\n existing.latestEventFile = eventFile;\n existing.fixPromptFile = promptFile;\n if (!existing.affectedUsers.includes(String(userId))) {\n existing.affectedUsers.push(String(userId));\n }\n if (existing.status === 'resolved') {\n existing.status = 'open';\n }\n } else {\n issues.push({\n fingerprint: fp,\n title: event.error?.message ?? 'Unknown error',\n errorType: event.error?.type ?? 'Error',\n count: 1,\n affectedUsers: [String(userId)],\n firstSeen: event.timestamp,\n lastSeen: event.timestamp,\n status: 'open',\n fixPromptFile: promptFile,\n latestEventFile: eventFile,\n });\n }\n }\n\n // Write updated index atomically\n const tmpIndex = indexPath + '.tmp';\n await fs.writeFile(tmpIndex, JSON.stringify(issues, null, 2), 'utf-8');\n await fs.rename(tmpIndex, indexPath);\n\n // Also write to SQLite\n try {\n const { openStore } = await import('./sqlite-store');\n const dbPath = path.join(baseDir, 'uncaught.db');\n const store = openStore(dbPath);\n for (const event of events) {\n if (!event.fingerprint) continue;\n store.insertEvent(event);\n }\n store.close();\n } catch {\n // SQLite is best-effort — flat files are the primary store\n }\n}\n"]}
@@ -0,0 +1,59 @@
1
+ 'use strict';var chunk2YXXFGBV_js=require('./chunk-2YXXFGBV.js'),G=require('better-sqlite3');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var G__default=/*#__PURE__*/_interopDefault(G);var W=`
2
+ CREATE TABLE IF NOT EXISTS issues (
3
+ fingerprint TEXT PRIMARY KEY,
4
+ title TEXT NOT NULL,
5
+ error_type TEXT NOT NULL,
6
+ count INTEGER NOT NULL DEFAULT 1,
7
+ affected_users TEXT NOT NULL DEFAULT '[]',
8
+ first_seen TEXT NOT NULL,
9
+ last_seen TEXT NOT NULL,
10
+ status TEXT NOT NULL DEFAULT 'open',
11
+ fix_prompt_file TEXT NOT NULL DEFAULT '',
12
+ latest_event_file TEXT NOT NULL DEFAULT '',
13
+ release TEXT NOT NULL DEFAULT '',
14
+ environment TEXT NOT NULL DEFAULT ''
15
+ );
16
+
17
+ CREATE INDEX IF NOT EXISTS idx_issues_status ON issues(status);
18
+ CREATE INDEX IF NOT EXISTS idx_issues_last_seen ON issues(last_seen);
19
+
20
+ CREATE TABLE IF NOT EXISTS events (
21
+ event_id TEXT PRIMARY KEY,
22
+ fingerprint TEXT NOT NULL,
23
+ timestamp TEXT NOT NULL,
24
+ level TEXT NOT NULL DEFAULT 'error',
25
+ fix_prompt TEXT NOT NULL DEFAULT '',
26
+ payload TEXT NOT NULL,
27
+ FOREIGN KEY (fingerprint) REFERENCES issues(fingerprint)
28
+ );
29
+
30
+ CREATE INDEX IF NOT EXISTS idx_events_fingerprint ON events(fingerprint);
31
+ CREATE INDEX IF NOT EXISTS idx_events_timestamp ON events(timestamp);
32
+
33
+ CREATE TABLE IF NOT EXISTS _meta (
34
+ key TEXT PRIMARY KEY,
35
+ value TEXT NOT NULL
36
+ );
37
+ `,Y=`
38
+ ALTER TABLE issues ADD COLUMN release TEXT NOT NULL DEFAULT '';
39
+ ALTER TABLE issues ADD COLUMN environment TEXT NOT NULL DEFAULT '';
40
+ `;function H(I){let t=new G__default.default(I);t.pragma("journal_mode = WAL"),t.pragma("foreign_keys = ON"),t.exec(W);try{for(let e of Y.trim().split(";").filter(Boolean))try{t.exec(e+";");}catch{}}catch{}let p=t.prepare(`
41
+ INSERT INTO issues (fingerprint, title, error_type, count, affected_users, first_seen, last_seen, status, fix_prompt_file, latest_event_file, release, environment)
42
+ VALUES (@fingerprint, @title, @error_type, @count, @affected_users, @first_seen, @last_seen, @status, @fix_prompt_file, @latest_event_file, @release, @environment)
43
+ ON CONFLICT(fingerprint) DO UPDATE SET
44
+ title = @title,
45
+ error_type = @error_type,
46
+ count = @count,
47
+ affected_users = @affected_users,
48
+ first_seen = @first_seen,
49
+ last_seen = @last_seen,
50
+ status = @status,
51
+ fix_prompt_file = @fix_prompt_file,
52
+ latest_event_file = @latest_event_file,
53
+ release = @release,
54
+ environment = @environment
55
+ `),O=t.prepare("SELECT * FROM issues ORDER BY last_seen DESC"),R=t.prepare("SELECT * FROM issues WHERE status = ? ORDER BY last_seen DESC"),U=t.prepare("SELECT * FROM issues WHERE environment = ? ORDER BY last_seen DESC"),F=t.prepare("SELECT * FROM issues WHERE status = ? AND environment = ? ORDER BY last_seen DESC"),d=t.prepare("SELECT * FROM issues WHERE fingerprint = ?"),A=t.prepare("UPDATE issues SET status = ? WHERE fingerprint = ?"),y=t.prepare("DELETE FROM issues"),C=t.prepare("DELETE FROM events"),S=t.prepare(`
56
+ INSERT OR IGNORE INTO events (event_id, fingerprint, timestamp, level, fix_prompt, payload)
57
+ VALUES (@event_id, @fingerprint, @timestamp, @level, @fix_prompt, @payload)
58
+ `),D=t.prepare("SELECT * FROM events WHERE fingerprint = ? ORDER BY timestamp DESC LIMIT ? OFFSET ?"),X=t.prepare("SELECT * FROM events WHERE fingerprint = ? ORDER BY timestamp DESC LIMIT 1"),x=t.prepare("SELECT COUNT(*) as cnt FROM events WHERE fingerprint = ?"),M=t.prepare("SELECT value FROM _meta WHERE key = ?"),b=t.prepare("INSERT OR REPLACE INTO _meta (key, value) VALUES (?, ?)"),h=t.prepare("SELECT COUNT(*) as cnt FROM issues"),m=t.prepare("SELECT COUNT(*) as cnt FROM issues WHERE status = ?"),B=t.prepare("SELECT COUNT(*) as cnt FROM events");function T(e){return {fingerprint:e.fingerprint,title:e.title,errorType:e.error_type,count:e.count,affectedUsers:JSON.parse(e.affected_users),firstSeen:e.first_seen,lastSeen:e.last_seen,status:e.status,fixPromptFile:e.fix_prompt_file,latestEventFile:e.latest_event_file,release:e.release||void 0,environment:e.environment||void 0}}function l(e){return {fingerprint:e.fingerprint,title:e.title,error_type:e.errorType,count:e.count,affected_users:JSON.stringify(e.affectedUsers),first_seen:e.firstSeen,last_seen:e.lastSeen,status:e.status,fix_prompt_file:e.fixPromptFile,latest_event_file:e.latestEventFile,release:e.release??"",environment:e.environment??""}}function _(e){return JSON.parse(e.payload)}let P=t.transaction((e,s,a)=>{let i=e.fingerprint,r=e.user?.id??e.user?.email??"anonymous";S.run({event_id:e.eventId,fingerprint:i,timestamp:e.timestamp,level:e.level,fix_prompt:e.fixPrompt??"",payload:JSON.stringify(e)});let o=d.get(i);if(o){let n=T(o);n.count+=1,n.lastSeen=e.timestamp,n.latestEventFile=s,n.fixPromptFile=a,n.release=e.release??n.release,n.environment=e.environment?.deploy??n.environment,n.affectedUsers.includes(String(r))||n.affectedUsers.push(String(r)),n.status==="resolved"&&(n.status="open"),p.run(l(n));}else p.run(l({fingerprint:i,title:e.error?.message??"Unknown error",errorType:e.error?.type??"Error",count:1,affectedUsers:[String(r)],firstSeen:e.timestamp,lastSeen:e.timestamp,status:"open",fixPromptFile:a,latestEventFile:s,release:e.release,environment:e.environment?.deploy}));});return {upsertIssue(e){p.run(l(e));},getIssues(e){let s;return e?.status&&e?.environment?s=F.all(e.status,e.environment):e?.status?s=R.all(e.status):e?.environment?s=U.all(e.environment):s=O.all(),s.map(T)},getIssue(e){let s=d.get(e);return s?T(s):void 0},updateIssueStatus(e,s){A.run(s,e);},deleteAllIssues(){C.run(),y.run();},insertEvent(e){let a=`event-${(e.timestamp??new Date().toISOString()).replace(/[:.]/g,"-")}.json`,i=`${e.fingerprint}.md`;P(e,a,i);},getEvents(e,s){let a=s?.limit??50,i=s?.offset??0;return D.all(e,a,i).map(_)},getLatestEvent(e){let s=X.get(e);return s?_(s):void 0},getEventCount(e){return x.get(e).cnt},getStats(){return {total:h.get().cnt,open:m.get("open").cnt,resolved:m.get("resolved").cnt,ignored:m.get("ignored").cnt,totalEvents:B.get().cnt}},importFromFiles(e){if(M.get("migrated")?.value==="true")return {issues:0,events:0};let a=0,i=0;try{let r=chunk2YXXFGBV_js.a("fs"),o=chunk2YXXFGBV_js.a("path"),n=o.join(e,"issues.json");if(r.existsSync(n)){let g=r.readFileSync(n,"utf-8"),v=JSON.parse(g);for(let u of v)p.run(l(u)),a++;}let c=o.join(e,"events");if(r.existsSync(c)){let g=r.readdirSync(c);for(let v of g){let u=o.join(c,v);if(!r.statSync(u).isDirectory())continue;let k=r.readdirSync(u).filter(f=>f.startsWith("event-")&&f.endsWith(".json"));for(let f of k)try{let L=r.readFileSync(o.join(u,f),"utf-8"),E=JSON.parse(L);S.run({event_id:E.eventId,fingerprint:E.fingerprint,timestamp:E.timestamp,level:E.level,fix_prompt:E.fixPrompt??"",payload:L}),i++;}catch{}}}}catch{}return b.run("migrated","true"),{issues:a,events:i}},close(){t.close();}}}exports.a=H;//# sourceMappingURL=chunk-VQXSHR3C.js.map
59
+ //# sourceMappingURL=chunk-VQXSHR3C.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/sqlite-store.ts"],"names":["SCHEMA_SQL","MIGRATION_SQL","openStore","dbPath","db","Database","stmt","stmtUpsertIssue","stmtGetIssues","stmtGetIssuesByStatus","stmtGetIssuesByEnv","stmtGetIssuesByStatusAndEnv","stmtGetIssue","stmtUpdateStatus","stmtDeleteAllIssues","stmtDeleteAllEvents","stmtInsertEvent","stmtGetEvents","stmtGetLatestEvent","stmtGetEventCount","stmtGetMeta","stmtSetMeta","stmtCountAll","stmtCountByStatus","stmtCountEvents","rowToIssue","row","issueToParams","entry","rowToEvent","insertEventAndUpsert","event","eventFile","promptFile","fp","userId","existingRow","existing","filter","rows","fingerprint","status","opts","limit","offset","baseDir","issueCount","eventCount","fsSync","N","pathMod","issuesPath","raw","issues","issue","eventsDir","fps","fpDir","files","file","eventRaw"],"mappings":"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","file":"chunk-VQXSHR3C.js","sourcesContent":["// ---------------------------------------------------------------------------\n// @uncaughtdev/core — SQLite storage layer\n// ---------------------------------------------------------------------------\n\nimport Database from 'better-sqlite3';\nimport type { IssueEntry, IssueStatus, UncaughtEvent } from './types';\n\n// ---------------------------------------------------------------------------\n// Schema\n// ---------------------------------------------------------------------------\n\nconst SCHEMA_SQL = `\nCREATE TABLE IF NOT EXISTS issues (\n fingerprint TEXT PRIMARY KEY,\n title TEXT NOT NULL,\n error_type TEXT NOT NULL,\n count INTEGER NOT NULL DEFAULT 1,\n affected_users TEXT NOT NULL DEFAULT '[]',\n first_seen TEXT NOT NULL,\n last_seen TEXT NOT NULL,\n status TEXT NOT NULL DEFAULT 'open',\n fix_prompt_file TEXT NOT NULL DEFAULT '',\n latest_event_file TEXT NOT NULL DEFAULT '',\n release TEXT NOT NULL DEFAULT '',\n environment TEXT NOT NULL DEFAULT ''\n);\n\nCREATE INDEX IF NOT EXISTS idx_issues_status ON issues(status);\nCREATE INDEX IF NOT EXISTS idx_issues_last_seen ON issues(last_seen);\n\nCREATE TABLE IF NOT EXISTS events (\n event_id TEXT PRIMARY KEY,\n fingerprint TEXT NOT NULL,\n timestamp TEXT NOT NULL,\n level TEXT NOT NULL DEFAULT 'error',\n fix_prompt TEXT NOT NULL DEFAULT '',\n payload TEXT NOT NULL,\n FOREIGN KEY (fingerprint) REFERENCES issues(fingerprint)\n);\n\nCREATE INDEX IF NOT EXISTS idx_events_fingerprint ON events(fingerprint);\nCREATE INDEX IF NOT EXISTS idx_events_timestamp ON events(timestamp);\n\nCREATE TABLE IF NOT EXISTS _meta (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL\n);\n`;\n\n// Migrate existing databases that lack new columns\nconst MIGRATION_SQL = `\nALTER TABLE issues ADD COLUMN release TEXT NOT NULL DEFAULT '';\nALTER TABLE issues ADD COLUMN environment TEXT NOT NULL DEFAULT '';\n`;\n\n// ---------------------------------------------------------------------------\n// Public interface\n// ---------------------------------------------------------------------------\n\nexport interface SqliteStore {\n upsertIssue(entry: IssueEntry): void;\n getIssues(filter?: { status?: IssueStatus; environment?: string }): IssueEntry[];\n getIssue(fingerprint: string): IssueEntry | undefined;\n updateIssueStatus(fingerprint: string, status: IssueStatus): void;\n deleteAllIssues(): void;\n\n insertEvent(event: UncaughtEvent): void;\n getEvents(fingerprint: string, opts?: { limit?: number; offset?: number }): UncaughtEvent[];\n getLatestEvent(fingerprint: string): UncaughtEvent | undefined;\n getEventCount(fingerprint: string): number;\n\n getStats(): { total: number; open: number; resolved: number; ignored: number; totalEvents: number };\n\n importFromFiles(baseDir: string): { issues: number; events: number };\n\n close(): void;\n}\n\n// ---------------------------------------------------------------------------\n// Implementation\n// ---------------------------------------------------------------------------\n\nexport function openStore(dbPath: string): SqliteStore {\n const db = new Database(dbPath);\n db.pragma('journal_mode = WAL');\n db.pragma('foreign_keys = ON');\n db.exec(SCHEMA_SQL);\n\n // Run migrations for existing databases\n try {\n for (const stmt of MIGRATION_SQL.trim().split(';').filter(Boolean)) {\n try { db.exec(stmt + ';'); } catch { /* column already exists */ }\n }\n } catch { /* migration best-effort */ }\n\n // Prepared statements\n const stmtUpsertIssue = db.prepare(`\n INSERT INTO issues (fingerprint, title, error_type, count, affected_users, first_seen, last_seen, status, fix_prompt_file, latest_event_file, release, environment)\n VALUES (@fingerprint, @title, @error_type, @count, @affected_users, @first_seen, @last_seen, @status, @fix_prompt_file, @latest_event_file, @release, @environment)\n ON CONFLICT(fingerprint) DO UPDATE SET\n title = @title,\n error_type = @error_type,\n count = @count,\n affected_users = @affected_users,\n first_seen = @first_seen,\n last_seen = @last_seen,\n status = @status,\n fix_prompt_file = @fix_prompt_file,\n latest_event_file = @latest_event_file,\n release = @release,\n environment = @environment\n `);\n\n const stmtGetIssues = db.prepare('SELECT * FROM issues ORDER BY last_seen DESC');\n const stmtGetIssuesByStatus = db.prepare('SELECT * FROM issues WHERE status = ? ORDER BY last_seen DESC');\n const stmtGetIssuesByEnv = db.prepare('SELECT * FROM issues WHERE environment = ? ORDER BY last_seen DESC');\n const stmtGetIssuesByStatusAndEnv = db.prepare('SELECT * FROM issues WHERE status = ? AND environment = ? ORDER BY last_seen DESC');\n const stmtGetIssue = db.prepare('SELECT * FROM issues WHERE fingerprint = ?');\n const stmtUpdateStatus = db.prepare('UPDATE issues SET status = ? WHERE fingerprint = ?');\n const stmtDeleteAllIssues = db.prepare('DELETE FROM issues');\n const stmtDeleteAllEvents = db.prepare('DELETE FROM events');\n\n const stmtInsertEvent = db.prepare(`\n INSERT OR IGNORE INTO events (event_id, fingerprint, timestamp, level, fix_prompt, payload)\n VALUES (@event_id, @fingerprint, @timestamp, @level, @fix_prompt, @payload)\n `);\n\n const stmtGetEvents = db.prepare('SELECT * FROM events WHERE fingerprint = ? ORDER BY timestamp DESC LIMIT ? OFFSET ?');\n const stmtGetLatestEvent = db.prepare('SELECT * FROM events WHERE fingerprint = ? ORDER BY timestamp DESC LIMIT 1');\n const stmtGetEventCount = db.prepare('SELECT COUNT(*) as cnt FROM events WHERE fingerprint = ?');\n\n const stmtGetMeta = db.prepare('SELECT value FROM _meta WHERE key = ?');\n const stmtSetMeta = db.prepare('INSERT OR REPLACE INTO _meta (key, value) VALUES (?, ?)');\n\n const stmtCountAll = db.prepare('SELECT COUNT(*) as cnt FROM issues');\n const stmtCountByStatus = db.prepare('SELECT COUNT(*) as cnt FROM issues WHERE status = ?');\n const stmtCountEvents = db.prepare('SELECT COUNT(*) as cnt FROM events');\n\n // Row → IssueEntry mapper\n function rowToIssue(row: Record<string, unknown>): IssueEntry {\n return {\n fingerprint: row.fingerprint as string,\n title: row.title as string,\n errorType: row.error_type as string,\n count: row.count as number,\n affectedUsers: JSON.parse(row.affected_users as string),\n firstSeen: row.first_seen as string,\n lastSeen: row.last_seen as string,\n status: row.status as IssueStatus,\n fixPromptFile: row.fix_prompt_file as string,\n latestEventFile: row.latest_event_file as string,\n release: (row.release as string) || undefined,\n environment: (row.environment as string) || undefined,\n };\n }\n\n // IssueEntry → row params mapper\n function issueToParams(entry: IssueEntry) {\n return {\n fingerprint: entry.fingerprint,\n title: entry.title,\n error_type: entry.errorType,\n count: entry.count,\n affected_users: JSON.stringify(entry.affectedUsers),\n first_seen: entry.firstSeen,\n last_seen: entry.lastSeen,\n status: entry.status,\n fix_prompt_file: entry.fixPromptFile,\n latest_event_file: entry.latestEventFile,\n release: entry.release ?? '',\n environment: entry.environment ?? '',\n };\n }\n\n // Row → UncaughtEvent mapper\n function rowToEvent(row: Record<string, unknown>): UncaughtEvent {\n return JSON.parse(row.payload as string) as UncaughtEvent;\n }\n\n // Insert event + upsert issue atomically\n const insertEventAndUpsert = db.transaction((event: UncaughtEvent, eventFile: string, promptFile: string) => {\n const fp = event.fingerprint;\n const userId = event.user?.id ?? event.user?.email ?? 'anonymous';\n\n // Insert event row\n stmtInsertEvent.run({\n event_id: event.eventId,\n fingerprint: fp,\n timestamp: event.timestamp,\n level: event.level,\n fix_prompt: event.fixPrompt ?? '',\n payload: JSON.stringify(event),\n });\n\n // Upsert issue\n const existingRow = stmtGetIssue.get(fp) as Record<string, unknown> | undefined;\n if (existingRow) {\n const existing = rowToIssue(existingRow);\n existing.count += 1;\n existing.lastSeen = event.timestamp;\n existing.latestEventFile = eventFile;\n existing.fixPromptFile = promptFile;\n existing.release = event.release ?? existing.release;\n existing.environment = event.environment?.deploy ?? existing.environment;\n if (!existing.affectedUsers.includes(String(userId))) {\n existing.affectedUsers.push(String(userId));\n }\n if (existing.status === 'resolved') {\n existing.status = 'open';\n }\n stmtUpsertIssue.run(issueToParams(existing));\n } else {\n stmtUpsertIssue.run(issueToParams({\n fingerprint: fp,\n title: event.error?.message ?? 'Unknown error',\n errorType: event.error?.type ?? 'Error',\n count: 1,\n affectedUsers: [String(userId)],\n firstSeen: event.timestamp,\n lastSeen: event.timestamp,\n status: 'open',\n fixPromptFile: promptFile,\n latestEventFile: eventFile,\n release: event.release,\n environment: event.environment?.deploy,\n }));\n }\n });\n\n return {\n upsertIssue(entry: IssueEntry): void {\n stmtUpsertIssue.run(issueToParams(entry));\n },\n\n getIssues(filter?: { status?: IssueStatus; environment?: string }): IssueEntry[] {\n let rows: unknown[];\n if (filter?.status && filter?.environment) {\n rows = stmtGetIssuesByStatusAndEnv.all(filter.status, filter.environment);\n } else if (filter?.status) {\n rows = stmtGetIssuesByStatus.all(filter.status);\n } else if (filter?.environment) {\n rows = stmtGetIssuesByEnv.all(filter.environment);\n } else {\n rows = stmtGetIssues.all();\n }\n return (rows as Record<string, unknown>[]).map(rowToIssue);\n },\n\n getIssue(fingerprint: string): IssueEntry | undefined {\n const row = stmtGetIssue.get(fingerprint) as Record<string, unknown> | undefined;\n return row ? rowToIssue(row) : undefined;\n },\n\n updateIssueStatus(fingerprint: string, status: IssueStatus): void {\n stmtUpdateStatus.run(status, fingerprint);\n },\n\n deleteAllIssues(): void {\n stmtDeleteAllEvents.run();\n stmtDeleteAllIssues.run();\n },\n\n insertEvent(event: UncaughtEvent): void {\n const ts = (event.timestamp ?? new Date().toISOString()).replace(/[:.]/g, '-');\n const eventFile = `event-${ts}.json`;\n const promptFile = `${event.fingerprint}.md`;\n insertEventAndUpsert(event, eventFile, promptFile);\n },\n\n getEvents(fingerprint: string, opts?: { limit?: number; offset?: number }): UncaughtEvent[] {\n const limit = opts?.limit ?? 50;\n const offset = opts?.offset ?? 0;\n const rows = stmtGetEvents.all(fingerprint, limit, offset);\n return (rows as Record<string, unknown>[]).map(rowToEvent);\n },\n\n getLatestEvent(fingerprint: string): UncaughtEvent | undefined {\n const row = stmtGetLatestEvent.get(fingerprint) as Record<string, unknown> | undefined;\n return row ? rowToEvent(row) : undefined;\n },\n\n getEventCount(fingerprint: string): number {\n const row = stmtGetEventCount.get(fingerprint) as { cnt: number };\n return row.cnt;\n },\n\n getStats() {\n return {\n total: (stmtCountAll.get() as { cnt: number }).cnt,\n open: (stmtCountByStatus.get('open') as { cnt: number }).cnt,\n resolved: (stmtCountByStatus.get('resolved') as { cnt: number }).cnt,\n ignored: (stmtCountByStatus.get('ignored') as { cnt: number }).cnt,\n totalEvents: (stmtCountEvents.get() as { cnt: number }).cnt,\n };\n },\n\n importFromFiles(baseDir: string): { issues: number; events: number } {\n const meta = stmtGetMeta.get('migrated') as { value: string } | undefined;\n if (meta?.value === 'true') return { issues: 0, events: 0 };\n\n let issueCount = 0;\n let eventCount = 0;\n\n try {\n const fsSync = require('fs');\n const pathMod = require('path');\n\n // Import issues.json\n const issuesPath = pathMod.join(baseDir, 'issues.json');\n if (fsSync.existsSync(issuesPath)) {\n const raw = fsSync.readFileSync(issuesPath, 'utf-8');\n const issues = JSON.parse(raw) as IssueEntry[];\n for (const issue of issues) {\n stmtUpsertIssue.run(issueToParams(issue));\n issueCount++;\n }\n }\n\n // Import event files\n const eventsDir = pathMod.join(baseDir, 'events');\n if (fsSync.existsSync(eventsDir)) {\n const fps = fsSync.readdirSync(eventsDir);\n for (const fp of fps) {\n const fpDir = pathMod.join(eventsDir, fp);\n if (!fsSync.statSync(fpDir).isDirectory()) continue;\n\n const files = fsSync.readdirSync(fpDir).filter((f: string) => f.startsWith('event-') && f.endsWith('.json'));\n for (const file of files) {\n try {\n const eventRaw = fsSync.readFileSync(pathMod.join(fpDir, file), 'utf-8');\n const event = JSON.parse(eventRaw) as UncaughtEvent;\n stmtInsertEvent.run({\n event_id: event.eventId,\n fingerprint: event.fingerprint,\n timestamp: event.timestamp,\n level: event.level,\n fix_prompt: event.fixPrompt ?? '',\n payload: eventRaw,\n });\n eventCount++;\n } catch {\n // Skip malformed event files\n }\n }\n }\n }\n } catch {\n // Migration is best-effort\n }\n\n stmtSetMeta.run('migrated', 'true');\n return { issues: issueCount, events: eventCount };\n },\n\n close(): void {\n db.close();\n },\n };\n}\n"]}
@@ -0,0 +1,23 @@
1
+ 'use strict';function f(r){let n=[];if(n.push(`I have a production bug in my application that I need help diagnosing and fixing.
2
+ `),r.error){let o=i(r.error.stack),t=["## Error",""];t.push(`- **Type:** ${r.error.type||"Error"}`),t.push(`- **Message:** ${r.error.message||"(no message)"}`),o&&t.push(`- **Location:** ${o}`),n.push(t.join(`
3
+ `));}let s=r.error?.resolvedStack??r.error?.stack;if(s){let o=s.split(`
4
+ `).slice(0,15).map(e=>e.trimEnd()).join(`
5
+ `),t=r.error?.resolvedStack?"Stack Trace (source-mapped)":"Stack Trace";n.push(`## ${t}
6
+
7
+ \`\`\`
8
+ ${o}
9
+ \`\`\``);}return r.operation&&n.push(a(r.operation)),r.request&&n.push(u(r.request)),r.breadcrumbs&&r.breadcrumbs.length>0&&n.push(c(r.breadcrumbs)),r.environment&&n.push(m(r.environment)),r.error?.componentStack&&n.push(`## React Component Stack
10
+
11
+ \`\`\`
12
+ ${r.error.componentStack.trim()}
13
+ \`\`\``),n.push(["## What I need","","1. **Root cause analysis** \u2014 explain why this error is occurring.","2. **A fix** \u2014 provide the corrected code with an explanation of the changes.","3. **Prevention** \u2014 suggest any guards or tests to prevent this from happening again."].join(`
14
+ `)),n.join(`
15
+
16
+ `)+`
17
+ `}function i(r){if(r)for(let n of r.split(`
18
+ `)){let s=n.trim(),o=s.match(/at\s+(?:.+?\s+\()?(.+?:\d+:\d+)\)?/);if(o)return o[1];let t=s.match(/@(.+?:\d+:\d+)/);if(t)return t[1]}}function a(r){let n=["## Failed Operation",""];return n.push(`- **Provider:** ${r.provider}`),n.push(`- **Type:** ${r.type}`),n.push(`- **Method:** ${r.method}`),r.params&&(n.push("- **Params:**"),n.push("```json"),n.push(JSON.stringify(r.params,null,2)),n.push("```")),r.errorCode&&n.push(`- **Error Code:** ${r.errorCode}`),r.errorDetails&&n.push(`- **Error Details:** ${r.errorDetails}`),n.join(`
19
+ `)}function u(r){let n=["## HTTP Request Context",""];return r.method&&n.push(`- **Method:** ${r.method}`),r.url&&n.push(`- **URL:** ${r.url}`),r.body&&(n.push("- **Body:**"),n.push("```json"),n.push(typeof r.body=="string"?r.body:JSON.stringify(r.body,null,2)),n.push("```")),n.join(`
20
+ `)}function c(r){let n=r.slice(-5),s=["## User Session",""];for(let o of n){let t=p(o.timestamp);s.push(`- \`${t}\` **[${o.type}]** ${o.message}`);}return s.join(`
21
+ `)}function p(r){try{let n=new Date(r),s=String(n.getHours()).padStart(2,"0"),o=String(n.getMinutes()).padStart(2,"0"),t=String(n.getSeconds()).padStart(2,"0");return `${s}:${o}:${t}`}catch{return r}}function m(r){let n=["## Environment",""],s=[["Deploy Environment",r.deploy],["Framework",r.framework],["Framework Version",r.frameworkVersion],["Runtime",r.runtime],["Runtime Version",r.runtimeVersion],["Platform",r.platform],["Browser",r.browser?`${r.browser} ${r.browserVersion??""}`.trim():void 0],["OS",r.os],["Device",r.deviceType],["Locale",r.locale],["Timezone",r.timezone],["URL",r.url]];for(let[o,t]of s)t&&n.push(`- **${o}:** ${t}`);return n.join(`
22
+ `)}exports.a=f;//# sourceMappingURL=chunk-WZBG5VLB.js.map
23
+ //# sourceMappingURL=chunk-WZBG5VLB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/prompt-builder.ts"],"names":["buildFixPrompt","event","sections","location","extractLocation","lines","stackSource","frames","l","label","formatOperation","formatRequest","formatBreadcrumbs","formatEnvironment","stack","line","trimmed","v8","sm","op","req","crumbs","recent","crumb","time","formatTime","iso","d","h","m","s","env","entries","value"],"mappings":"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","file":"chunk-WZBG5VLB.js","sourcesContent":["// ---------------------------------------------------------------------------\n// @uncaughtdev/core — fix-prompt builder\n// ---------------------------------------------------------------------------\n\nimport type { UncaughtEvent, Breadcrumb, EnvironmentInfo, OperationInfo, RequestInfo } from './types';\n\n/**\n * Build a structured Markdown prompt that can be pasted into an AI assistant\n * to diagnose and fix the production error described by `event`.\n *\n * Empty sections are omitted to keep the prompt concise.\n */\nexport function buildFixPrompt(event: Partial<UncaughtEvent>): string {\n const sections: string[] = [];\n\n // ----- Intro -------------------------------------------------------------\n sections.push(\n 'I have a production bug in my application that I need help diagnosing and fixing.\\n'\n );\n\n // ----- Error -------------------------------------------------------------\n if (event.error) {\n const location = extractLocation(event.error.stack);\n const lines: string[] = ['## Error', ''];\n lines.push(`- **Type:** ${event.error.type || 'Error'}`);\n lines.push(`- **Message:** ${event.error.message || '(no message)'}`);\n if (location) {\n lines.push(`- **Location:** ${location}`);\n }\n sections.push(lines.join('\\n'));\n }\n\n // ----- Stack Trace -------------------------------------------------------\n const stackSource = event.error?.resolvedStack ?? event.error?.stack;\n if (stackSource) {\n const frames = stackSource\n .split('\\n')\n .slice(0, 15)\n .map((l) => l.trimEnd())\n .join('\\n');\n const label = event.error?.resolvedStack ? 'Stack Trace (source-mapped)' : 'Stack Trace';\n sections.push(`## ${label}\\n\\n\\`\\`\\`\\n${frames}\\n\\`\\`\\``);\n }\n\n // ----- Failed Operation --------------------------------------------------\n if (event.operation) {\n sections.push(formatOperation(event.operation));\n }\n\n // ----- HTTP Request Context ----------------------------------------------\n if (event.request) {\n sections.push(formatRequest(event.request));\n }\n\n // ----- User Session (last 5 breadcrumbs) ---------------------------------\n if (event.breadcrumbs && event.breadcrumbs.length > 0) {\n sections.push(formatBreadcrumbs(event.breadcrumbs));\n }\n\n // ----- Environment -------------------------------------------------------\n if (event.environment) {\n sections.push(formatEnvironment(event.environment));\n }\n\n // ----- React Component Stack ---------------------------------------------\n if (event.error?.componentStack) {\n sections.push(\n `## React Component Stack\\n\\n\\`\\`\\`\\n${event.error.componentStack.trim()}\\n\\`\\`\\``\n );\n }\n\n // ----- What I need -------------------------------------------------------\n sections.push(\n [\n '## What I need',\n '',\n '1. **Root cause analysis** — explain why this error is occurring.',\n '2. **A fix** — provide the corrected code with an explanation of the changes.',\n '3. **Prevention** — suggest any guards or tests to prevent this from happening again.',\n ].join('\\n')\n );\n\n return sections.join('\\n\\n') + '\\n';\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Extract the top-most location (file:line:col) from a stack trace string.\n */\nfunction extractLocation(stack?: string): string | undefined {\n if (!stack) return undefined;\n\n for (const line of stack.split('\\n')) {\n const trimmed = line.trim();\n\n // V8: \" at fn (file:line:col)\"\n const v8 = trimmed.match(/at\\s+(?:.+?\\s+\\()?(.+?:\\d+:\\d+)\\)?/);\n if (v8) return v8[1];\n\n // SpiderMonkey / JSC: \"fn@file:line:col\"\n const sm = trimmed.match(/@(.+?:\\d+:\\d+)/);\n if (sm) return sm[1];\n }\n\n return undefined;\n}\n\nfunction formatOperation(op: OperationInfo): string {\n const lines: string[] = ['## Failed Operation', ''];\n lines.push(`- **Provider:** ${op.provider}`);\n lines.push(`- **Type:** ${op.type}`);\n lines.push(`- **Method:** ${op.method}`);\n if (op.params) {\n lines.push(`- **Params:**`);\n lines.push('```json');\n lines.push(JSON.stringify(op.params, null, 2));\n lines.push('```');\n }\n if (op.errorCode) {\n lines.push(`- **Error Code:** ${op.errorCode}`);\n }\n if (op.errorDetails) {\n lines.push(`- **Error Details:** ${op.errorDetails}`);\n }\n return lines.join('\\n');\n}\n\nfunction formatRequest(req: RequestInfo): string {\n const lines: string[] = ['## HTTP Request Context', ''];\n if (req.method) lines.push(`- **Method:** ${req.method}`);\n if (req.url) lines.push(`- **URL:** ${req.url}`);\n if (req.body) {\n lines.push(`- **Body:**`);\n lines.push('```json');\n lines.push(\n typeof req.body === 'string'\n ? req.body\n : JSON.stringify(req.body, null, 2)\n );\n lines.push('```');\n }\n return lines.join('\\n');\n}\n\nfunction formatBreadcrumbs(crumbs: Breadcrumb[]): string {\n // Take the last 5 breadcrumbs\n const recent = crumbs.slice(-5);\n const lines: string[] = ['## User Session', ''];\n\n for (const crumb of recent) {\n const time = formatTime(crumb.timestamp);\n lines.push(`- \\`${time}\\` **[${crumb.type}]** ${crumb.message}`);\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Extract HH:MM:SS from an ISO timestamp.\n */\nfunction formatTime(iso: string): string {\n try {\n const d = new Date(iso);\n const h = String(d.getHours()).padStart(2, '0');\n const m = String(d.getMinutes()).padStart(2, '0');\n const s = String(d.getSeconds()).padStart(2, '0');\n return `${h}:${m}:${s}`;\n } catch {\n return iso;\n }\n}\n\nfunction formatEnvironment(env: EnvironmentInfo): string {\n const lines: string[] = ['## Environment', ''];\n const entries: Array<[string, string | undefined]> = [\n ['Deploy Environment', env.deploy],\n ['Framework', env.framework],\n ['Framework Version', env.frameworkVersion],\n ['Runtime', env.runtime],\n ['Runtime Version', env.runtimeVersion],\n ['Platform', env.platform],\n ['Browser', env.browser ? `${env.browser} ${env.browserVersion ?? ''}`.trim() : undefined],\n ['OS', env.os],\n ['Device', env.deviceType],\n ['Locale', env.locale],\n ['Timezone', env.timezone],\n ['URL', env.url],\n ];\n\n for (const [label, value] of entries) {\n if (value) {\n lines.push(`- **${label}:** ${value}`);\n }\n }\n\n return lines.join('\\n');\n}\n"]}