@rallycry/conveyor-incidents
v0.3.1
Published
Typed TypeScript client for Conveyor's public incidents REST API
Maintainers
Readme
@rallycry/conveyor-incidents
Typed TypeScript client for reporting incidents to Conveyor via the public REST API.
Install
npm install @rallycry/conveyor-incidents
# or
bun add @rallycry/conveyor-incidentsUsage
import { ConveyorIncidents } from "@rallycry/conveyor-incidents";
const incidents = new ConveyorIncidents({
apiKey: process.env.CONVEYOR_INCIDENT_TOKEN!, // cvyr_... project token with "incident" scope
projectId: process.env.CONVEYOR_PROJECT_ID!,
});
const { incidentId, attachmentResults } = await incidents.report({
title: "Checkout service returned 500",
description: "Happened on release v1.4.2 under load.",
severity: "high",
source: "prod-web", // stable values let the server dedup repeats
fingerprintKey: "checkout-500-v1.4.2",
attachments: [
{
fileName: "stack.txt",
mimeType: "text/plain",
content: stackTrace, // string or Uint8Array
},
],
});Card types
report() accepts an optional type — "incident" (default), "suggestion", or "task":
"incident"— fingerprint dedup (see below); repeat reports collapse into one incident."suggestion"— AI duplicate detection; a repeat report upvotes the existing suggestion and returns its id instead of creating a new card.fingerprintKeyandseverityare ignored (suggestions are ranked by votes)."task"— creates a plain task card. No dedup;fingerprintKeyis ignored.severitymaps to the card's priority.
// Platform-user suggestion, routed to the team for review
await incidents.report({
type: "suggestion",
title: "Add dark mode toggle",
assigned: ["[email protected]"],
review: ["[email protected]", "[email protected]"],
});Assigning members by email
assigned and review are optional arrays of email addresses, matched against the target project's members:
assigned— the first email that resolves to a project member becomes the card's assignee; remaining entries are ignored.review— every email that resolves to a project member is added as a reviewer.- Emails that don't match a project member are silently skipped — safe to pass end-user emails; only teammates who are members of the Conveyor project resolve.
- Applied only when a new card is created. Dedup hits (incident fingerprint match, suggestion AI-merge) leave the existing card untouched.
// Incident auto-assigned when reporter is @rallycry.gg
await incidents.report({
title: "Checkout service returned 500",
severity: "high",
fingerprintKey: "checkout-500-v1.4.2",
assigned: ["[email protected]"],
});Creator attribution (createdBy)
createdBy is an optional single email, matched against the target project's members the same way as assigned/review:
- A resolvable project-member email becomes the card's creator.
- When omitted — or when the email doesn't resolve to a member — the card is attributed to the "Conveyor Incidents" system user, not a human.
- Applied only when a new card is created; dedup hits keep the existing creator.
Behavior change in 0.3.0: previously, cards reported through this endpoint were attributed to the token owner (suggestions/tasks) or the project owner (incidents). Pass
createdByexplicitly if you want a specific member credited.
await incidents.report({
type: "task",
title: "Wire up the new webhook",
createdBy: "[email protected]",
});About source and fingerprintKey
Conveyor deduplicates reports by a fingerprint derived from (projectId, source, fingerprintKey) — or by (projectId, source, title) if fingerprintKey is omitted. Use stable values for source (e.g. "prod-web", not "node-pid-1234") so that repeat reports collapse into a single incident instead of creating noise.
Attachment limits
- 5 MB per file (
MAX_ATTACHMENT_BYTES, exported). Oversized files are rejected client-side with a descriptiveattachmentResultserror — no HTTP call is made. - 10 attachments per card (server-enforced).
Error handling
- The main
report()call throwsConveyorIncidentsErroron non-2xx responses; it exposes.statusand.body. - Attachment upload failures are captured per-file in
attachmentResultsand never throw — inspectokanderror.
Node <18
Pass a fetch polyfill via opts.fetch if your runtime lacks a global fetch.
DEP0169 url.parse() warning
The @rallycry/conveyor-incidents SDK does not call url.parse() — it uses the WHATWG URL constructor and the global fetch API. If your process emits this warning while using the SDK, the call is coming from another dependency in your project. Run node --trace-deprecation your-script.js to locate the source.
Troubleshooting 403 from /api/incidents/report
The endpoint requires a project token with scope: "incident". After the 2026-04-22 scope migration, older project tokens default to scope: "claude_code" and are rejected. The error body now includes a reason field — "scope_mismatch" indicates the token exists but is scoped for another surface; generate a new token from Project Settings → Incidents in the Conveyor UI.
API
new ConveyorIncidents({
apiKey: string;
projectId: string;
baseUrl?: string; // default: "https://api.conveyor.rallycryapp.com"
fetch?: typeof fetch;
});
client.report({
title: string;
description?: string;
severity?: "critical" | "high" | "medium" | "low"; // default: "medium"
source?: string; // default: "client"
fingerprintKey?: string;
plan?: string;
type?: "incident" | "suggestion" | "task"; // default: "incident"
assigned?: string[]; // project-member emails; first match becomes assignee
review?: string[]; // project-member emails; every match becomes a reviewer
createdBy?: string; // project-member email; no match → "Conveyor Incidents" system user
attachments?: Array<{
fileName: string;
mimeType: string;
content: Uint8Array | string; // strings are utf-8 encoded
}>;
}): Promise<{
incidentId: string;
cardId: string; // alias of incidentId — prefer for suggestion/task types
attachmentResults: Array<{
fileName: string;
ok: boolean;
fileId?: string;
error?: string;
}>;
}>;License
MIT
