@athon-labs/help-widget-core
v0.0.1
Published
Shared helpers for Athon help widgets: issue FormData, screen capture, and submit.
Readme
@athon-labs/help-widget-core
Shared helpers for the Athon help widgets. Host apps should use @athon-labs/help-widget-react or @athon-labs/help-widget-svelte instead of this package directly.
The widget never sees an Athon live key. It POSTs multipart form data to your backend. Your server adds Authorization: Bearer sk_live_… and forwards to Athon ingest.
Payload
Field names match POST /api/v1/ingest/issues:
| Field | Source |
| --- | --- |
| title, description | Widget form |
| reporterEmail, reporterName, reporterExternalId | Logged-in user you pass in |
| screenshots | Screen capture or attached photos (max 5) |
| route, browser, viewport | Collected in the browser |
| metadata | Optional JSON of host-supplied key-values (user type, phone, …) |
| diagnostics | JSON of recent console logs and fetch/XHR (bodies and secrets redacted) |
Your proxy should add appId or projectId.
Backend proxy
See docs/proxy.md for Node.js, Express, Next.js, SvelteKit, and Hono.
Set these on the server only:
ATHON_LIVE_KEY=sk_live_…
ATHON_APP_ID=app_…
ATHON_INGEST_URL=https://YOUR_ATHON_HOST/api/v1/ingest/issuesNode.js
import { createServer } from 'node:http';
const server = createServer(async (req, res) => {
if (req.method !== 'POST' || req.url !== '/api/support/report') {
res.writeHead(404);
res.end('Not found');
return;
}
const incoming = new Request('http://local/api/support/report', {
method: 'POST',
headers: req.headers,
body: req,
duplex: 'half',
});
const form = await incoming.formData();
form.set('appId', process.env.ATHON_APP_ID ?? '');
const upstream = await fetch(process.env.ATHON_INGEST_URL ?? '', {
method: 'POST',
headers: { Authorization: `Bearer ${process.env.ATHON_LIVE_KEY}` },
body: form,
});
res.writeHead(upstream.status, {
'content-type': upstream.headers.get('content-type') ?? 'application/json',
});
res.end(await upstream.text());
});
server.listen(3000);Do not run a JSON body parser on this route. An Express variant is in docs/proxy.md.
Next.js
app/api/support/report/route.ts:
export async function POST(request: Request) {
const form = await request.formData();
form.set('appId', process.env.ATHON_APP_ID ?? '');
const upstream = await fetch(process.env.ATHON_INGEST_URL ?? '', {
method: 'POST',
headers: { Authorization: `Bearer ${process.env.ATHON_LIVE_KEY}` },
body: form,
});
return new Response(await upstream.text(), {
status: upstream.status,
headers: { 'content-type': upstream.headers.get('content-type') ?? 'application/json' },
});
}SvelteKit
src/routes/api/support/report/+server.ts:
import { env } from '$env/dynamic/private';
import type { RequestHandler } from './$types';
export const POST: RequestHandler = async ({ request }) => {
const form = await request.formData();
form.set('appId', env.ATHON_APP_ID);
const upstream = await fetch(env.ATHON_INGEST_URL, {
method: 'POST',
headers: { Authorization: `Bearer ${env.ATHON_LIVE_KEY}` },
body: form,
});
return new Response(await upstream.text(), {
status: upstream.status,
headers: { 'content-type': upstream.headers.get('content-type') ?? 'application/json' },
});
};