@mark1russell7/harness 0.11.3 → 0.11.4

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 CHANGED
@@ -159,6 +159,9 @@ The harness ships eight images, each as a shipped source (`ImageSource`). The ta
159
159
  - **The Go HTTP image** (`image/go-http`) is the `http.Transport` of Go 1.27.2 at its defaults (`client-go`). The program uses the standard library only, thus the digest of the Go builder pins all of its code. The build does `gofmt` and `go vet` first. A wrapper on each connection writes what the read loop of the transport reads. The trace of the transport writes each try of a request.
160
160
  - **The Node HTTP image** (`image/node-http`) holds the `http.Agent` of Node 24.21.0 (`client-agent.mjs`) and an HTTP/1.1 `Client` of undici 8.12.2 (`client-undici.mjs`). The digest of the image and an npm lockfile pin them. It is apart from the image of ioredis, thus the cells of ioredis keep their image.
161
161
  - **The PostgreSQL client image** (`image/pg`) is node-postgres: pg 8.23.1 with pg-pool 3.14.0 on Node 24.21.0. The digest of the image and an npm lockfile pin them. `client-pg.mjs` makes one `pg.Pool` with the options of the cell (`Cell.driverOptions`), and it prints the lines of the TCP client on the same clock. The first query makes the connection, and the reply gives the client back to the pool, where it is idle. An error of the pool for that idle client is the detection of an idle cell. The probe is `{ driver: { name: "pg", query } }`, with `SELECT 1` as the query when the cell gives none.
162
+ - **The HikariCP client image** (`image/hikari`) is HikariCP 7.1.0 over pgjdbc 42.7.13 on Temurin 21.0.12.1. The digests of the two stages and the SHA-256 of each jar pin them. The probe is `{ driver: { name: "hikari", query } }`.
163
+ - `ClientHikari.java` makes one `HikariDataSource` with the properties of the cell (`Cell.driverOptions`). A name with the prefix `dataSource.` is a property of pgjdbc.
164
+ - It prints the lines of the pg client on the same clock. Each socket comes from the `PGStream` of its connection, and a `pool` line gives each change of the counts of the pool. The errno of a failure is the SQLState of pgjdbc.
162
165
  - **The MongoDB client image** (`image/mongo`) is the driver mongodb 7.7.0 on Node 24.21.0. The digest of the image and an npm lockfile pin them. `client-mongo.mjs` prints the lines of the TCP client on the same clock:
163
166
  - Each socket of the driver is a `socket` line with its role: `monitor`, `rtt` or `pool`. The stack of the call that makes the socket gives the role.
164
167
  - The events of the driver are `sdam` lines (the heartbeats and the changes of each server), `cmap` lines (the pools) and `command` lines (each try of an operation).
@@ -573,7 +573,7 @@ type HarnessImage = "procedures";
573
573
  * A shipped image is an image that the harness ships, by its name. Its build context is in the
574
574
  * package of the harness, and in the package of the prober for `harness`.
575
575
  */
576
- type Shipped = "harness" | "node" | "go-http" | "node-http" | "mongo" | "pg" | "procedures" | "router";
576
+ type Shipped = "harness" | "node" | "go-http" | "node-http" | "mongo" | "pg" | "hikari" | "procedures" | "router";
577
577
  /**
578
578
  * An image source tells where an image comes from, as data. The harness resolves each kind to an
579
579
  * image that it can start:
@@ -629,10 +629,10 @@ interface Subject {
629
629
  /**
630
630
  * A client is what the runs of a cell use: the TCP client of the harness, or a driver on its
631
631
  * socket. The HTTP clients are the `http.Transport` of Go (`go-http`), the `http.Agent` of Node
632
- * (`http-agent`) and an HTTP/1.1 `Client` of undici (`undici`). The MongoDB driver is `mongodb`, node-postgres is `pg`, and
632
+ * (`http-agent`) and an HTTP/1.1 `Client` of undici (`undici`). The MongoDB driver is `mongodb`, node-postgres is `pg`, HikariCP over pgjdbc is `hikari`, and
633
633
  * the WebSocket client of `@procedures/client` is `procedures-ws`.
634
634
  */
