@debugbundle/cli 0.1.4 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/main.cjs +155 -25
  2. package/package.json +1 -1
package/dist/main.cjs CHANGED
@@ -14485,6 +14485,31 @@ var CaptureProbeEventsValues = ["buffer_only", "standalone_when_activated"];
14485
14485
  var CaptureProbeEventsSchema = external_exports.enum(CaptureProbeEventsValues);
14486
14486
  var RequestSignalClassificationValues = ["incident_signal", "context_signal"];
14487
14487
  var RequestSignalClassificationSchema = external_exports.enum(RequestSignalClassificationValues);
14488
+ var RECOMMENDED_IMMEDIATE_CLIENT_ERROR_STATUSES = [401, 403, 409, 422];
14489
+ var ImmediateClientErrorStatusSchema = external_exports.number().int().min(400).max(499);
14490
+ function normalizeImmediateClientErrorStatuses(statuses) {
14491
+ return Array.from(new Set(statuses)).sort((left, right) => left - right);
14492
+ }
14493
+ var ImmediateClientErrorStatusesSchema = external_exports.array(ImmediateClientErrorStatusSchema).max(12).transform((statuses) => normalizeImmediateClientErrorStatuses(statuses));
14494
+ var ResolvedCapturePolicySchema = external_exports.object({
14495
+ preset: CapturePresetSchema,
14496
+ capture_logs: CaptureLogsSchema,
14497
+ capture_request_events: CaptureRequestEventsSchema,
14498
+ capture_breadcrumbs: CaptureBreadcrumbsSchema,
14499
+ capture_probe_events: CaptureProbeEventsSchema,
14500
+ immediate_client_error_statuses: ImmediateClientErrorStatusesSchema
14501
+ });
14502
+ var CapturePolicyOverridesSchema = external_exports.object({
14503
+ capture_logs: CaptureLogsSchema.nullable(),
14504
+ capture_request_events: CaptureRequestEventsSchema.nullable(),
14505
+ capture_breadcrumbs: CaptureBreadcrumbsSchema.nullable(),
14506
+ capture_probe_events: CaptureProbeEventsSchema.nullable(),
14507
+ immediate_client_error_statuses: ImmediateClientErrorStatusesSchema.nullable()
14508
+ });
14509
+ var CapturePolicyResponseSchema = external_exports.object({
14510
+ policy: ResolvedCapturePolicySchema,
14511
+ overrides: CapturePolicyOverridesSchema
14512
+ });
14488
14513
  var CapturePolicySchema = external_exports.object({
14489
14514
  project_id: external_exports.string().uuid(),
14490
14515
  preset: CapturePresetSchema,
@@ -14492,6 +14517,7 @@ var CapturePolicySchema = external_exports.object({
14492
14517
  capture_request_events: CaptureRequestEventsSchema.nullable(),
14493
14518
  capture_breadcrumbs: CaptureBreadcrumbsSchema.nullable(),
14494
14519
  capture_probe_events: CaptureProbeEventsSchema.nullable(),
14520
+ immediate_client_error_statuses: ImmediateClientErrorStatusesSchema.nullable(),
14495
14521
  updated_at: external_exports.string().datetime()
14496
14522
  });
14497
14523
  var CapturePolicyUpdateSchema = external_exports.object({
@@ -14499,21 +14525,48 @@ var CapturePolicyUpdateSchema = external_exports.object({
14499
14525
  capture_logs: CaptureLogsSchema.nullable().optional(),
14500
14526
  capture_request_events: CaptureRequestEventsSchema.nullable().optional(),
14501
14527
  capture_breadcrumbs: CaptureBreadcrumbsSchema.nullable().optional(),
14502
- capture_probe_events: CaptureProbeEventsSchema.nullable().optional()
14528
+ capture_probe_events: CaptureProbeEventsSchema.nullable().optional(),
14529
+ immediate_client_error_statuses: ImmediateClientErrorStatusesSchema.nullable().optional()
14503
14530
  });
14531
+ var PRESET_DEFAULTS = {
14532
+ minimal: {
14533
+ capture_logs: "error",
14534
+ capture_request_events: "failures_only",
14535
+ capture_breadcrumbs: "local_only",
14536
+ capture_probe_events: "buffer_only",
14537
+ immediate_client_error_statuses: []
14538
+ },
14539
+ balanced: {
14540
+ capture_logs: "warning",
14541
+ capture_request_events: "failures_only",
14542
+ capture_breadcrumbs: "exception_only",
14543
+ capture_probe_events: "buffer_only",
14544
+ immediate_client_error_statuses: []
14545
+ },
14546
+ investigative: {
14547
+ capture_logs: "info",
14548
+ capture_request_events: "all",
14549
+ capture_breadcrumbs: "standalone",
14550
+ capture_probe_events: "standalone_when_activated",
14551
+ immediate_client_error_statuses: [...RECOMMENDED_IMMEDIATE_CLIENT_ERROR_STATUSES]
14552
+ }
14553
+ };
14504
14554
  var BALANCED_IMMEDIATE_REQUEST_STATUSES = /* @__PURE__ */ new Set([408, 423, 424, 425, 429]);
14505
14555
  var INVESTIGATIVE_IMMEDIATE_REQUEST_STATUSES = /* @__PURE__ */ new Set([...BALANCED_IMMEDIATE_REQUEST_STATUSES, 409]);
14506
14556
  var BALANCED_STANDARD_ANOMALY_STATUSES = /* @__PURE__ */ new Set([401, 403, 404, 409, 422]);
14507
14557
  var BALANCED_HIGH_VOLUME_ANOMALY_STATUSES = /* @__PURE__ */ new Set([400, 410]);
14508
14558
  var INVESTIGATIVE_ANOMALY_STATUSES = /* @__PURE__ */ new Set([...BALANCED_STANDARD_ANOMALY_STATUSES, ...BALANCED_HIGH_VOLUME_ANOMALY_STATUSES]);
14509
14559
  function classifyRequestStatus(input) {
14510
- const { responseStatus, capturePreset } = input;
14560
+ const { responseStatus, capturePreset, immediateClientErrorStatuses = [] } = input;
14511
14561
  if (responseStatus === null || !Number.isFinite(responseStatus)) {
14512
14562
  return "context_signal";
14513
14563
  }
14514
14564
  if (responseStatus >= 500) {
14515
14565
  return "incident_signal";
14516
14566
  }
14567
+ if (immediateClientErrorStatuses.includes(responseStatus)) {
14568
+ return "incident_signal";
14569
+ }
14517
14570
  if (capturePreset === "investigative") {
14518
14571
  return INVESTIGATIVE_IMMEDIATE_REQUEST_STATUSES.has(responseStatus) ? "incident_signal" : "context_signal";
14519
14572
  }
@@ -16565,7 +16618,7 @@ function getRequestResponseStatus(payload) {
16565
16618
  const status = payload?.["response_status"];
16566
16619
  return typeof status === "number" && Number.isFinite(status) ? status : null;
16567
16620
  }
16568
- function classifyEvent(eventType, logLevel, probeActivationId, payload, capturePreset = "minimal") {
16621
+ function classifyEvent(eventType, logLevel, probeActivationId, payload, capturePreset = "minimal", immediateClientErrorStatuses = []) {
16569
16622
  switch (eventType) {
16570
16623
  case "backend_exception":
16571
16624
  case "frontend_exception":
@@ -16577,7 +16630,7 @@ function classifyEvent(eventType, logLevel, probeActivationId, payload, captureP
16577
16630
  return "context_signal";
16578
16631
  case "request_event": {
16579
16632
  const responseStatus = getRequestResponseStatus(payload);
16580
- return classifyRequestStatus({ responseStatus, capturePreset });
16633
+ return classifyRequestStatus({ responseStatus, capturePreset, immediateClientErrorStatuses });
16581
16634
  }
16582
16635
  case "frontend_breadcrumb":
16583
16636
  case "deploy_metadata":
@@ -16680,6 +16733,13 @@ var STORAGE_SCHEMA_MIGRATIONS = [
16680
16733
  ON slack_destinations (organization_id, is_active, created_at)
16681
16734
  `
16682
16735
  ]
16736
+ }),
16737
+ defineStorageSchemaMigration({
16738
+ id: "202605140001_add_capture_policy_immediate_client_error_statuses",
16739
+ description: "Add nullable immediate client error status overrides to capture policies.",
16740
+ statements: [
16741
+ "ALTER TABLE capture_policies ADD COLUMN IF NOT EXISTS immediate_client_error_statuses jsonb"
16742
+ ]
16683
16743
  })
16684
16744
  ];
16685
16745
 
@@ -25275,7 +25335,7 @@ var CLI_USAGE_LINES = [
25275
25335
  " debugbundle weekly-report update <channel-id> [--day-of-week <day>] [--hour-of-day <0-23>] [--timezone <iana>] [--config-json <json>] [--is-enabled <true|false>] [--auth-file <path>] [--json]",
25276
25336
  " debugbundle weekly-report delete <channel-id> [--auth-file <path>] [--json]",
25277
25337
  " debugbundle capture-policy get --project <id> [--auth-file <path>] [--json]",
25278
- " debugbundle capture-policy set --project <id> [--preset <minimal|balanced|investigative>] [--override <key=value>] [--auth-file <path>] [--json]",
25338
+ " debugbundle capture-policy set --project <id> [--preset <minimal|balanced|investigative>] [--override <key=value>] [--client-error-incidents <preset-default|none|recommended|custom>] [--client-error-statuses <400,401,...>] [--auth-file <path>] [--json]",
25279
25339
  " debugbundle probe activate <project-id> --label-pattern <pattern> [--service <name>] [--environment <name>] [--ttl-seconds <n>] [--trigger-ttl-seconds <n>] [--auth-file <path>] [--json]",
25280
25340
  " debugbundle probe list <project-id> [--auth-file <path>] [--json]",
25281
25341
  " debugbundle probe deactivate <project-id> <activation-id> [--auth-file <path>] [--json]",
@@ -25942,16 +26002,6 @@ async function deleteAlertWithAuthCommand(input, dependencies) {
25942
26002
  }
25943
26003
 
25944
26004
  // src/capture-policy-commands.ts
25945
- var ResolvedCapturePolicySchema = external_exports.object({
25946
- preset: CapturePresetSchema,
25947
- capture_logs: CaptureLogsSchema,
25948
- capture_request_events: CaptureRequestEventsSchema,
25949
- capture_breadcrumbs: CaptureBreadcrumbsSchema,
25950
- capture_probe_events: CaptureProbeEventsSchema
25951
- });
25952
- var CapturePolicyResponseSchema = external_exports.object({
25953
- policy: ResolvedCapturePolicySchema
25954
- });
25955
26005
  var CapturePolicyApiError = class extends Error {
25956
26006
  status;
25957
26007
  constructor(status, message) {
@@ -25981,7 +26031,7 @@ function createCapturePolicyApi(httpClient) {
25981
26031
  if (!parsed.success) {
25982
26032
  throw new CapturePolicyApiError(500, "Invalid capture policy response.");
25983
26033
  }
25984
- return parsed.data.policy;
26034
+ return parsed.data;
25985
26035
  },
25986
26036
  async updateCapturePolicy(input) {
25987
26037
  const response = await httpClient.request({
@@ -25997,7 +26047,7 @@ function createCapturePolicyApi(httpClient) {
25997
26047
  if (!parsed.success) {
25998
26048
  throw new CapturePolicyApiError(500, "Invalid capture policy response.");
25999
26049
  }
26000
- return parsed.data.policy;
26050
+ return parsed.data;
26001
26051
  }
26002
26052
  };
26003
26053
  }
@@ -26016,24 +26066,48 @@ function mapErrorToExitCode5(error) {
26016
26066
  }
26017
26067
  return 1;
26018
26068
  }
26019
- function formatPolicy(policy) {
26069
+ function statusesEqual(left, right) {
26070
+ if (left.length !== right.length) {
26071
+ return false;
26072
+ }
26073
+ return left.every((value, index) => value === right[index]);
26074
+ }
26075
+ function formatStatusList(statuses) {
26076
+ return statuses.length === 0 ? "none" : statuses.join(", ");
26077
+ }
26078
+ function formatClientErrorIncidents(response) {
26079
+ const rawOverride = response.overrides.immediate_client_error_statuses;
26080
+ if (rawOverride === null) {
26081
+ return `preset default (${formatStatusList(response.policy.immediate_client_error_statuses)})`;
26082
+ }
26083
+ if (rawOverride.length === 0) {
26084
+ return "none (explicit)";
26085
+ }
26086
+ if (statusesEqual(rawOverride, RECOMMENDED_IMMEDIATE_CLIENT_ERROR_STATUSES)) {
26087
+ return `recommended (${formatStatusList(rawOverride)})`;
26088
+ }
26089
+ return `custom (${formatStatusList(rawOverride)})`;
26090
+ }
26091
+ function formatPolicy(response) {
26092
+ const policy = response.policy;
26020
26093
  return [
26021
26094
  `preset: ${policy.preset}`,
26022
26095
  `capture_logs: ${policy.capture_logs}`,
26023
26096
  `capture_request_events: ${policy.capture_request_events}`,
26024
26097
  `capture_breadcrumbs: ${policy.capture_breadcrumbs}`,
26025
- `capture_probe_events: ${policy.capture_probe_events}`
26098
+ `capture_probe_events: ${policy.capture_probe_events}`,
26099
+ `client_error_incidents: ${formatClientErrorIncidents(response)}`
26026
26100
  ].join("\n");
26027
26101
  }
26028
26102
  async function getCapturePolicyCommand(input, api) {
26029
26103
  try {
26030
- const policy = await api.getCapturePolicy({
26104
+ const response = await api.getCapturePolicy({
26031
26105
  bearerToken: input.bearerToken,
26032
26106
  projectId: input.projectId
26033
26107
  });
26034
26108
  return {
26035
26109
  exitCode: 0,
26036
- output: input.json ? JSON.stringify({ policy }) : formatPolicy(policy)
26110
+ output: input.json ? JSON.stringify(response) : formatPolicy(response)
26037
26111
  };
26038
26112
  } catch (error) {
26039
26113
  return {
@@ -26051,15 +26125,15 @@ async function setCapturePolicyCommand(input, api) {
26051
26125
  output: "Invalid capture policy update."
26052
26126
  };
26053
26127
  }
26054
- const policy = await api.updateCapturePolicy({
26128
+ const response = await api.updateCapturePolicy({
26055
26129
  bearerToken: input.bearerToken,
26056
26130
  projectId: input.projectId,
26057
26131
  update: parsedUpdate.data
26058
26132
  });
26059
26133
  return {
26060
26134
  exitCode: 0,
26061
- output: input.json ? JSON.stringify({ policy }) : `Capture policy updated.
26062
- ${formatPolicy(policy)}`
26135
+ output: input.json ? JSON.stringify(response) : `Capture policy updated.
26136
+ ${formatPolicy(response)}`
26063
26137
  };
26064
26138
  } catch (error) {
26065
26139
  return {
@@ -28568,6 +28642,28 @@ async function handleTokenCommand(parsedArgv, dependencies) {
28568
28642
  throw new CliInputError("Unknown token command.");
28569
28643
  }
28570
28644
  async function handleCapturePolicyCommand(parsedArgv, dependencies) {
28645
+ function parseClientErrorStatusesOption(value) {
28646
+ const parts = value.split(",").map((part) => part.trim()).filter((part) => part.length > 0);
28647
+ if (parts.length === 0) {
28648
+ throw new CliInputError("Invalid value for --client-error-statuses.");
28649
+ }
28650
+ const statuses = [];
28651
+ for (const part of parts) {
28652
+ if (!/^\d+$/.test(part)) {
28653
+ throw new CliInputError("Invalid value for --client-error-statuses.");
28654
+ }
28655
+ const status = Number(part);
28656
+ if (!Number.isInteger(status) || status < 400 || status > 499) {
28657
+ throw new CliInputError("Invalid value for --client-error-statuses.");
28658
+ }
28659
+ statuses.push(status);
28660
+ }
28661
+ const normalized = Array.from(new Set(statuses)).sort((left, right) => left - right);
28662
+ if (normalized.length > 12) {
28663
+ throw new CliInputError("Invalid value for --client-error-statuses.");
28664
+ }
28665
+ return normalized;
28666
+ }
28571
28667
  const action = requirePositional(parsedArgv, 1, "action");
28572
28668
  if (action === "get") {
28573
28669
  expectNoUnknownOptions(parsedArgv, ["auth-file", "json", "project"]);
@@ -28581,7 +28677,15 @@ async function handleCapturePolicyCommand(parsedArgv, dependencies) {
28581
28677
  );
28582
28678
  }
28583
28679
  if (action === "set") {
28584
- expectNoUnknownOptions(parsedArgv, ["auth-file", "json", "project", "preset", "override"]);
28680
+ expectNoUnknownOptions(parsedArgv, [
28681
+ "auth-file",
28682
+ "json",
28683
+ "project",
28684
+ "preset",
28685
+ "override",
28686
+ "client-error-incidents",
28687
+ "client-error-statuses"
28688
+ ]);
28585
28689
  ensureNoExtraPositionals(parsedArgv, 2);
28586
28690
  const projectId = readStringOption(parsedArgv, "project");
28587
28691
  if (projectId === void 0) {
@@ -28605,6 +28709,32 @@ async function handleCapturePolicyCommand(parsedArgv, dependencies) {
28605
28709
  }
28606
28710
  update[key] = rawValue === "null" ? null : rawValue;
28607
28711
  }
28712
+ const clientErrorIncidents = readStringOption(parsedArgv, "client-error-incidents");
28713
+ const clientErrorStatuses = readStringOption(parsedArgv, "client-error-statuses");
28714
+ if (clientErrorStatuses !== void 0 && clientErrorIncidents !== "custom") {
28715
+ throw new CliInputError("Use --client-error-statuses only with --client-error-incidents custom.");
28716
+ }
28717
+ if (clientErrorIncidents !== void 0) {
28718
+ switch (clientErrorIncidents) {
28719
+ case "preset-default":
28720
+ update.immediate_client_error_statuses = null;
28721
+ break;
28722
+ case "none":
28723
+ update.immediate_client_error_statuses = [];
28724
+ break;
28725
+ case "recommended":
28726
+ update.immediate_client_error_statuses = [...RECOMMENDED_IMMEDIATE_CLIENT_ERROR_STATUSES];
28727
+ break;
28728
+ case "custom":
28729
+ if (clientErrorStatuses === void 0) {
28730
+ throw new CliInputError("Missing required option --client-error-statuses.");
28731
+ }
28732
+ update.immediate_client_error_statuses = parseClientErrorStatusesOption(clientErrorStatuses);
28733
+ break;
28734
+ default:
28735
+ throw new CliInputError("Invalid value for --client-error-incidents.");
28736
+ }
28737
+ }
28608
28738
  if (Object.keys(update).length === 0) {
28609
28739
  throw new CliInputError("At least one capture policy field must be provided.");
28610
28740
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@debugbundle/cli",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "private": false,
5
5
  "description": "Command-line interface for DebugBundle",
6
6
  "license": "AGPL-3.0-only",