@cat-factory/kernel 0.329.0 → 0.330.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/domain/environment-reachability.logic.d.ts +122 -35
- package/dist/domain/environment-reachability.logic.d.ts.map +1 -1
- package/dist/domain/environment-reachability.logic.js +246 -61
- package/dist/domain/environment-reachability.logic.js.map +1 -1
- package/dist/domain/types.d.ts +1 -1
- package/dist/domain/types.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/ports/environment-investigation.d.ts +6 -6
- package/dist/ports/environment-investigation.d.ts.map +1 -1
- package/dist/ports/environment-provider.d.ts +9 -3
- package/dist/ports/environment-provider.d.ts.map +1 -1
- package/dist/ports/host-resolver.d.ts +59 -0
- package/dist/ports/host-resolver.d.ts.map +1 -0
- package/dist/ports/host-resolver.js +2 -0
- package/dist/ports/host-resolver.js.map +1 -0
- package/dist/ports/index.d.ts +1 -0
- package/dist/ports/index.d.ts.map +1 -1
- package/dist/ports/index.js.map +1 -1
- package/package.json +2 -2
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { EnvironmentRouteCandidate, EnvironmentRouteAttempt, EnvironmentRouteProof, EnvironmentUnreachableReason } from '@cat-factory/contracts';
|
|
2
|
+
import type { HostResolveOutcome } from '../ports/host-resolver.js';
|
|
2
3
|
import type { RouteProbeOutcome, RouteProbeRequest } from '../ports/route-probe.js';
|
|
3
4
|
/** How long one target gets before it counts as a route that does not carry. */
|
|
4
5
|
export declare const ROUTE_PROBE_TIMEOUT_MS = 4000;
|
|
@@ -12,53 +13,121 @@ export declare const ROUTE_PROBE_TIMEOUT_MS = 4000;
|
|
|
12
13
|
* 162ms, so the ceiling is well under a second of ordinary cost.
|
|
13
14
|
*/
|
|
14
15
|
export declare const MAX_PROBED_ADDRESSES = 4;
|
|
16
|
+
/**
|
|
17
|
+
* How long one stated NAME gets to resolve before the lookup counts as one the platform could not
|
|
18
|
+
* complete.
|
|
19
|
+
*
|
|
20
|
+
* Much tighter than {@link ROUTE_PROBE_TIMEOUT_MS}, because the two wait on different things: a
|
|
21
|
+
* connect legitimately hangs against a route that does not carry, which is the finding, whereas a
|
|
22
|
+
* resolver that has not answered in two seconds is not about to.
|
|
23
|
+
*/
|
|
24
|
+
export declare const HOST_RESOLVE_TIMEOUT_MS = 2000;
|
|
25
|
+
/**
|
|
26
|
+
* How many stated NAMES a proof will look up.
|
|
27
|
+
*
|
|
28
|
+
* Its own bound rather than a share of {@link MAX_PROBED_ADDRESSES}, because they cap different
|
|
29
|
+
* costs: that one caps sockets opened, this one caps lookups made, and one name can expand into
|
|
30
|
+
* several addresses so neither implies the other. The same four, sized for the same shape (an
|
|
31
|
+
* internal and a public balancer, with room for a second availability zone).
|
|
32
|
+
*/
|
|
33
|
+
export declare const MAX_RESOLVED_HOSTS = 4;
|
|
34
|
+
/**
|
|
35
|
+
* The stated NAMES a proof will resolve, in the provider's order, deduplicated and bounded.
|
|
36
|
+
*
|
|
37
|
+
* Exported because the caller does the I/O and the plan consumes the answers, so both have to
|
|
38
|
+
* agree about exactly which names are in scope. Stated ONCE here and read twice rather than
|
|
39
|
+
* recomputed on each side: two copies of a bound is how a name beyond it comes to be reported as a
|
|
40
|
+
* name nothing could resolve.
|
|
41
|
+
*/
|
|
42
|
+
export declare function planHostResolutions(candidates?: readonly EnvironmentRouteCandidate[]): string[];
|
|
15
43
|
/**
|
|
16
44
|
* One target a proof will try, in the order the proof will try it.
|
|
17
45
|
*
|
|
18
|
-
* A discriminated union rather than a dial target with a "skip me" flag, because the
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
46
|
+
* A discriminated union rather than a dial target with a "skip me" flag, because the second member
|
|
47
|
+
* carries NO {@link RouteProbeRequest}: a target the platform will not dial must be structurally
|
|
48
|
+
* undialable by whoever iterates this list, not merely marked. Handing out a request beside a
|
|
49
|
+
* boolean is how the next caller opens the socket anyway.
|
|
50
|
+
*
|
|
51
|
+
* ONE undialled member rather than one per cause, because the callers do the same thing with all
|
|
52
|
+
* of them (record the attempt, move on) and the cause they differ by is already the
|
|
53
|
+
* {@link EnvironmentUnreachableReason} each carries.
|
|
22
54
|
*/
|
|
23
55
|
export type RouteProbeTarget =
|
|
24
|
-
/**
|
|
56
|
+
/**
|
|
57
|
+
* Open a socket to this. `address` is null when the target dials the URL's own name, and
|
|
58
|
+
* `statedHost` is set when the address came from RESOLVING a stated name rather than from a
|
|
59
|
+
* stated address, so a proof can publish which candidate carried and not merely which literal.
|
|
60
|
+
*/
|
|
25
61
|
{
|
|
26
62
|
kind: 'dial';
|
|
27
63
|
request: RouteProbeRequest;
|
|
28
64
|
address: string | null;
|
|
65
|
+
statedHost?: string;
|
|
29
66
|
label: string;
|
|
30
67
|
}
|
|
31
|
-
/**
|
|
68
|
+
/**
|
|
69
|
+
* RECORD this and dial nothing: an address {@link isBridgeableAddress} refuses, a candidate
|
|
70
|
+
* naming no single target, a stated name that resolved nowhere, and a stated name this
|
|
71
|
+
* deployment has nothing to resolve with.
|
|
72
|
+
*/
|
|
32
73
|
| {
|
|
33
|
-
kind: '
|
|
34
|
-
address: string;
|
|
74
|
+
kind: 'undialled';
|
|
35
75
|
label: string;
|
|
36
76
|
reason: EnvironmentUnreachableReason;
|
|
77
|
+
detail?: string;
|
|
37
78
|
};
|
|
79
|
+
/** What {@link planRouteProbes} needs beyond the candidate list itself. */
|
|
80
|
+
export interface RouteProbePlan {
|
|
81
|
+
/**
|
|
82
|
+
* What the platform's resolver answered for each name {@link planHostResolutions} named, keyed
|
|
83
|
+
* by that same normalized name.
|
|
84
|
+
*
|
|
85
|
+
* A name IN that plan with no entry here means nothing was wired to resolve it, which is an
|
|
86
|
+
* admission about the deployment and is recorded as one. A name beyond the plan's bound is not
|
|
87
|
+
* in scope and is passed over, exactly as an address beyond the dial bound is.
|
|
88
|
+
*/
|
|
89
|
+
resolutions?: ReadonlyMap<string, HostResolveOutcome>;
|
|
90
|
+
timeoutMs?: number;
|
|
91
|
+
}
|
|
38
92
|
/**
|
|
39
93
|
* The targets a proof tries for one environment, in order: the URL's own name first, then each
|
|
40
|
-
* stated
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
94
|
+
* stated candidate in the PROVIDER'S preference order, a stated NAME expanded IN PLACE into the
|
|
95
|
+
* addresses it resolved to.
|
|
96
|
+
*
|
|
97
|
+
* The URL's name goes first because it is the answer that needs no bridge, and a deployment where
|
|
98
|
+
* it works must not start paying for `--add-host` entries and the warm-pool evictions they cost.
|
|
99
|
+
* The candidates keep the provider's order because the provider is the only thing that knows which
|
|
100
|
+
* of its balancers is the one it wants used; the platform decides only which one CARRIED. A name is
|
|
101
|
+
* expanded in place rather than having its addresses appended, so that order still means something
|
|
102
|
+
* when a provider states a name and an address side by side.
|
|
103
|
+
*
|
|
104
|
+
* **Every dialled target is an address a bridge could NAME**, whether the provider stated it or the
|
|
105
|
+
* platform resolved it. The rule is `isBridgeableAddress`, and applying it HERE rather than only at
|
|
106
|
+
* bridge-build time is the whole safety property of the probe: candidates are provider-authored
|
|
107
|
+
* data, so without it the orchestrator opens sockets wherever a manifest says and records the
|
|
108
|
+
* results on a row a workspace can read back, which is a liveness oracle against the deployment's
|
|
109
|
+
* own private network. Resolving first and grading each answer is what keeps that property intact
|
|
110
|
+
* for a name: the destination a bridge is built from is still an IP the platform itself proved, and
|
|
111
|
+
* a name answering with something unbridgeable is refused per address.
|
|
112
|
+
*
|
|
113
|
+
* The refusal costs nothing real either, because an address no bridge may name is an address no
|
|
114
|
+
* container could be pointed at, so proving it would prove something unusable. Refused and
|
|
115
|
+
* unresolvable targets are RECORDED (`kind: 'undialled'`) rather than dropped: a shortened list
|
|
116
|
+
* nobody is told about is how a provider's bad candidate becomes an unexplained `name_unresolved`.
|
|
117
|
+
*
|
|
118
|
+
* **Every cap this plan applies reports what it passed over**, in one final `not_attempted`
|
|
119
|
+
* target. Three of them bite (names beyond {@link MAX_RESOLVED_HOSTS}, addresses beyond the dial
|
|
120
|
+
* budget, records beyond the recording budget) and each ends the list early, so without that
|
|
121
|
+
* report a proof over a longer list is a prefix presented as the whole thing. It is not a
|
|
122
|
+
* cosmetic omission: {@link reduceRouteProof} grades `not_reached` only when every attempt
|
|
123
|
+
* established something, and a silently shortened list is how the deployer comes to fail a frame
|
|
124
|
+
* on a verdict about candidates the platform never looked at.
|
|
56
125
|
*
|
|
57
126
|
* Empty when there is no host or port to dial, which the caller reads as `no_candidate`: an
|
|
58
127
|
* environment with no URL was never going to be reached, and that is a different fact from one
|
|
59
128
|
* that was tried and failed.
|
|
60
129
|
*/
|
|
61
|
-
export declare function planRouteProbes(host: string | null | undefined, port: number | null | undefined, candidates?: readonly
|
|
130
|
+
export declare function planRouteProbes(host: string | null | undefined, port: number | null | undefined, candidates?: readonly EnvironmentRouteCandidate[], plan?: RouteProbePlan): RouteProbeTarget[];
|
|
62
131
|
/**
|
|
63
132
|
* Record one DIALLED attempt for the proof's log, whether it carried or not.
|
|
64
133
|
*
|
|
@@ -70,10 +139,27 @@ export declare function planRouteProbes(host: string | null | undefined, port: n
|
|
|
70
139
|
export declare function recordRouteAttempt(target: Extract<RouteProbeTarget, {
|
|
71
140
|
kind: 'dial';
|
|
72
141
|
}>, outcome: RouteProbeOutcome): EnvironmentRouteAttempt;
|
|
73
|
-
/**
|
|
74
|
-
|
|
75
|
-
|
|
142
|
+
/**
|
|
143
|
+
* Record a target the platform never DIALLED, so the omission is on the proof rather than lost.
|
|
144
|
+
*
|
|
145
|
+
* Carries the same `detail` a dialled attempt does, because one of the causes that lands here says
|
|
146
|
+
* nothing on its own: a lookup that failed rather than answering nothing is `probe_failed`, and
|
|
147
|
+
* without the resolver's own words a reader cannot tell a DNS timeout from a resolver outage from a
|
|
148
|
+
* bug in the adapter.
|
|
149
|
+
*/
|
|
150
|
+
export declare function recordUndialledAttempt(target: Extract<RouteProbeTarget, {
|
|
151
|
+
kind: 'undialled';
|
|
76
152
|
}>): EnvironmentRouteAttempt;
|
|
153
|
+
/**
|
|
154
|
+
* The target that carried, as {@link reduceRouteProof} publishes it: the address, plus the stated
|
|
155
|
+
* NAME it was resolved from when it came from one.
|
|
156
|
+
*
|
|
157
|
+
* The dial target's own shape, so the caller passes what it already has rather than picking two
|
|
158
|
+
* fields apart. Null for a proof where nothing carried, where `via` is null for the other reason.
|
|
159
|
+
*/
|
|
160
|
+
export type CarryingTarget = Pick<Extract<RouteProbeTarget, {
|
|
161
|
+
kind: 'dial';
|
|
162
|
+
}>, 'address' | 'statedHost'>;
|
|
77
163
|
/**
|
|
78
164
|
* Fold a completed set of attempts into the proof that is stored and narrated.
|
|
79
165
|
*
|
|
@@ -82,16 +168,17 @@ export declare function recordRefusedAttempt(target: Extract<RouteProbeTarget, {
|
|
|
82
168
|
*
|
|
83
169
|
* - **`reached`** as soon as any attempt carried, publishing the target that did.
|
|
84
170
|
* - **`inconclusive`** when nothing carried AND some attempt left a route unruled-out: a probe
|
|
85
|
-
* that could not classify its own failure,
|
|
86
|
-
* matching none of that facade's markers, or a Node errno
|
|
87
|
-
* here, and reading either as a verdict about the environment
|
|
88
|
-
* second way for a healthy deploy to die. The reason names the
|
|
171
|
+
* that could not classify its own failure, a candidate the plan passed over, or nothing to try
|
|
172
|
+
* at all. A workerd connect message matching none of that facade's markers, or a Node errno
|
|
173
|
+
* outside the mapped five, arrives here, and reading either as a verdict about the environment
|
|
174
|
+
* is how a diagnostic becomes a second way for a healthy deploy to die. The reason names the
|
|
175
|
+
* attempt that left it unknown.
|
|
89
176
|
* - **`not_reached`** only when EVERY attempt established something and none of them carried.
|
|
90
177
|
* The reported reason is then the FIRST attempt's, which is always the name, so a reader is
|
|
91
178
|
* told what happened to the address they were given rather than what happened to the last
|
|
92
179
|
* balancer in someone's preference list. The attempt log carries the rest, in order.
|
|
93
180
|
*/
|
|
94
|
-
export declare function reduceRouteProof(attempts: readonly EnvironmentRouteAttempt[],
|
|
181
|
+
export declare function reduceRouteProof(attempts: readonly EnvironmentRouteAttempt[], carried: CarryingTarget | null, checkedAt: number): EnvironmentRouteProof;
|
|
95
182
|
/**
|
|
96
183
|
* The operator-facing sentence for an environment nothing could reach, with every target tried.
|
|
97
184
|
*
|
|
@@ -147,7 +234,7 @@ export declare function describeRouteTargets(attempts: readonly EnvironmentRoute
|
|
|
147
234
|
* because it is an admission about the platform and naming it a cause is how "we could not tell"
|
|
148
235
|
* comes to read as a verdict.
|
|
149
236
|
*/
|
|
150
|
-
export declare function determinateRouteCause(candidates: readonly
|
|
237
|
+
export declare function determinateRouteCause(candidates: readonly EnvironmentRouteCandidate[], proof: EnvironmentRouteProof | null): string | null;
|
|
151
238
|
/**
|
|
152
239
|
* The proof recorded when nothing was wired to open a socket.
|
|
153
240
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"environment-reachability.logic.d.ts","sourceRoot":"","sources":["../../src/domain/environment-reachability.logic.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EACV,
|
|
1
|
+
{"version":3,"file":"environment-reachability.logic.d.ts","sourceRoot":"","sources":["../../src/domain/environment-reachability.logic.ts"],"names":[],"mappings":"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"}
|