Debug and gap reports

Receive a record of each CLI run in apps that use your package, and handle the gap reports they send about it.

Record runs with debug

Export a debug function from astryx.integration.mjs, and the CLI calls it once for each command run in an app that loads your package.

js
// astryx.integration.mjs
import {appendFileSync} from 'node:fs';
​
/** @param {import('@astryxdesign/cli/authoring').DebugEvent} event */
export function debug(event) {
if (event.outcome !== 'ok') {
appendFileSync('acme-failed-runs.ndjson', JSON.stringify(event) + '\n');
}
}
​
export default {
components: './components',
};

The event is a DebugEvent with command, outcome, exitCode, durationMs, error, and more, its values scrubbed (redacted: true). Every field is in astryx docs authoring.

Keep the function synchronous: the CLI calls it as the process exits and never waits for a promise. The app's own debug handler runs first, then yours. A handler that throws is skipped, and the command's output and exit code stay the same.

An app records every command only when its astryx.config names integrations or debug, as listing your package does. Otherwise your handler runs only for commands that load the app's project, such as component and docs, and not for --version or a mistyped command. In an app whose config names neither word, each of those commands also prints a warning on stderr.

debug is a named export, not a manifest field, so a CLI that does not know it ignores it and loads the rest of your manifest.

Turn off debug in an app

An app can refuse every integration's debug handler and keep its own. It sets inheritDebug in its package.json:

json
{"astryx": {"inheritDebug": false}}

From then on, your handler no longer runs in that app.

Handle gap reports

Export a gapReport handler, and astryx gap-report in an app sends it each gap report, such as a missing component or variant. The handler files the report and returns a receipt.

js
/** @type {import('@astryxdesign/cli/authoring').GapReportHandler} */
export const gapReport = {
audience: 'public',
async handle(report, {signal}) {
if (report.target.package !== '@acme/astryx-widgets') return {status: 'skipped'};
const body = JSON.stringify(report);
const response = await fetch('https://tracker.example.com/issues', {method: 'POST', body, signal});
const {url} = await response.json();
return {status: 'filed', url};
},
};

Every handler in the app gets every report, so check report.target.package and skip reports about other packages. The receipt status is one of:

`status`Meaning
filedYou created or queued the report. Return url or message.
routed_onlyYou point the caller to where to file it. url is required.
skippedYou chose not to act, for example on a duplicate.

The CLI waits 30 seconds, then aborts signal. A throw, a timeout, or an invalid receipt fails your delivery, and the command exits 1; the other handlers still run. Like debug, gapReport is a named export that older CLIs ignore.

Ask before filing in public

Set audience: 'public' when your handler writes somewhere the public can read. The CLI runs it only when the caller passes --confirm-public; an 'internal' handler always runs.

bash
npx astryx gap-report AcmeCarousel --category missing_variant --reason 'Need a vertical layout'
text
handlerType: integration
handler: @acme/astryx-widgets
audience: public
status: consent_required
message: Rerun with --confirm-public to file this report.

With --confirm-public, the same delivery reads status: filed and shows your url. The report goes to the package named by --package, else the package that owns the component, else Core.

Fall back to issuesUrl

When the app has no gapReport handler at all, the CLI routes the report to the target package's issuesUrl from its manifest instead.

  • A GitHub issues URL, such as https://github.com/acme/widgets/issues, gets an issue filed with the GitHub CLI, gh, once the caller passes --confirm-public.
  • Any other URL comes back as a routed_only receipt for the caller to open.
  • With no issuesUrl, the command fails: Package "@acme/astryx-widgets" provides neither a report handler nor an issues URL.

One handler anywhere in the app, from the app or from any package, turns the fallback off for every report. See astryx docs cli/commands/gap-report.