@debugbundle/cli 1.0.2 → 1.0.3

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 (2) hide show
  1. package/dist/main.cjs +281 -58
  2. package/package.json +1 -1
package/dist/main.cjs CHANGED
@@ -15169,8 +15169,24 @@ var BrowserExceptionEventSchema = external_exports.object({
15169
15169
  column_number: external_exports.number().int().nonnegative().nullable(),
15170
15170
  target: external_exports.object({
15171
15171
  tag_name: external_exports.string().nullable(),
15172
- source_url: external_exports.string().nullable()
15173
- }).nullable(),
15172
+ source_url: external_exports.string().nullable(),
15173
+ attributes: external_exports.object({
15174
+ rel: external_exports.string().optional(),
15175
+ as: external_exports.string().optional(),
15176
+ type: external_exports.string().optional(),
15177
+ media: external_exports.string().optional(),
15178
+ cross_origin: external_exports.string().optional(),
15179
+ async: external_exports.boolean().optional(),
15180
+ defer: external_exports.boolean().optional(),
15181
+ integrity_present: external_exports.boolean().optional()
15182
+ }).strict().optional()
15183
+ }).strict().nullable(),
15184
+ page: external_exports.object({
15185
+ url: external_exports.string().nullable(),
15186
+ referrer: external_exports.string().nullable(),
15187
+ ready_state: external_exports.enum(["loading", "interactive", "complete"]).nullable(),
15188
+ visibility_state: external_exports.enum(["visible", "hidden", "prerender", "unloaded"]).nullable()
15189
+ }).strict().optional(),
15174
15190
  opaque: external_exports.boolean()
15175
15191
  }).strict();
