feat(health-checks): enhance health check configuration and logging
quality / commitlint (push) Skipped
CD / update-wiki (push) Successful in 8s
quality / changes (push) Successful in 5s
quality / docker-check (push) Skipped
quality / web (push) Successful in 51s
quality / api (push) Successful in 44s
CD / quality (push) Successful in 1m44s
CD / publish (push) Successful in 1m35s
quality / commitlint (push) Skipped
CD / update-wiki (push) Successful in 8s
quality / changes (push) Successful in 5s
quality / docker-check (push) Skipped
quality / web (push) Successful in 51s
quality / api (push) Successful in 44s
CD / quality (push) Successful in 1m44s
CD / publish (push) Successful in 1m35s
- Added new health worker URL and token fields to the AppConfig interface, allowing for Cloudflare Worker integration. - Updated health check routes to utilize the new worker configuration, enabling dynamic health checks via Cloudflare Workers. - Introduced a health log endpoint for services, providing detailed logs of health probe results. - Enhanced health check service logic to support both local and Cloudflare Worker providers, improving flexibility in health monitoring. - Updated UI components to reflect changes in health check provider settings and display relevant health information. This commit significantly improves the health check management capabilities, allowing for better integration with Cloudflare Workers and enhanced logging features.
This commit is contained in:
Vendored
+693
-5
File diff suppressed because one or more lines are too long
Vendored
+118
-18
@@ -52,6 +52,7 @@ var serviceGroups = sqliteTable("service_groups", {
|
||||
health_check_interval_sec: integer("health_check_interval_sec").notNull().default(30),
|
||||
health_check_timeout_ms: integer("health_check_timeout_ms").notNull().default(3e3),
|
||||
health_check_verify_tls: integer("health_check_verify_tls", { mode: "boolean" }).notNull().default(false),
|
||||
health_check_provider: text("health_check_provider").notNull().default("local"),
|
||||
created_at: text("created_at").notNull().default(sql`datetime('now')`),
|
||||
updated_at: text("updated_at").notNull().default(sql`datetime('now')`)
|
||||
});
|
||||
@@ -117,6 +118,7 @@ var serviceBindings = sqliteTable(
|
||||
health_check_verify_tls: integer("health_check_verify_tls", {
|
||||
mode: "boolean"
|
||||
}).notNull().default(false),
|
||||
health_check_provider: text("health_check_provider").notNull().default("local"),
|
||||
routing_strategy: text("routing_strategy").notNull().default("round_robin"),
|
||||
operation_version: integer("operation_version").notNull().default(0),
|
||||
created_at: text("created_at").notNull().default(sql`datetime('now')`),
|
||||
@@ -252,6 +254,8 @@ var ipHealthStatus = sqliteTable(
|
||||
consecutive_successes: integer("consecutive_successes").notNull().default(0),
|
||||
last_checked_at: text("last_checked_at"),
|
||||
last_error: text("last_error"),
|
||||
colo: text("colo"),
|
||||
provider: text("provider").notNull().default("local"),
|
||||
created_at: text("created_at").notNull().default(sql`datetime('now')`),
|
||||
updated_at: text("updated_at").notNull().default(sql`datetime('now')`)
|
||||
},
|
||||
@@ -275,6 +279,8 @@ var appSettings = sqliteTable("app_settings", {
|
||||
health_down_failures: integer("health_down_failures"),
|
||||
health_latency_warn_ms: integer("health_latency_warn_ms"),
|
||||
health_success_recoveries: integer("health_success_recoveries"),
|
||||
health_worker_url: text("health_worker_url"),
|
||||
health_worker_token: text("health_worker_token"),
|
||||
created_at: text("created_at").notNull().default(sql`datetime('now')`),
|
||||
updated_at: text("updated_at").notNull().default(sql`datetime('now')`)
|
||||
});
|
||||
@@ -311,6 +317,19 @@ var domainMonitorResults = sqliteTable("domain_monitor_results", {
|
||||
error: text("error"),
|
||||
checked_at: text("checked_at").notNull().default(sql`datetime('now')`)
|
||||
});
|
||||
var healthProbeLog = sqliteTable("health_probe_log", {
|
||||
id: integer("id").primaryKey({ autoIncrement: true }),
|
||||
scope: text("scope").notNull(),
|
||||
ref_id: integer("ref_id").notNull(),
|
||||
ip: text("ip").notNull(),
|
||||
provider: text("provider").notNull(),
|
||||
status: text("status").notNull(),
|
||||
ok: integer("ok", { mode: "boolean" }).notNull(),
|
||||
latency_ms: integer("latency_ms"),
|
||||
colo: text("colo"),
|
||||
error: text("error"),
|
||||
checked_at: text("checked_at").notNull().default(sql`datetime('now')`)
|
||||
});
|
||||
var notificationLog = sqliteTable("notification_log", {
|
||||
id: integer("id").primaryKey({ autoIncrement: true }),
|
||||
kind: text("kind").notNull(),
|
||||
@@ -358,6 +377,7 @@ var schema = {
|
||||
domainTags,
|
||||
domainMonitors,
|
||||
domainMonitorResults,
|
||||
healthProbeLog,
|
||||
notificationLog,
|
||||
auditLog
|
||||
};
|
||||
@@ -508,7 +528,9 @@ function toDto(row, fallbacks) {
|
||||
healthDegradedFailures: 1,
|
||||
healthDownFailures: 2,
|
||||
healthLatencyWarnMs: 1e3,
|
||||
healthSuccessRecoveries: 2
|
||||
healthSuccessRecoveries: 2,
|
||||
healthWorkerUrl: "",
|
||||
healthWorkerTokenSet: false
|
||||
};
|
||||
return {
|
||||
id: row.id,
|
||||
@@ -535,7 +557,9 @@ function toDto(row, fallbacks) {
|
||||
healthSuccessRecoveries: coalesceInt(
|
||||
row.health_success_recoveries,
|
||||
env.healthSuccessRecoveries
|
||||
)
|
||||
),
|
||||
healthWorkerUrl: row.health_worker_url?.trim() || env.healthWorkerUrl,
|
||||
healthWorkerTokenSet: Boolean(row.health_worker_token?.trim()) || env.healthWorkerTokenSet
|
||||
};
|
||||
}
|
||||
function getAppSettings(db, fallbacks) {
|
||||
@@ -554,7 +578,9 @@ function getAppSettingsSecrets(db) {
|
||||
return {
|
||||
vpsTrackerUrl: row?.vps_tracker_url?.trim() ?? "",
|
||||
vpsTrackerIntegrationToken: row?.vps_tracker_integration_token?.trim() ?? "",
|
||||
vpsTrackerSyncEnabled: Boolean(row?.vps_tracker_sync_enabled)
|
||||
vpsTrackerSyncEnabled: Boolean(row?.vps_tracker_sync_enabled),
|
||||
healthWorkerUrl: row?.health_worker_url?.trim() ?? "",
|
||||
healthWorkerToken: row?.health_worker_token?.trim() ?? ""
|
||||
};
|
||||
}
|
||||
function updateAppSettings(db, patch, fallbacks) {
|
||||
@@ -574,6 +600,8 @@ function updateAppSettings(db, patch, fallbacks) {
|
||||
health_down_failures: patch.healthDownFailures !== void 0 ? patch.healthDownFailures : current.health_down_failures,
|
||||
health_latency_warn_ms: patch.healthLatencyWarnMs !== void 0 ? patch.healthLatencyWarnMs : current.health_latency_warn_ms,
|
||||
health_success_recoveries: patch.healthSuccessRecoveries !== void 0 ? patch.healthSuccessRecoveries : current.health_success_recoveries,
|
||||
health_worker_url: patch.healthWorkerUrl !== void 0 ? patch.healthWorkerUrl.trim() || null : current.health_worker_url,
|
||||
health_worker_token: patch.healthWorkerToken !== void 0 && patch.healthWorkerToken.trim() !== "" ? patch.healthWorkerToken : current.health_worker_token,
|
||||
updated_at: (/* @__PURE__ */ new Date()).toISOString()
|
||||
}).where(eq2(appSettings.id, SETTINGS_ID)).run();
|
||||
return getAppSettings(db, fallbacks);
|
||||
@@ -644,6 +672,7 @@ __export(repos_exports, {
|
||||
getSyncJob: () => getSyncJob,
|
||||
insertBinding: () => insertBinding,
|
||||
insertDnsRecord: () => insertDnsRecord,
|
||||
insertHealthProbeLog: () => insertHealthProbeLog,
|
||||
insertNotificationLog: () => insertNotificationLog,
|
||||
linkBindingRecord: () => linkBindingRecord,
|
||||
linkGroupDnsRecord: () => linkGroupDnsRecord,
|
||||
@@ -670,6 +699,7 @@ __export(repos_exports, {
|
||||
listGroups: () => listGroups,
|
||||
listHealthCheckTargets: () => listHealthCheckTargets,
|
||||
listHealthChecks: () => listHealthChecks,
|
||||
listHealthProbeLogForService: () => listHealthProbeLogForService,
|
||||
listIpHealthByServiceIds: () => listIpHealthByServiceIds,
|
||||
listIpHealthStatus: () => listIpHealthStatus,
|
||||
listNodes: () => listNodes,
|
||||
@@ -1106,6 +1136,9 @@ function deleteService(db, id) {
|
||||
const result = db.delete(services).where(eq3(services.id, id)).run();
|
||||
if (result.changes === 0) throw new NotFoundError(`service ${id}`);
|
||||
}
|
||||
function normalizeHealthProvider(value) {
|
||||
return value === "cloudflare" ? "cloudflare" : "local";
|
||||
}
|
||||
function mapServiceGroup(row) {
|
||||
return {
|
||||
id: row.id,
|
||||
@@ -1123,6 +1156,7 @@ function mapServiceGroup(row) {
|
||||
health_check_interval_sec: row.health_check_interval_sec,
|
||||
health_check_timeout_ms: row.health_check_timeout_ms,
|
||||
health_check_verify_tls: row.health_check_verify_tls,
|
||||
health_check_provider: normalizeHealthProvider(row.health_check_provider),
|
||||
created_at: row.created_at,
|
||||
updated_at: row.updated_at
|
||||
};
|
||||
@@ -1149,7 +1183,8 @@ function createServiceGroup(db, name, groupType, icon, domain, lbPatch) {
|
||||
health_check_expected_status: lbPatch?.health_check_expected_status ?? null,
|
||||
health_check_interval_sec: lbPatch?.health_check_interval_sec ?? 30,
|
||||
health_check_timeout_ms: lbPatch?.health_check_timeout_ms ?? 3e3,
|
||||
health_check_verify_tls: lbPatch?.health_check_verify_tls ?? false
|
||||
health_check_verify_tls: lbPatch?.health_check_verify_tls ?? false,
|
||||
health_check_provider: lbPatch?.health_check_provider ?? "local"
|
||||
}).returning({ id: serviceGroups.id }).get().id;
|
||||
return getServiceGroup(db, id);
|
||||
}
|
||||
@@ -1179,6 +1214,8 @@ function updateServiceGroup(db, id, name, groupType, icon, domain, lbPatch) {
|
||||
update.health_check_timeout_ms = lbPatch.health_check_timeout_ms;
|
||||
if (lbPatch.health_check_verify_tls !== void 0)
|
||||
update.health_check_verify_tls = lbPatch.health_check_verify_tls;
|
||||
if (lbPatch.health_check_provider !== void 0)
|
||||
update.health_check_provider = lbPatch.health_check_provider;
|
||||
}
|
||||
const result = db.update(serviceGroups).set(update).where(eq3(serviceGroups.id, id)).run();
|
||||
if (result.changes === 0) throw new NotFoundError(`service group ${id}`);
|
||||
@@ -1488,6 +1525,8 @@ function updateBindingLbConfig(db, bindingId, patch) {
|
||||
update.health_check_timeout_ms = patch.health_check_timeout_ms;
|
||||
if (patch.health_check_verify_tls !== void 0)
|
||||
update.health_check_verify_tls = patch.health_check_verify_tls;
|
||||
if (patch.health_check_provider !== void 0)
|
||||
update.health_check_provider = patch.health_check_provider;
|
||||
db.update(serviceBindings).set(update).where(eq3(serviceBindings.id, bindingId)).run();
|
||||
}
|
||||
function setBindingCnameTarget(db, bindingId, target) {
|
||||
@@ -1546,7 +1585,7 @@ function dnsRecordMatchesHostname(recordName, hostname, zoneName) {
|
||||
var SERVICE_BINDING_SELECT_COLUMNS = `sb.id, sb.domain_id, sb.service_id, sb.hostname, sb.dns_record_id,
|
||||
sb.lb_mode, sb.health_check_enabled, sb.health_check_type, sb.health_check_port,
|
||||
sb.health_check_path, sb.health_check_expected_status, sb.health_check_interval_sec,
|
||||
sb.health_check_timeout_ms, sb.health_check_verify_tls, sb.cname_target,
|
||||
sb.health_check_timeout_ms, sb.health_check_verify_tls, sb.health_check_provider, sb.cname_target,
|
||||
d.zone_name, d.group_id, g.name AS group_name,
|
||||
s.name AS service_name, s.slug AS service_slug,
|
||||
dr.content AS target_ip, dr.sync_status,
|
||||
@@ -1767,7 +1806,7 @@ function finishSyncJob(db, id, status, message) {
|
||||
function listIpHealthStatus(db, scope, refId) {
|
||||
return db.all(sql2`
|
||||
SELECT scope, ref_id, ip, status, latency_ms, consecutive_failures,
|
||||
last_checked_at, last_error
|
||||
last_checked_at, last_error, colo, provider
|
||||
FROM ip_health_status
|
||||
WHERE scope = ${scope} AND ref_id = ${refId}
|
||||
`);
|
||||
@@ -1891,7 +1930,11 @@ function listIpHealthByServiceIds(db, serviceIds) {
|
||||
SELECT sb.service_id AS service_id,
|
||||
ihs.ip AS ip,
|
||||
${WORST_HEALTH_SQL} AS health_status,
|
||||
MAX(ihs.latency_ms) AS health_latency_ms
|
||||
MAX(ihs.latency_ms) AS health_latency_ms,
|
||||
MAX(ihs.last_checked_at) AS last_checked_at,
|
||||
MAX(ihs.last_error) AS last_error,
|
||||
MAX(ihs.provider) AS provider,
|
||||
MAX(ihs.colo) AS colo
|
||||
FROM ip_health_status ihs
|
||||
INNER JOIN service_bindings sb
|
||||
ON ihs.scope = 'binding' AND ihs.ref_id = sb.id
|
||||
@@ -1907,7 +1950,11 @@ function listIpHealthByServiceIds(db, serviceIds) {
|
||||
list.push({
|
||||
ip: row.ip,
|
||||
status: parsed.health_status,
|
||||
latency_ms: parsed.health_latency_ms
|
||||
latency_ms: parsed.health_latency_ms,
|
||||
last_checked_at: row.last_checked_at,
|
||||
last_error: row.last_error,
|
||||
provider: normalizeHealthProvider(row.provider),
|
||||
colo: row.colo
|
||||
});
|
||||
result.set(row.service_id, list);
|
||||
}
|
||||
@@ -1942,20 +1989,24 @@ function mergeHealthAggregates(parts) {
|
||||
function getIpHealthStatusRow(db, scope, refId, ip) {
|
||||
const rows = db.all(sql2`
|
||||
SELECT scope, ref_id, ip, status, latency_ms, consecutive_failures,
|
||||
consecutive_successes, last_checked_at, last_error
|
||||
consecutive_successes, last_checked_at, last_error, colo, provider
|
||||
FROM ip_health_status
|
||||
WHERE scope = ${scope} AND ref_id = ${refId} AND ip = ${ip}
|
||||
LIMIT 1
|
||||
`);
|
||||
return rows[0] ?? null;
|
||||
}
|
||||
function upsertIpHealthStatus(db, scope, refId, ip, status, latencyMs, consecutiveFailures, lastError, consecutiveSuccesses = 0) {
|
||||
function upsertIpHealthStatus(db, scope, refId, ip, status, latencyMs, consecutiveFailures, lastError, consecutiveSuccesses = 0, extras) {
|
||||
const colo = extras?.colo ?? null;
|
||||
const provider = extras?.provider ?? "local";
|
||||
db.run(sql2`
|
||||
INSERT INTO ip_health_status
|
||||
(scope, ref_id, ip, status, latency_ms, consecutive_failures,
|
||||
consecutive_successes, last_checked_at, last_error, created_at, updated_at)
|
||||
consecutive_successes, last_checked_at, last_error, colo, provider,
|
||||
created_at, updated_at)
|
||||
VALUES (${scope}, ${refId}, ${ip}, ${status}, ${latencyMs}, ${consecutiveFailures},
|
||||
${consecutiveSuccesses}, datetime('now'), ${lastError}, datetime('now'), datetime('now'))
|
||||
${consecutiveSuccesses}, datetime('now'), ${lastError}, ${colo}, ${provider},
|
||||
datetime('now'), datetime('now'))
|
||||
ON CONFLICT(scope, ref_id, ip) DO UPDATE SET
|
||||
status = excluded.status,
|
||||
latency_ms = excluded.latency_ms,
|
||||
@@ -1963,6 +2014,8 @@ function upsertIpHealthStatus(db, scope, refId, ip, status, latencyMs, consecuti
|
||||
consecutive_successes = excluded.consecutive_successes,
|
||||
last_checked_at = excluded.last_checked_at,
|
||||
last_error = excluded.last_error,
|
||||
colo = excluded.colo,
|
||||
provider = excluded.provider,
|
||||
updated_at = datetime('now')
|
||||
`);
|
||||
}
|
||||
@@ -2025,7 +2078,8 @@ function listHealthCheckTargets(db) {
|
||||
sb.health_check_path AS path,
|
||||
sb.health_check_expected_status AS expected_status,
|
||||
sb.health_check_timeout_ms AS timeout_ms,
|
||||
sb.health_check_verify_tls AS verify_tls
|
||||
sb.health_check_verify_tls AS verify_tls,
|
||||
COALESCE(sb.health_check_provider, 'local') AS provider
|
||||
FROM service_binding_ips sbi
|
||||
JOIN service_bindings sb ON sb.id = sbi.binding_id
|
||||
JOIN domains d ON d.id = sb.domain_id
|
||||
@@ -2039,7 +2093,8 @@ function listHealthCheckTargets(db) {
|
||||
sg.health_check_path AS path,
|
||||
sg.health_check_expected_status AS expected_status,
|
||||
sg.health_check_timeout_ms AS timeout_ms,
|
||||
sg.health_check_verify_tls AS verify_tls
|
||||
sg.health_check_verify_tls AS verify_tls,
|
||||
COALESCE(sg.health_check_provider, 'local') AS provider
|
||||
FROM service_binding_ips sbi
|
||||
JOIN service_bindings sb ON sb.id = sbi.binding_id
|
||||
JOIN services s ON s.id = sb.service_id
|
||||
@@ -2059,7 +2114,8 @@ function listHealthCheckTargets(db) {
|
||||
sg.health_check_path AS path,
|
||||
sg.health_check_expected_status AS expected_status,
|
||||
sg.health_check_timeout_ms AS timeout_ms,
|
||||
sg.health_check_verify_tls AS verify_tls
|
||||
sg.health_check_verify_tls AS verify_tls,
|
||||
COALESCE(sg.health_check_provider, 'local') AS provider
|
||||
FROM service_binding_ips sbi
|
||||
JOIN service_bindings sb ON sb.id = sbi.binding_id
|
||||
JOIN domains d ON d.id = sb.domain_id
|
||||
@@ -2079,7 +2135,8 @@ function listHealthCheckTargets(db) {
|
||||
sb.health_check_path AS path,
|
||||
sb.health_check_expected_status AS expected_status,
|
||||
sb.health_check_timeout_ms AS timeout_ms,
|
||||
sb.health_check_verify_tls AS verify_tls
|
||||
sb.health_check_verify_tls AS verify_tls,
|
||||
COALESCE(sb.health_check_provider, 'local') AS provider
|
||||
FROM service_bindings sb
|
||||
JOIN domains d ON d.id = sb.domain_id
|
||||
JOIN services s ON s.id = sb.service_id
|
||||
@@ -2096,7 +2153,8 @@ function listHealthCheckTargets(db) {
|
||||
sg.health_check_path AS path,
|
||||
sg.health_check_expected_status AS expected_status,
|
||||
sg.health_check_timeout_ms AS timeout_ms,
|
||||
sg.health_check_verify_tls AS verify_tls
|
||||
sg.health_check_verify_tls AS verify_tls,
|
||||
COALESCE(sg.health_check_provider, 'local') AS provider
|
||||
FROM service_bindings sb
|
||||
JOIN domains d ON d.id = sb.domain_id
|
||||
JOIN services s ON s.id = sb.service_id
|
||||
@@ -2117,7 +2175,8 @@ function listHealthCheckTargets(db) {
|
||||
...groupInheritedCnameBindingTargets
|
||||
].map((t) => ({
|
||||
...t,
|
||||
verify_tls: Boolean(t.verify_tls)
|
||||
verify_tls: Boolean(t.verify_tls),
|
||||
provider: normalizeHealthProvider(t.provider)
|
||||
}));
|
||||
}
|
||||
function listDomainTags(db, domainId) {
|
||||
@@ -2212,6 +2271,46 @@ function listDomainMonitorResultsForDomain(db, domainId, limit = 50) {
|
||||
LIMIT ${limit}
|
||||
`);
|
||||
}
|
||||
var HEALTH_PROBE_LOG_KEEP = 50;
|
||||
function insertHealthProbeLog(db, entry) {
|
||||
db.insert(healthProbeLog).values({
|
||||
scope: entry.scope,
|
||||
ref_id: entry.refId,
|
||||
ip: entry.ip,
|
||||
provider: entry.provider,
|
||||
status: entry.status,
|
||||
ok: entry.ok,
|
||||
latency_ms: entry.latencyMs,
|
||||
colo: entry.colo,
|
||||
error: entry.error
|
||||
}).run();
|
||||
db.run(sql2`
|
||||
DELETE FROM health_probe_log
|
||||
WHERE id IN (
|
||||
SELECT id FROM health_probe_log
|
||||
WHERE scope = ${entry.scope} AND ref_id = ${entry.refId} AND ip = ${entry.ip}
|
||||
ORDER BY checked_at DESC, id DESC
|
||||
LIMIT -1 OFFSET ${HEALTH_PROBE_LOG_KEEP}
|
||||
)
|
||||
`);
|
||||
}
|
||||
function listHealthProbeLogForService(db, serviceId, limit = 50) {
|
||||
const rows = db.all(sql2`
|
||||
SELECT l.id, l.scope, l.ref_id, l.ip, l.provider, l.status, l.ok,
|
||||
l.latency_ms, l.colo, l.error, l.checked_at
|
||||
FROM health_probe_log l
|
||||
INNER JOIN service_bindings sb
|
||||
ON l.scope = 'binding' AND l.ref_id = sb.id
|
||||
WHERE sb.service_id = ${serviceId}
|
||||
ORDER BY l.checked_at DESC, l.id DESC
|
||||
LIMIT ${limit}
|
||||
`);
|
||||
return rows.map((row) => ({
|
||||
...row,
|
||||
provider: normalizeHealthProvider(row.provider),
|
||||
ok: Boolean(row.ok)
|
||||
}));
|
||||
}
|
||||
function insertNotificationLog(db, kind, refType, refId, title, message) {
|
||||
db.insert(notificationLog).values({
|
||||
kind,
|
||||
@@ -2249,6 +2348,7 @@ export {
|
||||
groups,
|
||||
healthCheck,
|
||||
healthChecks,
|
||||
healthProbeLog,
|
||||
ipHealthStatus,
|
||||
listAudit,
|
||||
nodes,
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
-- XOR health-check: persist provider on bindings/groups; Worker URL/token;
|
||||
-- colo + probe journal. Cloudflare = Worker edge probe, not Health Checks API.
|
||||
ALTER TABLE service_bindings ADD COLUMN health_check_provider TEXT NOT NULL DEFAULT 'local';
|
||||
ALTER TABLE service_groups ADD COLUMN health_check_provider TEXT NOT NULL DEFAULT 'local';
|
||||
|
||||
ALTER TABLE app_settings ADD COLUMN health_worker_url TEXT;
|
||||
ALTER TABLE app_settings ADD COLUMN health_worker_token TEXT;
|
||||
|
||||
ALTER TABLE ip_health_status ADD COLUMN colo TEXT;
|
||||
ALTER TABLE ip_health_status ADD COLUMN provider TEXT NOT NULL DEFAULT 'local';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS health_probe_log (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
scope TEXT NOT NULL,
|
||||
ref_id INTEGER NOT NULL,
|
||||
ip TEXT NOT NULL,
|
||||
provider TEXT NOT NULL,
|
||||
status TEXT NOT NULL,
|
||||
ok INTEGER NOT NULL,
|
||||
latency_ms INTEGER,
|
||||
colo TEXT,
|
||||
error TEXT,
|
||||
checked_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_health_probe_log_target
|
||||
ON health_probe_log(scope, ref_id, ip, checked_at DESC);
|
||||
+142
-11
@@ -5,6 +5,7 @@ import type {
|
||||
DomainListItem,
|
||||
Group,
|
||||
GroupWithStats,
|
||||
HealthCheckProvider,
|
||||
HealthCheckScope,
|
||||
HealthCheckTarget,
|
||||
HealthCheckType,
|
||||
@@ -33,6 +34,7 @@ import {
|
||||
domains,
|
||||
groups,
|
||||
healthChecks,
|
||||
healthProbeLog,
|
||||
ipHealthStatus,
|
||||
nodes,
|
||||
bindingNodes,
|
||||
@@ -768,6 +770,10 @@ export function deleteService(db: Db, id: number): void {
|
||||
|
||||
// --- Service Groups ---
|
||||
|
||||
function normalizeHealthProvider(value: unknown): HealthCheckProvider {
|
||||
return value === "cloudflare" ? "cloudflare" : "local";
|
||||
}
|
||||
|
||||
function mapServiceGroup(row: typeof serviceGroups.$inferSelect): ServiceGroup {
|
||||
return {
|
||||
id: row.id,
|
||||
@@ -785,6 +791,7 @@ function mapServiceGroup(row: typeof serviceGroups.$inferSelect): ServiceGroup {
|
||||
health_check_interval_sec: row.health_check_interval_sec,
|
||||
health_check_timeout_ms: row.health_check_timeout_ms,
|
||||
health_check_verify_tls: row.health_check_verify_tls,
|
||||
health_check_provider: normalizeHealthProvider(row.health_check_provider),
|
||||
created_at: row.created_at,
|
||||
updated_at: row.updated_at,
|
||||
};
|
||||
@@ -819,6 +826,7 @@ export interface ServiceGroupLbPatch {
|
||||
health_check_interval_sec?: number;
|
||||
health_check_timeout_ms?: number;
|
||||
health_check_verify_tls?: boolean;
|
||||
health_check_provider?: HealthCheckProvider;
|
||||
}
|
||||
|
||||
export function createServiceGroup(
|
||||
@@ -845,6 +853,7 @@ export function createServiceGroup(
|
||||
health_check_interval_sec: lbPatch?.health_check_interval_sec ?? 30,
|
||||
health_check_timeout_ms: lbPatch?.health_check_timeout_ms ?? 3000,
|
||||
health_check_verify_tls: lbPatch?.health_check_verify_tls ?? false,
|
||||
health_check_provider: lbPatch?.health_check_provider ?? "local",
|
||||
})
|
||||
.returning({ id: serviceGroups.id })
|
||||
.get()!.id;
|
||||
@@ -885,6 +894,8 @@ export function updateServiceGroup(
|
||||
update.health_check_timeout_ms = lbPatch.health_check_timeout_ms;
|
||||
if (lbPatch.health_check_verify_tls !== undefined)
|
||||
update.health_check_verify_tls = lbPatch.health_check_verify_tls;
|
||||
if (lbPatch.health_check_provider !== undefined)
|
||||
update.health_check_provider = lbPatch.health_check_provider;
|
||||
}
|
||||
const result = db
|
||||
.update(serviceGroups)
|
||||
@@ -1427,6 +1438,7 @@ export interface BindingLbPatch {
|
||||
health_check_interval_sec?: number;
|
||||
health_check_timeout_ms?: number;
|
||||
health_check_verify_tls?: boolean;
|
||||
health_check_provider?: HealthCheckProvider;
|
||||
}
|
||||
|
||||
export function updateBindingLbConfig(
|
||||
@@ -1457,6 +1469,8 @@ export function updateBindingLbConfig(
|
||||
update.health_check_timeout_ms = patch.health_check_timeout_ms;
|
||||
if (patch.health_check_verify_tls !== undefined)
|
||||
update.health_check_verify_tls = patch.health_check_verify_tls;
|
||||
if (patch.health_check_provider !== undefined)
|
||||
update.health_check_provider = patch.health_check_provider;
|
||||
db.update(serviceBindings)
|
||||
.set(update)
|
||||
.where(eq(serviceBindings.id, bindingId))
|
||||
@@ -1564,7 +1578,7 @@ function dnsRecordMatchesHostname(
|
||||
const SERVICE_BINDING_SELECT_COLUMNS = `sb.id, sb.domain_id, sb.service_id, sb.hostname, sb.dns_record_id,
|
||||
sb.lb_mode, sb.health_check_enabled, sb.health_check_type, sb.health_check_port,
|
||||
sb.health_check_path, sb.health_check_expected_status, sb.health_check_interval_sec,
|
||||
sb.health_check_timeout_ms, sb.health_check_verify_tls, sb.cname_target,
|
||||
sb.health_check_timeout_ms, sb.health_check_verify_tls, sb.health_check_provider, sb.cname_target,
|
||||
d.zone_name, d.group_id, g.name AS group_name,
|
||||
s.name AS service_name, s.slug AS service_slug,
|
||||
dr.content AS target_ip, dr.sync_status,
|
||||
@@ -1943,7 +1957,7 @@ export function listIpHealthStatus(
|
||||
return db
|
||||
.all<IpHealthStatus>(sql`
|
||||
SELECT scope, ref_id, ip, status, latency_ms, consecutive_failures,
|
||||
last_checked_at, last_error
|
||||
last_checked_at, last_error, colo, provider
|
||||
FROM ip_health_status
|
||||
WHERE scope = ${scope} AND ref_id = ${refId}
|
||||
`);
|
||||
@@ -2108,6 +2122,10 @@ export type ServiceIpHealthRow = {
|
||||
ip: string;
|
||||
status: IpHealthState;
|
||||
latency_ms: number | null;
|
||||
last_checked_at: string | null;
|
||||
last_error: string | null;
|
||||
provider: HealthCheckProvider;
|
||||
colo: string | null;
|
||||
};
|
||||
|
||||
/** Per-IP binding-scope health, worst status if the same IP is on several bindings. */
|
||||
@@ -2126,11 +2144,19 @@ export function listIpHealthByServiceIds(
|
||||
ip: string;
|
||||
health_status: string | null;
|
||||
health_latency_ms: number | null;
|
||||
last_checked_at: string | null;
|
||||
last_error: string | null;
|
||||
provider: string | null;
|
||||
colo: string | null;
|
||||
}>(sql`
|
||||
SELECT sb.service_id AS service_id,
|
||||
ihs.ip AS ip,
|
||||
${WORST_HEALTH_SQL} AS health_status,
|
||||
MAX(ihs.latency_ms) AS health_latency_ms
|
||||
MAX(ihs.latency_ms) AS health_latency_ms,
|
||||
MAX(ihs.last_checked_at) AS last_checked_at,
|
||||
MAX(ihs.last_error) AS last_error,
|
||||
MAX(ihs.provider) AS provider,
|
||||
MAX(ihs.colo) AS colo
|
||||
FROM ip_health_status ihs
|
||||
INNER JOIN service_bindings sb
|
||||
ON ihs.scope = 'binding' AND ihs.ref_id = sb.id
|
||||
@@ -2147,6 +2173,10 @@ export function listIpHealthByServiceIds(
|
||||
ip: row.ip,
|
||||
status: parsed.health_status,
|
||||
latency_ms: parsed.health_latency_ms,
|
||||
last_checked_at: row.last_checked_at,
|
||||
last_error: row.last_error,
|
||||
provider: normalizeHealthProvider(row.provider),
|
||||
colo: row.colo,
|
||||
});
|
||||
result.set(row.service_id, list);
|
||||
}
|
||||
@@ -2195,7 +2225,7 @@ export function getIpHealthStatusRow(
|
||||
): IpHealthStatus | null {
|
||||
const rows = db.all<IpHealthStatus>(sql`
|
||||
SELECT scope, ref_id, ip, status, latency_ms, consecutive_failures,
|
||||
consecutive_successes, last_checked_at, last_error
|
||||
consecutive_successes, last_checked_at, last_error, colo, provider
|
||||
FROM ip_health_status
|
||||
WHERE scope = ${scope} AND ref_id = ${refId} AND ip = ${ip}
|
||||
LIMIT 1
|
||||
@@ -2213,13 +2243,18 @@ export function upsertIpHealthStatus(
|
||||
consecutiveFailures: number,
|
||||
lastError: string | null,
|
||||
consecutiveSuccesses = 0,
|
||||
extras?: { colo?: string | null; provider?: HealthCheckProvider },
|
||||
): void {
|
||||
const colo = extras?.colo ?? null;
|
||||
const provider = extras?.provider ?? "local";
|
||||
db.run(sql`
|
||||
INSERT INTO ip_health_status
|
||||
(scope, ref_id, ip, status, latency_ms, consecutive_failures,
|
||||
consecutive_successes, last_checked_at, last_error, created_at, updated_at)
|
||||
consecutive_successes, last_checked_at, last_error, colo, provider,
|
||||
created_at, updated_at)
|
||||
VALUES (${scope}, ${refId}, ${ip}, ${status}, ${latencyMs}, ${consecutiveFailures},
|
||||
${consecutiveSuccesses}, datetime('now'), ${lastError}, datetime('now'), datetime('now'))
|
||||
${consecutiveSuccesses}, datetime('now'), ${lastError}, ${colo}, ${provider},
|
||||
datetime('now'), datetime('now'))
|
||||
ON CONFLICT(scope, ref_id, ip) DO UPDATE SET
|
||||
status = excluded.status,
|
||||
latency_ms = excluded.latency_ms,
|
||||
@@ -2227,6 +2262,8 @@ export function upsertIpHealthStatus(
|
||||
consecutive_successes = excluded.consecutive_successes,
|
||||
last_checked_at = excluded.last_checked_at,
|
||||
last_error = excluded.last_error,
|
||||
colo = excluded.colo,
|
||||
provider = excluded.provider,
|
||||
updated_at = datetime('now')
|
||||
`);
|
||||
}
|
||||
@@ -2321,7 +2358,8 @@ export function listHealthCheckTargets(db: Db): HealthCheckTarget[] {
|
||||
sb.health_check_path AS path,
|
||||
sb.health_check_expected_status AS expected_status,
|
||||
sb.health_check_timeout_ms AS timeout_ms,
|
||||
sb.health_check_verify_tls AS verify_tls
|
||||
sb.health_check_verify_tls AS verify_tls,
|
||||
COALESCE(sb.health_check_provider, 'local') AS provider
|
||||
FROM service_binding_ips sbi
|
||||
JOIN service_bindings sb ON sb.id = sbi.binding_id
|
||||
JOIN domains d ON d.id = sb.domain_id
|
||||
@@ -2339,7 +2377,8 @@ export function listHealthCheckTargets(db: Db): HealthCheckTarget[] {
|
||||
sg.health_check_path AS path,
|
||||
sg.health_check_expected_status AS expected_status,
|
||||
sg.health_check_timeout_ms AS timeout_ms,
|
||||
sg.health_check_verify_tls AS verify_tls
|
||||
sg.health_check_verify_tls AS verify_tls,
|
||||
COALESCE(sg.health_check_provider, 'local') AS provider
|
||||
FROM service_binding_ips sbi
|
||||
JOIN service_bindings sb ON sb.id = sbi.binding_id
|
||||
JOIN services s ON s.id = sb.service_id
|
||||
@@ -2364,7 +2403,8 @@ export function listHealthCheckTargets(db: Db): HealthCheckTarget[] {
|
||||
sg.health_check_path AS path,
|
||||
sg.health_check_expected_status AS expected_status,
|
||||
sg.health_check_timeout_ms AS timeout_ms,
|
||||
sg.health_check_verify_tls AS verify_tls
|
||||
sg.health_check_verify_tls AS verify_tls,
|
||||
COALESCE(sg.health_check_provider, 'local') AS provider
|
||||
FROM service_binding_ips sbi
|
||||
JOIN service_bindings sb ON sb.id = sbi.binding_id
|
||||
JOIN domains d ON d.id = sb.domain_id
|
||||
@@ -2386,7 +2426,8 @@ export function listHealthCheckTargets(db: Db): HealthCheckTarget[] {
|
||||
sb.health_check_path AS path,
|
||||
sb.health_check_expected_status AS expected_status,
|
||||
sb.health_check_timeout_ms AS timeout_ms,
|
||||
sb.health_check_verify_tls AS verify_tls
|
||||
sb.health_check_verify_tls AS verify_tls,
|
||||
COALESCE(sb.health_check_provider, 'local') AS provider
|
||||
FROM service_bindings sb
|
||||
JOIN domains d ON d.id = sb.domain_id
|
||||
JOIN services s ON s.id = sb.service_id
|
||||
@@ -2406,7 +2447,8 @@ export function listHealthCheckTargets(db: Db): HealthCheckTarget[] {
|
||||
sg.health_check_path AS path,
|
||||
sg.health_check_expected_status AS expected_status,
|
||||
sg.health_check_timeout_ms AS timeout_ms,
|
||||
sg.health_check_verify_tls AS verify_tls
|
||||
sg.health_check_verify_tls AS verify_tls,
|
||||
COALESCE(sg.health_check_provider, 'local') AS provider
|
||||
FROM service_bindings sb
|
||||
JOIN domains d ON d.id = sb.domain_id
|
||||
JOIN services s ON s.id = sb.service_id
|
||||
@@ -2429,6 +2471,7 @@ export function listHealthCheckTargets(db: Db): HealthCheckTarget[] {
|
||||
].map((t) => ({
|
||||
...t,
|
||||
verify_tls: Boolean(t.verify_tls),
|
||||
provider: normalizeHealthProvider(t.provider),
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -2633,6 +2676,94 @@ export function listDomainMonitorResultsForDomain(
|
||||
`);
|
||||
}
|
||||
|
||||
// --- Health probe journal ---
|
||||
|
||||
const HEALTH_PROBE_LOG_KEEP = 50;
|
||||
|
||||
export function insertHealthProbeLog(
|
||||
db: Db,
|
||||
entry: {
|
||||
scope: HealthCheckScope;
|
||||
refId: number;
|
||||
ip: string;
|
||||
provider: HealthCheckProvider;
|
||||
status: string;
|
||||
ok: boolean;
|
||||
latencyMs: number | null;
|
||||
colo: string | null;
|
||||
error: string | null;
|
||||
},
|
||||
): void {
|
||||
db.insert(healthProbeLog)
|
||||
.values({
|
||||
scope: entry.scope,
|
||||
ref_id: entry.refId,
|
||||
ip: entry.ip,
|
||||
provider: entry.provider,
|
||||
status: entry.status,
|
||||
ok: entry.ok,
|
||||
latency_ms: entry.latencyMs,
|
||||
colo: entry.colo,
|
||||
error: entry.error,
|
||||
})
|
||||
.run();
|
||||
db.run(sql`
|
||||
DELETE FROM health_probe_log
|
||||
WHERE id IN (
|
||||
SELECT id FROM health_probe_log
|
||||
WHERE scope = ${entry.scope} AND ref_id = ${entry.refId} AND ip = ${entry.ip}
|
||||
ORDER BY checked_at DESC, id DESC
|
||||
LIMIT -1 OFFSET ${HEALTH_PROBE_LOG_KEEP}
|
||||
)
|
||||
`);
|
||||
}
|
||||
|
||||
export function listHealthProbeLogForService(
|
||||
db: Db,
|
||||
serviceId: number,
|
||||
limit = 50,
|
||||
): {
|
||||
id: number;
|
||||
scope: string;
|
||||
ref_id: number;
|
||||
ip: string;
|
||||
provider: HealthCheckProvider;
|
||||
status: string;
|
||||
ok: boolean;
|
||||
latency_ms: number | null;
|
||||
colo: string | null;
|
||||
error: string | null;
|
||||
checked_at: string;
|
||||
}[] {
|
||||
const rows = db.all<{
|
||||
id: number;
|
||||
scope: string;
|
||||
ref_id: number;
|
||||
ip: string;
|
||||
provider: string;
|
||||
status: string;
|
||||
ok: number;
|
||||
latency_ms: number | null;
|
||||
colo: string | null;
|
||||
error: string | null;
|
||||
checked_at: string;
|
||||
}>(sql`
|
||||
SELECT l.id, l.scope, l.ref_id, l.ip, l.provider, l.status, l.ok,
|
||||
l.latency_ms, l.colo, l.error, l.checked_at
|
||||
FROM health_probe_log l
|
||||
INNER JOIN service_bindings sb
|
||||
ON l.scope = 'binding' AND l.ref_id = sb.id
|
||||
WHERE sb.service_id = ${serviceId}
|
||||
ORDER BY l.checked_at DESC, l.id DESC
|
||||
LIMIT ${limit}
|
||||
`);
|
||||
return rows.map((row) => ({
|
||||
...row,
|
||||
provider: normalizeHealthProvider(row.provider),
|
||||
ok: Boolean(row.ok),
|
||||
}));
|
||||
}
|
||||
|
||||
// --- Notification log ---
|
||||
|
||||
export function insertNotificationLog(
|
||||
|
||||
@@ -64,6 +64,7 @@ export const serviceGroups = sqliteTable("service_groups", {
|
||||
health_check_verify_tls: integer("health_check_verify_tls", { mode: "boolean" })
|
||||
.notNull()
|
||||
.default(false),
|
||||
health_check_provider: text("health_check_provider").notNull().default("local"),
|
||||
created_at: text("created_at")
|
||||
.notNull()
|
||||
.default(sql`datetime('now')`),
|
||||
@@ -165,6 +166,9 @@ export const serviceBindings = sqliteTable(
|
||||
})
|
||||
.notNull()
|
||||
.default(false),
|
||||
health_check_provider: text("health_check_provider")
|
||||
.notNull()
|
||||
.default("local"),
|
||||
routing_strategy: text("routing_strategy").notNull().default("round_robin"),
|
||||
operation_version: integer("operation_version").notNull().default(0),
|
||||
created_at: text("created_at")
|
||||
@@ -354,6 +358,8 @@ export const ipHealthStatus = sqliteTable(
|
||||
.default(0),
|
||||
last_checked_at: text("last_checked_at"),
|
||||
last_error: text("last_error"),
|
||||
colo: text("colo"),
|
||||
provider: text("provider").notNull().default("local"),
|
||||
created_at: text("created_at")
|
||||
.notNull()
|
||||
.default(sql`datetime('now')`),
|
||||
@@ -385,6 +391,8 @@ export const appSettings = sqliteTable("app_settings", {
|
||||
health_down_failures: integer("health_down_failures"),
|
||||
health_latency_warn_ms: integer("health_latency_warn_ms"),
|
||||
health_success_recoveries: integer("health_success_recoveries"),
|
||||
health_worker_url: text("health_worker_url"),
|
||||
health_worker_token: text("health_worker_token"),
|
||||
created_at: text("created_at")
|
||||
.notNull()
|
||||
.default(sql`datetime('now')`),
|
||||
@@ -441,6 +449,22 @@ export const domainMonitorResults = sqliteTable("domain_monitor_results", {
|
||||
.default(sql`datetime('now')`),
|
||||
});
|
||||
|
||||
export const healthProbeLog = sqliteTable("health_probe_log", {
|
||||
id: integer("id").primaryKey({ autoIncrement: true }),
|
||||
scope: text("scope").notNull(),
|
||||
ref_id: integer("ref_id").notNull(),
|
||||
ip: text("ip").notNull(),
|
||||
provider: text("provider").notNull(),
|
||||
status: text("status").notNull(),
|
||||
ok: integer("ok", { mode: "boolean" }).notNull(),
|
||||
latency_ms: integer("latency_ms"),
|
||||
colo: text("colo"),
|
||||
error: text("error"),
|
||||
checked_at: text("checked_at")
|
||||
.notNull()
|
||||
.default(sql`datetime('now')`),
|
||||
});
|
||||
|
||||
export const notificationLog = sqliteTable("notification_log", {
|
||||
id: integer("id").primaryKey({ autoIncrement: true }),
|
||||
kind: text("kind").notNull(),
|
||||
@@ -494,6 +518,7 @@ export const schema = {
|
||||
domainTags,
|
||||
domainMonitors,
|
||||
domainMonitorResults,
|
||||
healthProbeLog,
|
||||
notificationLog,
|
||||
auditLog,
|
||||
};
|
||||
|
||||
@@ -19,6 +19,8 @@ export type AppSettingsDto = {
|
||||
vpsTrackerSyncEnabled: boolean;
|
||||
vpsTrackerLastSyncAt: string | null;
|
||||
showQuickActions: boolean;
|
||||
healthWorkerUrl: string;
|
||||
healthWorkerTokenSet: boolean;
|
||||
} & HealthEngineSettings;
|
||||
|
||||
export type AppSettingsPatch = {
|
||||
@@ -31,9 +33,14 @@ export type AppSettingsPatch = {
|
||||
healthDownFailures?: number;
|
||||
healthLatencyWarnMs?: number;
|
||||
healthSuccessRecoveries?: number;
|
||||
healthWorkerUrl?: string;
|
||||
healthWorkerToken?: string;
|
||||
};
|
||||
|
||||
export type HealthEngineFallbacks = HealthEngineSettings;
|
||||
export type HealthEngineFallbacks = HealthEngineSettings & {
|
||||
healthWorkerUrl: string;
|
||||
healthWorkerTokenSet: boolean;
|
||||
};
|
||||
|
||||
function coalesceInt(value: number | null | undefined, fallback: number): number {
|
||||
return value == null || Number.isNaN(value) || value < 1 ? fallback : value;
|
||||
@@ -49,6 +56,8 @@ function toDto(
|
||||
healthDownFailures: 2,
|
||||
healthLatencyWarnMs: 1000,
|
||||
healthSuccessRecoveries: 2,
|
||||
healthWorkerUrl: "",
|
||||
healthWorkerTokenSet: false,
|
||||
};
|
||||
return {
|
||||
id: row.id,
|
||||
@@ -77,6 +86,9 @@ function toDto(
|
||||
row.health_success_recoveries,
|
||||
env.healthSuccessRecoveries,
|
||||
),
|
||||
healthWorkerUrl: row.health_worker_url?.trim() || env.healthWorkerUrl,
|
||||
healthWorkerTokenSet:
|
||||
Boolean(row.health_worker_token?.trim()) || env.healthWorkerTokenSet,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -103,6 +115,8 @@ export function getAppSettingsSecrets(db: Db): {
|
||||
vpsTrackerUrl: string;
|
||||
vpsTrackerIntegrationToken: string;
|
||||
vpsTrackerSyncEnabled: boolean;
|
||||
healthWorkerUrl: string;
|
||||
healthWorkerToken: string;
|
||||
} {
|
||||
const row = db
|
||||
.select()
|
||||
@@ -114,6 +128,8 @@ export function getAppSettingsSecrets(db: Db): {
|
||||
vpsTrackerIntegrationToken:
|
||||
row?.vps_tracker_integration_token?.trim() ?? "",
|
||||
vpsTrackerSyncEnabled: Boolean(row?.vps_tracker_sync_enabled),
|
||||
healthWorkerUrl: row?.health_worker_url?.trim() ?? "",
|
||||
healthWorkerToken: row?.health_worker_token?.trim() ?? "",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -176,6 +192,15 @@ export function updateAppSettings(
|
||||
patch.healthSuccessRecoveries !== undefined
|
||||
? patch.healthSuccessRecoveries
|
||||
: current.health_success_recoveries,
|
||||
health_worker_url:
|
||||
patch.healthWorkerUrl !== undefined
|
||||
? patch.healthWorkerUrl.trim() || null
|
||||
: current.health_worker_url,
|
||||
health_worker_token:
|
||||
patch.healthWorkerToken !== undefined &&
|
||||
patch.healthWorkerToken.trim() !== ""
|
||||
? patch.healthWorkerToken
|
||||
: current.health_worker_token,
|
||||
updated_at: new Date().toISOString(),
|
||||
})
|
||||
.where(eq(appSettings.id, SETTINGS_ID))
|
||||
|
||||
Vendored
+138
-1
@@ -31,6 +31,7 @@ interface ServiceGroup$1 {
|
||||
health_check_interval_sec: number;
|
||||
health_check_timeout_ms: number;
|
||||
health_check_verify_tls: boolean;
|
||||
health_check_provider: HealthCheckProvider;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
@@ -60,6 +61,7 @@ interface ServiceBinding {
|
||||
health_check_interval_sec: number;
|
||||
health_check_timeout_ms: number;
|
||||
health_check_verify_tls: boolean;
|
||||
health_check_provider: HealthCheckProvider;
|
||||
routing_strategy: LbMode;
|
||||
operation_version: number;
|
||||
created_at: string;
|
||||
@@ -90,6 +92,7 @@ interface ServiceBindingView {
|
||||
health_check_interval_sec: number;
|
||||
health_check_timeout_ms: number;
|
||||
health_check_verify_tls: boolean;
|
||||
health_check_provider: HealthCheckProvider;
|
||||
sync_status: string | null;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
@@ -114,6 +117,7 @@ interface ServiceDomainBindingView {
|
||||
health_check_interval_sec: number;
|
||||
health_check_timeout_ms: number;
|
||||
health_check_verify_tls: boolean;
|
||||
health_check_provider: HealthCheckProvider;
|
||||
sync_status: string | null;
|
||||
}
|
||||
interface ServiceView$1 {
|
||||
@@ -193,11 +197,17 @@ interface IpHealthStatus {
|
||||
consecutive_successes?: number;
|
||||
last_checked_at: string | null;
|
||||
last_error: string | null;
|
||||
colo?: string | null;
|
||||
provider?: HealthCheckProvider;
|
||||
}
|
||||
interface ServiceIpHealth$1 {
|
||||
ip: string;
|
||||
status: IpHealthState;
|
||||
latency_ms: number | null;
|
||||
last_checked_at?: string | null;
|
||||
last_error?: string | null;
|
||||
provider?: HealthCheckProvider;
|
||||
colo?: string | null;
|
||||
}
|
||||
interface ServiceNode {
|
||||
id: number;
|
||||
@@ -275,6 +285,7 @@ interface HealthCheckTarget {
|
||||
expected_status: number | null;
|
||||
timeout_ms: number;
|
||||
verify_tls: boolean;
|
||||
provider: HealthCheckProvider;
|
||||
}
|
||||
|
||||
declare class ValidationError extends Error {
|
||||
@@ -378,6 +389,11 @@ declare const ipHealthStatusSchema: z.ZodObject<{
|
||||
consecutive_successes: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
||||
last_checked_at: z.ZodNullable<z.ZodString>;
|
||||
last_error: z.ZodNullable<z.ZodString>;
|
||||
colo: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
||||
provider: z.ZodOptional<z.ZodEnum<{
|
||||
local: "local";
|
||||
cloudflare: "cloudflare";
|
||||
}>>;
|
||||
}, z.core.$strip>;
|
||||
declare const serviceIpHealthSchema: z.ZodObject<{
|
||||
ip: z.ZodString;
|
||||
@@ -388,8 +404,37 @@ declare const serviceIpHealthSchema: z.ZodObject<{
|
||||
degraded: "degraded";
|
||||
}>;
|
||||
latency_ms: z.ZodNullable<z.ZodNumber>;
|
||||
last_checked_at: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
||||
last_error: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
||||
provider: z.ZodOptional<z.ZodEnum<{
|
||||
local: "local";
|
||||
cloudflare: "cloudflare";
|
||||
}>>;
|
||||
colo: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
||||
}, z.core.$strip>;
|
||||
type ServiceIpHealth = z.infer<typeof serviceIpHealthSchema>;
|
||||
declare const healthProbeLogSchema: z.ZodObject<{
|
||||
id: z.ZodNumber;
|
||||
scope: z.ZodString;
|
||||
ref_id: z.ZodNumber;
|
||||
ip: z.ZodString;
|
||||
provider: z.ZodEnum<{
|
||||
local: "local";
|
||||
cloudflare: "cloudflare";
|
||||
}>;
|
||||
status: z.ZodEnum<{
|
||||
unknown: "unknown";
|
||||
up: "up";
|
||||
down: "down";
|
||||
degraded: "degraded";
|
||||
}>;
|
||||
ok: z.ZodCoercedBoolean<unknown>;
|
||||
latency_ms: z.ZodNullable<z.ZodNumber>;
|
||||
colo: z.ZodNullable<z.ZodString>;
|
||||
error: z.ZodNullable<z.ZodString>;
|
||||
checked_at: z.ZodString;
|
||||
}, z.core.$strip>;
|
||||
type HealthProbeLog = z.infer<typeof healthProbeLogSchema>;
|
||||
declare const groupSchema: z.ZodObject<{
|
||||
id: z.ZodNumber;
|
||||
name: z.ZodString;
|
||||
@@ -443,6 +488,10 @@ declare const serviceGroupSchema: z.ZodObject<{
|
||||
health_check_interval_sec: z.ZodDefault<z.ZodNumber>;
|
||||
health_check_timeout_ms: z.ZodDefault<z.ZodNumber>;
|
||||
health_check_verify_tls: z.ZodDefault<z.ZodCoercedBoolean<unknown>>;
|
||||
health_check_provider: z.ZodCatch<z.ZodEnum<{
|
||||
local: "local";
|
||||
cloudflare: "cloudflare";
|
||||
}>>;
|
||||
created_at: z.ZodString;
|
||||
updated_at: z.ZodString;
|
||||
}, z.core.$strip>;
|
||||
@@ -492,6 +541,10 @@ declare const serviceDomainBindingSchema: z.ZodPipe<z.ZodObject<{
|
||||
health_check_interval_sec: z.ZodDefault<z.ZodNumber>;
|
||||
health_check_timeout_ms: z.ZodDefault<z.ZodNumber>;
|
||||
health_check_verify_tls: z.ZodDefault<z.ZodCoercedBoolean<unknown>>;
|
||||
health_check_provider: z.ZodCatch<z.ZodEnum<{
|
||||
local: "local";
|
||||
cloudflare: "cloudflare";
|
||||
}>>;
|
||||
sync_status: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
||||
}, z.core.$strip>, z.ZodTransform<{
|
||||
target_ips: string[];
|
||||
@@ -513,6 +566,7 @@ declare const serviceDomainBindingSchema: z.ZodPipe<z.ZodObject<{
|
||||
health_check_interval_sec: number;
|
||||
health_check_timeout_ms: number;
|
||||
health_check_verify_tls: boolean;
|
||||
health_check_provider: "local" | "cloudflare";
|
||||
sync_status: string | null;
|
||||
target_ip?: string | null | undefined;
|
||||
}, {
|
||||
@@ -531,6 +585,7 @@ declare const serviceDomainBindingSchema: z.ZodPipe<z.ZodObject<{
|
||||
health_check_interval_sec: number;
|
||||
health_check_timeout_ms: number;
|
||||
health_check_verify_tls: boolean;
|
||||
health_check_provider: "local" | "cloudflare";
|
||||
sync_status: string | null;
|
||||
target_ips?: string[] | undefined;
|
||||
target_ip?: string | null | undefined;
|
||||
@@ -584,6 +639,10 @@ declare const serviceViewSchema: z.ZodObject<{
|
||||
health_check_interval_sec: z.ZodDefault<z.ZodNumber>;
|
||||
health_check_timeout_ms: z.ZodDefault<z.ZodNumber>;
|
||||
health_check_verify_tls: z.ZodDefault<z.ZodCoercedBoolean<unknown>>;
|
||||
health_check_provider: z.ZodCatch<z.ZodEnum<{
|
||||
local: "local";
|
||||
cloudflare: "cloudflare";
|
||||
}>>;
|
||||
sync_status: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
||||
}, z.core.$strip>, z.ZodTransform<{
|
||||
target_ips: string[];
|
||||
@@ -605,6 +664,7 @@ declare const serviceViewSchema: z.ZodObject<{
|
||||
health_check_interval_sec: number;
|
||||
health_check_timeout_ms: number;
|
||||
health_check_verify_tls: boolean;
|
||||
health_check_provider: "local" | "cloudflare";
|
||||
sync_status: string | null;
|
||||
target_ip?: string | null | undefined;
|
||||
}, {
|
||||
@@ -623,6 +683,7 @@ declare const serviceViewSchema: z.ZodObject<{
|
||||
health_check_interval_sec: number;
|
||||
health_check_timeout_ms: number;
|
||||
health_check_verify_tls: boolean;
|
||||
health_check_provider: "local" | "cloudflare";
|
||||
sync_status: string | null;
|
||||
target_ips?: string[] | undefined;
|
||||
target_ip?: string | null | undefined;
|
||||
@@ -646,6 +707,13 @@ declare const serviceViewSchema: z.ZodObject<{
|
||||
degraded: "degraded";
|
||||
}>;
|
||||
latency_ms: z.ZodNullable<z.ZodNumber>;
|
||||
last_checked_at: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
||||
last_error: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
||||
provider: z.ZodOptional<z.ZodEnum<{
|
||||
local: "local";
|
||||
cloudflare: "cloudflare";
|
||||
}>>;
|
||||
colo: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
||||
}, z.core.$strip>>>;
|
||||
ip_enabled: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodBoolean>>;
|
||||
}, z.core.$strip>;
|
||||
@@ -680,6 +748,10 @@ declare const serviceGroupViewSchema: z.ZodObject<{
|
||||
health_check_interval_sec: z.ZodDefault<z.ZodNumber>;
|
||||
health_check_timeout_ms: z.ZodDefault<z.ZodNumber>;
|
||||
health_check_verify_tls: z.ZodDefault<z.ZodCoercedBoolean<unknown>>;
|
||||
health_check_provider: z.ZodCatch<z.ZodEnum<{
|
||||
local: "local";
|
||||
cloudflare: "cloudflare";
|
||||
}>>;
|
||||
created_at: z.ZodString;
|
||||
updated_at: z.ZodString;
|
||||
services: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
||||
@@ -728,6 +800,10 @@ declare const serviceGroupViewSchema: z.ZodObject<{
|
||||
health_check_interval_sec: z.ZodDefault<z.ZodNumber>;
|
||||
health_check_timeout_ms: z.ZodDefault<z.ZodNumber>;
|
||||
health_check_verify_tls: z.ZodDefault<z.ZodCoercedBoolean<unknown>>;
|
||||
health_check_provider: z.ZodCatch<z.ZodEnum<{
|
||||
local: "local";
|
||||
cloudflare: "cloudflare";
|
||||
}>>;
|
||||
sync_status: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
||||
}, z.core.$strip>, z.ZodTransform<{
|
||||
target_ips: string[];
|
||||
@@ -749,6 +825,7 @@ declare const serviceGroupViewSchema: z.ZodObject<{
|
||||
health_check_interval_sec: number;
|
||||
health_check_timeout_ms: number;
|
||||
health_check_verify_tls: boolean;
|
||||
health_check_provider: "local" | "cloudflare";
|
||||
sync_status: string | null;
|
||||
target_ip?: string | null | undefined;
|
||||
}, {
|
||||
@@ -767,6 +844,7 @@ declare const serviceGroupViewSchema: z.ZodObject<{
|
||||
health_check_interval_sec: number;
|
||||
health_check_timeout_ms: number;
|
||||
health_check_verify_tls: boolean;
|
||||
health_check_provider: "local" | "cloudflare";
|
||||
sync_status: string | null;
|
||||
target_ips?: string[] | undefined;
|
||||
target_ip?: string | null | undefined;
|
||||
@@ -790,6 +868,13 @@ declare const serviceGroupViewSchema: z.ZodObject<{
|
||||
degraded: "degraded";
|
||||
}>;
|
||||
latency_ms: z.ZodNullable<z.ZodNumber>;
|
||||
last_checked_at: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
||||
last_error: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
||||
provider: z.ZodOptional<z.ZodEnum<{
|
||||
local: "local";
|
||||
cloudflare: "cloudflare";
|
||||
}>>;
|
||||
colo: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
||||
}, z.core.$strip>>>;
|
||||
ip_enabled: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodBoolean>>;
|
||||
}, z.core.$strip>>>;
|
||||
@@ -833,6 +918,10 @@ declare const serviceGroupsResponseSchema: z.ZodObject<{
|
||||
health_check_interval_sec: z.ZodDefault<z.ZodNumber>;
|
||||
health_check_timeout_ms: z.ZodDefault<z.ZodNumber>;
|
||||
health_check_verify_tls: z.ZodDefault<z.ZodCoercedBoolean<unknown>>;
|
||||
health_check_provider: z.ZodCatch<z.ZodEnum<{
|
||||
local: "local";
|
||||
cloudflare: "cloudflare";
|
||||
}>>;
|
||||
created_at: z.ZodString;
|
||||
updated_at: z.ZodString;
|
||||
services: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
||||
@@ -881,6 +970,10 @@ declare const serviceGroupsResponseSchema: z.ZodObject<{
|
||||
health_check_interval_sec: z.ZodDefault<z.ZodNumber>;
|
||||
health_check_timeout_ms: z.ZodDefault<z.ZodNumber>;
|
||||
health_check_verify_tls: z.ZodDefault<z.ZodCoercedBoolean<unknown>>;
|
||||
health_check_provider: z.ZodCatch<z.ZodEnum<{
|
||||
local: "local";
|
||||
cloudflare: "cloudflare";
|
||||
}>>;
|
||||
sync_status: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
||||
}, z.core.$strip>, z.ZodTransform<{
|
||||
target_ips: string[];
|
||||
@@ -902,6 +995,7 @@ declare const serviceGroupsResponseSchema: z.ZodObject<{
|
||||
health_check_interval_sec: number;
|
||||
health_check_timeout_ms: number;
|
||||
health_check_verify_tls: boolean;
|
||||
health_check_provider: "local" | "cloudflare";
|
||||
sync_status: string | null;
|
||||
target_ip?: string | null | undefined;
|
||||
}, {
|
||||
@@ -920,6 +1014,7 @@ declare const serviceGroupsResponseSchema: z.ZodObject<{
|
||||
health_check_interval_sec: number;
|
||||
health_check_timeout_ms: number;
|
||||
health_check_verify_tls: boolean;
|
||||
health_check_provider: "local" | "cloudflare";
|
||||
sync_status: string | null;
|
||||
target_ips?: string[] | undefined;
|
||||
target_ip?: string | null | undefined;
|
||||
@@ -943,6 +1038,13 @@ declare const serviceGroupsResponseSchema: z.ZodObject<{
|
||||
degraded: "degraded";
|
||||
}>;
|
||||
latency_ms: z.ZodNullable<z.ZodNumber>;
|
||||
last_checked_at: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
||||
last_error: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
||||
provider: z.ZodOptional<z.ZodEnum<{
|
||||
local: "local";
|
||||
cloudflare: "cloudflare";
|
||||
}>>;
|
||||
colo: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
||||
}, z.core.$strip>>>;
|
||||
ip_enabled: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodBoolean>>;
|
||||
}, z.core.$strip>>>;
|
||||
@@ -1000,6 +1102,10 @@ declare const serviceGroupsResponseSchema: z.ZodObject<{
|
||||
health_check_interval_sec: z.ZodDefault<z.ZodNumber>;
|
||||
health_check_timeout_ms: z.ZodDefault<z.ZodNumber>;
|
||||
health_check_verify_tls: z.ZodDefault<z.ZodCoercedBoolean<unknown>>;
|
||||
health_check_provider: z.ZodCatch<z.ZodEnum<{
|
||||
local: "local";
|
||||
cloudflare: "cloudflare";
|
||||
}>>;
|
||||
sync_status: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
||||
}, z.core.$strip>, z.ZodTransform<{
|
||||
target_ips: string[];
|
||||
@@ -1021,6 +1127,7 @@ declare const serviceGroupsResponseSchema: z.ZodObject<{
|
||||
health_check_interval_sec: number;
|
||||
health_check_timeout_ms: number;
|
||||
health_check_verify_tls: boolean;
|
||||
health_check_provider: "local" | "cloudflare";
|
||||
sync_status: string | null;
|
||||
target_ip?: string | null | undefined;
|
||||
}, {
|
||||
@@ -1039,6 +1146,7 @@ declare const serviceGroupsResponseSchema: z.ZodObject<{
|
||||
health_check_interval_sec: number;
|
||||
health_check_timeout_ms: number;
|
||||
health_check_verify_tls: boolean;
|
||||
health_check_provider: "local" | "cloudflare";
|
||||
sync_status: string | null;
|
||||
target_ips?: string[] | undefined;
|
||||
target_ip?: string | null | undefined;
|
||||
@@ -1062,6 +1170,13 @@ declare const serviceGroupsResponseSchema: z.ZodObject<{
|
||||
degraded: "degraded";
|
||||
}>;
|
||||
latency_ms: z.ZodNullable<z.ZodNumber>;
|
||||
last_checked_at: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
||||
last_error: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
||||
provider: z.ZodOptional<z.ZodEnum<{
|
||||
local: "local";
|
||||
cloudflare: "cloudflare";
|
||||
}>>;
|
||||
colo: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
||||
}, z.core.$strip>>>;
|
||||
ip_enabled: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodBoolean>>;
|
||||
}, z.core.$strip>>>;
|
||||
@@ -1265,6 +1380,10 @@ declare const healthCheckConfigSchema: z.ZodObject<{
|
||||
health_check_interval_sec: z.ZodOptional<z.ZodNumber>;
|
||||
health_check_timeout_ms: z.ZodOptional<z.ZodNumber>;
|
||||
health_check_verify_tls: z.ZodOptional<z.ZodBoolean>;
|
||||
health_check_provider: z.ZodOptional<z.ZodEnum<{
|
||||
local: "local";
|
||||
cloudflare: "cloudflare";
|
||||
}>>;
|
||||
}, z.core.$strip>;
|
||||
type HealthCheckConfig = z.infer<typeof healthCheckConfigSchema>;
|
||||
declare const createServiceSchema: z.ZodObject<{
|
||||
@@ -1292,6 +1411,10 @@ declare const createServiceWithConfigSchema: z.ZodObject<{
|
||||
health_check_interval_sec: z.ZodOptional<z.ZodNumber>;
|
||||
health_check_timeout_ms: z.ZodOptional<z.ZodNumber>;
|
||||
health_check_verify_tls: z.ZodOptional<z.ZodBoolean>;
|
||||
health_check_provider: z.ZodOptional<z.ZodEnum<{
|
||||
local: "local";
|
||||
cloudflare: "cloudflare";
|
||||
}>>;
|
||||
fqdn: z.ZodString;
|
||||
target_ips: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
||||
target_cname: z.ZodOptional<z.ZodString>;
|
||||
@@ -1480,6 +1603,10 @@ declare const updateServiceConfigSchema: z.ZodObject<{
|
||||
health_check_interval_sec: z.ZodOptional<z.ZodNumber>;
|
||||
health_check_timeout_ms: z.ZodOptional<z.ZodNumber>;
|
||||
health_check_verify_tls: z.ZodOptional<z.ZodBoolean>;
|
||||
health_check_provider: z.ZodOptional<z.ZodEnum<{
|
||||
local: "local";
|
||||
cloudflare: "cloudflare";
|
||||
}>>;
|
||||
fqdn: z.ZodString;
|
||||
target_ips: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
||||
target_cname: z.ZodOptional<z.ZodString>;
|
||||
@@ -1507,6 +1634,10 @@ declare const createServiceGroupSchema: z.ZodObject<{
|
||||
health_check_interval_sec: z.ZodOptional<z.ZodNumber>;
|
||||
health_check_timeout_ms: z.ZodOptional<z.ZodNumber>;
|
||||
health_check_verify_tls: z.ZodOptional<z.ZodBoolean>;
|
||||
health_check_provider: z.ZodOptional<z.ZodEnum<{
|
||||
local: "local";
|
||||
cloudflare: "cloudflare";
|
||||
}>>;
|
||||
name: z.ZodString;
|
||||
type: z.ZodDefault<z.ZodEnum<{
|
||||
vpn: "vpn";
|
||||
@@ -1537,6 +1668,10 @@ declare const updateServiceGroupSchema: z.ZodObject<{
|
||||
health_check_interval_sec: z.ZodOptional<z.ZodNumber>;
|
||||
health_check_timeout_ms: z.ZodOptional<z.ZodNumber>;
|
||||
health_check_verify_tls: z.ZodOptional<z.ZodBoolean>;
|
||||
health_check_provider: z.ZodOptional<z.ZodEnum<{
|
||||
local: "local";
|
||||
cloudflare: "cloudflare";
|
||||
}>>;
|
||||
name: z.ZodOptional<z.ZodString>;
|
||||
type: z.ZodOptional<z.ZodEnum<{
|
||||
vpn: "vpn";
|
||||
@@ -1783,6 +1918,8 @@ declare const appSettingsPatchSchema: z.ZodObject<{
|
||||
healthDownFailures: z.ZodOptional<z.ZodNumber>;
|
||||
healthLatencyWarnMs: z.ZodOptional<z.ZodNumber>;
|
||||
healthSuccessRecoveries: z.ZodOptional<z.ZodNumber>;
|
||||
healthWorkerUrl: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodLiteral<"">]>>;
|
||||
healthWorkerToken: z.ZodOptional<z.ZodString>;
|
||||
}, z.core.$strip>;
|
||||
type AppSettingsPatch = z.infer<typeof appSettingsPatchSchema>;
|
||||
declare const vpsTrackerEventSchema: z.ZodObject<{
|
||||
@@ -1907,4 +2044,4 @@ declare const ingestAuditEventSchema: z.ZodObject<{
|
||||
}, z.core.$strip>;
|
||||
type IngestAuditEvent = z.infer<typeof ingestAuditEventSchema>;
|
||||
|
||||
export { AUDIT_SEVERITIES, AUDIT_SOURCE_APPS, AUDIT_TARGET_TYPES, type AppSettingsPatch, type AppSwitcherConfig, type AppSwitcherEntry, type AuditListQuery, type AuditLogEntry, type AuditSeverity, type AuditSourceApp, type AuditTargetType, type BulkUpdateDomainsInput, CERT_ERROR, CERT_EXPIRED, CERT_MONITORING_VALUES, CERT_MONITOR_AUTO, CERT_MONITOR_REQUIRED, CERT_MONITOR_SKIPPED, CERT_OK, CERT_UNKNOWN, CERT_WARNING, type CertMonitoring, type Certificate, type CfDnsRecord, type CfHealthCheck, type CfZone, type CfdmBindingSyncItem, type ChangeDomainInput, type ChangeIpInput, type CreateDnsRecordInput, type CreateDnsRecordPayload, type CreateDomainInput, type CreateDomainMonitorInput, type CreateGroupInput, type CreateOriginHealthCheckInput, type CreateServiceBindingInput, type CreateServiceGroupInput, type CreateServiceInput, type CreateServiceNodeInput, type CreateServiceWithConfigInput, type CreateSubdomainInput, type DnsRecord, type Domain, type DomainEnvironment, type DomainListItem, type DomainMonitor, type DomainMonitorResult, type DomainMonitorType, type Group, type GroupWithStats, type HealthCheckConfig, type HealthCheckProvider, type HealthCheckScope, type HealthCheckTarget, type HealthCheckType, type HealthStatusQuery, type IngestAuditEvent, type IpHealthState, type IpHealthStatus, type JwtClaims, type LbMode, type LoginInput, type LoginRequest, type LoginResponse, type NodeHealthState, type NotificationLog, type OriginHealthCheck, type OriginHealthCheckRecord, type ParsedFqdn, type PatchDnsRecordPayload, type ReorderServicesInput, SYNC_CONFLICT, SYNC_ERROR, SYNC_PENDING_DELETE, SYNC_PENDING_PUSH, SYNC_SYNCED, type Service, type ServiceBinding, type ServiceBindingView, type ServiceDomainBinding, type ServiceDomainBindingView, type ServiceGroup, type ServiceGroupView, type ServiceGroupsResponse, type ServiceIpHealth, type ServiceNode, type ServiceNodeRecord, type ServiceOverview, type ServiceView, type Subdomain, type SubdomainRecord, type SyncJob, type ToggleEnabledInput, type ToggleServiceIpInput, type UpdateDomainInput, type UpdateServiceConfigInput, type UpdateServiceGroupInput, type UpdateServiceNodeInput, type UpdateSubdomainInput, ValidationError, type VpsTrackerEvent, appSettingsPatchSchema, appSwitcherConfigSchema, appSwitcherEntrySchema, appSwitcherIconSchema, auditListQuerySchema, auditLogEntrySchema, auditSeveritySchema, auditSourceAppSchema, auditTargetTypeSchema, bindingToFqdn, bulkUpdateDomainsSchema, certMonitoringSchema, certStatusFromExpiry, certificateSchema, cfdmBindingSyncItemSchema, cfdmSyncBindingsBodySchema, changeDomainSchema, changeIpSchema, createDnsRecordSchema, createDomainMonitorSchema, createDomainSchema, createGroupSchema, createOriginHealthCheckSchema, createServiceBindingSchema, createServiceGroupSchema, createServiceNodeSchema, createServiceSchema, createServiceWithConfigSchema, createSubdomainSchema, dnsNameToSubdomainLabel, dnsRecordNamesMatch, dnsRecordSchema, domainEnvironmentSchema, domainListItemSchema, domainMonitorResultSchema, domainMonitorSchema, domainMonitorTypeSchema, domainSchema, fqdnToDisplay, groupSchema, groupWithStatsSchema, healthCheckConfigSchema, healthCheckProviderSchema, healthCheckScopeSchema, healthCheckTypeSchema, healthStatusQuerySchema, ingestAuditEventSchema, ipHealthStateSchema, ipHealthStatusSchema, isIpLiteral, isValidIpv4, lbModeSchema, loginSchema, nodeHealthStateSchema, normalizeDnsRecordName, notificationLogSchema, originHealthCheckSchema, parseFqdn, reorderServicesSchema, serviceBindingSchema, serviceDomainBindingSchema, serviceGroupSchema, serviceGroupTypeSchema, serviceGroupViewSchema, serviceGroupsResponseSchema, serviceIpHealthSchema, serviceNodeSchema, serviceSchema, serviceViewSchema, shouldMonitorService, subdomainLabelToFqdn, subdomainSchema, toggleEnabledSchema, toggleServiceIpSchema, updateDomainGroupSchema, updateDomainSchema, updateServiceConfigSchema, updateServiceGroupSchema, updateServiceNodeSchema, updateSubdomainSchema, validateDnsRecord, vpsTrackerEventSchema };
|
||||
export { AUDIT_SEVERITIES, AUDIT_SOURCE_APPS, AUDIT_TARGET_TYPES, type AppSettingsPatch, type AppSwitcherConfig, type AppSwitcherEntry, type AuditListQuery, type AuditLogEntry, type AuditSeverity, type AuditSourceApp, type AuditTargetType, type BulkUpdateDomainsInput, CERT_ERROR, CERT_EXPIRED, CERT_MONITORING_VALUES, CERT_MONITOR_AUTO, CERT_MONITOR_REQUIRED, CERT_MONITOR_SKIPPED, CERT_OK, CERT_UNKNOWN, CERT_WARNING, type CertMonitoring, type Certificate, type CfDnsRecord, type CfHealthCheck, type CfZone, type CfdmBindingSyncItem, type ChangeDomainInput, type ChangeIpInput, type CreateDnsRecordInput, type CreateDnsRecordPayload, type CreateDomainInput, type CreateDomainMonitorInput, type CreateGroupInput, type CreateOriginHealthCheckInput, type CreateServiceBindingInput, type CreateServiceGroupInput, type CreateServiceInput, type CreateServiceNodeInput, type CreateServiceWithConfigInput, type CreateSubdomainInput, type DnsRecord, type Domain, type DomainEnvironment, type DomainListItem, type DomainMonitor, type DomainMonitorResult, type DomainMonitorType, type Group, type GroupWithStats, type HealthCheckConfig, type HealthCheckProvider, type HealthCheckScope, type HealthCheckTarget, type HealthCheckType, type HealthProbeLog, type HealthStatusQuery, type IngestAuditEvent, type IpHealthState, type IpHealthStatus, type JwtClaims, type LbMode, type LoginInput, type LoginRequest, type LoginResponse, type NodeHealthState, type NotificationLog, type OriginHealthCheck, type OriginHealthCheckRecord, type ParsedFqdn, type PatchDnsRecordPayload, type ReorderServicesInput, SYNC_CONFLICT, SYNC_ERROR, SYNC_PENDING_DELETE, SYNC_PENDING_PUSH, SYNC_SYNCED, type Service, type ServiceBinding, type ServiceBindingView, type ServiceDomainBinding, type ServiceDomainBindingView, type ServiceGroup, type ServiceGroupView, type ServiceGroupsResponse, type ServiceIpHealth, type ServiceNode, type ServiceNodeRecord, type ServiceOverview, type ServiceView, type Subdomain, type SubdomainRecord, type SyncJob, type ToggleEnabledInput, type ToggleServiceIpInput, type UpdateDomainInput, type UpdateServiceConfigInput, type UpdateServiceGroupInput, type UpdateServiceNodeInput, type UpdateSubdomainInput, ValidationError, type VpsTrackerEvent, appSettingsPatchSchema, appSwitcherConfigSchema, appSwitcherEntrySchema, appSwitcherIconSchema, auditListQuerySchema, auditLogEntrySchema, auditSeveritySchema, auditSourceAppSchema, auditTargetTypeSchema, bindingToFqdn, bulkUpdateDomainsSchema, certMonitoringSchema, certStatusFromExpiry, certificateSchema, cfdmBindingSyncItemSchema, cfdmSyncBindingsBodySchema, changeDomainSchema, changeIpSchema, createDnsRecordSchema, createDomainMonitorSchema, createDomainSchema, createGroupSchema, createOriginHealthCheckSchema, createServiceBindingSchema, createServiceGroupSchema, createServiceNodeSchema, createServiceSchema, createServiceWithConfigSchema, createSubdomainSchema, dnsNameToSubdomainLabel, dnsRecordNamesMatch, dnsRecordSchema, domainEnvironmentSchema, domainListItemSchema, domainMonitorResultSchema, domainMonitorSchema, domainMonitorTypeSchema, domainSchema, fqdnToDisplay, groupSchema, groupWithStatsSchema, healthCheckConfigSchema, healthCheckProviderSchema, healthCheckScopeSchema, healthCheckTypeSchema, healthProbeLogSchema, healthStatusQuerySchema, ingestAuditEventSchema, ipHealthStateSchema, ipHealthStatusSchema, isIpLiteral, isValidIpv4, lbModeSchema, loginSchema, nodeHealthStateSchema, normalizeDnsRecordName, notificationLogSchema, originHealthCheckSchema, parseFqdn, reorderServicesSchema, serviceBindingSchema, serviceDomainBindingSchema, serviceGroupSchema, serviceGroupTypeSchema, serviceGroupViewSchema, serviceGroupsResponseSchema, serviceIpHealthSchema, serviceNodeSchema, serviceSchema, serviceViewSchema, shouldMonitorService, subdomainLabelToFqdn, subdomainSchema, toggleEnabledSchema, toggleServiceIpSchema, updateDomainGroupSchema, updateDomainSchema, updateServiceConfigSchema, updateServiceGroupSchema, updateServiceNodeSchema, updateSubdomainSchema, validateDnsRecord, vpsTrackerEventSchema };
|
||||
|
||||
Vendored
+29
-4
@@ -190,12 +190,31 @@ var ipHealthStatusSchema = z.object({
|
||||
consecutive_failures: z.number(),
|
||||
consecutive_successes: z.number().optional().default(0),
|
||||
last_checked_at: z.string().nullable(),
|
||||
last_error: z.string().nullable()
|
||||
last_error: z.string().nullable(),
|
||||
colo: z.string().nullable().optional(),
|
||||
provider: healthCheckProviderSchema.optional()
|
||||
});
|
||||
var serviceIpHealthSchema = z.object({
|
||||
ip: z.string(),
|
||||
status: ipHealthStateSchema,
|
||||
latency_ms: z.number().nullable()
|
||||
latency_ms: z.number().nullable(),
|
||||
last_checked_at: z.string().nullable().optional(),
|
||||
last_error: z.string().nullable().optional(),
|
||||
provider: healthCheckProviderSchema.optional(),
|
||||
colo: z.string().nullable().optional()
|
||||
});
|
||||
var healthProbeLogSchema = z.object({
|
||||
id: z.number(),
|
||||
scope: z.string(),
|
||||
ref_id: z.number(),
|
||||
ip: z.string(),
|
||||
provider: healthCheckProviderSchema,
|
||||
status: ipHealthStateSchema,
|
||||
ok: z.coerce.boolean(),
|
||||
latency_ms: z.number().nullable(),
|
||||
colo: z.string().nullable(),
|
||||
error: z.string().nullable(),
|
||||
checked_at: z.string()
|
||||
});
|
||||
var groupSchema = z.object({
|
||||
id: z.number(),
|
||||
@@ -230,6 +249,7 @@ var serviceGroupSchema = z.object({
|
||||
health_check_interval_sec: z.number().default(30),
|
||||
health_check_timeout_ms: z.number().default(3e3),
|
||||
health_check_verify_tls: z.coerce.boolean().default(false),
|
||||
health_check_provider: healthCheckProviderSchema.catch("local"),
|
||||
created_at: z.string(),
|
||||
updated_at: z.string()
|
||||
});
|
||||
@@ -267,6 +287,7 @@ var serviceDomainBindingSchema = z.object({
|
||||
health_check_interval_sec: z.number().default(30),
|
||||
health_check_timeout_ms: z.number().default(3e3),
|
||||
health_check_verify_tls: z.coerce.boolean().default(false),
|
||||
health_check_provider: healthCheckProviderSchema.catch("local"),
|
||||
sync_status: z.string().nullable().default(null)
|
||||
}).transform((binding) => ({
|
||||
...binding,
|
||||
@@ -392,7 +413,8 @@ var healthCheckConfigFields = {
|
||||
health_check_expected_status: z.number().int().min(100).max(599).nullable().optional(),
|
||||
health_check_interval_sec: z.number().int().min(5).max(3600).optional(),
|
||||
health_check_timeout_ms: z.number().int().min(100).max(3e4).optional(),
|
||||
health_check_verify_tls: z.boolean().optional()
|
||||
health_check_verify_tls: z.boolean().optional(),
|
||||
health_check_provider: healthCheckProviderSchema.optional()
|
||||
};
|
||||
var healthCheckConfigSchema = z.object(healthCheckConfigFields);
|
||||
var serviceDomainInputSchema = z.object({
|
||||
@@ -703,7 +725,9 @@ var appSettingsPatchSchema = z3.object({
|
||||
healthDegradedFailures: z3.number().int().min(1).max(20).optional(),
|
||||
healthDownFailures: z3.number().int().min(1).max(50).optional(),
|
||||
healthLatencyWarnMs: z3.number().int().min(50).max(6e4).optional(),
|
||||
healthSuccessRecoveries: z3.number().int().min(1).max(20).optional()
|
||||
healthSuccessRecoveries: z3.number().int().min(1).max(20).optional(),
|
||||
healthWorkerUrl: z3.string().url().or(z3.literal("")).optional(),
|
||||
healthWorkerToken: z3.string().optional()
|
||||
}).superRefine((data, ctx) => {
|
||||
if (data.healthDegradedFailures != null && data.healthDownFailures != null && data.healthDownFailures < data.healthDegradedFailures) {
|
||||
ctx.addIssue({
|
||||
@@ -847,6 +871,7 @@ export {
|
||||
healthCheckProviderSchema,
|
||||
healthCheckScopeSchema,
|
||||
healthCheckTypeSchema,
|
||||
healthProbeLogSchema,
|
||||
healthStatusQuerySchema,
|
||||
ingestAuditEventSchema,
|
||||
ipHealthStateSchema,
|
||||
|
||||
@@ -35,6 +35,8 @@ export const appSettingsPatchSchema = z.object({
|
||||
healthDownFailures: z.number().int().min(1).max(50).optional(),
|
||||
healthLatencyWarnMs: z.number().int().min(50).max(60_000).optional(),
|
||||
healthSuccessRecoveries: z.number().int().min(1).max(20).optional(),
|
||||
healthWorkerUrl: z.string().url().or(z.literal("")).optional(),
|
||||
healthWorkerToken: z.string().optional(),
|
||||
}).superRefine((data, ctx) => {
|
||||
if (
|
||||
data.healthDegradedFailures != null &&
|
||||
|
||||
@@ -45,6 +45,8 @@ export const ipHealthStatusSchema = z.object({
|
||||
consecutive_successes: z.number().optional().default(0),
|
||||
last_checked_at: z.string().nullable(),
|
||||
last_error: z.string().nullable(),
|
||||
colo: z.string().nullable().optional(),
|
||||
provider: healthCheckProviderSchema.optional(),
|
||||
})
|
||||
|
||||
export type IpHealthStatus = z.infer<typeof ipHealthStatusSchema>
|
||||
@@ -53,10 +55,30 @@ export const serviceIpHealthSchema = z.object({
|
||||
ip: z.string(),
|
||||
status: ipHealthStateSchema,
|
||||
latency_ms: z.number().nullable(),
|
||||
last_checked_at: z.string().nullable().optional(),
|
||||
last_error: z.string().nullable().optional(),
|
||||
provider: healthCheckProviderSchema.optional(),
|
||||
colo: z.string().nullable().optional(),
|
||||
})
|
||||
|
||||
export type ServiceIpHealth = z.infer<typeof serviceIpHealthSchema>
|
||||
|
||||
export const healthProbeLogSchema = z.object({
|
||||
id: z.number(),
|
||||
scope: z.string(),
|
||||
ref_id: z.number(),
|
||||
ip: z.string(),
|
||||
provider: healthCheckProviderSchema,
|
||||
status: ipHealthStateSchema,
|
||||
ok: z.coerce.boolean(),
|
||||
latency_ms: z.number().nullable(),
|
||||
colo: z.string().nullable(),
|
||||
error: z.string().nullable(),
|
||||
checked_at: z.string(),
|
||||
})
|
||||
|
||||
export type HealthProbeLog = z.infer<typeof healthProbeLogSchema>
|
||||
|
||||
export const groupSchema = z.object({
|
||||
id: z.number(),
|
||||
name: z.string(),
|
||||
@@ -93,6 +115,7 @@ export const serviceGroupSchema = z.object({
|
||||
health_check_interval_sec: z.number().default(30),
|
||||
health_check_timeout_ms: z.number().default(3000),
|
||||
health_check_verify_tls: z.coerce.boolean().default(false),
|
||||
health_check_provider: healthCheckProviderSchema.catch('local'),
|
||||
created_at: z.string(),
|
||||
updated_at: z.string(),
|
||||
})
|
||||
@@ -133,6 +156,7 @@ export const serviceDomainBindingSchema = z
|
||||
health_check_interval_sec: z.number().default(30),
|
||||
health_check_timeout_ms: z.number().default(3000),
|
||||
health_check_verify_tls: z.coerce.boolean().default(false),
|
||||
health_check_provider: healthCheckProviderSchema.catch('local'),
|
||||
sync_status: z.string().nullable().default(null),
|
||||
})
|
||||
.transform((binding) => ({
|
||||
@@ -304,6 +328,7 @@ const healthCheckConfigFields = {
|
||||
health_check_interval_sec: z.number().int().min(5).max(3600).optional(),
|
||||
health_check_timeout_ms: z.number().int().min(100).max(30000).optional(),
|
||||
health_check_verify_tls: z.boolean().optional(),
|
||||
health_check_provider: healthCheckProviderSchema.optional(),
|
||||
}
|
||||
|
||||
export const healthCheckConfigSchema = z.object(healthCheckConfigFields)
|
||||
|
||||
@@ -22,6 +22,7 @@ export interface ServiceGroup {
|
||||
health_check_interval_sec: number;
|
||||
health_check_timeout_ms: number;
|
||||
health_check_verify_tls: boolean;
|
||||
health_check_provider: HealthCheckProvider;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
@@ -121,6 +122,7 @@ export interface ServiceBinding {
|
||||
health_check_interval_sec: number;
|
||||
health_check_timeout_ms: number;
|
||||
health_check_verify_tls: boolean;
|
||||
health_check_provider: HealthCheckProvider;
|
||||
routing_strategy: LbMode;
|
||||
operation_version: number;
|
||||
created_at: string;
|
||||
@@ -152,6 +154,7 @@ export interface ServiceBindingView {
|
||||
health_check_interval_sec: number;
|
||||
health_check_timeout_ms: number;
|
||||
health_check_verify_tls: boolean;
|
||||
health_check_provider: HealthCheckProvider;
|
||||
sync_status: string | null;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
@@ -177,6 +180,7 @@ export interface ServiceDomainBindingView {
|
||||
health_check_interval_sec: number;
|
||||
health_check_timeout_ms: number;
|
||||
health_check_verify_tls: boolean;
|
||||
health_check_provider: HealthCheckProvider;
|
||||
sync_status: string | null;
|
||||
}
|
||||
|
||||
@@ -293,12 +297,18 @@ export interface IpHealthStatus {
|
||||
consecutive_successes?: number;
|
||||
last_checked_at: string | null;
|
||||
last_error: string | null;
|
||||
colo?: string | null;
|
||||
provider?: HealthCheckProvider;
|
||||
}
|
||||
|
||||
export interface ServiceIpHealth {
|
||||
ip: string;
|
||||
status: IpHealthState;
|
||||
latency_ms: number | null;
|
||||
last_checked_at?: string | null;
|
||||
last_error?: string | null;
|
||||
provider?: HealthCheckProvider;
|
||||
colo?: string | null;
|
||||
}
|
||||
|
||||
export interface ServiceNode {
|
||||
@@ -382,4 +392,5 @@ export interface HealthCheckTarget {
|
||||
expected_status: number | null;
|
||||
timeout_ms: number;
|
||||
verify_tls: boolean;
|
||||
provider: HealthCheckProvider;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user