635
- type Client = "tcp" | "ioredis" | "go-http" | "http-agent" | "undici" | "mongodb" | "pg" | "procedures-ws";
635
+ type Client = "tcp" | "ioredis" | "go-http" | "http-agent" | "undici" | "mongodb" | "pg" | "hikari" | "procedures-ws";
636
636
  /**
637
637
  * A WebSocket probe is the workload and the settings of the WebSocket client of
638
638
  * `@procedures/client` (`procedures-ws`). The cell gives each setting, thus the client takes
@@ -749,6 +749,9 @@ interface Cell {
749
749
  * the read of a long document (`read-long`). `Cell.driverOptions` are its options.
750
750
  * - node-postgres on Node, as a `pg.Pool` against one server. Its operation is `query`, or
751
751
  * `SELECT 1`. `Cell.driverOptions` are the options of its pool.
752
+ * - HikariCP over pgjdbc on Java, as a `HikariDataSource` against one server. Its operation is
753
+ * `query`, or `SELECT 1`. `Cell.driverOptions` are the properties of HikariConfig, and a name
754
+ * with the prefix `dataSource.` is a property of pgjdbc.
752
755
  */
753
756
  readonly driver?: {
754
757
  readonly name: "ioredis";
@@ -760,6 +763,9 @@ interface Cell {
760
763
  } | {
761
764
  readonly name: "pg";
762
765
  readonly query?: string;
766
+ } | {
767
+ readonly name: "hikari";
768
+ readonly query?: string;
763
769
  };
764
770
  /** This workload is the workload of an HTTP client (`Cell.client` is an HTTP client). The client then ignores `keepalive` and `userTimeout`. */
765
771
  readonly http?: HttpProbe;
@@ -990,4 +996,4 @@ interface RunTopology {
990
996
  }
991
997
  //#endregion
992
998
  export { isHopPlace as $, Recovers as A, RunPart as B, Observer as C, ProxyHop as D, ProbeEvent as E, RequestPrediction as F, ShippedImage as G, SentinelEvent as H, RouterHop as I, Subject as J, Stage as K, RttRange as L, ReplicaSet as M, ReplicaSetStage as N, ProxyTime as O, Replies as P, WsProbe as Q, Run as R, MiddleboxForm as S, Prediction as T, SentinelStage as U, RunTopology as V, Shipped as W, Topology as X, Target as Y, Toxic as Z, ImageSource as _, DriverBand as a, MiddleboxEvent as b, FaultPlace as c, GroupPrediction as d, latestEndOf as et, GroupRole as f, HttpProbe as g, HopPlace as h, ClientImage as i, Reference as j, Reconnects as k, Group as l, Hop as m, Cell as n, DriverStep as o, HarnessImage as p, StageBand as q, Client as r, Fault as s, BuildImage as t, GroupPlace as u, KernelRecord as v, PinnedImage as w, MiddleboxExpectation as x, LineMatch as y, RunGroup as z };
993
- //# sourceMappingURL=cell-BmSnJJtn.d.ts.map
999
+ //# sourceMappingURL=cell-Di_YHiuB.d.ts.map
@@ -67,6 +67,11 @@ const SHIPPED = {
67
67
  dockerfile: "harness/image/pg/Dockerfile",
68
68
  from: ["harness/image/pg"]
69
69
  },
70
+ hikari: {
71
+ name: "loom-harness-hikari",
72
+ dockerfile: "harness/image/hikari/Dockerfile",
73
+ from: ["harness/image/hikari"]
74
+ },
70
75
  procedures: {
71
76
  name: "loom-harness-procedures",
72
77
  dockerfile: "harness/image/procedures/Dockerfile",
@@ -135,6 +140,16 @@ const SHIPPED_CLIENTS = {
135
140
  image: shipped("pg"),
136
141
  command: ["node", "/opt/harness/pg/client-pg.mjs"]
137
142
  },
143
+ hikari: {
144
+ image: shipped("hikari"),
145
+ command: [
146
+ "java",
147
+ "-Dslf4j.internal.verbosity=ERROR",
148
+ "-cp",
149
+ "/opt/harness/hikari/classes:/opt/harness/hikari/lib/*",
150
+ "ClientHikari"
151
+ ]
152
+ },
138
153
  "procedures-ws": {
139
154
  image: SUBJECTS.procedures.image,
140
155
  command: SUBJECTS.procedures.programs["client"]
@@ -395,6 +410,8 @@ const nodeHttpImage = () => imageOf(shipped("node-http"));
395
410
  const mongoClientImage = () => imageOf(shipped("mongo"));
396
411
  /** This function gives the image of the PostgreSQL client. */
397
412
  const pgClientImage = () => imageOf(shipped("pg"));
413
+ /** This function gives the image of the client of HikariCP over pgjdbc. */
414
+ const hikariClientImage = () => imageOf(shipped("hikari"));
398
415
  /** This function gives the image of the procedures subject: the WebSocket client of `@procedures/client`, and its server. */
399
416
  const proceduresImage = () => imageOf(SUBJECTS.procedures.image);
400
417
  /**
@@ -405,6 +422,6 @@ const targetSourceOf = (target) => target.subject ?? (target.harness === void 0
405
422
  /** This function gives the image that a target operates: the image of its subject, or its stock image. */
406
423
  const targetImageOf = (target) => imageOf(targetSourceOf(target));
407
424
  //#endregion
408
- export { targetSourceOf as C, targetImageOf as S, unpinnedBases as T, proceduresImage as _, SHIPPED_NAMES as a, subjectClient as b, harnessImage as c, inContext as d, mongoClientImage as f, planOf as g, pgClientImage as h, SHIPPED_CLIENTS as i, imageOf as l, nodeHttpImage as m, PINNED as n, SUBJECTS as o, nodeClientImage as p, REPOSITORY as r, goHttpImage as s, CLIENT_NAMES as t, imageProblems as u, programOf as v, unlockedManifests as w, subjectProblems as x, routerImage as y };
425
+ export { targetImageOf as C, unpinnedBases as E, subjectProblems as S, unlockedManifests as T, planOf as _, SHIPPED_NAMES as a, routerImage as b, harnessImage as c, imageProblems as d, inContext as f, pgClientImage as g, nodeHttpImage as h, SHIPPED_CLIENTS as i, hikariClientImage as l, nodeClientImage as m, PINNED as n, SUBJECTS as o, mongoClientImage as p, REPOSITORY as r, goHttpImage as s, CLIENT_NAMES as t, imageOf as u, proceduresImage as v, targetSourceOf as w, subjectClient as x, programOf as y };
409
426
 
410
- //# sourceMappingURL=image-Q_fs3rCC.js.map
427
+ //# sourceMappingURL=image-BfuXg-5t.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-BfuXg-5t.js","names":[],"sources":["../src/image.ts"],"sourcesContent":["import { 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 // @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};\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 \"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/** This function builds a staged context with Docker, through Testcontainers. */\nconst dockerBuild = async (context: string, plan: Extract<ImagePlan, { readonly kind: \"build\" }>): Promise<void> => {\n const { GenericContainer } = await import(\"testcontainers\");\n await GenericContainer.fromDockerfile(context, plan.dockerfile).build(plan.tag, { deleteOnExit: false });\n};\n\nconst built = new Map<string, Promise<string>>();\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 leaves the cache.\n * 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): 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 await builder(context, plan);\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. This function loads\n * Testcontainers only for a build.\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 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 isHopPlace, A as Recovers, B as RunPart, C as Observer, D as ProxyHop, E as ProbeEvent, F as RequestPrediction, G as ShippedImage, H as SentinelEvent, I as RouterHop, J as Subject, K as Stage, L as RttRange, M as ReplicaSet, N as ReplicaSetStage, O as ProxyTime, P as Replies, Q as WsProbe, R as Run, S as MiddleboxForm, T as Prediction, U as SentinelStage, V as RunTopology, W as Shipped, X as Topology, Y as Target, Z as Toxic, _ as ImageSource, a as DriverBand, b as MiddleboxEvent, c as FaultPlace, d as GroupPrediction, et as latestEndOf, f as GroupRole, g as HttpProbe, h as HopPlace, i as ClientImage, j as Reference, k as Reconnects, l as Group, m as Hop, n as Cell, o as DriverStep, p as HarnessImage, q as StageBand, r as Client, s as Fault, t as BuildImage, u as GroupPlace, v as KernelRecord, w as PinnedImage, x as MiddleboxExpectation, y as LineMatch, z as RunGroup } from "./cell-BmSnJJtn.js";
1
+ import { $ as isHopPlace, A as Recovers, B as RunPart, C as Observer, D as ProxyHop, E as ProbeEvent, F as RequestPrediction, G as ShippedImage, H as SentinelEvent, I as RouterHop, J as Subject, K as Stage, L as RttRange, M as ReplicaSet, N as ReplicaSetStage, O as ProxyTime, P as Replies, Q as WsProbe, R as Run, S as MiddleboxForm, T as Prediction, U as SentinelStage, V as RunTopology, W as Shipped, X as Topology, Y as Target, Z as Toxic, _ as ImageSource, a as DriverBand, b as MiddleboxEvent, c as FaultPlace, d as GroupPrediction, et as latestEndOf, f as GroupRole, g as HttpProbe, h as HopPlace, i as ClientImage, j as Reference, k as Reconnects, l as Group, m as Hop, n as Cell, o as DriverStep, p as HarnessImage, q as StageBand, r as Client, s as Fault, t as BuildImage, u as GroupPlace, v as KernelRecord, w as PinnedImage, x as MiddleboxExpectation, y as LineMatch, z as RunGroup } from "./cell-Di_YHiuB.js";
2
2
  import { Quantity } from "@mark1russell7/quantity";
3
3
  import "testcontainers";
4
4
  //#region src/application.d.ts
@@ -1063,6 +1063,8 @@ export declare const nodeHttpImage: () => Promise<string>;
1063
1063
  export declare const mongoClientImage: () => Promise<string>;
1064
1064
  /** This function gives the image of the PostgreSQL client. */
1065
1065
  export declare const pgClientImage: () => Promise<string>;
1066
+ /** This function gives the image of the client of HikariCP over pgjdbc. */
1067
+ export declare const hikariClientImage: () => Promise<string>;
1066
1068
  /** This function gives the image of the procedures subject: the WebSocket client of `@procedures/client`, and its server. */
1067
1069
  export declare const proceduresImage: () => Promise<string>;
1068
1070
  /**
package/build/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { C as targetSourceOf, S as targetImageOf, T as unpinnedBases, _ as proceduresImage, a as SHIPPED_NAMES, b as subjectClient, c as harnessImage, d as inContext, f as mongoClientImage, g as planOf, h as pgClientImage, i as SHIPPED_CLIENTS, l as imageOf, m as nodeHttpImage, n as PINNED, o as SUBJECTS, p as nodeClientImage, r as REPOSITORY, s as goHttpImage, t as CLIENT_NAMES, u as imageProblems, v as programOf, w as unlockedManifests, x as subjectProblems, y as routerImage } from "./image-Q_fs3rCC.js";
1
+ import { C as targetImageOf, E as unpinnedBases, S as subjectProblems, T as unlockedManifests, _ as planOf, a as SHIPPED_NAMES, b as routerImage, c as harnessImage, d as imageProblems, f as inContext, g as pgClientImage, h as nodeHttpImage, i as SHIPPED_CLIENTS, l as hikariClientImage, m as nodeClientImage, n as PINNED, o as SUBJECTS, p as mongoClientImage, r as REPOSITORY, s as goHttpImage, t as CLIENT_NAMES, u as imageOf, v as proceduresImage, w as targetSourceOf, x as subjectClient, y as programOf } from "./image-BfuXg-5t.js";
2
2
  import { quantity, valueIn } from "@mark1russell7/quantity";
3
3
  import { createHash } from "node:crypto";
4
4
  //#region src/cell.ts
@@ -4078,7 +4078,7 @@ const probeArgs = (cell, lab) => {
4078
4078
  args.push("--max-s", String(Math.ceil(longest * 2 + 10)));
4079
4079
  return args;
4080
4080
  }
4081
- if (probe.driver?.name === "pg") {
4081
+ if (probe.driver?.name === "pg" || probe.driver?.name === "hikari") {
4082
4082
  if (probe.driver.query !== void 0) args.push("--query", probe.driver.query);
4083
4083
  if (cell.before === true) args.push("--before");
4084
4084
  if (cell.driverOptions !== void 0) args.push("--options", JSON.stringify(cell.driverOptions));
@@ -4612,6 +4612,6 @@ const runCell = async (cell, say = () => {}) => {
4612
4612
  }
4613
4613
  };
4614
4614
  //#endregion
4615
- export { CLIENT_NAMES, CONVERGE_MS, INJECT, KEPT, LINGER_MS, LISTING, MEMBER_MARKS, NOISE, PINNED, PUMP, QUIET_MS, RELATIVE, REPLICA_SET_STAGES, REPOSITORY, SHIPPED_CLIENTS, SHIPPED_NAMES, STAGES, STATUS_SCRIPT, STEPS, STEP_DOWN, SUBJECTS, callOf, clockOffsetOf, closeOrExit, crossingsOf, cutOf, deadlineOf, delayVoids, deviceOf, dropFinding, dropOf, endpointAfter, errorsOf, exitOf, fieldOf, fieldsOf, firstUnanswered, goHttpImage, groupOnce, groupVerdictOf, harnessImage, hzOf, imageOf, imageProblems, inContext, infoOf, initiateScript, isHopPlace, judge, lagsOf, latestEndOf, leftAfter, matches, measure, measureDriver, measureGroup, medianInterval, memberCommand, memberConfig, memberLineOf, mongoClientImage, nodeClientImage, nodeHttpImage, noiseOf, onMonotonic, openGroupLab, openLab, openReplicaSetLab, peersOf, pgClientImage, pingsOf, planOf, proceduresImage, programLines, programOf, quantileOf, reconnectFinding, reconnectOf, referenceOf, reorderingOf, replicaSetArgs, replicaSetOnce, replicaSetStagesOf, requestOf, requestWords, routerImage, routesOf, runCell, sentinelConfig, socketAt, socketOf, socketsOf, spread, spreadOf, stagesOf, statusViewOf, subjectClient, subjectProblems, subscriptionsOf, targetImageOf, targetSourceOf, templated, toxicBody, unlockedManifests, unpinnedBases, verdictOf, viewOf, writesOf };
4615
+ export { CLIENT_NAMES, CONVERGE_MS, INJECT, KEPT, LINGER_MS, LISTING, MEMBER_MARKS, NOISE, PINNED, PUMP, QUIET_MS, RELATIVE, REPLICA_SET_STAGES, REPOSITORY, SHIPPED_CLIENTS, SHIPPED_NAMES, STAGES, STATUS_SCRIPT, STEPS, STEP_DOWN, SUBJECTS, callOf, clockOffsetOf, closeOrExit, crossingsOf, cutOf, deadlineOf, delayVoids, deviceOf, dropFinding, dropOf, endpointAfter, errorsOf, exitOf, fieldOf, fieldsOf, firstUnanswered, goHttpImage, groupOnce, groupVerdictOf, harnessImage, hikariClientImage, hzOf, imageOf, imageProblems, inContext, infoOf, initiateScript, isHopPlace, judge, lagsOf, latestEndOf, leftAfter, matches, measure, measureDriver, measureGroup, medianInterval, memberCommand, memberConfig, memberLineOf, mongoClientImage, nodeClientImage, nodeHttpImage, noiseOf, onMonotonic, openGroupLab, openLab, openReplicaSetLab, peersOf, pgClientImage, pingsOf, planOf, proceduresImage, programLines, programOf, quantileOf, reconnectFinding, reconnectOf, referenceOf, reorderingOf, replicaSetArgs, replicaSetOnce, replicaSetStagesOf, requestOf, requestWords, routerImage, routesOf, runCell, sentinelConfig, socketAt, socketOf, socketsOf, spread, spreadOf, stagesOf, statusViewOf, subjectClient, subjectProblems, subscriptionsOf, targetImageOf, targetSourceOf, templated, toxicBody, unlockedManifests, unpinnedBases, verdictOf, viewOf, writesOf };
4616
4616
 
4617
4617
  //# sourceMappingURL=index.js.map