Create your first portable bug report#
This runnable Node example creates an incomplete but useful report, adds observed behavior as a new revision, and exports it with an explicit review policy. No browser, React component, tracker, or server is required.
Prepare#
Want to inspect the revision behavior before setting up Node? Run the small browser example. It uses supported APIs with authored data; the Node example below additionally exports a portable bundle.
Complete workspace setup and pnpm build. Save the following as an .mjs file at the repository root so Node resolves the built workspace packages. Run it with the pinned Node runtime (pnpm exec node your-file.mjs). Generated report output belongs outside tracked source.
import { mkdir, writeFile } from 'node:fs/promises';
import { join } from 'node:path';
import { createBugReport, reviseBugReport } from '@snagbadger/reporting';
import { createReportBundle } from '@snagbadger/reporting/bundle';
const at = '2026-10-11T12:00:00.000Z';
const initial = createBugReport({
id: 'profile-save-example',
at,
title: 'Saved profile name disappears after navigation',
expected: {
text: 'The saved display name survives in-page navigation',
basis: 'established',
},
});
const report = reviseBugReport(
initial,
{
actual: 'Save confirmed Morgan Lee; returning showed Alex Morgan',
steps: [
{
id: 'save-and-return',
instruction:
'In Buggy save mode, save Morgan Lee, visit Overview, then Profile',
basis: 'observed',
verification: 'unverified',
evidenceIds: [],
interactionIds: [],
},
],
},
'2026-10-11T12:01:00.000Z',
);
const bundle = await createReportBundle(report, {
exportId: 'profile-export-example',
at: '2026-10-11T12:02:00.000Z',
readAttachment: () => null,
policy: {
id: 'reviewed-public-example',
// Only this known, authored example has been manually reviewed.
reviewReport: (value) => value,
// Real attachments need a project-owned review before inclusion.
reviewAttachment: () => ({ action: 'omit' }),
},
});
const directory = 'dist/first-bug-report';
for (const file of bundle.files) {
const target = join(directory, file.path);
await mkdir(join(target, '..'), { recursive: true });
await writeFile(target, file.content);
}
console.log(
report.id,
report.revision,
bundle.files.map((file) => file.path),
);
Inspect the result#
The identity remains profile-save-example, and the revision is 2. Open dist/first-bug-report/index.html; inspect report.json beside it. The report has no screenshot, executable reproduction, or verified replay claim. Its described steps are authored from the sample observation; running this snippet does not observe a browser.
The source report remains unchanged by export. Export identity and review policy identify a reviewed derivative of revision 2. This example's pass-through narrative review is appropriate only for its known authored text, not arbitrary user reports.
For a prepared fixture with a diagnostic redaction and incidental test comment, use the generated report example. For real data, continue with sanitization and export and portable report contracts.