@clivly/core 0.10.2 → 0.10.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -103,6 +103,19 @@ function deriveLiveness(facts) {
|
|
|
103
103
|
} } : {}
|
|
104
104
|
};
|
|
105
105
|
if (facts.presence && facts.presence.transport === "websocket") return websocketLiveness(facts, facts.presence, base);
|
|
106
|
+
const probe = facts.reachabilityProbe;
|
|
107
|
+
if (probe?.reachable && facts.now - probe.checkedAt < staleMs) {
|
|
108
|
+
const probeAgeMs = facts.now - probe.checkedAt;
|
|
109
|
+
const issues = livenessIssues(facts);
|
|
110
|
+
return {
|
|
111
|
+
...base,
|
|
112
|
+
ageMs: probeAgeMs,
|
|
113
|
+
ageLabel: formatAge(probeAgeMs),
|
|
114
|
+
health: issues.length > 0 ? "live_with_issues" : "live",
|
|
115
|
+
issues,
|
|
116
|
+
reachable: true
|
|
117
|
+
};
|
|
118
|
+
}
|
|
106
119
|
if (ageMs === null || ageMs >= staleMs) return {
|
|
107
120
|
...base,
|
|
108
121
|
health: "offline",
|
|
@@ -55,6 +55,19 @@ interface IntegrationFacts {
|
|
|
55
55
|
* transport keeps the cadence-derived behaviour every SDK in the field uses.
|
|
56
56
|
*/
|
|
57
57
|
presence?: DeploymentPresence | null;
|
|
58
|
+
/**
|
|
59
|
+
* The result of Clivly asking the app directly whether it is up.
|
|
60
|
+
*
|
|
61
|
+
* Every other signal here is *pushed* by the app. On a serverless host there
|
|
62
|
+
* is no process between requests to push anything: the SDK's heartbeat timer
|
|
63
|
+
* fires once at boot and is then frozen, so cadence alone reports a perfectly
|
|
64
|
+
* healthy deployment as offline forever. A probe inverts that — Clivly asks,
|
|
65
|
+
* and a host that answers is up by definition.
|
|
66
|
+
*
|
|
67
|
+
* Absent keeps the pure cadence behaviour, so nothing changes for apps that
|
|
68
|
+
* do hold a long-lived process.
|
|
69
|
+
*/
|
|
70
|
+
reachabilityProbe?: ReachabilityProbe | null;
|
|
58
71
|
/**
|
|
59
72
|
* Faults the running app diagnosed about itself on its last heartbeat — an
|
|
60
73
|
* unreadable database, a secret missing from the process environment. These
|
|
@@ -84,6 +97,21 @@ declare function formatAge(ms: number): string;
|
|
|
84
97
|
/** The cadence `createClivlySDK` uses when the host app configures none. */
|
|
85
98
|
declare const DEFAULT_HEARTBEAT_INTERVAL_MS = 60000;
|
|
86
99
|
type ConnectionHealth = "live" | "live_with_issues" | "stale" | "offline";
|
|
100
|
+
/**
|
|
101
|
+
* Clivly's own answer to "is this app up", obtained by asking it rather than
|
|
102
|
+
* waiting to be told.
|
|
103
|
+
*
|
|
104
|
+
* `reachable` is deliberately about the *connection*, not the response body: an
|
|
105
|
+
* app that answers `401` has proved it is running just as conclusively as one
|
|
106
|
+
* that answers `200`. Only silence — a timeout, a refused connection, DNS that
|
|
107
|
+
* does not resolve — means offline.
|
|
108
|
+
*/
|
|
109
|
+
interface ReachabilityProbe {
|
|
110
|
+
/** When Clivly performed the check. Probe results are cached, so this ages. */
|
|
111
|
+
checkedAt: number;
|
|
112
|
+
/** Did anything answer at the other end? */
|
|
113
|
+
reachable: boolean;
|
|
114
|
+
}
|
|
87
115
|
/** Which algorithm decides whether this deployment is up. */
|
|
88
116
|
type PresenceTransport = "websocket" | "http";
|
|
89
117
|
type PresenceConnectionState = "connected" | "reconnecting" | "disconnected";
|
|
@@ -172,4 +200,4 @@ declare const INSTALL_COMMAND = "npx clivly init";
|
|
|
172
200
|
declare function nextAction(steps: IntegrationStep[], status: IntegrationStatus, liveness: ConnectionLiveness): NextAction | null;
|
|
173
201
|
declare function computeIntegrationState(facts: IntegrationFacts): IntegrationState;
|
|
174
202
|
//#endregion
|
|
175
|
-
export { ConnectionHealth, ConnectionLiveness, DEFAULT_HEARTBEAT_INTERVAL_MS, DeploymentPresence, HostEnvironment, INSTALL_COMMAND, INTEGRATION_STEPS, INTEGRATION_STEP_LABELS, IntegrationFacts, IntegrationState, IntegrationStatus, IntegrationStep, NextAction, PresenceConnectionState, PresenceTransport, RunFact, STEP_PREREQUISITES, StepId, StepProblem, StepState, computeIntegrationState, deriveLiveness, deriveStatus, formatAge, livenessWindows, nextAction, resolveSteps, stepIndex };
|
|
203
|
+
export { ConnectionHealth, ConnectionLiveness, DEFAULT_HEARTBEAT_INTERVAL_MS, DeploymentPresence, HostEnvironment, INSTALL_COMMAND, INTEGRATION_STEPS, INTEGRATION_STEP_LABELS, IntegrationFacts, IntegrationState, IntegrationStatus, IntegrationStep, NextAction, PresenceConnectionState, PresenceTransport, ReachabilityProbe, RunFact, STEP_PREREQUISITES, StepId, StepProblem, StepState, computeIntegrationState, deriveLiveness, deriveStatus, formatAge, livenessWindows, nextAction, resolveSteps, stepIndex };
|
|
@@ -55,6 +55,19 @@ interface IntegrationFacts {
|
|
|
55
55
|
* transport keeps the cadence-derived behaviour every SDK in the field uses.
|
|
56
56
|
*/
|
|
57
57
|
presence?: DeploymentPresence | null;
|
|
58
|
+
/**
|
|
59
|
+
* The result of Clivly asking the app directly whether it is up.
|
|
60
|
+
*
|
|
61
|
+
* Every other signal here is *pushed* by the app. On a serverless host there
|
|
62
|
+
* is no process between requests to push anything: the SDK's heartbeat timer
|
|
63
|
+
* fires once at boot and is then frozen, so cadence alone reports a perfectly
|
|
64
|
+
* healthy deployment as offline forever. A probe inverts that — Clivly asks,
|
|
65
|
+
* and a host that answers is up by definition.
|
|
66
|
+
*
|
|
67
|
+
* Absent keeps the pure cadence behaviour, so nothing changes for apps that
|
|
68
|
+
* do hold a long-lived process.
|
|
69
|
+
*/
|
|
70
|
+
reachabilityProbe?: ReachabilityProbe | null;
|
|
58
71
|
/**
|
|
59
72
|
* Faults the running app diagnosed about itself on its last heartbeat — an
|
|
60
73
|
* unreadable database, a secret missing from the process environment. These
|
|
@@ -84,6 +97,21 @@ declare function formatAge(ms: number): string;
|
|
|
84
97
|
/** The cadence `createClivlySDK` uses when the host app configures none. */
|
|
85
98
|
declare const DEFAULT_HEARTBEAT_INTERVAL_MS = 60000;
|
|
86
99
|
type ConnectionHealth = "live" | "live_with_issues" | "stale" | "offline";
|
|
100
|
+
/**
|
|
101
|
+
* Clivly's own answer to "is this app up", obtained by asking it rather than
|
|
102
|
+
* waiting to be told.
|
|
103
|
+
*
|
|
104
|
+
* `reachable` is deliberately about the *connection*, not the response body: an
|
|
105
|
+
* app that answers `401` has proved it is running just as conclusively as one
|
|
106
|
+
* that answers `200`. Only silence — a timeout, a refused connection, DNS that
|
|
107
|
+
* does not resolve — means offline.
|
|
108
|
+
*/
|
|
109
|
+
interface ReachabilityProbe {
|
|
110
|
+
/** When Clivly performed the check. Probe results are cached, so this ages. */
|
|
111
|
+
checkedAt: number;
|
|
112
|
+
/** Did anything answer at the other end? */
|
|
113
|
+
reachable: boolean;
|
|
114
|
+
}
|
|
87
115
|
/** Which algorithm decides whether this deployment is up. */
|
|
88
116
|
type PresenceTransport = "websocket" | "http";
|
|
89
117
|
type PresenceConnectionState = "connected" | "reconnecting" | "disconnected";
|
|
@@ -172,4 +200,4 @@ declare const INSTALL_COMMAND = "npx clivly init";
|
|
|
172
200
|
declare function nextAction(steps: IntegrationStep[], status: IntegrationStatus, liveness: ConnectionLiveness): NextAction | null;
|
|
173
201
|
declare function computeIntegrationState(facts: IntegrationFacts): IntegrationState;
|
|
174
202
|
//#endregion
|
|
175
|
-
export { ConnectionHealth, ConnectionLiveness, DEFAULT_HEARTBEAT_INTERVAL_MS, DeploymentPresence, HostEnvironment, INSTALL_COMMAND, INTEGRATION_STEPS, INTEGRATION_STEP_LABELS, IntegrationFacts, IntegrationState, IntegrationStatus, IntegrationStep, NextAction, PresenceConnectionState, PresenceTransport, RunFact, STEP_PREREQUISITES, StepId, StepProblem, StepState, computeIntegrationState, deriveLiveness, deriveStatus, formatAge, livenessWindows, nextAction, resolveSteps, stepIndex };
|
|
203
|
+
export { ConnectionHealth, ConnectionLiveness, DEFAULT_HEARTBEAT_INTERVAL_MS, DeploymentPresence, HostEnvironment, INSTALL_COMMAND, INTEGRATION_STEPS, INTEGRATION_STEP_LABELS, IntegrationFacts, IntegrationState, IntegrationStatus, IntegrationStep, NextAction, PresenceConnectionState, PresenceTransport, ReachabilityProbe, RunFact, STEP_PREREQUISITES, StepId, StepProblem, StepState, computeIntegrationState, deriveLiveness, deriveStatus, formatAge, livenessWindows, nextAction, resolveSteps, stepIndex };
|
|
@@ -102,6 +102,19 @@ function deriveLiveness(facts) {
|
|
|
102
102
|
} } : {}
|
|
103
103
|
};
|
|
104
104
|
if (facts.presence && facts.presence.transport === "websocket") return websocketLiveness(facts, facts.presence, base);
|
|
105
|
+
const probe = facts.reachabilityProbe;
|
|
106
|
+
if (probe?.reachable && facts.now - probe.checkedAt < staleMs) {
|
|
107
|
+
const probeAgeMs = facts.now - probe.checkedAt;
|
|
108
|
+
const issues = livenessIssues(facts);
|
|
109
|
+
return {
|
|
110
|
+
...base,
|
|
111
|
+
ageMs: probeAgeMs,
|
|
112
|
+
ageLabel: formatAge(probeAgeMs),
|
|
113
|
+
health: issues.length > 0 ? "live_with_issues" : "live",
|
|
114
|
+
issues,
|
|
115
|
+
reachable: true
|
|
116
|
+
};
|
|
117
|
+
}
|
|
105
118
|
if (ageMs === null || ageMs >= staleMs) return {
|
|
106
119
|
...base,
|
|
107
120
|
health: "offline",
|