@mark1russell7/harness 0.11.19 → 0.11.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -3
- package/build/{cell-PYx_218L.d.ts → cell-BxBZUssi.d.ts} +12 -6
- package/build/{image-Dqji7rnm.js → image-vB51btI1.js} +47 -7
- package/build/image-vB51btI1.js.map +1 -0
- package/build/index.d.ts +4 -4
- package/build/index.js +1 -1
- package/build/index.js.map +1 -1
- package/build/schema.d.ts +1 -1
- package/build/schema.js +1 -1
- package/image/docker-proxy/Dockerfile +11 -0
- package/image/native/src/bin/inject.rs +3 -0
- package/package.json +3 -2
- package/build/image-Dqji7rnm.js.map +0 -1
package/README.md
CHANGED
|
@@ -165,7 +165,9 @@ The entry `@mark1russell7/harness/schema` has the zod schemas of a source (`imag
|
|
|
165
165
|
|
|
166
166
|
## The images
|
|
167
167
|
|
|
168
|
-
The harness ships
|
|
168
|
+
The harness ships sixteen images, each as a shipped source (`ImageSource`). The tag of each image comes from the path of its Dockerfile and the content of all the files that its Dockerfile reads. The harness copies these files into a new build context, from its own package and from the prober package. Thus the build works in a workspace and from npm.
|
|
169
|
+
|
|
170
|
+
From 0.11.20, the harness builds each image with the CLI of Docker (`docker build`), thus with BuildKit where the CLI has it. Testcontainers reads nothing of the output of a build, and its error is "Failed to build image" only. The error of a failed build holds each line of its output that names an error, and its last 15 lines (`buildFailure`). Thus the host of a lab needs the CLI of Docker and its daemon.
|
|
169
171
|
|
|
170
172
|
- **The harness image** (`image/Dockerfile`) has two stages, each a digest-pinned Alpine. `Cargo.lock` pins the crates. The image holds:
|
|
171
173
|
- the kernel program of the prober, compiled against the BTF of the kernel that builds it, and its Rust collector.
|
|
@@ -210,6 +212,7 @@ The harness ships fifteen images, each as a shipped source (`ImageSource`). The
|
|
|
210
212
|
- A cell gives its configuration as files of the hop (`ProxyHop.files`): `/etc/pgbouncer/pgbouncer.ini` and `/etc/pgbouncer/userlist.txt`. In them, `{{next.host}}` and `{{next.port}}` are the host and the port of the server.
|
|
211
213
|
- PgBouncer does not start as root, thus it operates as its own user.
|
|
212
214
|
- **The Pgpool-II image** (`image/pgpool`) is Pgpool-II 4.7.3, a pooler hop, on a digest-pinned Alpine. The build gets the source of the tag V4_7_3 from GitHub and checks its SHA-256 before it builds. The tree of git holds no `configure`, thus the build runs autoreconf, and bison and flex make the parser.
|
|
215
|
+
- **The docker-proxy image** (`image/docker-proxy`) is docker-proxy of Docker Engine 29.1.5, the userland proxy of a published port, as a proxy hop. The build gets the static bundle of Docker 29.1.5 and checks its SHA-256. The proxy writes its status to fd 3, the pipe of its parent in Docker. Thus a cell starts it with `3>/dev/null`.
|
|
213
216
|
- A hop takes the image as a shipped source: `{ kind: "shipped", name: "pgpool" }`.
|
|
214
217
|
- A cell gives its configuration as one file of the hop: `/etc/pgpool/pgpool.conf`. Each other file that Pgpool-II reads is empty in the image. Pgpool-II operates in the foreground as its own user.
|
|
215
218
|
|
|
@@ -243,8 +246,8 @@ ioredis sets the keepalive of its socket itself, after it connects. Thus a cell
|
|
|
243
246
|
- **A toxic** (`toxic`, `Cell.toxic`) is one toxic of Toxiproxy, added through its HTTP API by `inject http`, with monotonic stamps around the request. Its name is `fault`, and the harness removes it after the run. A cell whose fault is another one adds its toxic first: a slow close, then the close of the server.
|
|
244
247
|
- **A close of the server** (`server-close`) makes the server close the connection of each client, with `Target.close`: `CLIENT KILL` for Redis.
|
|
245
248
|
- **A stall of the application** (`app-stall`) injects nothing. The server process holds the reply, because the request asks for it (`HttpProbe.hold`), and its kernel stays up.
|
|
246
|
-
- **An event at a proxy** (`hop-event`, `Cell.event`) is a signal to the program of the proxy, or a query on its console. Examples are a reload of the configuration and PAUSE on the console of PgBouncer.
|
|
247
|
-
- A signal goes to each process of `ProxyHop.program
|
|
249
|
+
- **An event at a proxy** (`hop-event`, `Cell.event`) is a signal to the program of the proxy, or a query on its console. Examples are a reload of the configuration, a stop of a proxy and PAUSE on the console of PgBouncer.
|
|
250
|
+
- A signal goes to each process of `ProxyHop.program`: HUP, TERM or INT (`HopSignal`). A sidecar in the network and process namespaces of the proxy sends it (`inject signal NAME HUP`). The lab starts that sidecar at the first signal.
|
|
248
251
|
- A query goes from the injector of the proxy to its console on 127.0.0.1, as a user that the console trusts (`inject query`). The injector speaks the simple query of the PostgreSQL protocol. Its stamps bracket the query and its ReadyForQuery. After the run, the harness sends the `undo` of the query, for example RESUME after PAUSE.
|
|
249
252
|
- Without `inFlight`, the event comes first, and the request meets it. With `inFlight`, the request goes first, and the event comes while it is in flight. A run whose order is not that order is void.
|
|
250
253
|
- **A fault on a group** acts on the part that `Cell.faultAt` names by its role:
|
|
@@ -31,8 +31,8 @@ import { KernelRecord } from "@mark1russell7/prober";
|
|
|
31
31
|
* - `none` injects nothing. A calibration cell measures the path itself: for example the time of a
|
|
32
32
|
* proxy between its two sockets (`Cell.calibrates`).
|
|
33
33
|
* - `hop-event` is an event at a proxy of the topology (`Cell.event`): a signal to its program, or a
|
|
34
|
-
* query on its console. Examples are a reload of the configuration (SIGHUP)
|
|
35
|
-
* console of PgBouncer.
|
|
34
|
+
* query on its console. Examples are a reload of the configuration (SIGHUP), a stop of a proxy
|
|
35
|
+
* (SIGTERM or SIGINT) and PAUSE on the console of PgBouncer.
|
|
36
36
|
*
|
|
37
37
|
* A fault at a router of the topology (`Cell.faultAt`) acts on what the router forwards toward
|
|
38
38
|
* one side. It is a black hole, a reset or an ICMP unreachable. It can also be a simplex drop, an
|
|
@@ -127,6 +127,11 @@ interface ProxyHop {
|
|
|
127
127
|
/** This name is the process of the proxy, as /proc/PID/comm holds it, for a signal of a `hop-event`. */
|
|
128
128
|
readonly program?: string;
|
|
129
129
|
}
|
|
130
|
+
/**
|
|
131
|
+
* A signal of a hop event. HUP reloads the configuration of a pooler. TERM stops a proxy, as a stop of
|
|
132
|
+
* its container does. INT stops docker-proxy, as Docker does when it removes a port binding.
|
|
133
|
+
*/
|
|
134
|
+
type HopSignal = "HUP" | "TERM" | "INT";
|
|
130
135
|
/**
|
|
131
136
|
* An event at a proxy hop (`hop-event`). A signal goes to each process of the program of the hop
|
|
132
137
|
* (`ProxyHop.program`). A query goes to the console of the hop from its own namespace, as a user
|
|
@@ -136,7 +141,7 @@ interface ProxyHop {
|
|
|
136
141
|
*/
|
|
137
142
|
type HopEvent = {
|
|
138
143
|
readonly hop: string;
|
|
139
|
-
readonly signal:
|
|
144
|
+
readonly signal: HopSignal;
|
|
140
145
|
readonly inFlight?: true;
|
|
141
146
|
} | {
|
|
142
147
|
readonly hop: string;
|
|
@@ -659,8 +664,9 @@ type HarnessImage = "procedures";
|
|
|
659
664
|
* A shipped image is an image that the harness ships, by its name. Its build context is in the
|
|
660
665
|
* package of the harness, and in the package of the prober for `harness`. `grpc-go` is a server of
|
|
661
666
|
* grpc-go and `etcd` is etcd on Alpine: each is a subject of a target (`Target.subject`).
|
|
667
|
+
* `docker-proxy` is the userland proxy of Docker Engine 29.1.5, the program of a proxy hop.
|
|
662
668
|
*/
|
|
663
|
-
type Shipped = "harness" | "node" | "go-http" | "node-http" | "mongo" | "pg" | "hikari" | "amqp" | "grpc" | "grpc-go" | "etcd" | "procedures" | "router" | "pgbouncer" | "pgpool";
|
|
669
|
+
type Shipped = "harness" | "node" | "go-http" | "node-http" | "mongo" | "pg" | "hikari" | "amqp" | "grpc" | "grpc-go" | "etcd" | "procedures" | "router" | "pgbouncer" | "pgpool" | "docker-proxy";
|
|
664
670
|
/**
|
|
665
671
|
* An image source tells where an image comes from, as data. The harness resolves each kind to an
|
|
666
672
|
* image that it can start:
|
|
@@ -1116,5 +1122,5 @@ interface RunTopology {
|
|
|
1116
1122
|
}>>;
|
|
1117
1123
|
}
|
|
1118
1124
|
//#endregion
|
|
1119
|
-
export {
|
|
1120
|
-
//# sourceMappingURL=cell-
|
|
1125
|
+
export { Subject as $, Prediction as A, RequestPrediction as B, KernelRecord as C, MiddleboxForm as D, MiddleboxExpectation as E, Recovers as F, RunPart as G, RttRange as H, Reference as I, SentinelStage as J, RunTopology as K, ReplicaSet as L, ProxyHop as M, ProxyTime as N, Observer as O, Reconnects as P, StageBand as Q, ReplicaSetStage as R, ImageSource as S, MiddleboxEvent as T, Run as U, RouterHop as V, RunGroup as W, ShippedImage as X, Shipped as Y, Stage as Z, Hop as _, Cluster as a, latestEndOf as at, HopSignal as b, DriverBand as c, FaultPlace as d, Target as et, Group as f, HarnessImage as g, GroupRole as h, ClientImage as i, isHopPlace as it, ProbeEvent as j, PinnedImage as k, DriverStep as l, GroupPrediction as m, Cell as n, Toxic as nt, ClusterClientAt as o, GroupPlace as p, SentinelEvent as q, Client as r, WsProbe as rt, ClusterStage as s, BuildImage as t, Topology as tt, Fault as u, HopEvent as v, LineMatch as w, HttpProbe as x, HopPlace as y, Replies as z };
|
|
1126
|
+
//# sourceMappingURL=cell-BxBZUssi.d.ts.map
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
+
import { execFile } from "node:child_process";
|
|
2
3
|
import { copyFileSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, realpathSync, rmSync, statSync } from "node:fs";
|
|
3
4
|
import { createRequire } from "node:module";
|
|
4
5
|
import { tmpdir } from "node:os";
|
|
@@ -111,6 +112,11 @@ const SHIPPED = {
|
|
|
111
112
|
name: "loom-harness-pgpool",
|
|
112
113
|
dockerfile: "harness/image/pgpool/Dockerfile",
|
|
113
114
|
from: ["harness/image/pgpool"]
|
|
115
|
+
},
|
|
116
|
+
"docker-proxy": {
|
|
117
|
+
name: "loom-harness-docker-proxy",
|
|
118
|
+
dockerfile: "harness/image/docker-proxy/Dockerfile",
|
|
119
|
+
from: ["harness/image/docker-proxy"]
|
|
114
120
|
}
|
|
115
121
|
};
|
|
116
122
|
/** These are the names of the images that the harness ships. */
|
|
@@ -387,11 +393,45 @@ const planOf = (source) => {
|
|
|
387
393
|
if (source.kind === "shipped") shippedPlans.set(source.name, plan);
|
|
388
394
|
return plan;
|
|
389
395
|
};
|
|
390
|
-
/**
|
|
391
|
-
const
|
|
392
|
-
|
|
393
|
-
|
|
396
|
+
/** These counts are how many lines of the output of a failed build its error holds: its error lines, then its last lines. */
|
|
397
|
+
const BUILD_ERRORS = 10;
|
|
398
|
+
/**
|
|
399
|
+
* This function gives the lines of the output of a failed build that its error holds. They are each
|
|
400
|
+
* line that names an error, for example the diagnostic of a compiler, then the last lines.
|
|
401
|
+
*/
|
|
402
|
+
const buildFailure = (output) => {
|
|
403
|
+
const lines = output.trim().split(/\r?\n/);
|
|
404
|
+
const tail = lines.slice(-15);
|
|
405
|
+
const errors = lines.slice(0, -15).filter((line) => /\berror\b/i.test(line)).slice(0, BUILD_ERRORS);
|
|
406
|
+
return [
|
|
407
|
+
...errors,
|
|
408
|
+
...errors.length > 0 ? ["..."] : [],
|
|
409
|
+
...tail
|
|
410
|
+
].join("\n");
|
|
394
411
|
};
|
|
412
|
+
/**
|
|
413
|
+
* This function builds a staged context with the CLI of Docker, thus with BuildKit where the CLI has
|
|
414
|
+
* it. Testcontainers reads nothing of the output of a build, and it fails with "Failed to build
|
|
415
|
+
* image" only. The error of a failed build here holds its error lines and the end of its output.
|
|
416
|
+
*/
|
|
417
|
+
const dockerBuild = (context, plan) => new Promise((resolve, reject) => {
|
|
418
|
+
const args = [
|
|
419
|
+
"build",
|
|
420
|
+
"--progress=plain",
|
|
421
|
+
"--tag",
|
|
422
|
+
plan.tag,
|
|
423
|
+
"--file",
|
|
424
|
+
join(context, plan.dockerfile),
|
|
425
|
+
context
|
|
426
|
+
];
|
|
427
|
+
execFile("docker", args, { maxBuffer: 67108864 }, (error, _stdout, stderr) => {
|
|
428
|
+
if (error === null) {
|
|
429
|
+
resolve();
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
432
|
+
reject(/* @__PURE__ */ new Error(`docker build of ${plan.tag} failed (${error.message.split("\n")[0]}):\n${buildFailure(String(stderr))}`));
|
|
433
|
+
});
|
|
434
|
+
});
|
|
395
435
|
const built = /* @__PURE__ */ new Map();
|
|
396
436
|
/**
|
|
397
437
|
* These are the waits before each next try of a build that fails, in milliseconds. A fault of a
|
|
@@ -442,8 +482,8 @@ const buildOnce = (plan, builder = dockerBuild, waits = BUILD_WAITS) => {
|
|
|
442
482
|
};
|
|
443
483
|
/**
|
|
444
484
|
* This function gives an image that a lab can start, from its source. It is the name of a stock
|
|
445
|
-
* image or of a pinned image, which the lab pulls, or the tag of a build.
|
|
446
|
-
*
|
|
485
|
+
* image or of a pinned image, which the lab pulls, or the tag of a build. A build goes through the CLI
|
|
486
|
+
* of Docker.
|
|
447
487
|
*/
|
|
448
488
|
const imageOf = async (source) => {
|
|
449
489
|
const plan = planOf(source);
|
|
@@ -481,4 +521,4 @@ const targetImageOf = (target) => imageOf(targetSourceOf(target));
|
|
|
481
521
|
//#endregion
|
|
482
522
|
export { subjectClient as C, unlockedManifests as D, targetSourceOf as E, unpinnedBases as O, routerImage as S, targetImageOf as T, nodeHttpImage as _, SHIPPED_NAMES as a, proceduresImage as b, goHttpImage as c, hikariClientImage as d, imageOf as f, nodeClientImage as g, mongoClientImage as h, SHIPPED_CLIENTS as i, grpcClientImage as l, inContext as m, PINNED as n, SUBJECTS as o, imageProblems as p, REPOSITORY as r, amqpClientImage as s, CLIENT_NAMES as t, harnessImage as u, pgClientImage as v, subjectProblems as w, programOf as x, planOf as y };
|
|
483
523
|
|
|
484
|
-
//# sourceMappingURL=image-
|
|
524
|
+
//# sourceMappingURL=image-vB51btI1.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image-vB51btI1.js","names":[],"sources":["../src/image.ts"],"sourcesContent":["import { execFile } from \"node:child_process\";\nimport { createHash } from \"node:crypto\";\nimport { copyFileSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, realpathSync, rmSync, statSync } from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport { tmpdir } from \"node:os\";\nimport { dirname, join, posix, relative, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { isDeepStrictEqual } from \"node:util\";\nimport type { BuildImage, Client, ClientImage, ImageSource, Shipped, ShippedImage, Subject, Target } from \"./cell.ts\";\n\n/**\n * This module resolves the source of each image (`ImageSource`) to an image that a lab can start.\n * A pinned image is its own name. A build context, or an image that the harness ships, becomes a\n * build with a tag from its content. Each image of the harness is a shipped source in one table.\n * Thus the procedures image of a subject is data, as the image of a caller is.\n */\n\n/**\n * These are the roots of the two packages that the shipped images read: this package, and the\n * prober that Node resolves for it. In a workspace, they are two folders side by side. From npm,\n * the prober is a link, and a Docker build context does not follow a link. Thus each image builds\n * from a context that the harness copies from the two roots.\n */\nconst ROOTS: Readonly<Record<string, string>> = {\n harness: fileURLToPath(new URL(\"..\", import.meta.url)),\n prober: dirname(realpathSync(createRequire(import.meta.url).resolve(\"@mark1russell7/prober/package.json\"))),\n};\n\n/** This function gives the path of a part of a shipped image, which is `<package>/<path>` in the context. */\nconst pathOf = (part: string): string => {\n const [root, ...rest] = part.split(\"/\");\n const base = ROOTS[root!];\n if (base === undefined) throw new Error(`${part} is in no package that the images read`);\n return join(base, ...rest);\n};\n\n/** A shipped context is the build context of a shipped image: its Dockerfile, and each file or folder that the Dockerfile reads, as `<package>/<path>`. */\ninterface ShippedContext {\n readonly name: string;\n readonly dockerfile: string;\n readonly from: readonly string[];\n}\n\n/** These are the build contexts of the images that the harness ships, by their names. */\nconst SHIPPED: Readonly<Record<Shipped, ShippedContext>> = {\n // the prober, the TCP client, the injector and the namespace admin\n harness: {\n name: \"loom-harness\",\n dockerfile: \"harness/image/Dockerfile\",\n from: [\"harness/image/Dockerfile\", \"harness/image/native\", \"prober/bpf\", \"prober/native\", \"prober/fixtures\"],\n },\n // the Node client: ioredis 6.0.0 on Node 24.21.0\n node: { name: \"loom-harness-node\", dockerfile: \"harness/image/node/Dockerfile\", from: [\"harness/image/node\"] },\n // the Go HTTP client: the http.Transport of Go 1.27.2\n \"go-http\": { name: \"loom-harness-go-http\", dockerfile: \"harness/image/go-http/Dockerfile\", from: [\"harness/image/go-http\"] },\n // the Node HTTP clients: the http.Agent of Node 24.21.0, and undici 8.12.2\n \"node-http\": { name: \"loom-harness-node-http\", dockerfile: \"harness/image/node-http/Dockerfile\", from: [\"harness/image/node-http\"] },\n // the MongoDB client: the driver mongodb 7.7.0 on Node 24.21.0, and its step-down script\n mongo: { name: \"loom-harness-mongo\", dockerfile: \"harness/image/mongo/Dockerfile\", from: [\"harness/image/mongo\"] },\n // the PostgreSQL client: node-postgres (pg 8.23.1 with pg-pool 3.14.0) on Node 24.21.0\n pg: { name: \"loom-harness-pg\", dockerfile: \"harness/image/pg/Dockerfile\", from: [\"harness/image/pg\"] },\n // the client of HikariCP 7.1.0 over pgjdbc 42.7.13 on Temurin 21.0.12.1: its jars by their SHA-256\n hikari: { name: \"loom-harness-hikari\", dockerfile: \"harness/image/hikari/Dockerfile\", from: [\"harness/image/hikari\"] },\n // the RabbitMQ client: amqplib 2.2.0 on Node 24.21.0\n amqp: { name: \"loom-harness-amqp\", dockerfile: \"harness/image/amqp/Dockerfile\", from: [\"harness/image/amqp\"] },\n // the gRPC client: grpc-js 1.14.6 on Node 24.21.0\n grpc: { name: \"loom-harness-grpc\", dockerfile: \"harness/image/grpc/Dockerfile\", from: [\"harness/image/grpc\"] },\n // the gRPC server: a server of grpc-go v1.84.0, built with Go 1.27.2, that can hold a reply\n \"grpc-go\": { name: \"loom-harness-grpc-go\", dockerfile: \"harness/image/grpc-go/Dockerfile\", from: [\"harness/image/grpc-go\"] },\n // etcd v3.6.15 from its image, on Alpine: a shell to hold it, and its binaries unchanged\n etcd: { name: \"loom-harness-etcd\", dockerfile: \"harness/image/etcd/Dockerfile\", from: [\"harness/image/etcd\"] },\n // @procedures/client 0.7.0 on Node 24.21.0: its WebSocket client, and the script of its server\n procedures: { name: \"loom-harness-procedures\", dockerfile: \"harness/image/procedures/Dockerfile\", from: [\"harness/image/procedures\"] },\n // the router of a middlebox chain: NAT and conntrack, with a form for a forgotten flow\n router: { name: \"loom-harness-router\", dockerfile: \"harness/image/router/Dockerfile\", from: [\"harness/image/router\"] },\n // PgBouncer 1.26.1, a pooler hop: built from its release tarball, by its SHA-256\n pgbouncer: { name: \"loom-harness-pgbouncer\", dockerfile: \"harness/image/pgbouncer/Dockerfile\", from: [\"harness/image/pgbouncer\"] },\n // Pgpool-II 4.7.3, a pooler hop: built from the source of its tag, by its SHA-256\n pgpool: { name: \"loom-harness-pgpool\", dockerfile: \"harness/image/pgpool/Dockerfile\", from: [\"harness/image/pgpool\"] },\n // docker-proxy of Docker Engine 29.1.5, a proxy hop: its binary from the static bundle of Docker, by its SHA-256\n \"docker-proxy\": { name: \"loom-harness-docker-proxy\", dockerfile: \"harness/image/docker-proxy/Dockerfile\", from: [\"harness/image/docker-proxy\"] },\n};\n\n/** These are the names of the images that the harness ships. */\nexport const SHIPPED_NAMES: readonly [Shipped, ...Shipped[]] = Object.keys(SHIPPED) as [Shipped, ...Shipped[]];\n\n/** This image is the stock base of the Node images of the harness: Node 24.21.0 on Alpine, pinned by digest. */\nconst NODE_BASE = \"node:24.21.0-alpine@sha256:ebfe2f90462722a7a4de65e91990e97fe0d401c70e0e762c5b53302f905ec1c1\";\n\n/**\n * These are the subjects that the harness ships, by their names. `procedures` is\n * `@procedures/client` on Node: its WebSocket client (`client-ws.mjs`) and its server\n * (`server-ws.mjs`), from one image. Thus the client and the server use one release.\n */\nexport const SUBJECTS: Readonly<Record<\"procedures\", Subject>> = {\n procedures: {\n name: \"procedures\",\n image: { kind: \"shipped\", name: \"procedures\" },\n base: NODE_BASE,\n programs: {\n client: [\"node\", \"/opt/harness/procedures/client-ws.mjs\"],\n server: [\"node\", \"/opt/harness/procedures/server-ws.mjs\"],\n },\n },\n};\n\n/** This function gives the source of a shipped image. */\nconst shipped = (name: Shipped): ImageSource => ({ kind: \"shipped\", name });\n\n/**\n * These are the clients that the harness ships, by their names (`Client`): the image of each, and\n * its command. A cell that names a client gets this image and this command.\n */\nexport const SHIPPED_CLIENTS: Readonly<Record<Client, ClientImage>> = {\n tcp: { image: shipped(\"harness\"), command: [\"/opt/harness/client\"] },\n ioredis: { image: shipped(\"node\"), command: [\"node\", \"/opt/harness/node/client-ioredis.mjs\"] },\n \"go-http\": { image: shipped(\"go-http\"), command: [\"/opt/harness/client-go\"] },\n \"http-agent\": { image: shipped(\"node-http\"), command: [\"node\", \"/opt/harness/node-http/client-agent.mjs\"] },\n undici: { image: shipped(\"node-http\"), command: [\"node\", \"/opt/harness/node-http/client-undici.mjs\"] },\n mongodb: { image: shipped(\"mongo\"), command: [\"node\", \"/opt/harness/mongo/client-mongo.mjs\"] },\n pg: { image: shipped(\"pg\"), command: [\"node\", \"/opt/harness/pg/client-pg.mjs\"] },\n hikari: {\n image: shipped(\"hikari\"),\n command: [\"java\", \"-Dslf4j.internal.verbosity=ERROR\", \"-cp\", \"/opt/harness/hikari/classes:/opt/harness/hikari/lib/*\", \"ClientHikari\"],\n },\n amqp: { image: shipped(\"amqp\"), command: [\"node\", \"/opt/harness/amqp/client-amqp.mjs\"] },\n grpc: { image: shipped(\"grpc\"), command: [\"node\", \"/opt/harness/grpc/client-grpc.mjs\"] },\n \"procedures-ws\": { image: SUBJECTS.procedures.image, command: SUBJECTS.procedures.programs[\"client\"]! },\n};\n\n/** These are the names of the clients that the harness ships. */\nexport const CLIENT_NAMES: readonly [Client, ...Client[]] = Object.keys(SHIPPED_CLIENTS) as [Client, ...Client[]];\n\n/** This function gives the command of a program of a subject by its role. It fails when the subject has no such program. */\nexport const programOf = (subject: Subject, role: string): readonly string[] => {\n const program = Object.hasOwn(subject.programs, role) ? subject.programs[role] : undefined;\n if (program === undefined) throw new Error(`the subject ${subject.name} has no program ${role}`);\n return program;\n};\n\n/**\n * This function gives the client of a subject for a cell (`Cell.client`): the image of the subject,\n * with the command of a program. A client that the harness ships goes by its name, thus its records\n * stay the same.\n */\nexport const subjectClient = (subject: Subject, role = \"client\"): Client | ClientImage => {\n const client: ClientImage = { image: subject.image, command: programOf(subject, role) };\n return CLIENT_NAMES.find((name) => isDeepStrictEqual(SHIPPED_CLIENTS[name], client)) ?? client;\n};\n\n/** This pattern matches an image pinned by digest: a name, a tag or none, then `@sha256:` and 64 hex digits. */\nexport const PINNED: RegExp = /^[a-z0-9][A-Za-z0-9._\\-/:]*@sha256:[0-9a-f]{64}$/;\n/** This pattern matches the repository of a tag that the harness builds. Its parts are lower case, with `/` between them. */\nexport const REPOSITORY: RegExp = /^[a-z0-9]+(?:[._-]+[a-z0-9]+)*(?:\\/[a-z0-9]+(?:[._-]+[a-z0-9]+)*)*$/;\n\n/** This function tells if a path stays in its context: relative, with `/` between its parts, and no `..`. */\nexport const inContext = (path: string): boolean =>\n typeof path === \"string\" &&\n path.length > 0 &&\n !path.startsWith(\"/\") &&\n !path.includes(\"\\\\\") &&\n !/^[A-Za-z]:/.test(path) &&\n !path.split(\"/\").includes(\"..\");\n\n/** This function tells if a value is a command: an array of one text or more. */\nconst isCommand = (value: unknown): boolean =>\n Array.isArray(value) && value.length > 0 && value.every((word) => typeof word === \"string\" && word.length > 0);\n\n/**\n * This function gives the problems of the source of an image, as data. A pinned image names a\n * digest. A build names a repository, a context, and paths that stay in the context. A shipped image\n * is one that the harness ships.\n */\nexport const imageProblems = (source: ImageSource): string[] => {\n const kind = (source as { readonly kind?: unknown } | null)?.kind;\n if (kind === \"pinned\") {\n const { image } = source as { readonly image?: unknown };\n return typeof image === \"string\" && PINNED.test(image) ? [] : [`${String(image)} is not pinned by digest: name@sha256:<64 hex digits>`];\n }\n if (kind === \"shipped\") {\n const { name } = source as { readonly name?: unknown };\n return typeof name === \"string\" && Object.hasOwn(SHIPPED, name) ? [] : [`the harness ships no image ${String(name)}: ${SHIPPED_NAMES.join(\", \")}`];\n }\n if (kind === \"build\") {\n const build = source as Partial<BuildImage>;\n const problems: string[] = [];\n if (typeof build.name !== \"string\" || !REPOSITORY.test(build.name)) problems.push(`${String(build.name)} is not the name of a repository`);\n if (typeof build.context !== \"string\" || build.context.length === 0) problems.push(\"the build names no context\");\n if (build.files !== undefined && (!Array.isArray(build.files) || build.files.length === 0)) problems.push(\"the build names no files\");\n for (const path of [build.dockerfile ?? \"Dockerfile\", ...(Array.isArray(build.files) ? build.files : [])])\n if (!inContext(path)) problems.push(`${String(path)} is not a path in the context`);\n return problems;\n }\n return [`${JSON.stringify(kind)} is not a kind of image source: pinned, build or shipped`];\n};\n\n/**\n * This function gives the problems of a subject, as data. A subject has a name and a base that a\n * digest pins. Its image source has no problems, and each of its programs is a command.\n */\nexport const subjectProblems = (subject: Subject): string[] => {\n const programs = (subject as { readonly programs?: unknown }).programs;\n const roles = typeof programs === \"object\" && programs !== null ? Object.entries(programs) : [];\n return [\n ...(typeof subject.name === \"string\" && subject.name.length > 0 ? [] : [\"the subject has no name\"]),\n ...(typeof subject.base === \"string\" && PINNED.test(subject.base) ? [] : [`the base ${String(subject.base)} is not pinned by digest`]),\n ...imageProblems(subject.image),\n ...(roles.length === 0 ? [\"the subject has no programs\"] : []),\n ...roles.flatMap(([role, command]) => (isCommand(command) ? [] : [`the program ${role} is not a command`])),\n ];\n};\n\n/**\n * This function gives each `FROM` of a Dockerfile that no digest pins. A `FROM` of an earlier stage\n * by its name, or of `scratch`, needs no digest. A base from an `ARG` has no digest that the harness\n * can read, thus it is in the list too.\n */\nexport const unpinnedBases = (dockerfile: string): string[] => {\n const stages = new Set<string>([\"scratch\"]);\n const found: string[] = [];\n for (const line of dockerfile.replace(/\\\\\\r?\\n/g, \" \").split(/\\r?\\n/)) {\n const from = /^\\s*FROM\\s+(.+)$/i.exec(line)?.[1];\n if (from === undefined) continue;\n const [image, as, stage] = from.split(/\\s+/).filter((word) => !word.startsWith(\"--\"));\n if (image === undefined) continue;\n if (!stages.has(image.toLowerCase()) && !PINNED.test(image)) found.push(image);\n if (as?.toLowerCase() === \"as\" && stage !== undefined) stages.add(stage.toLowerCase());\n }\n return found;\n};\n\n/** These are the lockfiles of each manifest of packages. A manifest without a lockfile installs other packages each time. */\nconst LOCKFILES: Readonly<Record<string, readonly string[]>> = {\n \"package.json\": [\"package-lock.json\", \"npm-lock.json\", \"npm-shrinkwrap.json\", \"pnpm-lock.yaml\", \"yarn.lock\", \"bun.lock\"],\n \"Cargo.toml\": [\"Cargo.lock\"],\n};\n\n/**\n * This function gives each manifest of packages in a context (`package.json`, `Cargo.toml`) that\n * has no lockfile in its folder or in a folder above it. The paths are the paths in the context.\n */\nexport const unlockedManifests = (paths: readonly string[]): string[] => {\n const present = new Set(paths);\n return paths.filter((path) => {\n const parts = path.split(\"/\");\n const locks = LOCKFILES[parts.at(-1)!];\n if (locks === undefined) return false;\n for (let depth = parts.length - 1; depth >= 0; depth -= 1) {\n const folder = parts.slice(0, depth).join(\"/\");\n if (locks.some((lock) => present.has(folder === \"\" ? lock : `${folder}/${lock}`))) return false;\n }\n return true;\n });\n};\n\n/**\n * An image plan tells how the harness gets the image of a source. It is a pull of an image by its\n * name, or a build of a context. A build has its tag, its Dockerfile, and each file with its path.\n */\nexport type ImagePlan =\n | { readonly kind: \"pull\"; readonly image: string }\n | {\n readonly kind: \"build\";\n readonly tag: string;\n readonly dockerfile: string;\n readonly files: ReadonlyArray<{ readonly file: string; readonly at: string }>;\n };\n\n/** This function gives each file under a path, in a stable sequence, but not the output of a local build. */\nconst sources = (path: string): string[] => {\n if (statSync(path).isFile()) return [path];\n return readdirSync(path, { withFileTypes: true })\n .filter((entry) => entry.name !== \"target\" && entry.name !== \"node_modules\")\n .flatMap((entry) => sources(join(path, entry.name)))\n .sort();\n};\n\n/** A part is a file or a folder of a context: its path on the machine, and its path in the context. */\ninterface Part {\n readonly path: string;\n readonly at: string;\n}\n\n/** This function gives the name, the Dockerfile and the parts of the context of a build or of a shipped image. */\nconst contextOf = (source: BuildImage | ShippedImage): { name: string; dockerfile: string; parts: Part[] } => {\n if (source.kind === \"shipped\") {\n const { name, dockerfile, from } = SHIPPED[source.name];\n return { name, dockerfile, parts: from.map((part) => ({ path: pathOf(part), at: part })) };\n }\n const root = resolve(source.context);\n return {\n name: source.name,\n dockerfile: posix.normalize(source.dockerfile ?? \"Dockerfile\"),\n parts: (source.files ?? [\".\"]).map((file) => ({ path: resolve(root, file), at: file === \".\" ? \"\" : file })),\n };\n};\n\n/** This function gives a text for a source in a message. */\nconst labelOf = (source: ImageSource): string =>\n source.kind === \"pinned\" ? source.image : `the ${source.kind === \"build\" ? \"build\" : \"shipped image\"} ${source.name}`;\n\nconst shippedPlans = new Map<Shipped, ImagePlan>();\n\n/**\n * This function gives the plan of the image of a source. A stock image by its name, or a pinned\n * image, is a pull. A build or a shipped image is a build. Its tag is its name, then 12 digits of a\n * sha256. The sha256 reads the path of the Dockerfile, and the path and the content of each file.\n * Thus a changed program cannot operate as an old one.\n *\n * A build fails before it starts on a problem of its source. It also fails on a `FROM` that no\n * digest pins, and on a manifest of packages without a lockfile.\n */\nexport const planOf = (source: string | ImageSource): ImagePlan => {\n if (typeof source === \"string\") return { kind: \"pull\", image: source };\n const problems = imageProblems(source);\n if (problems.length > 0) throw new Error(`${labelOf(source)}: ${problems.join(\", \")}`);\n if (source.kind === \"pinned\") return { kind: \"pull\", image: source.image };\n const known = source.kind === \"shipped\" ? shippedPlans.get(source.name) : undefined;\n if (known !== undefined) return known;\n const { name, dockerfile, parts } = contextOf(source);\n const files = parts.flatMap((part) =>\n sources(part.path).map((file) => ({ file, at: join(part.at, relative(part.path, file)).replaceAll(\"\\\\\", \"/\") })),\n );\n const docker = files.find((each) => each.at === dockerfile);\n if (docker === undefined) throw new Error(`${labelOf(source)}: the context has no ${dockerfile}`);\n const unpinned = unpinnedBases(readFileSync(docker.file, \"utf8\"));\n const unlocked = unlockedManifests(files.map((each) => each.at));\n if (unpinned.length > 0 || unlocked.length > 0)\n throw new Error(\n `${labelOf(source)}: ${[\n ...unpinned.map((image) => `the base ${image} is not pinned by digest`),\n ...unlocked.map((path) => `${path} has no lockfile`),\n ].join(\", \")}`,\n );\n const hash = createHash(\"sha256\");\n hash.update(dockerfile);\n for (const { file, at } of files) {\n hash.update(at);\n hash.update(readFileSync(file));\n }\n const plan: ImagePlan = { kind: \"build\", tag: `${name}:${hash.digest(\"hex\").slice(0, 12)}`, dockerfile, files };\n if (source.kind === \"shipped\") shippedPlans.set(source.name, plan);\n return plan;\n};\n\n/** These counts are how many lines of the output of a failed build its error holds: its error lines, then its last lines. */\nconst BUILD_ERRORS = 10;\nconst BUILD_TAIL = 15;\n\n/**\n * This function gives the lines of the output of a failed build that its error holds. They are each\n * line that names an error, for example the diagnostic of a compiler, then the last lines.\n */\nexport const buildFailure = (output: string): string => {\n const lines = output.trim().split(/\\r?\\n/);\n const tail = lines.slice(-BUILD_TAIL);\n const errors = lines.slice(0, -BUILD_TAIL).filter((line) => /\\berror\\b/i.test(line)).slice(0, BUILD_ERRORS);\n return [...errors, ...(errors.length > 0 ? [\"...\"] : []), ...tail].join(\"\\n\");\n};\n\n/**\n * This function builds a staged context with the CLI of Docker, thus with BuildKit where the CLI has\n * it. Testcontainers reads nothing of the output of a build, and it fails with \"Failed to build\n * image\" only. The error of a failed build here holds its error lines and the end of its output.\n */\nconst dockerBuild = (context: string, plan: Extract<ImagePlan, { readonly kind: \"build\" }>): Promise<void> =>\n new Promise((resolve, reject) => {\n const args = [\"build\", \"--progress=plain\", \"--tag\", plan.tag, \"--file\", join(context, plan.dockerfile), context];\n execFile(\"docker\", args, { maxBuffer: 64 * 1024 * 1024 }, (error, _stdout, stderr) => {\n if (error === null) {\n resolve();\n return;\n }\n reject(new Error(`docker build of ${plan.tag} failed (${error.message.split(\"\\n\")[0]}):\\n${buildFailure(String(stderr))}`));\n });\n });\n\nconst built = new Map<string, Promise<string>>();\n\n/**\n * These are the waits before each next try of a build that fails, in milliseconds. A fault of a\n * registry or of the network often stops in seconds. In run 39278390448 of the cells, two runners\n * failed a build in the same second, and the same builds then passed.\n */\nexport const BUILD_WAITS: readonly number[] = [5_000, 20_000];\n\n/**\n * This function builds the image of a plan one time for each process, from a new context that it\n * copies the files into. Docker keeps its layers between runs. A build that fails tries again after\n * each wait (`waits`), and it writes each failure to stderr. A build that fails each try leaves the\n * cache. Thus a later cell builds again after a fault of Docker or of the network.\n */\nexport const buildOnce = (\n plan: Extract<ImagePlan, { readonly kind: \"build\" }>,\n builder: (context: string, plan: Extract<ImagePlan, { readonly kind: \"build\" }>) => Promise<void> = dockerBuild,\n waits: readonly number[] = BUILD_WAITS,\n): Promise<string> => {\n let tag = built.get(plan.tag);\n if (tag === undefined) {\n const building = (async () => {\n const context = mkdtempSync(join(tmpdir(), `${plan.tag.split(\":\")[0]!.replaceAll(\"/\", \"-\")}-`));\n try {\n for (const { file, at } of plan.files) {\n mkdirSync(dirname(join(context, at)), { recursive: true });\n copyFileSync(file, join(context, at));\n }\n for (let attempt = 0; ; attempt += 1) {\n try {\n await builder(context, plan);\n break;\n } catch (error) {\n const wait = waits[attempt];\n if (wait === undefined) throw error;\n process.stderr.write(`the build of ${plan.tag} failed (${error instanceof Error ? error.message : String(error)}): try ${attempt + 2} after ${wait} ms\\n`);\n await new Promise((resolve) => setTimeout(resolve, wait));\n }\n }\n } finally {\n rmSync(context, { recursive: true, force: true });\n }\n return plan.tag;\n })();\n // a failed build does not stay: the next caller tries again\n building.catch(() => {\n if (built.get(plan.tag) === building) built.delete(plan.tag);\n });\n built.set(plan.tag, building);\n tag = building;\n }\n return tag;\n};\n\n/**\n * This function gives an image that a lab can start, from its source. It is the name of a stock\n * image or of a pinned image, which the lab pulls, or the tag of a build. A build goes through the CLI\n * of Docker.\n */\nexport const imageOf = async (source: string | ImageSource): Promise<string> => {\n const plan = planOf(source);\n return plan.kind === \"pull\" ? plan.image : buildOnce(plan);\n};\n\n/** This function gives the image of the harness: the prober, the TCP client, the injector and the namespace admin. */\nexport const harnessImage = (): Promise<string> => imageOf(shipped(\"harness\"));\n/** This function gives the image of the Node client. */\nexport const nodeClientImage = (): Promise<string> => imageOf(shipped(\"node\"));\n/** This function gives the image of the router. */\nexport const routerImage = (): Promise<string> => imageOf(shipped(\"router\"));\n/** This function gives the image of the Go HTTP client. */\nexport const goHttpImage = (): Promise<string> => imageOf(shipped(\"go-http\"));\n/** This function gives the image of the Node HTTP clients. */\nexport const nodeHttpImage = (): Promise<string> => imageOf(shipped(\"node-http\"));\n/** This function gives the image of the MongoDB client. */\nexport const mongoClientImage = (): Promise<string> => imageOf(shipped(\"mongo\"));\n/** This function gives the image of the PostgreSQL client. */\nexport const pgClientImage = (): Promise<string> => imageOf(shipped(\"pg\"));\n/** This function gives the image of the client of HikariCP over pgjdbc. */\nexport const hikariClientImage = (): Promise<string> => imageOf(shipped(\"hikari\"));\n/** This function gives the image of the RabbitMQ client: amqplib, with the client and the admin of a cluster cell. */\nexport const amqpClientImage = (): Promise<string> => imageOf(shipped(\"amqp\"));\n\n/** This function gives the image of the gRPC client of the harness: grpc-js 1.14.6 on Node 24.21.0, with its client. */\nexport const grpcClientImage = (): Promise<string> => imageOf(shipped(\"grpc\"));\n/** This function gives the image of the procedures subject: the WebSocket client of `@procedures/client`, and its server. */\nexport const proceduresImage = (): Promise<string> => imageOf(SUBJECTS.procedures.image);\n\n/**\n * This function gives the source of the image that a target operates. It is the image of its\n * subject (`Target.subject`), a shipped image by its short form (`Target.harness`), or its stock image.\n */\nexport const targetSourceOf = (target: Target): string | ImageSource =>\n target.subject ?? (target.harness === undefined ? target.image : shipped(target.harness));\n\n/** This function gives the image that a target operates: the image of its subject, or its stock image. */\nexport const targetImageOf = (target: Target): Promise<string> => imageOf(targetSourceOf(target));\n"],"mappings":"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"}
|
package/build/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as
|
|
1
|
+
import { $ as Subject, A as Prediction, B as RequestPrediction, C as KernelRecord, D as MiddleboxForm, E as MiddleboxExpectation, F as Recovers, G as RunPart, H as RttRange, I as Reference, J as SentinelStage, K as RunTopology, L as ReplicaSet, M as ProxyHop, N as ProxyTime, O as Observer, P as Reconnects, Q as StageBand, R as ReplicaSetStage, S as ImageSource, T as MiddleboxEvent, U as Run, V as RouterHop, W as RunGroup, X as ShippedImage, Y as Shipped, Z as Stage, _ as Hop, a as Cluster, at as latestEndOf, b as HopSignal, c as DriverBand, d as FaultPlace, et as Target, f as Group, g as HarnessImage, h as GroupRole, i as ClientImage, it as isHopPlace, j as ProbeEvent, k as PinnedImage, l as DriverStep, m as GroupPrediction, n as Cell, nt as Toxic, o as ClusterClientAt, p as GroupPlace, q as SentinelEvent, r as Client, rt as WsProbe, s as ClusterStage, t as BuildImage, tt as Topology, u as Fault, v as HopEvent, w as LineMatch, x as HttpProbe, y as HopPlace, z as Replies } from "./cell-BxBZUssi.js";
|
|
2
2
|
import { Quantity } from "@mark1russell7/quantity";
|
|
3
3
|
import "testcontainers";
|
|
4
4
|
//#region src/application.d.ts
|
|
@@ -1089,8 +1089,8 @@ type ImagePlan = {
|
|
|
1089
1089
|
export declare const planOf: (source: string | ImageSource) => ImagePlan;
|
|
1090
1090
|
/**
|
|
1091
1091
|
* This function gives an image that a lab can start, from its source. It is the name of a stock
|
|
1092
|
-
* image or of a pinned image, which the lab pulls, or the tag of a build.
|
|
1093
|
-
*
|
|
1092
|
+
* image or of a pinned image, which the lab pulls, or the tag of a build. A build goes through the CLI
|
|
1093
|
+
* of Docker.
|
|
1094
1094
|
*/
|
|
1095
1095
|
export declare const imageOf: (source: string | ImageSource) => Promise<string>;
|
|
1096
1096
|
/** This function gives the image of the harness: the prober, the TCP client, the injector and the namespace admin. */
|
|
@@ -1627,5 +1627,5 @@ export declare const spread: (runs: number, environments: number) => number[];
|
|
|
1627
1627
|
*/
|
|
1628
1628
|
export declare const runCell: (cell: Cell, say?: (line: string) => void) => Promise<CellResult>;
|
|
1629
1629
|
//#endregion
|
|
1630
|
-
export { type Agent, type BuildImage, type CallReading, type Cell, type CellResult, type Client, type ClientImage, type Cluster, type ClusterClientAt, type ClusterLab, type ClusterStage, type Crossings, type Cut, type Decision, type DriverBand, type DriverSocket, type DriverStep, type DriverStepTime, type ErrorOnTheWay, type Fault, type FaultPlace, type FaultSide, type Group, type GroupClient, type GroupLab, type GroupMeasured, type GroupNetworkFault, type GroupPlace, type GroupPrediction, type GroupReading, type GroupRole, type GroupVerdict, type GroupView, type HarnessImage, type Hop, type HopEvent, type HopPlace, type HttpProbe, type ImagePlan, type ImageSource, type Interval, type KernelRecord, type Lab, type LineMatch, type Manifest, type ManifestHop, type Measured, type MemberLine, type MiddleboxEvent, type MiddleboxExpectation, type MiddleboxForm, type NetworkFault, type NodeLine, type Observer, type Outcome, type PinnedImage, type Prediction, type Probe, type ProbeEvent, type ProgramEvent, type ProxyHop, type ProxyTime, type ReconnectReading, type ReconnectVerdict, type Reconnects, type Recovers, type Reference, type Reordering, type ReplicaSet, type ReplicaSetLab, type ReplicaSetStage, type Replies, type RequestPrediction, type RequestReading, type RouterHop, type RttRange, type Run, type RunGroup, type RunPart, type RunTopology, type SentinelEvent, type SentinelStage, type Shipped, type ShippedImage, type SocketPlace, type Spread, type Stage, type StageBand, type StageVerdict, type Stamp, type Status, type StatusRow, type Subject, type Target, type Topology, type Toxic, type Verdict, type WallStamp, type Writes, type WsProbe, isHopPlace, latestEndOf };
|
|
1630
|
+
export { type Agent, type BuildImage, type CallReading, type Cell, type CellResult, type Client, type ClientImage, type Cluster, type ClusterClientAt, type ClusterLab, type ClusterStage, type Crossings, type Cut, type Decision, type DriverBand, type DriverSocket, type DriverStep, type DriverStepTime, type ErrorOnTheWay, type Fault, type FaultPlace, type FaultSide, type Group, type GroupClient, type GroupLab, type GroupMeasured, type GroupNetworkFault, type GroupPlace, type GroupPrediction, type GroupReading, type GroupRole, type GroupVerdict, type GroupView, type HarnessImage, type Hop, type HopEvent, type HopPlace, type HopSignal, type HttpProbe, type ImagePlan, type ImageSource, type Interval, type KernelRecord, type Lab, type LineMatch, type Manifest, type ManifestHop, type Measured, type MemberLine, type MiddleboxEvent, type MiddleboxExpectation, type MiddleboxForm, type NetworkFault, type NodeLine, type Observer, type Outcome, type PinnedImage, type Prediction, type Probe, type ProbeEvent, type ProgramEvent, type ProxyHop, type ProxyTime, type ReconnectReading, type ReconnectVerdict, type Reconnects, type Recovers, type Reference, type Reordering, type ReplicaSet, type ReplicaSetLab, type ReplicaSetStage, type Replies, type RequestPrediction, type RequestReading, type RouterHop, type RttRange, type Run, type RunGroup, type RunPart, type RunTopology, type SentinelEvent, type SentinelStage, type Shipped, type ShippedImage, type SocketPlace, type Spread, type Stage, type StageBand, type StageVerdict, type Stamp, type Status, type StatusRow, type Subject, type Target, type Topology, type Toxic, type Verdict, type WallStamp, type Writes, type WsProbe, isHopPlace, latestEndOf };
|
|
1631
1631
|
//# sourceMappingURL=index.d.ts.map
|
package/build/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as subjectClient, D as unlockedManifests, E as targetSourceOf, O as unpinnedBases, S as routerImage, T as targetImageOf, _ as nodeHttpImage, a as SHIPPED_NAMES, b as proceduresImage, c as goHttpImage, d as hikariClientImage, f as imageOf, g as nodeClientImage, h as mongoClientImage, i as SHIPPED_CLIENTS, l as grpcClientImage, m as inContext, n as PINNED, o as SUBJECTS, p as imageProblems, r as REPOSITORY, s as amqpClientImage, t as CLIENT_NAMES, u as harnessImage, v as pgClientImage, w as subjectProblems, x as programOf, y as planOf } from "./image-
|
|
1
|
+
import { C as subjectClient, D as unlockedManifests, E as targetSourceOf, O as unpinnedBases, S as routerImage, T as targetImageOf, _ as nodeHttpImage, a as SHIPPED_NAMES, b as proceduresImage, c as goHttpImage, d as hikariClientImage, f as imageOf, g as nodeClientImage, h as mongoClientImage, i as SHIPPED_CLIENTS, l as grpcClientImage, m as inContext, n as PINNED, o as SUBJECTS, p as imageProblems, r as REPOSITORY, s as amqpClientImage, t as CLIENT_NAMES, u as harnessImage, v as pgClientImage, w as subjectProblems, x as programOf, y as planOf } from "./image-vB51btI1.js";
|
|
2
2
|
import { quantity, valueIn } from "@mark1russell7/quantity";
|
|
3
3
|
import { createHash } from "node:crypto";
|
|
4
4
|
//#region src/cell.ts
|