15176
15192
  var FrontendExceptionPayloadSchema = external_exports.object({
@@ -18121,6 +18137,7 @@ var STORAGE_BOOTSTRAP_STATEMENTS = [
18121
18137
  channel text NOT NULL,
18122
18138
  condition_type text NOT NULL,
18123
18139
  severity_min text,
18140
+ cooldown_seconds integer NOT NULL DEFAULT 0,
18124
18141
  config jsonb NOT NULL DEFAULT '{}'::jsonb,
18125
18142
  is_enabled boolean NOT NULL DEFAULT true,
18126
18143
  created_at timestamptz NOT NULL DEFAULT now(),
@@ -18159,6 +18176,7 @@ var STORAGE_BOOTSTRAP_STATEMENTS = [
18159
18176
  incident_id uuid NOT NULL REFERENCES incidents(id) ON DELETE CASCADE,
18160
18177
  condition_type text NOT NULL,
18161
18178
  dedupe_key text NOT NULL,
18179
+ notification_key text NOT NULL DEFAULT '',
18162
18180
  channel text NOT NULL,
18163
18181
  status text NOT NULL,
18164
18182
  payload jsonb NOT NULL,
@@ -18173,6 +18191,10 @@ var STORAGE_BOOTSTRAP_STATEMENTS = [
18173
18191
  CREATE INDEX alert_deliveries_project_status_idx
18174
18192
  ON alert_deliveries (project_id, status, created_at DESC)
18175
18193
  `,
18194
+ `
18195
+ CREATE INDEX alert_deliveries_alert_notification_idx
18196
+ ON alert_deliveries (alert_id, notification_key, created_at DESC)
18197
+ `,
18176
18198
  `
18177
18199
  CREATE TABLE alert_email_digests (
18178
18200
  id uuid PRIMARY KEY,
@@ -18205,6 +18227,7 @@ var STORAGE_BOOTSTRAP_STATEMENTS = [
18205
18227
  incident_id uuid NOT NULL REFERENCES incidents(id) ON DELETE CASCADE,
18206
18228
  condition_type text NOT NULL,
18207
18229
  dedupe_key text NOT NULL,
18230
+ notification_key text NOT NULL DEFAULT '',
18208
18231
  payload jsonb NOT NULL,
18209
18232
  created_at timestamptz NOT NULL DEFAULT now(),
18210
18233
  UNIQUE (alert_id, incident_id, dedupe_key)
@@ -18214,6 +18237,10 @@ var STORAGE_BOOTSTRAP_STATEMENTS = [
18214
18237
  CREATE INDEX alert_email_digest_items_digest_created_idx
18215
18238
  ON alert_email_digest_items (digest_id, created_at ASC)
18216
18239
  `,
18240
+ `
18241
+ CREATE INDEX alert_email_digest_items_alert_notification_idx
18242
+ ON alert_email_digest_items (alert_id, notification_key, created_at DESC)
18243
+ `,
18217
18244
  `
18218
18245
  CREATE TABLE agent_webhooks (
18219
18246
  id uuid PRIMARY KEY,
@@ -18265,6 +18292,19 @@ var STORAGE_BOOTSTRAP_STATEMENTS = [
18265
18292
  processed_at timestamptz NOT NULL DEFAULT now()
18266
18293
  )
18267
18294
  `,
18295
+ `
18296
+ CREATE TABLE processed_github_marketplace_events (
18297
+ delivery_id text PRIMARY KEY,
18298
+ event_name text NOT NULL,
18299
+ marketplace_account_id bigint,
18300
+ action text,
18301
+ processed_at timestamptz NOT NULL DEFAULT now()
18302
+ )
18303
+ `,
18304
+ `
18305
+ CREATE INDEX processed_github_marketplace_events_account_idx
18306
+ ON processed_github_marketplace_events (marketplace_account_id, processed_at DESC)
18307
+ `,
18268
18308
  `
18269
18309
  CREATE TABLE github_installations (
18270
18310
  id uuid PRIMARY KEY,
@@ -18282,6 +18322,41 @@ var STORAGE_BOOTSTRAP_STATEMENTS = [
18282
18322
  CREATE INDEX github_installations_status_idx
18283
18323
  ON github_installations (status)
18284
18324
  `,
18325
+ `
18326
+ CREATE TABLE github_marketplace_accounts (
18327
+ id uuid PRIMARY KEY,
18328
+ organization_id uuid REFERENCES organizations(id) ON DELETE SET NULL,
18329
+ marketplace_account_id bigint NOT NULL UNIQUE,
18330
+ marketplace_account_login text NOT NULL,
18331
+ marketplace_account_type text NOT NULL CHECK (marketplace_account_type IN ('Organization', 'User')),
18332
+ marketplace_account_node_id text,
18333
+ marketplace_listing_plan_id bigint NOT NULL,
18334
+ marketplace_listing_plan_name text NOT NULL,
18335
+ marketplace_plan_price_model text,
18336
+ billing_cycle text CHECK (billing_cycle IN ('monthly', 'yearly')),
18337
+ unit_count integer,
18338
+ on_free_trial boolean NOT NULL DEFAULT false,
18339
+ free_trial_ends_on timestamptz,
18340
+ next_billing_date timestamptz,
18341
+ effective_date timestamptz NOT NULL,
18342
+ installation_id bigint,
18343
+ marketplace_purchase_status text NOT NULL
18344
+ CHECK (marketplace_purchase_status IN ('purchased', 'cancelled', 'pending_change', 'pending_change_cancelled', 'changed')),
18345
+ last_event_id text NOT NULL,
18346
+ last_event_action text NOT NULL,
18347
+ created_at timestamptz NOT NULL DEFAULT now(),
18348
+ updated_at timestamptz NOT NULL DEFAULT now()
18349
+ )
18350
+ `,
18351
+ `
18352
+ CREATE INDEX github_marketplace_accounts_org_idx
18353
+ ON github_marketplace_accounts (organization_id, updated_at DESC)
18354
+ `,
18355
+ `
18356
+ CREATE UNIQUE INDEX github_marketplace_accounts_installation_idx
18357
+ ON github_marketplace_accounts (installation_id)
18358
+ WHERE installation_id IS NOT NULL
18359
+ `,
18285
18360
  `
18286
18361
  CREATE TABLE project_github_repos (
18287
18362
  id uuid PRIMARY KEY,
@@ -18881,6 +18956,86 @@ var STORAGE_SCHEMA_MIGRATIONS = [
18881
18956
  ON capture_rules (project_id, updated_at DESC)
18882
18957
  `
18883
18958
  ]
18959
+ }),
18960
+ defineStorageSchemaMigration({
18961
+ id: "202606020001_add_github_marketplace_tracking",
18962
+ description: "Add GitHub Marketplace purchase tracking tables and webhook idempotency ledger.",
18963
+ statements: [
18964
+ `
18965
+ CREATE TABLE IF NOT EXISTS processed_github_marketplace_events (
18966
+ delivery_id text PRIMARY KEY,
18967
+ event_name text NOT NULL,
18968
+ marketplace_account_id bigint,
18969
+ action text,
18970
+ processed_at timestamptz NOT NULL DEFAULT now()
18971
+ )
18972
+ `,
18973
+ `
18974
+ CREATE INDEX IF NOT EXISTS processed_github_marketplace_events_account_idx
18975
+ ON processed_github_marketplace_events (marketplace_account_id, processed_at DESC)
18976
+ `,
18977
+ `
18978
+ CREATE TABLE IF NOT EXISTS github_marketplace_accounts (
18979
+ id uuid PRIMARY KEY,
18980
+ organization_id uuid REFERENCES organizations(id) ON DELETE SET NULL,
18981
+ marketplace_account_id bigint NOT NULL UNIQUE,
18982
+ marketplace_account_login text NOT NULL,
18983
+ marketplace_account_type text NOT NULL CHECK (marketplace_account_type IN ('Organization', 'User')),
18984
+ marketplace_account_node_id text,
18985
+ marketplace_listing_plan_id bigint NOT NULL,
18986
+ marketplace_listing_plan_name text NOT NULL,
18987
+ marketplace_plan_price_model text,
18988
+ billing_cycle text CHECK (billing_cycle IN ('monthly', 'yearly')),
18989
+ unit_count integer,
18990
+ on_free_trial boolean NOT NULL DEFAULT false,
18991
+ free_trial_ends_on timestamptz,
18992
+ next_billing_date timestamptz,
18993
+ effective_date timestamptz NOT NULL,
18994
+ installation_id bigint,
18995
+ marketplace_purchase_status text NOT NULL
18996
+ CHECK (marketplace_purchase_status IN ('purchased', 'cancelled', 'pending_change', 'pending_change_cancelled', 'changed')),
18997
+ last_event_id text NOT NULL,
18998
+ last_event_action text NOT NULL,
18999
+ created_at timestamptz NOT NULL DEFAULT now(),
19000
+ updated_at timestamptz NOT NULL DEFAULT now()
19001
+ )
19002
+ `,
19003
+ `
19004
+ CREATE INDEX IF NOT EXISTS github_marketplace_accounts_org_idx
19005
+ ON github_marketplace_accounts (organization_id, updated_at DESC)
19006
+ `,
19007
+ `
19008
+ CREATE UNIQUE INDEX IF NOT EXISTS github_marketplace_accounts_installation_idx
19009
+ ON github_marketplace_accounts (installation_id)
19010
+ WHERE installation_id IS NOT NULL
19011
+ `
19012
+ ]
19013
+ }),
19014
+ defineStorageSchemaMigration({
19015
+ id: "202606030001_add_alert_notification_cooldowns_and_rule_window",
19016
+ description: "Add configurable alert cooldown windows and notification keys for cross-incident suppression.",
19017
+ statements: [
19018
+ "ALTER TABLE alert_rules ADD COLUMN IF NOT EXISTS cooldown_seconds integer",
19019
+ "UPDATE alert_rules SET cooldown_seconds = 0 WHERE cooldown_seconds IS NULL",
19020
+ "ALTER TABLE alert_rules ALTER COLUMN cooldown_seconds SET DEFAULT 0",
19021
+ "ALTER TABLE alert_rules ALTER COLUMN cooldown_seconds SET NOT NULL",
19022
+ "ALTER TABLE alert_deliveries ADD COLUMN IF NOT EXISTS notification_key text",
19023
+ "UPDATE alert_deliveries SET notification_key = dedupe_key WHERE notification_key IS NULL",
19024
+ "ALTER TABLE alert_deliveries ALTER COLUMN notification_key SET DEFAULT ''",
19025
+ "ALTER TABLE alert_deliveries ALTER COLUMN notification_key SET NOT NULL",
19026
+ `
19027
+ CREATE INDEX IF NOT EXISTS alert_deliveries_alert_notification_idx
19028
+ ON alert_deliveries (alert_id, notification_key, created_at DESC)
19029
+ `,
19030
+ "ALTER TABLE alert_email_digest_items ADD COLUMN IF NOT EXISTS notification_key text",
19031
+ "UPDATE alert_email_digest_items SET notification_key = dedupe_key WHERE notification_key IS NULL",
19032
+ "ALTER TABLE alert_email_digest_items ALTER COLUMN notification_key SET DEFAULT ''",
19033
+ "ALTER TABLE alert_email_digest_items ALTER COLUMN notification_key SET NOT NULL",
19034
+ `
19035
+ CREATE INDEX IF NOT EXISTS alert_email_digest_items_alert_notification_idx
19036
+ ON alert_email_digest_items (alert_id, notification_key, created_at DESC)
19037
+ `
19038
+ ]
18884
19039
  })
18885
19040
  ];
18886
19041
 
@@ -20002,6 +20157,7 @@ var AlertSchema = external_exports.object({
20002
20157
  channel: AlertChannelSchema,
20003
20158
  condition_type: AlertConditionTypeSchema,
20004
20159
  severity_min: external_exports.enum(["low", "medium", "high", "critical"]).nullable(),
20160
+ cooldown_seconds: external_exports.number().int().min(0),
20005
20161
  config: external_exports.record(external_exports.string(), external_exports.unknown()),
20006
20162
  is_enabled: external_exports.boolean(),
20007
20163
  created_at: external_exports.string(),
@@ -20088,6 +20244,9 @@ function createAlertApi(client) {
20088
20244
  if (input2.severityMin !== void 0) {
20089
20245
  body.severity_min = input2.severityMin;
20090
20246
  }
20247
+ if (input2.cooldownSeconds !== void 0) {
20248
+ body.cooldown_seconds = input2.cooldownSeconds;
20249
+ }
20091
20250
  if (input2.isEnabled !== void 0) {
20092
20251
  body.is_enabled = input2.isEnabled;
20093
20252
  }
@@ -20114,6 +20273,9 @@ function createAlertApi(client) {
20114
20273
  if (input2.severityMin !== void 0) {
20115
20274
  body.severity_min = input2.severityMin;
20116
20275
  }
20276
+ if (input2.cooldownSeconds !== void 0) {
20277
+ body.cooldown_seconds = input2.cooldownSeconds;
20278
+ }
20117
20279
  if (input2.config !== void 0) {
20118
20280
  body.config = input2.config;
20119
20281
  }
@@ -23262,7 +23424,8 @@ function normalizeRouteTemplate(path) {
23262
23424
  return normalizedSegments.length === 0 ? "/" : `/${normalizedSegments.join("/")}`;
23263
23425
  }
23264
23426
  function isBrowserSdkFallbackFrame(frame) {
23265
- return frame.includes("debugbundle-browser-sdk") && frame.includes("onError");
23427
+ const normalizedFrame = frame.toLowerCase();
23428
+ return normalizedFrame.includes("onerror") && (normalizedFrame.includes("debugbundle-browser-sdk") || normalizedFrame.includes("debugbundle-browser.js") || normalizedFrame.includes("wp-content/plugins/debugbundle/"));
23266
23429
  }
23267
23430
  function deriveFirstApplicationFrame(errorContext) {
23268
23431
  const firstFrame = errorContext?.top_frames[0];
@@ -23307,6 +23470,20 @@ function isOpaqueBrowserError(errorContext, browserEvent) {
23307
23470
  const firstFrame = errorContext?.top_frames[0];
23308
23471
  return errorContext?.message === "Window error" && firstFrame !== void 0 && isBrowserSdkFallbackFrame(firstFrame);
23309
23472
  }
23473
+ function stableJson2(value) {
23474
+ if (value === null || typeof value !== "object") {
23475
+ return JSON.stringify(value);
23476
+ }
23477
+ if (Array.isArray(value)) {
23478
+ return `[${value.map((entry) => stableJson2(entry)).join(",")}]`;
23479
+ }
23480
+ const record = value;
23481
+ const keys = Object.keys(record).sort();
23482
+ return `{${keys.map((key) => `${JSON.stringify(key)}:${stableJson2(record[key])}`).join(",")}}`;
23483
+ }
23484
+ function buildFrontendBreadcrumbKey(input2) {
23485
+ return `${input2.breadcrumb_type}:${input2.ts}:${input2.route ?? ""}:${stableJson2(input2.data)}`;
23486
+ }
23310
23487
  function buildErrorContext(envelopes, incident, primarySignalEnvelope) {
23311
23488
  if (primarySignalEnvelope !== null && isBackendExceptionEnvelope(primarySignalEnvelope)) {
23312
23489
  return {
@@ -23568,6 +23745,7 @@ function buildLogsContext(envelopes) {
23568
23745
  };
23569
23746
  }
23570
23747
  function buildFrontendContext(envelopes) {
23748
+ const breadcrumbs = /* @__PURE__ */ new Map();
23571
23749
  const routeChanges = [];
23572
23750
  const clicks = [];
23573
23751
  const formSubmissions = [];
@@ -23576,54 +23754,24 @@ function buildFrontendContext(envelopes) {
23576
23754
  const exceptions = [];
23577
23755
  for (const envelope of envelopes) {
23578
23756
  if (isFrontendBreadcrumbEnvelope(envelope)) {
23579
- const timestamp = toIsoTimestamp(envelope.occurred_at);
23580
- if (envelope.payload.breadcrumb_type === "route_change") {
23581
- const from = typeof envelope.payload.data["from"] === "string" ? envelope.payload.data["from"] : "unknown";
23582
- const to = typeof envelope.payload.data["to"] === "string" ? envelope.payload.data["to"] : envelope.payload.route ?? "unknown";
23583
- routeChanges.push({ from, to, ts: timestamp });
23584
- }
23585
- if (envelope.payload.breadcrumb_type === "click") {
23586
- clicks.push({
23587
- selector: typeof envelope.payload.data["selector"] === "string" ? envelope.payload.data["selector"] : "unknown",
23588
- label: typeof envelope.payload.data["label"] === "string" ? envelope.payload.data["label"] : "unknown",
23589
- ts: timestamp
23590
- });
23591
- }
23592
- if (envelope.payload.breadcrumb_type === "form_submit") {
23593
- formSubmissions.push({
23594
- form: typeof envelope.payload.data["form"] === "string" ? envelope.payload.data["form"] : "unknown",
23595
- fields: envelope.payload.data["fields"] !== null && typeof envelope.payload.data["fields"] === "object" ? envelope.payload.data["fields"] : {},
23596
- ts: timestamp
23597
- });
23598
- }
23599
- if (envelope.payload.breadcrumb_type === "console_log") {
23600
- consoleLogs.push({
23601
- ts: timestamp,
23602
- ...envelope.payload.data
23603
- });
23604
- }
23605
- if (envelope.payload.breadcrumb_type === "network_request") {
23606
- const d = envelope.payload.data;
23757
+ const entry = {
23758
+ breadcrumb_type: envelope.payload.breadcrumb_type,
23759
+ route: envelope.payload.route,
23760
+ data: envelope.payload.data,
23761
+ ts: toIsoTimestamp(envelope.occurred_at)
23762
+ };
23763
+ breadcrumbs.set(buildFrontendBreadcrumbKey(entry), entry);
23764
+ }
23765
+ if (isFrontendExceptionEnvelope(envelope)) {
23766
+ for (const breadcrumb of envelope.payload.breadcrumbs ?? []) {
23607
23767
  const entry = {
23608
- method: typeof d["method"] === "string" ? d["method"] : "GET",
23609
- url: typeof d["url"] === "string" ? d["url"] : "unknown",
23610
- 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,
23611
- ts: timestamp
23768
+ breadcrumb_type: breadcrumb.breadcrumb_type,
23769
+ route: breadcrumb.route,
23770
+ data: breadcrumb.data,
23771
+ ts: toIsoTimestamp(breadcrumb.ts)
23612
23772
  };
23613
- if (typeof d["duration_ms"] === "number") entry.duration_ms = d["duration_ms"];
23614
- if (Array.isArray(d["caller_trace"])) entry.caller_trace = d["caller_trace"];
23615
- if (d["response_body"] !== void 0) entry.response_body = d["response_body"];
23616
- if (d["request_body"] !== void 0) entry.request_body = d["request_body"];
23617
- if (typeof d["response_headers"] === "object" && d["response_headers"] !== null) {
23618
- entry.response_headers = d["response_headers"];
23619
- }
23620
- if (typeof d["response_content_length"] === "number") {
23621
- entry.response_content_length = d["response_content_length"];
23622
- }
23623
- networkRequests.push(entry);
23773
+ breadcrumbs.set(buildFrontendBreadcrumbKey(entry), entry);
23624
23774
  }
23625
- }
23626
- if (isFrontendExceptionEnvelope(envelope)) {
23627
23775
  exceptions.push({
23628
23776
  name: envelope.payload.name,
23629
23777
  message: envelope.payload.message,
@@ -23634,6 +23782,59 @@ function buildFrontendContext(envelopes) {
23634
23782
  });
23635
23783
  }
23636
23784
  }
23785
+ const sortedBreadcrumbs = [...breadcrumbs.values()].sort((left, right) => {
23786
+ const timestampComparison = left.ts.localeCompare(right.ts);
23787
+ if (timestampComparison !== 0) {
23788
+ return timestampComparison;
23789
+ }
23790
+ return buildFrontendBreadcrumbKey(left).localeCompare(buildFrontendBreadcrumbKey(right));
23791
+ });
23792
+ for (const breadcrumb of sortedBreadcrumbs) {
23793
+ if (breadcrumb.breadcrumb_type === "route_change") {
23794
+ const from = typeof breadcrumb.data["from"] === "string" ? breadcrumb.data["from"] : "unknown";
23795
+ const to = typeof breadcrumb.data["to"] === "string" ? breadcrumb.data["to"] : breadcrumb.route ?? "unknown";
23796
+ routeChanges.push({ from, to, ts: breadcrumb.ts });
23797
+ }
23798
+ if (breadcrumb.breadcrumb_type === "click") {
23799
+ clicks.push({
23800
+ selector: typeof breadcrumb.data["selector"] === "string" ? breadcrumb.data["selector"] : "unknown",
23801
+ label: typeof breadcrumb.data["label"] === "string" ? breadcrumb.data["label"] : "unknown",
23802
+ ts: breadcrumb.ts
23803
+ });
23804
+ }
23805
+ if (breadcrumb.breadcrumb_type === "form_submit") {
23806
+ formSubmissions.push({
23807
+ form: typeof breadcrumb.data["form"] === "string" ? breadcrumb.data["form"] : "unknown",
23808
+ fields: breadcrumb.data["fields"] !== null && typeof breadcrumb.data["fields"] === "object" ? breadcrumb.data["fields"] : {},
23809
+ ts: breadcrumb.ts
23810
+ });
23811
+ }
23812
+ if (breadcrumb.breadcrumb_type === "console_log") {
23813
+ consoleLogs.push({
23814
+ ts: breadcrumb.ts,
23815
+ ...breadcrumb.data
23816
+ });
23817
+ }
23818
+ if (breadcrumb.breadcrumb_type === "network_request") {
23819
+ const entry = {
23820
+ method: typeof breadcrumb.data["method"] === "string" ? breadcrumb.data["method"] : "GET",
23821
+ url: typeof breadcrumb.data["url"] === "string" ? breadcrumb.data["url"] : "unknown",
23822
+ 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,
23823
+ ts: breadcrumb.ts
23824
+ };
23825
+ if (typeof breadcrumb.data["duration_ms"] === "number") entry.duration_ms = breadcrumb.data["duration_ms"];
23826
+ if (Array.isArray(breadcrumb.data["caller_trace"])) entry.caller_trace = breadcrumb.data["caller_trace"];
23827
+ if (breadcrumb.data["response_body"] !== void 0) entry.response_body = breadcrumb.data["response_body"];
23828
+ if (breadcrumb.data["request_body"] !== void 0) entry.request_body = breadcrumb.data["request_body"];
23829
+ if (typeof breadcrumb.data["response_headers"] === "object" && breadcrumb.data["response_headers"] !== null) {
23830
+ entry.response_headers = breadcrumb.data["response_headers"];
23831
+ }
23832
+ if (typeof breadcrumb.data["response_content_length"] === "number") {
23833
+ entry.response_content_length = breadcrumb.data["response_content_length"];
23834
+ }
23835
+ networkRequests.push(entry);
23836
+ }
23837
+ }
23637
23838
  const latestFrontendException = selectLatestEnvelopeByType(envelopes, isFrontendExceptionEnvelope);
23638
23839
  const domContext = latestFrontendException?.payload.dom_context ?? null;
23639
23840
  if (routeChanges.length === 0 && clicks.length === 0 && formSubmissions.length === 0 && consoleLogs.length === 0 && networkRequests.length === 0 && exceptions.length === 0 && domContext === null) {
@@ -23783,7 +23984,7 @@ function buildBundle(input2) {
23783
23984
  const serviceRuntime = input2.incident.service_runtime ?? selectLatestEnvelope(sourceEnvelopes, (envelope) => envelope.event_type !== "probe_event")?.service.runtime ?? null;
23784
23985
  const serviceFramework = input2.incident.service_framework ?? selectLatestEnvelope(sourceEnvelopes, (envelope) => envelope.event_type !== "probe_event")?.service.framework ?? null;
23785
23986
  const customerVisible = frontendContext !== null;
23786
- const firstApplicationFrame = deriveFirstApplicationFrame(errorContext);
23987
+ const firstApplicationFrame = opaqueBrowserError ? null : deriveFirstApplicationFrame(errorContext);
23787
23988
  const summaryGuidance = buildSummaryGuidance({
23788
23989
  errorContext,
23789
23990
  requestContext,
@@ -24304,20 +24505,20 @@ function mergeSourceEvents(existingEvents, nextEvents) {
24304
24505
  }
24305
24506
  return [...merged.values()].sort(compareEventEnvelopes);
24306
24507
  }
24307
- function stableJson2(value) {
24508
+ function stableJson3(value) {
24308
24509
  if (value === null || typeof value !== "object") {
24309
24510
  return JSON.stringify(value);
24310
24511
  }
24311
24512
  if (Array.isArray(value)) {
24312
- return `[${value.map((entry) => stableJson2(entry)).join(",")}]`;
24513
+ return `[${value.map((entry) => stableJson3(entry)).join(",")}]`;
24313
24514
  }
24314
24515
  const record = value;
24315
24516
  const keys = Object.keys(record).sort();
24316
- return `{${keys.map((key) => `${JSON.stringify(key)}:${stableJson2(record[key])}`).join(",")}}`;
24517
+ return `{${keys.map((key) => `${JSON.stringify(key)}:${stableJson3(record[key])}`).join(",")}}`;
24317
24518
  }
24318
24519
  function buildRequestAnomalyFingerprint(input2) {
24319
24520
  return (0, import_node_crypto4.createHash)("sha256").update(
24320
- stableJson2({
24521
+ stableJson3({
24321
24522
  kind: "request_status_anomaly",
24322
24523
  project_id: input2.projectId,
24323
24524
  service_name: input2.serviceName,
@@ -28279,8 +28480,8 @@ var CLI_USAGE_LINES = [
28279
28480
  " debugbundle token member create --label <label> [--auth-file <path>] [--json]",
28280
28481
  " debugbundle token member revoke <token-id> [--auth-file <path>] [--json]",
28281
28482
  " debugbundle alert list --project-id <id> [--limit <n>] [--auth-file <path>] [--json]",
28282
- " debugbundle alert create --project-id <id> --channel <channel> --condition <condition> [--service-id <id>] [--severity-min <level>] --config-json <json> [--is-enabled <true|false>] [--auth-file <path>] [--json]",
28283
- " debugbundle alert update <alert-id> --project-id <id> [--service-id <id|null>] [--channel <channel>] [--condition <condition>] [--severity-min <level|null>] [--config-json <json|null>] [--is-enabled <true|false>] [--auth-file <path>] [--json]",
28483
+ " debugbundle alert create --project-id <id> --channel <channel> --condition <condition> [--service-id <id>] [--severity-min <level>] [--cooldown <seconds>] --config-json <json> [--is-enabled <true|false>] [--auth-file <path>] [--json]",
28484
+ " debugbundle alert update <alert-id> --project-id <id> [--service-id <id|null>] [--channel <channel>] [--condition <condition>] [--severity-min <level|null>] [--cooldown <seconds>] [--config-json <json|null>] [--is-enabled <true|false>] [--auth-file <path>] [--json]",
28284
28485
  " debugbundle alert delete <alert-id> --project-id <id> [--auth-file <path>] [--json]",
28285
28486
  " debugbundle slack list --project-id <id> [--auth-file <path>] [--json]",
28286
28487
  " debugbundle slack connect-url --project-id <id> [--return-to </projects/...>] [--auth-file <path>] [--json]",
@@ -28819,7 +29020,7 @@ function formatAlertTable(alerts) {
28819
29020
  return "No alerts found.";
28820
29021
  }
28821
29022
  return alerts.map(
28822
- (alert) => `${alert.alert_id} | ${alert.is_enabled ? "enabled" : "disabled"} | ${alert.condition_type} | ${alert.channel} | project=${alert.project_id}`
29023
+ (alert) => `${alert.alert_id} | ${alert.is_enabled ? "enabled" : "disabled"} | ${alert.condition_type} | ${alert.channel} | cooldown=${alert.cooldown_seconds}s | project=${alert.project_id}`
28823
29024
  ).join("\n");
28824
29025
  }
28825
29026
  async function listAlertsCommand(input2, api) {
@@ -28876,6 +29077,9 @@ async function createAlertCommand(input2, api) {
28876
29077
  if (input2.severityMin !== void 0) {
28877
29078
  requestInput.severityMin = input2.severityMin;
28878
29079
  }
29080
+ if (input2.cooldownSeconds !== void 0) {
29081
+ requestInput.cooldownSeconds = input2.cooldownSeconds;
29082
+ }
28879
29083
  if (input2.isEnabled !== void 0) {
28880
29084
  requestInput.isEnabled = input2.isEnabled;
28881
29085
  }
@@ -28906,6 +29110,9 @@ async function createAlertWithAuthCommand(input2, dependencies) {
28906
29110
  if (input2.severityMin !== void 0) {
28907
29111
  commandInput.severityMin = input2.severityMin;
28908
29112
  }
29113
+ if (input2.cooldownSeconds !== void 0) {
29114
+ commandInput.cooldownSeconds = input2.cooldownSeconds;
29115
+ }
28909
29116
  if (input2.isEnabled !== void 0) {
28910
29117
  commandInput.isEnabled = input2.isEnabled;
28911
29118
  }
@@ -28937,6 +29144,9 @@ async function updateAlertCommand(input2, api) {
28937
29144
  if (input2.severityMin !== void 0) {
28938
29145
  requestInput.severityMin = input2.severityMin;
28939
29146
  }
29147
+ if (input2.cooldownSeconds !== void 0) {
29148
+ requestInput.cooldownSeconds = input2.cooldownSeconds;
29149
+ }
28940
29150
  if (input2.config !== void 0) {
28941
29151
  requestInput.config = input2.config;
28942
29152
  }
@@ -28974,6 +29184,9 @@ async function updateAlertWithAuthCommand(input2, dependencies) {
28974
29184
  if (input2.severityMin !== void 0) {
28975
29185
  commandInput.severityMin = input2.severityMin;
28976
29186
  }
29187
+ if (input2.cooldownSeconds !== void 0) {
29188
+ commandInput.cooldownSeconds = input2.cooldownSeconds;
29189
+ }
28977
29190
  if (input2.config !== void 0) {
28978
29191
  commandInput.config = input2.config;
28979
29192
  }
@@ -33391,6 +33604,7 @@ async function handleAlertCommand(parsedArgv, dependencies) {
33391
33604
  "channel",
33392
33605
  "condition",
33393
33606
  "severity-min",
33607
+ "cooldown",
33394
33608
  "config-json",
33395
33609
  "is-enabled"
33396
33610
  ]);
@@ -33420,6 +33634,10 @@ async function handleAlertCommand(parsedArgv, dependencies) {
33420
33634
  if (severityMin !== void 0) {
33421
33635
  input2.severityMin = severityMin;
33422
33636
  }
33637
+ const cooldownSeconds = readIntegerOption(parsedArgv, "cooldown");
33638
+ if (cooldownSeconds !== void 0) {
33639
+ input2.cooldownSeconds = cooldownSeconds;
33640
+ }
33423
33641
  const config = readJsonOption(parsedArgv, "config-json");
33424
33642
  if (config === void 0 || typeof config !== "object" || config === null) {
33425
33643
  throw new CliInputError("Missing required option --config-json.");
@@ -33440,6 +33658,7 @@ async function handleAlertCommand(parsedArgv, dependencies) {
33440
33658
  "channel",
33441
33659
  "condition",
33442
33660
  "severity-min",
33661
+ "cooldown",
33443
33662
  "config-json",
33444
33663
  "is-enabled"
33445
33664
  ]);
@@ -33468,6 +33687,10 @@ async function handleAlertCommand(parsedArgv, dependencies) {
33468
33687
  if (severityMin !== void 0) {
33469
33688
  input2.severityMin = severityMin === "null" ? null : severityMin;
33470
33689
  }
33690
+ const cooldownSeconds = readIntegerOption(parsedArgv, "cooldown");
33691
+ if (cooldownSeconds !== void 0) {
33692
+ input2.cooldownSeconds = cooldownSeconds;
33693
+ }
33471
33694
  const config = readJsonOption(parsedArgv, "config-json");
33472
33695
  if (config !== void 0) {
33473
33696
  input2.config = config;
@@ -33476,7 +33699,7 @@ async function handleAlertCommand(parsedArgv, dependencies) {
33476
33699
  if (isEnabled !== void 0) {
33477
33700
  input2.isEnabled = isEnabled;
33478
33701
  }
33479
- if (input2.serviceId === void 0 && input2.channel === void 0 && input2.conditionType === void 0 && input2.severityMin === void 0 && input2.config === void 0 && input2.isEnabled === void 0) {
33702
+ if (input2.serviceId === void 0 && input2.channel === void 0 && input2.conditionType === void 0 && input2.severityMin === void 0 && input2.cooldownSeconds === void 0 && input2.config === void 0 && input2.isEnabled === void 0) {
33480
33703
  throw new CliInputError("At least one alert field must be provided.");
33481
33704
  }
33482
33705
  return await (dependencies.updateAlertCommand ?? updateAlertWithAuthCommand)(input2);
@@ -33734,7 +33957,7 @@ async function handleCaptureRuleCommand2(parsedArgv, dependencies) {
33734
33957
  // package.json
33735
33958
  var package_default = {
33736
33959
  name: "@debugbundle/cli",
33737
- version: "1.0.2",
33960
+ version: "1.0.3",
33738
33961
  private: false,
33739
33962
  description: "Command-line interface for DebugBundle",
33740
33963
  license: "AGPL-3.0-only",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@debugbundle/cli",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "private": false,
5
5
  "description": "Command-line interface for DebugBundle",
6
6
  "license": "AGPL-3.0-only",