@debugbundle/cli 1.1.1 → 1.2.0
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 +291 -40
- package/package.json +1 -1
package/dist/main.cjs
CHANGED
|
@@ -14486,25 +14486,74 @@ var CaptureProbeEventsSchema = external_exports.enum(CaptureProbeEventsValues);
|
|
|
14486
14486
|
var RequestSignalClassificationValues = ["incident_signal", "context_signal"];
|
|
14487
14487
|
var RequestSignalClassificationSchema = external_exports.enum(RequestSignalClassificationValues);
|
|
14488
14488
|
var RECOMMENDED_IMMEDIATE_CLIENT_ERROR_STATUSES = [401, 403, 409, 422];
|
|
14489
|
+
var HTTP_METHOD_VALUES = ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"];
|
|
14489
14490
|
var ImmediateClientErrorStatusSchema = external_exports.number().int().min(400).max(499);
|
|
14491
|
+
var HttpMethodSchema = external_exports.enum(HTTP_METHOD_VALUES);
|
|
14490
14492
|
function normalizeImmediateClientErrorStatuses(statuses) {
|
|
14491
14493
|
return Array.from(new Set(statuses)).sort((left, right) => left - right);
|
|
14492
14494
|
}
|
|
14493
14495
|
var ImmediateClientErrorStatusesSchema = external_exports.array(ImmediateClientErrorStatusSchema).max(12).transform((statuses) => normalizeImmediateClientErrorStatuses(statuses));
|
|
14496
|
+
function normalizePathPattern(value) {
|
|
14497
|
+
return value.trim().replace(/\/{2,}/g, "/");
|
|
14498
|
+
}
|
|
14499
|
+
function isValidPathPattern(value) {
|
|
14500
|
+
const normalized = normalizePathPattern(value);
|
|
14501
|
+
if (!normalized.startsWith("/") || normalized.includes("?") || normalized.includes("#")) {
|
|
14502
|
+
return false;
|
|
14503
|
+
}
|
|
14504
|
+
const wildcardIndex = normalized.indexOf("*");
|
|
14505
|
+
return wildcardIndex === -1 || wildcardIndex === normalized.length - 1;
|
|
14506
|
+
}
|
|
14507
|
+
function normalizeHttpMethods(methods) {
|
|
14508
|
+
if (methods === void 0 || methods.length === 0) {
|
|
14509
|
+
return [];
|
|
14510
|
+
}
|
|
14511
|
+
const normalized = methods.map((method) => method.toUpperCase()).filter(
|
|
14512
|
+
(method) => HTTP_METHOD_VALUES.includes(method)
|
|
14513
|
+
);
|
|
14514
|
+
return Array.from(new Set(normalized)).sort();
|
|
14515
|
+
}
|
|
14516
|
+
function normalizeImmediateClientErrorPathRules(rules) {
|
|
14517
|
+
const normalized = rules.map((rule) => ({
|
|
14518
|
+
status_code: rule.status_code,
|
|
14519
|
+
path_pattern: normalizePathPattern(rule.path_pattern),
|
|
14520
|
+
methods: normalizeHttpMethods(rule.methods)
|
|
14521
|
+
}));
|
|
14522
|
+
const deduped = /* @__PURE__ */ new Map();
|
|
14523
|
+
for (const rule of normalized) {
|
|
14524
|
+
deduped.set(`${rule.status_code}:${rule.path_pattern}:${rule.methods.join(",")}`, rule);
|
|
14525
|
+
}
|
|
14526
|
+
return Array.from(deduped.values()).sort((left, right) => {
|
|
14527
|
+
if (left.status_code !== right.status_code) return left.status_code - right.status_code;
|
|
14528
|
+
const pathComparison = left.path_pattern.localeCompare(right.path_pattern);
|
|
14529
|
+
if (pathComparison !== 0) return pathComparison;
|
|
14530
|
+
return left.methods.join(",").localeCompare(right.methods.join(","));
|
|
14531
|
+
});
|
|
14532
|
+
}
|
|
14533
|
+
var ImmediateClientErrorPathRuleSchema = external_exports.object({
|
|
14534
|
+
status_code: ImmediateClientErrorStatusSchema,
|
|
14535
|
+
path_pattern: external_exports.string().min(1).max(256).transform(normalizePathPattern).refine(isValidPathPattern, {
|
|
14536
|
+
message: "path_pattern must start with / and may only use a terminal * wildcard"
|
|
14537
|
+
}),
|
|
14538
|
+
methods: external_exports.array(HttpMethodSchema).max(7).optional().default([]).transform(normalizeHttpMethods)
|
|
14539
|
+
});
|
|
14540
|
+
var ImmediateClientErrorPathRulesSchema = external_exports.array(ImmediateClientErrorPathRuleSchema).max(25).transform((rules) => normalizeImmediateClientErrorPathRules(rules));
|
|
14494
14541
|
var ResolvedCapturePolicySchema = external_exports.object({
|
|
14495
14542
|
preset: CapturePresetSchema,
|
|
14496
14543
|
capture_logs: CaptureLogsSchema,
|
|
14497
14544
|
capture_request_events: CaptureRequestEventsSchema,
|
|
14498
14545
|
capture_breadcrumbs: CaptureBreadcrumbsSchema,
|
|
14499
14546
|
capture_probe_events: CaptureProbeEventsSchema,
|
|
14500
|
-
immediate_client_error_statuses: ImmediateClientErrorStatusesSchema
|
|
14547
|
+
immediate_client_error_statuses: ImmediateClientErrorStatusesSchema,
|
|
14548
|
+
immediate_client_error_path_rules: ImmediateClientErrorPathRulesSchema.default([])
|
|
14501
14549
|
});
|
|
14502
14550
|
var CapturePolicyOverridesSchema = external_exports.object({
|
|
14503
14551
|
capture_logs: CaptureLogsSchema.nullable(),
|
|
14504
14552
|
capture_request_events: CaptureRequestEventsSchema.nullable(),
|
|
14505
14553
|
capture_breadcrumbs: CaptureBreadcrumbsSchema.nullable(),
|
|
14506
14554
|
capture_probe_events: CaptureProbeEventsSchema.nullable(),
|
|
14507
|
-
immediate_client_error_statuses: ImmediateClientErrorStatusesSchema.nullable()
|
|
14555
|
+
immediate_client_error_statuses: ImmediateClientErrorStatusesSchema.nullable(),
|
|
14556
|
+
immediate_client_error_path_rules: ImmediateClientErrorPathRulesSchema.nullable().default(null)
|
|
14508
14557
|
});
|
|
14509
14558
|
var CapturePolicyResponseSchema = external_exports.object({
|
|
14510
14559
|
access_mode: external_exports.enum(["manage", "preview"]),
|
|
@@ -14519,6 +14568,7 @@ var CapturePolicySchema = external_exports.object({
|
|
|
14519
14568
|
capture_breadcrumbs: CaptureBreadcrumbsSchema.nullable(),
|
|
14520
14569
|
capture_probe_events: CaptureProbeEventsSchema.nullable(),
|
|
14521
14570
|
immediate_client_error_statuses: ImmediateClientErrorStatusesSchema.nullable(),
|
|
14571
|
+
immediate_client_error_path_rules: ImmediateClientErrorPathRulesSchema.nullable().default(null),
|
|
14522
14572
|
updated_at: external_exports.string().datetime()
|
|
14523
14573
|
});
|
|
14524
14574
|
var CapturePolicyUpdateSchema = external_exports.object({
|
|
@@ -14527,7 +14577,8 @@ var CapturePolicyUpdateSchema = external_exports.object({
|
|
|
14527
14577
|
capture_request_events: CaptureRequestEventsSchema.nullable().optional(),
|
|
14528
14578
|
capture_breadcrumbs: CaptureBreadcrumbsSchema.nullable().optional(),
|
|
14529
14579
|
capture_probe_events: CaptureProbeEventsSchema.nullable().optional(),
|
|
14530
|
-
immediate_client_error_statuses: ImmediateClientErrorStatusesSchema.nullable().optional()
|
|
14580
|
+
immediate_client_error_statuses: ImmediateClientErrorStatusesSchema.nullable().optional(),
|
|
14581
|
+
immediate_client_error_path_rules: ImmediateClientErrorPathRulesSchema.nullable().optional()
|
|
14531
14582
|
});
|
|
14532
14583
|
var PRESET_DEFAULTS = {
|
|
14533
14584
|
minimal: {
|
|
@@ -14535,30 +14586,69 @@ var PRESET_DEFAULTS = {
|
|
|
14535
14586
|
capture_request_events: "failures_only",
|
|
14536
14587
|
capture_breadcrumbs: "local_only",
|
|
14537
14588
|
capture_probe_events: "buffer_only",
|
|
14538
|
-
immediate_client_error_statuses: []
|
|
14589
|
+
immediate_client_error_statuses: [],
|
|
14590
|
+
immediate_client_error_path_rules: []
|
|
14539
14591
|
},
|
|
14540
14592
|
balanced: {
|
|
14541
14593
|
capture_logs: "warning",
|
|
14542
14594
|
capture_request_events: "failures_only",
|
|
14543
14595
|
capture_breadcrumbs: "exception_only",
|
|
14544
14596
|
capture_probe_events: "buffer_only",
|
|
14545
|
-
immediate_client_error_statuses: []
|
|
14597
|
+
immediate_client_error_statuses: [],
|
|
14598
|
+
immediate_client_error_path_rules: []
|
|
14546
14599
|
},
|
|
14547
14600
|
investigative: {
|
|
14548
14601
|
capture_logs: "info",
|
|
14549
14602
|
capture_request_events: "all",
|
|
14550
14603
|
capture_breadcrumbs: "standalone",
|
|
14551
14604
|
capture_probe_events: "standalone_when_activated",
|
|
14552
|
-
immediate_client_error_statuses: [...RECOMMENDED_IMMEDIATE_CLIENT_ERROR_STATUSES]
|
|
14605
|
+
immediate_client_error_statuses: [...RECOMMENDED_IMMEDIATE_CLIENT_ERROR_STATUSES],
|
|
14606
|
+
immediate_client_error_path_rules: []
|
|
14553
14607
|
}
|
|
14554
14608
|
};
|
|
14555
14609
|
var BALANCED_IMMEDIATE_REQUEST_STATUSES = /* @__PURE__ */ new Set([408, 423, 424, 425, 429]);
|
|
14556
14610
|
var INVESTIGATIVE_IMMEDIATE_REQUEST_STATUSES = /* @__PURE__ */ new Set([...BALANCED_IMMEDIATE_REQUEST_STATUSES, 409]);
|
|
14557
|
-
|
|
14558
|
-
|
|
14559
|
-
|
|
14611
|
+
function normalizeRequestPath(value) {
|
|
14612
|
+
if (typeof value !== "string") {
|
|
14613
|
+
return null;
|
|
14614
|
+
}
|
|
14615
|
+
const trimmed = value.trim();
|
|
14616
|
+
if (trimmed.length === 0) {
|
|
14617
|
+
return null;
|
|
14618
|
+
}
|
|
14619
|
+
const path = trimmed.startsWith("http://") || trimmed.startsWith("https://") ? (() => {
|
|
14620
|
+
try {
|
|
14621
|
+
return new URL(trimmed).pathname;
|
|
14622
|
+
} catch {
|
|
14623
|
+
return trimmed;
|
|
14624
|
+
}
|
|
14625
|
+
})() : trimmed;
|
|
14626
|
+
return (path.split(/[?#]/, 1)[0] ?? path).replace(/\/{2,}/g, "/");
|
|
14627
|
+
}
|
|
14628
|
+
function pathPatternMatches(rulePattern, requestPath) {
|
|
14629
|
+
const pattern = normalizePathPattern(rulePattern);
|
|
14630
|
+
if (!pattern.endsWith("*")) {
|
|
14631
|
+
return requestPath === pattern;
|
|
14632
|
+
}
|
|
14633
|
+
const prefix = pattern.slice(0, -1);
|
|
14634
|
+
return requestPath.startsWith(prefix);
|
|
14635
|
+
}
|
|
14636
|
+
function matchesImmediateClientErrorPathRule(input2) {
|
|
14637
|
+
const { responseStatus, immediateClientErrorPathRules = [] } = input2;
|
|
14638
|
+
if (responseStatus === null || !Number.isFinite(responseStatus) || immediateClientErrorPathRules.length === 0) {
|
|
14639
|
+
return false;
|
|
14640
|
+
}
|
|
14641
|
+
const requestPath = normalizeRequestPath(input2.requestPath);
|
|
14642
|
+
if (requestPath === null) {
|
|
14643
|
+
return false;
|
|
14644
|
+
}
|
|
14645
|
+
const httpMethod = typeof input2.httpMethod === "string" ? input2.httpMethod.toUpperCase() : null;
|
|
14646
|
+
return immediateClientErrorPathRules.some(
|
|
14647
|
+
(rule) => rule.status_code === responseStatus && (rule.methods.length === 0 || httpMethod !== null && rule.methods.includes(httpMethod)) && pathPatternMatches(rule.path_pattern, requestPath)
|
|
14648
|
+
);
|
|
14649
|
+
}
|
|
14560
14650
|
function classifyRequestStatus(input2) {
|
|
14561
|
-
const { responseStatus, capturePreset, immediateClientErrorStatuses = [] } = input2;
|
|
14651
|
+
const { responseStatus, capturePreset, immediateClientErrorStatuses = [], immediateClientErrorPathRules = [] } = input2;
|
|
14562
14652
|
if (responseStatus === null || !Number.isFinite(responseStatus)) {
|
|
14563
14653
|
return "context_signal";
|
|
14564
14654
|
}
|
|
@@ -14568,6 +14658,14 @@ function classifyRequestStatus(input2) {
|
|
|
14568
14658
|
if (immediateClientErrorStatuses.includes(responseStatus)) {
|
|
14569
14659
|
return "incident_signal";
|
|
14570
14660
|
}
|
|
14661
|
+
if (matchesImmediateClientErrorPathRule({
|
|
14662
|
+
responseStatus,
|
|
14663
|
+
requestPath: input2.requestPath,
|
|
14664
|
+
httpMethod: input2.httpMethod,
|
|
14665
|
+
immediateClientErrorPathRules
|
|
14666
|
+
})) {
|
|
14667
|
+
return "incident_signal";
|
|
14668
|
+
}
|
|
14571
14669
|
if (capturePreset === "investigative") {
|
|
14572
14670
|
return INVESTIGATIVE_IMMEDIATE_REQUEST_STATUSES.has(responseStatus) ? "incident_signal" : "context_signal";
|
|
14573
14671
|
}
|
|
@@ -14577,33 +14675,101 @@ function classifyRequestStatus(input2) {
|
|
|
14577
14675
|
return "context_signal";
|
|
14578
14676
|
}
|
|
14579
14677
|
function getRequestAnomalyThreshold(input2) {
|
|
14580
|
-
const { responseStatus
|
|
14678
|
+
const { responseStatus } = input2;
|
|
14581
14679
|
if (responseStatus === null || !Number.isFinite(responseStatus) || responseStatus < 400 || responseStatus >= 500) {
|
|
14582
14680
|
return null;
|
|
14583
14681
|
}
|
|
14584
|
-
|
|
14585
|
-
|
|
14682
|
+
return null;
|
|
14683
|
+
}
|
|
14684
|
+
|
|
14685
|
+
// ../../packages/shared-types/src/request-failure-noise.ts
|
|
14686
|
+
function isLowValueExternalProbeRequestFailure404(input2) {
|
|
14687
|
+
if (input2.responseStatus !== 404 || input2.httpMethod.toUpperCase() !== "GET") {
|
|
14688
|
+
return false;
|
|
14586
14689
|
}
|
|
14587
|
-
|
|
14588
|
-
|
|
14589
|
-
|
|
14590
|
-
|
|
14591
|
-
|
|
14690
|
+
const normalizedRoute = input2.routeTemplate.toLowerCase().replace(/\/+$/, "") || "/";
|
|
14691
|
+
const normalizedPath = normalizePath(input2.requestPath ?? input2.routeTemplate);
|
|
14692
|
+
const routesToCheck = /* @__PURE__ */ new Set([normalizedRoute, normalizedPath]);
|
|
14693
|
+
for (const route of routesToCheck) {
|
|
14694
|
+
if (isRouteOnlyExternalProbe(route)) {
|
|
14695
|
+
return true;
|
|
14696
|
+
}
|
|
14592
14697
|
}
|
|
14593
|
-
|
|
14594
|
-
|
|
14595
|
-
|
|
14596
|
-
|
|
14597
|
-
|
|
14698
|
+
return isDirectIpRequest(input2.headers ?? null) && [...routesToCheck].some(isGenericDirectIpProbeRoute);
|
|
14699
|
+
}
|
|
14700
|
+
function normalizePath(path) {
|
|
14701
|
+
const withoutQuery = path.split("?")[0] ?? path;
|
|
14702
|
+
return withoutQuery.toLowerCase().replace(/\/+$/, "") || "/";
|
|
14703
|
+
}
|
|
14704
|
+
function isRouteOnlyExternalProbe(normalizedRoute) {
|
|
14705
|
+
const exactRoutes = /* @__PURE__ */ new Set([
|
|
14706
|
+
"/.env",
|
|
14707
|
+
"/__debug__/render_panel",
|
|
14708
|
+
"/actuator",
|
|
14709
|
+
"/autodiscover/autodiscover.json",
|
|
14710
|
+
"/developmentserver/metadatauploader",
|
|
14711
|
+
"/cpanel",
|
|
14712
|
+
"/favicon.ico",
|
|
14713
|
+
"/geoserver/web",
|
|
14714
|
+
"/hnap1",
|
|
14715
|
+
"/logon/logonpoint/index.html",
|
|
14716
|
+
"/owa/auth/logon.aspx",
|
|
14717
|
+
"/robots.txt",
|
|
14718
|
+
"/rdweb/pages",
|
|
14719
|
+
"/web",
|
|
14720
|
+
"/webclient/login.xhtml",
|
|
14721
|
+
"/webconsole",
|
|
14722
|
+
"/webui",
|
|
14723
|
+
"/whm",
|
|
14724
|
+
"/wp-admin",
|
|
14725
|
+
"/wp-login.php",
|
|
14726
|
+
"/wsman",
|
|
14727
|
+
"/xmlrpc.php"
|
|
14728
|
+
]);
|
|
14729
|
+
if (exactRoutes.has(normalizedRoute)) {
|
|
14730
|
+
return true;
|
|
14598
14731
|
}
|
|
14599
|
-
|
|
14600
|
-
|
|
14601
|
-
|
|
14602
|
-
|
|
14603
|
-
|
|
14732
|
+
return normalizedRoute.includes("/.git/") || normalizedRoute.includes("/.svn/") || normalizedRoute.includes("/api_keys") || normalizedRoute.includes("/backup/api_keys") || normalizedRoute.includes("/phpmyadmin") || normalizedRoute.includes("/pma/") || normalizedRoute.includes("/vendor/phpunit/") || normalizedRoute.startsWith("/autodiscover/") || normalizedRoute.startsWith("/cgi-bin/") || normalizedRoute.startsWith("/ecp/") || normalizedRoute.endsWith("/.git/config") || normalizedRoute.endsWith("/composer.json") || normalizedRoute.endsWith("/composer.lock") || normalizedRoute.endsWith("/package-lock.json") || normalizedRoute.endsWith("/package.json") || normalizedRoute.endsWith("/server-status") || normalizedRoute.includes("wp-config") || normalizedRoute.startsWith("/owa/") || normalizedRoute.startsWith("/rdweb/") || normalizedRoute.startsWith("/vpn/") || normalizedRoute.startsWith("/wp-") || isSensitiveBackupFileProbe(normalizedRoute);
|
|
14733
|
+
}
|
|
14734
|
+
function isSensitiveBackupFileProbe(normalizedRoute) {
|
|
14735
|
+
if (!/\.(?:bak|backup|dump|old|orig|save|sql|swp|tar|tar\.gz|zip)$/.test(normalizedRoute)) {
|
|
14736
|
+
return false;
|
|
14737
|
+
}
|
|
14738
|
+
return /(?:^|\/|\.)(?:backup|config|database|db|dump|env|secret|site|www|wp-config)(?:\/|\.|_|-|$)/.test(normalizedRoute);
|
|
14739
|
+
}
|
|
14740
|
+
function isGenericDirectIpProbeRoute(normalizedRoute) {
|
|
14741
|
+
return [
|
|
14742
|
+
"/admin",
|
|
14743
|
+
"/administrator",
|
|
14744
|
+
"/login",
|
|
14745
|
+
"/logincheck",
|
|
14746
|
+
"/remote/logincheck"
|
|
14747
|
+
].includes(normalizedRoute);
|
|
14748
|
+
}
|
|
14749
|
+
function isDirectIpRequest(headers) {
|
|
14750
|
+
if (headers === null) {
|
|
14751
|
+
return false;
|
|
14752
|
+
}
|
|
14753
|
+
const host = readHeader(headers, "x-forwarded-host") ?? readHeader(headers, "host");
|
|
14754
|
+
if (host === null) {
|
|
14755
|
+
return false;
|
|
14756
|
+
}
|
|
14757
|
+
return isIpLikeHost(host);
|
|
14758
|
+
}
|
|
14759
|
+
function readHeader(headers, name) {
|
|
14760
|
+
const direct = headers[name] ?? headers[name.toLowerCase()];
|
|
14761
|
+
if (typeof direct === "string") {
|
|
14762
|
+
return direct;
|
|
14763
|
+
}
|
|
14764
|
+
if (Array.isArray(direct) && typeof direct[0] === "string") {
|
|
14765
|
+
return direct[0];
|
|
14604
14766
|
}
|
|
14605
14767
|
return null;
|
|
14606
14768
|
}
|
|
14769
|
+
function isIpLikeHost(value) {
|
|
14770
|
+
const host = value.trim().replace(/:\d+$/, "");
|
|
14771
|
+
return /^(?:\d{1,3}\.){3}\d{1,3}$/.test(host) || /^\[[0-9a-f:]+\]$/i.test(host) || host.includes(":") && /^[0-9a-f:]+$/i.test(host);
|
|
14772
|
+
}
|
|
14607
14773
|
|
|
14608
14774
|
// ../../packages/shared-types/src/capture-rules.ts
|
|
14609
14775
|
var CAPTURE_RULE_EVENT_TYPES = [
|
|
@@ -17542,7 +17708,7 @@ function getRequestResponseStatus(payload) {
|
|
|
17542
17708
|
const status = payload?.["response_status"];
|
|
17543
17709
|
return typeof status === "number" && Number.isFinite(status) ? status : null;
|
|
17544
17710
|
}
|
|
17545
|
-
function classifyEvent(eventType, logLevel, probeActivationId, payload, capturePreset = "minimal", immediateClientErrorStatuses = []) {
|
|
17711
|
+
function classifyEvent(eventType, logLevel, probeActivationId, payload, capturePreset = "minimal", immediateClientErrorStatuses = [], immediateClientErrorPathRules = []) {
|
|
17546
17712
|
switch (eventType) {
|
|
17547
17713
|
case "backend_exception":
|
|
17548
17714
|
case "frontend_exception":
|
|
@@ -17554,7 +17720,14 @@ function classifyEvent(eventType, logLevel, probeActivationId, payload, captureP
|
|
|
17554
17720
|
return "context_signal";
|
|
17555
17721
|
case "request_event": {
|
|
17556
17722
|
const responseStatus = getRequestResponseStatus(payload);
|
|
17557
|
-
return classifyRequestStatus({
|
|
17723
|
+
return classifyRequestStatus({
|
|
17724
|
+
responseStatus,
|
|
17725
|
+
requestPath: payload?.["path"],
|
|
17726
|
+
httpMethod: payload?.["method"],
|
|
17727
|
+
capturePreset,
|
|
17728
|
+
immediateClientErrorStatuses,
|
|
17729
|
+
immediateClientErrorPathRules
|
|
17730
|
+
});
|
|
17558
17731
|
}
|
|
17559
17732
|
case "frontend_breadcrumb":
|
|
17560
17733
|
case "deploy_metadata":
|
|
@@ -17892,6 +18065,7 @@ var STORAGE_BOOTSTRAP_STATEMENTS = [
|
|
|
17892
18065
|
capture_breadcrumbs text,
|
|
17893
18066
|
capture_probe_events text,
|
|
17894
18067
|
immediate_client_error_statuses jsonb,
|
|
18068
|
+
immediate_client_error_path_rules jsonb,
|
|
17895
18069
|
updated_at timestamptz NOT NULL DEFAULT now()
|
|
17896
18070
|
)
|
|
17897
18071
|
`,
|
|
@@ -19247,6 +19421,13 @@ var STORAGE_SCHEMA_MIGRATIONS = [
|
|
|
19247
19421
|
ON plan_cleanup_tasks (completed_at, next_attempt_at, created_at)
|
|
19248
19422
|
`
|
|
19249
19423
|
]
|
|
19424
|
+
}),
|
|
19425
|
+
defineStorageSchemaMigration({
|
|
19426
|
+
id: "202606080001_add_capture_policy_client_error_path_rules",
|
|
19427
|
+
description: "Add path-scoped client error incident promotion rules to capture policies.",
|
|
19428
|
+
statements: [
|
|
19429
|
+
"ALTER TABLE capture_policies ADD COLUMN IF NOT EXISTS immediate_client_error_path_rules jsonb"
|
|
19430
|
+
]
|
|
19250
19431
|
})
|
|
19251
19432
|
];
|
|
19252
19433
|
|
|
@@ -19998,7 +20179,7 @@ var ProjectMetricsSchema = external_exports.object({
|
|
|
19998
20179
|
monthly_raw_ingested_events: external_exports.number().int().nonnegative(),
|
|
19999
20180
|
retained_bundles: external_exports.number().int().nonnegative(),
|
|
20000
20181
|
monthly_alert_deliveries: external_exports.number().int().nonnegative()
|
|
20001
|
-
})
|
|
20182
|
+
});
|
|
20002
20183
|
var ProjectRecordSchema = external_exports.object({
|
|
20003
20184
|
project_id: external_exports.string(),
|
|
20004
20185
|
organization_id: external_exports.string(),
|
|
@@ -20015,13 +20196,13 @@ var ProjectRecordSchema = external_exports.object({
|
|
|
20015
20196
|
metrics: ProjectMetricsSchema,
|
|
20016
20197
|
created_at: external_exports.string(),
|
|
20017
20198
|
updated_at: external_exports.string()
|
|
20018
|
-
})
|
|
20199
|
+
});
|
|
20019
20200
|
var ProjectListResponseSchema = external_exports.object({
|
|
20020
20201
|
projects: external_exports.array(ProjectRecordSchema)
|
|
20021
|
-
})
|
|
20202
|
+
});
|
|
20022
20203
|
var ProjectCreateResponseSchema = external_exports.object({
|
|
20023
20204
|
project: ProjectRecordSchema
|
|
20024
|
-
})
|
|
20205
|
+
});
|
|
20025
20206
|
var DeletedProjectRecordSchema = external_exports.object({
|
|
20026
20207
|
project_id: external_exports.string(),
|
|
20027
20208
|
organization_id: external_exports.string(),
|
|
@@ -20037,10 +20218,10 @@ var DeletedProjectRecordSchema = external_exports.object({
|
|
|
20037
20218
|
organization_plan: external_exports.enum(["free", "solo", "team"]),
|
|
20038
20219
|
created_at: external_exports.string(),
|
|
20039
20220
|
updated_at: external_exports.string()
|
|
20040
|
-
})
|
|
20221
|
+
});
|
|
20041
20222
|
var ProjectDeleteResponseSchema = external_exports.object({
|
|
20042
20223
|
project: DeletedProjectRecordSchema
|
|
20043
|
-
})
|
|
20224
|
+
});
|
|
20044
20225
|
var ApiErrorResponseSchema2 = external_exports.object({
|
|
20045
20226
|
error: external_exports.string()
|
|
20046
20227
|
}).strict();
|
|
@@ -24809,6 +24990,15 @@ function collectRequestAnomalyAggregates(batches, capturePreset) {
|
|
|
24809
24990
|
if (threshold === null || responseStatus === null || method === null || routeTemplate === null) {
|
|
24810
24991
|
continue;
|
|
24811
24992
|
}
|
|
24993
|
+
if (isLowValueExternalProbeRequestFailure404({
|
|
24994
|
+
httpMethod: method,
|
|
24995
|
+
requestPath: event.payload.path,
|
|
24996
|
+
routeTemplate,
|
|
24997
|
+
responseStatus,
|
|
24998
|
+
headers: event.payload.headers
|
|
24999
|
+
})) {
|
|
25000
|
+
continue;
|
|
25001
|
+
}
|
|
24812
25002
|
const projectId = requireProjectId(event);
|
|
24813
25003
|
const incidentFingerprint = buildRequestAnomalyFingerprint({
|
|
24814
25004
|
projectId,
|
|
@@ -28938,7 +29128,7 @@ var CLI_USAGE_LINES = [
|
|
|
28938
29128
|
" 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]",
|
|
28939
29129
|
" debugbundle weekly-report delete <channel-id> [--auth-file <path>] [--json]",
|
|
28940
29130
|
" debugbundle capture-policy get --project <id> [--auth-file <path>] [--json]",
|
|
28941
|
-
" 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]",
|
|
29131
|
+
" 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,...>] [--client-error-path-rule <404=/path/*@GET,POST>] [--client-error-path-rules-json <json|null>] [--auth-file <path>] [--json]",
|
|
28942
29132
|
" debugbundle capture-rule list --project-id <id> [--auth-file <path>] [--json]",
|
|
28943
29133
|
" debugbundle capture-rule suggest <incident-id> [--auth-file <path>] [--json]",
|
|
28944
29134
|
" debugbundle capture-rule create-from-suggestion <incident-id> --suggestion-id <id> [--name <name>] [--description <text>] [--enabled <true|false>] [--expires-at <ISO8601>] [--auth-file <path>] [--json]",
|
|
@@ -31918,6 +32108,18 @@ function statusesEqual(left, right) {
|
|
|
31918
32108
|
function formatStatusList(statuses) {
|
|
31919
32109
|
return statuses.length === 0 ? "none" : statuses.join(", ");
|
|
31920
32110
|
}
|
|
32111
|
+
function formatClientErrorPathRules(response) {
|
|
32112
|
+
const rawOverride = response.overrides.immediate_client_error_path_rules ?? null;
|
|
32113
|
+
const rules = rawOverride ?? response.policy.immediate_client_error_path_rules ?? [];
|
|
32114
|
+
if (rules.length === 0) {
|
|
32115
|
+
return rawOverride === null ? "preset default (none)" : "none (explicit)";
|
|
32116
|
+
}
|
|
32117
|
+
const formatted = rules.map((rule) => {
|
|
32118
|
+
const methods = rule.methods.length === 0 ? "" : `@${rule.methods.join(",")}`;
|
|
32119
|
+
return `${rule.status_code}=${rule.path_pattern}${methods}`;
|
|
32120
|
+
});
|
|
32121
|
+
return `${rawOverride === null ? "preset default" : "custom"} (${formatted.join("; ")})`;
|
|
32122
|
+
}
|
|
31921
32123
|
function formatClientErrorIncidents(response) {
|
|
31922
32124
|
const rawOverride = response.overrides.immediate_client_error_statuses;
|
|
31923
32125
|
if (rawOverride === null) {
|
|
@@ -31939,7 +32141,8 @@ function formatPolicy(response) {
|
|
|
31939
32141
|
`capture_request_events: ${policy.capture_request_events}`,
|
|
31940
32142
|
`capture_breadcrumbs: ${policy.capture_breadcrumbs}`,
|
|
31941
32143
|
`capture_probe_events: ${policy.capture_probe_events}`,
|
|
31942
|
-
`client_error_incidents: ${formatClientErrorIncidents(response)}
|
|
32144
|
+
`client_error_incidents: ${formatClientErrorIncidents(response)}`,
|
|
32145
|
+
`client_error_path_rules: ${formatClientErrorPathRules(response)}`
|
|
31943
32146
|
].join("\n");
|
|
31944
32147
|
}
|
|
31945
32148
|
async function getCapturePolicyCommand(input2, api) {
|
|
@@ -32712,6 +32915,31 @@ async function handleCapturePolicyCommand(parsedArgv, dependencies) {
|
|
|
32712
32915
|
}
|
|
32713
32916
|
return normalized;
|
|
32714
32917
|
}
|
|
32918
|
+
function parseClientErrorPathRuleOption(value) {
|
|
32919
|
+
const separatorIndex = value.indexOf("=");
|
|
32920
|
+
if (separatorIndex <= 0 || separatorIndex === value.length - 1) {
|
|
32921
|
+
throw new CliInputError("Invalid value for --client-error-path-rule.");
|
|
32922
|
+
}
|
|
32923
|
+
const status = Number(value.slice(0, separatorIndex));
|
|
32924
|
+
if (!Number.isInteger(status) || status < 400 || status > 499) {
|
|
32925
|
+
throw new CliInputError("Invalid value for --client-error-path-rule.");
|
|
32926
|
+
}
|
|
32927
|
+
const ruleValue = value.slice(separatorIndex + 1);
|
|
32928
|
+
const methodSeparatorIndex = ruleValue.lastIndexOf("@");
|
|
32929
|
+
const pathPattern = methodSeparatorIndex === -1 ? ruleValue : ruleValue.slice(0, methodSeparatorIndex);
|
|
32930
|
+
const methods = methodSeparatorIndex === -1 ? [] : ruleValue.slice(methodSeparatorIndex + 1).split(",").map((method) => method.trim().toUpperCase()).filter((method) => method.length > 0);
|
|
32931
|
+
const parsed = ImmediateClientErrorPathRulesSchema.safeParse([
|
|
32932
|
+
{
|
|
32933
|
+
status_code: status,
|
|
32934
|
+
path_pattern: pathPattern,
|
|
32935
|
+
methods
|
|
32936
|
+
}
|
|
32937
|
+
]);
|
|
32938
|
+
if (!parsed.success || parsed.data[0] === void 0) {
|
|
32939
|
+
throw new CliInputError("Invalid value for --client-error-path-rule.");
|
|
32940
|
+
}
|
|
32941
|
+
return parsed.data[0];
|
|
32942
|
+
}
|
|
32715
32943
|
const action = requirePositional(parsedArgv, 1, "action");
|
|
32716
32944
|
if (action === "get") {
|
|
32717
32945
|
expectNoUnknownOptions(parsedArgv, ["auth-file", "json", "project"]);
|
|
@@ -32732,7 +32960,9 @@ async function handleCapturePolicyCommand(parsedArgv, dependencies) {
|
|
|
32732
32960
|
"preset",
|
|
32733
32961
|
"override",
|
|
32734
32962
|
"client-error-incidents",
|
|
32735
|
-
"client-error-statuses"
|
|
32963
|
+
"client-error-statuses",
|
|
32964
|
+
"client-error-path-rule",
|
|
32965
|
+
"client-error-path-rules-json"
|
|
32736
32966
|
]);
|
|
32737
32967
|
ensureNoExtraPositionals(parsedArgv, 2);
|
|
32738
32968
|
const projectId = readStringOption(parsedArgv, "project");
|
|
@@ -32759,9 +32989,14 @@ async function handleCapturePolicyCommand(parsedArgv, dependencies) {
|
|
|
32759
32989
|
}
|
|
32760
32990
|
const clientErrorIncidents = readStringOption(parsedArgv, "client-error-incidents");
|
|
32761
32991
|
const clientErrorStatuses = readStringOption(parsedArgv, "client-error-statuses");
|
|
32992
|
+
const clientErrorPathRuleOptions = readStringListOption(parsedArgv, "client-error-path-rule") ?? [];
|
|
32993
|
+
const clientErrorPathRulesJson = readJsonOption(parsedArgv, "client-error-path-rules-json");
|
|
32762
32994
|
if (clientErrorStatuses !== void 0 && clientErrorIncidents !== "custom") {
|
|
32763
32995
|
throw new CliInputError("Use --client-error-statuses only with --client-error-incidents custom.");
|
|
32764
32996
|
}
|
|
32997
|
+
if (clientErrorPathRuleOptions.length > 0 && clientErrorPathRulesJson !== void 0) {
|
|
32998
|
+
throw new CliInputError("Use either --client-error-path-rule or --client-error-path-rules-json, not both.");
|
|
32999
|
+
}
|
|
32765
33000
|
if (clientErrorIncidents !== void 0) {
|
|
32766
33001
|
switch (clientErrorIncidents) {
|
|
32767
33002
|
case "preset-default":
|
|
@@ -32783,6 +33018,22 @@ async function handleCapturePolicyCommand(parsedArgv, dependencies) {
|
|
|
32783
33018
|
throw new CliInputError("Invalid value for --client-error-incidents.");
|
|
32784
33019
|
}
|
|
32785
33020
|
}
|
|
33021
|
+
if (clientErrorPathRulesJson !== void 0) {
|
|
33022
|
+
if (clientErrorPathRulesJson === null) {
|
|
33023
|
+
update.immediate_client_error_path_rules = null;
|
|
33024
|
+
} else {
|
|
33025
|
+
const parsed = ImmediateClientErrorPathRulesSchema.safeParse(clientErrorPathRulesJson);
|
|
33026
|
+
if (!parsed.success) {
|
|
33027
|
+
throw new CliInputError("Invalid value for --client-error-path-rules-json.");
|
|
33028
|
+
}
|
|
33029
|
+
update.immediate_client_error_path_rules = parsed.data;
|
|
33030
|
+
}
|
|
33031
|
+
}
|
|
33032
|
+
if (clientErrorPathRuleOptions.length > 0) {
|
|
33033
|
+
update.immediate_client_error_path_rules = ImmediateClientErrorPathRulesSchema.parse(
|
|
33034
|
+
clientErrorPathRuleOptions.map(parseClientErrorPathRuleOption)
|
|
33035
|
+
);
|
|
33036
|
+
}
|
|
32786
33037
|
if (Object.keys(update).length === 0) {
|
|
32787
33038
|
throw new CliInputError("At least one capture policy field must be provided.");
|
|
32788
33039
|
}
|
|
@@ -34488,7 +34739,7 @@ async function handleCaptureRuleCommand2(parsedArgv, dependencies) {
|
|
|
34488
34739
|
// package.json
|
|
34489
34740
|
var package_default = {
|
|
34490
34741
|
name: "@debugbundle/cli",
|
|
34491
|
-
version: "1.
|
|
34742
|
+
version: "1.2.0",
|
|
34492
34743
|
private: false,
|
|
34493
34744
|
description: "Command-line interface for DebugBundle",
|
|
34494
34745
|
license: "AGPL-3.0-only",
|