@belvador/mcp 0.1.0 → 0.3.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/README.md +4 -0
- package/dist/cli.js +2186 -837
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -104,6 +104,7 @@ var API_ERROR_STATUS = {
|
|
|
104
104
|
APPROVAL_EXPIRED: 410,
|
|
105
105
|
APPROVAL_REJECTED: 403,
|
|
106
106
|
APPROVAL_PARAMS_MISMATCH: 409,
|
|
107
|
+
APPROVAL_OUTCOME_UNKNOWN: 409,
|
|
107
108
|
IDEMPOTENCY_KEY_REUSED: 422,
|
|
108
109
|
IDEMPOTENCY_IN_PROGRESS: 409,
|
|
109
110
|
PRECONDITION_REQUIRED: 428,
|
|
@@ -177,7 +178,7 @@ function cleanUntrustedText(raw, maxBytes = MCP_LIMITS.untrustedStringMaxBytes)
|
|
|
177
178
|
const { text, cut } = cutUtf8(escaped, maxBytes);
|
|
178
179
|
return { text, cut, suspicious };
|
|
179
180
|
}
|
|
180
|
-
var MCP_TOOLS_VERSION =
|
|
181
|
+
var MCP_TOOLS_VERSION = 3;
|
|
181
182
|
var MCP_TOOLS = [
|
|
182
183
|
{ name: "get_workspace", toolset: "investigate", scope: "org:read", readOnly: true, destructive: false, idempotent: true },
|
|
183
184
|
{ name: "list_projects", toolset: "investigate", scope: "projects:read", readOnly: true, destructive: false, idempotent: true },
|
|
@@ -209,14 +210,7 @@ var MCP_TOOLS = [
|
|
|
209
210
|
var MCP_TOOLS_PENDING = {
|
|
210
211
|
query_metrics: "P14",
|
|
211
212
|
release_health: "P15",
|
|
212
|
-
|
|
213
|
-
get_incident: "P9",
|
|
214
|
-
get_coverage: "P10",
|
|
215
|
-
search_operations: "P7",
|
|
216
|
-
describe_operation: "P7",
|
|
217
|
-
plan_change: "P7",
|
|
218
|
-
apply_change: "P7",
|
|
219
|
-
get_operation: "P7"
|
|
213
|
+
get_coverage: "P10"
|
|
220
214
|
};
|
|
221
215
|
|
|
222
216
|
// ../src/shared/mcp/docs.ts
|
|
@@ -258,10 +252,10 @@ function docsFetcher(siteUrl, fetcher = fetch, now = () => Date.now()) {
|
|
|
258
252
|
}
|
|
259
253
|
|
|
260
254
|
// ../src/shared/mcp/server.ts
|
|
261
|
-
import { McpServer } from "@modelcontextprotocol/server";
|
|
255
|
+
import { CLIENT_CAPABILITIES_META_KEY, inputRequired, McpServer } from "@modelcontextprotocol/server";
|
|
262
256
|
|
|
263
257
|
// ../src/shared/contracts/mcp-tools.ts
|
|
264
|
-
import { z as
|
|
258
|
+
import { z as z24 } from "zod";
|
|
265
259
|
|
|
266
260
|
// ../src/shared/contracts/api-ops/access.ts
|
|
267
261
|
import { z as z3 } from "zod";
|
|
@@ -641,7 +635,16 @@ var UPTIME_TRIGGER = "uptime_problem";
|
|
|
641
635
|
var SLO_TRIGGER = "slo_burn";
|
|
642
636
|
var RULE_TRIGGERS = [...ALERT_TRIGGERS, INTEGRATION_TRIGGER, MONITOR_TRIGGER, UPTIME_TRIGGER, SLO_TRIGGER];
|
|
643
637
|
var SOLO_TRIGGERS = [INTEGRATION_TRIGGER, MONITOR_TRIGGER, UPTIME_TRIGGER, SLO_TRIGGER];
|
|
644
|
-
var MONITOR_RULE_KINDS = [
|
|
638
|
+
var MONITOR_RULE_KINDS = [
|
|
639
|
+
"missed",
|
|
640
|
+
"failed",
|
|
641
|
+
"timeout",
|
|
642
|
+
"unknown",
|
|
643
|
+
"count",
|
|
644
|
+
"assertion",
|
|
645
|
+
"deadline",
|
|
646
|
+
"stalled"
|
|
647
|
+
];
|
|
645
648
|
var SLO_RULE_SEVERITIES = ["page", "ticket"];
|
|
646
649
|
function validRuleTriggers(triggers) {
|
|
647
650
|
if (triggers.length === 1 && SOLO_TRIGGERS.includes(triggers[0]))
|
|
@@ -662,8 +665,9 @@ var ruleInputSchema = z4.object({
|
|
|
662
665
|
isEnabled: z4.boolean(),
|
|
663
666
|
notifyAll: z4.boolean(),
|
|
664
667
|
destinationIds: z4.array(z4.guid()).max(20),
|
|
665
|
-
monitorKinds: z4.array(z4.enum(MONITOR_RULE_KINDS)).min(1).max(
|
|
666
|
-
sloSeverities: z4.array(z4.enum(SLO_RULE_SEVERITIES)).min(1).max(2).default([...SLO_RULE_SEVERITIES])
|
|
668
|
+
monitorKinds: z4.array(z4.enum(MONITOR_RULE_KINDS)).min(1).max(MONITOR_RULE_KINDS.length).default([...MONITOR_RULE_KINDS]),
|
|
669
|
+
sloSeverities: z4.array(z4.enum(SLO_RULE_SEVERITIES)).min(1).max(2).default([...SLO_RULE_SEVERITIES]),
|
|
670
|
+
policyId: z4.guid().nullable().default(null)
|
|
667
671
|
});
|
|
668
672
|
|
|
669
673
|
// ../src/shared/contracts/api-ops/alerts.ts
|
|
@@ -680,7 +684,7 @@ var ALERT_INPUTS = {
|
|
|
680
684
|
destinationOnly: z5.object({ destinationId: uuid }),
|
|
681
685
|
createDestination: z5.object({
|
|
682
686
|
workspaceId: uuid,
|
|
683
|
-
provider: z5.enum(["telegram", "slack", "email", "webhook"]),
|
|
687
|
+
provider: z5.enum(["telegram", "slack", "email", "webhook", "pagerduty", "incident_io"]),
|
|
684
688
|
name,
|
|
685
689
|
projectIds,
|
|
686
690
|
locale
|
|
@@ -762,12 +766,14 @@ var ALERT_OPERATIONS = [
|
|
|
762
766
|
idempotency: "required",
|
|
763
767
|
status: 201,
|
|
764
768
|
mcp: "configure",
|
|
765
|
-
summary: "Start adding a Telegram, Slack, email or
|
|
769
|
+
summary: "Start adding a Telegram, Slack, email, webhook, PagerDuty or incident.io destination; a person enters its secrets.",
|
|
766
770
|
ui: [
|
|
767
771
|
"alerts#createSlackDestination",
|
|
768
772
|
"alerts#createWebhookDestination",
|
|
769
773
|
"alerts#createTelegramDestination",
|
|
770
|
-
"alerts#createEmailDestination"
|
|
774
|
+
"alerts#createEmailDestination",
|
|
775
|
+
"alerts#createPagerDutyDestination",
|
|
776
|
+
"alerts#createIncidentIoDestination"
|
|
771
777
|
]
|
|
772
778
|
}),
|
|
773
779
|
op({
|
|
@@ -856,17 +862,78 @@ var ALERT_OPERATIONS = [
|
|
|
856
862
|
})
|
|
857
863
|
];
|
|
858
864
|
|
|
859
|
-
// ../src/shared/contracts/api-ops/
|
|
860
|
-
import { z as
|
|
865
|
+
// ../src/shared/contracts/api-ops/incidents.ts
|
|
866
|
+
import { z as z10 } from "zod";
|
|
861
867
|
|
|
862
|
-
// ../src/shared/contracts/
|
|
868
|
+
// ../src/shared/contracts/notifications.ts
|
|
869
|
+
import { z as z9 } from "zod";
|
|
870
|
+
|
|
871
|
+
// ../src/shared/contracts/maintenance.ts
|
|
872
|
+
import { z as z6 } from "zod";
|
|
873
|
+
var MAINTENANCE_SCOPES = ["workspace", "project", "monitor"];
|
|
874
|
+
var MAINTENANCE_LIMITS = {
|
|
875
|
+
durationMinutesMin: 5,
|
|
876
|
+
durationMinutesMax: 1440,
|
|
877
|
+
reasonMax: 200,
|
|
878
|
+
idsMax: 50,
|
|
879
|
+
onceAheadDays: 366,
|
|
880
|
+
previewStarts: 3
|
|
881
|
+
};
|
|
882
|
+
var weekdaySchema = z6.number().int().min(1).max(7);
|
|
883
|
+
var timeOfDay = z6.string().regex(/^([01]\d|2[0-3]):[0-5]\d$/);
|
|
884
|
+
var base = {
|
|
885
|
+
scope: z6.enum(MAINTENANCE_SCOPES),
|
|
886
|
+
projectIds: z6.array(z6.number().int().positive()).max(MAINTENANCE_LIMITS.idsMax),
|
|
887
|
+
monitorIds: z6.array(z6.guid()).max(MAINTENANCE_LIMITS.idsMax),
|
|
888
|
+
timezone: z6.string().trim().min(1).max(64),
|
|
889
|
+
durationMinutes: z6.number().int().min(MAINTENANCE_LIMITS.durationMinutesMin).max(MAINTENANCE_LIMITS.durationMinutesMax),
|
|
890
|
+
reason: z6.string().trim().max(MAINTENANCE_LIMITS.reasonMax).regex(/^[^\p{Cc}]*$/u)
|
|
891
|
+
};
|
|
892
|
+
var maintenanceInputSchema = z6.discriminatedUnion("kind", [
|
|
893
|
+
z6.object({ kind: z6.literal("once"), startsAt: z6.string().datetime({ offset: true }), ...base }),
|
|
894
|
+
z6.object({
|
|
895
|
+
kind: z6.literal("weekly"),
|
|
896
|
+
weekdays: z6.array(weekdaySchema).min(1).max(7),
|
|
897
|
+
startTime: timeOfDay,
|
|
898
|
+
...base
|
|
899
|
+
})
|
|
900
|
+
]).superRefine((w, ctx) => {
|
|
901
|
+
const bad = (path) => ctx.addIssue({ code: "custom", path: [path], message: "MAINTENANCE_INVALID" });
|
|
902
|
+
if (w.scope === "workspace" && (w.projectIds.length || w.monitorIds.length))
|
|
903
|
+
bad("scope");
|
|
904
|
+
if (w.scope === "project" && (!w.projectIds.length || w.monitorIds.length))
|
|
905
|
+
bad("projectIds");
|
|
906
|
+
if (w.scope === "monitor" && (!w.monitorIds.length || w.projectIds.length))
|
|
907
|
+
bad("monitorIds");
|
|
908
|
+
if (new Set(w.projectIds).size !== w.projectIds.length)
|
|
909
|
+
bad("projectIds");
|
|
910
|
+
if (new Set(w.monitorIds).size !== w.monitorIds.length)
|
|
911
|
+
bad("monitorIds");
|
|
912
|
+
if (w.kind === "weekly" && new Set(w.weekdays).size !== w.weekdays.length)
|
|
913
|
+
bad("weekdays");
|
|
914
|
+
if (!validTimeZone(w.timezone))
|
|
915
|
+
bad("timezone");
|
|
916
|
+
});
|
|
917
|
+
function validTimeZone(tz) {
|
|
918
|
+
try {
|
|
919
|
+
new Intl.DateTimeFormat("en-US", { timeZone: tz });
|
|
920
|
+
return true;
|
|
921
|
+
} catch {
|
|
922
|
+
return false;
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
var fmtCache = new Map;
|
|
926
|
+
|
|
927
|
+
// ../src/shared/contracts/signal-monitors.ts
|
|
863
928
|
import { z as z8 } from "zod";
|
|
864
929
|
|
|
865
930
|
// ../src/shared/contracts/monitors.ts
|
|
866
|
-
import { z as
|
|
931
|
+
import { z as z7 } from "zod";
|
|
867
932
|
|
|
868
933
|
// ../src/shared/contracts/vocab/monitors.ts
|
|
869
934
|
var MONITOR_MODES = ["check_in", "heartbeat"];
|
|
935
|
+
var MONITOR_TYPES = ["job", "count", "assertion", "deadline", "progress"];
|
|
936
|
+
var SIGNAL_MONITOR_TYPES = ["count", "assertion", "deadline", "progress"];
|
|
870
937
|
|
|
871
938
|
// ../src/shared/contracts/monitors.ts
|
|
872
939
|
var MONITOR_KINDS = ["crontab", "interval", "on_demand"];
|
|
@@ -876,8 +943,13 @@ var MONITOR_INCIDENT_CODES = [
|
|
|
876
943
|
"MONITOR_MISSED",
|
|
877
944
|
"MONITOR_FAILED",
|
|
878
945
|
"MONITOR_TIMEOUT",
|
|
879
|
-
"MONITOR_UNKNOWN"
|
|
946
|
+
"MONITOR_UNKNOWN",
|
|
947
|
+
"MONITOR_COUNT",
|
|
948
|
+
"MONITOR_ASSERTION",
|
|
949
|
+
"MONITOR_DEADLINE_MISSED",
|
|
950
|
+
"MONITOR_STALLED"
|
|
880
951
|
];
|
|
952
|
+
var FAILURE_INCIDENT_CODES = MONITOR_INCIDENT_CODES.filter((c) => c !== "MONITOR_UNKNOWN");
|
|
881
953
|
var INCIDENT_EVENTS = ["opened", "updated", "resolved"];
|
|
882
954
|
var UNOBSERVABLE_REASONS = [
|
|
883
955
|
"node_offline",
|
|
@@ -928,100 +1000,112 @@ function crontabShapeOk(value) {
|
|
|
928
1000
|
const fields = value.trim().split(/\s+/);
|
|
929
1001
|
return value.length <= 120 && fields.length === 5 && fields.every((f) => /^[0-9A-Za-z*,/?#LW-]+$/.test(f));
|
|
930
1002
|
}
|
|
931
|
-
var crontabScheduleSchema =
|
|
932
|
-
type:
|
|
933
|
-
value:
|
|
1003
|
+
var crontabScheduleSchema = z7.object({
|
|
1004
|
+
type: z7.literal("crontab"),
|
|
1005
|
+
value: z7.string().refine(crontabShapeOk, "crontab")
|
|
934
1006
|
});
|
|
935
|
-
var intervalScheduleSchema =
|
|
936
|
-
type:
|
|
937
|
-
value:
|
|
938
|
-
unit:
|
|
1007
|
+
var intervalScheduleSchema = z7.object({
|
|
1008
|
+
type: z7.literal("interval"),
|
|
1009
|
+
value: z7.number().int().min(1).max(MONITOR_LIMITS.intervalValueMax),
|
|
1010
|
+
unit: z7.enum(INTERVAL_UNITS)
|
|
939
1011
|
});
|
|
940
|
-
var scheduleSchema =
|
|
1012
|
+
var scheduleSchema = z7.discriminatedUnion("type", [
|
|
941
1013
|
crontabScheduleSchema,
|
|
942
1014
|
intervalScheduleSchema
|
|
943
1015
|
]);
|
|
944
|
-
var monitorSettingsSchema =
|
|
1016
|
+
var monitorSettingsSchema = z7.object({
|
|
945
1017
|
schedule: scheduleSchema.nullable(),
|
|
946
|
-
timezone:
|
|
947
|
-
checkin_margin:
|
|
948
|
-
max_runtime:
|
|
949
|
-
failure_issue_threshold:
|
|
950
|
-
recovery_threshold:
|
|
951
|
-
});
|
|
952
|
-
var iso =
|
|
953
|
-
var projectId2 =
|
|
954
|
-
var envName =
|
|
1018
|
+
timezone: z7.string().min(1).max(64),
|
|
1019
|
+
checkin_margin: z7.number().int().min(MONITOR_LIMITS.checkinMarginMin).max(MONITOR_LIMITS.checkinMarginMax),
|
|
1020
|
+
max_runtime: z7.number().int().min(MONITOR_LIMITS.maxRuntimeMin).max(MONITOR_LIMITS.maxRuntimeMax),
|
|
1021
|
+
failure_issue_threshold: z7.number().int().min(MONITOR_LIMITS.thresholdMin).max(MONITOR_LIMITS.thresholdMax),
|
|
1022
|
+
recovery_threshold: z7.number().int().min(MONITOR_LIMITS.thresholdMin).max(MONITOR_LIMITS.thresholdMax)
|
|
1023
|
+
});
|
|
1024
|
+
var iso = z7.string().datetime();
|
|
1025
|
+
var projectId2 = z7.number().int().positive();
|
|
1026
|
+
var envName = z7.string().min(1).max(MONITOR_LIMITS.environmentMax);
|
|
955
1027
|
var monitorDefinitionSchema = monitorSettingsSchema.extend({
|
|
956
|
-
id:
|
|
1028
|
+
id: z7.guid(),
|
|
957
1029
|
project_id: projectId2,
|
|
958
|
-
slug:
|
|
959
|
-
kind:
|
|
960
|
-
expected_environments:
|
|
1030
|
+
slug: z7.string().regex(SLUG_RE),
|
|
1031
|
+
kind: z7.enum(MONITOR_KINDS),
|
|
1032
|
+
expected_environments: z7.array(envName).max(MONITOR_LIMITS.expectedEnvironmentsMax),
|
|
961
1033
|
paused_until: iso.nullable(),
|
|
962
1034
|
created_at: iso,
|
|
963
|
-
config_source:
|
|
964
|
-
config_hash:
|
|
965
|
-
});
|
|
966
|
-
var outcomeCounts =
|
|
967
|
-
ok:
|
|
968
|
-
skipped:
|
|
969
|
-
error:
|
|
970
|
-
timeout:
|
|
971
|
-
missed:
|
|
972
|
-
unknown:
|
|
973
|
-
});
|
|
974
|
-
var
|
|
975
|
-
|
|
1035
|
+
config_source: z7.enum(CONFIG_SOURCES),
|
|
1036
|
+
config_hash: z7.string().regex(/^[0-9a-f]{64}$/).nullable()
|
|
1037
|
+
});
|
|
1038
|
+
var outcomeCounts = z7.object({
|
|
1039
|
+
ok: z7.number().int().nonnegative(),
|
|
1040
|
+
skipped: z7.number().int().nonnegative(),
|
|
1041
|
+
error: z7.number().int().nonnegative(),
|
|
1042
|
+
timeout: z7.number().int().nonnegative(),
|
|
1043
|
+
missed: z7.number().int().nonnegative(),
|
|
1044
|
+
unknown: z7.number().int().nonnegative()
|
|
1045
|
+
});
|
|
1046
|
+
var signalStatusSchema = z7.object({
|
|
1047
|
+
type: z7.enum(SIGNAL_MONITOR_TYPES),
|
|
1048
|
+
value: z7.number().int().nonnegative().max(1e9).nullable(),
|
|
1049
|
+
threshold: z7.number().int().nonnegative().max(1e9).nullable(),
|
|
1050
|
+
window_end: iso.nullable(),
|
|
1051
|
+
pending: z7.number().int().nonnegative().max(1e6).nullable(),
|
|
1052
|
+
stalled: z7.number().int().nonnegative().max(1e6).nullable(),
|
|
1053
|
+
refused_24h: z7.number().int().nonnegative().max(1e9).nullable()
|
|
1054
|
+
});
|
|
1055
|
+
var monitorStatusSchema = z7.object({
|
|
1056
|
+
monitor_id: z7.guid(),
|
|
976
1057
|
project_id: projectId2,
|
|
977
1058
|
environment: envName,
|
|
978
|
-
open_failure:
|
|
979
|
-
open_unknown:
|
|
980
|
-
unobservable:
|
|
981
|
-
last_outcome:
|
|
1059
|
+
open_failure: z7.enum(FAILURE_INCIDENT_CODES).nullable(),
|
|
1060
|
+
open_unknown: z7.boolean(),
|
|
1061
|
+
unobservable: z7.enum(UNOBSERVABLE_REASONS).nullable(),
|
|
1062
|
+
last_outcome: z7.enum(RUN_OUTCOMES).nullable(),
|
|
982
1063
|
last_check_in_at: iso.nullable(),
|
|
983
1064
|
last_healthy_at: iso.nullable(),
|
|
984
1065
|
next_deadline_at: iso.nullable(),
|
|
985
1066
|
next_due_at: iso.nullable().optional(),
|
|
986
|
-
in_progress:
|
|
1067
|
+
in_progress: z7.boolean(),
|
|
987
1068
|
counts_24h: outcomeCounts,
|
|
1069
|
+
signal: signalStatusSchema.optional(),
|
|
988
1070
|
evaluated_at: iso
|
|
989
1071
|
});
|
|
990
|
-
var monitorIncidentSchema =
|
|
991
|
-
incident_id:
|
|
992
|
-
monitor_id:
|
|
1072
|
+
var monitorIncidentSchema = z7.object({
|
|
1073
|
+
incident_id: z7.guid(),
|
|
1074
|
+
monitor_id: z7.guid(),
|
|
993
1075
|
project_id: projectId2,
|
|
994
1076
|
environment: envName,
|
|
995
|
-
code:
|
|
996
|
-
event:
|
|
1077
|
+
code: z7.enum(MONITOR_INCIDENT_CODES),
|
|
1078
|
+
event: z7.enum(INCIDENT_EVENTS),
|
|
997
1079
|
occurred_at: iso,
|
|
998
|
-
detected_late:
|
|
999
|
-
reason:
|
|
1000
|
-
duration_ms:
|
|
1001
|
-
consecutive:
|
|
1002
|
-
reviewed_by:
|
|
1080
|
+
detected_late: z7.boolean(),
|
|
1081
|
+
reason: z7.string().regex(REASON_RE).nullable(),
|
|
1082
|
+
duration_ms: z7.number().int().nonnegative().nullable(),
|
|
1083
|
+
consecutive: z7.number().int().min(1).max(1e5),
|
|
1084
|
+
reviewed_by: z7.guid().nullable(),
|
|
1085
|
+
observed: z7.number().int().min(0).max(1e9).nullable().optional(),
|
|
1086
|
+
threshold: z7.number().int().min(0).max(1e9).nullable().optional()
|
|
1003
1087
|
});
|
|
1004
|
-
var monitorDiscoverySchema =
|
|
1088
|
+
var monitorDiscoverySchema = z7.object({
|
|
1005
1089
|
project_id: projectId2,
|
|
1006
|
-
slug:
|
|
1090
|
+
slug: z7.string().regex(SLUG_RE),
|
|
1007
1091
|
settings: monitorSettingsSchema.nullable(),
|
|
1008
|
-
config_hash:
|
|
1009
|
-
check_ins:
|
|
1092
|
+
config_hash: z7.string().regex(/^[0-9a-f]{64}$/).nullable(),
|
|
1093
|
+
check_ins: z7.number().int().nonnegative(),
|
|
1010
1094
|
last_seen_at: iso
|
|
1011
1095
|
});
|
|
1012
1096
|
var MONITOR_NAME_MAX = MONITOR_LIMITS.nameMax;
|
|
1013
|
-
var environmentName =
|
|
1014
|
-
var monitorInputSchema =
|
|
1015
|
-
name:
|
|
1016
|
-
mode:
|
|
1017
|
-
kind:
|
|
1097
|
+
var environmentName = z7.string().trim().min(1).max(MONITOR_LIMITS.environmentMax).regex(/^[A-Za-z0-9._-]+$/);
|
|
1098
|
+
var monitorInputSchema = z7.object({
|
|
1099
|
+
name: z7.string().trim().min(1).max(MONITOR_LIMITS.nameMax),
|
|
1100
|
+
mode: z7.enum(MONITOR_MODES).default("check_in"),
|
|
1101
|
+
kind: z7.enum(MONITOR_KINDS),
|
|
1018
1102
|
schedule: scheduleSchema.nullable(),
|
|
1019
|
-
timezone:
|
|
1020
|
-
checkinMarginMin:
|
|
1021
|
-
maxRuntimeMin:
|
|
1022
|
-
failureThreshold:
|
|
1023
|
-
recoveryThreshold:
|
|
1024
|
-
expectedEnvironments:
|
|
1103
|
+
timezone: z7.string().trim().min(1).max(64),
|
|
1104
|
+
checkinMarginMin: z7.number().int().min(MONITOR_LIMITS.checkinMarginMin).max(MONITOR_LIMITS.checkinMarginMax),
|
|
1105
|
+
maxRuntimeMin: z7.number().int().min(MONITOR_LIMITS.maxRuntimeMin).max(MONITOR_LIMITS.maxRuntimeMax),
|
|
1106
|
+
failureThreshold: z7.number().int().min(MONITOR_LIMITS.thresholdMin).max(MONITOR_LIMITS.thresholdMax),
|
|
1107
|
+
recoveryThreshold: z7.number().int().min(MONITOR_LIMITS.thresholdMin).max(MONITOR_LIMITS.thresholdMax),
|
|
1108
|
+
expectedEnvironments: z7.array(environmentName).min(1).max(MONITOR_LIMITS.expectedEnvironmentsMax)
|
|
1025
1109
|
}).refine((v) => v.kind === "on_demand" ? v.schedule === null : v.schedule?.type === v.kind, {
|
|
1026
1110
|
path: ["schedule"],
|
|
1027
1111
|
message: "schedule"
|
|
@@ -1036,98 +1120,601 @@ var MONITOR_INPUT_DEFAULTS = {
|
|
|
1036
1120
|
recoveryThreshold: MONITOR_LIMITS.recoveryThresholdDefault,
|
|
1037
1121
|
expectedEnvironments: [DEFAULT_CHECK_IN_ENVIRONMENT]
|
|
1038
1122
|
};
|
|
1039
|
-
var runOutcome =
|
|
1040
|
-
var runFlags =
|
|
1041
|
-
var monitorRunSchema =
|
|
1042
|
-
id:
|
|
1043
|
-
kind:
|
|
1123
|
+
var runOutcome = z7.enum(RUN_OUTCOMES);
|
|
1124
|
+
var runFlags = z7.array(z7.string().max(32)).max(16);
|
|
1125
|
+
var monitorRunSchema = z7.object({
|
|
1126
|
+
id: z7.number().int().positive(),
|
|
1127
|
+
kind: z7.enum(["run", "missed"]),
|
|
1044
1128
|
outcome: runOutcome,
|
|
1045
1129
|
started_at: iso,
|
|
1046
1130
|
ended_at: iso,
|
|
1047
|
-
attempts:
|
|
1048
|
-
duration_ms:
|
|
1049
|
-
reason:
|
|
1050
|
-
check_in_id:
|
|
1051
|
-
trace_id:
|
|
1052
|
-
release:
|
|
1131
|
+
attempts: z7.number().int().nonnegative(),
|
|
1132
|
+
duration_ms: z7.number().int().nonnegative().nullable(),
|
|
1133
|
+
reason: z7.string().max(64).nullable(),
|
|
1134
|
+
check_in_id: z7.string().max(64).nullable(),
|
|
1135
|
+
trace_id: z7.string().max(32).nullable(),
|
|
1136
|
+
release: z7.string().max(MONITOR_LIMITS.releaseMax).nullable(),
|
|
1053
1137
|
flags: runFlags
|
|
1054
1138
|
});
|
|
1055
|
-
var openAttemptSchema =
|
|
1056
|
-
check_in_id:
|
|
1057
|
-
run_key:
|
|
1058
|
-
attempt:
|
|
1059
|
-
state:
|
|
1139
|
+
var openAttemptSchema = z7.object({
|
|
1140
|
+
check_in_id: z7.string().max(64),
|
|
1141
|
+
run_key: z7.string().max(64),
|
|
1142
|
+
attempt: z7.number().int().nonnegative(),
|
|
1143
|
+
state: z7.string().max(16),
|
|
1060
1144
|
started_at: iso,
|
|
1061
1145
|
deadline_at: iso
|
|
1062
1146
|
});
|
|
1063
|
-
var monitorRunsResponseSchema =
|
|
1064
|
-
open:
|
|
1065
|
-
runs:
|
|
1066
|
-
next_cursor:
|
|
1147
|
+
var monitorRunsResponseSchema = z7.object({
|
|
1148
|
+
open: z7.array(openAttemptSchema).max(100),
|
|
1149
|
+
runs: z7.array(monitorRunSchema).max(MONITOR_LIMITS.runsPageSize),
|
|
1150
|
+
next_cursor: z7.string().max(32).nullable()
|
|
1067
1151
|
});
|
|
1068
|
-
var timelineRunSchema =
|
|
1069
|
-
id:
|
|
1070
|
-
kind:
|
|
1152
|
+
var timelineRunSchema = z7.object({
|
|
1153
|
+
id: z7.number().int().positive(),
|
|
1154
|
+
kind: z7.enum(["run", "missed"]),
|
|
1071
1155
|
outcome: runOutcome,
|
|
1072
1156
|
ended_at: iso,
|
|
1073
1157
|
flags: runFlags
|
|
1074
1158
|
});
|
|
1075
|
-
var monitorTimelineResponseSchema =
|
|
1076
|
-
runs:
|
|
1159
|
+
var monitorTimelineResponseSchema = z7.object({
|
|
1160
|
+
runs: z7.array(timelineRunSchema).max(MONITOR_LIMITS.timelineRuns)
|
|
1077
1161
|
});
|
|
1078
|
-
var monitorStripsResponseSchema =
|
|
1079
|
-
strips:
|
|
1080
|
-
monitor_id:
|
|
1162
|
+
var monitorStripsResponseSchema = z7.object({
|
|
1163
|
+
strips: z7.array(z7.object({
|
|
1164
|
+
monitor_id: z7.guid(),
|
|
1081
1165
|
environment: envName,
|
|
1082
|
-
runs:
|
|
1166
|
+
runs: z7.array(timelineRunSchema).max(MONITOR_LIMITS.listStripRuns)
|
|
1083
1167
|
})).max(5000)
|
|
1084
1168
|
});
|
|
1085
|
-
var monitorDiagnosticSchema =
|
|
1086
|
-
id:
|
|
1087
|
-
check_in_id:
|
|
1088
|
-
signal:
|
|
1089
|
-
exit_code:
|
|
1169
|
+
var monitorDiagnosticSchema = z7.object({
|
|
1170
|
+
id: z7.string().regex(/^\d{1,19}$/),
|
|
1171
|
+
check_in_id: z7.string().max(64).nullable(),
|
|
1172
|
+
signal: z7.string().max(16),
|
|
1173
|
+
exit_code: z7.number().int().min(0).max(255).nullable(),
|
|
1090
1174
|
received_at: iso,
|
|
1091
|
-
body:
|
|
1092
|
-
});
|
|
1093
|
-
var monitorDiagnosticsResponseSchema =
|
|
1094
|
-
diagnostics:
|
|
1095
|
-
next_cursor:
|
|
1096
|
-
});
|
|
1097
|
-
var checkInDetailSchema =
|
|
1098
|
-
run_key:
|
|
1099
|
-
attempts:
|
|
1100
|
-
check_in_id:
|
|
1101
|
-
attempt:
|
|
1102
|
-
result:
|
|
1175
|
+
body: z7.string().max(MONITOR_LIMITS.diagnosticMaxBytes * 2)
|
|
1176
|
+
});
|
|
1177
|
+
var monitorDiagnosticsResponseSchema = z7.object({
|
|
1178
|
+
diagnostics: z7.array(monitorDiagnosticSchema).max(50),
|
|
1179
|
+
next_cursor: z7.string().regex(/^\d{1,19}$/).nullable()
|
|
1180
|
+
});
|
|
1181
|
+
var checkInDetailSchema = z7.object({
|
|
1182
|
+
run_key: z7.string().max(64),
|
|
1183
|
+
attempts: z7.array(z7.object({
|
|
1184
|
+
check_in_id: z7.string().max(64),
|
|
1185
|
+
attempt: z7.number().int().nonnegative(),
|
|
1186
|
+
result: z7.string().max(16),
|
|
1103
1187
|
started_at: iso,
|
|
1104
1188
|
ended_at: iso.nullable(),
|
|
1105
|
-
duration_ms:
|
|
1106
|
-
reason:
|
|
1107
|
-
trace_id:
|
|
1108
|
-
release:
|
|
1189
|
+
duration_ms: z7.number().int().nonnegative().nullable(),
|
|
1190
|
+
reason: z7.string().max(64).nullable(),
|
|
1191
|
+
trace_id: z7.string().max(32).nullable(),
|
|
1192
|
+
release: z7.string().max(MONITOR_LIMITS.releaseMax).nullable()
|
|
1109
1193
|
})).max(1000),
|
|
1110
|
-
errors:
|
|
1111
|
-
event_id:
|
|
1112
|
-
issue_id:
|
|
1113
|
-
title:
|
|
1114
|
-
level:
|
|
1194
|
+
errors: z7.array(z7.object({
|
|
1195
|
+
event_id: z7.string().max(64),
|
|
1196
|
+
issue_id: z7.number().int().nonnegative(),
|
|
1197
|
+
title: z7.string().max(1024),
|
|
1198
|
+
level: z7.string().max(16),
|
|
1115
1199
|
timestamp: iso,
|
|
1116
|
-
same_trace:
|
|
1200
|
+
same_trace: z7.boolean()
|
|
1117
1201
|
})).max(50),
|
|
1118
|
-
diagnostics:
|
|
1202
|
+
diagnostics: z7.array(monitorDiagnosticSchema).max(20).default([])
|
|
1119
1203
|
});
|
|
1120
|
-
var incidentReviewSchema =
|
|
1204
|
+
var incidentReviewSchema = z7.object({ incident_id: z7.guid() });
|
|
1205
|
+
|
|
1206
|
+
// ../src/shared/contracts/signal-monitors.ts
|
|
1207
|
+
var isSignalMonitorType = (t) => SIGNAL_MONITOR_TYPES.includes(t);
|
|
1208
|
+
var SIGNAL_KINDS = ["event", "check_in", "span", "log"];
|
|
1209
|
+
var SELECTOR_OPS = ["eq", "ne", "lt", "le", "gt", "ge", "in", "exists", "not_exists", "prefix"];
|
|
1210
|
+
var NUMERIC_OPS = new Set(["lt", "le", "gt", "ge"]);
|
|
1211
|
+
var VALUELESS_OPS = new Set(["exists", "not_exists"]);
|
|
1212
|
+
var COMPARATORS = ["lt", "gt", "outside"];
|
|
1213
|
+
var MISSING_DATA_POLICIES = ["alert", "keep", "resolve", "treat_as_zero"];
|
|
1214
|
+
var SEVERITIES = ["critical", "high", "medium", "low"];
|
|
1215
|
+
var OCCURRENCE_STATES = [
|
|
1216
|
+
"pending",
|
|
1217
|
+
"in_progress",
|
|
1218
|
+
"success",
|
|
1219
|
+
"late_success",
|
|
1220
|
+
"missed",
|
|
1221
|
+
"failed",
|
|
1222
|
+
"cancelled"
|
|
1223
|
+
];
|
|
1224
|
+
var OCCURRENCE_OPEN = new Set(["pending", "in_progress"]);
|
|
1225
|
+
var SIGNAL_LIMITS = {
|
|
1226
|
+
matchMax: 5,
|
|
1227
|
+
assertMax: 5,
|
|
1228
|
+
inValuesMax: 20,
|
|
1229
|
+
valueMax: 256,
|
|
1230
|
+
keyMax: 128,
|
|
1231
|
+
environmentsMax: MONITOR_LIMITS.expectedEnvironmentsMax,
|
|
1232
|
+
windowMinutesMin: 1,
|
|
1233
|
+
windowMinutesMax: 1440,
|
|
1234
|
+
thresholdMax: 1e6,
|
|
1235
|
+
graceMinutesMax: 1440,
|
|
1236
|
+
progressMinutesMin: 1,
|
|
1237
|
+
progressMinutesMax: 1440,
|
|
1238
|
+
occurrenceIdMax: 128,
|
|
1239
|
+
occurrenceDueMaxDays: 35,
|
|
1240
|
+
lateSuccessDays: 7,
|
|
1241
|
+
evaluateEverySeconds: 15,
|
|
1242
|
+
settleSeconds: 20,
|
|
1243
|
+
countMaxDelayMinutes: 10,
|
|
1244
|
+
countMinutesPerTick: 60,
|
|
1245
|
+
windowsPerTick: 120,
|
|
1246
|
+
monitorsPerQuery: 50,
|
|
1247
|
+
bucketRowsPerQuery: 9000,
|
|
1248
|
+
backtestDays: 30,
|
|
1249
|
+
bucketRetentionMinutes: 2 * 1440 + 60,
|
|
1250
|
+
occurrencesKeptFinished: 1000,
|
|
1251
|
+
occurrencesPageSize: 50,
|
|
1252
|
+
runIdsPerQuery: 500,
|
|
1253
|
+
dueJudgedPerTick: 5000,
|
|
1254
|
+
queryMaxSeconds: 5
|
|
1255
|
+
};
|
|
1256
|
+
var SELECTOR_KEY_RE = /^(?:tags\.[A-Za-z0-9_.:-]{1,100}|[A-Za-z_][A-Za-z0-9_.:-]{0,127})$/;
|
|
1257
|
+
var scalar = z8.union([z8.string().max(SIGNAL_LIMITS.valueMax), z8.number().finite(), z8.boolean()]);
|
|
1258
|
+
var selectorConditionSchema = z8.object({
|
|
1259
|
+
key: z8.string().min(1).max(SIGNAL_LIMITS.keyMax).regex(SELECTOR_KEY_RE),
|
|
1260
|
+
op: z8.enum(SELECTOR_OPS),
|
|
1261
|
+
value: z8.union([scalar, z8.array(z8.string().max(SIGNAL_LIMITS.valueMax)).min(1).max(SIGNAL_LIMITS.inValuesMax)]).optional()
|
|
1262
|
+
}).superRefine((c, ctx) => {
|
|
1263
|
+
const bad = (message) => ctx.addIssue({ code: "custom", path: ["value"], message });
|
|
1264
|
+
if (VALUELESS_OPS.has(c.op)) {
|
|
1265
|
+
if (c.value !== undefined)
|
|
1266
|
+
bad("no_value");
|
|
1267
|
+
return;
|
|
1268
|
+
}
|
|
1269
|
+
if (c.value === undefined)
|
|
1270
|
+
return bad("value");
|
|
1271
|
+
if (c.op === "in") {
|
|
1272
|
+
if (!Array.isArray(c.value))
|
|
1273
|
+
bad("list");
|
|
1274
|
+
return;
|
|
1275
|
+
}
|
|
1276
|
+
if (Array.isArray(c.value))
|
|
1277
|
+
return bad("scalar");
|
|
1278
|
+
if (NUMERIC_OPS.has(c.op) && toNumber(c.value) === null)
|
|
1279
|
+
bad("number");
|
|
1280
|
+
if (c.op === "prefix" && (typeof c.value !== "string" || c.value.length === 0))
|
|
1281
|
+
bad("text");
|
|
1282
|
+
});
|
|
1283
|
+
var environmentListSchema = z8.array(z8.string().trim().min(1).max(MONITOR_LIMITS.environmentMax).regex(/^[A-Za-z0-9._-]+$/)).min(1).max(SIGNAL_LIMITS.environmentsMax).refine((v) => new Set(v).size === v.length, "unique");
|
|
1284
|
+
var selectorSchema = z8.object({
|
|
1285
|
+
signal: z8.enum(SIGNAL_KINDS),
|
|
1286
|
+
match: z8.array(selectorConditionSchema).max(SIGNAL_LIMITS.matchMax)
|
|
1287
|
+
});
|
|
1288
|
+
function toNumber(v) {
|
|
1289
|
+
if (typeof v === "number")
|
|
1290
|
+
return Number.isFinite(v) ? v : null;
|
|
1291
|
+
if (typeof v === "string" && v.trim() !== "" && v.length <= 64) {
|
|
1292
|
+
const n = Number(v);
|
|
1293
|
+
return Number.isFinite(n) ? n : null;
|
|
1294
|
+
}
|
|
1295
|
+
return null;
|
|
1296
|
+
}
|
|
1297
|
+
var minutes = (min, max) => z8.number().int().min(min).max(max);
|
|
1298
|
+
var threshold = z8.number().int().min(0).max(SIGNAL_LIMITS.thresholdMax);
|
|
1299
|
+
var recovery = z8.number().int().min(MONITOR_LIMITS.thresholdMin).max(MONITOR_LIMITS.thresholdMax);
|
|
1300
|
+
var common = {
|
|
1301
|
+
environments: environmentListSchema,
|
|
1302
|
+
severity: z8.enum(SEVERITIES),
|
|
1303
|
+
recovery_threshold: recovery
|
|
1304
|
+
};
|
|
1305
|
+
var countSettingsSchema = z8.object({
|
|
1306
|
+
type: z8.literal("count"),
|
|
1307
|
+
selector: selectorSchema,
|
|
1308
|
+
window_minutes: minutes(SIGNAL_LIMITS.windowMinutesMin, SIGNAL_LIMITS.windowMinutesMax),
|
|
1309
|
+
comparator: z8.enum(COMPARATORS),
|
|
1310
|
+
threshold,
|
|
1311
|
+
threshold_high: threshold.nullable(),
|
|
1312
|
+
missing_data: z8.enum(MISSING_DATA_POLICIES),
|
|
1313
|
+
...common
|
|
1314
|
+
}).superRefine((s, ctx) => {
|
|
1315
|
+
if (s.comparator === "outside" && (s.threshold_high === null || s.threshold_high <= s.threshold)) {
|
|
1316
|
+
ctx.addIssue({ code: "custom", path: ["threshold_high"], message: "threshold_high" });
|
|
1317
|
+
}
|
|
1318
|
+
if (s.comparator !== "outside" && s.threshold_high !== null) {
|
|
1319
|
+
ctx.addIssue({ code: "custom", path: ["threshold_high"], message: "threshold_high" });
|
|
1320
|
+
}
|
|
1321
|
+
if (s.comparator === "lt" && s.threshold === 0) {
|
|
1322
|
+
ctx.addIssue({ code: "custom", path: ["threshold"], message: "threshold" });
|
|
1323
|
+
}
|
|
1324
|
+
});
|
|
1325
|
+
var assertionSettingsSchema = z8.object({
|
|
1326
|
+
type: z8.literal("assertion"),
|
|
1327
|
+
selector: selectorSchema,
|
|
1328
|
+
assert: z8.array(selectorConditionSchema).min(1).max(SIGNAL_LIMITS.assertMax),
|
|
1329
|
+
window_minutes: minutes(SIGNAL_LIMITS.windowMinutesMin, SIGNAL_LIMITS.windowMinutesMax),
|
|
1330
|
+
threshold: z8.number().int().min(1).max(SIGNAL_LIMITS.thresholdMax),
|
|
1331
|
+
missing_data: z8.enum(MISSING_DATA_POLICIES),
|
|
1332
|
+
...common
|
|
1333
|
+
});
|
|
1334
|
+
var deadlineSettingsSchema = z8.object({
|
|
1335
|
+
type: z8.literal("deadline"),
|
|
1336
|
+
occurrence_grace_minutes: minutes(0, SIGNAL_LIMITS.graceMinutesMax),
|
|
1337
|
+
progress_timeout_minutes: minutes(SIGNAL_LIMITS.progressMinutesMin, SIGNAL_LIMITS.progressMinutesMax).nullable(),
|
|
1338
|
+
...common
|
|
1339
|
+
});
|
|
1340
|
+
var progressSettingsSchema = z8.object({
|
|
1341
|
+
type: z8.literal("progress"),
|
|
1342
|
+
progress_timeout_minutes: minutes(SIGNAL_LIMITS.progressMinutesMin, SIGNAL_LIMITS.progressMinutesMax),
|
|
1343
|
+
...common
|
|
1344
|
+
});
|
|
1345
|
+
var signalSettingsSchema = z8.discriminatedUnion("type", [
|
|
1346
|
+
countSettingsSchema,
|
|
1347
|
+
assertionSettingsSchema,
|
|
1348
|
+
deadlineSettingsSchema,
|
|
1349
|
+
progressSettingsSchema
|
|
1350
|
+
]);
|
|
1351
|
+
function settingsFromRow(row) {
|
|
1352
|
+
if (!isSignalMonitorType(row.type) || !row.signal_settings || typeof row.signal_settings !== "object")
|
|
1353
|
+
return null;
|
|
1354
|
+
const r = signalSettingsSchema.safeParse({
|
|
1355
|
+
...row.signal_settings,
|
|
1356
|
+
type: row.type,
|
|
1357
|
+
environments: [...row.expected_environments],
|
|
1358
|
+
severity: row.severity,
|
|
1359
|
+
recovery_threshold: row.recovery_threshold
|
|
1360
|
+
});
|
|
1361
|
+
return r.success ? r.data : null;
|
|
1362
|
+
}
|
|
1363
|
+
var signalMonitorInputSchema = z8.object({
|
|
1364
|
+
name: z8.string().trim().min(1).max(MONITOR_LIMITS.nameMax),
|
|
1365
|
+
settings: signalSettingsSchema
|
|
1366
|
+
});
|
|
1367
|
+
var signalMonitorDefinitionSchema = z8.object({
|
|
1368
|
+
id: z8.guid(),
|
|
1369
|
+
project_id: z8.number().int().positive(),
|
|
1370
|
+
slug: z8.string().regex(SLUG_RE),
|
|
1371
|
+
settings: signalSettingsSchema,
|
|
1372
|
+
paused_until: z8.string().datetime().nullable(),
|
|
1373
|
+
created_at: z8.string().datetime(),
|
|
1374
|
+
revision: z8.number().int().nonnegative()
|
|
1375
|
+
});
|
|
1376
|
+
var signalLimitsConfigSchema = z8.object({
|
|
1377
|
+
pending_occurrences_per_monitor: z8.number().int().min(1).max(1e6),
|
|
1378
|
+
pending_occurrences_per_project: z8.number().int().min(1).max(1e7)
|
|
1379
|
+
});
|
|
1380
|
+
var OCCURRENCE_ID_RE = /^[A-Za-z0-9._:-]{1,128}$/;
|
|
1381
|
+
var occurrenceInputSchema = z8.object({
|
|
1382
|
+
monitor_slug: z8.string().regex(SLUG_RE),
|
|
1383
|
+
occurrence_id: z8.string().regex(OCCURRENCE_ID_RE),
|
|
1384
|
+
due_at: z8.string().datetime({ offset: true }),
|
|
1385
|
+
environment: z8.string().trim().min(1).max(MONITOR_LIMITS.environmentMax).regex(/^[A-Za-z0-9._-]+$/).optional()
|
|
1386
|
+
});
|
|
1387
|
+
var occurrenceCancelSchema = occurrenceInputSchema.pick({ monitor_slug: true, occurrence_id: true, environment: true });
|
|
1388
|
+
var OCCURRENCE_PAST_SKEW_MS = 5 * 60000;
|
|
1389
|
+
var occurrenceRowSchema = z8.object({
|
|
1390
|
+
occurrence_id: z8.string().max(SIGNAL_LIMITS.occurrenceIdMax),
|
|
1391
|
+
environment: z8.string().max(MONITOR_LIMITS.environmentMax),
|
|
1392
|
+
state: z8.enum(OCCURRENCE_STATES),
|
|
1393
|
+
due_at: z8.string().datetime(),
|
|
1394
|
+
deadline_at: z8.string().datetime(),
|
|
1395
|
+
registered_at: z8.string().datetime(),
|
|
1396
|
+
started_at: z8.string().datetime().nullable(),
|
|
1397
|
+
last_signal_at: z8.string().datetime().nullable(),
|
|
1398
|
+
ended_at: z8.string().datetime().nullable(),
|
|
1399
|
+
stalled: z8.boolean()
|
|
1400
|
+
});
|
|
1401
|
+
var occurrencesResponseSchema = z8.object({
|
|
1402
|
+
occurrences: z8.array(occurrenceRowSchema).max(SIGNAL_LIMITS.occurrencesPageSize),
|
|
1403
|
+
pending: z8.number().int().nonnegative(),
|
|
1404
|
+
next_due_at: z8.string().datetime().nullable(),
|
|
1405
|
+
next_cursor: z8.string().max(64).nullable(),
|
|
1406
|
+
refused_24h: z8.number().int().nonnegative()
|
|
1407
|
+
});
|
|
1408
|
+
var signalSeriesSchema = z8.object({
|
|
1409
|
+
environment: z8.string().max(MONITOR_LIMITS.environmentMax),
|
|
1410
|
+
buckets: z8.array(z8.object({ minute: z8.string().datetime(), matched: z8.number().int().nonnegative(), violations: z8.number().int().nonnegative(), lossy: z8.boolean() })).max(1440),
|
|
1411
|
+
counted_through: z8.string().datetime().nullable()
|
|
1412
|
+
});
|
|
1413
|
+
var signalResponseSchema = z8.object({
|
|
1414
|
+
series: z8.array(signalSeriesSchema).max(SIGNAL_LIMITS.environmentsMax),
|
|
1415
|
+
runs: z8.array(z8.object({
|
|
1416
|
+
run_id: z8.string().max(SIGNAL_LIMITS.occurrenceIdMax),
|
|
1417
|
+
environment: z8.string().max(MONITOR_LIMITS.environmentMax),
|
|
1418
|
+
started_at: z8.string().datetime(),
|
|
1419
|
+
last_signal_at: z8.string().datetime(),
|
|
1420
|
+
stalled: z8.boolean()
|
|
1421
|
+
})).max(SIGNAL_LIMITS.occurrencesPageSize)
|
|
1422
|
+
});
|
|
1423
|
+
var backtestSettingsSchema = z8.union([countSettingsSchema, assertionSettingsSchema]);
|
|
1424
|
+
var backtestResponseSchema = z8.object({
|
|
1425
|
+
alerts: z8.number().int().nonnegative(),
|
|
1426
|
+
windows: z8.number().int().nonnegative(),
|
|
1427
|
+
violated_windows: z8.number().int().nonnegative(),
|
|
1428
|
+
first_at: z8.string().datetime().nullable(),
|
|
1429
|
+
last_at: z8.string().datetime().nullable(),
|
|
1430
|
+
days: z8.number().nonnegative(),
|
|
1431
|
+
matched_total: z8.number().int().nonnegative(),
|
|
1432
|
+
violations_total: z8.number().int().nonnegative()
|
|
1433
|
+
});
|
|
1434
|
+
|
|
1435
|
+
// ../src/shared/contracts/notifications.ts
|
|
1436
|
+
var NOTIFY_LIMITS = {
|
|
1437
|
+
policiesMax: 20,
|
|
1438
|
+
nameMax: 80,
|
|
1439
|
+
chainMax: 5,
|
|
1440
|
+
escalateMinutesMin: 5,
|
|
1441
|
+
escalateMinutesMax: 240,
|
|
1442
|
+
digestRowsMax: 50,
|
|
1443
|
+
slotSearchDays: 8
|
|
1444
|
+
};
|
|
1445
|
+
var HOLDABLE_SEVERITIES = ["medium", "low"];
|
|
1446
|
+
var DIGEST_MODES = ["off", "hourly", "daily"];
|
|
1447
|
+
var timeOfDay2 = z9.string().regex(/^([01]\d|2[0-3]):[0-5]\d$/);
|
|
1448
|
+
var unique = (xs) => new Set(xs).size === xs.length;
|
|
1449
|
+
var quietHoursSchema = z9.object({
|
|
1450
|
+
days: z9.array(weekdaySchema).min(1).max(7).refine(unique),
|
|
1451
|
+
start: timeOfDay2,
|
|
1452
|
+
end: timeOfDay2
|
|
1453
|
+
}).refine((q) => q.start !== q.end, { path: ["end"] });
|
|
1454
|
+
var policyInputSchema = z9.object({
|
|
1455
|
+
name: z9.string().trim().min(1).max(NOTIFY_LIMITS.nameMax).regex(/^[^\p{Cc}]*$/u),
|
|
1456
|
+
timezone: z9.string().trim().min(1).max(64).refine(validTimeZone),
|
|
1457
|
+
quietHours: quietHoursSchema.nullable(),
|
|
1458
|
+
quietSeverities: z9.array(z9.enum(HOLDABLE_SEVERITIES)).max(2).refine(unique),
|
|
1459
|
+
digest: z9.enum(DIGEST_MODES),
|
|
1460
|
+
digestAt: timeOfDay2.nullable(),
|
|
1461
|
+
digestSeverities: z9.array(z9.enum(HOLDABLE_SEVERITIES)).max(2).refine(unique),
|
|
1462
|
+
fallback: z9.array(z9.guid()).max(NOTIFY_LIMITS.chainMax).refine(unique),
|
|
1463
|
+
escalateAfterMinutes: z9.number().int().min(NOTIFY_LIMITS.escalateMinutesMin).max(NOTIFY_LIMITS.escalateMinutesMax).nullable(),
|
|
1464
|
+
escalation: z9.array(z9.guid()).max(NOTIFY_LIMITS.chainMax).refine(unique)
|
|
1465
|
+
}).superRefine((p, ctx) => {
|
|
1466
|
+
if (p.digest === "daily" !== (p.digestAt !== null))
|
|
1467
|
+
ctx.addIssue({ code: "custom", path: ["digestAt"], message: "digest_at" });
|
|
1468
|
+
if (p.escalateAfterMinutes !== null !== p.escalation.length > 0)
|
|
1469
|
+
ctx.addIssue({ code: "custom", path: ["escalation"], message: "escalation" });
|
|
1470
|
+
});
|
|
1471
|
+
var MIN = 60000;
|
|
1472
|
+
var HOUR = 60 * MIN;
|
|
1473
|
+
var DAY = 24 * HOUR;
|
|
1474
|
+
|
|
1475
|
+
// ../src/shared/contracts/api-ops/incidents.ts
|
|
1476
|
+
var incidentOnly = z10.object({ workspaceId: uuid, incidentId: uuid });
|
|
1477
|
+
var note = z10.string().trim().min(1).max(2000).regex(/^[^\u0000-\u0008\u000b\u000c\u000e-\u001f]*$/);
|
|
1478
|
+
var INCIDENT_KINDS = ["monitor", "uptime", "slo", "issue"];
|
|
1479
|
+
var INCIDENT_GROUP_BY = ["monitor", "project_env"];
|
|
1480
|
+
var incidentRuleInputSchema = z10.object({
|
|
1481
|
+
name: z10.string().trim().min(1).max(80).regex(/^[^\p{Cc}]*$/u),
|
|
1482
|
+
isEnabled: z10.boolean(),
|
|
1483
|
+
position: z10.number().int().min(0).max(1000).default(0),
|
|
1484
|
+
projectIds: z10.array(z10.number().int().positive()).max(50),
|
|
1485
|
+
environments: z10.array(z10.string().trim().min(1).max(64)).max(20),
|
|
1486
|
+
kinds: z10.array(z10.enum(INCIDENT_KINDS)).min(1).max(4),
|
|
1487
|
+
minSeverity: z10.enum(SEVERITIES),
|
|
1488
|
+
groupBy: z10.enum(INCIDENT_GROUP_BY),
|
|
1489
|
+
windowMinutes: z10.number().int().min(5).max(240),
|
|
1490
|
+
recoveryHoldMinutes: z10.number().int().min(0).max(1440)
|
|
1491
|
+
});
|
|
1492
|
+
var INCIDENT_INPUTS = {
|
|
1493
|
+
list: z10.object({
|
|
1494
|
+
workspaceId: uuid,
|
|
1495
|
+
limit: pageLimit,
|
|
1496
|
+
cursor,
|
|
1497
|
+
state: z10.enum(["active", "resolved", "all"]).default("all")
|
|
1498
|
+
}),
|
|
1499
|
+
incidentOnly,
|
|
1500
|
+
resolve: incidentOnly.extend({ note: note.max(500) }),
|
|
1501
|
+
note: incidentOnly.extend({ note }),
|
|
1502
|
+
update: incidentOnly.extend({
|
|
1503
|
+
title: z10.string().trim().min(1).max(120).regex(/^[^\p{Cc}]*$/u).optional(),
|
|
1504
|
+
ownerUserId: uuid.nullable().optional()
|
|
1505
|
+
}),
|
|
1506
|
+
workspace: z10.object({ workspaceId: uuid }),
|
|
1507
|
+
saveRule: z10.object({ workspaceId: uuid, ruleId: uuid.nullable(), input: incidentRuleInputSchema }),
|
|
1508
|
+
ruleOnly: z10.object({ workspaceId: uuid, ruleId: uuid }),
|
|
1509
|
+
savePolicy: z10.object({
|
|
1510
|
+
workspaceId: uuid,
|
|
1511
|
+
policyId: uuid.nullable(),
|
|
1512
|
+
isDefault: z10.boolean(),
|
|
1513
|
+
input: policyInputSchema
|
|
1514
|
+
}),
|
|
1515
|
+
policyOnly: z10.object({ workspaceId: uuid, policyId: uuid })
|
|
1516
|
+
};
|
|
1517
|
+
var I = INCIDENT_INPUTS;
|
|
1518
|
+
var w = "incidents:write";
|
|
1519
|
+
var INCIDENT_OPERATIONS = [
|
|
1520
|
+
op({
|
|
1521
|
+
id: "incidents.list",
|
|
1522
|
+
method: "GET",
|
|
1523
|
+
path: "/v1/incidents",
|
|
1524
|
+
scope: "incidents:read",
|
|
1525
|
+
sensitivity: "normal",
|
|
1526
|
+
kind: "read",
|
|
1527
|
+
rpcs: ["api_read_incidents"],
|
|
1528
|
+
input: I.list,
|
|
1529
|
+
workspace: true,
|
|
1530
|
+
idempotency: "none",
|
|
1531
|
+
paged: true,
|
|
1532
|
+
mcp: "reliability",
|
|
1533
|
+
summary: "Incidents (INC-n): state, severity and peak, owner, linked alert count; newest first.",
|
|
1534
|
+
ui: []
|
|
1535
|
+
}),
|
|
1536
|
+
op({
|
|
1537
|
+
id: "incidents.get",
|
|
1538
|
+
method: "GET",
|
|
1539
|
+
path: "/v1/incidents/{incident_id}",
|
|
1540
|
+
scope: "incidents:read",
|
|
1541
|
+
sensitivity: "normal",
|
|
1542
|
+
kind: "read",
|
|
1543
|
+
rpcs: ["api_read_incident"],
|
|
1544
|
+
input: I.incidentOnly,
|
|
1545
|
+
workspace: true,
|
|
1546
|
+
idempotency: "none",
|
|
1547
|
+
mcp: "reliability",
|
|
1548
|
+
summary: "One incident with its linked alerts, timeline (notes included) and message deliveries (`accepted` = the provider took it; only a person acknowledges).",
|
|
1549
|
+
ui: []
|
|
1550
|
+
}),
|
|
1551
|
+
op({
|
|
1552
|
+
id: "incidents.acknowledge",
|
|
1553
|
+
method: "POST",
|
|
1554
|
+
path: "/v1/incidents/{incident_id}/ack",
|
|
1555
|
+
scope: w,
|
|
1556
|
+
sensitivity: "normal",
|
|
1557
|
+
kind: "write",
|
|
1558
|
+
rpcs: ["acknowledge_incident"],
|
|
1559
|
+
input: I.incidentOnly,
|
|
1560
|
+
workspace: true,
|
|
1561
|
+
idempotency: "optional",
|
|
1562
|
+
mcp: "configure",
|
|
1563
|
+
summary: "Take ownership of an open incident; stops its escalation. Members and up.",
|
|
1564
|
+
ui: ["incidents#acknowledgeIncident"]
|
|
1565
|
+
}),
|
|
1566
|
+
op({
|
|
1567
|
+
id: "incidents.resolve",
|
|
1568
|
+
method: "POST",
|
|
1569
|
+
path: "/v1/incidents/{incident_id}/resolve",
|
|
1570
|
+
scope: w,
|
|
1571
|
+
sensitivity: "normal",
|
|
1572
|
+
kind: "write",
|
|
1573
|
+
rpcs: ["resolve_incident"],
|
|
1574
|
+
input: I.resolve,
|
|
1575
|
+
workspace: true,
|
|
1576
|
+
idempotency: "optional",
|
|
1577
|
+
mcp: "configure",
|
|
1578
|
+
summary: 'Close an incident by hand with a reason (1–500 characters); it is labelled "not verified".',
|
|
1579
|
+
ui: ["incidents#resolveIncident"]
|
|
1580
|
+
}),
|
|
1581
|
+
op({
|
|
1582
|
+
id: "incidents.note",
|
|
1583
|
+
method: "POST",
|
|
1584
|
+
path: "/v1/incidents/{incident_id}/notes",
|
|
1585
|
+
scope: w,
|
|
1586
|
+
sensitivity: "normal",
|
|
1587
|
+
kind: "write",
|
|
1588
|
+
rpcs: ["add_incident_note"],
|
|
1589
|
+
input: I.note,
|
|
1590
|
+
workspace: true,
|
|
1591
|
+
idempotency: "optional",
|
|
1592
|
+
mcp: "configure",
|
|
1593
|
+
summary: "Add a note to the incident timeline (plain text, ≤ 2,000 characters).",
|
|
1594
|
+
ui: ["incidents#addIncidentNote"]
|
|
1595
|
+
}),
|
|
1596
|
+
op({
|
|
1597
|
+
id: "incidents.update",
|
|
1598
|
+
method: "PATCH",
|
|
1599
|
+
path: "/v1/incidents/{incident_id}",
|
|
1600
|
+
scope: w,
|
|
1601
|
+
sensitivity: "normal",
|
|
1602
|
+
kind: "write",
|
|
1603
|
+
rpcs: ["update_incident"],
|
|
1604
|
+
input: I.update,
|
|
1605
|
+
workspace: true,
|
|
1606
|
+
idempotency: "none",
|
|
1607
|
+
mcp: "configure",
|
|
1608
|
+
summary: "Rename an incident or assign it to a member (`owner_user_id: null` clears it).",
|
|
1609
|
+
ui: ["incidents#updateIncident"]
|
|
1610
|
+
}),
|
|
1611
|
+
op({
|
|
1612
|
+
id: "incident_rules.list",
|
|
1613
|
+
method: "GET",
|
|
1614
|
+
path: "/v1/incident-rules",
|
|
1615
|
+
scope: "alerts:read",
|
|
1616
|
+
sensitivity: "normal",
|
|
1617
|
+
kind: "read",
|
|
1618
|
+
rpcs: ["api_read_incident_rules"],
|
|
1619
|
+
input: I.workspace,
|
|
1620
|
+
workspace: true,
|
|
1621
|
+
idempotency: "none",
|
|
1622
|
+
mcp: "investigate",
|
|
1623
|
+
summary: "Rules that turn alerts into incidents: match, grouping, window and recovery wait.",
|
|
1624
|
+
ui: []
|
|
1625
|
+
}),
|
|
1626
|
+
op({
|
|
1627
|
+
id: "incident_rules.save",
|
|
1628
|
+
method: "POST",
|
|
1629
|
+
path: "/v1/incident-rules",
|
|
1630
|
+
scope: "alerts:write",
|
|
1631
|
+
sensitivity: "normal",
|
|
1632
|
+
kind: "write",
|
|
1633
|
+
rpcs: ["save_incident_rule"],
|
|
1634
|
+
input: I.saveRule,
|
|
1635
|
+
workspace: true,
|
|
1636
|
+
idempotency: "optional",
|
|
1637
|
+
mcp: "configure",
|
|
1638
|
+
summary: "Create (`rule_id` null) or replace an incident rule. Admins.",
|
|
1639
|
+
ui: ["incidents#saveIncidentRule"]
|
|
1640
|
+
}),
|
|
1641
|
+
op({
|
|
1642
|
+
id: "incident_rules.delete",
|
|
1643
|
+
method: "DELETE",
|
|
1644
|
+
path: "/v1/incident-rules/{rule_id}",
|
|
1645
|
+
scope: "alerts:write",
|
|
1646
|
+
sensitivity: "normal",
|
|
1647
|
+
kind: "write",
|
|
1648
|
+
rpcs: ["delete_incident_rule"],
|
|
1649
|
+
input: I.ruleOnly,
|
|
1650
|
+
workspace: true,
|
|
1651
|
+
idempotency: "none",
|
|
1652
|
+
mcp: "configure",
|
|
1653
|
+
summary: "Delete an incident rule; open incidents stay as they are.",
|
|
1654
|
+
ui: ["incidents#deleteIncidentRule"]
|
|
1655
|
+
}),
|
|
1656
|
+
op({
|
|
1657
|
+
id: "notification_policies.list",
|
|
1658
|
+
method: "GET",
|
|
1659
|
+
path: "/v1/notification-policies",
|
|
1660
|
+
scope: "alerts:read",
|
|
1661
|
+
sensitivity: "normal",
|
|
1662
|
+
kind: "read",
|
|
1663
|
+
rpcs: ["api_read_notification_policies"],
|
|
1664
|
+
input: I.workspace,
|
|
1665
|
+
workspace: true,
|
|
1666
|
+
idempotency: "none",
|
|
1667
|
+
mcp: "investigate",
|
|
1668
|
+
summary: "Notification policies: quiet hours, digest, fallback chain and escalation.",
|
|
1669
|
+
ui: []
|
|
1670
|
+
}),
|
|
1671
|
+
op({
|
|
1672
|
+
id: "notification_policies.save",
|
|
1673
|
+
method: "POST",
|
|
1674
|
+
path: "/v1/notification-policies",
|
|
1675
|
+
scope: "alerts:write",
|
|
1676
|
+
sensitivity: "normal",
|
|
1677
|
+
kind: "write",
|
|
1678
|
+
rpcs: ["save_notification_policy"],
|
|
1679
|
+
input: I.savePolicy,
|
|
1680
|
+
workspace: true,
|
|
1681
|
+
idempotency: "optional",
|
|
1682
|
+
mcp: "configure",
|
|
1683
|
+
summary: "Create (`policy_id` null) or replace a policy. Critical and high are never held; chains use existing destinations only. Admins.",
|
|
1684
|
+
ui: ["incidents#saveNotificationPolicy"]
|
|
1685
|
+
}),
|
|
1686
|
+
op({
|
|
1687
|
+
id: "notification_policies.delete",
|
|
1688
|
+
method: "DELETE",
|
|
1689
|
+
path: "/v1/notification-policies/{policy_id}",
|
|
1690
|
+
scope: "alerts:write",
|
|
1691
|
+
sensitivity: "normal",
|
|
1692
|
+
kind: "write",
|
|
1693
|
+
rpcs: ["delete_notification_policy"],
|
|
1694
|
+
input: I.policyOnly,
|
|
1695
|
+
workspace: true,
|
|
1696
|
+
idempotency: "none",
|
|
1697
|
+
mcp: "configure",
|
|
1698
|
+
summary: "Delete a policy (not the default); its rules fall back to the default policy.",
|
|
1699
|
+
ui: ["incidents#deleteNotificationPolicy"]
|
|
1700
|
+
})
|
|
1701
|
+
];
|
|
1702
|
+
|
|
1703
|
+
// ../src/shared/contracts/api-ops/monitors.ts
|
|
1704
|
+
import { z as z15 } from "zod";
|
|
1705
|
+
|
|
1706
|
+
// ../src/shared/contracts/heartbeat.ts
|
|
1707
|
+
import { z as z12 } from "zod";
|
|
1121
1708
|
|
|
1122
1709
|
// ../src/shared/contracts/signed-message.ts
|
|
1123
|
-
import { z as
|
|
1124
|
-
var nodeIdSchema =
|
|
1125
|
-
var signedEnvelopeSchema =
|
|
1710
|
+
import { z as z11 } from "zod";
|
|
1711
|
+
var nodeIdSchema = z11.guid();
|
|
1712
|
+
var signedEnvelopeSchema = z11.object({
|
|
1126
1713
|
node_id: nodeIdSchema,
|
|
1127
|
-
ts:
|
|
1128
|
-
nonce:
|
|
1129
|
-
payload:
|
|
1130
|
-
sig:
|
|
1714
|
+
ts: z11.number().int().positive(),
|
|
1715
|
+
nonce: z11.string().regex(/^[A-Za-z0-9_-]{16,64}$/),
|
|
1716
|
+
payload: z11.record(z11.string(), z11.unknown()),
|
|
1717
|
+
sig: z11.string().regex(/^[A-Za-z0-9_-]{86}$/)
|
|
1131
1718
|
});
|
|
1132
1719
|
|
|
1133
1720
|
// ../src/shared/contracts/heartbeat.ts
|
|
@@ -1165,78 +1752,78 @@ var HEARTBEAT_LIMITS = {
|
|
|
1165
1752
|
diagnosticsPerRun: 5
|
|
1166
1753
|
};
|
|
1167
1754
|
var PAUSED_FOREVER_MS = Date.parse("9999-12-31T00:00:00.000Z");
|
|
1168
|
-
var uuid2 =
|
|
1169
|
-
var ms =
|
|
1170
|
-
var hex64 =
|
|
1171
|
-
var envName2 =
|
|
1172
|
-
var heartbeatMonitorConfigSchema =
|
|
1755
|
+
var uuid2 = z12.guid();
|
|
1756
|
+
var ms = z12.number().int().nonnegative();
|
|
1757
|
+
var hex64 = z12.string().regex(/^[0-9a-f]{64}$/);
|
|
1758
|
+
var envName2 = z12.string().min(1).max(MONITOR_LIMITS.environmentMax);
|
|
1759
|
+
var heartbeatMonitorConfigSchema = z12.object({
|
|
1173
1760
|
id: uuid2,
|
|
1174
|
-
project_id:
|
|
1175
|
-
slug:
|
|
1761
|
+
project_id: z12.number().int().positive(),
|
|
1762
|
+
slug: z12.string().regex(SLUG_RE),
|
|
1176
1763
|
environment: envName2,
|
|
1177
1764
|
schedule: scheduleSchema,
|
|
1178
|
-
timezone:
|
|
1179
|
-
grace_min:
|
|
1180
|
-
max_runtime_min:
|
|
1181
|
-
failure_threshold:
|
|
1182
|
-
recovery_threshold:
|
|
1765
|
+
timezone: z12.string().min(1).max(64),
|
|
1766
|
+
grace_min: z12.number().int().min(MONITOR_LIMITS.checkinMarginMin).max(MONITOR_LIMITS.checkinMarginMax),
|
|
1767
|
+
max_runtime_min: z12.number().int().min(MONITOR_LIMITS.maxRuntimeMin).max(MONITOR_LIMITS.maxRuntimeMax),
|
|
1768
|
+
failure_threshold: z12.number().int().min(MONITOR_LIMITS.thresholdMin).max(MONITOR_LIMITS.thresholdMax),
|
|
1769
|
+
recovery_threshold: z12.number().int().min(MONITOR_LIMITS.thresholdMin).max(MONITOR_LIMITS.thresholdMax),
|
|
1183
1770
|
paused_until: ms.nullable(),
|
|
1184
1771
|
created_at: ms
|
|
1185
1772
|
});
|
|
1186
|
-
var heartbeatTokenConfigSchema =
|
|
1773
|
+
var heartbeatTokenConfigSchema = z12.object({
|
|
1187
1774
|
id: uuid2,
|
|
1188
1775
|
monitor_id: uuid2,
|
|
1189
1776
|
hash: hex64,
|
|
1190
1777
|
expires_at: ms.nullable()
|
|
1191
1778
|
});
|
|
1192
|
-
var heartbeatSyncSchema =
|
|
1193
|
-
v:
|
|
1779
|
+
var heartbeatSyncSchema = z12.object({
|
|
1780
|
+
v: z12.literal(1),
|
|
1194
1781
|
workspace_id: uuid2,
|
|
1195
|
-
route:
|
|
1196
|
-
revision:
|
|
1197
|
-
workspace_status:
|
|
1198
|
-
ingest_kill:
|
|
1199
|
-
limits:
|
|
1200
|
-
check_in_rate_per_sec:
|
|
1201
|
-
check_in_burst:
|
|
1202
|
-
monthly_check_in_cap:
|
|
1203
|
-
}),
|
|
1204
|
-
projects:
|
|
1205
|
-
monitors:
|
|
1206
|
-
tokens:
|
|
1207
|
-
});
|
|
1208
|
-
var signedHeartbeatSyncSchema =
|
|
1209
|
-
body:
|
|
1210
|
-
ts:
|
|
1211
|
-
kid:
|
|
1212
|
-
sig:
|
|
1213
|
-
});
|
|
1214
|
-
var heartbeatHourSchema =
|
|
1782
|
+
route: z12.string().regex(PING_ROUTE_RE),
|
|
1783
|
+
revision: z12.number().int().positive(),
|
|
1784
|
+
workspace_status: z12.enum(["active", "suspended", "deleting"]),
|
|
1785
|
+
ingest_kill: z12.boolean(),
|
|
1786
|
+
limits: z12.object({
|
|
1787
|
+
check_in_rate_per_sec: z12.number().int().positive(),
|
|
1788
|
+
check_in_burst: z12.number().int().positive(),
|
|
1789
|
+
monthly_check_in_cap: z12.number().int().positive()
|
|
1790
|
+
}),
|
|
1791
|
+
projects: z12.array(z12.object({ id: z12.number().int().positive(), node_id: nodeIdSchema.nullable() })).max(1000),
|
|
1792
|
+
monitors: z12.array(heartbeatMonitorConfigSchema).max(HEARTBEAT_LIMITS.maxMonitorsPerWorkspace),
|
|
1793
|
+
tokens: z12.array(heartbeatTokenConfigSchema).max(HEARTBEAT_LIMITS.maxMonitorsPerWorkspace * 2)
|
|
1794
|
+
});
|
|
1795
|
+
var signedHeartbeatSyncSchema = z12.object({
|
|
1796
|
+
body: z12.string().min(2).max(4 * 1024 * 1024),
|
|
1797
|
+
ts: z12.number().int().positive(),
|
|
1798
|
+
kid: z12.string().regex(/^[A-Za-z0-9_-]{1,40}$/),
|
|
1799
|
+
sig: z12.string().regex(/^[A-Za-z0-9_-]{86}$/)
|
|
1800
|
+
});
|
|
1801
|
+
var heartbeatHourSchema = z12.object({
|
|
1215
1802
|
monitor_id: uuid2,
|
|
1216
|
-
hour:
|
|
1217
|
-
ok:
|
|
1218
|
-
failed:
|
|
1219
|
-
started:
|
|
1220
|
-
missed:
|
|
1221
|
-
logs:
|
|
1222
|
-
});
|
|
1223
|
-
var heartbeatReportSchema =
|
|
1224
|
-
v:
|
|
1803
|
+
hour: z12.string().datetime(),
|
|
1804
|
+
ok: z12.number().int().nonnegative(),
|
|
1805
|
+
failed: z12.number().int().nonnegative(),
|
|
1806
|
+
started: z12.number().int().nonnegative(),
|
|
1807
|
+
missed: z12.number().int().nonnegative(),
|
|
1808
|
+
logs: z12.number().int().nonnegative()
|
|
1809
|
+
});
|
|
1810
|
+
var heartbeatReportSchema = z12.object({
|
|
1811
|
+
v: z12.literal(1),
|
|
1225
1812
|
workspace_id: uuid2,
|
|
1226
|
-
route:
|
|
1227
|
-
revision:
|
|
1228
|
-
sent_at:
|
|
1229
|
-
incidents:
|
|
1230
|
-
statuses:
|
|
1231
|
-
hours:
|
|
1232
|
-
token_uses:
|
|
1813
|
+
route: z12.string().regex(PING_ROUTE_RE),
|
|
1814
|
+
revision: z12.number().int().nonnegative(),
|
|
1815
|
+
sent_at: z12.string().datetime(),
|
|
1816
|
+
incidents: z12.array(monitorIncidentSchema).max(HEARTBEAT_LIMITS.reportMaxIncidents),
|
|
1817
|
+
statuses: z12.array(monitorStatusSchema).max(HEARTBEAT_LIMITS.reportMaxStatuses),
|
|
1818
|
+
hours: z12.array(heartbeatHourSchema).max(HEARTBEAT_LIMITS.reportMaxHours),
|
|
1819
|
+
token_uses: z12.array(z12.object({ token_id: uuid2, last_used_at: z12.string().datetime() })).max(HEARTBEAT_LIMITS.maxMonitorsPerWorkspace * 2)
|
|
1233
1820
|
});
|
|
1234
1821
|
var ENCODER = new TextEncoder;
|
|
1235
1822
|
var UTF8 = new TextDecoder("utf-8", { fatal: false, ignoreBOM: false });
|
|
1236
1823
|
var TOKEN_IN_TEXT = new RegExp(PING_TOKEN_PATTERN, "g");
|
|
1237
1824
|
|
|
1238
1825
|
// ../src/shared/contracts/slo.ts
|
|
1239
|
-
import { z as
|
|
1826
|
+
import { z as z13 } from "zod";
|
|
1240
1827
|
|
|
1241
1828
|
// ../src/shared/contracts/vocab/slo.ts
|
|
1242
1829
|
var SLO_SOURCES = ["uptime", "monitor", "heartbeat", "spans"];
|
|
@@ -1268,17 +1855,17 @@ var SLO_SOURCE_META = {
|
|
|
1268
1855
|
heartbeat: { provenance: "ping_token", estimated: false, slis: ["availability"], budgeting: "Occurrences" },
|
|
1269
1856
|
spans: { provenance: "ingest_key", estimated: true, slis: ["availability", "latency"], budgeting: "Occurrences" }
|
|
1270
1857
|
};
|
|
1271
|
-
var nodeSloSchema =
|
|
1272
|
-
slo_id:
|
|
1273
|
-
project_id:
|
|
1274
|
-
source:
|
|
1275
|
-
sli:
|
|
1276
|
-
monitor_id:
|
|
1277
|
-
environment:
|
|
1278
|
-
service:
|
|
1279
|
-
operation:
|
|
1280
|
-
latency_threshold_ms:
|
|
1281
|
-
public_sources:
|
|
1858
|
+
var nodeSloSchema = z13.object({
|
|
1859
|
+
slo_id: z13.guid(),
|
|
1860
|
+
project_id: z13.number().int().positive(),
|
|
1861
|
+
source: z13.enum(["monitor", "spans"]),
|
|
1862
|
+
sli: z13.enum(SLO_SLIS),
|
|
1863
|
+
monitor_id: z13.guid().optional(),
|
|
1864
|
+
environment: z13.string().min(1).max(SLO_LIMITS.environmentMaxChars).optional(),
|
|
1865
|
+
service: z13.string().min(1).max(128).optional(),
|
|
1866
|
+
operation: z13.string().min(1).max(256).optional(),
|
|
1867
|
+
latency_threshold_ms: z13.number().int().min(1).max(60000).optional(),
|
|
1868
|
+
public_sources: z13.boolean()
|
|
1282
1869
|
}).superRefine((v, ctx) => {
|
|
1283
1870
|
if (v.source === "monitor" && (!v.monitor_id || v.sli !== "availability"))
|
|
1284
1871
|
ctx.addIssue({ code: "custom", path: ["monitor_id"], message: "INVALID_INPUT" });
|
|
@@ -1287,27 +1874,27 @@ var nodeSloSchema = z9.object({
|
|
|
1287
1874
|
if (v.sli === "latency" !== (v.latency_threshold_ms !== undefined))
|
|
1288
1875
|
ctx.addIssue({ code: "custom", path: ["latency_threshold_ms"], message: "INVALID_INPUT" });
|
|
1289
1876
|
});
|
|
1290
|
-
var sliCountsSchema =
|
|
1291
|
-
minute:
|
|
1292
|
-
items:
|
|
1293
|
-
});
|
|
1294
|
-
var sloInputSchema =
|
|
1295
|
-
name:
|
|
1296
|
-
description:
|
|
1297
|
-
source:
|
|
1298
|
-
sourceRef:
|
|
1299
|
-
id:
|
|
1300
|
-
projectId:
|
|
1301
|
-
service:
|
|
1302
|
-
operation:
|
|
1303
|
-
environment:
|
|
1304
|
-
}),
|
|
1305
|
-
sli:
|
|
1306
|
-
latencyThresholdMs:
|
|
1307
|
-
objective:
|
|
1308
|
-
windowDays:
|
|
1309
|
-
alertPolicy:
|
|
1310
|
-
allowPublicSources:
|
|
1877
|
+
var sliCountsSchema = z13.object({
|
|
1878
|
+
minute: z13.string().datetime(),
|
|
1879
|
+
items: z13.array(z13.object({ slo_id: z13.guid(), good: z13.number().int().min(0), total: z13.number().int().min(0) }).refine((x) => x.good <= x.total, { message: "INVALID_INPUT" })).max(SLO_LIMITS.sliItemsPerMessage)
|
|
1880
|
+
});
|
|
1881
|
+
var sloInputSchema = z13.object({
|
|
1882
|
+
name: z13.string().trim().min(1).max(SLO_LIMITS.nameMaxChars),
|
|
1883
|
+
description: z13.string().max(SLO_LIMITS.descriptionMaxChars).default(""),
|
|
1884
|
+
source: z13.enum(SLO_SOURCES),
|
|
1885
|
+
sourceRef: z13.object({
|
|
1886
|
+
id: z13.guid().optional(),
|
|
1887
|
+
projectId: z13.number().int().positive().optional(),
|
|
1888
|
+
service: z13.string().max(128).optional(),
|
|
1889
|
+
operation: z13.string().max(256).optional(),
|
|
1890
|
+
environment: z13.string().max(SLO_LIMITS.environmentMaxChars).optional()
|
|
1891
|
+
}),
|
|
1892
|
+
sli: z13.enum(SLO_SLIS),
|
|
1893
|
+
latencyThresholdMs: z13.number().int().min(1).max(60000).nullable(),
|
|
1894
|
+
objective: z13.number().min(SLO_LIMITS.objectiveMin).max(SLO_LIMITS.objectiveMax),
|
|
1895
|
+
windowDays: z13.union([z13.literal(7), z13.literal(28), z13.literal(30)]),
|
|
1896
|
+
alertPolicy: z13.enum(SLO_ALERT_POLICIES),
|
|
1897
|
+
allowPublicSources: z13.boolean().default(false)
|
|
1311
1898
|
}).superRefine((v, ctx) => {
|
|
1312
1899
|
if (!SLO_SOURCE_META[v.source].slis.includes(v.sli))
|
|
1313
1900
|
ctx.addIssue({ code: "custom", path: ["sli"], message: "INVALID_INPUT" });
|
|
@@ -1322,7 +1909,7 @@ var sloInputSchema = z9.object({
|
|
|
1322
1909
|
});
|
|
1323
1910
|
|
|
1324
1911
|
// ../src/shared/contracts/uptime.ts
|
|
1325
|
-
import { z as
|
|
1912
|
+
import { z as z14 } from "zod";
|
|
1326
1913
|
|
|
1327
1914
|
// ../src/shared/contracts/vocab/uptime.ts
|
|
1328
1915
|
var UPTIME_STATUSES = ["up", "degraded", "down", "unknown", "paused", "pending"];
|
|
@@ -1395,51 +1982,51 @@ function isForbiddenHeader(name) {
|
|
|
1395
1982
|
const n = name.trim().toLowerCase();
|
|
1396
1983
|
return UPTIME_FORBIDDEN_HEADERS.includes(n) || n.startsWith("proxy-") || n.startsWith("sec-");
|
|
1397
1984
|
}
|
|
1398
|
-
var text =
|
|
1399
|
-
var statusRange =
|
|
1400
|
-
var assertionSchema =
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
type:
|
|
1406
|
-
pointer:
|
|
1407
|
-
op:
|
|
1408
|
-
value:
|
|
1409
|
-
}),
|
|
1410
|
-
|
|
1411
|
-
type:
|
|
1412
|
-
name:
|
|
1413
|
-
op:
|
|
1414
|
-
value:
|
|
1415
|
-
}),
|
|
1416
|
-
|
|
1417
|
-
|
|
1985
|
+
var text = z14.string().min(1).max(UPTIME_LIMITS.assertionTextMax);
|
|
1986
|
+
var statusRange = z14.string().regex(/^[1-5][0-9]{2}(-[1-5][0-9]{2})?$/);
|
|
1987
|
+
var assertionSchema = z14.discriminatedUnion("type", [
|
|
1988
|
+
z14.object({ type: z14.literal("status"), in: z14.array(statusRange).min(1).max(10) }),
|
|
1989
|
+
z14.object({ type: z14.literal("body_contains"), value: text, case_sensitive: z14.boolean().default(true) }),
|
|
1990
|
+
z14.object({ type: z14.literal("body_not_contains"), value: text, case_sensitive: z14.boolean().default(true) }),
|
|
1991
|
+
z14.object({
|
|
1992
|
+
type: z14.literal("json_pointer"),
|
|
1993
|
+
pointer: z14.string().max(256).regex(/^(\/([^~/]|~0|~1)*)*$/),
|
|
1994
|
+
op: z14.enum(["exists", "equals", "type"]),
|
|
1995
|
+
value: z14.string().max(UPTIME_LIMITS.assertionTextMax).optional()
|
|
1996
|
+
}),
|
|
1997
|
+
z14.object({
|
|
1998
|
+
type: z14.literal("header"),
|
|
1999
|
+
name: z14.string().min(1).max(UPTIME_LIMITS.headerNameMax).regex(/^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/),
|
|
2000
|
+
op: z14.enum(["equals", "contains", "exists"]),
|
|
2001
|
+
value: z14.string().max(UPTIME_LIMITS.assertionTextMax).optional()
|
|
2002
|
+
}),
|
|
2003
|
+
z14.object({ type: z14.literal("latency_ms"), lt: z14.number().int().min(1).max(60000) }),
|
|
2004
|
+
z14.object({ type: z14.literal("tls_valid") })
|
|
1418
2005
|
]);
|
|
1419
|
-
var header =
|
|
1420
|
-
name:
|
|
1421
|
-
value:
|
|
1422
|
-
});
|
|
1423
|
-
var uptimeCheckInputSchema =
|
|
1424
|
-
projectId:
|
|
1425
|
-
name:
|
|
1426
|
-
kind:
|
|
1427
|
-
url:
|
|
1428
|
-
host:
|
|
1429
|
-
port:
|
|
1430
|
-
method:
|
|
1431
|
-
headers:
|
|
1432
|
-
followRedirects:
|
|
1433
|
-
timeoutMs:
|
|
1434
|
-
intervalSeconds:
|
|
1435
|
-
regions:
|
|
1436
|
-
assertions:
|
|
1437
|
-
failureThreshold:
|
|
1438
|
-
recoveryThreshold:
|
|
1439
|
-
certWarningDays:
|
|
1440
|
-
environment:
|
|
1441
|
-
strictMetadata:
|
|
1442
|
-
evidenceOnFailure:
|
|
2006
|
+
var header = z14.object({
|
|
2007
|
+
name: z14.string().min(1).max(UPTIME_LIMITS.headerNameMax).regex(/^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/),
|
|
2008
|
+
value: z14.string().max(UPTIME_LIMITS.headerValueMax).regex(/^[^\r\n\u0000]*$/)
|
|
2009
|
+
});
|
|
2010
|
+
var uptimeCheckInputSchema = z14.object({
|
|
2011
|
+
projectId: z14.number().int().positive(),
|
|
2012
|
+
name: z14.string().trim().min(1).max(UPTIME_LIMITS.nameMaxChars),
|
|
2013
|
+
kind: z14.enum(UPTIME_KINDS),
|
|
2014
|
+
url: z14.string().max(UPTIME_LIMITS.urlMaxChars).nullable(),
|
|
2015
|
+
host: z14.string().max(253).nullable(),
|
|
2016
|
+
port: z14.number().int().min(1).max(65535).nullable(),
|
|
2017
|
+
method: z14.enum(UPTIME_METHODS).default("GET"),
|
|
2018
|
+
headers: z14.array(header).max(UPTIME_LIMITS.headersMax).default([]),
|
|
2019
|
+
followRedirects: z14.boolean().default(false),
|
|
2020
|
+
timeoutMs: z14.number().int().min(UPTIME_LIMITS.timeoutMs.min).max(UPTIME_LIMITS.timeoutMs.max),
|
|
2021
|
+
intervalSeconds: z14.number().int().refine((n) => UPTIME_INTERVALS.includes(n)),
|
|
2022
|
+
regions: z14.array(z14.enum(UPTIME_REGIONS)).min(UPTIME_LIMITS.minRegions).max(UPTIME_REGIONS.length),
|
|
2023
|
+
assertions: z14.array(assertionSchema).max(UPTIME_LIMITS.assertionsMax).default([]),
|
|
2024
|
+
failureThreshold: z14.number().int().min(1).max(5),
|
|
2025
|
+
recoveryThreshold: z14.number().int().min(1).max(5),
|
|
2026
|
+
certWarningDays: z14.number().int().min(1).max(60),
|
|
2027
|
+
environment: z14.string().trim().max(64).default(""),
|
|
2028
|
+
strictMetadata: z14.boolean().default(false),
|
|
2029
|
+
evidenceOnFailure: z14.boolean().default(true)
|
|
1443
2030
|
}).superRefine((v, ctx) => {
|
|
1444
2031
|
if (v.kind === "http" && !v.url)
|
|
1445
2032
|
ctx.addIssue({ code: "custom", path: ["url"], message: "INVALID_INPUT" });
|
|
@@ -1450,237 +2037,243 @@ var uptimeCheckInputSchema = z10.object({
|
|
|
1450
2037
|
if (v.headers.some((h) => isForbiddenHeader(h.name)))
|
|
1451
2038
|
ctx.addIssue({ code: "custom", path: ["headers"], message: "UPTIME_HEADER_FORBIDDEN" });
|
|
1452
2039
|
});
|
|
1453
|
-
var uptimeDefinitionSchema =
|
|
1454
|
-
check_id:
|
|
1455
|
-
workspace_id:
|
|
1456
|
-
project_id:
|
|
1457
|
-
revision:
|
|
1458
|
-
kind:
|
|
1459
|
-
url:
|
|
1460
|
-
host:
|
|
1461
|
-
port:
|
|
1462
|
-
method:
|
|
1463
|
-
headers:
|
|
1464
|
-
follow_redirects:
|
|
1465
|
-
timeout_ms:
|
|
1466
|
-
interval_seconds:
|
|
1467
|
-
regions:
|
|
1468
|
-
assertions:
|
|
1469
|
-
failure_threshold:
|
|
1470
|
-
recovery_threshold:
|
|
1471
|
-
cert_warning_days:
|
|
1472
|
-
strict_metadata:
|
|
1473
|
-
evidence_on_failure:
|
|
1474
|
-
paused_until:
|
|
1475
|
-
muted_until:
|
|
1476
|
-
});
|
|
1477
|
-
var timingsSchema =
|
|
1478
|
-
dns_ms:
|
|
1479
|
-
connect_ms:
|
|
1480
|
-
tls_ms:
|
|
1481
|
-
ttfb_ms:
|
|
1482
|
-
download_ms:
|
|
1483
|
-
total_ms:
|
|
1484
|
-
});
|
|
1485
|
-
var probeResultSchema =
|
|
1486
|
-
check_id:
|
|
1487
|
-
revision:
|
|
1488
|
-
slot:
|
|
1489
|
-
region:
|
|
1490
|
-
run_now:
|
|
1491
|
-
scheduled_at:
|
|
1492
|
-
started_at:
|
|
1493
|
-
outcome:
|
|
1494
|
-
reason:
|
|
1495
|
-
reason_group:
|
|
1496
|
-
status_code:
|
|
2040
|
+
var uptimeDefinitionSchema = z14.object({
|
|
2041
|
+
check_id: z14.guid(),
|
|
2042
|
+
workspace_id: z14.guid(),
|
|
2043
|
+
project_id: z14.number().int().positive(),
|
|
2044
|
+
revision: z14.number().int().nonnegative(),
|
|
2045
|
+
kind: z14.enum(UPTIME_KINDS),
|
|
2046
|
+
url: z14.string().max(UPTIME_LIMITS.urlMaxChars).nullable(),
|
|
2047
|
+
host: z14.string().max(253).nullable(),
|
|
2048
|
+
port: z14.number().int().min(1).max(65535).nullable(),
|
|
2049
|
+
method: z14.enum(UPTIME_METHODS),
|
|
2050
|
+
headers: z14.array(header).max(UPTIME_LIMITS.headersMax),
|
|
2051
|
+
follow_redirects: z14.boolean(),
|
|
2052
|
+
timeout_ms: z14.number().int().min(UPTIME_LIMITS.timeoutMs.min).max(UPTIME_LIMITS.timeoutMs.max),
|
|
2053
|
+
interval_seconds: z14.number().int().positive(),
|
|
2054
|
+
regions: z14.array(z14.enum(UPTIME_REGIONS)).min(1).max(3),
|
|
2055
|
+
assertions: z14.array(assertionSchema).max(UPTIME_LIMITS.assertionsMax),
|
|
2056
|
+
failure_threshold: z14.number().int().min(1).max(5),
|
|
2057
|
+
recovery_threshold: z14.number().int().min(1).max(5),
|
|
2058
|
+
cert_warning_days: z14.number().int().min(1).max(60),
|
|
2059
|
+
strict_metadata: z14.boolean(),
|
|
2060
|
+
evidence_on_failure: z14.boolean(),
|
|
2061
|
+
paused_until: z14.string().nullable(),
|
|
2062
|
+
muted_until: z14.string().nullable()
|
|
2063
|
+
});
|
|
2064
|
+
var timingsSchema = z14.object({
|
|
2065
|
+
dns_ms: z14.number().nonnegative().max(60000).nullable(),
|
|
2066
|
+
connect_ms: z14.number().nonnegative().max(60000).nullable(),
|
|
2067
|
+
tls_ms: z14.number().nonnegative().max(60000).nullable(),
|
|
2068
|
+
ttfb_ms: z14.number().nonnegative().max(60000).nullable(),
|
|
2069
|
+
download_ms: z14.number().nonnegative().max(60000).nullable(),
|
|
2070
|
+
total_ms: z14.number().nonnegative().max(60000)
|
|
2071
|
+
});
|
|
2072
|
+
var probeResultSchema = z14.object({
|
|
2073
|
+
check_id: z14.guid(),
|
|
2074
|
+
revision: z14.number().int().nonnegative(),
|
|
2075
|
+
slot: z14.number().int().nonnegative(),
|
|
2076
|
+
region: z14.enum(UPTIME_REGIONS),
|
|
2077
|
+
run_now: z14.string().max(64).optional(),
|
|
2078
|
+
scheduled_at: z14.number().int().positive(),
|
|
2079
|
+
started_at: z14.number().int().positive(),
|
|
2080
|
+
outcome: z14.enum(UPTIME_OUTCOMES),
|
|
2081
|
+
reason: z14.enum(UPTIME_REASONS).nullable(),
|
|
2082
|
+
reason_group: z14.enum(UPTIME_REASON_GROUPS).nullable(),
|
|
2083
|
+
status_code: z14.number().int().min(100).max(599).nullable(),
|
|
1497
2084
|
timings: timingsSchema.nullable(),
|
|
1498
|
-
ip_family:
|
|
1499
|
-
http_version:
|
|
1500
|
-
cert_not_after:
|
|
1501
|
-
cert_issuer:
|
|
1502
|
-
cert_expiring:
|
|
1503
|
-
evidence_sealed:
|
|
1504
|
-
});
|
|
1505
|
-
var probeIdSchema =
|
|
1506
|
-
var resultBatchSchema =
|
|
1507
|
-
v:
|
|
2085
|
+
ip_family: z14.enum(["v4", "v6"]).nullable(),
|
|
2086
|
+
http_version: z14.string().max(8).nullable(),
|
|
2087
|
+
cert_not_after: z14.number().int().positive().nullable(),
|
|
2088
|
+
cert_issuer: z14.string().max(200).nullable(),
|
|
2089
|
+
cert_expiring: z14.boolean(),
|
|
2090
|
+
evidence_sealed: z14.string().max(16384).nullable()
|
|
2091
|
+
});
|
|
2092
|
+
var probeIdSchema = z14.string().regex(/^probe-(eu|us|ap)-[a-z0-9]{4,16}$/);
|
|
2093
|
+
var resultBatchSchema = z14.object({
|
|
2094
|
+
v: z14.literal(1),
|
|
1508
2095
|
probe_id: probeIdSchema,
|
|
1509
|
-
region:
|
|
1510
|
-
version:
|
|
1511
|
-
sent_at:
|
|
1512
|
-
results:
|
|
1513
|
-
stats:
|
|
2096
|
+
region: z14.enum(UPTIME_REGIONS),
|
|
2097
|
+
version: z14.string().max(40),
|
|
2098
|
+
sent_at: z14.number().int().positive(),
|
|
2099
|
+
results: z14.array(probeResultSchema).max(UPTIME_LIMITS.resultsBatchMax),
|
|
2100
|
+
stats: z14.object({ lag_p99_ms: z14.number().nonnegative(), checks_per_min: z14.number().nonnegative() })
|
|
1514
2101
|
});
|
|
1515
2102
|
var assignmentSchema = uptimeDefinitionSchema.omit({ workspace_id: true, paused_until: true, muted_until: true }).extend({
|
|
1516
|
-
seal_public_key:
|
|
1517
|
-
});
|
|
1518
|
-
var assignmentsSchema =
|
|
1519
|
-
v:
|
|
1520
|
-
region:
|
|
1521
|
-
revision:
|
|
1522
|
-
issued_at:
|
|
1523
|
-
checks:
|
|
1524
|
-
denied_hosts:
|
|
1525
|
-
run_now:
|
|
1526
|
-
});
|
|
1527
|
-
var uuid3 =
|
|
1528
|
-
var b64key =
|
|
1529
|
-
var iso2 =
|
|
1530
|
-
var uptimeSyncSchema =
|
|
1531
|
-
v:
|
|
2103
|
+
seal_public_key: z14.string().regex(/^[A-Za-z0-9_-]{43}$/).nullable()
|
|
2104
|
+
});
|
|
2105
|
+
var assignmentsSchema = z14.object({
|
|
2106
|
+
v: z14.literal(1),
|
|
2107
|
+
region: z14.enum(UPTIME_REGIONS),
|
|
2108
|
+
revision: z14.number().int().nonnegative(),
|
|
2109
|
+
issued_at: z14.number().int().positive(),
|
|
2110
|
+
checks: z14.array(assignmentSchema).max(50000),
|
|
2111
|
+
denied_hosts: z14.array(z14.string().max(253)).max(1e4),
|
|
2112
|
+
run_now: z14.array(z14.object({ id: z14.string().max(64), check_id: z14.guid(), expires_at: z14.number().int() })).max(500)
|
|
2113
|
+
});
|
|
2114
|
+
var uuid3 = z14.guid();
|
|
2115
|
+
var b64key = z14.string().regex(/^[A-Za-z0-9_-]{43}$/);
|
|
2116
|
+
var iso2 = z14.string().datetime();
|
|
2117
|
+
var uptimeSyncSchema = z14.object({
|
|
2118
|
+
v: z14.literal(1),
|
|
1532
2119
|
workspace_id: uuid3,
|
|
1533
|
-
revision:
|
|
1534
|
-
workspace_status:
|
|
1535
|
-
suspended:
|
|
1536
|
-
checks:
|
|
1537
|
-
projects:
|
|
1538
|
-
});
|
|
1539
|
-
var uptimeReconcileSchema =
|
|
1540
|
-
v:
|
|
1541
|
-
as_of:
|
|
1542
|
-
workspace_ids:
|
|
1543
|
-
heartbeat_routes:
|
|
1544
|
-
});
|
|
1545
|
-
var probeDirectorySyncSchema =
|
|
1546
|
-
v:
|
|
1547
|
-
revision:
|
|
1548
|
-
probes:
|
|
1549
|
-
denied_hosts:
|
|
1550
|
-
});
|
|
1551
|
-
var runNowRequestSchema =
|
|
1552
|
-
var signedAssignmentsSchema =
|
|
1553
|
-
var uptimeRegionStateSchema =
|
|
1554
|
-
region:
|
|
1555
|
-
outcome:
|
|
1556
|
-
reason:
|
|
1557
|
-
status_code:
|
|
1558
|
-
total_ms:
|
|
2120
|
+
revision: z14.number().int().positive(),
|
|
2121
|
+
workspace_status: z14.enum(["active", "suspended", "deleting"]),
|
|
2122
|
+
suspended: z14.boolean(),
|
|
2123
|
+
checks: z14.array(uptimeDefinitionSchema).max(UPTIME_LIMITS.maxChecksPerWorkspace),
|
|
2124
|
+
projects: z14.array(z14.object({ id: z14.number().int().positive(), node_id: z14.guid().nullable(), seal_public_key: b64key.nullable() })).max(1000)
|
|
2125
|
+
});
|
|
2126
|
+
var uptimeReconcileSchema = z14.object({
|
|
2127
|
+
v: z14.literal(1),
|
|
2128
|
+
as_of: z14.number().int().positive(),
|
|
2129
|
+
workspace_ids: z14.array(uuid3).max(UPTIME_LIMITS.reconcileMaxWorkspaces),
|
|
2130
|
+
heartbeat_routes: z14.array(z14.string().regex(PING_ROUTE_RE)).max(UPTIME_LIMITS.reconcileMaxWorkspaces).optional()
|
|
2131
|
+
});
|
|
2132
|
+
var probeDirectorySyncSchema = z14.object({
|
|
2133
|
+
v: z14.literal(1),
|
|
2134
|
+
revision: z14.number().int().positive(),
|
|
2135
|
+
probes: z14.array(z14.object({ probe_id: probeIdSchema, region: z14.enum(UPTIME_REGIONS), public_key: b64key, status: z14.enum(["active", "revoked"]) })).max(30),
|
|
2136
|
+
denied_hosts: z14.array(z14.string().min(1).max(253)).max(1e4)
|
|
2137
|
+
});
|
|
2138
|
+
var runNowRequestSchema = z14.object({ v: z14.literal(1), workspace_id: uuid3, check_id: uuid3, run_id: z14.string().regex(/^[A-Za-z0-9_-]{8,64}$/) });
|
|
2139
|
+
var signedAssignmentsSchema = z14.object({ assignments: assignmentsSchema, sig: z14.string().regex(/^[A-Za-z0-9_-]{86}$/) });
|
|
2140
|
+
var uptimeRegionStateSchema = z14.object({
|
|
2141
|
+
region: z14.enum(UPTIME_REGIONS),
|
|
2142
|
+
outcome: z14.enum(UPTIME_OUTCOMES),
|
|
2143
|
+
reason: z14.enum(UPTIME_REASONS).nullable(),
|
|
2144
|
+
status_code: z14.number().int().min(100).max(599).nullable(),
|
|
2145
|
+
total_ms: z14.number().nonnegative().max(60000).nullable(),
|
|
1559
2146
|
timings: timingsSchema.nullable().optional(),
|
|
1560
2147
|
at: iso2
|
|
1561
2148
|
});
|
|
1562
|
-
var uptimeStatusReportSchema =
|
|
2149
|
+
var uptimeStatusReportSchema = z14.object({
|
|
1563
2150
|
check_id: uuid3,
|
|
1564
|
-
revision:
|
|
1565
|
-
status:
|
|
1566
|
-
last_verdict:
|
|
2151
|
+
revision: z14.number().int().nonnegative(),
|
|
2152
|
+
status: z14.enum(UPTIME_STATUSES),
|
|
2153
|
+
last_verdict: z14.enum(SLOT_VERDICTS).nullable(),
|
|
1567
2154
|
last_slot_at: iso2.nullable(),
|
|
1568
2155
|
incident_id: uuid3.nullable(),
|
|
1569
|
-
down_streak:
|
|
1570
|
-
up_streak:
|
|
1571
|
-
regions:
|
|
1572
|
-
unobserved_regions:
|
|
2156
|
+
down_streak: z14.number().int().nonnegative(),
|
|
2157
|
+
up_streak: z14.number().int().nonnegative(),
|
|
2158
|
+
regions: z14.array(uptimeRegionStateSchema).max(3),
|
|
2159
|
+
unobserved_regions: z14.array(z14.enum(UPTIME_REGIONS)).max(3),
|
|
1573
2160
|
cert_not_after: iso2.nullable(),
|
|
1574
|
-
cert_expiring:
|
|
1575
|
-
run_now:
|
|
2161
|
+
cert_expiring: z14.boolean(),
|
|
2162
|
+
run_now: z14.object({ run_id: z14.string().max(64), results: z14.array(uptimeRegionStateSchema).max(3) }).nullable()
|
|
1576
2163
|
});
|
|
1577
2164
|
var UPTIME_EVENT_KINDS = ["opened", "resolved", "cert_expiring"];
|
|
1578
|
-
var uptimeEventSchema =
|
|
1579
|
-
event_id:
|
|
2165
|
+
var uptimeEventSchema = z14.object({
|
|
2166
|
+
event_id: z14.string().regex(/^[A-Za-z0-9:_-]{8,96}$/),
|
|
1580
2167
|
check_id: uuid3,
|
|
1581
|
-
kind:
|
|
2168
|
+
kind: z14.enum(UPTIME_EVENT_KINDS),
|
|
1582
2169
|
incident_id: uuid3.nullable(),
|
|
1583
2170
|
at: iso2,
|
|
1584
|
-
reason:
|
|
1585
|
-
regions:
|
|
1586
|
-
cert_days_left:
|
|
2171
|
+
reason: z14.enum(UPTIME_REASONS).nullable(),
|
|
2172
|
+
regions: z14.array(z14.enum(UPTIME_REGIONS)).max(3),
|
|
2173
|
+
cert_days_left: z14.number().int().nullable()
|
|
1587
2174
|
});
|
|
1588
|
-
var uptimeMinuteSchema =
|
|
2175
|
+
var uptimeMinuteSchema = z14.object({
|
|
1589
2176
|
check_id: uuid3,
|
|
1590
2177
|
minute: iso2,
|
|
1591
|
-
up:
|
|
1592
|
-
degraded:
|
|
1593
|
-
down:
|
|
1594
|
-
unknown:
|
|
1595
|
-
latency:
|
|
1596
|
-
});
|
|
1597
|
-
var uptimeReportSchema =
|
|
1598
|
-
v:
|
|
2178
|
+
up: z14.number().int().nonnegative(),
|
|
2179
|
+
degraded: z14.number().int().nonnegative(),
|
|
2180
|
+
down: z14.number().int().nonnegative(),
|
|
2181
|
+
unknown: z14.number().int().nonnegative(),
|
|
2182
|
+
latency: z14.array(z14.object({ region: z14.enum(UPTIME_REGIONS), n: z14.number().int().positive(), p50_ms: z14.number().nonnegative(), p95_ms: z14.number().nonnegative() })).max(3)
|
|
2183
|
+
});
|
|
2184
|
+
var uptimeReportSchema = z14.object({
|
|
2185
|
+
v: z14.literal(1),
|
|
1599
2186
|
workspace_id: uuid3,
|
|
1600
|
-
revision:
|
|
2187
|
+
revision: z14.number().int().nonnegative(),
|
|
1601
2188
|
sent_at: iso2,
|
|
1602
|
-
events:
|
|
1603
|
-
statuses:
|
|
1604
|
-
minutes:
|
|
2189
|
+
events: z14.array(uptimeEventSchema).max(UPTIME_LIMITS.reportMaxEvents),
|
|
2190
|
+
statuses: z14.array(uptimeStatusReportSchema).max(UPTIME_LIMITS.reportMaxStatuses),
|
|
2191
|
+
minutes: z14.array(uptimeMinuteSchema).max(UPTIME_LIMITS.reportMaxMinutes)
|
|
1605
2192
|
});
|
|
1606
|
-
var probeFleetReportSchema =
|
|
1607
|
-
v:
|
|
2193
|
+
var probeFleetReportSchema = z14.object({
|
|
2194
|
+
v: z14.literal(1),
|
|
1608
2195
|
sent_at: iso2,
|
|
1609
|
-
probes:
|
|
2196
|
+
probes: z14.array(z14.object({
|
|
1610
2197
|
probe_id: probeIdSchema,
|
|
1611
|
-
region:
|
|
1612
|
-
version:
|
|
2198
|
+
region: z14.enum(UPTIME_REGIONS),
|
|
2199
|
+
version: z14.string().max(40).nullable(),
|
|
1613
2200
|
last_seen_at: iso2.nullable(),
|
|
1614
|
-
lag_p99_ms:
|
|
1615
|
-
checks_per_min:
|
|
2201
|
+
lag_p99_ms: z14.number().nonnegative().nullable(),
|
|
2202
|
+
checks_per_min: z14.number().nonnegative().nullable()
|
|
1616
2203
|
})).max(30),
|
|
1617
|
-
regions_alive:
|
|
2204
|
+
regions_alive: z14.array(z14.enum(UPTIME_REGIONS)).max(3)
|
|
1618
2205
|
});
|
|
1619
|
-
var probeEnrollSchema =
|
|
1620
|
-
v:
|
|
2206
|
+
var probeEnrollSchema = z14.object({
|
|
2207
|
+
v: z14.literal(1),
|
|
1621
2208
|
probe_id: probeIdSchema,
|
|
1622
|
-
public_key:
|
|
1623
|
-
code:
|
|
1624
|
-
ts:
|
|
1625
|
-
sig:
|
|
1626
|
-
});
|
|
1627
|
-
var uptimeEvidenceEnvelopeSchema =
|
|
1628
|
-
v:
|
|
1629
|
-
check_id:
|
|
1630
|
-
slot:
|
|
1631
|
-
region:
|
|
2209
|
+
public_key: z14.string().regex(/^[A-Za-z0-9_-]{43}$/),
|
|
2210
|
+
code: z14.string().regex(/^[A-Za-z0-9_-]{43}$/),
|
|
2211
|
+
ts: z14.number().int().positive(),
|
|
2212
|
+
sig: z14.string().regex(/^[A-Za-z0-9_-]{86}$/)
|
|
2213
|
+
});
|
|
2214
|
+
var uptimeEvidenceEnvelopeSchema = z14.object({
|
|
2215
|
+
v: z14.literal(1),
|
|
2216
|
+
check_id: z14.guid(),
|
|
2217
|
+
slot: z14.number().int().nonnegative(),
|
|
2218
|
+
region: z14.enum(UPTIME_REGIONS),
|
|
1632
2219
|
probe_id: probeIdSchema,
|
|
1633
|
-
at:
|
|
1634
|
-
sealed:
|
|
2220
|
+
at: z14.number().int().positive(),
|
|
2221
|
+
sealed: z14.string().regex(/^[A-Za-z0-9_-]+$/).max(16384)
|
|
1635
2222
|
}).strict();
|
|
1636
|
-
var uptimeEvidenceSchema =
|
|
1637
|
-
v:
|
|
1638
|
-
check_id:
|
|
1639
|
-
slot:
|
|
1640
|
-
region:
|
|
1641
|
-
at:
|
|
1642
|
-
reason:
|
|
1643
|
-
status_line:
|
|
1644
|
-
headers:
|
|
1645
|
-
body:
|
|
1646
|
-
body_truncated:
|
|
2223
|
+
var uptimeEvidenceSchema = z14.object({
|
|
2224
|
+
v: z14.literal(1),
|
|
2225
|
+
check_id: z14.guid(),
|
|
2226
|
+
slot: z14.number().int().nonnegative(),
|
|
2227
|
+
region: z14.enum(UPTIME_REGIONS),
|
|
2228
|
+
at: z14.number().int().positive(),
|
|
2229
|
+
reason: z14.enum(UPTIME_REASONS).nullable(),
|
|
2230
|
+
status_line: z14.string().max(200).nullable(),
|
|
2231
|
+
headers: z14.record(z14.string().max(64), z14.string().max(512)).refine((h) => Object.keys(h).length <= 20),
|
|
2232
|
+
body: z14.string().max(UPTIME_LIMITS.evidenceMaxBytes * 4).nullable(),
|
|
2233
|
+
body_truncated: z14.boolean(),
|
|
1647
2234
|
timings: timingsSchema.nullable(),
|
|
1648
|
-
ip:
|
|
1649
|
-
error:
|
|
2235
|
+
ip: z14.string().max(64).nullable(),
|
|
2236
|
+
error: z14.string().max(300).nullable()
|
|
1650
2237
|
}).strict();
|
|
1651
|
-
var uptimeEvidenceListSchema =
|
|
1652
|
-
items:
|
|
2238
|
+
var uptimeEvidenceListSchema = z14.object({
|
|
2239
|
+
items: z14.array(uptimeEvidenceSchema.extend({ received_at: z14.number().int().positive() })).max(UPTIME_LIMITS.evidenceKeepPerCheck)
|
|
1653
2240
|
});
|
|
1654
2241
|
|
|
1655
2242
|
// ../src/shared/contracts/api-ops/monitors.ts
|
|
2243
|
+
var anyMonitorInputSchema = z15.union([monitorInputSchema, signalMonitorInputSchema]);
|
|
2244
|
+
var MAINTENANCE_INPUTS = {
|
|
2245
|
+
create: z15.object({ workspaceId: uuid, input: maintenanceInputSchema }),
|
|
2246
|
+
update: z15.object({ workspaceId: uuid, windowId: uuid, input: maintenanceInputSchema }),
|
|
2247
|
+
delete: z15.object({ workspaceId: uuid, windowId: uuid })
|
|
2248
|
+
};
|
|
1656
2249
|
var MONITOR_INPUTS = {
|
|
1657
|
-
create:
|
|
1658
|
-
update:
|
|
1659
|
-
delete:
|
|
1660
|
-
setPause:
|
|
1661
|
-
setMuted:
|
|
1662
|
-
dismissDiscovery:
|
|
1663
|
-
rotatePing:
|
|
2250
|
+
create: z15.object({ projectId, slug: z15.string().regex(SLUG_RE), input: anyMonitorInputSchema }),
|
|
2251
|
+
update: z15.object({ monitorId: uuid, input: anyMonitorInputSchema }),
|
|
2252
|
+
delete: z15.object({ monitorId: uuid, confirmSlug: z15.string().max(64) }),
|
|
2253
|
+
setPause: z15.object({ monitorId: uuid, until: holdUntil }),
|
|
2254
|
+
setMuted: z15.object({ monitorId: uuid, muted: z15.boolean() }),
|
|
2255
|
+
dismissDiscovery: z15.object({ discoveryId: uuid }),
|
|
2256
|
+
rotatePing: z15.object({
|
|
1664
2257
|
monitorId: uuid,
|
|
1665
|
-
graceHours:
|
|
2258
|
+
graceHours: z15.number().int().refine((h) => HEARTBEAT_LIMITS.rotationGraceHoursChoices.includes(h))
|
|
1666
2259
|
}),
|
|
1667
|
-
monitorOnly:
|
|
2260
|
+
monitorOnly: z15.object({ monitorId: uuid })
|
|
1668
2261
|
};
|
|
1669
2262
|
var UPTIME_INPUTS = {
|
|
1670
2263
|
create: uptimeCheckInputSchema,
|
|
1671
|
-
update:
|
|
1672
|
-
checkOnly:
|
|
1673
|
-
setHold:
|
|
2264
|
+
update: z15.object({ checkId: uuid, input: uptimeCheckInputSchema }),
|
|
2265
|
+
checkOnly: z15.object({ checkId: uuid }),
|
|
2266
|
+
setHold: z15.object({ checkId: uuid, kind: z15.enum(["pause", "mute"]), until: holdUntil })
|
|
1674
2267
|
};
|
|
1675
2268
|
var SLO_INPUTS = {
|
|
1676
|
-
create:
|
|
1677
|
-
update:
|
|
1678
|
-
sloOnly:
|
|
1679
|
-
setHold:
|
|
1680
|
-
import:
|
|
2269
|
+
create: z15.object({ workspaceId: uuid, input: sloInputSchema }),
|
|
2270
|
+
update: z15.object({ sloId: uuid, input: sloInputSchema }),
|
|
2271
|
+
sloOnly: z15.object({ sloId: uuid }),
|
|
2272
|
+
setHold: z15.object({ sloId: uuid, kind: z15.enum(["pause", "mute"]), until: holdUntil }),
|
|
2273
|
+
import: z15.object({
|
|
1681
2274
|
workspaceId: uuid,
|
|
1682
|
-
text:
|
|
1683
|
-
dryRun:
|
|
2275
|
+
text: z15.string().max(SLO_LIMITS.openSloMaxBytes * 2),
|
|
2276
|
+
dryRun: z15.boolean()
|
|
1684
2277
|
})
|
|
1685
2278
|
};
|
|
1686
2279
|
var m = "monitors:write";
|
|
@@ -1692,13 +2285,13 @@ var MONITOR_OPERATIONS = [
|
|
|
1692
2285
|
scope: m,
|
|
1693
2286
|
sensitivity: "normal",
|
|
1694
2287
|
kind: "write",
|
|
1695
|
-
rpcs: ["create_monitor", "create_heartbeat_monitor"],
|
|
2288
|
+
rpcs: ["create_monitor", "create_heartbeat_monitor", "create_signal_monitor"],
|
|
1696
2289
|
input: MONITOR_INPUTS.create,
|
|
1697
2290
|
bodyField: "input",
|
|
1698
2291
|
idempotency: "required",
|
|
1699
2292
|
status: 201,
|
|
1700
2293
|
mcp: "configure",
|
|
1701
|
-
summary: "Create a cron or heartbeat monitor. A heartbeat monitor returns its ping token once.",
|
|
2294
|
+
summary: "Create a cron or heartbeat monitor, or a signal monitor (`settings.type`: count, assertion, deadline, progress). A heartbeat monitor returns its ping token once.",
|
|
1702
2295
|
secretOutput: ["ping_token"],
|
|
1703
2296
|
ui: ["monitors#createMonitor"]
|
|
1704
2297
|
}),
|
|
@@ -1709,13 +2302,13 @@ var MONITOR_OPERATIONS = [
|
|
|
1709
2302
|
scope: m,
|
|
1710
2303
|
sensitivity: "normal",
|
|
1711
2304
|
kind: "write",
|
|
1712
|
-
rpcs: ["update_monitor"],
|
|
2305
|
+
rpcs: ["update_monitor", "update_signal_monitor"],
|
|
1713
2306
|
input: MONITOR_INPUTS.update,
|
|
1714
2307
|
bodyField: "input",
|
|
1715
2308
|
ifMatch: true,
|
|
1716
2309
|
idempotency: "none",
|
|
1717
2310
|
mcp: "configure",
|
|
1718
|
-
summary: "Replace a monitor's schedule, margins and thresholds.",
|
|
2311
|
+
summary: "Replace a monitor's schedule, margins and thresholds, or a signal monitor's settings (the type stays).",
|
|
1719
2312
|
ui: ["monitors#updateMonitor"]
|
|
1720
2313
|
}),
|
|
1721
2314
|
op({
|
|
@@ -1970,23 +2563,71 @@ var MONITOR_OPERATIONS = [
|
|
|
1970
2563
|
mcp: "configure",
|
|
1971
2564
|
summary: "Import OpenSLO YAML, all or nothing; `dry_run` returns the plan without applying it.",
|
|
1972
2565
|
ui: ["slos#importOpenSlo"]
|
|
2566
|
+
}),
|
|
2567
|
+
op({
|
|
2568
|
+
id: "maintenance.create",
|
|
2569
|
+
method: "POST",
|
|
2570
|
+
path: "/v1/maintenance-windows",
|
|
2571
|
+
scope: m,
|
|
2572
|
+
sensitivity: "normal",
|
|
2573
|
+
kind: "write",
|
|
2574
|
+
rpcs: ["create_maintenance_window"],
|
|
2575
|
+
input: MAINTENANCE_INPUTS.create,
|
|
2576
|
+
bodyField: "input",
|
|
2577
|
+
workspace: true,
|
|
2578
|
+
idempotency: "required",
|
|
2579
|
+
status: 201,
|
|
2580
|
+
mcp: "configure",
|
|
2581
|
+
summary: "Hold back monitor notifications during a one-off or weekly window (workspace, projects or monitors); monitors keep evaluating and recording.",
|
|
2582
|
+
ui: ["maintenance#createMaintenanceWindow"]
|
|
2583
|
+
}),
|
|
2584
|
+
op({
|
|
2585
|
+
id: "maintenance.update",
|
|
2586
|
+
method: "PATCH",
|
|
2587
|
+
path: "/v1/maintenance-windows/{window_id}",
|
|
2588
|
+
scope: m,
|
|
2589
|
+
sensitivity: "normal",
|
|
2590
|
+
kind: "write",
|
|
2591
|
+
rpcs: ["update_maintenance_window"],
|
|
2592
|
+
input: MAINTENANCE_INPUTS.update,
|
|
2593
|
+
bodyField: "input",
|
|
2594
|
+
workspace: true,
|
|
2595
|
+
idempotency: "none",
|
|
2596
|
+
mcp: "configure",
|
|
2597
|
+
summary: "Replace a maintenance window's scope, times and reason.",
|
|
2598
|
+
ui: ["maintenance#updateMaintenanceWindow"]
|
|
2599
|
+
}),
|
|
2600
|
+
op({
|
|
2601
|
+
id: "maintenance.delete",
|
|
2602
|
+
method: "DELETE",
|
|
2603
|
+
path: "/v1/maintenance-windows/{window_id}",
|
|
2604
|
+
scope: m,
|
|
2605
|
+
sensitivity: "normal",
|
|
2606
|
+
kind: "write",
|
|
2607
|
+
rpcs: ["delete_maintenance_window"],
|
|
2608
|
+
input: MAINTENANCE_INPUTS.delete,
|
|
2609
|
+
workspace: true,
|
|
2610
|
+
idempotency: "none",
|
|
2611
|
+
mcp: "configure",
|
|
2612
|
+
summary: "Delete a maintenance window; notifications resume at once.",
|
|
2613
|
+
ui: ["maintenance#deleteMaintenanceWindow"]
|
|
1973
2614
|
})
|
|
1974
2615
|
];
|
|
1975
2616
|
|
|
1976
2617
|
// ../src/shared/contracts/api-ops/node-data.ts
|
|
1977
|
-
import { z as
|
|
1978
|
-
var issueId =
|
|
1979
|
-
var csv =
|
|
1980
|
-
var name2 =
|
|
1981
|
-
var period =
|
|
1982
|
-
var nodeCursor =
|
|
2618
|
+
import { z as z16 } from "zod";
|
|
2619
|
+
var issueId = z16.number().int().positive();
|
|
2620
|
+
var csv = z16.string().min(1).max(2000);
|
|
2621
|
+
var name2 = z16.string().min(1).max(256);
|
|
2622
|
+
var period = z16.enum(["1h", "24h", "7d", "14d", "30d"]);
|
|
2623
|
+
var nodeCursor = z16.string().min(1).max(600).optional();
|
|
1983
2624
|
var windowFields = {
|
|
1984
|
-
start:
|
|
1985
|
-
end:
|
|
2625
|
+
start: z16.string().max(40).optional(),
|
|
2626
|
+
end: z16.string().max(40).optional()
|
|
1986
2627
|
};
|
|
1987
|
-
var traceId =
|
|
1988
|
-
var spanId =
|
|
1989
|
-
var attrs =
|
|
2628
|
+
var traceId = z16.string().regex(/^[0-9a-fA-F]{32}$/);
|
|
2629
|
+
var spanId = z16.string().regex(/^[0-9a-fA-F]{16}$/);
|
|
2630
|
+
var attrs = z16.string().max(2000).optional();
|
|
1990
2631
|
var telemetryCommon = {
|
|
1991
2632
|
...windowFields,
|
|
1992
2633
|
project: csv.optional(),
|
|
@@ -1994,91 +2635,112 @@ var telemetryCommon = {
|
|
|
1994
2635
|
service: csv.optional(),
|
|
1995
2636
|
attrs
|
|
1996
2637
|
};
|
|
1997
|
-
var issueChange =
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
action:
|
|
2003
|
-
mode:
|
|
2004
|
-
events:
|
|
2005
|
-
users:
|
|
2006
|
-
until:
|
|
2007
|
-
}),
|
|
2008
|
-
|
|
2009
|
-
|
|
2638
|
+
var issueChange = z16.union([
|
|
2639
|
+
z16.object({ action: z16.literal("resolve"), inNextRelease: z16.boolean().optional() }),
|
|
2640
|
+
z16.object({ action: z16.literal("unresolve") }),
|
|
2641
|
+
z16.object({ action: z16.literal("archive"), mode: z16.enum(["until_escalating", "forever"]) }),
|
|
2642
|
+
z16.object({
|
|
2643
|
+
action: z16.literal("archive"),
|
|
2644
|
+
mode: z16.literal("until_condition"),
|
|
2645
|
+
events: z16.number().int().min(1).max(1e6).optional(),
|
|
2646
|
+
users: z16.number().int().min(1).max(1e5).optional(),
|
|
2647
|
+
until: z16.string().datetime().optional()
|
|
2648
|
+
}),
|
|
2649
|
+
z16.object({ action: z16.literal("assign"), userId: z16.guid().nullable() }),
|
|
2650
|
+
z16.object({ action: z16.literal("priority"), priority: z16.enum(["low", "medium", "high"]) })
|
|
2010
2651
|
]);
|
|
2011
2652
|
var NODE_INPUTS = {
|
|
2012
|
-
issuesList:
|
|
2653
|
+
issuesList: z16.object({
|
|
2013
2654
|
project: csv.optional(),
|
|
2014
|
-
status:
|
|
2655
|
+
status: z16.enum(["unresolved", "resolved", "archived", "all"]).optional(),
|
|
2015
2656
|
level: csv.optional(),
|
|
2016
2657
|
priority: csv.optional(),
|
|
2017
2658
|
environment: csv.optional(),
|
|
2018
2659
|
release: csv.optional(),
|
|
2019
|
-
assignee:
|
|
2660
|
+
assignee: z16.string().max(64).optional(),
|
|
2020
2661
|
period: period.optional(),
|
|
2021
|
-
q:
|
|
2022
|
-
sort:
|
|
2662
|
+
q: z16.string().max(200).optional(),
|
|
2663
|
+
sort: z16.enum(["last_seen", "first_seen", "events", "users", "priority"]).optional(),
|
|
2023
2664
|
cursor: nodeCursor,
|
|
2024
|
-
limit:
|
|
2665
|
+
limit: z16.number().int().min(1).max(100).optional()
|
|
2025
2666
|
}),
|
|
2026
|
-
issue:
|
|
2027
|
-
issueStats:
|
|
2028
|
-
issueEvents:
|
|
2029
|
-
issueEvent:
|
|
2667
|
+
issue: z16.object({ issueId }),
|
|
2668
|
+
issueStats: z16.object({ issueId, range: z16.enum(["24h", "30d"]).optional() }),
|
|
2669
|
+
issueEvents: z16.object({ issueId, cursor: nodeCursor }),
|
|
2670
|
+
issueEvent: z16.object({
|
|
2030
2671
|
issueId,
|
|
2031
|
-
eventId:
|
|
2672
|
+
eventId: z16.string().regex(/^([0-9a-f]{32}|latest|oldest)$/)
|
|
2032
2673
|
}),
|
|
2033
|
-
issueUpdate:
|
|
2034
|
-
issuesBulk:
|
|
2035
|
-
issueIds:
|
|
2674
|
+
issueUpdate: z16.object({ issueId, change: issueChange }),
|
|
2675
|
+
issuesBulk: z16.object({
|
|
2676
|
+
issueIds: z16.array(issueId).min(1).max(100),
|
|
2036
2677
|
action: issueChange
|
|
2037
2678
|
}),
|
|
2038
|
-
spansList:
|
|
2679
|
+
spansList: z16.object({
|
|
2039
2680
|
...telemetryCommon,
|
|
2040
|
-
operation:
|
|
2041
|
-
status:
|
|
2042
|
-
kind:
|
|
2043
|
-
minDurationMs:
|
|
2044
|
-
maxDurationMs:
|
|
2045
|
-
mode:
|
|
2681
|
+
operation: z16.string().min(1).max(1024).optional(),
|
|
2682
|
+
status: z16.enum(["unset", "ok", "error"]).optional(),
|
|
2683
|
+
kind: z16.enum(["internal", "server", "client", "producer", "consumer"]).optional(),
|
|
2684
|
+
minDurationMs: z16.number().min(0).max(86400000).optional(),
|
|
2685
|
+
maxDurationMs: z16.number().min(0).max(86400000).optional(),
|
|
2686
|
+
mode: z16.enum(["spans", "traces"]).optional(),
|
|
2046
2687
|
cursor: nodeCursor
|
|
2047
2688
|
}),
|
|
2048
|
-
spansHistogram:
|
|
2689
|
+
spansHistogram: z16.object({
|
|
2049
2690
|
...telemetryCommon,
|
|
2050
|
-
operation:
|
|
2051
|
-
status:
|
|
2691
|
+
operation: z16.string().min(1).max(1024).optional(),
|
|
2692
|
+
status: z16.enum(["unset", "ok", "error"]).optional()
|
|
2052
2693
|
}),
|
|
2053
|
-
trace:
|
|
2054
|
-
traceSpans:
|
|
2055
|
-
span:
|
|
2056
|
-
logsList:
|
|
2694
|
+
trace: z16.object({ traceId }),
|
|
2695
|
+
traceSpans: z16.object({ traceId, errorsOnly: z16.enum(["1"]).optional(), ...windowFields }),
|
|
2696
|
+
span: z16.object({ traceId, spanId, ...windowFields }),
|
|
2697
|
+
logsList: z16.object({
|
|
2057
2698
|
...telemetryCommon,
|
|
2058
|
-
severityMin:
|
|
2699
|
+
severityMin: z16.enum(["trace", "debug", "info", "warn", "error", "fatal"]).optional(),
|
|
2059
2700
|
traceId: traceId.optional(),
|
|
2060
2701
|
spanId: spanId.optional(),
|
|
2061
|
-
q:
|
|
2062
|
-
order:
|
|
2702
|
+
q: z16.string().max(500).optional(),
|
|
2703
|
+
order: z16.enum(["asc", "desc"]).optional(),
|
|
2063
2704
|
cursor: nodeCursor
|
|
2064
2705
|
}),
|
|
2065
|
-
logsFacets:
|
|
2706
|
+
logsFacets: z16.object({
|
|
2066
2707
|
...telemetryCommon,
|
|
2067
|
-
severityMin:
|
|
2068
|
-
q:
|
|
2708
|
+
severityMin: z16.enum(["trace", "debug", "info", "warn", "error", "fatal"]).optional(),
|
|
2709
|
+
q: z16.string().max(500).optional()
|
|
2069
2710
|
}),
|
|
2070
|
-
logAround:
|
|
2711
|
+
logAround: z16.object({
|
|
2071
2712
|
logId: name2,
|
|
2072
|
-
at:
|
|
2073
|
-
same:
|
|
2074
|
-
before:
|
|
2075
|
-
after:
|
|
2076
|
-
}),
|
|
2077
|
-
telemetryUsage:
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2713
|
+
at: z16.string().max(40),
|
|
2714
|
+
same: z16.enum(["service", "trace"]).optional(),
|
|
2715
|
+
before: z16.number().int().min(0).max(200).optional(),
|
|
2716
|
+
after: z16.number().int().min(0).max(200).optional()
|
|
2717
|
+
}),
|
|
2718
|
+
telemetryUsage: z16.object({ project: csv.optional(), days: z16.number().int().min(1).max(31).optional() }),
|
|
2719
|
+
monitorSignal: z16.object({ monitorId: z16.guid(), hours: z16.number().int().min(1).max(24).optional() }),
|
|
2720
|
+
monitorOccurrences: z16.object({
|
|
2721
|
+
monitorId: z16.guid(),
|
|
2722
|
+
state: z16.enum(["open", "finished", "all"]).optional(),
|
|
2723
|
+
environment: z16.string().min(1).max(64).optional(),
|
|
2724
|
+
cursor: nodeCursor
|
|
2725
|
+
}),
|
|
2726
|
+
monitorBacktest: z16.object({ project: z16.number().int().positive(), settings: backtestSettingsSchema }),
|
|
2727
|
+
occurrenceCreate: z16.object({
|
|
2728
|
+
project: z16.number().int().positive(),
|
|
2729
|
+
monitorSlug: occurrenceInputSchema.shape.monitor_slug,
|
|
2730
|
+
occurrenceId: occurrenceInputSchema.shape.occurrence_id,
|
|
2731
|
+
dueAt: occurrenceInputSchema.shape.due_at,
|
|
2732
|
+
environment: occurrenceInputSchema.shape.environment
|
|
2733
|
+
}),
|
|
2734
|
+
occurrenceCancel: z16.object({
|
|
2735
|
+
project: z16.number().int().positive(),
|
|
2736
|
+
monitorSlug: z16.string().regex(SLUG_RE),
|
|
2737
|
+
occurrenceId: z16.string().regex(OCCURRENCE_ID_RE),
|
|
2738
|
+
environment: z16.string().min(1).max(64).optional()
|
|
2739
|
+
}),
|
|
2740
|
+
ticket: z16.object({
|
|
2741
|
+
scope: z16.enum(["read", "write"]).default("read"),
|
|
2742
|
+
project: z16.number().int().positive().optional(),
|
|
2743
|
+
environment: z16.string().min(1).max(64).optional()
|
|
2082
2744
|
})
|
|
2083
2745
|
};
|
|
2084
2746
|
var N = NODE_INPUTS;
|
|
@@ -2249,6 +2911,60 @@ var NODE_OPERATIONS = [
|
|
|
2249
2911
|
node: { path: "q/telemetry/usage" },
|
|
2250
2912
|
summary: "Stored spans and logs per day and project on the node."
|
|
2251
2913
|
}),
|
|
2914
|
+
op({
|
|
2915
|
+
...read,
|
|
2916
|
+
id: "monitors.signal",
|
|
2917
|
+
path: "/v1/monitors/{monitor_id}/signal",
|
|
2918
|
+
scope: "monitors:read",
|
|
2919
|
+
input: N.monitorSignal,
|
|
2920
|
+
node: { path: "q/monitors/{monitor_id}/signal" },
|
|
2921
|
+
mcp: "reliability",
|
|
2922
|
+
summary: "A signal monitor's minute counts (count/assertion) for up to 24 h per environment, and its open runs (progress, deadline)."
|
|
2923
|
+
}),
|
|
2924
|
+
op({
|
|
2925
|
+
...read,
|
|
2926
|
+
id: "monitors.occurrences",
|
|
2927
|
+
path: "/v1/monitors/{monitor_id}/occurrences",
|
|
2928
|
+
scope: "monitors:read",
|
|
2929
|
+
input: N.monitorOccurrences,
|
|
2930
|
+
node: { path: "q/monitors/{monitor_id}/occurrences", list: "occurrences" },
|
|
2931
|
+
paged: true,
|
|
2932
|
+
mcp: "reliability",
|
|
2933
|
+
summary: "Occurrences of a deadline monitor (pending, on time, late, missed, failed, cancelled), newest due first."
|
|
2934
|
+
}),
|
|
2935
|
+
op({
|
|
2936
|
+
...read,
|
|
2937
|
+
id: "monitors.backtest",
|
|
2938
|
+
method: "POST",
|
|
2939
|
+
path: "/v1/monitors/backtest",
|
|
2940
|
+
scope: "monitors:read",
|
|
2941
|
+
input: N.monitorBacktest,
|
|
2942
|
+
node: { path: "q/monitors/backtest" },
|
|
2943
|
+
mcp: "reliability",
|
|
2944
|
+
summary: "How often count/assertion settings would have alerted over the last 30 days of stored data (same rule as the live evaluator)."
|
|
2945
|
+
}),
|
|
2946
|
+
op({
|
|
2947
|
+
...read,
|
|
2948
|
+
id: "occurrences.create",
|
|
2949
|
+
method: "POST",
|
|
2950
|
+
path: "/v1/occurrences",
|
|
2951
|
+
scope: "monitors:write",
|
|
2952
|
+
input: N.occurrenceCreate,
|
|
2953
|
+
node: { path: "w/monitors/occurrences", body: "*" },
|
|
2954
|
+
mcp: "configure",
|
|
2955
|
+
summary: "Register one run a deadline monitor expects (`due_at` within 35 days); the same id again moves its due time while it is pending."
|
|
2956
|
+
}),
|
|
2957
|
+
op({
|
|
2958
|
+
...read,
|
|
2959
|
+
id: "occurrences.cancel",
|
|
2960
|
+
method: "DELETE",
|
|
2961
|
+
path: "/v1/occurrences/{monitor_slug}/{occurrence_id}",
|
|
2962
|
+
scope: "monitors:write",
|
|
2963
|
+
input: N.occurrenceCancel,
|
|
2964
|
+
node: { path: "w/monitors/occurrences/cancel", body: "*" },
|
|
2965
|
+
mcp: "configure",
|
|
2966
|
+
summary: "Cancel a pending occurrence (the app moved or dropped the job); a cancelled occurrence never alerts."
|
|
2967
|
+
}),
|
|
2252
2968
|
op({
|
|
2253
2969
|
...read,
|
|
2254
2970
|
id: "issues.update",
|
|
@@ -2286,10 +3002,10 @@ var NODE_OPERATIONS = [
|
|
|
2286
3002
|
];
|
|
2287
3003
|
|
|
2288
3004
|
// ../src/shared/contracts/api-ops/projects.ts
|
|
2289
|
-
import { z as
|
|
3005
|
+
import { z as z21 } from "zod";
|
|
2290
3006
|
|
|
2291
3007
|
// ../src/shared/contracts/ingest-keys.ts
|
|
2292
|
-
import { z as
|
|
3008
|
+
import { z as z17 } from "zod";
|
|
2293
3009
|
var INGEST_KEY_SCOPES = ["traces", "logs", "errors", "monitors"];
|
|
2294
3010
|
var INGEST_KEY_STATES = ["active", "revoked"];
|
|
2295
3011
|
var INGEST_KEY_LIMITS = {
|
|
@@ -2299,51 +3015,51 @@ var INGEST_KEY_LIMITS = {
|
|
|
2299
3015
|
edgeCacheSeconds: 60
|
|
2300
3016
|
};
|
|
2301
3017
|
var CHECKIN_AUTH_MODES = ["public_or_key", "key_only"];
|
|
2302
|
-
var ingestKeyConfigSchema =
|
|
2303
|
-
v:
|
|
2304
|
-
key_id:
|
|
2305
|
-
project_public_id:
|
|
2306
|
-
project_id:
|
|
2307
|
-
workspace_id:
|
|
3018
|
+
var ingestKeyConfigSchema = z17.object({
|
|
3019
|
+
v: z17.literal(1),
|
|
3020
|
+
key_id: z17.guid(),
|
|
3021
|
+
project_public_id: z17.number().int().positive(),
|
|
3022
|
+
project_id: z17.number().int().positive(),
|
|
3023
|
+
workspace_id: z17.guid(),
|
|
2308
3024
|
node_id: nodeIdSchema,
|
|
2309
|
-
scopes:
|
|
2310
|
-
environments:
|
|
2311
|
-
expires_at:
|
|
2312
|
-
state:
|
|
2313
|
-
workspace_status:
|
|
2314
|
-
ingest_kill:
|
|
2315
|
-
telemetry_kill:
|
|
2316
|
-
telemetry_rate_bytes_per_sec:
|
|
2317
|
-
telemetry_burst_bytes:
|
|
2318
|
-
traces_monthly_bytes:
|
|
2319
|
-
logs_monthly_bytes:
|
|
2320
|
-
telemetry_buffer_minutes:
|
|
2321
|
-
revision:
|
|
2322
|
-
});
|
|
2323
|
-
var createIngestKeyInputSchema =
|
|
2324
|
-
projectId:
|
|
2325
|
-
name:
|
|
2326
|
-
scopes:
|
|
2327
|
-
environments:
|
|
2328
|
-
expiresAt:
|
|
2329
|
-
});
|
|
2330
|
-
var ingestKeyRowSchema =
|
|
2331
|
-
id:
|
|
2332
|
-
project_id:
|
|
2333
|
-
name:
|
|
2334
|
-
prefix:
|
|
2335
|
-
scopes:
|
|
2336
|
-
environments:
|
|
2337
|
-
expires_at:
|
|
2338
|
-
state:
|
|
2339
|
-
created_by:
|
|
2340
|
-
created_at:
|
|
2341
|
-
revoked_at:
|
|
2342
|
-
last_used_at:
|
|
3025
|
+
scopes: z17.array(z17.enum(INGEST_KEY_SCOPES)).min(1).max(INGEST_KEY_SCOPES.length),
|
|
3026
|
+
environments: z17.array(z17.string().max(INGEST_KEY_LIMITS.environmentMaxChars)).max(INGEST_KEY_LIMITS.environmentsMax),
|
|
3027
|
+
expires_at: z17.string().datetime({ offset: true }).nullable(),
|
|
3028
|
+
state: z17.enum(INGEST_KEY_STATES),
|
|
3029
|
+
workspace_status: z17.enum(["active", "suspended", "deleting"]),
|
|
3030
|
+
ingest_kill: z17.boolean(),
|
|
3031
|
+
telemetry_kill: z17.boolean(),
|
|
3032
|
+
telemetry_rate_bytes_per_sec: z17.number().int().positive(),
|
|
3033
|
+
telemetry_burst_bytes: z17.number().int().positive(),
|
|
3034
|
+
traces_monthly_bytes: z17.number().int().positive(),
|
|
3035
|
+
logs_monthly_bytes: z17.number().int().positive(),
|
|
3036
|
+
telemetry_buffer_minutes: z17.number().int().min(1).max(1440),
|
|
3037
|
+
revision: z17.number().int().nonnegative()
|
|
3038
|
+
});
|
|
3039
|
+
var createIngestKeyInputSchema = z17.object({
|
|
3040
|
+
projectId: z17.number().int().positive(),
|
|
3041
|
+
name: z17.string().trim().min(1).max(INGEST_KEY_LIMITS.nameMaxChars).refine((s) => !/[\u0000-\u001f\u007f]/.test(s)),
|
|
3042
|
+
scopes: z17.array(z17.enum(INGEST_KEY_SCOPES)).min(1).max(INGEST_KEY_SCOPES.length),
|
|
3043
|
+
environments: z17.array(z17.string().trim().min(1).max(INGEST_KEY_LIMITS.environmentMaxChars).regex(/^[^\s/\u0000-\u001f]+$/)).max(INGEST_KEY_LIMITS.environmentsMax),
|
|
3044
|
+
expiresAt: z17.string().datetime({ offset: true }).nullable()
|
|
3045
|
+
});
|
|
3046
|
+
var ingestKeyRowSchema = z17.object({
|
|
3047
|
+
id: z17.guid(),
|
|
3048
|
+
project_id: z17.number().int().positive(),
|
|
3049
|
+
name: z17.string(),
|
|
3050
|
+
prefix: z17.string(),
|
|
3051
|
+
scopes: z17.array(z17.enum(INGEST_KEY_SCOPES)),
|
|
3052
|
+
environments: z17.array(z17.string()),
|
|
3053
|
+
expires_at: z17.string().nullable(),
|
|
3054
|
+
state: z17.enum(INGEST_KEY_STATES),
|
|
3055
|
+
created_by: z17.guid().nullable(),
|
|
3056
|
+
created_at: z17.string(),
|
|
3057
|
+
revoked_at: z17.string().nullable(),
|
|
3058
|
+
last_used_at: z17.string().nullable()
|
|
2343
3059
|
});
|
|
2344
3060
|
|
|
2345
3061
|
// ../src/shared/contracts/integration-health.ts
|
|
2346
|
-
import { z as
|
|
3062
|
+
import { z as z18 } from "zod";
|
|
2347
3063
|
|
|
2348
3064
|
// ../src/shared/contracts/platforms.ts
|
|
2349
3065
|
var PLATFORMS = [
|
|
@@ -2357,116 +3073,116 @@ var PLATFORMS = [
|
|
|
2357
3073
|
|
|
2358
3074
|
// ../src/shared/contracts/integration-health.ts
|
|
2359
3075
|
var VERIFICATION_ID_RE = /^bv1_[0-9a-f]{32}$/;
|
|
2360
|
-
var verificationIdSchema =
|
|
3076
|
+
var verificationIdSchema = z18.string().regex(VERIFICATION_ID_RE);
|
|
2361
3077
|
var SURFACES = ["browser", "server"];
|
|
2362
3078
|
var RECEIPT_SURFACES = ["browser", "server", "belvador"];
|
|
2363
3079
|
var CHECKS = ["delivery", "uncaught", "pipeline"];
|
|
2364
3080
|
var HOOK_STATES = ["ok", "missing", "unknown"];
|
|
2365
|
-
var verificationContextSchema =
|
|
2366
|
-
v:
|
|
2367
|
-
surface:
|
|
2368
|
-
check:
|
|
2369
|
-
hook:
|
|
2370
|
-
uncaught_expected:
|
|
2371
|
-
});
|
|
2372
|
-
var iso3 =
|
|
2373
|
-
var projectId3 =
|
|
2374
|
-
var verificationReceiptSchema =
|
|
3081
|
+
var verificationContextSchema = z18.object({
|
|
3082
|
+
v: z18.literal(1),
|
|
3083
|
+
surface: z18.enum(RECEIPT_SURFACES),
|
|
3084
|
+
check: z18.enum(CHECKS),
|
|
3085
|
+
hook: z18.enum(HOOK_STATES).optional(),
|
|
3086
|
+
uncaught_expected: z18.boolean().optional()
|
|
3087
|
+
});
|
|
3088
|
+
var iso3 = z18.string().datetime();
|
|
3089
|
+
var projectId3 = z18.number().int().positive();
|
|
3090
|
+
var verificationReceiptSchema = z18.object({
|
|
2375
3091
|
project_id: projectId3,
|
|
2376
3092
|
verification_id: verificationIdSchema,
|
|
2377
|
-
surface:
|
|
2378
|
-
check:
|
|
2379
|
-
hook:
|
|
2380
|
-
uncaught_expected:
|
|
2381
|
-
sdk_name:
|
|
2382
|
-
sdk_version:
|
|
2383
|
-
environment:
|
|
2384
|
-
release:
|
|
2385
|
-
source_host:
|
|
3093
|
+
surface: z18.enum(RECEIPT_SURFACES),
|
|
3094
|
+
check: z18.enum(CHECKS),
|
|
3095
|
+
hook: z18.enum(HOOK_STATES),
|
|
3096
|
+
uncaught_expected: z18.boolean(),
|
|
3097
|
+
sdk_name: z18.string().max(80),
|
|
3098
|
+
sdk_version: z18.string().max(40),
|
|
3099
|
+
environment: z18.string().max(64),
|
|
3100
|
+
release: z18.string().max(200),
|
|
3101
|
+
source_host: z18.string().max(253),
|
|
2386
3102
|
received_at: iso3
|
|
2387
3103
|
});
|
|
2388
3104
|
var SDK_DELIVERY_DROP_REASONS = ["network_error", "queue_overflow", "send_error"];
|
|
2389
|
-
var clientDiscardSchema =
|
|
3105
|
+
var clientDiscardSchema = z18.object({
|
|
2390
3106
|
hour: iso3,
|
|
2391
|
-
reason:
|
|
2392
|
-
n:
|
|
3107
|
+
reason: z18.enum(SDK_DELIVERY_DROP_REASONS),
|
|
3108
|
+
n: z18.number().int().nonnegative()
|
|
2393
3109
|
});
|
|
2394
|
-
var edgeVerificationRequestSchema =
|
|
2395
|
-
v:
|
|
3110
|
+
var edgeVerificationRequestSchema = z18.object({
|
|
3111
|
+
v: z18.literal(1),
|
|
2396
3112
|
project_id: projectId3,
|
|
2397
3113
|
verification_id: verificationIdSchema
|
|
2398
3114
|
});
|
|
2399
|
-
var readbackCheckSchema =
|
|
2400
|
-
surface:
|
|
2401
|
-
check:
|
|
2402
|
-
hook:
|
|
3115
|
+
var readbackCheckSchema = z18.object({
|
|
3116
|
+
surface: z18.enum(RECEIPT_SURFACES),
|
|
3117
|
+
check: z18.enum(CHECKS),
|
|
3118
|
+
hook: z18.enum(HOOK_STATES),
|
|
2403
3119
|
received_at: iso3
|
|
2404
3120
|
});
|
|
2405
|
-
var edgeVerificationResponseSchema =
|
|
2406
|
-
checks:
|
|
3121
|
+
var edgeVerificationResponseSchema = z18.object({
|
|
3122
|
+
checks: z18.array(readbackCheckSchema).max(8)
|
|
2407
3123
|
});
|
|
2408
|
-
var readbackResponseSchema =
|
|
2409
|
-
v:
|
|
3124
|
+
var readbackResponseSchema = z18.object({
|
|
3125
|
+
v: z18.literal(1),
|
|
2410
3126
|
verification_id: verificationIdSchema,
|
|
2411
|
-
node:
|
|
2412
|
-
checks:
|
|
3127
|
+
node: z18.enum(["connected", "offline"]),
|
|
3128
|
+
checks: z18.array(readbackCheckSchema).max(8)
|
|
2413
3129
|
});
|
|
2414
3130
|
var ENVIRONMENT_RE = /^[^\u0000-\u001f]{1,64}$/;
|
|
2415
|
-
var projectRuntimeSchema =
|
|
3131
|
+
var projectRuntimeSchema = z18.object({
|
|
2416
3132
|
project_id: projectId3,
|
|
2417
|
-
environment:
|
|
2418
|
-
surface:
|
|
2419
|
-
sdk_name:
|
|
2420
|
-
sdk_version:
|
|
2421
|
-
latest_release:
|
|
3133
|
+
environment: z18.string().max(64),
|
|
3134
|
+
surface: z18.enum(SURFACES),
|
|
3135
|
+
sdk_name: z18.string().max(80),
|
|
3136
|
+
sdk_version: z18.string().max(40),
|
|
3137
|
+
latest_release: z18.string().max(200),
|
|
2422
3138
|
first_seen: iso3,
|
|
2423
3139
|
last_seen: iso3,
|
|
2424
|
-
events_24h:
|
|
2425
|
-
check_ins_24h:
|
|
3140
|
+
events_24h: z18.number().int().nonnegative(),
|
|
3141
|
+
check_ins_24h: z18.number().int().nonnegative()
|
|
2426
3142
|
});
|
|
2427
3143
|
|
|
2428
3144
|
// ../src/shared/contracts/node-config.ts
|
|
2429
|
-
import { z as
|
|
3145
|
+
import { z as z20 } from "zod";
|
|
2430
3146
|
|
|
2431
3147
|
// ../src/shared/contracts/backup.ts
|
|
2432
|
-
import { z as
|
|
3148
|
+
import { z as z19 } from "zod";
|
|
2433
3149
|
var BACKUP_KINDS = ["daily", "weekly", "manual", "pre_upgrade"];
|
|
2434
|
-
var ageRecipient =
|
|
2435
|
-
var backupIdSchema =
|
|
2436
|
-
var nodeBackupConfigSchema =
|
|
2437
|
-
enabled:
|
|
2438
|
-
hour_utc:
|
|
2439
|
-
weekly_day:
|
|
3150
|
+
var ageRecipient = z19.string().regex(/^age1[02-9ac-hj-np-z]{58}$/);
|
|
3151
|
+
var backupIdSchema = z19.string().regex(/^[a-z0-9-]{8,64}$/);
|
|
3152
|
+
var nodeBackupConfigSchema = z19.object({
|
|
3153
|
+
enabled: z19.boolean(),
|
|
3154
|
+
hour_utc: z19.number().int().min(0).max(23),
|
|
3155
|
+
weekly_day: z19.number().int().min(1).max(7),
|
|
2440
3156
|
workspace_recipient: ageRecipient
|
|
2441
3157
|
});
|
|
2442
|
-
var backupCredentialsRequestSchema =
|
|
2443
|
-
mode:
|
|
3158
|
+
var backupCredentialsRequestSchema = z19.object({
|
|
3159
|
+
mode: z19.enum(["upload", "download"]),
|
|
2444
3160
|
backup_id: backupIdSchema,
|
|
2445
|
-
source_node_id:
|
|
2446
|
-
});
|
|
2447
|
-
var backupCredentialsSchema =
|
|
2448
|
-
endpoint:
|
|
2449
|
-
bucket:
|
|
2450
|
-
prefix:
|
|
2451
|
-
access_key_id:
|
|
2452
|
-
secret_access_key:
|
|
2453
|
-
session_token:
|
|
2454
|
-
expires_at:
|
|
2455
|
-
});
|
|
2456
|
-
var rowCountsSchema =
|
|
2457
|
-
var backupManifestSchema =
|
|
2458
|
-
v:
|
|
3161
|
+
source_node_id: z19.guid().optional()
|
|
3162
|
+
});
|
|
3163
|
+
var backupCredentialsSchema = z19.object({
|
|
3164
|
+
endpoint: z19.string().url(),
|
|
3165
|
+
bucket: z19.string().regex(/^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$/),
|
|
3166
|
+
prefix: z19.string().regex(/^backups\/[0-9a-f-]{36}\/$/),
|
|
3167
|
+
access_key_id: z19.string().min(8).max(200),
|
|
3168
|
+
secret_access_key: z19.string().min(8).max(200),
|
|
3169
|
+
session_token: z19.string().min(8).max(4000),
|
|
3170
|
+
expires_at: z19.string().datetime()
|
|
3171
|
+
});
|
|
3172
|
+
var rowCountsSchema = z19.record(z19.string().regex(/^[a-z_][a-z0-9_]{0,63}$/), z19.number().int().nonnegative());
|
|
3173
|
+
var backupManifestSchema = z19.object({
|
|
3174
|
+
v: z19.literal(1),
|
|
2459
3175
|
backup_id: backupIdSchema,
|
|
2460
|
-
node_id:
|
|
2461
|
-
kind:
|
|
2462
|
-
created_at:
|
|
2463
|
-
object_key:
|
|
2464
|
-
size_bytes:
|
|
2465
|
-
sha256:
|
|
2466
|
-
clickhouse_version:
|
|
2467
|
-
schema_version:
|
|
3176
|
+
node_id: z19.guid(),
|
|
3177
|
+
kind: z19.enum(BACKUP_KINDS),
|
|
3178
|
+
created_at: z19.string().datetime(),
|
|
3179
|
+
object_key: z19.string(),
|
|
3180
|
+
size_bytes: z19.number().int().nonnegative(),
|
|
3181
|
+
sha256: z19.string().regex(/^[0-9a-f]{64}$/),
|
|
3182
|
+
clickhouse_version: z19.string().max(40),
|
|
3183
|
+
schema_version: z19.number().int().nonnegative(),
|
|
2468
3184
|
row_counts: rowCountsSchema,
|
|
2469
|
-
recipients:
|
|
3185
|
+
recipients: z19.array(z19.string().regex(/^[0-9a-f]{8}$/)).min(1).max(4)
|
|
2470
3186
|
});
|
|
2471
3187
|
var BACKUP_ERROR_CODES = [
|
|
2472
3188
|
"CLICKHOUSE_BACKUP_FAILED",
|
|
@@ -2480,48 +3196,48 @@ var BACKUP_ERROR_CODES = [
|
|
|
2480
3196
|
"RESTORE_FAILED",
|
|
2481
3197
|
"ROW_COUNT_MISMATCH"
|
|
2482
3198
|
];
|
|
2483
|
-
var backupReportSchema =
|
|
3199
|
+
var backupReportSchema = z19.object({
|
|
2484
3200
|
backup_id: backupIdSchema,
|
|
2485
|
-
kind:
|
|
2486
|
-
status:
|
|
2487
|
-
started_at:
|
|
2488
|
-
finished_at:
|
|
3201
|
+
kind: z19.enum(BACKUP_KINDS),
|
|
3202
|
+
status: z19.enum(["succeeded", "failed"]),
|
|
3203
|
+
started_at: z19.string().datetime(),
|
|
3204
|
+
finished_at: z19.string().datetime(),
|
|
2489
3205
|
manifest: backupManifestSchema.nullable(),
|
|
2490
|
-
error_code:
|
|
3206
|
+
error_code: z19.enum(BACKUP_ERROR_CODES).nullable()
|
|
2491
3207
|
});
|
|
2492
|
-
var drillReportSchema =
|
|
3208
|
+
var drillReportSchema = z19.object({
|
|
2493
3209
|
backup_id: backupIdSchema,
|
|
2494
|
-
kind:
|
|
2495
|
-
status:
|
|
2496
|
-
finished_at:
|
|
2497
|
-
detail:
|
|
2498
|
-
error_code:
|
|
2499
|
-
});
|
|
2500
|
-
var nodeIdentityEscrowSchema =
|
|
2501
|
-
v:
|
|
2502
|
-
node_id:
|
|
2503
|
-
seal:
|
|
2504
|
-
publicKey:
|
|
2505
|
-
privateKey:
|
|
2506
|
-
}),
|
|
2507
|
-
created_at:
|
|
2508
|
-
});
|
|
2509
|
-
var restoreArgsSchema =
|
|
2510
|
-
job_id:
|
|
2511
|
-
workspace_id:
|
|
2512
|
-
source_node_id:
|
|
3210
|
+
kind: z19.enum(["weekly_local", "monthly_new_machine"]),
|
|
3211
|
+
status: z19.enum(["passed", "failed"]),
|
|
3212
|
+
finished_at: z19.string().datetime(),
|
|
3213
|
+
detail: z19.string().max(300),
|
|
3214
|
+
error_code: z19.enum(BACKUP_ERROR_CODES).nullable()
|
|
3215
|
+
});
|
|
3216
|
+
var nodeIdentityEscrowSchema = z19.object({
|
|
3217
|
+
v: z19.literal(1),
|
|
3218
|
+
node_id: z19.guid(),
|
|
3219
|
+
seal: z19.object({
|
|
3220
|
+
publicKey: z19.string().regex(/^[A-Za-z0-9_-]{43}$/),
|
|
3221
|
+
privateKey: z19.string().regex(/^[A-Za-z0-9_-]{43}$/)
|
|
3222
|
+
}),
|
|
3223
|
+
created_at: z19.string().datetime()
|
|
3224
|
+
});
|
|
3225
|
+
var restoreArgsSchema = z19.object({
|
|
3226
|
+
job_id: z19.guid(),
|
|
3227
|
+
workspace_id: z19.guid(),
|
|
3228
|
+
source_node_id: z19.guid(),
|
|
2513
3229
|
manifest: backupManifestSchema,
|
|
2514
|
-
sealed_identity:
|
|
2515
|
-
mode:
|
|
3230
|
+
sealed_identity: z19.string().regex(/^[A-Za-z0-9_-]{40,2000}$/),
|
|
3231
|
+
mode: z19.enum(["rebuild", "drill"])
|
|
2516
3232
|
});
|
|
2517
|
-
var restoreReportSchema =
|
|
2518
|
-
job_id:
|
|
3233
|
+
var restoreReportSchema = z19.object({
|
|
3234
|
+
job_id: z19.guid(),
|
|
2519
3235
|
backup_id: backupIdSchema,
|
|
2520
|
-
mode:
|
|
2521
|
-
status:
|
|
2522
|
-
finished_at:
|
|
2523
|
-
detail:
|
|
2524
|
-
error_code:
|
|
3236
|
+
mode: z19.enum(["rebuild", "drill"]),
|
|
3237
|
+
status: z19.enum(["succeeded", "failed"]),
|
|
3238
|
+
finished_at: z19.string().datetime(),
|
|
3239
|
+
detail: z19.string().max(300),
|
|
3240
|
+
error_code: z19.enum(BACKUP_ERROR_CODES).nullable()
|
|
2525
3241
|
});
|
|
2526
3242
|
|
|
2527
3243
|
// ../src/shared/contracts/node-config.ts
|
|
@@ -2535,79 +3251,81 @@ var SCRUB_GROUPS = [
|
|
|
2535
3251
|
"headers"
|
|
2536
3252
|
];
|
|
2537
3253
|
var MAX_NODE_MONITORS = 5000;
|
|
2538
|
-
var kid =
|
|
2539
|
-
var publicKey =
|
|
2540
|
-
var nodeConfigSchema =
|
|
2541
|
-
v:
|
|
2542
|
-
config_version:
|
|
2543
|
-
node_id:
|
|
2544
|
-
workspace_id:
|
|
2545
|
-
workspace_status:
|
|
2546
|
-
issued_at:
|
|
2547
|
-
retention_days:
|
|
2548
|
-
channel:
|
|
2549
|
-
projects:
|
|
2550
|
-
project_id:
|
|
2551
|
-
slug:
|
|
2552
|
-
short_prefix:
|
|
2553
|
-
user_id_salt:
|
|
2554
|
-
scrub_disabled:
|
|
2555
|
-
upload_tokens:
|
|
2556
|
-
hash:
|
|
2557
|
-
expires_at:
|
|
3254
|
+
var kid = z20.string().regex(/^[A-Za-z0-9_-]{1,40}$/);
|
|
3255
|
+
var publicKey = z20.string().regex(/^[A-Za-z0-9_-]{43}$/);
|
|
3256
|
+
var nodeConfigSchema = z20.object({
|
|
3257
|
+
v: z20.literal(1),
|
|
3258
|
+
config_version: z20.number().int().positive(),
|
|
3259
|
+
node_id: z20.guid(),
|
|
3260
|
+
workspace_id: z20.guid(),
|
|
3261
|
+
workspace_status: z20.enum(["active", "suspended"]),
|
|
3262
|
+
issued_at: z20.string().datetime(),
|
|
3263
|
+
retention_days: z20.number().int().min(1).max(3650),
|
|
3264
|
+
channel: z20.enum(["stable", "canary"]).optional(),
|
|
3265
|
+
projects: z20.array(z20.object({
|
|
3266
|
+
project_id: z20.number().int().positive(),
|
|
3267
|
+
slug: z20.string().max(64),
|
|
3268
|
+
short_prefix: z20.string().regex(/^[A-Z0-9]{1,12}$/),
|
|
3269
|
+
user_id_salt: z20.string().regex(/^[A-Za-z0-9_-]{22,64}$/),
|
|
3270
|
+
scrub_disabled: z20.array(z20.enum(SCRUB_GROUPS)).max(SCRUB_GROUPS.length),
|
|
3271
|
+
upload_tokens: z20.array(z20.object({
|
|
3272
|
+
hash: z20.string().regex(/^[a-f0-9]{64}$/),
|
|
3273
|
+
expires_at: z20.string().datetime()
|
|
2558
3274
|
})).max(10).optional()
|
|
2559
3275
|
})).max(1000),
|
|
2560
|
-
ticket_keys:
|
|
2561
|
-
control_ops_keys:
|
|
2562
|
-
kill_switches:
|
|
3276
|
+
ticket_keys: z20.array(z20.object({ kid, public_key: publicKey, not_after: z20.string().datetime() })).min(1).max(5),
|
|
3277
|
+
control_ops_keys: z20.array(z20.object({ kid, public_key: publicKey })).min(1).max(5),
|
|
3278
|
+
kill_switches: z20.object({ ingest: z20.boolean(), alerts: z20.boolean() }),
|
|
2563
3279
|
backup: nodeBackupConfigSchema.optional(),
|
|
2564
|
-
purged_projects:
|
|
2565
|
-
monitors:
|
|
2566
|
-
purged_monitors:
|
|
2567
|
-
telemetry:
|
|
2568
|
-
traces_retention_days:
|
|
2569
|
-
logs_retention_days:
|
|
2570
|
-
traces_disk_share:
|
|
3280
|
+
purged_projects: z20.array(z20.number().int().positive()).max(1000).optional(),
|
|
3281
|
+
monitors: z20.array(monitorDefinitionSchema).max(MAX_NODE_MONITORS).optional(),
|
|
3282
|
+
purged_monitors: z20.array(z20.guid()).max(5000).optional(),
|
|
3283
|
+
telemetry: z20.object({
|
|
3284
|
+
traces_retention_days: z20.number().int().min(1).max(90),
|
|
3285
|
+
logs_retention_days: z20.number().int().min(1).max(90),
|
|
3286
|
+
traces_disk_share: z20.number().min(0.2).max(0.8)
|
|
2571
3287
|
}).optional(),
|
|
2572
|
-
slos:
|
|
3288
|
+
slos: z20.array(nodeSloSchema).max(SLO_LIMITS.maxNodeSlos).optional(),
|
|
3289
|
+
signal_monitors: z20.array(signalMonitorDefinitionSchema).max(MAX_NODE_MONITORS).optional(),
|
|
3290
|
+
signal_limits: signalLimitsConfigSchema.optional()
|
|
2573
3291
|
});
|
|
2574
|
-
var signedNodeConfigSchema =
|
|
3292
|
+
var signedNodeConfigSchema = z20.object({ config: nodeConfigSchema, kid, sig: z20.string() });
|
|
2575
3293
|
|
|
2576
3294
|
// ../src/shared/contracts/api-ops/projects.ts
|
|
2577
|
-
var slug =
|
|
2578
|
-
var name3 =
|
|
2579
|
-
var label =
|
|
2580
|
-
var platform =
|
|
2581
|
-
var origin =
|
|
2582
|
-
var keyId =
|
|
3295
|
+
var slug = z21.string().regex(/^[a-z0-9][a-z0-9-]{1,38}[a-z0-9]$/);
|
|
3296
|
+
var name3 = z21.string().trim().min(1).max(60);
|
|
3297
|
+
var label = z21.string().trim().min(1).max(40);
|
|
3298
|
+
var platform = z21.enum(PLATFORMS);
|
|
3299
|
+
var origin = z21.string().trim().toLowerCase().regex(/^https?:\/\/[a-z0-9.-]+(:[0-9]{1,5})?$/).max(200);
|
|
3300
|
+
var keyId = z21.number().int().positive();
|
|
2583
3301
|
var PROJECT_INPUTS = {
|
|
2584
|
-
create:
|
|
2585
|
-
update:
|
|
2586
|
-
updateIntake:
|
|
3302
|
+
create: z21.object({ workspaceId: uuid, name: name3, slug, platform }),
|
|
3303
|
+
update: z21.object({ projectId, name: name3, platform, isPinned: z21.boolean() }),
|
|
3304
|
+
updateIntake: z21.object({
|
|
2587
3305
|
projectId,
|
|
2588
|
-
rateLimit:
|
|
2589
|
-
burst:
|
|
2590
|
-
allowedOrigins:
|
|
3306
|
+
rateLimit: z21.number().int().positive().nullable(),
|
|
3307
|
+
burst: z21.number().int().positive().nullable(),
|
|
3308
|
+
allowedOrigins: z21.array(origin).max(50)
|
|
2591
3309
|
}),
|
|
2592
|
-
updateObservability:
|
|
3310
|
+
updateObservability: z21.object({
|
|
2593
3311
|
projectId,
|
|
2594
|
-
primaryEnvironment:
|
|
2595
|
-
allowCodeMonitors:
|
|
3312
|
+
primaryEnvironment: z21.string().trim().min(1).max(64).refine((v) => v !== "*" && ENVIRONMENT_RE.test(v)),
|
|
3313
|
+
allowCodeMonitors: z21.boolean()
|
|
2596
3314
|
}),
|
|
2597
|
-
setScrub:
|
|
2598
|
-
setCheckinAuth:
|
|
2599
|
-
setEnvironmentHidden:
|
|
3315
|
+
setScrub: z21.object({ projectId, group: z21.enum(SCRUB_GROUPS), enabled: z21.boolean() }),
|
|
3316
|
+
setCheckinAuth: z21.object({ projectId, mode: z21.enum(CHECKIN_AUTH_MODES) }),
|
|
3317
|
+
setEnvironmentHidden: z21.object({
|
|
2600
3318
|
projectId,
|
|
2601
|
-
name:
|
|
2602
|
-
hidden:
|
|
2603
|
-
}),
|
|
2604
|
-
scheduleDeletion:
|
|
2605
|
-
projectOnly:
|
|
2606
|
-
labelled:
|
|
2607
|
-
keyOnly:
|
|
2608
|
-
tokenOnly:
|
|
3319
|
+
name: z21.string().min(1).max(64),
|
|
3320
|
+
hidden: z21.boolean()
|
|
3321
|
+
}),
|
|
3322
|
+
scheduleDeletion: z21.object({ projectId, confirmSlug: slug }),
|
|
3323
|
+
projectOnly: z21.object({ projectId }),
|
|
3324
|
+
labelled: z21.object({ projectId, label }),
|
|
3325
|
+
keyOnly: z21.object({ keyId }),
|
|
3326
|
+
tokenOnly: z21.object({ tokenId: keyId }),
|
|
2609
3327
|
createIngestKey: createIngestKeyInputSchema,
|
|
2610
|
-
ingestKeyOnly:
|
|
3328
|
+
ingestKeyOnly: z21.object({ keyId: uuid })
|
|
2611
3329
|
};
|
|
2612
3330
|
var P = PROJECT_INPUTS;
|
|
2613
3331
|
var PROJECT_OPERATIONS = [
|
|
@@ -2862,23 +3580,28 @@ var PROJECT_OPERATIONS = [
|
|
|
2862
3580
|
];
|
|
2863
3581
|
|
|
2864
3582
|
// ../src/shared/contracts/api-ops/reads.ts
|
|
2865
|
-
import { z as
|
|
2866
|
-
var list =
|
|
3583
|
+
import { z as z22 } from "zod";
|
|
3584
|
+
var list = z22.object({ workspaceId: uuid, limit: pageLimit, cursor });
|
|
2867
3585
|
var READ_INPUTS = {
|
|
2868
|
-
workspace:
|
|
3586
|
+
workspace: z22.object({ workspaceId: uuid }),
|
|
2869
3587
|
list,
|
|
2870
|
-
projectsGet:
|
|
3588
|
+
projectsGet: z22.object({ workspaceId: uuid, projectId }),
|
|
2871
3589
|
monitorsList: list.extend({ projectId: projectId.optional() }),
|
|
2872
|
-
monitorsGet:
|
|
2873
|
-
uptimeGet:
|
|
2874
|
-
slosGet:
|
|
3590
|
+
monitorsGet: z22.object({ workspaceId: uuid, monitorId: uuid }),
|
|
3591
|
+
uptimeGet: z22.object({ workspaceId: uuid, checkId: uuid }),
|
|
3592
|
+
slosGet: z22.object({ workspaceId: uuid, sloId: uuid }),
|
|
2875
3593
|
alertsList: list.extend({
|
|
2876
|
-
state:
|
|
3594
|
+
state: z22.enum(["open", "resolved", "all"]).default("all"),
|
|
2877
3595
|
monitorId: uuid.optional()
|
|
3596
|
+
}),
|
|
3597
|
+
approvalsGet: z22.object({ workspaceId: uuid, approvalId: uuid }),
|
|
3598
|
+
monitorsListTyped: list.extend({
|
|
3599
|
+
projectId: projectId.optional(),
|
|
3600
|
+
type: z22.enum(MONITOR_TYPES).optional()
|
|
2878
3601
|
})
|
|
2879
3602
|
};
|
|
2880
3603
|
var R = READ_INPUTS;
|
|
2881
|
-
var
|
|
3604
|
+
var base2 = {
|
|
2882
3605
|
sensitivity: "normal",
|
|
2883
3606
|
kind: "read",
|
|
2884
3607
|
method: "GET",
|
|
@@ -2888,7 +3611,7 @@ var base = {
|
|
|
2888
3611
|
};
|
|
2889
3612
|
var READ_OPERATIONS = [
|
|
2890
3613
|
op({
|
|
2891
|
-
...
|
|
3614
|
+
...base2,
|
|
2892
3615
|
id: "workspace.get",
|
|
2893
3616
|
path: "/v1/workspace",
|
|
2894
3617
|
scope: "org:read",
|
|
@@ -2898,7 +3621,7 @@ var READ_OPERATIONS = [
|
|
|
2898
3621
|
summary: "The token's workspace, plan and the caller's role."
|
|
2899
3622
|
}),
|
|
2900
3623
|
op({
|
|
2901
|
-
...
|
|
3624
|
+
...base2,
|
|
2902
3625
|
id: "members.list",
|
|
2903
3626
|
path: "/v1/members",
|
|
2904
3627
|
scope: "members:read",
|
|
@@ -2909,7 +3632,7 @@ var READ_OPERATIONS = [
|
|
|
2909
3632
|
summary: "Workspace members and their roles."
|
|
2910
3633
|
}),
|
|
2911
3634
|
op({
|
|
2912
|
-
...
|
|
3635
|
+
...base2,
|
|
2913
3636
|
id: "projects.list",
|
|
2914
3637
|
path: "/v1/projects",
|
|
2915
3638
|
scope: "projects:read",
|
|
@@ -2920,7 +3643,7 @@ var READ_OPERATIONS = [
|
|
|
2920
3643
|
summary: "Projects the token can see."
|
|
2921
3644
|
}),
|
|
2922
3645
|
op({
|
|
2923
|
-
...
|
|
3646
|
+
...base2,
|
|
2924
3647
|
id: "projects.get",
|
|
2925
3648
|
path: "/v1/projects/{project_id}",
|
|
2926
3649
|
scope: "projects:read",
|
|
@@ -2930,18 +3653,18 @@ var READ_OPERATIONS = [
|
|
|
2930
3653
|
summary: "One project."
|
|
2931
3654
|
}),
|
|
2932
3655
|
op({
|
|
2933
|
-
...
|
|
3656
|
+
...base2,
|
|
2934
3657
|
id: "monitors.list",
|
|
2935
3658
|
path: "/v1/monitors",
|
|
2936
3659
|
scope: "monitors:read",
|
|
2937
3660
|
rpcs: ["api_read_monitors"],
|
|
2938
|
-
input: R.
|
|
3661
|
+
input: R.monitorsListTyped,
|
|
2939
3662
|
paged: true,
|
|
2940
3663
|
mcp: "investigate",
|
|
2941
|
-
summary: "
|
|
3664
|
+
summary: "Monitors of every type (cron, heartbeat, count, assertion, deadline, progress); `type` narrows the list."
|
|
2942
3665
|
}),
|
|
2943
3666
|
op({
|
|
2944
|
-
...
|
|
3667
|
+
...base2,
|
|
2945
3668
|
id: "monitors.get",
|
|
2946
3669
|
path: "/v1/monitors/{monitor_id}",
|
|
2947
3670
|
scope: "monitors:read",
|
|
@@ -2951,7 +3674,7 @@ var READ_OPERATIONS = [
|
|
|
2951
3674
|
summary: "One monitor with its ETag."
|
|
2952
3675
|
}),
|
|
2953
3676
|
op({
|
|
2954
|
-
...
|
|
3677
|
+
...base2,
|
|
2955
3678
|
id: "uptime.list",
|
|
2956
3679
|
path: "/v1/uptime-checks",
|
|
2957
3680
|
scope: "monitors:read",
|
|
@@ -2962,7 +3685,7 @@ var READ_OPERATIONS = [
|
|
|
2962
3685
|
summary: "Uptime checks (header values are never returned)."
|
|
2963
3686
|
}),
|
|
2964
3687
|
op({
|
|
2965
|
-
...
|
|
3688
|
+
...base2,
|
|
2966
3689
|
id: "uptime.get",
|
|
2967
3690
|
path: "/v1/uptime-checks/{check_id}",
|
|
2968
3691
|
scope: "monitors:read",
|
|
@@ -2972,7 +3695,7 @@ var READ_OPERATIONS = [
|
|
|
2972
3695
|
summary: "One uptime check."
|
|
2973
3696
|
}),
|
|
2974
3697
|
op({
|
|
2975
|
-
...
|
|
3698
|
+
...base2,
|
|
2976
3699
|
id: "slos.list",
|
|
2977
3700
|
path: "/v1/slos",
|
|
2978
3701
|
scope: "monitors:read",
|
|
@@ -2983,7 +3706,7 @@ var READ_OPERATIONS = [
|
|
|
2983
3706
|
summary: "SLO definitions."
|
|
2984
3707
|
}),
|
|
2985
3708
|
op({
|
|
2986
|
-
...
|
|
3709
|
+
...base2,
|
|
2987
3710
|
id: "slos.get",
|
|
2988
3711
|
path: "/v1/slos/{slo_id}",
|
|
2989
3712
|
scope: "monitors:read",
|
|
@@ -2993,7 +3716,7 @@ var READ_OPERATIONS = [
|
|
|
2993
3716
|
summary: "One SLO definition."
|
|
2994
3717
|
}),
|
|
2995
3718
|
op({
|
|
2996
|
-
...
|
|
3719
|
+
...base2,
|
|
2997
3720
|
id: "alert_rules.list",
|
|
2998
3721
|
path: "/v1/alert-rules",
|
|
2999
3722
|
scope: "alerts:read",
|
|
@@ -3004,7 +3727,7 @@ var READ_OPERATIONS = [
|
|
|
3004
3727
|
summary: "Alert rules."
|
|
3005
3728
|
}),
|
|
3006
3729
|
op({
|
|
3007
|
-
...
|
|
3730
|
+
...base2,
|
|
3008
3731
|
id: "destinations.list",
|
|
3009
3732
|
path: "/v1/destinations",
|
|
3010
3733
|
scope: "alerts:read",
|
|
@@ -3015,7 +3738,7 @@ var READ_OPERATIONS = [
|
|
|
3015
3738
|
summary: "Alert destinations with a masked hint; secrets never leave the server."
|
|
3016
3739
|
}),
|
|
3017
3740
|
op({
|
|
3018
|
-
...
|
|
3741
|
+
...base2,
|
|
3019
3742
|
id: "alerts.list",
|
|
3020
3743
|
path: "/v1/alerts",
|
|
3021
3744
|
scope: "alerts:read",
|
|
@@ -3026,7 +3749,18 @@ var READ_OPERATIONS = [
|
|
|
3026
3749
|
summary: "Alerts: one row per violation episode of a monitor, open or resolved."
|
|
3027
3750
|
}),
|
|
3028
3751
|
op({
|
|
3029
|
-
...
|
|
3752
|
+
...base2,
|
|
3753
|
+
id: "maintenance.list",
|
|
3754
|
+
path: "/v1/maintenance-windows",
|
|
3755
|
+
scope: "monitors:read",
|
|
3756
|
+
rpcs: ["api_read_maintenance_windows"],
|
|
3757
|
+
input: R.list,
|
|
3758
|
+
paged: true,
|
|
3759
|
+
mcp: "reliability",
|
|
3760
|
+
summary: "Maintenance windows and whether each is active now."
|
|
3761
|
+
}),
|
|
3762
|
+
op({
|
|
3763
|
+
...base2,
|
|
3030
3764
|
id: "node.get",
|
|
3031
3765
|
path: "/v1/node",
|
|
3032
3766
|
scope: "org:read",
|
|
@@ -3036,7 +3770,7 @@ var READ_OPERATIONS = [
|
|
|
3036
3770
|
summary: "The node's state, versions and last heartbeat (null before provisioning)."
|
|
3037
3771
|
}),
|
|
3038
3772
|
op({
|
|
3039
|
-
...
|
|
3773
|
+
...base2,
|
|
3040
3774
|
id: "usage.get",
|
|
3041
3775
|
path: "/v1/usage",
|
|
3042
3776
|
scope: "usage:read",
|
|
@@ -3046,7 +3780,7 @@ var READ_OPERATIONS = [
|
|
|
3046
3780
|
summary: "The workspace's plan and limits."
|
|
3047
3781
|
}),
|
|
3048
3782
|
op({
|
|
3049
|
-
...
|
|
3783
|
+
...base2,
|
|
3050
3784
|
id: "audit.list",
|
|
3051
3785
|
path: "/v1/audit-log",
|
|
3052
3786
|
scope: "audit:read",
|
|
@@ -3055,6 +3789,16 @@ var READ_OPERATIONS = [
|
|
|
3055
3789
|
paged: true,
|
|
3056
3790
|
mcp: "investigate",
|
|
3057
3791
|
summary: "Audit log, newest first (admins)."
|
|
3792
|
+
}),
|
|
3793
|
+
op({
|
|
3794
|
+
...base2,
|
|
3795
|
+
id: "approvals.get",
|
|
3796
|
+
path: "/v1/approvals/{approval_id}",
|
|
3797
|
+
scope: "org:read",
|
|
3798
|
+
rpcs: ["api_read_approval"],
|
|
3799
|
+
input: R.approvalsGet,
|
|
3800
|
+
mcp: "configure",
|
|
3801
|
+
summary: "State of an approval this token asked for (admins: any in the workspace): pending, approved, executed, rejected, expired or failed, with its result ids."
|
|
3058
3802
|
})
|
|
3059
3803
|
];
|
|
3060
3804
|
|
|
@@ -3064,6 +3808,7 @@ var API_OPERATIONS = [
|
|
|
3064
3808
|
...PROJECT_OPERATIONS,
|
|
3065
3809
|
...MONITOR_OPERATIONS,
|
|
3066
3810
|
...ALERT_OPERATIONS,
|
|
3811
|
+
...INCIDENT_OPERATIONS,
|
|
3067
3812
|
...ACCESS_OPERATIONS,
|
|
3068
3813
|
...NODE_OPERATIONS
|
|
3069
3814
|
];
|
|
@@ -3071,13 +3816,279 @@ var BY_ID = new Map(API_OPERATIONS.map((o) => [o.id, o]));
|
|
|
3071
3816
|
function apiOperation(id) {
|
|
3072
3817
|
return BY_ID.get(id);
|
|
3073
3818
|
}
|
|
3819
|
+
function pathParams(path) {
|
|
3820
|
+
return [...path.matchAll(/\{([a-z_]+)\}/g)].map((m) => m[1]);
|
|
3821
|
+
}
|
|
3822
|
+
|
|
3823
|
+
// ../src/shared/contracts/approvals.ts
|
|
3824
|
+
var APPROVAL_STATES = ["pending", "approved", "executed", "rejected", "expired", "failed"];
|
|
3825
|
+
var APPROVAL_LIMITS = {
|
|
3826
|
+
ttlMinutes: 15,
|
|
3827
|
+
stepUpMaxAgeSeconds: 600,
|
|
3828
|
+
pendingPerWorkspace: 20,
|
|
3829
|
+
paramsMaxBytes: 16 * 1024,
|
|
3830
|
+
decisionNoteMax: 500,
|
|
3831
|
+
notifyMaxRecipients: 10
|
|
3832
|
+
};
|
|
3833
|
+
var APPROVAL_APPROVER = {
|
|
3834
|
+
"projects.set_checkin_auth": "admin",
|
|
3835
|
+
"projects.schedule_deletion": "admin",
|
|
3836
|
+
"project_keys.create": "member",
|
|
3837
|
+
"project_keys.rotate": "member",
|
|
3838
|
+
"project_keys.revoke": "member",
|
|
3839
|
+
"upload_tokens.create": "member",
|
|
3840
|
+
"upload_tokens.revoke": "member",
|
|
3841
|
+
"ingest_keys.create": "admin",
|
|
3842
|
+
"ingest_keys.revoke": "admin",
|
|
3843
|
+
"ping_tokens.rotate": "admin",
|
|
3844
|
+
"ping_tokens.revoke_previous": "admin",
|
|
3845
|
+
"ping_tokens.reset": "admin",
|
|
3846
|
+
"destinations.create": "admin",
|
|
3847
|
+
"destinations.update": "admin",
|
|
3848
|
+
"destinations.update_connection": "admin",
|
|
3849
|
+
"destinations.delete": "admin",
|
|
3850
|
+
"destinations.set_recipients": "admin",
|
|
3851
|
+
"members.change_role": "admin",
|
|
3852
|
+
"members.remove": "admin",
|
|
3853
|
+
"invites.create": "admin",
|
|
3854
|
+
"tokens.create_personal": "self",
|
|
3855
|
+
"tokens.create_service": "admin",
|
|
3856
|
+
"tokens.set_policy": "admin",
|
|
3857
|
+
"service_principals.create": "admin",
|
|
3858
|
+
"service_principals.update": "admin",
|
|
3859
|
+
"node.provision": "admin",
|
|
3860
|
+
"node.resize": "admin",
|
|
3861
|
+
"node.schedule_deletion": "owner",
|
|
3862
|
+
"node.set_backup_custody": "owner",
|
|
3863
|
+
"node.rebuild": "owner",
|
|
3864
|
+
"node.submit_recovery_kit": "owner"
|
|
3865
|
+
};
|
|
3866
|
+
var APPROVAL_HUMAN_FIELDS = {
|
|
3867
|
+
"projects.schedule_deletion": ["confirmSlug"],
|
|
3868
|
+
"node.schedule_deletion": ["confirmName"],
|
|
3869
|
+
"node.rebuild": ["confirmName"]
|
|
3870
|
+
};
|
|
3871
|
+
var APPROVAL_SETUP_OPS = ["destinations.create", "destinations.update_connection"];
|
|
3872
|
+
function approvalRequestSchema(operationId, input) {
|
|
3873
|
+
const human = APPROVAL_HUMAN_FIELDS[operationId] ?? [];
|
|
3874
|
+
if (!human.length)
|
|
3875
|
+
return input;
|
|
3876
|
+
return input.omit(Object.fromEntries(human.map((k) => [k, true])));
|
|
3877
|
+
}
|
|
3074
3878
|
|
|
3075
3879
|
// ../src/shared/contracts/api-ops/wire.ts
|
|
3076
|
-
import { z as
|
|
3880
|
+
import { z as z23 } from "zod";
|
|
3077
3881
|
var toSnake = (s) => s.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`);
|
|
3882
|
+
var toCamel = (s) => s.replace(/_([a-z0-9])/g, (_, c) => c.toUpperCase());
|
|
3078
3883
|
var schemaCache = new WeakMap;
|
|
3884
|
+
function inputJsonSchema(op) {
|
|
3885
|
+
let js = schemaCache.get(op.input);
|
|
3886
|
+
if (!js) {
|
|
3887
|
+
js = z23.toJSONSchema(op.input, { io: "input", unrepresentable: "any" });
|
|
3888
|
+
schemaCache.set(op.input, js);
|
|
3889
|
+
}
|
|
3890
|
+
return js;
|
|
3891
|
+
}
|
|
3892
|
+
function variants(js) {
|
|
3893
|
+
return [js, ...js.anyOf ?? [], ...js.oneOf ?? [], ...js.allOf ?? []];
|
|
3894
|
+
}
|
|
3895
|
+
function propertyMap(js) {
|
|
3896
|
+
const out = new Map;
|
|
3897
|
+
if (!js)
|
|
3898
|
+
return out;
|
|
3899
|
+
for (const v of variants(js)) {
|
|
3900
|
+
for (const [name, schema] of Object.entries(v.properties ?? {}))
|
|
3901
|
+
out.set(toSnake(name), { name, schema });
|
|
3902
|
+
}
|
|
3903
|
+
return out;
|
|
3904
|
+
}
|
|
3905
|
+
function itemSchema(js) {
|
|
3906
|
+
if (!js)
|
|
3907
|
+
return;
|
|
3908
|
+
for (const v of variants(js)) {
|
|
3909
|
+
if (v.items && !Array.isArray(v.items))
|
|
3910
|
+
return v.items;
|
|
3911
|
+
}
|
|
3912
|
+
return;
|
|
3913
|
+
}
|
|
3914
|
+
function isPlainObject(v) {
|
|
3915
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
3916
|
+
}
|
|
3917
|
+
function camelize(value, js) {
|
|
3918
|
+
if (Array.isArray(value))
|
|
3919
|
+
return value.map((v) => camelize(v, itemSchema(js)));
|
|
3920
|
+
if (!isPlainObject(value))
|
|
3921
|
+
return value;
|
|
3922
|
+
const props = propertyMap(js);
|
|
3923
|
+
if (props.size === 0)
|
|
3924
|
+
return value;
|
|
3925
|
+
const out = {};
|
|
3926
|
+
for (const [k, v] of Object.entries(value)) {
|
|
3927
|
+
const p = props.get(k);
|
|
3928
|
+
out[p ? p.name : k] = p ? camelize(v, p.schema) : v;
|
|
3929
|
+
}
|
|
3930
|
+
return out;
|
|
3931
|
+
}
|
|
3932
|
+
function snakeSchema(js, drop = []) {
|
|
3933
|
+
const out = { ...js };
|
|
3934
|
+
if (js.properties) {
|
|
3935
|
+
out.properties = Object.fromEntries(Object.entries(js.properties).filter(([k]) => !drop.includes(k)).map(([k, v]) => [toSnake(k), snakeSchema(v)]));
|
|
3936
|
+
if (js.required)
|
|
3937
|
+
out.required = js.required.filter((k) => !drop.includes(k)).map(toSnake);
|
|
3938
|
+
if (out.required && !out.required.length)
|
|
3939
|
+
delete out.required;
|
|
3940
|
+
}
|
|
3941
|
+
if (js.items && !Array.isArray(js.items))
|
|
3942
|
+
out.items = snakeSchema(js.items);
|
|
3943
|
+
for (const key of ["anyOf", "oneOf", "allOf"]) {
|
|
3944
|
+
if (js[key])
|
|
3945
|
+
out[key] = js[key].map((v) => snakeSchema(v, drop));
|
|
3946
|
+
}
|
|
3947
|
+
if (isPlainObject(js.additionalProperties))
|
|
3948
|
+
out.additionalProperties = snakeSchema(js.additionalProperties);
|
|
3949
|
+
return out;
|
|
3950
|
+
}
|
|
3951
|
+
function scalarType(js) {
|
|
3952
|
+
if (!js)
|
|
3953
|
+
return;
|
|
3954
|
+
for (const v of variants(js)) {
|
|
3955
|
+
const t = Array.isArray(v.type) ? v.type.find((x) => x !== "null") : v.type;
|
|
3956
|
+
if (t)
|
|
3957
|
+
return t;
|
|
3958
|
+
}
|
|
3959
|
+
return;
|
|
3960
|
+
}
|
|
3961
|
+
function coerce(raw, js) {
|
|
3962
|
+
const t = scalarType(js);
|
|
3963
|
+
if ((t === "integer" || t === "number") && /^-?\d+(\.\d+)?$/.test(raw))
|
|
3964
|
+
return Number(raw);
|
|
3965
|
+
if (t === "boolean" && (raw === "true" || raw === "false"))
|
|
3966
|
+
return raw === "true";
|
|
3967
|
+
return raw;
|
|
3968
|
+
}
|
|
3969
|
+
function buildOpInput(op, req, workspaceId) {
|
|
3970
|
+
const js = inputJsonSchema(op);
|
|
3971
|
+
const top = propertyMap(js);
|
|
3972
|
+
const out = {};
|
|
3973
|
+
const nested = {};
|
|
3974
|
+
const bodyKey = op.bodyField ? toSnake(op.bodyField) : null;
|
|
3975
|
+
const body = isPlainObject(req.body) ? req.body : req.body === undefined || req.body === null ? {} : null;
|
|
3976
|
+
if (body === null) {
|
|
3977
|
+
out["__invalidBody"] = true;
|
|
3978
|
+
return out;
|
|
3979
|
+
}
|
|
3980
|
+
for (const [k, v] of Object.entries(body)) {
|
|
3981
|
+
const p = top.get(k);
|
|
3982
|
+
if (p && k !== bodyKey)
|
|
3983
|
+
out[p.name] = camelize(v, p.schema);
|
|
3984
|
+
else if (bodyKey)
|
|
3985
|
+
nested[k] = v;
|
|
3986
|
+
else
|
|
3987
|
+
out[k] = v;
|
|
3988
|
+
}
|
|
3989
|
+
if (op.bodyField)
|
|
3990
|
+
out[op.bodyField] = camelize(nested, top.get(bodyKey)?.schema);
|
|
3991
|
+
for (const [k, raw] of Object.entries(req.query)) {
|
|
3992
|
+
const p = top.get(k);
|
|
3993
|
+
if (p)
|
|
3994
|
+
out[p.name] = coerce(raw, p.schema);
|
|
3995
|
+
}
|
|
3996
|
+
for (const name of pathParams(op.path)) {
|
|
3997
|
+
const p = top.get(name);
|
|
3998
|
+
const raw = req.path[name];
|
|
3999
|
+
if (p && raw !== undefined)
|
|
4000
|
+
out[p.name] = coerce(raw, p.schema);
|
|
4001
|
+
}
|
|
4002
|
+
if (op.workspace)
|
|
4003
|
+
out["workspaceId"] = workspaceId;
|
|
4004
|
+
return out;
|
|
4005
|
+
}
|
|
4006
|
+
function wirePointer(op, path) {
|
|
4007
|
+
const segs = path.map((p) => typeof p === "string" ? toSnake(p) : String(p));
|
|
4008
|
+
if (op.bodyField && segs[0] === toSnake(op.bodyField))
|
|
4009
|
+
segs.shift();
|
|
4010
|
+
return `/${segs.map((s) => s.replace(/~/g, "~0").replace(/\//g, "~1")).join("/")}`;
|
|
4011
|
+
}
|
|
4012
|
+
var WIRE_ERRORS_MAX = 20;
|
|
4013
|
+
function wireErrors(op, error) {
|
|
4014
|
+
const flat = (issues, prefix) => issues.flatMap((i) => {
|
|
4015
|
+
if (i.code === "invalid_union" && i.errors && i.errors.length > 0) {
|
|
4016
|
+
const best = i.errors.reduce((a, b) => b.length < a.length ? b : a);
|
|
4017
|
+
if (best.length > 0)
|
|
4018
|
+
return flat(best, [...prefix, ...i.path]);
|
|
4019
|
+
}
|
|
4020
|
+
return [{ ...i, path: [...prefix, ...i.path] }];
|
|
4021
|
+
});
|
|
4022
|
+
return flat(error.issues, []).slice(0, WIRE_ERRORS_MAX).map((i) => ({ pointer: wirePointer(op, i.path), code: i.code }));
|
|
4023
|
+
}
|
|
4024
|
+
|
|
4025
|
+
// ../src/shared/contracts/api-ops/openapi.ts
|
|
4026
|
+
function clean(js) {
|
|
4027
|
+
const { $schema: _drop, ...rest } = js;
|
|
4028
|
+
return rest;
|
|
4029
|
+
}
|
|
4030
|
+
function propertyOf(js, camel) {
|
|
4031
|
+
return clean(snakeSchema(js.properties?.[camel] ?? {}));
|
|
4032
|
+
}
|
|
4033
|
+
function requestSchema(op) {
|
|
4034
|
+
const js = inputJsonSchema(op);
|
|
4035
|
+
const path = pathParams(op.path).map(toCamel);
|
|
4036
|
+
const drop = ["workspaceId", ...path];
|
|
4037
|
+
if (!op.bodyField) {
|
|
4038
|
+
const s = clean(snakeSchema(js, drop));
|
|
4039
|
+
return s.properties && Object.keys(s.properties).length === 0 && !s.anyOf && !s.oneOf ? null : s;
|
|
4040
|
+
}
|
|
4041
|
+
const outer = clean(snakeSchema(js, [...drop, op.bodyField]));
|
|
4042
|
+
const inner = clean(snakeSchema(js.properties?.[op.bodyField] ?? {}));
|
|
4043
|
+
if (!inner.properties)
|
|
4044
|
+
return { allOf: [outer, inner] };
|
|
4045
|
+
return {
|
|
4046
|
+
...inner,
|
|
4047
|
+
properties: { ...outer.properties ?? {}, ...inner.properties },
|
|
4048
|
+
required: [...outer.required ?? [], ...inner.required ?? []]
|
|
4049
|
+
};
|
|
4050
|
+
}
|
|
4051
|
+
function operationArgsSchema(op, drop = []) {
|
|
4052
|
+
const js = inputJsonSchema(op);
|
|
4053
|
+
const path = pathParams(op.path);
|
|
4054
|
+
const pathProps = Object.fromEntries(path.map((n) => [n, propertyOf(js, toCamel(n))]));
|
|
4055
|
+
const rest = op.method === "GET" ? (() => {
|
|
4056
|
+
const s = clean(snakeSchema(js, ["workspaceId", ...path.map(toCamel)]));
|
|
4057
|
+
return { ...s, required: [] };
|
|
4058
|
+
})() : requestSchema(op);
|
|
4059
|
+
if (rest && !rest.properties) {
|
|
4060
|
+
return { type: "object", properties: pathProps, required: path, allOf: [rest] };
|
|
4061
|
+
}
|
|
4062
|
+
const props = { ...pathProps, ...rest?.properties ?? {} };
|
|
4063
|
+
for (const d of drop)
|
|
4064
|
+
delete props[d];
|
|
4065
|
+
const required = [...path, ...rest?.required ?? []].filter((k) => !drop.includes(k));
|
|
4066
|
+
return {
|
|
4067
|
+
type: "object",
|
|
4068
|
+
properties: props,
|
|
4069
|
+
...required.length ? { required: [...new Set(required)] } : {},
|
|
4070
|
+
additionalProperties: false
|
|
4071
|
+
};
|
|
4072
|
+
}
|
|
3079
4073
|
|
|
3080
4074
|
// ../src/shared/contracts/mcp-tools.ts
|
|
4075
|
+
function wireFromArgs(op, args) {
|
|
4076
|
+
const names = new Set(pathParams(op.path));
|
|
4077
|
+
const path = {};
|
|
4078
|
+
const query = {};
|
|
4079
|
+
const body = {};
|
|
4080
|
+
for (const [k, v] of Object.entries(args)) {
|
|
4081
|
+
if (v === undefined || v === null)
|
|
4082
|
+
continue;
|
|
4083
|
+
if (names.has(k))
|
|
4084
|
+
path[k] = String(v);
|
|
4085
|
+
else if (op.method === "GET")
|
|
4086
|
+
query[k] = typeof v === "string" ? v : JSON.stringify(v);
|
|
4087
|
+
else
|
|
4088
|
+
body[k] = v;
|
|
4089
|
+
}
|
|
4090
|
+
return { path, query, body: op.method === "GET" ? undefined : body };
|
|
4091
|
+
}
|
|
3081
4092
|
function wireInput(operationId, opts = {}) {
|
|
3082
4093
|
const op = apiOperation(operationId);
|
|
3083
4094
|
if (!op)
|
|
@@ -3087,7 +4098,7 @@ function wireInput(operationId, opts = {}) {
|
|
|
3087
4098
|
for (const [k, v] of Object.entries(op.input.shape))
|
|
3088
4099
|
if (!omit.has(k))
|
|
3089
4100
|
shape[toSnake(k)] = v;
|
|
3090
|
-
return
|
|
4101
|
+
return z24.object(shape);
|
|
3091
4102
|
}
|
|
3092
4103
|
var BUDGETS = [
|
|
3093
4104
|
{ stringBytes: MCP_LIMITS.untrustedStringMaxBytes, listMax: MCP_LIMITS.listMax },
|
|
@@ -3177,27 +4188,40 @@ function errorResult(o) {
|
|
|
3177
4188
|
}
|
|
3178
4189
|
};
|
|
3179
4190
|
}
|
|
3180
|
-
var TOOL_OUTPUT_SCHEMA =
|
|
3181
|
-
untrusted:
|
|
3182
|
-
data:
|
|
3183
|
-
provenance:
|
|
3184
|
-
source:
|
|
3185
|
-
operations:
|
|
4191
|
+
var TOOL_OUTPUT_SCHEMA = z24.object({
|
|
4192
|
+
untrusted: z24.object({
|
|
4193
|
+
data: z24.unknown(),
|
|
4194
|
+
provenance: z24.object({
|
|
4195
|
+
source: z24.enum(["node", "control_plane", "docs"]),
|
|
4196
|
+
operations: z24.array(z24.string())
|
|
3186
4197
|
})
|
|
3187
4198
|
}).optional(),
|
|
3188
|
-
doc:
|
|
3189
|
-
results:
|
|
3190
|
-
next_cursor:
|
|
3191
|
-
complete:
|
|
3192
|
-
omitted:
|
|
3193
|
-
truncated:
|
|
3194
|
-
suspicious_unicode:
|
|
3195
|
-
error:
|
|
3196
|
-
code:
|
|
3197
|
-
status:
|
|
3198
|
-
detail:
|
|
3199
|
-
scope:
|
|
3200
|
-
retry_after:
|
|
4199
|
+
doc: z24.object({ slug: z24.string(), locale: z24.enum(["en", "vi"]), url: z24.string(), markdown: z24.string(), truncated: z24.boolean() }).optional(),
|
|
4200
|
+
results: z24.array(z24.object({ slug: z24.string(), title: z24.string(), description: z24.string(), section: z24.string(), url: z24.string() })).optional(),
|
|
4201
|
+
next_cursor: z24.string().nullable().optional(),
|
|
4202
|
+
complete: z24.boolean().optional(),
|
|
4203
|
+
omitted: z24.array(z24.object({ part: z24.string(), reason: z24.string(), scope: z24.string().optional() })).optional(),
|
|
4204
|
+
truncated: z24.literal(true).optional(),
|
|
4205
|
+
suspicious_unicode: z24.literal(true).optional(),
|
|
4206
|
+
error: z24.object({
|
|
4207
|
+
code: z24.string(),
|
|
4208
|
+
status: z24.number(),
|
|
4209
|
+
detail: z24.string().optional(),
|
|
4210
|
+
scope: z24.string().optional(),
|
|
4211
|
+
retry_after: z24.number().optional()
|
|
4212
|
+
}).optional(),
|
|
4213
|
+
operations: z24.array(z24.record(z24.string(), z24.unknown())).optional(),
|
|
4214
|
+
operation: z24.record(z24.string(), z24.unknown()).optional(),
|
|
4215
|
+
plan: z24.record(z24.string(), z24.unknown()).optional(),
|
|
4216
|
+
status: z24.enum(["done", "approval_required", "approval_pending", ...APPROVAL_STATES]).optional(),
|
|
4217
|
+
approval: z24.object({
|
|
4218
|
+
approval_id: z24.string(),
|
|
4219
|
+
approval_url: z24.string(),
|
|
4220
|
+
expires_at: z24.string(),
|
|
4221
|
+
state: z24.enum(APPROVAL_STATES),
|
|
4222
|
+
result_code: z24.string().nullable().optional(),
|
|
4223
|
+
result: z24.record(z24.string(), z24.unknown()).optional(),
|
|
4224
|
+
next: z24.string().optional()
|
|
3201
4225
|
}).optional()
|
|
3202
4226
|
});
|
|
3203
4227
|
var spec = (name) => {
|
|
@@ -3243,22 +4267,95 @@ var has = (rt, operationId) => {
|
|
|
3243
4267
|
return !!op && rt.scopes.includes(op.scope);
|
|
3244
4268
|
};
|
|
3245
4269
|
var isoWindow = {
|
|
3246
|
-
start:
|
|
3247
|
-
end:
|
|
4270
|
+
start: z24.string().max(40).describe("RFC 3339 start of the window, e.g. 2026-10-26T00:00:00Z. Required with end."),
|
|
4271
|
+
end: z24.string().max(40).describe("RFC 3339 end of the window. The plan limits its length.")
|
|
3248
4272
|
};
|
|
3249
|
-
var traceIdSchema =
|
|
4273
|
+
var traceIdSchema = z24.string().regex(/^[0-9a-fA-F]{32}$/);
|
|
3250
4274
|
var MONITOR_KINDS2 = {
|
|
3251
4275
|
cron: { list: "monitors.list", get: "monitors.get", idField: "monitor_id" },
|
|
3252
4276
|
uptime: { list: "uptime.list", get: "uptime.get", idField: "check_id" },
|
|
3253
4277
|
slo: { list: "slos.list", get: "slos.get", idField: "slo_id" }
|
|
3254
4278
|
};
|
|
4279
|
+
var DESTRUCTIVE_VERBS = new Set([
|
|
4280
|
+
"delete",
|
|
4281
|
+
"revoke",
|
|
4282
|
+
"remove",
|
|
4283
|
+
"schedule_deletion",
|
|
4284
|
+
"rotate",
|
|
4285
|
+
"reset",
|
|
4286
|
+
"revoke_previous",
|
|
4287
|
+
"rebuild",
|
|
4288
|
+
"change_role"
|
|
4289
|
+
]);
|
|
4290
|
+
function configureOperations() {
|
|
4291
|
+
return API_OPERATIONS.filter((o) => o.mcp === "configure");
|
|
4292
|
+
}
|
|
4293
|
+
function configureOp(id) {
|
|
4294
|
+
if (typeof id !== "string")
|
|
4295
|
+
return null;
|
|
4296
|
+
const op = apiOperation(id);
|
|
4297
|
+
return op && op.mcp === "configure" ? op : null;
|
|
4298
|
+
}
|
|
4299
|
+
function isDestructiveOperation(op) {
|
|
4300
|
+
return op.method === "DELETE" || DESTRUCTIVE_VERBS.has(op.id.slice(op.id.indexOf(".") + 1));
|
|
4301
|
+
}
|
|
4302
|
+
var humanWire = (op) => (APPROVAL_HUMAN_FIELDS[op.id] ?? []).map(toSnake);
|
|
4303
|
+
function resourceRead(op) {
|
|
4304
|
+
if (op.method === "GET")
|
|
4305
|
+
return null;
|
|
4306
|
+
return API_OPERATIONS.find((o) => o.method === "GET" && o.path === op.path && o.kind !== "node") ?? null;
|
|
4307
|
+
}
|
|
4308
|
+
var PLACEHOLDER_WS = "00000000-0000-0000-0000-000000000000";
|
|
4309
|
+
function validateConfigure(op, params) {
|
|
4310
|
+
for (const f of humanWire(op))
|
|
4311
|
+
if (f in params)
|
|
4312
|
+
return { ok: false, errors: [{ pointer: `/${f}`, code: "typed_by_approver" }] };
|
|
4313
|
+
const input = buildOpInput(op, wireFromArgs(op, params), PLACEHOLDER_WS);
|
|
4314
|
+
if (input["__invalidBody"])
|
|
4315
|
+
return { ok: false, errors: [{ pointer: "", code: "object_expected" }] };
|
|
4316
|
+
const schema = op.sensitivity === "approval" ? approvalRequestSchema(op.id, op.input) : op.input;
|
|
4317
|
+
const r = schema.safeParse(input);
|
|
4318
|
+
if (r.success)
|
|
4319
|
+
return { ok: true };
|
|
4320
|
+
return {
|
|
4321
|
+
ok: false,
|
|
4322
|
+
errors: wireErrors(op, r.error)
|
|
4323
|
+
};
|
|
4324
|
+
}
|
|
4325
|
+
function describe(op, scopes) {
|
|
4326
|
+
return {
|
|
4327
|
+
operation_id: op.id,
|
|
4328
|
+
summary: op.summary,
|
|
4329
|
+
method: op.method,
|
|
4330
|
+
path: op.path,
|
|
4331
|
+
scope: op.scope,
|
|
4332
|
+
scope_held: scopes.includes(op.scope),
|
|
4333
|
+
requires_approval: op.sensitivity === "approval",
|
|
4334
|
+
destructive: isDestructiveOperation(op)
|
|
4335
|
+
};
|
|
4336
|
+
}
|
|
4337
|
+
var params = z24.record(z24.string(), z24.unknown()).default({}).describe("Operation fields in wire names (snake_case), as describe_operation's args_schema shows.");
|
|
4338
|
+
var operationIdArg = z24.string().min(3).max(80).describe("An operation id from search_operations, e.g. `monitors.update`.");
|
|
4339
|
+
function approvalBlock(t, next) {
|
|
4340
|
+
return {
|
|
4341
|
+
approval_id: t.approval_id,
|
|
4342
|
+
approval_url: t.approval_url,
|
|
4343
|
+
expires_at: t.expires_at,
|
|
4344
|
+
state: t.state,
|
|
4345
|
+
...t.result_code !== undefined ? { result_code: t.result_code } : {},
|
|
4346
|
+
...t.result !== undefined ? { result: t.result } : {},
|
|
4347
|
+
next
|
|
4348
|
+
};
|
|
4349
|
+
}
|
|
4350
|
+
var NEXT_PENDING = "A person with the right role must approve this on belvador.dev (open approval_url; it needs their authenticator code). Nothing has changed yet. Show the link to the user, then call get_operation with approval_id, or apply_change again with the same idempotency_key to get the result.";
|
|
4351
|
+
var NEXT_SETUP = "The approving person also types the secret (bot token, webhook URL, password) on that page; it never passes through the agent.";
|
|
3255
4352
|
var MCP_TOOL_DEFS = [
|
|
3256
4353
|
{
|
|
3257
4354
|
...spec("get_workspace"),
|
|
3258
4355
|
title: "Workspace and node",
|
|
3259
4356
|
description: "The workspace this token belongs to (name, plan, limits) and the state of its node, the server that stores errors, traces and logs. Start here to learn what the token can reach.",
|
|
3260
4357
|
operations: ["workspace.get", "node.get"],
|
|
3261
|
-
input:
|
|
4358
|
+
input: z24.object({}),
|
|
3262
4359
|
async run(_args, rt) {
|
|
3263
4360
|
const [ws, node] = await Promise.all([rt.call("workspace.get", {}), rt.call("node.get", {})]);
|
|
3264
4361
|
if (!ws.ok)
|
|
@@ -3276,9 +4373,9 @@ var MCP_TOOL_DEFS = [
|
|
|
3276
4373
|
title: "Get an issue",
|
|
3277
4374
|
description: "One issue with its 24 h and 30 d counts and, when the token can read events, its latest event (stack trace, request, breadcrumbs — scrubbed on the node).",
|
|
3278
4375
|
operations: ["issues.get", "events.get"],
|
|
3279
|
-
input:
|
|
3280
|
-
issue_id:
|
|
3281
|
-
include_latest_event:
|
|
4376
|
+
input: z24.object({
|
|
4377
|
+
issue_id: z24.number().int().positive().describe("Issue id from search_issues."),
|
|
4378
|
+
include_latest_event: z24.boolean().default(true)
|
|
3282
4379
|
}),
|
|
3283
4380
|
async run(args, rt) {
|
|
3284
4381
|
const omitted = [];
|
|
@@ -3306,9 +4403,9 @@ var MCP_TOOL_DEFS = [
|
|
|
3306
4403
|
title: "Get a trace",
|
|
3307
4404
|
description: "Summary of one distributed trace (services, duration, errors) by its 32-hex trace id, and optionally its spans (errors only, or the first page).",
|
|
3308
4405
|
operations: ["traces.get", "traces.spans"],
|
|
3309
|
-
input:
|
|
4406
|
+
input: z24.object({
|
|
3310
4407
|
trace_id: traceIdSchema.describe("W3C trace id, 32 hex characters."),
|
|
3311
|
-
spans:
|
|
4408
|
+
spans: z24.enum(["none", "errors", "all"]).default("none")
|
|
3312
4409
|
}),
|
|
3313
4410
|
async run(args, rt) {
|
|
3314
4411
|
const sum = await rt.call("traces.get", { trace_id: args["trace_id"] });
|
|
@@ -3336,11 +4433,11 @@ var MCP_TOOL_DEFS = [
|
|
|
3336
4433
|
title: "Correlate by trace or run",
|
|
3337
4434
|
description: "Everything that shares one W3C trace id or one Belvador run id (`belvador.run.id`, set by job monitors) in a time window: the trace summary, its error spans and the logs. Give exactly one of trace_id or run_id.",
|
|
3338
4435
|
operations: ["traces.get", "traces.spans", "spans.list", "logs.list"],
|
|
3339
|
-
input:
|
|
4436
|
+
input: z24.object({
|
|
3340
4437
|
trace_id: traceIdSchema.optional(),
|
|
3341
|
-
run_id:
|
|
4438
|
+
run_id: z24.string().min(1).max(128).optional(),
|
|
3342
4439
|
...isoWindow,
|
|
3343
|
-
project:
|
|
4440
|
+
project: z24.string().max(2000).optional().describe("Comma-separated project ids.")
|
|
3344
4441
|
}),
|
|
3345
4442
|
async run(args, rt) {
|
|
3346
4443
|
const trace = args["trace_id"];
|
|
@@ -3383,12 +4480,12 @@ var MCP_TOOL_DEFS = [
|
|
|
3383
4480
|
{
|
|
3384
4481
|
...spec("list_monitors"),
|
|
3385
4482
|
title: "List monitors",
|
|
3386
|
-
description: "
|
|
4483
|
+
description: "Monitors (cron, heartbeat, count, assertion, deadline, progress), uptime checks and SLOs with their current status. `kind` narrows to one family; `project_id` to one project (cron and uptime).",
|
|
3387
4484
|
operations: ["monitors.list", "uptime.list", "slos.list"],
|
|
3388
|
-
input:
|
|
3389
|
-
kind:
|
|
3390
|
-
project_id:
|
|
3391
|
-
limit:
|
|
4485
|
+
input: z24.object({
|
|
4486
|
+
kind: z24.enum(["all", "cron", "uptime", "slo"]).default("all"),
|
|
4487
|
+
project_id: z24.number().int().positive().optional(),
|
|
4488
|
+
limit: z24.number().int().min(1).max(200).default(50)
|
|
3392
4489
|
}),
|
|
3393
4490
|
async run(args, rt) {
|
|
3394
4491
|
const kinds = args["kind"] && args["kind"] !== "all" ? [args["kind"]] : ["cron", "uptime", "slo"];
|
|
@@ -3414,26 +4511,69 @@ var MCP_TOOL_DEFS = [
|
|
|
3414
4511
|
{
|
|
3415
4512
|
...spec("get_monitor_status"),
|
|
3416
4513
|
title: "Get a monitor",
|
|
3417
|
-
description: "One
|
|
3418
|
-
operations: ["monitors.get", "uptime.get", "slos.get"],
|
|
3419
|
-
input:
|
|
4514
|
+
description: "One monitor (any type), uptime check or SLO by id: settings, current status and recent results. For count, assertion, deadline and progress monitors it adds the last 24 h of minute counts or runs from the node, and for deadline monitors the newest occurrences. `backtest: true` (count/assertion only) also replays the current settings over the last 30 days: how often it would have alerted.",
|
|
4515
|
+
operations: ["monitors.get", "uptime.get", "slos.get", "monitors.signal", "monitors.occurrences", "monitors.backtest"],
|
|
4516
|
+
input: z24.object({
|
|
4517
|
+
kind: z24.enum(["cron", "uptime", "slo"]),
|
|
4518
|
+
id: z24.guid(),
|
|
4519
|
+
backtest: z24.boolean().default(false)
|
|
4520
|
+
}),
|
|
3420
4521
|
async run(args, rt) {
|
|
3421
4522
|
const k = MONITOR_KINDS2[args["kind"]];
|
|
3422
4523
|
const r = await rt.call(k.get, { [k.idField]: args["id"] });
|
|
3423
4524
|
if (!r.ok)
|
|
3424
4525
|
return errorResult(r);
|
|
3425
|
-
|
|
4526
|
+
const row = r.body ?? {};
|
|
4527
|
+
const type = typeof row["type"] === "string" ? row["type"] : "job";
|
|
4528
|
+
if (k.get !== "monitors.get" || !isSignalMonitorType(type)) {
|
|
4529
|
+
return wrapResult({ data: r.body, operations: [k.get], source: "control_plane" });
|
|
4530
|
+
}
|
|
4531
|
+
const ops = [k.get, "monitors.signal"];
|
|
4532
|
+
const calls = [
|
|
4533
|
+
rt.call("monitors.signal", { monitor_id: args["id"], hours: 24 })
|
|
4534
|
+
];
|
|
4535
|
+
const parts = ["signal"];
|
|
4536
|
+
if (type === "deadline") {
|
|
4537
|
+
ops.push("monitors.occurrences");
|
|
4538
|
+
parts.push("occurrences");
|
|
4539
|
+
calls.push(rt.call("monitors.occurrences", { monitor_id: args["id"], state: "all" }));
|
|
4540
|
+
}
|
|
4541
|
+
const settings = args["backtest"] === true && (type === "count" || type === "assertion") ? settingsFromRow({
|
|
4542
|
+
type,
|
|
4543
|
+
signal_settings: row["signal_settings"],
|
|
4544
|
+
expected_environments: Array.isArray(row["expected_environments"]) ? row["expected_environments"] : [],
|
|
4545
|
+
severity: String(row["severity"] ?? "medium"),
|
|
4546
|
+
recovery_threshold: Number(row["recovery_threshold"] ?? 1)
|
|
4547
|
+
}) : null;
|
|
4548
|
+
if (settings) {
|
|
4549
|
+
ops.push("monitors.backtest");
|
|
4550
|
+
parts.push("backtest");
|
|
4551
|
+
calls.push(rt.call("monitors.backtest", { project: row["project_id"], settings }));
|
|
4552
|
+
}
|
|
4553
|
+
const answers = await Promise.all(calls);
|
|
4554
|
+
const data = { monitor: r.body };
|
|
4555
|
+
const omitted = [];
|
|
4556
|
+
for (const [i, part] of parts.entries()) {
|
|
4557
|
+
const a = answers[i];
|
|
4558
|
+
if (a.ok)
|
|
4559
|
+
data[part] = part === "occurrences" ? withoutPaging(a.body) : a.body;
|
|
4560
|
+
else
|
|
4561
|
+
omitted.push({ part, reason: a.code });
|
|
4562
|
+
}
|
|
4563
|
+
return wrapResult({ data, operations: ops, source: omitted.length === parts.length ? "control_plane" : "node" }, { omitted });
|
|
3426
4564
|
}
|
|
3427
4565
|
},
|
|
3428
4566
|
single("list_alerts", "alerts.list", "List alerts", "Alerts Belvador raised (open, resolved or all), newest first, optionally for one monitor."),
|
|
4567
|
+
single("list_incidents", "incidents.list", "List incidents", "Incidents (INC-n): related alerts grouped into one piece of work. State (open, acknowledged, monitoring, resolved), severity and peak, owner, linked and still-firing alert counts; newest first. `state` = active, resolved or all. Returns ids for get_incident."),
|
|
4568
|
+
single("get_incident", "incidents.get", "Get an incident", "One incident by id: its linked alerts (monitor, uptime, SLO, issue) with ids for get_monitor_status or get_issue, the timeline (opened, joined, acknowledged, notes, escalation, resolution) and each message's delivery state. `accepted` means the service took the message; only `acknowledged: true` means a person took the incident."),
|
|
3429
4569
|
{
|
|
3430
4570
|
...spec("verify_integration"),
|
|
3431
4571
|
title: "Send a test event",
|
|
3432
4572
|
description: "Asks the node to send one tagged test error through the public intake of a project, proving the path real errors take. Not read-only: it creates one test event (reuse idempotency_key to retry without a second one).",
|
|
3433
4573
|
operations: ["projects.send_test_event"],
|
|
3434
|
-
input:
|
|
3435
|
-
project_id:
|
|
3436
|
-
idempotency_key:
|
|
4574
|
+
input: z24.object({
|
|
4575
|
+
project_id: z24.number().int().positive(),
|
|
4576
|
+
idempotency_key: z24.string().min(8).max(255).optional()
|
|
3437
4577
|
}),
|
|
3438
4578
|
async run(args, rt) {
|
|
3439
4579
|
const r = await rt.call("projects.send_test_event", { project_id: args["project_id"] }, { idempotencyKey: args["idempotency_key"] ?? rt.newKey() });
|
|
@@ -3442,15 +4582,198 @@ var MCP_TOOL_DEFS = [
|
|
|
3442
4582
|
return wrapResult({ data: r.body, operations: ["projects.send_test_event"], source: "control_plane" });
|
|
3443
4583
|
}
|
|
3444
4584
|
},
|
|
4585
|
+
{
|
|
4586
|
+
...spec("search_operations"),
|
|
4587
|
+
title: "Find a configuration change",
|
|
4588
|
+
description: "Searches what this token can change in its Belvador workspace: projects, keys and tokens, monitors of every type, maintenance windows, occurrences, uptime checks, SLOs, alert rules and destinations, members, service accounts and the node. Returns operation ids for describe_operation and plan_change, whether a person must approve the change, and whether this token holds the scope.",
|
|
4589
|
+
operations: [],
|
|
4590
|
+
input: z24.object({
|
|
4591
|
+
query: z24.string().min(1).max(200).describe("Words such as `rotate dsn key`, `heartbeat monitor`, `slack alert`."),
|
|
4592
|
+
limit: z24.number().int().min(1).max(20).default(10)
|
|
4593
|
+
}),
|
|
4594
|
+
async run(args, rt) {
|
|
4595
|
+
const q = words(String(args["query"]));
|
|
4596
|
+
const scored = configureOperations().filter((o) => o.method !== "GET").map((o) => {
|
|
4597
|
+
const id = words(o.id.replace(/[._]/g, " "));
|
|
4598
|
+
const rest = words(`${o.summary} ${o.path}`);
|
|
4599
|
+
let score = 0;
|
|
4600
|
+
for (const w of q) {
|
|
4601
|
+
if (id.some((t) => t === w))
|
|
4602
|
+
score += 4;
|
|
4603
|
+
else if (id.some((t) => t.startsWith(w)))
|
|
4604
|
+
score += 2;
|
|
4605
|
+
if (rest.some((t) => t === w))
|
|
4606
|
+
score += 2;
|
|
4607
|
+
else if (rest.some((t) => t.startsWith(w)))
|
|
4608
|
+
score += 1;
|
|
4609
|
+
}
|
|
4610
|
+
return { o, score };
|
|
4611
|
+
}).filter((x) => x.score > 0).sort((a, b) => b.score - a.score || a.o.id.localeCompare(b.o.id)).slice(0, Number(args["limit"] ?? 10));
|
|
4612
|
+
return { structuredContent: { operations: scored.map((x) => describe(x.o, rt.scopes)) } };
|
|
4613
|
+
}
|
|
4614
|
+
},
|
|
4615
|
+
{
|
|
4616
|
+
...spec("describe_operation"),
|
|
4617
|
+
title: "Describe a configuration change",
|
|
4618
|
+
description: "Everything needed to call one operation: its fields (JSON Schema, wire names), the scope, whether it needs If-Match (call plan_change for the current ETag), an idempotency key, or a person's approval, and which fields the approving person types on belvador.dev instead of the agent.",
|
|
4619
|
+
operations: [],
|
|
4620
|
+
input: z24.object({ operation_id: operationIdArg }),
|
|
4621
|
+
async run(args, rt) {
|
|
4622
|
+
const op = configureOp(args["operation_id"]);
|
|
4623
|
+
if (!op || op.method === "GET")
|
|
4624
|
+
return errorResult({ ok: false, status: 404, code: "NOT_FOUND" });
|
|
4625
|
+
const approval = op.sensitivity === "approval";
|
|
4626
|
+
return {
|
|
4627
|
+
structuredContent: {
|
|
4628
|
+
operation: {
|
|
4629
|
+
...describe(op, rt.scopes),
|
|
4630
|
+
idempotency: op.idempotency,
|
|
4631
|
+
if_match_required: !!op.ifMatch,
|
|
4632
|
+
args_schema: operationArgsSchema(op, humanWire(op)),
|
|
4633
|
+
...approval ? {
|
|
4634
|
+
approver: APPROVAL_APPROVER[op.id] ?? "admin",
|
|
4635
|
+
typed_by_approver: humanWire(op),
|
|
4636
|
+
secrets_typed_by_approver: APPROVAL_SETUP_OPS.includes(op.id)
|
|
4637
|
+
} : {},
|
|
4638
|
+
...op.secretOutput?.length ? { secret_output: [...op.secretOutput] } : {}
|
|
4639
|
+
}
|
|
4640
|
+
}
|
|
4641
|
+
};
|
|
4642
|
+
}
|
|
4643
|
+
},
|
|
4644
|
+
{
|
|
4645
|
+
...spec("plan_change"),
|
|
4646
|
+
title: "Check a change before applying it",
|
|
4647
|
+
description: "Validates params for one operation without changing anything: field errors, missing scope, whether a person must approve, and — when the resource can be read — its current state, the fields that would change and the ETag to pass as if_match.",
|
|
4648
|
+
operations: [],
|
|
4649
|
+
input: z24.object({ operation_id: operationIdArg, params }),
|
|
4650
|
+
async run(args, rt) {
|
|
4651
|
+
const op = configureOp(args["operation_id"]);
|
|
4652
|
+
if (!op || op.method === "GET")
|
|
4653
|
+
return errorResult({ ok: false, status: 404, code: "NOT_FOUND" });
|
|
4654
|
+
const p = args["params"] ?? {};
|
|
4655
|
+
const v = validateConfigure(op, p);
|
|
4656
|
+
const scopeMissing = rt.scopes.includes(op.scope) ? [] : [op.scope];
|
|
4657
|
+
let etag = null;
|
|
4658
|
+
let current = undefined;
|
|
4659
|
+
const read = resourceRead(op);
|
|
4660
|
+
const ids = read ? Object.fromEntries(pathParams(read.path).map((n) => [n, p[n]])) : {};
|
|
4661
|
+
if (read && rt.scopes.includes(read.scope) && Object.values(ids).every((x) => x != null && x !== "")) {
|
|
4662
|
+
const r = await rt.call(read.id, ids);
|
|
4663
|
+
if (r.ok) {
|
|
4664
|
+
etag = r.etag ?? null;
|
|
4665
|
+
current = r.body;
|
|
4666
|
+
}
|
|
4667
|
+
}
|
|
4668
|
+
const changes = Object.entries(p).filter(([k]) => !pathParams(op.path).includes(k)).map(([field, to]) => {
|
|
4669
|
+
const cur = current && typeof current === "object" && !Array.isArray(current) ? current : null;
|
|
4670
|
+
return cur && field in cur ? { field, from: cur[field], to } : { field, to };
|
|
4671
|
+
});
|
|
4672
|
+
const plan = {
|
|
4673
|
+
operation_id: op.id,
|
|
4674
|
+
valid: v.ok,
|
|
4675
|
+
...v.ok ? {} : { errors: v.errors },
|
|
4676
|
+
scope: op.scope,
|
|
4677
|
+
scope_missing: scopeMissing,
|
|
4678
|
+
requires_approval: op.sensitivity === "approval",
|
|
4679
|
+
...op.sensitivity === "approval" ? { approver: APPROVAL_APPROVER[op.id] ?? "admin" } : {},
|
|
4680
|
+
destructive: isDestructiveOperation(op),
|
|
4681
|
+
idempotency: op.idempotency,
|
|
4682
|
+
if_match_required: !!op.ifMatch,
|
|
4683
|
+
etag
|
|
4684
|
+
};
|
|
4685
|
+
const out = wrapResult({
|
|
4686
|
+
data: { changes, ...current !== undefined ? { current } : {} },
|
|
4687
|
+
operations: read && current !== undefined ? [read.id] : [],
|
|
4688
|
+
source: "control_plane"
|
|
4689
|
+
});
|
|
4690
|
+
return { structuredContent: { plan, ...out.structuredContent } };
|
|
4691
|
+
}
|
|
4692
|
+
},
|
|
4693
|
+
{
|
|
4694
|
+
...spec("apply_change"),
|
|
4695
|
+
title: "Apply a configuration change",
|
|
4696
|
+
description: "Runs one operation with params (validate first with plan_change). Always send idempotency_key: repeating a call with the same key never applies it twice. Sensitive operations answer approval_required with an approval_url a person opens on belvador.dev; nothing changes until they approve with their authenticator code.",
|
|
4697
|
+
operations: [],
|
|
4698
|
+
input: z24.object({
|
|
4699
|
+
operation_id: operationIdArg,
|
|
4700
|
+
params,
|
|
4701
|
+
idempotency_key: z24.string().min(8).max(255).describe("Unique per change; reuse it to retry or to fetch the result."),
|
|
4702
|
+
if_match: z24.string().max(200).optional().describe("ETag from plan_change, for operations that need it.")
|
|
4703
|
+
}),
|
|
4704
|
+
async run(args, rt) {
|
|
4705
|
+
const op = configureOp(args["operation_id"]);
|
|
4706
|
+
if (!op || op.method === "GET")
|
|
4707
|
+
return errorResult({ ok: false, status: 404, code: "NOT_FOUND" });
|
|
4708
|
+
const p = args["params"] ?? {};
|
|
4709
|
+
for (const f of humanWire(op))
|
|
4710
|
+
if (f in p)
|
|
4711
|
+
return errorResult({ ok: false, status: 400, code: "INVALID_INPUT", detail: `${f} is typed by the approving person` });
|
|
4712
|
+
const opts = { idempotencyKey: String(args["idempotency_key"]) };
|
|
4713
|
+
if (typeof args["if_match"] === "string" && args["if_match"])
|
|
4714
|
+
opts.ifMatch = args["if_match"];
|
|
4715
|
+
const r = await rt.call(op.id, p, opts);
|
|
4716
|
+
if (r.ok) {
|
|
4717
|
+
const body = r.body;
|
|
4718
|
+
if (op.sensitivity === "approval" && body && typeof body["approval_id"] === "string") {
|
|
4719
|
+
return {
|
|
4720
|
+
structuredContent: {
|
|
4721
|
+
status: "executed",
|
|
4722
|
+
approval: approvalBlock(body, "Approved and run once by a person; result holds the ids.")
|
|
4723
|
+
}
|
|
4724
|
+
};
|
|
4725
|
+
}
|
|
4726
|
+
const out = wrapResult({ data: r.body, operations: [op.id], source: sourceOf(op.id) });
|
|
4727
|
+
return { structuredContent: { status: "done", ...out.structuredContent } };
|
|
4728
|
+
}
|
|
4729
|
+
if (r.approval && r.approval.state === "pending") {
|
|
4730
|
+
const next = APPROVAL_SETUP_OPS.includes(op.id) ? `${NEXT_PENDING} ${NEXT_SETUP}` : NEXT_PENDING;
|
|
4731
|
+
return {
|
|
4732
|
+
structuredContent: { status: "approval_required", approval: approvalBlock(r.approval, next) },
|
|
4733
|
+
approval: r.approval
|
|
4734
|
+
};
|
|
4735
|
+
}
|
|
4736
|
+
if (r.approval) {
|
|
4737
|
+
return {
|
|
4738
|
+
isError: true,
|
|
4739
|
+
structuredContent: {
|
|
4740
|
+
...errorResult(r).structuredContent,
|
|
4741
|
+
approval: approvalBlock(r.approval, "This request is closed; send a new one with a new idempotency_key if the change is still wanted.")
|
|
4742
|
+
}
|
|
4743
|
+
};
|
|
4744
|
+
}
|
|
4745
|
+
return errorResult(r);
|
|
4746
|
+
}
|
|
4747
|
+
},
|
|
4748
|
+
{
|
|
4749
|
+
...spec("get_operation"),
|
|
4750
|
+
title: "Follow an approval",
|
|
4751
|
+
description: "State of a change waiting for a person's approval: pending, approved, executed (with the ids it produced), rejected, expired or failed (with the error code).",
|
|
4752
|
+
operations: ["approvals.get"],
|
|
4753
|
+
input: z24.object({ approval_id: z24.guid().describe("approval_id from apply_change.") }),
|
|
4754
|
+
async run(args, rt) {
|
|
4755
|
+
const r = await rt.call("approvals.get", { approval_id: args["approval_id"] });
|
|
4756
|
+
if (!r.ok)
|
|
4757
|
+
return errorResult(r);
|
|
4758
|
+
const b = r.body;
|
|
4759
|
+
const next = b.state === "pending" ? NEXT_PENDING : b.state === "executed" ? "Done: the change ran once." : b.state === "approved" ? "Approved; the change is running or waits for the person to finish the form." : "Closed without a change.";
|
|
4760
|
+
return {
|
|
4761
|
+
structuredContent: {
|
|
4762
|
+
status: b.state,
|
|
4763
|
+
approval: approvalBlock({ ...b, approval_url: b.approval_url ?? "" }, next)
|
|
4764
|
+
}
|
|
4765
|
+
};
|
|
4766
|
+
}
|
|
4767
|
+
},
|
|
3445
4768
|
{
|
|
3446
4769
|
...spec("search_docs"),
|
|
3447
4770
|
title: "Search Belvador docs",
|
|
3448
4771
|
description: "Searches the public Belvador documentation (titles and summaries) and returns the best pages with their slugs for get_doc.",
|
|
3449
4772
|
operations: [],
|
|
3450
|
-
input:
|
|
3451
|
-
query:
|
|
3452
|
-
locale:
|
|
3453
|
-
limit:
|
|
4773
|
+
input: z24.object({
|
|
4774
|
+
query: z24.string().min(1).max(200),
|
|
4775
|
+
locale: z24.enum(["en", "vi"]).default("en"),
|
|
4776
|
+
limit: z24.number().int().min(1).max(10).default(5)
|
|
3454
4777
|
}),
|
|
3455
4778
|
async run(args, rt) {
|
|
3456
4779
|
const locale = args["locale"] ?? "en";
|
|
@@ -3466,9 +4789,9 @@ var MCP_TOOL_DEFS = [
|
|
|
3466
4789
|
title: "Read a docs page",
|
|
3467
4790
|
description: "The Markdown of one public Belvador docs page by slug (e.g. `quickstart`, `sdk/react`, `reference/api`).",
|
|
3468
4791
|
operations: [],
|
|
3469
|
-
input:
|
|
3470
|
-
slug:
|
|
3471
|
-
locale:
|
|
4792
|
+
input: z24.object({
|
|
4793
|
+
slug: z24.string().regex(/^[a-z0-9][a-z0-9/-]{0,120}$/),
|
|
4794
|
+
locale: z24.enum(["en", "vi"]).default("en")
|
|
3472
4795
|
}),
|
|
3473
4796
|
async run(args, rt) {
|
|
3474
4797
|
const locale = args["locale"] ?? "en";
|
|
@@ -3542,6 +4865,12 @@ function toolsFor(toolsets, scopes) {
|
|
|
3542
4865
|
|
|
3543
4866
|
// ../src/shared/mcp/server.ts
|
|
3544
4867
|
var MCP_SERVER_VERSION = `1.${MCP_TOOLS_VERSION}.0`;
|
|
4868
|
+
var APPROVAL_ELICIT_MESSAGE = "Belvador needs a person to approve this change. Open the link, review it and confirm with your authenticator code; then the agent continues.";
|
|
4869
|
+
function wantsApprovalLink(ctx) {
|
|
4870
|
+
const env = ctx?.mcpReq.envelope;
|
|
4871
|
+
const caps = env?.[CLIENT_CAPABILITIES_META_KEY];
|
|
4872
|
+
return !!caps?.elicitation?.url && !ctx?.mcpReq.inputResponses?.["approval"];
|
|
4873
|
+
}
|
|
3545
4874
|
function buildMcpServer(rt, toolsets) {
|
|
3546
4875
|
const server = new McpServer({ name: "belvador", title: "Belvador", version: MCP_SERVER_VERSION }, { instructions: MCP_SERVER_INSTRUCTIONS });
|
|
3547
4876
|
for (const t of toolsFor([...toolsets], rt.scopes)) {
|
|
@@ -3557,8 +4886,15 @@ function buildMcpServer(rt, toolsets) {
|
|
|
3557
4886
|
idempotentHint: t.idempotent,
|
|
3558
4887
|
openWorldHint: false
|
|
3559
4888
|
}
|
|
3560
|
-
}, async (args) => {
|
|
4889
|
+
}, async (args, ctx) => {
|
|
3561
4890
|
const r = await t.run(args, rt);
|
|
4891
|
+
if (r.approval && r.approval.state === "pending" && wantsApprovalLink(ctx)) {
|
|
4892
|
+
return inputRequired({
|
|
4893
|
+
inputRequests: {
|
|
4894
|
+
approval: inputRequired.elicitUrl({ message: APPROVAL_ELICIT_MESSAGE, url: r.approval.approval_url })
|
|
4895
|
+
}
|
|
4896
|
+
});
|
|
4897
|
+
}
|
|
3562
4898
|
return {
|
|
3563
4899
|
content: [{ type: "text", text: JSON.stringify(r.structuredContent) }],
|
|
3564
4900
|
structuredContent: r.structuredContent,
|
|
@@ -3579,7 +4915,15 @@ function outcomeOfError(e) {
|
|
|
3579
4915
|
code: e.code === "ABORTED" ? "UNAVAILABLE" : e.code,
|
|
3580
4916
|
...e.detail ? { detail: e.detail } : {},
|
|
3581
4917
|
...e.scope ? { scope: e.scope } : {},
|
|
3582
|
-
...e.retryAfter ? { retryAfter: e.retryAfter } : {}
|
|
4918
|
+
...e.retryAfter ? { retryAfter: e.retryAfter } : {},
|
|
4919
|
+
...e.approval ? {
|
|
4920
|
+
approval: {
|
|
4921
|
+
approval_id: e.approval.id,
|
|
4922
|
+
approval_url: e.approval.url,
|
|
4923
|
+
expires_at: e.approval.expiresAt,
|
|
4924
|
+
state: e.approval.state
|
|
4925
|
+
}
|
|
4926
|
+
} : {}
|
|
3583
4927
|
};
|
|
3584
4928
|
return { ok: false, status: 503, code: "UNAVAILABLE" };
|
|
3585
4929
|
}
|
|
@@ -3591,8 +4935,13 @@ function clientRuntime(client, scopes, docs) {
|
|
|
3591
4935
|
async call(operationId, args, opts) {
|
|
3592
4936
|
try {
|
|
3593
4937
|
const call = client.call.bind(client);
|
|
3594
|
-
const
|
|
3595
|
-
|
|
4938
|
+
const o = {};
|
|
4939
|
+
if (opts?.idempotencyKey)
|
|
4940
|
+
o.idempotencyKey = opts.idempotencyKey;
|
|
4941
|
+
if (opts?.ifMatch)
|
|
4942
|
+
o.ifMatch = opts.ifMatch;
|
|
4943
|
+
const r = await call(operationId, args, o);
|
|
4944
|
+
return { ok: true, status: r.status, body: r.data, etag: r.etag };
|
|
3596
4945
|
} catch (e) {
|
|
3597
4946
|
return outcomeOfError(e);
|
|
3598
4947
|
}
|
|
@@ -3624,7 +4973,7 @@ function findToken(env = process.env, keychain = keychainToken) {
|
|
|
3624
4973
|
}
|
|
3625
4974
|
|
|
3626
4975
|
// packages/mcp/src/cli.ts
|
|
3627
|
-
var PACKAGE_VERSION = "0.
|
|
4976
|
+
var PACKAGE_VERSION = "0.3.0";
|
|
3628
4977
|
var HELP = `belvador-mcp ${PACKAGE_VERSION} — Belvador MCP server (stdio)
|
|
3629
4978
|
|
|
3630
4979
|
Usage: npx -y @belvador/mcp [--toolsets=${MCP_DEFAULT_TOOLSETS.join(",")}]
|