@debugbundle/mcp 1.0.0 → 1.0.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.
package/dist/main.cjs CHANGED
@@ -14475,6 +14475,7 @@ var AlertSchema = external_exports.object({
14475
14475
  channel: AlertChannelSchema,
14476
14476
  condition_type: AlertConditionTypeSchema,
14477
14477
  severity_min: external_exports.enum(["low", "medium", "high", "critical"]).nullable(),
14478
+ cooldown_seconds: external_exports.number().int().min(0),
14478
14479
  config: external_exports.record(external_exports.string(), external_exports.unknown()),
14479
14480
  is_enabled: external_exports.boolean(),
14480
14481
  created_at: external_exports.string(),
@@ -14561,6 +14562,9 @@ function createAlertApi(client) {
14561
14562
  if (input.severityMin !== void 0) {
14562
14563
  body.severity_min = input.severityMin;
14563
14564
  }
14565
+ if (input.cooldownSeconds !== void 0) {
14566
+ body.cooldown_seconds = input.cooldownSeconds;
14567
+ }
14564
14568
  if (input.isEnabled !== void 0) {
14565
14569
  body.is_enabled = input.isEnabled;
14566
14570
  }
@@ -14587,6 +14591,9 @@ function createAlertApi(client) {
14587
14591
  if (input.severityMin !== void 0) {
14588
14592
  body.severity_min = input.severityMin;
14589
14593
  }
14594
+ if (input.cooldownSeconds !== void 0) {
14595
+ body.cooldown_seconds = input.cooldownSeconds;
14596
+ }
14590
14597
  if (input.config !== void 0) {
14591
14598
  body.config = input.config;
14592
14599
  }
@@ -17117,8 +17124,24 @@ var BrowserExceptionEventSchema = external_exports.object({
17117
17124
  column_number: external_exports.number().int().nonnegative().nullable(),
17118
17125
  target: external_exports.object({
17119
17126
  tag_name: external_exports.string().nullable(),
17120
- source_url: external_exports.string().nullable()
17121
- }).nullable(),
17127
+ source_url: external_exports.string().nullable(),
17128
+ attributes: external_exports.object({
17129
+ rel: external_exports.string().optional(),
17130
+ as: external_exports.string().optional(),
17131
+ type: external_exports.string().optional(),
17132
+ media: external_exports.string().optional(),
17133
+ cross_origin: external_exports.string().optional(),
17134
+ async: external_exports.boolean().optional(),
17135
+ defer: external_exports.boolean().optional(),
17136
+ integrity_present: external_exports.boolean().optional()
17137
+ }).strict().optional()
17138
+ }).strict().nullable(),
17139
+ page: external_exports.object({
17140
+ url: external_exports.string().nullable(),
17141
+ referrer: external_exports.string().nullable(),
17142
+ ready_state: external_exports.enum(["loading", "interactive", "complete"]).nullable(),
17143
+ visibility_state: external_exports.enum(["visible", "hidden", "prerender", "unloaded"]).nullable()
17144
+ }).strict().optional(),
17122
17145
  opaque: external_exports.boolean()
17123
17146
  }).strict();
17124
17147
  var FrontendExceptionPayloadSchema = external_exports.object({
@@ -18609,6 +18632,17 @@ function createMemberApi(httpClient) {
18609
18632
  throw toApiError4(response.status, response.body);
18610
18633
  }
18611
18634
  return response.body;
18635
+ },
18636
+ async leaveProject(input) {
18637
+ const response = await httpClient.request({
18638
+ method: "DELETE",
18639
+ path: `/v1/projects/${input.projectId}/membership`,
18640
+ bearerToken: input.bearerToken
18641
+ });
18642
+ if (response.status !== 200) {
18643
+ throw toApiError4(response.status, response.body);
18644
+ }
18645
+ return response.body;
18612
18646
  }
18613
18647
  };
18614
18648
  }
@@ -18824,11 +18858,129 @@ var ISO_TIMESTAMP_PATTERN = /\b\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z\b/
18824
18858
  var IPV4_PATTERN = /\b(?:\d{1,3}\.){3}\d{1,3}\b/g;
18825
18859
  var HEX_PATTERN = /\b0x[0-9a-f]+\b/gi;
18826
18860
  var BARE_HEX_PATTERN = /\b(?=[0-9a-f]{8,}\b)(?=[0-9a-f]*[a-f])[0-9a-f]+\b/gi;
18861
+ var LONG_ALPHANUMERIC_TOKEN_PATTERN = /\b(?=[A-Za-z0-9_-]{16,}\b)(?=[A-Za-z0-9_-]*[A-Za-z])(?=[A-Za-z0-9_-]*\d)[A-Za-z0-9_-]+\b/g;
18827
18862
  var LARGE_NUMBER_PATTERN = /\b\d{2,}\b/g;
18828
18863
  var DYNAMIC_SEGMENT_PATTERN = /^(?:\d+|[0-9a-f]{8}-[0-9a-f-]{27}|[A-Za-z0-9_-]{24,})$/;
18829
18864
  var FRAME_NOISE_PATTERNS = ["node_modules/", "vendor/", "site-packages/", ".venv/"];
18865
+ var KNOWN_DATABASE_MESSAGE_FAMILIES = [
18866
+ {
18867
+ summary: "PostgreSQL access rejected by pg_hba.conf",
18868
+ when: (message) => looksLikePostgresMessage(message) && message.includes("pg_hba.conf")
18869
+ },
18870
+ {
18871
+ summary: "PostgreSQL authentication failed",
18872
+ when: (message) => looksLikePostgresMessage(message) && (message.includes("password authentication failed") || message.includes("authentication failed for user"))
18873
+ },
18874
+ {
18875
+ summary: "PostgreSQL host resolution failed",
18876
+ when: (message) => looksLikePostgresMessage(message) && (message.includes("could not translate host name") || message.includes("getaddrinfo enotfound"))
18877
+ },
18878
+ {
18879
+ summary: "PostgreSQL connection timed out",
18880
+ when: (message) => looksLikePostgresMessage(message) && (message.includes("connection timed out") || message.includes("timeout expired") || message.includes("etimedout"))
18881
+ },
18882
+ {
18883
+ summary: "PostgreSQL connection limit reached",
18884
+ when: (message) => looksLikePostgresMessage(message) && (message.includes("too many connections") || message.includes("remaining connection slots are reserved"))
18885
+ },
18886
+ {
18887
+ summary: "PostgreSQL database does not exist",
18888
+ when: (message) => looksLikePostgresMessage(message) && message.includes("does not exist")
18889
+ },
18890
+ {
18891
+ summary: "PostgreSQL connection refused",
18892
+ when: (message) => looksLikePostgresMessage(message) && message.includes("connection refused")
18893
+ },
18894
+ {
18895
+ summary: "MySQL authentication failed",
18896
+ when: (message) => looksLikeMySqlMessage(message) && (message.includes("access denied for user") || message.includes("authentication failed"))
18897
+ },
18898
+ {
18899
+ summary: "MySQL connection refused",
18900
+ when: (message) => looksLikeMySqlMessage(message) && (message.includes("connection refused") || message.includes("can't connect to mysql server"))
18901
+ },
18902
+ {
18903
+ summary: "MySQL connection dropped",
18904
+ when: (message) => looksLikeMySqlMessage(message) && message.includes("server has gone away")
18905
+ },
18906
+ {
18907
+ summary: "MySQL connection limit reached",
18908
+ when: (message) => looksLikeMySqlMessage(message) && message.includes("too many connections")
18909
+ },
18910
+ {
18911
+ summary: "MySQL database does not exist",
18912
+ when: (message) => looksLikeMySqlMessage(message) && message.includes("unknown database")
18913
+ },
18914
+ {
18915
+ summary: "MongoDB authentication failed",
18916
+ when: (message) => looksLikeMongoMessage(message) && message.includes("authentication failed")
18917
+ },
18918
+ {
18919
+ summary: "MongoDB host resolution failed",
18920
+ when: (message) => looksLikeMongoMessage(message) && (message.includes("getaddrinfo enotfound") || message.includes("ename not found"))
18921
+ },
18922
+ {
18923
+ summary: "MongoDB connection timed out",
18924
+ when: (message) => looksLikeMongoMessage(message) && (message.includes("connection timed out") || message.includes("etimedout") || message.includes("server selection timed out"))
18925
+ },
18926
+ {
18927
+ summary: "MongoDB connection refused",
18928
+ when: (message) => looksLikeMongoMessage(message) && message.includes("connection refused")
18929
+ },
18930
+ {
18931
+ summary: "Redis authentication failed",
18932
+ when: (message) => looksLikeRedisMessage(message) && message.includes("wrongpass")
18933
+ },
18934
+ {
18935
+ summary: "Redis replica is read-only",
18936
+ when: (message) => looksLikeRedisMessage(message) && message.includes("readonly")
18937
+ },
18938
+ {
18939
+ summary: "Redis host resolution failed",
18940
+ when: (message) => looksLikeRedisMessage(message) && (message.includes("getaddrinfo enotfound") || message.includes("ename not found"))
18941
+ },
18942
+ {
18943
+ summary: "Redis connection timed out",
18944
+ when: (message) => looksLikeRedisMessage(message) && (message.includes("connection timed out") || message.includes("etimedout") || message.includes("timeout"))
18945
+ },
18946
+ {
18947
+ summary: "Redis connection refused",
18948
+ when: (message) => looksLikeRedisMessage(message) && message.includes("connection refused")
18949
+ }
18950
+ ];
18951
+ function looksLikePostgresMessage(message) {
18952
+ return message.includes("postgres") || message.includes("pgsql") || message.includes("pg_hba.conf") || message.includes("connection to server at");
18953
+ }
18954
+ function looksLikeMySqlMessage(message) {
18955
+ return message.includes("mysql") || message.includes("mariadb");
18956
+ }
18957
+ function looksLikeMongoMessage(message) {
18958
+ return message.includes("mongodb") || message.includes("mongoserver") || message.includes("mongo");
18959
+ }
18960
+ function looksLikeRedisMessage(message) {
18961
+ return message.includes("redis");
18962
+ }
18963
+ function normalizeScalarTokens(message) {
18964
+ return message.replace(UUID_PATTERN, "{dynamic}").replace(EMAIL_PATTERN, "{dynamic}").replace(ISO_TIMESTAMP_PATTERN, "{dynamic}").replace(IPV4_PATTERN, "{dynamic}").replace(HEX_PATTERN, "{dynamic}").replace(BARE_HEX_PATTERN, "{dynamic}").replace(LONG_ALPHANUMERIC_TOKEN_PATTERN, "{dynamic}").replace(LARGE_NUMBER_PATTERN, "{dynamic}");
18965
+ }
18966
+ function collapseWhitespace(message) {
18967
+ return message.replace(/\s+/g, " ").trim();
18968
+ }
18969
+ function normalizeKnownDatabaseMessage(message) {
18970
+ const lowerMessage = message.toLowerCase();
18971
+ for (const family of KNOWN_DATABASE_MESSAGE_FAMILIES) {
18972
+ if (family.when(lowerMessage)) {
18973
+ return family.summary;
18974
+ }
18975
+ }
18976
+ return null;
18977
+ }
18830
18978
  function normalizeMessage(message) {
18831
- return message.replace(UUID_PATTERN, "{dynamic}").replace(EMAIL_PATTERN, "{dynamic}").replace(ISO_TIMESTAMP_PATTERN, "{dynamic}").replace(IPV4_PATTERN, "{dynamic}").replace(HEX_PATTERN, "{dynamic}").replace(BARE_HEX_PATTERN, "{dynamic}").replace(LARGE_NUMBER_PATTERN, "{dynamic}");
18979
+ const knownDatabaseMessage = normalizeKnownDatabaseMessage(message);
18980
+ if (knownDatabaseMessage !== null) {
18981
+ return knownDatabaseMessage;
18982
+ }
18983
+ return collapseWhitespace(normalizeScalarTokens(message));
18832
18984
  }
18833
18985
  function normalizeRoute(path) {
18834
18986
  if (path === null || path.length === 0) {
@@ -20509,6 +20661,7 @@ var STORAGE_BOOTSTRAP_STATEMENTS = [
20509
20661
  channel text NOT NULL,
20510
20662
  condition_type text NOT NULL,
20511
20663
  severity_min text,
20664
+ cooldown_seconds integer NOT NULL DEFAULT 0,
20512
20665
  config jsonb NOT NULL DEFAULT '{}'::jsonb,
20513
20666
  is_enabled boolean NOT NULL DEFAULT true,
20514
20667
  created_at timestamptz NOT NULL DEFAULT now(),
@@ -20547,6 +20700,7 @@ var STORAGE_BOOTSTRAP_STATEMENTS = [
20547
20700
  incident_id uuid NOT NULL REFERENCES incidents(id) ON DELETE CASCADE,
20548
20701
  condition_type text NOT NULL,
20549
20702
  dedupe_key text NOT NULL,
20703
+ notification_key text NOT NULL DEFAULT '',
20550
20704
  channel text NOT NULL,
20551
20705
  status text NOT NULL,
20552
20706
  payload jsonb NOT NULL,
@@ -20561,6 +20715,10 @@ var STORAGE_BOOTSTRAP_STATEMENTS = [
20561
20715
  CREATE INDEX alert_deliveries_project_status_idx
20562
20716
  ON alert_deliveries (project_id, status, created_at DESC)
20563
20717
  `,
20718
+ `
20719
+ CREATE INDEX alert_deliveries_alert_notification_idx
20720
+ ON alert_deliveries (alert_id, notification_key, created_at DESC)
20721
+ `,
20564
20722
  `
20565
20723
  CREATE TABLE alert_email_digests (
20566
20724
  id uuid PRIMARY KEY,
@@ -20593,6 +20751,7 @@ var STORAGE_BOOTSTRAP_STATEMENTS = [
20593
20751
  incident_id uuid NOT NULL REFERENCES incidents(id) ON DELETE CASCADE,
20594
20752
  condition_type text NOT NULL,
20595
20753
  dedupe_key text NOT NULL,
20754
+ notification_key text NOT NULL DEFAULT '',
20596
20755
  payload jsonb NOT NULL,
20597
20756
  created_at timestamptz NOT NULL DEFAULT now(),
20598
20757
  UNIQUE (alert_id, incident_id, dedupe_key)
@@ -20602,6 +20761,10 @@ var STORAGE_BOOTSTRAP_STATEMENTS = [
20602
20761
  CREATE INDEX alert_email_digest_items_digest_created_idx
20603
20762
  ON alert_email_digest_items (digest_id, created_at ASC)
20604
20763
  `,
20764
+ `
20765
+ CREATE INDEX alert_email_digest_items_alert_notification_idx
20766
+ ON alert_email_digest_items (alert_id, notification_key, created_at DESC)
20767
+ `,
20605
20768
  `
20606
20769
  CREATE TABLE agent_webhooks (
20607
20770
  id uuid PRIMARY KEY,
@@ -20653,6 +20816,19 @@ var STORAGE_BOOTSTRAP_STATEMENTS = [
20653
20816
  processed_at timestamptz NOT NULL DEFAULT now()
20654
20817
  )
20655
20818
  `,
20819
+ `
20820
+ CREATE TABLE processed_github_marketplace_events (
20821
+ delivery_id text PRIMARY KEY,
20822
+ event_name text NOT NULL,
20823
+ marketplace_account_id bigint,
20824
+ action text,
20825
+ processed_at timestamptz NOT NULL DEFAULT now()
20826
+ )
20827
+ `,
20828
+ `
20829
+ CREATE INDEX processed_github_marketplace_events_account_idx
20830
+ ON processed_github_marketplace_events (marketplace_account_id, processed_at DESC)
20831
+ `,
20656
20832
  `
20657
20833
  CREATE TABLE github_installations (
20658
20834
  id uuid PRIMARY KEY,
@@ -20670,6 +20846,41 @@ var STORAGE_BOOTSTRAP_STATEMENTS = [
20670
20846
  CREATE INDEX github_installations_status_idx
20671
20847
  ON github_installations (status)
20672
20848
  `,
20849
+ `
20850
+ CREATE TABLE github_marketplace_accounts (
20851
+ id uuid PRIMARY KEY,
20852
+ organization_id uuid REFERENCES organizations(id) ON DELETE SET NULL,
20853
+ marketplace_account_id bigint NOT NULL UNIQUE,
20854
+ marketplace_account_login text NOT NULL,
20855
+ marketplace_account_type text NOT NULL CHECK (marketplace_account_type IN ('Organization', 'User')),
20856
+ marketplace_account_node_id text,
20857
+ marketplace_listing_plan_id bigint NOT NULL,
20858
+ marketplace_listing_plan_name text NOT NULL,
20859
+ marketplace_plan_price_model text,
20860
+ billing_cycle text CHECK (billing_cycle IN ('monthly', 'yearly')),
20861
+ unit_count integer,
20862
+ on_free_trial boolean NOT NULL DEFAULT false,
20863
+ free_trial_ends_on timestamptz,
20864
+ next_billing_date timestamptz,
20865
+ effective_date timestamptz NOT NULL,
20866
+ installation_id bigint,
20867
+ marketplace_purchase_status text NOT NULL
20868
+ CHECK (marketplace_purchase_status IN ('purchased', 'cancelled', 'pending_change', 'pending_change_cancelled', 'changed')),
20869
+ last_event_id text NOT NULL,
20870
+ last_event_action text NOT NULL,
20871
+ created_at timestamptz NOT NULL DEFAULT now(),
20872
+ updated_at timestamptz NOT NULL DEFAULT now()
20873
+ )
20874
+ `,
20875
+ `
20876
+ CREATE INDEX github_marketplace_accounts_org_idx
20877
+ ON github_marketplace_accounts (organization_id, updated_at DESC)
20878
+ `,
20879
+ `
20880
+ CREATE UNIQUE INDEX github_marketplace_accounts_installation_idx
20881
+ ON github_marketplace_accounts (installation_id)
20882
+ WHERE installation_id IS NOT NULL
20883
+ `,
20673
20884
  `
20674
20885
  CREATE TABLE project_github_repos (
20675
20886
  id uuid PRIMARY KEY,
@@ -21269,6 +21480,86 @@ var STORAGE_SCHEMA_MIGRATIONS = [
21269
21480
  ON capture_rules (project_id, updated_at DESC)
21270
21481
  `
21271
21482
  ]
21483
+ }),
21484
+ defineStorageSchemaMigration({
21485
+ id: "202606020001_add_github_marketplace_tracking",
21486
+ description: "Add GitHub Marketplace purchase tracking tables and webhook idempotency ledger.",
21487
+ statements: [
21488
+ `
21489
+ CREATE TABLE IF NOT EXISTS processed_github_marketplace_events (
21490
+ delivery_id text PRIMARY KEY,
21491
+ event_name text NOT NULL,
21492
+ marketplace_account_id bigint,
21493
+ action text,
21494
+ processed_at timestamptz NOT NULL DEFAULT now()
21495
+ )
21496
+ `,
21497
+ `
21498
+ CREATE INDEX IF NOT EXISTS processed_github_marketplace_events_account_idx
21499
+ ON processed_github_marketplace_events (marketplace_account_id, processed_at DESC)
21500
+ `,
21501
+ `
21502
+ CREATE TABLE IF NOT EXISTS github_marketplace_accounts (
21503
+ id uuid PRIMARY KEY,
21504
+ organization_id uuid REFERENCES organizations(id) ON DELETE SET NULL,
21505
+ marketplace_account_id bigint NOT NULL UNIQUE,
21506
+ marketplace_account_login text NOT NULL,
21507
+ marketplace_account_type text NOT NULL CHECK (marketplace_account_type IN ('Organization', 'User')),
21508
+ marketplace_account_node_id text,
21509
+ marketplace_listing_plan_id bigint NOT NULL,
21510
+ marketplace_listing_plan_name text NOT NULL,
21511
+ marketplace_plan_price_model text,
21512
+ billing_cycle text CHECK (billing_cycle IN ('monthly', 'yearly')),
21513
+ unit_count integer,
21514
+ on_free_trial boolean NOT NULL DEFAULT false,
21515
+ free_trial_ends_on timestamptz,
21516
+ next_billing_date timestamptz,
21517
+ effective_date timestamptz NOT NULL,
21518
+ installation_id bigint,
21519
+ marketplace_purchase_status text NOT NULL
21520
+ CHECK (marketplace_purchase_status IN ('purchased', 'cancelled', 'pending_change', 'pending_change_cancelled', 'changed')),
21521
+ last_event_id text NOT NULL,
21522
+ last_event_action text NOT NULL,
21523
+ created_at timestamptz NOT NULL DEFAULT now(),
21524
+ updated_at timestamptz NOT NULL DEFAULT now()
21525
+ )
21526
+ `,
21527
+ `
21528
+ CREATE INDEX IF NOT EXISTS github_marketplace_accounts_org_idx
21529
+ ON github_marketplace_accounts (organization_id, updated_at DESC)
21530
+ `,
21531
+ `
21532
+ CREATE UNIQUE INDEX IF NOT EXISTS github_marketplace_accounts_installation_idx
21533
+ ON github_marketplace_accounts (installation_id)
21534
+ WHERE installation_id IS NOT NULL
21535
+ `
21536
+ ]
21537
+ }),
21538
+ defineStorageSchemaMigration({
21539
+ id: "202606030001_add_alert_notification_cooldowns_and_rule_window",
21540
+ description: "Add configurable alert cooldown windows and notification keys for cross-incident suppression.",
21541
+ statements: [
21542
+ "ALTER TABLE alert_rules ADD COLUMN IF NOT EXISTS cooldown_seconds integer",
21543
+ "UPDATE alert_rules SET cooldown_seconds = 0 WHERE cooldown_seconds IS NULL",
21544
+ "ALTER TABLE alert_rules ALTER COLUMN cooldown_seconds SET DEFAULT 0",
21545
+ "ALTER TABLE alert_rules ALTER COLUMN cooldown_seconds SET NOT NULL",
21546
+ "ALTER TABLE alert_deliveries ADD COLUMN IF NOT EXISTS notification_key text",
21547
+ "UPDATE alert_deliveries SET notification_key = dedupe_key WHERE notification_key IS NULL",
21548
+ "ALTER TABLE alert_deliveries ALTER COLUMN notification_key SET DEFAULT ''",
21549
+ "ALTER TABLE alert_deliveries ALTER COLUMN notification_key SET NOT NULL",
21550
+ `
21551
+ CREATE INDEX IF NOT EXISTS alert_deliveries_alert_notification_idx
21552
+ ON alert_deliveries (alert_id, notification_key, created_at DESC)
21553
+ `,
21554
+ "ALTER TABLE alert_email_digest_items ADD COLUMN IF NOT EXISTS notification_key text",
21555
+ "UPDATE alert_email_digest_items SET notification_key = dedupe_key WHERE notification_key IS NULL",
21556
+ "ALTER TABLE alert_email_digest_items ALTER COLUMN notification_key SET DEFAULT ''",
21557
+ "ALTER TABLE alert_email_digest_items ALTER COLUMN notification_key SET NOT NULL",
21558
+ `
21559
+ CREATE INDEX IF NOT EXISTS alert_email_digest_items_alert_notification_idx
21560
+ ON alert_email_digest_items (alert_id, notification_key, created_at DESC)
21561
+ `
21562
+ ]
21272
21563
  })
21273
21564
  ];
21274
21565
 
@@ -21392,7 +21683,8 @@ function normalizeRouteTemplate(path) {
21392
21683
  return normalizedSegments.length === 0 ? "/" : `/${normalizedSegments.join("/")}`;
21393
21684
  }
21394
21685
  function isBrowserSdkFallbackFrame(frame) {
21395
- return frame.includes("debugbundle-browser-sdk") && frame.includes("onError");
21686
+ const normalizedFrame = frame.toLowerCase();
21687
+ return normalizedFrame.includes("onerror") && (normalizedFrame.includes("debugbundle-browser-sdk") || normalizedFrame.includes("debugbundle-browser.js") || normalizedFrame.includes("wp-content/plugins/debugbundle/"));
21396
21688
  }
21397
21689
  function deriveFirstApplicationFrame(errorContext) {
21398
21690
  const firstFrame = errorContext?.top_frames[0];
@@ -21437,6 +21729,20 @@ function isOpaqueBrowserError(errorContext, browserEvent) {
21437
21729
  const firstFrame = errorContext?.top_frames[0];
21438
21730
  return errorContext?.message === "Window error" && firstFrame !== void 0 && isBrowserSdkFallbackFrame(firstFrame);
21439
21731
  }
21732
+ function stableJson2(value) {
21733
+ if (value === null || typeof value !== "object") {
21734
+ return JSON.stringify(value);
21735
+ }
21736
+ if (Array.isArray(value)) {
21737
+ return `[${value.map((entry) => stableJson2(entry)).join(",")}]`;
21738
+ }
21739
+ const record = value;
21740
+ const keys = Object.keys(record).sort();
21741
+ return `{${keys.map((key) => `${JSON.stringify(key)}:${stableJson2(record[key])}`).join(",")}}`;
21742
+ }
21743
+ function buildFrontendBreadcrumbKey(input) {
21744
+ return `${input.breadcrumb_type}:${input.ts}:${input.route ?? ""}:${stableJson2(input.data)}`;
21745
+ }
21440
21746
  function buildErrorContext(envelopes, incident, primarySignalEnvelope) {
21441
21747
  if (primarySignalEnvelope !== null && isBackendExceptionEnvelope(primarySignalEnvelope)) {
21442
21748
  return {
@@ -21698,6 +22004,7 @@ function buildLogsContext(envelopes) {
21698
22004
  };
21699
22005
  }
21700
22006
  function buildFrontendContext(envelopes) {
22007
+ const breadcrumbs = /* @__PURE__ */ new Map();
21701
22008
  const routeChanges = [];
21702
22009
  const clicks = [];
21703
22010
  const formSubmissions = [];
@@ -21706,54 +22013,24 @@ function buildFrontendContext(envelopes) {
21706
22013
  const exceptions = [];
21707
22014
  for (const envelope of envelopes) {
21708
22015
  if (isFrontendBreadcrumbEnvelope(envelope)) {
21709
- const timestamp = toIsoTimestamp(envelope.occurred_at);
21710
- if (envelope.payload.breadcrumb_type === "route_change") {
21711
- const from = typeof envelope.payload.data["from"] === "string" ? envelope.payload.data["from"] : "unknown";
21712
- const to = typeof envelope.payload.data["to"] === "string" ? envelope.payload.data["to"] : envelope.payload.route ?? "unknown";
21713
- routeChanges.push({ from, to, ts: timestamp });
21714
- }
21715
- if (envelope.payload.breadcrumb_type === "click") {
21716
- clicks.push({
21717
- selector: typeof envelope.payload.data["selector"] === "string" ? envelope.payload.data["selector"] : "unknown",
21718
- label: typeof envelope.payload.data["label"] === "string" ? envelope.payload.data["label"] : "unknown",
21719
- ts: timestamp
21720
- });
21721
- }
21722
- if (envelope.payload.breadcrumb_type === "form_submit") {
21723
- formSubmissions.push({
21724
- form: typeof envelope.payload.data["form"] === "string" ? envelope.payload.data["form"] : "unknown",
21725
- fields: envelope.payload.data["fields"] !== null && typeof envelope.payload.data["fields"] === "object" ? envelope.payload.data["fields"] : {},
21726
- ts: timestamp
21727
- });
21728
- }
21729
- if (envelope.payload.breadcrumb_type === "console_log") {
21730
- consoleLogs.push({
21731
- ts: timestamp,
21732
- ...envelope.payload.data
21733
- });
21734
- }
21735
- if (envelope.payload.breadcrumb_type === "network_request") {
21736
- const d = envelope.payload.data;
22016
+ const entry = {
22017
+ breadcrumb_type: envelope.payload.breadcrumb_type,
22018
+ route: envelope.payload.route,
22019
+ data: envelope.payload.data,
22020
+ ts: toIsoTimestamp(envelope.occurred_at)
22021
+ };
22022
+ breadcrumbs.set(buildFrontendBreadcrumbKey(entry), entry);
22023
+ }
22024
+ if (isFrontendExceptionEnvelope(envelope)) {
22025
+ for (const breadcrumb of envelope.payload.breadcrumbs ?? []) {
21737
22026
  const entry = {
21738
- method: typeof d["method"] === "string" ? d["method"] : "GET",
21739
- url: typeof d["url"] === "string" ? d["url"] : "unknown",
21740
- status: typeof d["status_code"] === "number" && Number.isInteger(d["status_code"]) ? d["status_code"] : typeof d["status"] === "number" && Number.isInteger(d["status"]) ? d["status"] : 0,
21741
- ts: timestamp
22027
+ breadcrumb_type: breadcrumb.breadcrumb_type,
22028
+ route: breadcrumb.route,
22029
+ data: breadcrumb.data,
22030
+ ts: toIsoTimestamp(breadcrumb.ts)
21742
22031
  };
21743
- if (typeof d["duration_ms"] === "number") entry.duration_ms = d["duration_ms"];
21744
- if (Array.isArray(d["caller_trace"])) entry.caller_trace = d["caller_trace"];
21745
- if (d["response_body"] !== void 0) entry.response_body = d["response_body"];
21746
- if (d["request_body"] !== void 0) entry.request_body = d["request_body"];
21747
- if (typeof d["response_headers"] === "object" && d["response_headers"] !== null) {
21748
- entry.response_headers = d["response_headers"];
21749
- }
21750
- if (typeof d["response_content_length"] === "number") {
21751
- entry.response_content_length = d["response_content_length"];
21752
- }
21753
- networkRequests.push(entry);
22032
+ breadcrumbs.set(buildFrontendBreadcrumbKey(entry), entry);
21754
22033
  }
21755
- }
21756
- if (isFrontendExceptionEnvelope(envelope)) {
21757
22034
  exceptions.push({
21758
22035
  name: envelope.payload.name,
21759
22036
  message: envelope.payload.message,
@@ -21764,6 +22041,59 @@ function buildFrontendContext(envelopes) {
21764
22041
  });
21765
22042
  }
21766
22043
  }
22044
+ const sortedBreadcrumbs = [...breadcrumbs.values()].sort((left, right) => {
22045
+ const timestampComparison = left.ts.localeCompare(right.ts);
22046
+ if (timestampComparison !== 0) {
22047
+ return timestampComparison;
22048
+ }
22049
+ return buildFrontendBreadcrumbKey(left).localeCompare(buildFrontendBreadcrumbKey(right));
22050
+ });
22051
+ for (const breadcrumb of sortedBreadcrumbs) {
22052
+ if (breadcrumb.breadcrumb_type === "route_change") {
22053
+ const from = typeof breadcrumb.data["from"] === "string" ? breadcrumb.data["from"] : "unknown";
22054
+ const to = typeof breadcrumb.data["to"] === "string" ? breadcrumb.data["to"] : breadcrumb.route ?? "unknown";
22055
+ routeChanges.push({ from, to, ts: breadcrumb.ts });
22056
+ }
22057
+ if (breadcrumb.breadcrumb_type === "click") {
22058
+ clicks.push({
22059
+ selector: typeof breadcrumb.data["selector"] === "string" ? breadcrumb.data["selector"] : "unknown",
22060
+ label: typeof breadcrumb.data["label"] === "string" ? breadcrumb.data["label"] : "unknown",
22061
+ ts: breadcrumb.ts
22062
+ });
22063
+ }
22064
+ if (breadcrumb.breadcrumb_type === "form_submit") {
22065
+ formSubmissions.push({
22066
+ form: typeof breadcrumb.data["form"] === "string" ? breadcrumb.data["form"] : "unknown",
22067
+ fields: breadcrumb.data["fields"] !== null && typeof breadcrumb.data["fields"] === "object" ? breadcrumb.data["fields"] : {},
22068
+ ts: breadcrumb.ts
22069
+ });
22070
+ }
22071
+ if (breadcrumb.breadcrumb_type === "console_log") {
22072
+ consoleLogs.push({
22073
+ ts: breadcrumb.ts,
22074
+ ...breadcrumb.data
22075
+ });
22076
+ }
22077
+ if (breadcrumb.breadcrumb_type === "network_request") {
22078
+ const entry = {
22079
+ method: typeof breadcrumb.data["method"] === "string" ? breadcrumb.data["method"] : "GET",
22080
+ url: typeof breadcrumb.data["url"] === "string" ? breadcrumb.data["url"] : "unknown",
22081
+ status: typeof breadcrumb.data["status_code"] === "number" && Number.isInteger(breadcrumb.data["status_code"]) ? breadcrumb.data["status_code"] : typeof breadcrumb.data["status"] === "number" && Number.isInteger(breadcrumb.data["status"]) ? breadcrumb.data["status"] : 0,
22082
+ ts: breadcrumb.ts
22083
+ };
22084
+ if (typeof breadcrumb.data["duration_ms"] === "number") entry.duration_ms = breadcrumb.data["duration_ms"];
22085
+ if (Array.isArray(breadcrumb.data["caller_trace"])) entry.caller_trace = breadcrumb.data["caller_trace"];
22086
+ if (breadcrumb.data["response_body"] !== void 0) entry.response_body = breadcrumb.data["response_body"];
22087
+ if (breadcrumb.data["request_body"] !== void 0) entry.request_body = breadcrumb.data["request_body"];
22088
+ if (typeof breadcrumb.data["response_headers"] === "object" && breadcrumb.data["response_headers"] !== null) {
22089
+ entry.response_headers = breadcrumb.data["response_headers"];
22090
+ }
22091
+ if (typeof breadcrumb.data["response_content_length"] === "number") {
22092
+ entry.response_content_length = breadcrumb.data["response_content_length"];
22093
+ }
22094
+ networkRequests.push(entry);
22095
+ }
22096
+ }
21767
22097
  const latestFrontendException = selectLatestEnvelopeByType(envelopes, isFrontendExceptionEnvelope);
21768
22098
  const domContext = latestFrontendException?.payload.dom_context ?? null;
21769
22099
  if (routeChanges.length === 0 && clicks.length === 0 && formSubmissions.length === 0 && consoleLogs.length === 0 && networkRequests.length === 0 && exceptions.length === 0 && domContext === null) {
@@ -21913,7 +22243,7 @@ function buildBundle(input) {
21913
22243
  const serviceRuntime = input.incident.service_runtime ?? selectLatestEnvelope(sourceEnvelopes, (envelope) => envelope.event_type !== "probe_event")?.service.runtime ?? null;
21914
22244
  const serviceFramework = input.incident.service_framework ?? selectLatestEnvelope(sourceEnvelopes, (envelope) => envelope.event_type !== "probe_event")?.service.framework ?? null;
21915
22245
  const customerVisible = frontendContext !== null;
21916
- const firstApplicationFrame = deriveFirstApplicationFrame(errorContext);
22246
+ const firstApplicationFrame = opaqueBrowserError ? null : deriveFirstApplicationFrame(errorContext);
21917
22247
  const summaryGuidance = buildSummaryGuidance({
21918
22248
  errorContext,
21919
22249
  requestContext,
@@ -22446,20 +22776,20 @@ function mergeSourceEvents(existingEvents, nextEvents) {
22446
22776
  }
22447
22777
  return [...merged.values()].sort(compareEventEnvelopes);
22448
22778
  }
22449
- function stableJson2(value) {
22779
+ function stableJson3(value) {
22450
22780
  if (value === null || typeof value !== "object") {
22451
22781
  return JSON.stringify(value);
22452
22782
  }
22453
22783
  if (Array.isArray(value)) {
22454
- return `[${value.map((entry) => stableJson2(entry)).join(",")}]`;
22784
+ return `[${value.map((entry) => stableJson3(entry)).join(",")}]`;
22455
22785
  }
22456
22786
  const record = value;
22457
22787
  const keys = Object.keys(record).sort();
22458
- return `{${keys.map((key) => `${JSON.stringify(key)}:${stableJson2(record[key])}`).join(",")}}`;
22788
+ return `{${keys.map((key) => `${JSON.stringify(key)}:${stableJson3(record[key])}`).join(",")}}`;
22459
22789
  }
22460
22790
  function buildRequestAnomalyFingerprint(input) {
22461
22791
  return (0, import_node_crypto4.createHash)("sha256").update(
22462
- stableJson2({
22792
+ stableJson3({
22463
22793
  kind: "request_status_anomaly",
22464
22794
  project_id: input.projectId,
22465
22795
  service_name: input.serviceName,
@@ -24553,6 +24883,9 @@ function createAlertMcpTools(api) {
24553
24883
  if (typeof input["severityMin"] === "string") {
24554
24884
  requestInput.severityMin = input["severityMin"];
24555
24885
  }
24886
+ if (typeof input["cooldownSeconds"] === "number") {
24887
+ requestInput.cooldownSeconds = input["cooldownSeconds"];
24888
+ }
24556
24889
  if (typeof input["isEnabled"] === "boolean") {
24557
24890
  requestInput.isEnabled = input["isEnabled"];
24558
24891
  }
@@ -24584,6 +24917,9 @@ function createAlertMcpTools(api) {
24584
24917
  } else if (input["severityMin"] === null) {
24585
24918
  requestInput.severityMin = null;
24586
24919
  }
24920
+ if (typeof input["cooldownSeconds"] === "number") {
24921
+ requestInput.cooldownSeconds = input["cooldownSeconds"];
24922
+ }
24587
24923
  if (typeof input["config"] === "object") {
24588
24924
  requestInput.config = input["config"];
24589
24925
  }
@@ -25177,6 +25513,16 @@ function createMemberMcpTools(api) {
25177
25513
  } catch (error) {
25178
25514
  mapMcpError9(error);
25179
25515
  }
25516
+ },
25517
+ async leave_project(input) {
25518
+ try {
25519
+ return await api.leaveProject({
25520
+ bearerToken: String(input["bearerToken"]),
25521
+ projectId: String(input["projectId"])
25522
+ });
25523
+ } catch (error) {
25524
+ mapMcpError9(error);
25525
+ }
25180
25526
  }
25181
25527
  };
25182
25528
  }
@@ -27759,7 +28105,7 @@ var zodToJsonSchema = (schema, options) => {
27759
28105
  var package_default = {
27760
28106
  name: "@debugbundle/mcp",
27761
28107
  mcpName: "com.debugbundle/mcp",
27762
- version: "1.0.0",
28108
+ version: "1.0.2",
27763
28109
  private: false,
27764
28110
  description: "Model Context Protocol server for DebugBundle",
27765
28111
  license: "AGPL-3.0-only",
@@ -28349,6 +28695,7 @@ var MCP_TOOL_CATALOG = [
28349
28695
  channel: external_exports.string(),
28350
28696
  conditionType: external_exports.string(),
28351
28697
  severityMin: external_exports.string().optional(),
28698
+ cooldownSeconds: external_exports.number().int().min(0).max(604800).optional(),
28352
28699
  config: jsonObjectSchema,
28353
28700
  isEnabled: external_exports.boolean().optional()
28354
28701
  })
@@ -28365,6 +28712,7 @@ var MCP_TOOL_CATALOG = [
28365
28712
  channel: external_exports.string().optional(),
28366
28713
  conditionType: external_exports.string().optional(),
28367
28714
  severityMin: external_exports.string().nullable().optional(),
28715
+ cooldownSeconds: external_exports.number().int().min(0).max(604800).optional(),
28368
28716
  config: jsonObjectSchema.nullable().optional(),
28369
28717
  isEnabled: external_exports.boolean().optional()
28370
28718
  })
@@ -28654,6 +29002,15 @@ var MCP_TOOL_CATALOG = [
28654
29002
  userId: external_exports.string()
28655
29003
  })
28656
29004
  },
29005
+ {
29006
+ name: "leave_project",
29007
+ group: "members",
29008
+ description: "Leave a shared project as the authenticated collaborator.",
29009
+ inputSchema: external_exports.object({
29010
+ bearerToken: external_exports.string(),
29011
+ projectId: external_exports.string()
29012
+ })
29013
+ },
28657
29014
  {
28658
29015
  name: "list_services",
28659
29016
  group: "services",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@debugbundle/mcp",
3
3
  "mcpName": "com.debugbundle/mcp",
4
- "version": "1.0.0",
4
+ "version": "1.0.2",
5
5
  "private": false,
6
6
  "description": "Model Context Protocol server for DebugBundle",
7
7
  "license": "AGPL-3.0-only",
package/server.json CHANGED
@@ -8,13 +8,13 @@
8
8
  "source": "github",
9
9
  "subfolder": "apps/mcp"
10
10
  },
11
- "version": "1.0.0",
11
+ "version": "1.0.2",
12
12
  "packages": [
13
13
  {
14
14
  "registryType": "npm",
15
15
  "registryBaseUrl": "https://registry.npmjs.org",
16
16
  "identifier": "@debugbundle/mcp",
17
- "version": "1.0.0",
17
+ "version": "1.0.2",
18
18
  "transport": {
19
19
  "type": "stdio"
20
20
  },