@rallycry/conveyor-incidents 0.3.4 → 0.3.5

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.
package/README.md CHANGED
@@ -49,8 +49,8 @@ const { incidentId, attachmentResults } = await incidents.report({
49
49
  await incidents.report({
50
50
  type: "suggestion",
51
51
  title: "Add dark mode toggle",
52
- assigned: ["logan@rallycry.gg"],
53
- review: ["dev1@rallycry.gg", "dev2@rallycry.gg"],
52
+ assigned: ["alice@example.com"],
53
+ review: ["bob@example.com", "carol@example.com"],
54
54
  });
55
55
  ```
56
56
 
@@ -64,12 +64,12 @@ await incidents.report({
64
64
  - Applied **only when a new card is created**. Dedup hits (incident fingerprint match, suggestion AI-merge) leave the existing card untouched.
65
65
 
66
66
  ```ts
67
- // Incident auto-assigned when reporter is @rallycry.gg
67
+ // Incident auto-assigned when the reporter is on your own email domain
68
68
  await incidents.report({
69
69
  title: "Checkout service returned 500",
70
70
  severity: "high",
71
71
  fingerprintKey: "checkout-500-v1.4.2",
72
- assigned: ["logan@rallycry.gg"],
72
+ assigned: ["alice@example.com"],
73
73
  });
74
74
  ```
75
75
 
@@ -87,7 +87,7 @@ await incidents.report({
87
87
  await incidents.report({
88
88
  type: "task",
89
89
  title: "Wire up the new webhook",
90
- createdBy: "logan@rallycry.gg",
90
+ createdBy: "alice@example.com",
91
91
  });
92
92
  ```
93
93
 
package/dist/index.js CHANGED
@@ -358,4 +358,3 @@ export {
358
358
  installNetworkCapture,
359
359
  uninstallNetworkCapture
360
360
  };
361
- //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rallycry/conveyor-incidents",
3
- "version": "0.3.4",
3
+ "version": "0.3.5",
4
4
  "description": "Typed TypeScript client for Conveyor's public incidents REST API",
5
5
  "keywords": [
6
6
  "client",
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/index.ts"],"sourcesContent":["export class ConveyorIncidentsError extends Error {\n readonly status: number;\n readonly body: unknown;\n\n constructor(message: string, status: number, body: unknown) {\n super(message);\n this.name = \"ConveyorIncidentsError\";\n this.status = status;\n this.body = body;\n }\n}\n","import { ConveyorIncidentsError } from \"./errors.js\";\n\nexport { ConveyorIncidentsError } from \"./errors.js\";\n\nconst DEFAULT_BASE_URL = \"https://api.conveyor.rallycryapp.com\";\nconst DEFAULT_SOURCE = \"client\";\nconst DEFAULT_SEVERITY: IncidentSeverity = \"medium\";\n\n/** Server-side per-file ceiling — keep in sync with MAX_ATTACHMENT_BYTES in\n * conveyor's incident-routes.ts. Checked client-side so an oversized file\n * fails with a descriptive `attachmentResults` error instead of an HTTP 413. */\nexport const MAX_ATTACHMENT_BYTES = 5 * 1024 * 1024;\n\nexport type IncidentSeverity = \"critical\" | \"high\" | \"medium\" | \"low\";\n\nexport type ConveyorCardType = \"incident\" | \"suggestion\" | \"task\";\n\nexport interface ConveyorIncidentsOptions {\n apiKey: string;\n projectId: string;\n baseUrl?: string;\n fetch?: typeof fetch;\n}\n\nexport interface IncidentAttachment {\n fileName: string;\n mimeType: string;\n content: Uint8Array | string;\n}\n\nexport interface NetworkCaptureOptions {\n /** Maximum entries kept in memory. Defaults to 80. */\n maxEntries?: number;\n /** Maximum response body characters kept per captured entry. Defaults to 4000. */\n maxBodyChars?: number;\n /** Capture response snippets for successful tRPC batch calls as well as failures. Defaults to true. */\n captureTrpcResponses?: boolean;\n}\n\nexport interface NetworkLogEntry {\n timestamp: string;\n kind: \"fetch\";\n method: string;\n url: string;\n status: number | null;\n ok: boolean | null;\n durationMs: number;\n responseBytes: number | null;\n contentType?: string;\n requestTraceparent?: string;\n responseTraceparent?: string;\n trpcProcedures?: string[];\n responseSnippet?: string;\n error?: string;\n}\n\n/**\n * Who filed the report and where they were when they filed it. Unlike\n * `createdBy`, this needs no Conveyor project membership — it's descriptive\n * metadata, rendered into the card's description footer and onto the Slack\n * card. Send it for every user-initiated report: without it a card from an\n * end user is indistinguishable from an automated alert.\n */\nexport interface ReportReporter {\n /** Display name / username of the person filing the report. */\n name?: string;\n /** Contact email. Also used for attribution when it matches a member. */\n email?: string;\n /** Absolute http(s) URL of the page the user was on at report time. */\n url?: string;\n}\n\nexport interface ReportIncidentInput {\n title: string;\n description?: string;\n severity?: IncidentSeverity;\n source?: string;\n fingerprintKey?: string;\n plan?: string;\n attachments?: IncidentAttachment[];\n /** Card type to create. The server defaults to \"incident\" when omitted. */\n type?: ConveyorCardType;\n /**\n * Project-member emails. The FIRST email that resolves to a member of the\n * target project becomes the card's assignee; the rest are ignored.\n * Non-member emails are silently skipped.\n */\n assigned?: string[];\n /**\n * Project-member emails. EVERY email that resolves to a member of the\n * target project is added as a reviewer. Non-member emails are silently\n * skipped.\n */\n review?: string[];\n /**\n * Project-member email used as the card's creator. When omitted — or when\n * the email doesn't resolve to a member of the target project — the card\n * is attributed to the \"Conveyor Incidents\" system user.\n */\n createdBy?: string;\n /**\n * Reporter identity + the page they were on. Rendered into the card's\n * description metadata footer (and the Slack card) by the server; lines the\n * description already carries are not duplicated.\n *\n * `reporter.email` is also stored on the card as a structured field, which is\n * what Conveyor replies to when it drafts a thank-you email to the reporter.\n * No project membership is required, so an external reporter with no Conveyor\n * account still gets a reply.\n */\n reporter?: ReportReporter;\n}\n\nexport interface AttachmentResult {\n fileName: string;\n ok: boolean;\n fileId?: string;\n error?: string;\n}\n\nexport interface ReportIncidentResult {\n incidentId: string;\n /** Alias of `incidentId` — prefer this when reporting type \"suggestion\" or \"task\". */\n cardId: string;\n attachmentResults: AttachmentResult[];\n}\n\nlet networkCaptureState:\n | {\n installed: true;\n originalFetch: typeof fetch;\n entries: NetworkLogEntry[];\n options: Required<NetworkCaptureOptions>;\n }\n | undefined;\n\nconst DEFAULT_NETWORK_CAPTURE_OPTIONS: Required<NetworkCaptureOptions> = {\n maxEntries: 80,\n maxBodyChars: 4000,\n captureTrpcResponses: true,\n};\n\nexport function installNetworkCapture(options: NetworkCaptureOptions = {}): void {\n if (typeof globalThis.fetch !== \"function\") return;\n // Bind to globalThis: some browsers (notably Safari/WebKit) throw\n // \"Illegal invocation\" when the native fetch is called without its\n // original receiver, which a bare captured reference loses.\n const fetchImpl = globalThis.fetch.bind(globalThis);\n\n const resolvedOptions = {\n ...DEFAULT_NETWORK_CAPTURE_OPTIONS,\n ...options,\n };\n\n if (networkCaptureState) {\n networkCaptureState.options = resolvedOptions;\n return;\n }\n\n const entries: NetworkLogEntry[] = [];\n networkCaptureState = {\n installed: true,\n originalFetch: fetchImpl,\n entries,\n options: resolvedOptions,\n };\n\n globalThis.fetch = async (input: RequestInfo | URL, init?: RequestInit): Promise<Response> => {\n const state = networkCaptureState;\n const originalFetch = state?.originalFetch ?? fetchImpl;\n const startedAt = Date.now();\n const timestamp = new Date(startedAt).toISOString();\n const request = normalizeRequest(input, init);\n\n try {\n const response = await originalFetch(input, init);\n const entry = await buildNetworkEntry({\n timestamp,\n request,\n response,\n durationMs: Date.now() - startedAt,\n options: state?.options ?? resolvedOptions,\n });\n pushNetworkEntry(entry);\n return response;\n } catch (err) {\n pushNetworkEntry({\n timestamp,\n kind: \"fetch\",\n method: request.method,\n url: redactUrl(request.url),\n status: null,\n ok: null,\n durationMs: Date.now() - startedAt,\n responseBytes: null,\n requestTraceparent: request.traceparent,\n trpcProcedures: extractTrpcProcedures(request.url),\n error: err instanceof Error ? err.message : String(err),\n });\n throw err;\n }\n };\n}\n\nexport function uninstallNetworkCapture(): void {\n if (!networkCaptureState) return;\n globalThis.fetch = networkCaptureState.originalFetch;\n networkCaptureState = undefined;\n}\n\nexport function clearNetworkLogEntries(): void {\n networkCaptureState?.entries.splice(0);\n}\n\nexport function getNetworkLogEntries(): NetworkLogEntry[] {\n return [...(networkCaptureState?.entries ?? [])];\n}\n\nexport function buildNetworkLogAttachment(\n fileName = \"network.log\",\n): IncidentAttachment | undefined {\n const entries = getNetworkLogEntries();\n if (entries.length === 0) return undefined;\n return {\n fileName,\n mimeType: \"application/x-ndjson\",\n content: entries.map((entry) => JSON.stringify(entry)).join(\"\\n\"),\n };\n}\n\nexport class ConveyorIncidents {\n private readonly apiKey: string;\n private readonly projectId: string;\n private readonly baseUrl: string;\n private readonly fetchImpl: typeof fetch;\n\n constructor(opts: ConveyorIncidentsOptions) {\n if (!opts.apiKey) {\n throw new Error(\"ConveyorIncidents: apiKey is required\");\n }\n if (!opts.projectId) {\n throw new Error(\"ConveyorIncidents: projectId is required\");\n }\n const resolvedFetch = opts.fetch ?? globalThis.fetch;\n if (typeof resolvedFetch !== \"function\") {\n throw new Error(\"ConveyorIncidents: no global fetch available — pass opts.fetch on Node <18\");\n }\n this.apiKey = opts.apiKey;\n this.projectId = opts.projectId;\n this.baseUrl = stripTrailingSlash(opts.baseUrl ?? DEFAULT_BASE_URL);\n this.fetchImpl = resolvedFetch;\n }\n\n async report(input: ReportIncidentInput): Promise<ReportIncidentResult> {\n const body = {\n projectId: this.projectId,\n source: input.source ?? DEFAULT_SOURCE,\n severity: input.severity ?? DEFAULT_SEVERITY,\n title: input.title,\n description: input.description,\n plan: input.plan,\n fingerprintKey: input.fingerprintKey,\n type: input.type,\n assigned: input.assigned,\n review: input.review,\n createdBy: input.createdBy,\n reporter: normalizeReporter(input.reporter),\n };\n\n const res = await this.fetchImpl(`${this.baseUrl}/api/incidents/report`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.apiKey}`,\n },\n body: JSON.stringify(body),\n });\n\n const payload = await readJson(res);\n\n if (!res.ok) {\n throw new ConveyorIncidentsError(\n `Failed to report incident: ${res.status} ${res.statusText}`,\n res.status,\n payload,\n );\n }\n\n const incidentId = extractId(payload, \"incidentId\") ?? extractId(payload, \"cardId\");\n\n if (!incidentId) {\n throw new ConveyorIncidentsError(\n \"Invalid response from /api/incidents/report: missing incidentId\",\n res.status,\n payload,\n );\n }\n\n const attachmentResults: AttachmentResult[] = [];\n if (input.attachments && input.attachments.length > 0) {\n for (const attachment of input.attachments) {\n attachmentResults.push(await this.uploadAttachment(incidentId, attachment));\n }\n }\n\n return { incidentId, cardId: incidentId, attachmentResults };\n }\n\n private async uploadAttachment(\n incidentId: string,\n attachment: IncidentAttachment,\n ): Promise<AttachmentResult> {\n try {\n const bytes =\n typeof attachment.content === \"string\"\n ? new TextEncoder().encode(attachment.content)\n : attachment.content;\n if (bytes.byteLength > MAX_ATTACHMENT_BYTES) {\n return {\n fileName: attachment.fileName,\n ok: false,\n error: `Attachment is ${bytes.byteLength} bytes — exceeds the ${MAX_ATTACHMENT_BYTES}-byte (5 MB) server limit; upload skipped`,\n };\n }\n const contentBase64 = bytesToBase64(bytes);\n const res = await this.fetchImpl(\n `${this.baseUrl}/api/incidents/${encodeURIComponent(incidentId)}/files`,\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.apiKey}`,\n },\n body: JSON.stringify({\n fileName: attachment.fileName,\n mimeType: attachment.mimeType,\n contentBase64,\n }),\n },\n );\n\n const payload = await readJson(res);\n\n if (!res.ok) {\n return {\n fileName: attachment.fileName,\n ok: false,\n error: formatErrorBody(res.status, res.statusText, payload),\n };\n }\n\n const fileId =\n payload && typeof payload === \"object\" && \"fileId\" in payload\n ? String((payload as { fileId: unknown }).fileId)\n : undefined;\n\n return { fileName: attachment.fileName, ok: true, fileId };\n } catch (err) {\n return {\n fileName: attachment.fileName,\n ok: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n }\n}\n\nfunction pushNetworkEntry(entry: NetworkLogEntry): void {\n const state = networkCaptureState;\n if (!state) return;\n state.entries.push(entry);\n const overflow = state.entries.length - state.options.maxEntries;\n if (overflow > 0) state.entries.splice(0, overflow);\n}\n\nfunction normalizeRequest(\n input: RequestInfo | URL,\n init: RequestInit | undefined,\n): { method: string; url: string; traceparent?: string } {\n const request = typeof Request !== \"undefined\" && input instanceof Request ? input : undefined;\n const method = init?.method ?? request?.method ?? \"GET\";\n const url = request?.url ?? String(input);\n const traceparent =\n readHeader(init?.headers, \"traceparent\") ?? readHeader(request?.headers, \"traceparent\");\n return { method: method.toUpperCase(), url, traceparent };\n}\n\nasync function buildNetworkEntry(params: {\n timestamp: string;\n request: { method: string; url: string; traceparent?: string };\n response: Response;\n durationMs: number;\n options: Required<NetworkCaptureOptions>;\n}): Promise<NetworkLogEntry> {\n const { timestamp, request, response, durationMs, options } = params;\n const contentType = response.headers.get(\"content-type\") ?? undefined;\n const trpcProcedures = extractTrpcProcedures(request.url);\n const shouldCaptureBody =\n !response.ok || (options.captureTrpcResponses && trpcProcedures !== undefined);\n const bodyText = shouldCaptureBody\n ? await readResponseSnippet(response, options.maxBodyChars)\n : undefined;\n const responseBytes = readContentLength(response.headers) ?? estimateUtf8Bytes(bodyText);\n\n return {\n timestamp,\n kind: \"fetch\",\n method: request.method,\n url: redactUrl(request.url),\n status: response.status,\n ok: response.ok,\n durationMs,\n responseBytes,\n contentType,\n requestTraceparent: request.traceparent,\n responseTraceparent: response.headers.get(\"traceparent\") ?? undefined,\n trpcProcedures,\n responseSnippet: bodyText,\n };\n}\n\nfunction readHeader(headers: HeadersInit | undefined, name: string): string | undefined {\n if (!headers) return undefined;\n if (headers instanceof Headers) return headers.get(name) ?? undefined;\n const lowerName = name.toLowerCase();\n if (Array.isArray(headers)) {\n const hit = headers.find(([key]) => key.toLowerCase() === lowerName);\n return hit?.[1];\n }\n const value = Object.entries(headers).find(([key]) => key.toLowerCase() === lowerName)?.[1];\n return value;\n}\n\nfunction readContentLength(headers: Headers): number | null {\n const raw = headers.get(\"content-length\");\n if (!raw) return null;\n const parsed = Number.parseInt(raw, 10);\n return Number.isFinite(parsed) ? parsed : null;\n}\n\nfunction estimateUtf8Bytes(value: string | undefined): number | null {\n if (value === undefined) return null;\n return new TextEncoder().encode(value).byteLength;\n}\n\nasync function readResponseSnippet(\n response: Response,\n maxChars: number,\n): Promise<string | undefined> {\n try {\n const text = await response.clone().text();\n if (text.length <= maxChars) return text;\n return `${text.slice(0, maxChars)}...[truncated ${String(text.length - maxChars)} chars]`;\n } catch {\n return undefined;\n }\n}\n\nfunction extractTrpcProcedures(rawUrl: string): string[] | undefined {\n let url: URL;\n try {\n url = new URL(rawUrl, \"https://placeholder.invalid\");\n } catch {\n return undefined;\n }\n const marker = \"/trpc/\";\n const index = url.pathname.indexOf(marker);\n if (index === -1) return undefined;\n const path = url.pathname.slice(index + marker.length);\n const procedures = path\n .split(\",\")\n .map((part) => decodeURIComponent(part).trim())\n .filter((part) => part.length > 0);\n return procedures.length > 0 ? procedures : undefined;\n}\n\nfunction redactUrl(rawUrl: string): string {\n let url: URL;\n try {\n url = new URL(rawUrl, \"https://placeholder.invalid\");\n } catch {\n return rawUrl;\n }\n for (const key of [...url.searchParams.keys()]) {\n const lower = key.toLowerCase();\n if (\n lower.includes(\"token\") ||\n lower.includes(\"key\") ||\n lower.includes(\"secret\") ||\n lower.includes(\"signature\") ||\n lower.includes(\"sig\")\n ) {\n url.searchParams.set(key, \"[redacted]\");\n }\n }\n return url.origin === \"https://placeholder.invalid\"\n ? `${url.pathname}${url.search}`\n : url.toString();\n}\n\nfunction stripTrailingSlash(url: string): string {\n return url.endsWith(\"/\") ? url.slice(0, -1) : url;\n}\n\n/**\n * Trim reporter fields and drop empty ones, so a caller passing\n * `{ name: user.name ?? \"\" }` doesn't send a blank line to the server.\n * Returns undefined when nothing useful survives.\n */\nfunction normalizeReporter(reporter: ReportReporter | undefined): ReportReporter | undefined {\n if (!reporter) return undefined;\n const entries = ([\"name\", \"email\", \"url\"] as const)\n .map((key) => [key, reporter[key]?.trim()] as const)\n .filter((entry): entry is readonly [(typeof entry)[0], string] => !!entry[1]);\n if (entries.length === 0) return undefined;\n return Object.fromEntries(entries) as ReportReporter;\n}\n\nfunction extractId(payload: unknown, key: \"incidentId\" | \"cardId\"): string | undefined {\n if (payload && typeof payload === \"object\" && key in payload) {\n const value = (payload as Record<string, unknown>)[key];\n if (value !== undefined && value !== null) return String(value);\n }\n return undefined;\n}\n\nasync function readJson(res: Response): Promise<unknown> {\n const text = await res.text();\n if (!text) return undefined;\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n}\n\nfunction formatErrorBody(status: number, statusText: string, body: unknown): string {\n const prefix = `${status} ${statusText}`.trim();\n if (body && typeof body === \"object\" && \"error\" in body) {\n return `${prefix}: ${String((body as { error: unknown }).error)}`;\n }\n if (typeof body === \"string\" && body.length > 0) {\n return `${prefix}: ${body}`;\n }\n return prefix;\n}\n\nfunction bytesToBase64(bytes: Uint8Array): string {\n if (typeof Buffer !== \"undefined\") {\n return Buffer.from(bytes).toString(\"base64\");\n }\n let binary = \"\";\n for (const byte of bytes) {\n binary += String.fromCharCode(byte);\n }\n return btoa(binary);\n}\n"],"mappings":"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","names":[]}