@debugbundle/mcp 1.8.1 → 1.8.2

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.
Files changed (3) hide show
  1. package/dist/main.cjs +685 -435
  2. package/package.json +1 -1
  3. package/server.json +2 -2
package/dist/main.cjs CHANGED
@@ -39659,17 +39659,17 @@ var require_dns = __commonJS({
39659
39659
  const timestamp = Date.now();
39660
39660
  const records = { records: { 4: null, 6: null } };
39661
39661
  let minTTL = this.#maxTTL;
39662
- for (const record of addresses) {
39663
- record.timestamp = timestamp;
39664
- if (typeof record.ttl === "number") {
39665
- record.ttl = Math.min(record.ttl, this.#maxTTL);
39666
- minTTL = Math.min(minTTL, record.ttl);
39662
+ for (const record2 of addresses) {
39663
+ record2.timestamp = timestamp;
39664
+ if (typeof record2.ttl === "number") {
39665
+ record2.ttl = Math.min(record2.ttl, this.#maxTTL);
39666
+ minTTL = Math.min(minTTL, record2.ttl);
39667
39667
  } else {
39668
- record.ttl = this.#maxTTL;
39668
+ record2.ttl = this.#maxTTL;
39669
39669
  }
39670
- const familyRecords = records.records[record.family] ?? { ips: [] };
39671
- familyRecords.ips.push(record);
39672
- records.records[record.family] = familyRecords;
39670
+ const familyRecords = records.records[record2.family] ?? { ips: [] };
39671
+ familyRecords.ips.push(record2);
39672
+ records.records[record2.family] = familyRecords;
39673
39673
  }
39674
39674
  this.storage.set(origin.hostname, records, { ttl: minTTL });
39675
39675
  }
@@ -55119,15 +55119,15 @@ var require_util7 = __commonJS({
55119
55119
  exports2.getUniqueHostnamesFromOptions = getUniqueHostnamesFromOptions;
55120
55120
  function groupSrvRecords(records) {
55121
55121
  const recordsByPriority = {};
55122
- for (const record of records) {
55123
- if (!recordsByPriority.hasOwnProperty(record.priority)) {
55124
- recordsByPriority[record.priority] = {
55125
- totalWeight: record.weight,
55126
- records: [record]
55122
+ for (const record2 of records) {
55123
+ if (!recordsByPriority.hasOwnProperty(record2.priority)) {
55124
+ recordsByPriority[record2.priority] = {
55125
+ totalWeight: record2.weight,
55126
+ records: [record2]
55127
55127
  };
55128
55128
  } else {
55129
- recordsByPriority[record.priority].totalWeight += record.weight;
55130
- recordsByPriority[record.priority].records.push(record);
55129
+ recordsByPriority[record2.priority].totalWeight += record2.weight;
55130
+ recordsByPriority[record2.priority].records.push(record2);
55131
55131
  }
55132
55132
  }
55133
55133
  return recordsByPriority;
@@ -55140,12 +55140,12 @@ var require_util7 = __commonJS({
55140
55140
  }
55141
55141
  const random = Math.floor(Math.random() * (recordsGroup.totalWeight + recordsGroup.records.length));
55142
55142
  let total = 0;
55143
- for (const [i, record] of recordsGroup.records.entries()) {
55144
- total += 1 + record.weight;
55143
+ for (const [i, record2] of recordsGroup.records.entries()) {
55144
+ total += 1 + record2.weight;
55145
55145
  if (total > random) {
55146
- recordsGroup.totalWeight -= record.weight;
55146
+ recordsGroup.totalWeight -= record2.weight;
55147
55147
  recordsGroup.records.splice(i, 1);
55148
- return record;
55148
+ return record2;
55149
55149
  }
55150
55150
  }
55151
55151
  }
@@ -57067,13 +57067,13 @@ var require_cluster = __commonJS({
57067
57067
  if (!sortedKeys.length) {
57068
57068
  return reject(err2);
57069
57069
  }
57070
- const key = sortedKeys[0], group = groupedRecords[key], record = (0, util_1.weightSrvRecords)(group);
57070
+ const key = sortedKeys[0], group = groupedRecords[key], record2 = (0, util_1.weightSrvRecords)(group);
57071
57071
  if (!group.records.length) {
57072
57072
  sortedKeys.shift();
57073
57073
  }
57074
- self.dnsLookup(record.name).then((host) => resolve2({
57074
+ self.dnsLookup(record2.name).then((host) => resolve2({
57075
57075
  host,
57076
- port: record.port
57076
+ port: record2.port
57077
57077
  }), tryFirstOne);
57078
57078
  }
57079
57079
  tryFirstOne();
@@ -64420,6 +64420,73 @@ function createEventEnvelope(input2) {
64420
64420
  return EventEnvelopeSchema.parse(candidate);
64421
64421
  }
64422
64422
 
64423
+ // ../../packages/shared-types/src/browser-resource-routes.ts
64424
+ var BrowserResourceRoutesSchema = external_exports.object({
64425
+ items: external_exports.array(external_exports.object({ route: external_exports.string().max(1024), occurrences: external_exports.number().int().positive() })).max(20),
64426
+ recorded_occurrences: external_exports.number().int().nonnegative(),
64427
+ unattributed_occurrences: external_exports.number().int().nonnegative(),
64428
+ omitted_routes: external_exports.number().int().nonnegative(),
64429
+ coverage: external_exports.enum(["occurrence_metadata", "retained_samples"])
64430
+ });
64431
+ function normalizeResourceRoute(value) {
64432
+ if (typeof value !== "string" || !value.startsWith("/") || value.startsWith("//") || value.length > 4096)
64433
+ return null;
64434
+ const path = value.split(/[?#]/, 1)[0];
64435
+ if (/[\u0000-\u0020\u007f\\]/.test(path)) return null;
64436
+ const segments = path.split("/").filter(Boolean).map((segment) => {
64437
+ let decoded;
64438
+ try {
64439
+ decoded = decodeURIComponent(segment);
64440
+ } catch {
64441
+ return "{param}";
64442
+ }
64443
+ if (decoded === "{param}" || /^:[A-Za-z_][A-Za-z_0-9]*$/.test(decoded)) return "{param}";
64444
+ return /^\d+$/.test(decoded) || /^[a-f0-9-]{16,}$/i.test(decoded) || /^[A-Za-z0-9_-]{24,}$/.test(decoded) || decoded.length >= 16 && /[A-Za-z]/.test(decoded) && /\d/.test(decoded) || /[@/\\\u0000-\u0020\u007f]/.test(decoded) ? "{param}" : segment;
64445
+ });
64446
+ const route = `/${segments.join("/")}`;
64447
+ return route.length <= 1024 ? route : null;
64448
+ }
64449
+ function summarizeResourceRoutes(routes, occurrenceCount) {
64450
+ const counts = /* @__PURE__ */ new Map();
64451
+ for (const raw of routes) {
64452
+ const route = normalizeResourceRoute(raw);
64453
+ if (route !== null) counts.set(route, (counts.get(route) ?? 0) + 1);
64454
+ }
64455
+ const items = [...counts].map(([route, occurrences]) => ({ route, occurrences })).sort(
64456
+ (a, b) => b.occurrences - a.occurrences || (a.route < b.route ? -1 : a.route > b.route ? 1 : 0)
64457
+ );
64458
+ const recorded = items.reduce((total, item) => total + item.occurrences, 0);
64459
+ return {
64460
+ items: items.slice(0, 20),
64461
+ recorded_occurrences: recorded,
64462
+ unattributed_occurrences: Math.max(0, occurrenceCount - recorded),
64463
+ omitted_routes: Math.max(0, items.length - 20),
64464
+ coverage: "retained_samples"
64465
+ };
64466
+ }
64467
+
64468
+ // ../../packages/shared-types/src/browser-resource-context.ts
64469
+ var BrowserResourceContextSchema = external_exports.object({
64470
+ version: external_exports.literal(1),
64471
+ host: external_exports.string().max(255).nullable(),
64472
+ path: external_exports.string().max(1024),
64473
+ type: external_exports.string().nullable(),
64474
+ first_party: external_exports.boolean().nullable(),
64475
+ role: external_exports.enum([
64476
+ "analytics",
64477
+ "advertising",
64478
+ "tag_manager",
64479
+ "authentication",
64480
+ "application_asset",
64481
+ "unknown"
64482
+ ]),
64483
+ provider: external_exports.string().nullable(),
64484
+ title: external_exports.string(),
64485
+ optional_candidate: external_exports.boolean(),
64486
+ diagnosis: external_exports.string(),
64487
+ routes: BrowserResourceRoutesSchema
64488
+ });
64489
+
64423
64490
  // ../../packages/shared-types/src/tier-capabilities.ts
64424
64491
  var TIER_CAPABILITIES = {
64425
64492
  free: {
@@ -65254,6 +65321,93 @@ var CaptureRulesFileSchema = external_exports.object({
65254
65321
  rules: external_exports.array(CaptureRuleSchema)
65255
65322
  });
65256
65323
 
65324
+ // ../../packages/shared-types/src/browser-resource.ts
65325
+ function record(value) {
65326
+ return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
65327
+ }
65328
+ function httpUrl(value, base2) {
65329
+ if (typeof value !== "string" || value.length === 0 || value.length > 4096 || /[\u0000-\u0020\u007f]/.test(value))
65330
+ return null;
65331
+ try {
65332
+ const url = base2 === void 0 ? new URL(value) : new URL(value, base2);
65333
+ return url.protocol === "http:" || url.protocol === "https:" ? url : null;
65334
+ } catch {
65335
+ return null;
65336
+ }
65337
+ }
65338
+ function browserResourceLocation(source, page) {
65339
+ if (typeof source !== "string") return null;
65340
+ const pageUrl = httpUrl(page);
65341
+ const url = httpUrl(source, pageUrl ?? void 0);
65342
+ if (url !== null) {
65343
+ if (url.pathname.length > 1024 || url.hostname.length > 255) return null;
65344
+ return {
65345
+ host: url.hostname.toLowerCase(),
65346
+ path: url.pathname || "/",
65347
+ first_party: pageUrl === null ? null : url.origin === pageUrl.origin
65348
+ };
65349
+ }
65350
+ if (source.startsWith("/") && !source.startsWith("//") && !source.includes("\\") && !/[\u0000-\u0020\u007f]/.test(source)) {
65351
+ const path = source.split(/[?#]/, 1)[0];
65352
+ if (path.length <= 1024) return { host: null, path, first_party: true };
65353
+ }
65354
+ return null;
65355
+ }
65356
+ function describeBrowserResource(value) {
65357
+ const event = record(value);
65358
+ if (event?.["kind"] !== "resource_error") return null;
65359
+ const target = record(event["target"]);
65360
+ const page = record(event["page"]);
65361
+ const location = browserResourceLocation(
65362
+ target?.["source_url"] ?? event["file_name"],
65363
+ page?.["url"]
65364
+ );
65365
+ if (location === null) return null;
65366
+ const tag2 = typeof target?.["tag_name"] === "string" ? target["tag_name"].toLowerCase() : null;
65367
+ const type = tag2 !== null && [
65368
+ "script",
65369
+ "link",
65370
+ "img",
65371
+ "audio",
65372
+ "video",
65373
+ "source",
65374
+ "iframe",
65375
+ "object",
65376
+ "embed",
65377
+ "input"
65378
+ ].includes(tag2) ? tag2 : null;
65379
+ let role = location.first_party === true ? "application_asset" : "unknown";
65380
+ let provider = null;
65381
+ if (type === "script") {
65382
+ if (location.host === "www.googletagmanager.com" && location.path === "/gtm.js") {
65383
+ provider = "Google Tag Manager";
65384
+ role = "tag_manager";
65385
+ } else if (location.host === "connect.facebook.net" && /^\/[a-z]{2}_[A-Z]{2}\/fbevents\.js$/.test(location.path)) {
65386
+ provider = "Meta Pixel";
65387
+ role = "advertising";
65388
+ } else if (location.host === "www.clarity.ms" && /^\/tag\/[A-Za-z0-9]+$/.test(location.path)) {
65389
+ provider = "Microsoft Clarity";
65390
+ role = "analytics";
65391
+ } else if (location.host === "accounts.google.com" && location.path === "/gsi/client") {
65392
+ provider = "Google sign-in";
65393
+ role = "authentication";
65394
+ }
65395
+ }
65396
+ const file = location.path.split("/").filter(Boolean).at(-1) ?? location.path;
65397
+ const kind = type === "img" ? "Image" : type === "script" || /\.m?js$/i.test(file) ? "JavaScript asset" : "Resource";
65398
+ return {
65399
+ ...location,
65400
+ type,
65401
+ role,
65402
+ provider,
65403
+ title: provider !== null ? `${provider} script failed to load` : `${kind} failed to load: ${file}${location.host === null ? "" : ` (${location.host})`}`,
65404
+ optional_candidate: event["opaque"] === true && location.first_party !== true && ["analytics", "advertising", "tag_manager"].includes(role)
65405
+ };
65406
+ }
65407
+ function browserResourceDiagnosis(resource) {
65408
+ return resource?.optional_candidate === true ? "The browser reported that this script failed to load. Possibly blocked by privacy tools; network, CSP or provider failures are also possible. The captured event does not identify the cause." : "The browser reported that this resource failed to load. The captured event does not identify the cause or establish whether application functionality was affected.";
65409
+ }
65410
+
65257
65411
  // ../../packages/shared-types/src/capture-rule-evaluation.ts
65258
65412
  var CaptureRuleEvaluationUrlSchema = external_exports.object({
65259
65413
  host: external_exports.string().min(1).transform((value) => value.toLowerCase()).optional(),
@@ -65321,6 +65475,7 @@ var CaptureRuleSuggestionSchema = external_exports.object({
65321
65475
  rule: CaptureRuleCreateSchema
65322
65476
  });
65323
65477
  var CaptureRuleSuggestionsResponseSchema = external_exports.object({
65478
+ access_mode: external_exports.enum(["manage", "preview"]).optional(),
65324
65479
  suggestions: external_exports.array(CaptureRuleSuggestionSchema),
65325
65480
  bundle_status: external_exports.enum(["ready", "pending", "failed"]).optional(),
65326
65481
  bundle_reason: external_exports.string().nullable().optional()
@@ -65816,6 +65971,14 @@ function looksSensitiveCustomDimensionValue(value) {
65816
65971
  return /https?:\/\//i.test(value) || /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value) || /\bBearer\s+[A-Za-z0-9._~+/=-]+/i.test(value) || /\b(?:token|password|secret|api_key)=/i.test(value);
65817
65972
  }
65818
65973
 
65974
+ // ../../packages/shared-types/src/frontend-severity.ts
65975
+ function inferFrontendExceptionSeverity(event) {
65976
+ const browserEvent = event.payload.browser_event;
65977
+ if (browserEvent?.opaque === true)
65978
+ return browserEvent.kind === "resource_error" ? "medium" : "low";
65979
+ return "high";
65980
+ }
65981
+
65819
65982
  // ../../packages/shared-types/src/analytics-product.ts
65820
65983
  var AnalyticsOpportunityStatusValues = ["open", "resolved", "snoozed"];
65821
65984
  var AnalyticsOpportunityStatusSchema = external_exports.enum(AnalyticsOpportunityStatusValues);
@@ -66390,6 +66553,7 @@ var ContextDeviceSchema = external_exports.object({
66390
66553
  color_scheme_preference: external_exports.enum(["light", "dark", "no-preference"]).nullable()
66391
66554
  });
66392
66555
  var BundleContextSchema = external_exports.object({
66556
+ resource_failure: BrowserResourceContextSchema.optional(),
66393
66557
  error: ContextErrorSchema.nullable().optional(),
66394
66558
  request: ContextRequestSchema.nullable().optional(),
66395
66559
  response: ContextResponseSchema.nullable().optional(),
@@ -68072,6 +68236,15 @@ function buildSkill() {
68072
68236
  "- Scope frontend noise by structured evidence such as service, environment, `browser_event_kind`, `browser_event_opaque`, `client_kind`, `bot_family`, and message fields. Do not broadly demote generic `Unhandled promise rejection` incidents without bot-scoped or otherwise narrow evidence.",
68073
68237
  "- For expected or intentionally promoted 4xx responses on known routes, use capture-policy client-error path rules instead of promoting all client errors: `debugbundle capture-policy set --client-error-path-rule <status=/path/*@GET>`.",
68074
68238
  "",
68239
+ "### Browser resource failures",
68240
+ "",
68241
+ "- Inspect the primary failure and routes: one resource can span pages, route coverage may be incomplete, and historical incidents stay separate. Related tracker evidence does not explain an application exception.",
68242
+ '- If the cause is unknown, say "possibly blocked by privacy tools." Network/CSP/provider failures remain possible; provider recognition proves neither Pi-hole blocking nor optionality.',
68243
+ "- Review exact host/path, service, environment and opaque resource-error scope; never widen to a whole host. Google sign-in, app assets and unknown dependencies have no automatic resource noise recommendation.",
68244
+ "- For confirmed optional dependencies, context (demote) retains diagnostics without new incidents/alerts/automation and may remain billable. Drop discards future matches; choose it only when evidence has no diagnostic value. Explain the tradeoff; neither deletes history. Use the returned suggestion ID.",
68245
+ "- Check existing/disabled rules. Empty suggestions or pending/failed bundles do not justify broader rules. Applying requires user authorization and owner/admin access; preview is read-only. Verify subsequent matching and protected captures before claiming improvement; live tests need authorization.",
68246
+ "- The official OpenAI connection cannot suggest or apply rules. When it is the only connection, review returned evidence and hand off through a returned safe dashboard URL; never invent tools or switch credentials.",
68247
+ "",
68075
68248
  "## Notification Delivery",
68076
68249
  "",
68077
68250
  "When notification or automation delivery is the reported failure, inspect configuration and delivery records before changing incident logic.",
@@ -68179,6 +68352,7 @@ function buildCliReference() {
68179
68352
  "- `debugbundle capture-policy set [--project <id>] --client-error-path-rule <404=/path/*@GET,POST> [--json]`",
68180
68353
  "",
68181
68354
  "Use capture-rule suggestions for repeated operational noise after inspecting an incident bundle. Use capture-policy client-error path rules for route-scoped 4xx incidents instead of promoting all client errors.",
68355
+ "For browser resource failures, follow the skill's Browser resource failures guidance. Use the current response's suggestion ID, inspect `bundle_status`, `access_mode` and existing-rule state, and review the complete matcher before applying.",
68182
68356
  "",
68183
68357
  "## Probes",
68184
68358
  "",
@@ -68327,6 +68501,7 @@ function buildMcpReference() {
68327
68501
  "- `get_capture_policy`, `update_capture_policy` \u2014 review or update capture policy, including path-scoped client-error incident rules.",
68328
68502
  "",
68329
68503
  "Use these tools for repeated low-value operational noise only after inspecting incident evidence. Keep frontend suppression scoped by structured browser and client signals, and use path-scoped capture policy for known 4xx routes.",
68504
+ "For browser resource failures, follow the skill's Browser resource failures guidance and use the suggestion ID returned by the server. These management tools belong to the member-authenticated MCP surface; the official OpenAI connection is read-only and cannot suggest or apply capture rules.",
68330
68505
  "",
68331
68506
  "## Product Analytics Tools",
68332
68507
  "",
@@ -68522,6 +68697,43 @@ function buildSkillEvals() {
68522
68697
  "Use capture-policy path rules for known route-scoped 4xx incidents."
68523
68698
  ]
68524
68699
  },
68700
+ {
68701
+ name: "browser_resource_noise_review",
68702
+ prompt: "GTM failed on four routes. The owner says analytics is optional and asks to keep useful diagnostics without repeated alerts. The suggestion response offers resource_context and resource_drop with exact host/path/service/environment matchers. Explain and apply the appropriate authorized choice.",
68703
+ expected_behavior: [
68704
+ "Inspect the primary failure and bounded route coverage; do not count each route as a separate application defect.",
68705
+ "Describe privacy blocking as possible, not proven; do not diagnose Pi-hole.",
68706
+ "Review the exact matcher and use the returned context suggestion ID; explain retained evidence and possible paid usage.",
68707
+ "Verify the returned rule without claiming historical incidents were removed or live noise reduction was already observed."
68708
+ ]
68709
+ },
68710
+ {
68711
+ name: "protected_resource_noise_review",
68712
+ prompt: "A checkout TypeError has related GTM evidence. Separate incidents show Google sign-in and an unknown script failing. The user asks whether ignoring all Google or third-party hosts would clean this up.",
68713
+ expected_behavior: [
68714
+ "Keep the primary checkout exception separate from related tracker evidence.",
68715
+ "Do not broaden rules to whole hosts or infer that sign-in, app assets or unknown dependencies are optional.",
68716
+ "Inspect evidence and available suggestions before proposing any narrowly scoped change."
68717
+ ]
68718
+ },
68719
+ {
68720
+ name: "unavailable_resource_noise_suggestions",
68721
+ prompt: "Resource suggestions are pending or empty, the current member has preview access, and a matching rule is disabled. The user asks why the resource still opens incidents.",
68722
+ expected_behavior: [
68723
+ "Explain the missing evidence and access limits without inventing a rule or bypassing authorization.",
68724
+ "Inspect the disabled rule; do not assume it is active, create a duplicate or silently enable it.",
68725
+ "Do not claim noise was reduced or resolve historical incidents based solely on a policy proposal."
68726
+ ]
68727
+ },
68728
+ {
68729
+ name: "readonly_resource_noise_handoff",
68730
+ prompt: "Only the official read-only OpenAI connection is available. The user asks to ignore recurring tracker failures.",
68731
+ expected_behavior: [
68732
+ "Inspect only available incident evidence; distinguish possible privacy blocking from a proven cause.",
68733
+ "Explain that this connection cannot fetch capture-rule suggestions or apply rules; do not invent a management tool or switch credentials.",
68734
+ "Use a returned safe dashboard URL for a reviewed handoff when available, and never claim a rule was applied."
68735
+ ]
68736
+ },
68525
68737
  {
68526
68738
  name: "operational_controls_guidance",
68527
68739
  prompt: "The user reports missing webhook deliveries and asks whether probes or alerts are available. Confirm the skill points the agent to the relevant operational controls and docs.",
@@ -70062,8 +70274,57 @@ function createHealthCheckApi(httpClient) {
70062
70274
  var import_promises4 = require("node:fs/promises");
70063
70275
  var import_node_path4 = require("node:path");
70064
70276
 
70065
- // ../../packages/event-normalizer/src/index.ts
70066
- var import_node_crypto2 = require("node:crypto");
70277
+ // ../../packages/event-normalizer/src/fingerprints.ts
70278
+ var import_node_crypto = require("node:crypto");
70279
+ var FINGERPRINT_VERSION = "v2";
70280
+ var RESOURCE_FINGERPRINT_VERSION = "v3";
70281
+ function fingerprintVersion(event) {
70282
+ return event.resource_type != null ? RESOURCE_FINGERPRINT_VERSION : FINGERPRINT_VERSION;
70283
+ }
70284
+ function stableJson(value) {
70285
+ if (value === null || typeof value !== "object") return JSON.stringify(value);
70286
+ if (Array.isArray(value)) return `[${value.map(stableJson).join(",")}]`;
70287
+ const object = value;
70288
+ return `{${Object.keys(object).sort().map((key) => `${JSON.stringify(key)}:${stableJson(object[key])}`).join(",")}}`;
70289
+ }
70290
+ function fingerprint(event) {
70291
+ const canonical = event.resource_type != null ? {
70292
+ // A concrete resource is the grouping unit, not proof of a common underlying cause.
70293
+ browser_event_kind: "resource_error",
70294
+ resource_host: event.resource_host,
70295
+ resource_path: event.resource_path,
70296
+ resource_type: event.resource_type,
70297
+ environment: event.environment,
70298
+ fingerprint_version: RESOURCE_FINGERPRINT_VERSION
70299
+ } : {
70300
+ // Preserve exact historical bytes for every non-resource event and explicit legacy normalization.
70301
+ error_type: event.error_type,
70302
+ normalized_message: event.normalized_message,
70303
+ top_frames: event.top_frames,
70304
+ route_template: event.route_template,
70305
+ browser_event_kind: event.browser_event_kind,
70306
+ resource_host: event.resource_host,
70307
+ resource_path: event.resource_path,
70308
+ http_method: event.http_method,
70309
+ http_status: event.http_status,
70310
+ environment: event.environment
70311
+ };
70312
+ return (0, import_node_crypto.createHash)("sha256").update(stableJson(canonical)).digest("hex");
70313
+ }
70314
+ function inferMatchedFields(event) {
70315
+ if (event.resource_type != null)
70316
+ return ["environment", "browser_event_kind", "resource_host", "resource_path", "resource_type"];
70317
+ const fields = ["environment", "normalized_message"];
70318
+ if (event.error_type !== null) fields.push("error_type");
70319
+ if (event.route_template !== null) fields.push("route_template");
70320
+ if (event.top_frames.length > 0) fields.push("top_frames");
70321
+ if (event.browser_event_kind != null) fields.push("browser_event_kind");
70322
+ if (event.resource_host != null) fields.push("resource_host");
70323
+ if (event.resource_path != null) fields.push("resource_path");
70324
+ if (event.http_method !== null) fields.push("http_method");
70325
+ if (event.http_status !== null) fields.push("http_status");
70326
+ return fields;
70327
+ }
70067
70328
 
70068
70329
  // ../../packages/redaction/src/index.ts
70069
70330
  var DEFAULT_SENSITIVE_KEYS = [
@@ -70162,7 +70423,7 @@ function redact(payload2, options) {
70162
70423
  }
70163
70424
 
70164
70425
  // ../../packages/event-normalizer/src/mobile-event-compatibility.ts
70165
- var import_node_crypto = require("node:crypto");
70426
+ var import_node_crypto2 = require("node:crypto");
70166
70427
  var MOBILE_SDKS = /* @__PURE__ */ new Set(["@debugbundle/sdk-android", "@debugbundle/sdk-swift"]);
70167
70428
  function isRecord(candidate) {
70168
70429
  return typeof candidate === "object" && candidate !== null && !Array.isArray(candidate);
@@ -70189,8 +70450,8 @@ function readInteger(candidate) {
70189
70450
  function readBoolean(candidate) {
70190
70451
  return typeof candidate === "boolean" ? candidate : null;
70191
70452
  }
70192
- function readField(record, snakeCase, camelCase) {
70193
- return record[snakeCase] ?? record[camelCase];
70453
+ function readField(record2, snakeCase, camelCase) {
70454
+ return record2[snakeCase] ?? record2[camelCase];
70194
70455
  }
70195
70456
  function stableValue(candidate) {
70196
70457
  if (Array.isArray(candidate)) {
@@ -70204,7 +70465,7 @@ function stableValue(candidate) {
70204
70465
  );
70205
70466
  }
70206
70467
  function deterministicEventId(candidate) {
70207
- const digest2 = (0, import_node_crypto.createHash)("sha256").update(JSON.stringify(stableValue(candidate))).digest("hex");
70468
+ const digest2 = (0, import_node_crypto2.createHash)("sha256").update(JSON.stringify(stableValue(candidate))).digest("hex");
70208
70469
  const chars = digest2.slice(0, 32).split("");
70209
70470
  chars[12] = "5";
70210
70471
  chars[16] = ["8", "9", "a", "b"][Number.parseInt(chars[16] ?? "0", 16) % 4] ?? "8";
@@ -70570,7 +70831,6 @@ function normalizeJavaTimerMessage(message3) {
70570
70831
  }
70571
70832
 
70572
70833
  // ../../packages/event-normalizer/src/index.ts
70573
- var FINGERPRINT_VERSION = "v2";
70574
70834
  var PAYLOAD_ALLOWED_KEYS = {
70575
70835
  backend_exception: /* @__PURE__ */ new Set([
70576
70836
  "name",
@@ -70753,34 +71013,6 @@ function normalizeCompatibleEventCandidate(candidate) {
70753
71013
  }
70754
71014
  return event;
70755
71015
  }
70756
- function inferMatchedFields(event) {
70757
- const matchedFields = ["environment", "normalized_message"];
70758
- if (event.error_type !== null) {
70759
- matchedFields.push("error_type");
70760
- }
70761
- if (event.route_template !== null) {
70762
- matchedFields.push("route_template");
70763
- }
70764
- if (event.top_frames.length > 0) {
70765
- matchedFields.push("top_frames");
70766
- }
70767
- if (event.browser_event_kind != null) {
70768
- matchedFields.push("browser_event_kind");
70769
- }
70770
- if (event.resource_host != null) {
70771
- matchedFields.push("resource_host");
70772
- }
70773
- if (event.resource_path != null) {
70774
- matchedFields.push("resource_path");
70775
- }
70776
- if (event.http_method !== null) {
70777
- matchedFields.push("http_method");
70778
- }
70779
- if (event.http_status !== null) {
70780
- matchedFields.push("http_status");
70781
- }
70782
- return matchedFields;
70783
- }
70784
71016
  var UUID_PATTERN = /\b[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\b/gi;
70785
71017
  var EMAIL_PATTERN = /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi;
70786
71018
  var ISO_TIMESTAMP_PATTERN = /\b\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z\b/g;
@@ -70984,22 +71216,10 @@ function normalizeResourceIdentity(value) {
70984
71216
  };
70985
71217
  }
70986
71218
  }
70987
- function stableJson(value) {
70988
- if (value === null || typeof value !== "object") {
70989
- return JSON.stringify(value);
70990
- }
70991
- if (Array.isArray(value)) {
70992
- return `[${value.map((entry) => stableJson(entry)).join(",")}]`;
70993
- }
70994
- const record = value;
70995
- const keys2 = Object.keys(record).sort();
70996
- const pairs = keys2.map((key) => `${JSON.stringify(key)}:${stableJson(record[key])}`);
70997
- return `{${pairs.join(",")}}`;
70998
- }
70999
71219
  function validateEvent(candidate) {
71000
71220
  return EventEnvelopeSchema.safeParse(normalizeCompatibleEventCandidate(candidate));
71001
71221
  }
71002
- function normalizeEvent(event, version2 = FINGERPRINT_VERSION) {
71222
+ function normalizeEvent(event, version2 = RESOURCE_FINGERPRINT_VERSION) {
71003
71223
  const redactedPayload = redact(event.payload).redacted;
71004
71224
  if (event.event_type === "backend_exception") {
71005
71225
  return {
@@ -71053,6 +71273,8 @@ function normalizeEvent(event, version2 = FINGERPRINT_VERSION) {
71053
71273
  const browserEvent = event.payload.browser_event;
71054
71274
  const resourceIdentity = browserEvent?.kind === "resource_error" ? normalizeResourceIdentity(browserEvent.target?.source_url ?? browserEvent.file_name) : { host: null, path: null };
71055
71275
  const topFrames = browserEvent?.opaque === true ? [] : selectTopFrames(event.payload.stack);
71276
+ const resource = describeBrowserResource(browserEvent);
71277
+ const concreteResource = version2 === RESOURCE_FINGERPRINT_VERSION && browserEvent?.opaque === true && resource?.host != null && resource.type !== null;
71056
71278
  return {
71057
71279
  event_type: event.event_type,
71058
71280
  environment: event.service.environment,
@@ -71063,8 +71285,10 @@ function normalizeEvent(event, version2 = FINGERPRINT_VERSION) {
71063
71285
  http_status: null,
71064
71286
  top_frames: topFrames,
71065
71287
  browser_event_kind: browserEvent?.kind ?? null,
71066
- resource_host: resourceIdentity.host,
71067
- resource_path: resourceIdentity.path,
71288
+ resource_host: concreteResource ? resource.host : resourceIdentity.host,
71289
+ resource_path: concreteResource ? resource.path : resourceIdentity.path,
71290
+ ...concreteResource ? { resource_type: resource.type } : {},
71291
+ ...resource === null ? {} : { incident_title: resource.title },
71068
71292
  payload: redactedPayload
71069
71293
  };
71070
71294
  }
@@ -71083,21 +71307,6 @@ function normalizeEvent(event, version2 = FINGERPRINT_VERSION) {
71083
71307
  payload: redactedPayload
71084
71308
  };
71085
71309
  }
71086
- function fingerprint(event) {
71087
- const canonical = {
71088
- error_type: event.error_type,
71089
- normalized_message: event.normalized_message,
71090
- top_frames: event.top_frames,
71091
- route_template: event.route_template,
71092
- browser_event_kind: event.browser_event_kind,
71093
- resource_host: event.resource_host,
71094
- resource_path: event.resource_path,
71095
- http_method: event.http_method,
71096
- http_status: event.http_status,
71097
- environment: event.environment
71098
- };
71099
- return (0, import_node_crypto2.createHash)("sha256").update(stableJson(canonical)).digest("hex");
71100
- }
71101
71310
  var INCIDENT_LOG_LEVELS = /* @__PURE__ */ new Set(["error", "fatal", "critical"]);
71102
71311
  function getRequestResponseStatus(payload2) {
71103
71312
  const status = payload2?.["response_status"];
@@ -89312,6 +89521,192 @@ var OPENAI_OAUTH_BOOTSTRAP_STATEMENTS = [
89312
89521
  `CREATE INDEX oauth_provider_artifacts_expires_idx ON oauth_provider_artifacts (expires_at, model, provider_id_hash)`
89313
89522
  ];
89314
89523
 
89524
+ // ../../packages/storage/src/storage-bootstrap-incident-statements.ts
89525
+ var STORAGE_BOOTSTRAP_INCIDENT_STATEMENTS = [
89526
+ `
89527
+ CREATE TABLE incidents (
89528
+ id uuid PRIMARY KEY,
89529
+ project_id uuid NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
89530
+ service_id uuid REFERENCES services(id) ON DELETE SET NULL,
89531
+ environment text NOT NULL DEFAULT 'production',
89532
+ fingerprint text NOT NULL,
89533
+ fingerprint_version text NOT NULL DEFAULT 'v1',
89534
+ title text NOT NULL,
89535
+ severity text NOT NULL,
89536
+ status text NOT NULL DEFAULT 'open',
89537
+ first_seen_at timestamptz NOT NULL,
89538
+ last_seen_at timestamptz NOT NULL,
89539
+ occurrence_count integer NOT NULL DEFAULT 1,
89540
+ matched_fields text[],
89541
+ created_at timestamptz NOT NULL DEFAULT now(),
89542
+ updated_at timestamptz NOT NULL DEFAULT now(),
89543
+ regressed_at timestamptz,
89544
+ spike_detected_at timestamptz,
89545
+ frequency_occurrences_1m integer,
89546
+ frequency_occurrences_5m integer,
89547
+ frequency_occurrences_1h integer,
89548
+ frequency_occurrences_24h integer,
89549
+ frequency_baseline_1h_per_5m double precision,
89550
+ frequency_spike_ratio_5m_to_1h double precision,
89551
+ frequency_has_sufficient_baseline boolean,
89552
+ frequency_is_spiking boolean,
89553
+ frequency_snapshot_at timestamptz,
89554
+ latest_deployment_id uuid REFERENCES deployments(id) ON DELETE SET NULL,
89555
+ bundle_generation_number integer NOT NULL DEFAULT 0,
89556
+ bundle_created_at timestamptz,
89557
+ bundle_updated_at timestamptz,
89558
+ bundle_source_event_id uuid,
89559
+ bundle_source_occurred_at timestamptz,
89560
+ bundle_trigger text,
89561
+ bundle_failure_reason text,
89562
+ resolved_at timestamptz,
89563
+ resolved_by_member_id uuid REFERENCES users(id) ON DELETE SET NULL,
89564
+ UNIQUE (project_id, environment, service_id, fingerprint)
89565
+ )
89566
+ `,
89567
+ `
89568
+ CREATE TABLE processed_events (
89569
+ event_id uuid PRIMARY KEY,
89570
+ project_id uuid NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
89571
+ event_type text NOT NULL,
89572
+ fingerprint text NOT NULL,
89573
+ normalized_message text NOT NULL,
89574
+ processed_at timestamptz NOT NULL DEFAULT now()
89575
+ )
89576
+ `,
89577
+ `
89578
+ CREATE TABLE improvement_opportunities (
89579
+ id uuid PRIMARY KEY,
89580
+ project_id uuid NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
89581
+ service_id uuid REFERENCES services(id) ON DELETE SET NULL,
89582
+ service_name text NOT NULL,
89583
+ environment text NOT NULL DEFAULT 'production',
89584
+ kind text NOT NULL,
89585
+ status text NOT NULL DEFAULT 'open',
89586
+ severity text NOT NULL,
89587
+ confidence numeric NOT NULL,
89588
+ fingerprint text NOT NULL,
89589
+ title text NOT NULL,
89590
+ summary text NOT NULL,
89591
+ occurrence_count integer NOT NULL DEFAULT 1,
89592
+ evidence jsonb NOT NULL,
89593
+ first_detected_at timestamptz NOT NULL,
89594
+ last_detected_at timestamptz NOT NULL,
89595
+ last_source_event_id uuid,
89596
+ related_incident_ids uuid[] NOT NULL DEFAULT '{}',
89597
+ bundle_generation_number integer NOT NULL DEFAULT 0,
89598
+ bundle_created_at timestamptz,
89599
+ bundle_updated_at timestamptz,
89600
+ bundle_source_event_id uuid,
89601
+ bundle_failure_reason text,
89602
+ resolved_at timestamptz,
89603
+ resolved_by_user_id uuid REFERENCES users(id) ON DELETE SET NULL,
89604
+ snoozed_until timestamptz,
89605
+ created_at timestamptz NOT NULL DEFAULT now(),
89606
+ updated_at timestamptz NOT NULL DEFAULT now(),
89607
+ UNIQUE (project_id, fingerprint)
89608
+ )
89609
+ `,
89610
+ `
89611
+ CREATE INDEX improvement_opportunities_project_status_detected_idx
89612
+ ON improvement_opportunities (project_id, status, last_detected_at DESC)
89613
+ `,
89614
+ `
89615
+ CREATE INDEX improvement_opportunities_project_kind_detected_idx
89616
+ ON improvement_opportunities (project_id, kind, last_detected_at DESC)
89617
+ `,
89618
+ `
89619
+ CREATE INDEX improvement_opportunities_project_service_env_idx
89620
+ ON improvement_opportunities (project_id, service_id, environment)
89621
+ `,
89622
+ `
89623
+ CREATE TABLE improvement_opportunity_events (
89624
+ improvement_opportunity_id uuid NOT NULL REFERENCES improvement_opportunities(id) ON DELETE CASCADE,
89625
+ event_id uuid NOT NULL,
89626
+ event_type text NOT NULL,
89627
+ occurred_at timestamptz NOT NULL,
89628
+ PRIMARY KEY (improvement_opportunity_id, event_id)
89629
+ )
89630
+ `,
89631
+ `
89632
+ CREATE INDEX improvement_opportunity_events_detected_idx
89633
+ ON improvement_opportunity_events (improvement_opportunity_id, occurred_at DESC, event_id DESC)
89634
+ `,
89635
+ `
89636
+ CREATE TABLE bundle_generations (
89637
+ id uuid PRIMARY KEY,
89638
+ project_id uuid NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
89639
+ incident_id uuid REFERENCES incidents(id) ON DELETE CASCADE,
89640
+ improvement_opportunity_id uuid REFERENCES improvement_opportunities(id) ON DELETE CASCADE,
89641
+ bundle_type text NOT NULL,
89642
+ generation_number integer NOT NULL,
89643
+ source_event_id uuid NOT NULL,
89644
+ source_occurred_at timestamptz NOT NULL,
89645
+ trigger text NOT NULL,
89646
+ created_at timestamptz NOT NULL,
89647
+ updated_at timestamptz NOT NULL,
89648
+ CHECK (
89649
+ (incident_id IS NOT NULL AND improvement_opportunity_id IS NULL AND bundle_type = 'failure')
89650
+ OR (incident_id IS NULL AND improvement_opportunity_id IS NOT NULL AND bundle_type = 'improvement')
89651
+ )
89652
+ )
89653
+ `,
89654
+ `
89655
+ CREATE UNIQUE INDEX bundle_generations_incident_source_idx
89656
+ ON bundle_generations (incident_id, source_event_id)
89657
+ WHERE incident_id IS NOT NULL
89658
+ `,
89659
+ `
89660
+ CREATE UNIQUE INDEX bundle_generations_improvement_source_idx
89661
+ ON bundle_generations (improvement_opportunity_id, source_event_id)
89662
+ WHERE improvement_opportunity_id IS NOT NULL
89663
+ `,
89664
+ `
89665
+ CREATE INDEX bundle_generations_project_created_idx
89666
+ ON bundle_generations (project_id, created_at DESC, bundle_type)
89667
+ `,
89668
+ `
89669
+ CREATE INDEX bundle_generations_incident_generation_idx
89670
+ ON bundle_generations (incident_id, generation_number DESC)
89671
+ `,
89672
+ `
89673
+ CREATE INDEX bundle_generations_improvement_generation_idx
89674
+ ON bundle_generations (improvement_opportunity_id, generation_number DESC)
89675
+ WHERE improvement_opportunity_id IS NOT NULL
89676
+ `,
89677
+ `
89678
+ CREATE TABLE incident_events (
89679
+ incident_id uuid NOT NULL REFERENCES incidents(id) ON DELETE CASCADE,
89680
+ event_id uuid NOT NULL,
89681
+ event_type text NOT NULL,
89682
+ event_class text NOT NULL DEFAULT 'context_signal',
89683
+ occurred_at timestamptz NOT NULL,
89684
+ is_sampled boolean NOT NULL DEFAULT false,
89685
+ level text,
89686
+ resource_route text,
89687
+ retain_first boolean NOT NULL DEFAULT false,
89688
+ retain_latest boolean NOT NULL DEFAULT false,
89689
+ retain_after_deploy boolean NOT NULL DEFAULT false,
89690
+ retain_highest_severity boolean NOT NULL DEFAULT false,
89691
+ retain_deploy_metadata boolean NOT NULL DEFAULT false,
89692
+ severity_rank integer NOT NULL DEFAULT 0,
89693
+ PRIMARY KEY (incident_id, event_id)
89694
+ )
89695
+ `,
89696
+ `
89697
+ CREATE INDEX incident_events_incident_occurred_event_idx
89698
+ ON incident_events (incident_id, occurred_at DESC, event_id DESC)
89699
+ `,
89700
+ `
89701
+ CREATE INDEX incident_events_incident_level_occurred_event_idx
89702
+ ON incident_events (incident_id, level, occurred_at DESC, event_id DESC)
89703
+ `,
89704
+ `
89705
+ CREATE INDEX incident_events_incident_sampled_idx
89706
+ ON incident_events (incident_id, is_sampled, occurred_at ASC, event_id ASC)
89707
+ `
89708
+ ];
89709
+
89315
89710
  // ../../packages/storage/src/storage-bootstrap-account-analytics-statements.ts
89316
89711
  var STORAGE_BOOTSTRAP_ACCOUNT_ANALYTICS_STATEMENTS = [
89317
89712
  `
@@ -89832,187 +90227,7 @@ var STORAGE_BOOTSTRAP_STATEMENTS = [
89832
90227
  CREATE INDEX deployments_project_service_env_deployed_idx
89833
90228
  ON deployments (project_id, service_id, environment, deployed_at DESC)
89834
90229
  `,
89835
- `
89836
- CREATE TABLE incidents (
89837
- id uuid PRIMARY KEY,
89838
- project_id uuid NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
89839
- service_id uuid REFERENCES services(id) ON DELETE SET NULL,
89840
- environment text NOT NULL DEFAULT 'production',
89841
- fingerprint text NOT NULL,
89842
- fingerprint_version text NOT NULL DEFAULT 'v1',
89843
- title text NOT NULL,
89844
- severity text NOT NULL,
89845
- status text NOT NULL DEFAULT 'open',
89846
- first_seen_at timestamptz NOT NULL,
89847
- last_seen_at timestamptz NOT NULL,
89848
- occurrence_count integer NOT NULL DEFAULT 1,
89849
- matched_fields text[],
89850
- created_at timestamptz NOT NULL DEFAULT now(),
89851
- updated_at timestamptz NOT NULL DEFAULT now(),
89852
- regressed_at timestamptz,
89853
- spike_detected_at timestamptz,
89854
- frequency_occurrences_1m integer,
89855
- frequency_occurrences_5m integer,
89856
- frequency_occurrences_1h integer,
89857
- frequency_occurrences_24h integer,
89858
- frequency_baseline_1h_per_5m double precision,
89859
- frequency_spike_ratio_5m_to_1h double precision,
89860
- frequency_has_sufficient_baseline boolean,
89861
- frequency_is_spiking boolean,
89862
- frequency_snapshot_at timestamptz,
89863
- latest_deployment_id uuid REFERENCES deployments(id) ON DELETE SET NULL,
89864
- bundle_generation_number integer NOT NULL DEFAULT 0,
89865
- bundle_created_at timestamptz,
89866
- bundle_updated_at timestamptz,
89867
- bundle_source_event_id uuid,
89868
- bundle_source_occurred_at timestamptz,
89869
- bundle_trigger text,
89870
- bundle_failure_reason text,
89871
- resolved_at timestamptz,
89872
- resolved_by_member_id uuid REFERENCES users(id) ON DELETE SET NULL,
89873
- UNIQUE (project_id, environment, service_id, fingerprint)
89874
- )
89875
- `,
89876
- `
89877
- CREATE TABLE processed_events (
89878
- event_id uuid PRIMARY KEY,
89879
- project_id uuid NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
89880
- event_type text NOT NULL,
89881
- fingerprint text NOT NULL,
89882
- normalized_message text NOT NULL,
89883
- processed_at timestamptz NOT NULL DEFAULT now()
89884
- )
89885
- `,
89886
- `
89887
- CREATE TABLE improvement_opportunities (
89888
- id uuid PRIMARY KEY,
89889
- project_id uuid NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
89890
- service_id uuid REFERENCES services(id) ON DELETE SET NULL,
89891
- service_name text NOT NULL,
89892
- environment text NOT NULL DEFAULT 'production',
89893
- kind text NOT NULL,
89894
- status text NOT NULL DEFAULT 'open',
89895
- severity text NOT NULL,
89896
- confidence numeric NOT NULL,
89897
- fingerprint text NOT NULL,
89898
- title text NOT NULL,
89899
- summary text NOT NULL,
89900
- occurrence_count integer NOT NULL DEFAULT 1,
89901
- evidence jsonb NOT NULL,
89902
- first_detected_at timestamptz NOT NULL,
89903
- last_detected_at timestamptz NOT NULL,
89904
- last_source_event_id uuid,
89905
- related_incident_ids uuid[] NOT NULL DEFAULT '{}',
89906
- bundle_generation_number integer NOT NULL DEFAULT 0,
89907
- bundle_created_at timestamptz,
89908
- bundle_updated_at timestamptz,
89909
- bundle_source_event_id uuid,
89910
- bundle_failure_reason text,
89911
- resolved_at timestamptz,
89912
- resolved_by_user_id uuid REFERENCES users(id) ON DELETE SET NULL,
89913
- snoozed_until timestamptz,
89914
- created_at timestamptz NOT NULL DEFAULT now(),
89915
- updated_at timestamptz NOT NULL DEFAULT now(),
89916
- UNIQUE (project_id, fingerprint)
89917
- )
89918
- `,
89919
- `
89920
- CREATE INDEX improvement_opportunities_project_status_detected_idx
89921
- ON improvement_opportunities (project_id, status, last_detected_at DESC)
89922
- `,
89923
- `
89924
- CREATE INDEX improvement_opportunities_project_kind_detected_idx
89925
- ON improvement_opportunities (project_id, kind, last_detected_at DESC)
89926
- `,
89927
- `
89928
- CREATE INDEX improvement_opportunities_project_service_env_idx
89929
- ON improvement_opportunities (project_id, service_id, environment)
89930
- `,
89931
- `
89932
- CREATE TABLE improvement_opportunity_events (
89933
- improvement_opportunity_id uuid NOT NULL REFERENCES improvement_opportunities(id) ON DELETE CASCADE,
89934
- event_id uuid NOT NULL,
89935
- event_type text NOT NULL,
89936
- occurred_at timestamptz NOT NULL,
89937
- PRIMARY KEY (improvement_opportunity_id, event_id)
89938
- )
89939
- `,
89940
- `
89941
- CREATE INDEX improvement_opportunity_events_detected_idx
89942
- ON improvement_opportunity_events (improvement_opportunity_id, occurred_at DESC, event_id DESC)
89943
- `,
89944
- `
89945
- CREATE TABLE bundle_generations (
89946
- id uuid PRIMARY KEY,
89947
- project_id uuid NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
89948
- incident_id uuid REFERENCES incidents(id) ON DELETE CASCADE,
89949
- improvement_opportunity_id uuid REFERENCES improvement_opportunities(id) ON DELETE CASCADE,
89950
- bundle_type text NOT NULL,
89951
- generation_number integer NOT NULL,
89952
- source_event_id uuid NOT NULL,
89953
- source_occurred_at timestamptz NOT NULL,
89954
- trigger text NOT NULL,
89955
- created_at timestamptz NOT NULL,
89956
- updated_at timestamptz NOT NULL,
89957
- CHECK (
89958
- (incident_id IS NOT NULL AND improvement_opportunity_id IS NULL AND bundle_type = 'failure')
89959
- OR (incident_id IS NULL AND improvement_opportunity_id IS NOT NULL AND bundle_type = 'improvement')
89960
- )
89961
- )
89962
- `,
89963
- `
89964
- CREATE UNIQUE INDEX bundle_generations_incident_source_idx
89965
- ON bundle_generations (incident_id, source_event_id)
89966
- WHERE incident_id IS NOT NULL
89967
- `,
89968
- `
89969
- CREATE UNIQUE INDEX bundle_generations_improvement_source_idx
89970
- ON bundle_generations (improvement_opportunity_id, source_event_id)
89971
- WHERE improvement_opportunity_id IS NOT NULL
89972
- `,
89973
- `
89974
- CREATE INDEX bundle_generations_project_created_idx
89975
- ON bundle_generations (project_id, created_at DESC, bundle_type)
89976
- `,
89977
- `
89978
- CREATE INDEX bundle_generations_incident_generation_idx
89979
- ON bundle_generations (incident_id, generation_number DESC)
89980
- `,
89981
- `
89982
- CREATE INDEX bundle_generations_improvement_generation_idx
89983
- ON bundle_generations (improvement_opportunity_id, generation_number DESC)
89984
- WHERE improvement_opportunity_id IS NOT NULL
89985
- `,
89986
- `
89987
- CREATE TABLE incident_events (
89988
- incident_id uuid NOT NULL REFERENCES incidents(id) ON DELETE CASCADE,
89989
- event_id uuid NOT NULL,
89990
- event_type text NOT NULL,
89991
- event_class text NOT NULL DEFAULT 'context_signal',
89992
- occurred_at timestamptz NOT NULL,
89993
- is_sampled boolean NOT NULL DEFAULT false,
89994
- level text,
89995
- retain_first boolean NOT NULL DEFAULT false,
89996
- retain_latest boolean NOT NULL DEFAULT false,
89997
- retain_after_deploy boolean NOT NULL DEFAULT false,
89998
- retain_highest_severity boolean NOT NULL DEFAULT false,
89999
- retain_deploy_metadata boolean NOT NULL DEFAULT false,
90000
- severity_rank integer NOT NULL DEFAULT 0,
90001
- PRIMARY KEY (incident_id, event_id)
90002
- )
90003
- `,
90004
- `
90005
- CREATE INDEX incident_events_incident_occurred_event_idx
90006
- ON incident_events (incident_id, occurred_at DESC, event_id DESC)
90007
- `,
90008
- `
90009
- CREATE INDEX incident_events_incident_level_occurred_event_idx
90010
- ON incident_events (incident_id, level, occurred_at DESC, event_id DESC)
90011
- `,
90012
- `
90013
- CREATE INDEX incident_events_incident_sampled_idx
90014
- ON incident_events (incident_id, is_sampled, occurred_at ASC, event_id ASC)
90015
- `,
90230
+ ...STORAGE_BOOTSTRAP_INCIDENT_STATEMENTS,
90016
90231
  `
90017
90232
  CREATE TABLE weekly_report_channels (
90018
90233
  id uuid PRIMARY KEY,
@@ -92601,7 +92816,12 @@ var LATE_STORAGE_SCHEMA_MIGRATIONS = [
92601
92816
  // ../../packages/storage/src/schema-migrations-catalog.ts
92602
92817
  var STORAGE_SCHEMA_MIGRATIONS = [
92603
92818
  ...EARLY_STORAGE_SCHEMA_MIGRATIONS,
92604
- ...LATE_STORAGE_SCHEMA_MIGRATIONS
92819
+ ...LATE_STORAGE_SCHEMA_MIGRATIONS,
92820
+ defineStorageSchemaMigration({
92821
+ id: "202609160001_add_browser_resource_routes",
92822
+ description: "Retain sanitized browser resource routes independently of raw event sampling.",
92823
+ statements: ["ALTER TABLE incident_events ADD COLUMN IF NOT EXISTS resource_route text"]
92824
+ })
92605
92825
  ];
92606
92826
 
92607
92827
  // ../../packages/storage/src/schema-migrations.ts
@@ -92622,6 +92842,27 @@ var import_node_crypto10 = require("node:crypto");
92622
92842
  var import_promises5 = require("node:fs/promises");
92623
92843
  var import_node_path6 = require("node:path");
92624
92844
 
92845
+ // ../../packages/bundle-engine/src/browser-resource-context.ts
92846
+ function buildBrowserResourceContext(browserEvent, incident, events2) {
92847
+ const resource = describeBrowserResource(browserEvent);
92848
+ if (resource === null) return void 0;
92849
+ const routes = [];
92850
+ for (const event of events2) {
92851
+ if (event.event_type !== "frontend_exception" || event.service.name !== incident.service_name || event.service.environment !== incident.environment)
92852
+ continue;
92853
+ const candidate = describeBrowserResource(event.payload.browser_event);
92854
+ if (candidate !== null && candidate.host === resource.host && candidate.path === resource.path && candidate.type === resource.type) {
92855
+ routes.push(event.payload.route ?? null);
92856
+ }
92857
+ }
92858
+ return {
92859
+ version: 1,
92860
+ ...resource,
92861
+ diagnosis: browserResourceDiagnosis(resource),
92862
+ routes: incident.resource_routes ?? summarizeResourceRoutes(routes, incident.occurrence_count)
92863
+ };
92864
+ }
92865
+
92625
92866
  // ../../packages/bundle-engine/src/deployment-context.ts
92626
92867
  function selectScopedDeployments(input2) {
92627
92868
  const cutoff = Date.parse(input2.occurredAt);
@@ -92707,9 +92948,9 @@ function stableJson2(value) {
92707
92948
  if (Array.isArray(value)) {
92708
92949
  return `[${value.map((entry) => stableJson2(entry)).join(",")}]`;
92709
92950
  }
92710
- const record = value;
92711
- const keys2 = Object.keys(record).sort();
92712
- return `{${keys2.map((key) => `${JSON.stringify(key)}:${stableJson2(record[key])}`).join(",")}}`;
92951
+ const record2 = value;
92952
+ const keys2 = Object.keys(record2).sort();
92953
+ return `{${keys2.map((key) => `${JSON.stringify(key)}:${stableJson2(record2[key])}`).join(",")}}`;
92713
92954
  }
92714
92955
  function buildFrontendBreadcrumbKey(input2) {
92715
92956
  return `${input2.breadcrumb_type}:${input2.ts}:${input2.route ?? ""}:${stableJson2(input2.data)}`;
@@ -93083,10 +93324,11 @@ function buildSummaryGuidance(input2) {
93083
93324
  }
93084
93325
  if (input2.opaqueBrowserError) {
93085
93326
  if (input2.browserEvent?.kind === "resource_error") {
93327
+ const resource = describeBrowserResource(input2.browserEvent);
93086
93328
  return {
93087
- likely_cause: "The browser reported a resource load error without a usable application stack.",
93329
+ likely_cause: browserResourceDiagnosis(resource),
93088
93330
  confidence: 0.35,
93089
- recommended_action: "Inspect the captured resource target, browser network failures, CSP rules, and cross-origin asset configuration."
93331
+ recommended_action: "Check the affected resource and routes, browser network failures, CSP and provider availability." + (resource?.optional_candidate === true ? " If the dependency is optional for your app, review a resource-scoped noise rule." : " Verify whether application functionality is affected.")
93090
93332
  };
93091
93333
  }
93092
93334
  return {
@@ -93360,8 +93602,10 @@ function buildBundle(input2) {
93360
93602
  errorContext,
93361
93603
  requestContext
93362
93604
  );
93363
- const browserEvent = getPrimaryBrowserExceptionEvent(sourceEnvelopes, primarySignalEnvelope);
93605
+ const browserEventCandidate = getPrimaryBrowserExceptionEvent(sourceEnvelopes, primarySignalEnvelope);
93606
+ const browserEvent = browserEventCandidate?.kind === "resource_error" && primarySignalEnvelope !== null && !isFrontendExceptionEnvelope(primarySignalEnvelope) ? null : browserEventCandidate;
93364
93607
  const opaqueBrowserError = isOpaqueBrowserError(errorContext, browserEvent);
93608
+ const resourceContext = buildBrowserResourceContext(browserEvent, input2.incident, sourceEnvelopes);
93365
93609
  const primarySignalType = primarySignalEnvelope !== null ? mapSignalType(primarySignalEnvelope.event_type) : inferSignalTypeFromSourceEventTypes(sourceEventTypes);
93366
93610
  const primarySourceEvent = errorContext?.name ?? sourceEventTypes[0] ?? "backend_exception";
93367
93611
  const firstSeenAt = new Date(input2.incident.first_seen_at).toISOString();
@@ -93435,6 +93679,7 @@ function buildBundle(input2) {
93435
93679
  regression_suspected: input2.job.trigger === "regression_reopen"
93436
93680
  },
93437
93681
  context: {
93682
+ ...resourceContext === void 0 ? {} : { resource_failure: resourceContext },
93438
93683
  error: errorContext,
93439
93684
  request: requestContext,
93440
93685
  response: responseContext,
@@ -93498,8 +93743,8 @@ function stableStringify(value) {
93498
93743
  function shellQuote(value) {
93499
93744
  return `'${value.replaceAll("'", `'\\''`)}'`;
93500
93745
  }
93501
- function sortRecordEntries(record) {
93502
- return Object.entries(record).sort(([left], [right]) => left.localeCompare(right));
93746
+ function sortRecordEntries(record2) {
93747
+ return Object.entries(record2).sort(([left], [right]) => left.localeCompare(right));
93503
93748
  }
93504
93749
  var REPLAY_HEADER_PRIORITY = [
93505
93750
  "authorization",
@@ -93816,6 +94061,159 @@ function resolveWorkspacePath(rootDirectory, targetPath) {
93816
94061
  return (0, import_node_path5.isAbsolute)(targetPath) ? targetPath : (0, import_node_path5.join)(rootDirectory, targetPath);
93817
94062
  }
93818
94063
 
94064
+ // ../cli/src/local-processing-state.ts
94065
+ var EVENT_TYPE_SET = new Set(EventTypeValues);
94066
+ function isEventType(value) {
94067
+ return typeof value === "string" && EVENT_TYPE_SET.has(value);
94068
+ }
94069
+ function parseIncidentState(candidate) {
94070
+ if (!isRecord5(candidate)) {
94071
+ return null;
94072
+ }
94073
+ if (candidate["source"] !== "local" || candidate["status"] !== "open" && candidate["status"] !== "resolved") {
94074
+ return null;
94075
+ }
94076
+ const sourceEvents = candidate["source_events"];
94077
+ if (!Array.isArray(sourceEvents)) {
94078
+ return null;
94079
+ }
94080
+ const validatedSourceEvents = [];
94081
+ for (const sourceEvent of sourceEvents) {
94082
+ const validated = validateEvent(sourceEvent);
94083
+ if (!validated.success) {
94084
+ return null;
94085
+ }
94086
+ validatedSourceEvents.push(validated.data);
94087
+ }
94088
+ const matchedFields = candidate["matched_fields"];
94089
+ const sourceEventTypes = candidate["source_event_types"];
94090
+ if (!Array.isArray(matchedFields) || !matchedFields.every((value) => typeof value === "string")) {
94091
+ return null;
94092
+ }
94093
+ if (!Array.isArray(sourceEventTypes) || !sourceEventTypes.every(isEventType)) {
94094
+ return null;
94095
+ }
94096
+ const severity = candidate["severity"];
94097
+ if (severity !== "low" && severity !== "medium" && severity !== "high" && severity !== "critical") {
94098
+ return null;
94099
+ }
94100
+ const status = candidate["status"];
94101
+ if (status !== "open" && status !== "resolved") {
94102
+ return null;
94103
+ }
94104
+ const requiredStringKeys = [
94105
+ "incident_id",
94106
+ "project_id",
94107
+ "service_id",
94108
+ "service_name",
94109
+ "environment",
94110
+ "fingerprint",
94111
+ "fingerprint_version",
94112
+ "title",
94113
+ "first_seen_at",
94114
+ "last_seen_at",
94115
+ "source_event_id",
94116
+ "source_occurred_at",
94117
+ "bundle_path",
94118
+ "reproduction_path"
94119
+ ];
94120
+ for (const key of requiredStringKeys) {
94121
+ if (typeof candidate[key] !== "string") {
94122
+ return null;
94123
+ }
94124
+ }
94125
+ if (typeof candidate["occurrence_count"] !== "number" || typeof candidate["generation_number"] !== "number") {
94126
+ return null;
94127
+ }
94128
+ const serviceRuntime = candidate["service_runtime"];
94129
+ const serviceFramework = candidate["service_framework"];
94130
+ if (serviceRuntime !== null && typeof serviceRuntime !== "string") {
94131
+ return null;
94132
+ }
94133
+ if (serviceFramework !== null && typeof serviceFramework !== "string") {
94134
+ return null;
94135
+ }
94136
+ const incidentId = candidate["incident_id"];
94137
+ const projectId = candidate["project_id"];
94138
+ const serviceId = candidate["service_id"];
94139
+ const serviceName = candidate["service_name"];
94140
+ const environment = candidate["environment"];
94141
+ const incidentFingerprint = candidate["fingerprint"];
94142
+ const fingerprintVersion2 = candidate["fingerprint_version"];
94143
+ const title = candidate["title"];
94144
+ const firstSeenAt = candidate["first_seen_at"];
94145
+ const lastSeenAt = candidate["last_seen_at"];
94146
+ const occurrenceCount = candidate["occurrence_count"];
94147
+ const sourceEventId = candidate["source_event_id"];
94148
+ const sourceOccurredAt = candidate["source_occurred_at"];
94149
+ const bundlePath = candidate["bundle_path"];
94150
+ const reproductionPath = candidate["reproduction_path"];
94151
+ const generationNumber = candidate["generation_number"];
94152
+ const normalizedSourceEventTypes = [...sourceEventTypes].sort();
94153
+ return {
94154
+ incident_id: incidentId,
94155
+ source: "local",
94156
+ project_id: projectId,
94157
+ service_id: serviceId,
94158
+ service_name: serviceName,
94159
+ service_runtime: serviceRuntime,
94160
+ service_framework: serviceFramework,
94161
+ environment,
94162
+ fingerprint: incidentFingerprint,
94163
+ fingerprint_version: fingerprintVersion2,
94164
+ title,
94165
+ severity,
94166
+ status,
94167
+ first_seen_at: firstSeenAt,
94168
+ last_seen_at: lastSeenAt,
94169
+ occurrence_count: occurrenceCount,
94170
+ source_event_id: sourceEventId,
94171
+ source_occurred_at: sourceOccurredAt,
94172
+ source_event_types: normalizedSourceEventTypes,
94173
+ matched_fields: [...matchedFields].sort(),
94174
+ bundle_path: bundlePath,
94175
+ reproduction_path: reproductionPath,
94176
+ generation_number: generationNumber,
94177
+ source_events: validatedSourceEvents.sort(compareEventEnvelopes)
94178
+ };
94179
+ }
94180
+ function parseState(rawState) {
94181
+ const parsed = JSON.parse(rawState);
94182
+ if (!isRecord5(parsed) || parsed["version"] !== 1) {
94183
+ return null;
94184
+ }
94185
+ const lastProcessedEventFile = parsed["last_processed_event_file"];
94186
+ if (lastProcessedEventFile !== null && typeof lastProcessedEventFile !== "string") {
94187
+ return null;
94188
+ }
94189
+ const incidents = parsed["incidents"];
94190
+ if (!isRecord5(incidents)) {
94191
+ return null;
94192
+ }
94193
+ const parsedIncidents = {};
94194
+ for (const [incidentId, incidentValue] of Object.entries(incidents).sort(
94195
+ ([left], [right]) => left.localeCompare(right)
94196
+ )) {
94197
+ const incident = parseIncidentState(incidentValue);
94198
+ if (incident === null || incident.incident_id !== incidentId) {
94199
+ return null;
94200
+ }
94201
+ parsedIncidents[incidentId] = incident;
94202
+ }
94203
+ return {
94204
+ version: 1,
94205
+ last_processed_event_file: lastProcessedEventFile,
94206
+ incidents: parsedIncidents
94207
+ };
94208
+ }
94209
+ function compareEventEnvelopes(left, right) {
94210
+ const occurredAtComparison = left.occurred_at.localeCompare(right.occurred_at);
94211
+ if (occurredAtComparison !== 0) {
94212
+ return occurredAtComparison;
94213
+ }
94214
+ return left.event_id.localeCompare(right.event_id);
94215
+ }
94216
+
93819
94217
  // ../cli/src/process-command.ts
93820
94218
  var LOCAL_EVENTS_DIRECTORY_PATH = ".debugbundle/local/events";
93821
94219
  var LOCAL_STATE_FILE_PATH = ".debugbundle/local/state.json";
@@ -93826,10 +94224,6 @@ var CLI_SDK = {
93826
94224
  name: "debugbundle-cli",
93827
94225
  version: "0.1.0"
93828
94226
  };
93829
- var EVENT_TYPE_SET = new Set(EventTypeValues);
93830
- function isEventType(value) {
93831
- return typeof value === "string" && EVENT_TYPE_SET.has(value);
93832
- }
93833
94227
  function inferSeverity2(event, capturePreset, incidentKind = "immediate") {
93834
94228
  if (incidentKind === "request_anomaly") {
93835
94229
  return "medium";
@@ -93837,7 +94231,8 @@ function inferSeverity2(event, capturePreset, incidentKind = "immediate") {
93837
94231
  if (event.event_type === "request_event") {
93838
94232
  return classifyRequestStatus({ responseStatus: event.payload.response_status, capturePreset }) === "incident_signal" ? "high" : "low";
93839
94233
  }
93840
- if (event.event_type === "backend_exception" || event.event_type === "frontend_exception") {
94234
+ if (event.event_type === "frontend_exception") return inferFrontendExceptionSeverity(event);
94235
+ if (event.event_type === "backend_exception") {
93841
94236
  return "high";
93842
94237
  }
93843
94238
  if (event.event_type === "error_suppressed") {
@@ -93857,13 +94252,6 @@ function severityRank(severity) {
93857
94252
  return 1;
93858
94253
  }
93859
94254
  }
93860
- function compareEventEnvelopes(left, right) {
93861
- const occurredAtComparison = left.occurred_at.localeCompare(right.occurred_at);
93862
- if (occurredAtComparison !== 0) {
93863
- return occurredAtComparison;
93864
- }
93865
- return left.event_id.localeCompare(right.event_id);
93866
- }
93867
94255
  function classifyEnvelope(envelope, capturePreset) {
93868
94256
  return classifyEvent(
93869
94257
  envelope.event_type,
@@ -93955,9 +94343,9 @@ function stableJson3(value) {
93955
94343
  if (Array.isArray(value)) {
93956
94344
  return `[${value.map((entry) => stableJson3(entry)).join(",")}]`;
93957
94345
  }
93958
- const record = value;
93959
- const keys2 = Object.keys(record).sort();
93960
- return `{${keys2.map((key) => `${JSON.stringify(key)}:${stableJson3(record[key])}`).join(",")}}`;
94346
+ const record2 = value;
94347
+ const keys2 = Object.keys(record2).sort();
94348
+ return `{${keys2.map((key) => `${JSON.stringify(key)}:${stableJson3(record2[key])}`).join(",")}}`;
93961
94349
  }
93962
94350
  function buildRequestAnomalyFingerprint(input2) {
93963
94351
  return (0, import_node_crypto10.createHash)("sha256").update(
@@ -94110,144 +94498,6 @@ async function pathExists4(path, stat) {
94110
94498
  throw error;
94111
94499
  }
94112
94500
  }
94113
- function parseIncidentState(candidate) {
94114
- if (!isRecord5(candidate)) {
94115
- return null;
94116
- }
94117
- if (candidate["source"] !== "local" || candidate["status"] !== "open" && candidate["status"] !== "resolved") {
94118
- return null;
94119
- }
94120
- const sourceEvents = candidate["source_events"];
94121
- if (!Array.isArray(sourceEvents)) {
94122
- return null;
94123
- }
94124
- const validatedSourceEvents = [];
94125
- for (const sourceEvent of sourceEvents) {
94126
- const validated = validateEvent(sourceEvent);
94127
- if (!validated.success) {
94128
- return null;
94129
- }
94130
- validatedSourceEvents.push(validated.data);
94131
- }
94132
- const matchedFields = candidate["matched_fields"];
94133
- const sourceEventTypes = candidate["source_event_types"];
94134
- if (!Array.isArray(matchedFields) || !matchedFields.every((value) => typeof value === "string")) {
94135
- return null;
94136
- }
94137
- if (!Array.isArray(sourceEventTypes) || !sourceEventTypes.every(isEventType)) {
94138
- return null;
94139
- }
94140
- const severity = candidate["severity"];
94141
- if (severity !== "low" && severity !== "medium" && severity !== "high" && severity !== "critical") {
94142
- return null;
94143
- }
94144
- const status = candidate["status"];
94145
- if (status !== "open" && status !== "resolved") {
94146
- return null;
94147
- }
94148
- const requiredStringKeys = [
94149
- "incident_id",
94150
- "project_id",
94151
- "service_id",
94152
- "service_name",
94153
- "environment",
94154
- "fingerprint",
94155
- "fingerprint_version",
94156
- "title",
94157
- "first_seen_at",
94158
- "last_seen_at",
94159
- "source_event_id",
94160
- "source_occurred_at",
94161
- "bundle_path",
94162
- "reproduction_path"
94163
- ];
94164
- for (const key of requiredStringKeys) {
94165
- if (typeof candidate[key] !== "string") {
94166
- return null;
94167
- }
94168
- }
94169
- if (typeof candidate["occurrence_count"] !== "number" || typeof candidate["generation_number"] !== "number") {
94170
- return null;
94171
- }
94172
- const serviceRuntime = candidate["service_runtime"];
94173
- const serviceFramework = candidate["service_framework"];
94174
- if (serviceRuntime !== null && typeof serviceRuntime !== "string") {
94175
- return null;
94176
- }
94177
- if (serviceFramework !== null && typeof serviceFramework !== "string") {
94178
- return null;
94179
- }
94180
- const incidentId = candidate["incident_id"];
94181
- const projectId = candidate["project_id"];
94182
- const serviceId = candidate["service_id"];
94183
- const serviceName = candidate["service_name"];
94184
- const environment = candidate["environment"];
94185
- const incidentFingerprint = candidate["fingerprint"];
94186
- const fingerprintVersion = candidate["fingerprint_version"];
94187
- const title = candidate["title"];
94188
- const firstSeenAt = candidate["first_seen_at"];
94189
- const lastSeenAt = candidate["last_seen_at"];
94190
- const occurrenceCount = candidate["occurrence_count"];
94191
- const sourceEventId = candidate["source_event_id"];
94192
- const sourceOccurredAt = candidate["source_occurred_at"];
94193
- const bundlePath = candidate["bundle_path"];
94194
- const reproductionPath = candidate["reproduction_path"];
94195
- const generationNumber = candidate["generation_number"];
94196
- const normalizedSourceEventTypes = [...sourceEventTypes].sort();
94197
- return {
94198
- incident_id: incidentId,
94199
- source: "local",
94200
- project_id: projectId,
94201
- service_id: serviceId,
94202
- service_name: serviceName,
94203
- service_runtime: serviceRuntime,
94204
- service_framework: serviceFramework,
94205
- environment,
94206
- fingerprint: incidentFingerprint,
94207
- fingerprint_version: fingerprintVersion,
94208
- title,
94209
- severity,
94210
- status,
94211
- first_seen_at: firstSeenAt,
94212
- last_seen_at: lastSeenAt,
94213
- occurrence_count: occurrenceCount,
94214
- source_event_id: sourceEventId,
94215
- source_occurred_at: sourceOccurredAt,
94216
- source_event_types: normalizedSourceEventTypes,
94217
- matched_fields: [...matchedFields].sort(),
94218
- bundle_path: bundlePath,
94219
- reproduction_path: reproductionPath,
94220
- generation_number: generationNumber,
94221
- source_events: validatedSourceEvents.sort(compareEventEnvelopes)
94222
- };
94223
- }
94224
- function parseState(rawState) {
94225
- const parsed = JSON.parse(rawState);
94226
- if (!isRecord5(parsed) || parsed["version"] !== 1) {
94227
- return null;
94228
- }
94229
- const lastProcessedEventFile = parsed["last_processed_event_file"];
94230
- if (lastProcessedEventFile !== null && typeof lastProcessedEventFile !== "string") {
94231
- return null;
94232
- }
94233
- const incidents = parsed["incidents"];
94234
- if (!isRecord5(incidents)) {
94235
- return null;
94236
- }
94237
- const parsedIncidents = {};
94238
- for (const [incidentId, incidentValue] of Object.entries(incidents).sort(([left], [right]) => left.localeCompare(right))) {
94239
- const incident = parseIncidentState(incidentValue);
94240
- if (incident === null || incident.incident_id !== incidentId) {
94241
- return null;
94242
- }
94243
- parsedIncidents[incidentId] = incident;
94244
- }
94245
- return {
94246
- version: 1,
94247
- last_processed_event_file: lastProcessedEventFile,
94248
- incidents: parsedIncidents
94249
- };
94250
- }
94251
94501
  async function readState(statePath, readFile, stat) {
94252
94502
  if (!await pathExists4(statePath, stat)) {
94253
94503
  return null;
@@ -94381,7 +94631,7 @@ async function processCommand(input2, dependencies = {}) {
94381
94631
  mergedIncidentIds: /* @__PURE__ */ new Set([incidentId]),
94382
94632
  signalEventTypes: /* @__PURE__ */ new Set(),
94383
94633
  traceIds: /* @__PURE__ */ new Set(),
94384
- title: normalizedEvent.normalized_message,
94634
+ title: normalizedEvent.incident_title ?? normalizedEvent.normalized_message,
94385
94635
  kind: "immediate",
94386
94636
  severity: inferSeverity2(event, capturePreset)
94387
94637
  };
@@ -94391,7 +94641,7 @@ async function processCommand(input2, dependencies = {}) {
94391
94641
  aggregate.newEvents.push(event);
94392
94642
  aggregate.signalEventTypes.add(event.event_type);
94393
94643
  const traceId = getTraceId(event);
94394
- if (traceId !== null) {
94644
+ if (traceId !== null && normalizedEvent.resource_type === void 0) {
94395
94645
  aggregate.traceIds.add(traceId);
94396
94646
  const traceCorrelationGroup = traceCorrelationGroups.get(traceId) ?? {
94397
94647
  incidentIds: /* @__PURE__ */ new Set(),
@@ -94483,7 +94733,7 @@ async function processCommand(input2, dependencies = {}) {
94483
94733
  service_framework: latestSignalEvent.service.framework ?? existing?.service_framework ?? null,
94484
94734
  environment: aggregate.environment,
94485
94735
  fingerprint: aggregate.fingerprint,
94486
- fingerprint_version: FINGERPRINT_VERSION,
94736
+ fingerprint_version: aggregate.kind === "request_anomaly" ? FINGERPRINT_VERSION : fingerprintVersion(normalizeEvent(latestSignalEvent)),
94487
94737
  title: aggregate.title,
94488
94738
  severity,
94489
94739
  status: existingIncidents.some((incidentState) => incidentState.status === "resolved") ? "open" : existing?.status ?? "open",
@@ -100032,7 +100282,7 @@ var zodToJsonSchema = (schema, options) => {
100032
100282
  var package_default = {
100033
100283
  name: "@debugbundle/mcp",
100034
100284
  mcpName: "com.debugbundle/mcp",
100035
- version: "1.8.1",
100285
+ version: "1.8.2",
100036
100286
  private: false,
100037
100287
  description: "MCP server for runtime error reporting, incident response, health checks, debug bundles, and product analytics",
100038
100288
  license: "Apache-2.0",