rightsize 0.1.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/LICENSE +202 -0
- package/NOTICE +4 -0
- package/README.md +255 -0
- package/dist/backend-docker/backend.d.ts +53 -0
- package/dist/backend-docker/backend.d.ts.map +1 -0
- package/dist/backend-docker/backend.js +336 -0
- package/dist/backend-docker/backend.js.map +1 -0
- package/dist/backend-docker/client.d.ts +82 -0
- package/dist/backend-docker/client.d.ts.map +1 -0
- package/dist/backend-docker/client.js +190 -0
- package/dist/backend-docker/client.js.map +1 -0
- package/dist/backend-docker/frames.d.ts +44 -0
- package/dist/backend-docker/frames.d.ts.map +1 -0
- package/dist/backend-docker/frames.js +105 -0
- package/dist/backend-docker/frames.js.map +1 -0
- package/dist/backend-docker/index.d.ts +5 -0
- package/dist/backend-docker/index.d.ts.map +1 -0
- package/dist/backend-docker/index.js +20 -0
- package/dist/backend-docker/index.js.map +1 -0
- package/dist/backend-docker/json.d.ts +13 -0
- package/dist/backend-docker/json.d.ts.map +1 -0
- package/dist/backend-docker/json.js +47 -0
- package/dist/backend-docker/json.js.map +1 -0
- package/dist/backend-docker/labels.d.ts +11 -0
- package/dist/backend-docker/labels.d.ts.map +1 -0
- package/dist/backend-docker/labels.js +13 -0
- package/dist/backend-docker/labels.js.map +1 -0
- package/dist/backend-docker/port-conflict.d.ts +9 -0
- package/dist/backend-docker/port-conflict.d.ts.map +1 -0
- package/dist/backend-docker/port-conflict.js +12 -0
- package/dist/backend-docker/port-conflict.js.map +1 -0
- package/dist/backend-docker/provider.d.ts +22 -0
- package/dist/backend-docker/provider.d.ts.map +1 -0
- package/dist/backend-docker/provider.js +36 -0
- package/dist/backend-docker/provider.js.map +1 -0
- package/dist/backend-msb/backend.d.ts +169 -0
- package/dist/backend-msb/backend.d.ts.map +1 -0
- package/dist/backend-msb/backend.js +664 -0
- package/dist/backend-msb/backend.js.map +1 -0
- package/dist/backend-msb/commands.d.ts +28 -0
- package/dist/backend-msb/commands.d.ts.map +1 -0
- package/dist/backend-msb/commands.js +67 -0
- package/dist/backend-msb/commands.js.map +1 -0
- package/dist/backend-msb/exec-tunnel.d.ts +33 -0
- package/dist/backend-msb/exec-tunnel.d.ts.map +1 -0
- package/dist/backend-msb/exec-tunnel.js +163 -0
- package/dist/backend-msb/exec-tunnel.js.map +1 -0
- package/dist/backend-msb/follow-replay.d.ts +14 -0
- package/dist/backend-msb/follow-replay.d.ts.map +1 -0
- package/dist/backend-msb/follow-replay.js +20 -0
- package/dist/backend-msb/follow-replay.js.map +1 -0
- package/dist/backend-msb/image-cache.d.ts +25 -0
- package/dist/backend-msb/image-cache.d.ts.map +1 -0
- package/dist/backend-msb/image-cache.js +27 -0
- package/dist/backend-msb/image-cache.js.map +1 -0
- package/dist/backend-msb/index.d.ts +6 -0
- package/dist/backend-msb/index.d.ts.map +1 -0
- package/dist/backend-msb/index.js +21 -0
- package/dist/backend-msb/index.js.map +1 -0
- package/dist/backend-msb/invoke.d.ts +24 -0
- package/dist/backend-msb/invoke.d.ts.map +1 -0
- package/dist/backend-msb/invoke.js +73 -0
- package/dist/backend-msb/invoke.js.map +1 -0
- package/dist/backend-msb/ls-json.d.ts +23 -0
- package/dist/backend-msb/ls-json.d.ts.map +1 -0
- package/dist/backend-msb/ls-json.js +113 -0
- package/dist/backend-msb/ls-json.js.map +1 -0
- package/dist/backend-msb/network-links.d.ts +7 -0
- package/dist/backend-msb/network-links.d.ts.map +1 -0
- package/dist/backend-msb/network-links.js +31 -0
- package/dist/backend-msb/network-links.js.map +1 -0
- package/dist/backend-msb/platform.d.ts +29 -0
- package/dist/backend-msb/platform.d.ts.map +1 -0
- package/dist/backend-msb/platform.js +128 -0
- package/dist/backend-msb/platform.js.map +1 -0
- package/dist/backend-msb/port-conflict.d.ts +10 -0
- package/dist/backend-msb/port-conflict.d.ts.map +1 -0
- package/dist/backend-msb/port-conflict.js +16 -0
- package/dist/backend-msb/port-conflict.js.map +1 -0
- package/dist/backend-msb/provider.d.ts +10 -0
- package/dist/backend-msb/provider.d.ts.map +1 -0
- package/dist/backend-msb/provider.js +40 -0
- package/dist/backend-msb/provider.js.map +1 -0
- package/dist/backend-msb/provisioner.d.ts +19 -0
- package/dist/backend-msb/provisioner.d.ts.map +1 -0
- package/dist/backend-msb/provisioner.js +332 -0
- package/dist/backend-msb/provisioner.js.map +1 -0
- package/dist/backend-msb/reaper.d.ts +10 -0
- package/dist/backend-msb/reaper.d.ts.map +1 -0
- package/dist/backend-msb/reaper.js +73 -0
- package/dist/backend-msb/reaper.js.map +1 -0
- package/dist/core/backend.d.ts +98 -0
- package/dist/core/backend.d.ts.map +1 -0
- package/dist/core/backend.js +2 -0
- package/dist/core/backend.js.map +1 -0
- package/dist/core/backends.d.ts +37 -0
- package/dist/core/backends.d.ts.map +1 -0
- package/dist/core/backends.js +127 -0
- package/dist/core/backends.js.map +1 -0
- package/dist/core/cleanup.d.ts +37 -0
- package/dist/core/cleanup.d.ts.map +1 -0
- package/dist/core/cleanup.js +86 -0
- package/dist/core/cleanup.js.map +1 -0
- package/dist/core/errors.d.ts +51 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +66 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/free-ports.d.ts +23 -0
- package/dist/core/free-ports.d.ts.map +1 -0
- package/dist/core/free-ports.js +63 -0
- package/dist/core/free-ports.js.map +1 -0
- package/dist/core/generic-container.d.ts +145 -0
- package/dist/core/generic-container.d.ts.map +1 -0
- package/dist/core/generic-container.js +385 -0
- package/dist/core/generic-container.js.map +1 -0
- package/dist/core/model.d.ts +60 -0
- package/dist/core/model.d.ts.map +1 -0
- package/dist/core/model.js +2 -0
- package/dist/core/model.js.map +1 -0
- package/dist/core/mountable-file.d.ts +25 -0
- package/dist/core/mountable-file.d.ts.map +1 -0
- package/dist/core/mountable-file.js +64 -0
- package/dist/core/mountable-file.js.map +1 -0
- package/dist/core/network.d.ts +58 -0
- package/dist/core/network.d.ts.map +1 -0
- package/dist/core/network.js +84 -0
- package/dist/core/network.js.map +1 -0
- package/dist/core/run-id.d.ts +18 -0
- package/dist/core/run-id.d.ts.map +1 -0
- package/dist/core/run-id.js +18 -0
- package/dist/core/run-id.js.map +1 -0
- package/dist/core/wait.d.ts +59 -0
- package/dist/core/wait.d.ts.map +1 -0
- package/dist/core/wait.js +239 -0
- package/dist/core/wait.js.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/modules/arango.d.ts +14 -0
- package/dist/modules/arango.d.ts.map +1 -0
- package/dist/modules/arango.js +37 -0
- package/dist/modules/arango.js.map +1 -0
- package/dist/modules/clickhouse.d.ts +37 -0
- package/dist/modules/clickhouse.d.ts.map +1 -0
- package/dist/modules/clickhouse.js +69 -0
- package/dist/modules/clickhouse.js.map +1 -0
- package/dist/modules/flink.d.ts +65 -0
- package/dist/modules/flink.d.ts.map +1 -0
- package/dist/modules/flink.js +125 -0
- package/dist/modules/flink.js.map +1 -0
- package/dist/modules/floci.d.ts +46 -0
- package/dist/modules/floci.d.ts.map +1 -0
- package/dist/modules/floci.js +62 -0
- package/dist/modules/floci.js.map +1 -0
- package/dist/modules/index.d.ts +31 -0
- package/dist/modules/index.d.ts.map +1 -0
- package/dist/modules/index.js +31 -0
- package/dist/modules/index.js.map +1 -0
- package/dist/modules/kafka.d.ts +11 -0
- package/dist/modules/kafka.d.ts.map +1 -0
- package/dist/modules/kafka.js +41 -0
- package/dist/modules/kafka.js.map +1 -0
- package/dist/modules/keycloak.d.ts +40 -0
- package/dist/modules/keycloak.d.ts.map +1 -0
- package/dist/modules/keycloak.js +67 -0
- package/dist/modules/keycloak.js.map +1 -0
- package/dist/modules/mariadb.d.ts +56 -0
- package/dist/modules/mariadb.d.ts.map +1 -0
- package/dist/modules/mariadb.js +89 -0
- package/dist/modules/mariadb.js.map +1 -0
- package/dist/modules/memcached.d.ts +24 -0
- package/dist/modules/memcached.d.ts.map +1 -0
- package/dist/modules/memcached.js +105 -0
- package/dist/modules/memcached.js.map +1 -0
- package/dist/modules/mongodb.d.ts +19 -0
- package/dist/modules/mongodb.d.ts.map +1 -0
- package/dist/modules/mongodb.js +69 -0
- package/dist/modules/mongodb.js.map +1 -0
- package/dist/modules/mysql.d.ts +61 -0
- package/dist/modules/mysql.d.ts.map +1 -0
- package/dist/modules/mysql.js +101 -0
- package/dist/modules/mysql.js.map +1 -0
- package/dist/modules/neo4j.d.ts +60 -0
- package/dist/modules/neo4j.d.ts.map +1 -0
- package/dist/modules/neo4j.js +83 -0
- package/dist/modules/neo4j.js.map +1 -0
- package/dist/modules/pinot.d.ts +30 -0
- package/dist/modules/pinot.d.ts.map +1 -0
- package/dist/modules/pinot.js +49 -0
- package/dist/modules/pinot.js.map +1 -0
- package/dist/modules/postgres.d.ts +29 -0
- package/dist/modules/postgres.d.ts.map +1 -0
- package/dist/modules/postgres.js +73 -0
- package/dist/modules/postgres.js.map +1 -0
- package/dist/modules/rabbitmq.d.ts +46 -0
- package/dist/modules/rabbitmq.d.ts.map +1 -0
- package/dist/modules/rabbitmq.js +68 -0
- package/dist/modules/rabbitmq.js.map +1 -0
- package/dist/modules/redis.d.ts +15 -0
- package/dist/modules/redis.d.ts.map +1 -0
- package/dist/modules/redis.js +24 -0
- package/dist/modules/redis.js.map +1 -0
- package/dist/modules/redpanda.d.ts +27 -0
- package/dist/modules/redpanda.d.ts.map +1 -0
- package/dist/modules/redpanda.js +58 -0
- package/dist/modules/redpanda.js.map +1 -0
- package/dist/modules/spring-cloud-config.d.ts +18 -0
- package/dist/modules/spring-cloud-config.d.ts.map +1 -0
- package/dist/modules/spring-cloud-config.js +28 -0
- package/dist/modules/spring-cloud-config.js.map +1 -0
- package/dist/modules/wiremock.d.ts +21 -0
- package/dist/modules/wiremock.d.ts.map +1 -0
- package/dist/modules/wiremock.js +32 -0
- package/dist/modules/wiremock.js.map +1 -0
- package/package.json +104 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { GenericContainer } from "../core/generic-container.js";
|
|
2
|
+
/**
|
|
3
|
+
* A single-node Neo4j Community container, queried over its HTTP Cypher
|
|
4
|
+
* transaction endpoint (`/db/neo4j/tx/commit`) — no bolt driver dependency
|
|
5
|
+
* needed, matching this library's HTTP-first module convention
|
|
6
|
+
* (`ClickHouseContainer`, `PinotContainer`). The bolt port (7687) is still
|
|
7
|
+
* exposed and its URI available via `boltUrl` for callers who do want a
|
|
8
|
+
* real driver.
|
|
9
|
+
*
|
|
10
|
+
* Defaults to a `neo4j`/`rightsize-test` username/password pair (the image
|
|
11
|
+
* refuses passwords under 8 characters — `neo4j`/`neo4j` is rejected at
|
|
12
|
+
* boot) so `httpUrl` plus basic auth is usable with zero configuration;
|
|
13
|
+
* call `withPassword` before `start()` to override it. The username is
|
|
14
|
+
* fixed by the image at `neo4j` — there is no env var to change it.
|
|
15
|
+
*
|
|
16
|
+
* ### Readiness — `Started.` is the exact log line, verified against a real boot
|
|
17
|
+
*
|
|
18
|
+
* Captured verbatim from `neo4j:5-community`:
|
|
19
|
+
*
|
|
20
|
+
* ```
|
|
21
|
+
* ... INFO Bolt enabled on 0.0.0.0:7687.
|
|
22
|
+
* ... INFO HTTP enabled on 0.0.0.0:7474.
|
|
23
|
+
* ... INFO Remote interface available at http://localhost:7474/
|
|
24
|
+
* ... INFO Started.
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* `Started.` is logged only after both connectors are already listening, so
|
|
28
|
+
* it's both accurate and simpler than a two-port HTTP/bolt race. The dot in
|
|
29
|
+
* the regex is deliberately ESCAPED (`Started\\.`) — an unescaped dot would
|
|
30
|
+
* also match the literal character it's meant to require, but escaping is
|
|
31
|
+
* the correct contract for a real regex engine (`.` otherwise matches any
|
|
32
|
+
* character, not just itself).
|
|
33
|
+
*
|
|
34
|
+
* ### Memory — measured, needed the ladder
|
|
35
|
+
*
|
|
36
|
+
* At msb's default ~450MB microVM RAM, the server logs `Invalid memory
|
|
37
|
+
* configuration - exceeds physical memory` and shuts itself down cleanly
|
|
38
|
+
* (`Stopped.`) rather than hanging or getting OOM-killed — Neo4j's own
|
|
39
|
+
* memory-recommendation calculator sizes the page cache and heap off total
|
|
40
|
+
* visible RAM and refuses to start if the sums don't fit. A real boot with
|
|
41
|
+
* no memory cap sits at ~430MiB RSS, just over that default budget.
|
|
42
|
+
* `withMemoryLimit(1024)` is this module's default (verified: boots clean,
|
|
43
|
+
* the HTTP Cypher endpoint answers well within the startup timeout).
|
|
44
|
+
*/
|
|
45
|
+
export declare class Neo4jContainer extends GenericContainer {
|
|
46
|
+
private passwordState;
|
|
47
|
+
constructor(image?: string);
|
|
48
|
+
static start(image?: string): Promise<Neo4jContainer>;
|
|
49
|
+
/** Overrides `NEO4J_AUTH`'s password half (default `rightsize-test`; the image requires at least 8 characters). */
|
|
50
|
+
withPassword(password: string): this;
|
|
51
|
+
/** The fixed admin username (`neo4j` — the image has no env var to change it). */
|
|
52
|
+
get username(): string;
|
|
53
|
+
/** The configured admin password (default `rightsize-test`). */
|
|
54
|
+
get password(): string;
|
|
55
|
+
/** The HTTP interface's base URL (Cypher transactions via `POST {httpUrl}/db/neo4j/tx/commit`). */
|
|
56
|
+
get httpUrl(): string;
|
|
57
|
+
/** The bolt interface's URI, for callers using a real bolt driver instead of the HTTP helpers. */
|
|
58
|
+
get boltUrl(): string;
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=neo4j.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"neo4j.d.ts","sourceRoot":"","sources":["../../src/modules/neo4j.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAOhE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AACH,qBAAa,cAAe,SAAQ,gBAAgB;IAClD,OAAO,CAAC,aAAa,CAAoB;gBAE7B,KAAK,SAAsB;WAQjB,KAAK,CAAC,KAAK,SAAsB,GAAG,OAAO,CAAC,cAAc,CAAC;IAIjF,mHAAmH;IACnH,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAKpC,kFAAkF;IAClF,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED,gEAAgE;IAChE,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED,mGAAmG;IACnG,IAAI,OAAO,IAAI,MAAM,CAEpB;IAED,kGAAkG;IAClG,IAAI,OAAO,IAAI,MAAM,CAEpB;CACF"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { GenericContainer } from "../core/generic-container.js";
|
|
2
|
+
import { Wait } from "../core/wait.js";
|
|
3
|
+
const HTTP_PORT = 7474;
|
|
4
|
+
const BOLT_PORT = 7687;
|
|
5
|
+
const DEFAULT_PASSWORD = "rightsize-test";
|
|
6
|
+
/**
|
|
7
|
+
* A single-node Neo4j Community container, queried over its HTTP Cypher
|
|
8
|
+
* transaction endpoint (`/db/neo4j/tx/commit`) — no bolt driver dependency
|
|
9
|
+
* needed, matching this library's HTTP-first module convention
|
|
10
|
+
* (`ClickHouseContainer`, `PinotContainer`). The bolt port (7687) is still
|
|
11
|
+
* exposed and its URI available via `boltUrl` for callers who do want a
|
|
12
|
+
* real driver.
|
|
13
|
+
*
|
|
14
|
+
* Defaults to a `neo4j`/`rightsize-test` username/password pair (the image
|
|
15
|
+
* refuses passwords under 8 characters — `neo4j`/`neo4j` is rejected at
|
|
16
|
+
* boot) so `httpUrl` plus basic auth is usable with zero configuration;
|
|
17
|
+
* call `withPassword` before `start()` to override it. The username is
|
|
18
|
+
* fixed by the image at `neo4j` — there is no env var to change it.
|
|
19
|
+
*
|
|
20
|
+
* ### Readiness — `Started.` is the exact log line, verified against a real boot
|
|
21
|
+
*
|
|
22
|
+
* Captured verbatim from `neo4j:5-community`:
|
|
23
|
+
*
|
|
24
|
+
* ```
|
|
25
|
+
* ... INFO Bolt enabled on 0.0.0.0:7687.
|
|
26
|
+
* ... INFO HTTP enabled on 0.0.0.0:7474.
|
|
27
|
+
* ... INFO Remote interface available at http://localhost:7474/
|
|
28
|
+
* ... INFO Started.
|
|
29
|
+
* ```
|
|
30
|
+
*
|
|
31
|
+
* `Started.` is logged only after both connectors are already listening, so
|
|
32
|
+
* it's both accurate and simpler than a two-port HTTP/bolt race. The dot in
|
|
33
|
+
* the regex is deliberately ESCAPED (`Started\\.`) — an unescaped dot would
|
|
34
|
+
* also match the literal character it's meant to require, but escaping is
|
|
35
|
+
* the correct contract for a real regex engine (`.` otherwise matches any
|
|
36
|
+
* character, not just itself).
|
|
37
|
+
*
|
|
38
|
+
* ### Memory — measured, needed the ladder
|
|
39
|
+
*
|
|
40
|
+
* At msb's default ~450MB microVM RAM, the server logs `Invalid memory
|
|
41
|
+
* configuration - exceeds physical memory` and shuts itself down cleanly
|
|
42
|
+
* (`Stopped.`) rather than hanging or getting OOM-killed — Neo4j's own
|
|
43
|
+
* memory-recommendation calculator sizes the page cache and heap off total
|
|
44
|
+
* visible RAM and refuses to start if the sums don't fit. A real boot with
|
|
45
|
+
* no memory cap sits at ~430MiB RSS, just over that default budget.
|
|
46
|
+
* `withMemoryLimit(1024)` is this module's default (verified: boots clean,
|
|
47
|
+
* the HTTP Cypher endpoint answers well within the startup timeout).
|
|
48
|
+
*/
|
|
49
|
+
export class Neo4jContainer extends GenericContainer {
|
|
50
|
+
passwordState = DEFAULT_PASSWORD;
|
|
51
|
+
constructor(image = "neo4j:5-community") {
|
|
52
|
+
super(image);
|
|
53
|
+
this.withExposedPorts(HTTP_PORT, BOLT_PORT)
|
|
54
|
+
.withEnv("NEO4J_AUTH", `neo4j/${this.passwordState}`)
|
|
55
|
+
.withMemoryLimit(1024)
|
|
56
|
+
.waitingFor(Wait.forLogMessage(".*Started\\..*", 1).withStartupTimeout(120_000));
|
|
57
|
+
}
|
|
58
|
+
static async start(image = "neo4j:5-community") {
|
|
59
|
+
return (await new Neo4jContainer(image).start());
|
|
60
|
+
}
|
|
61
|
+
/** Overrides `NEO4J_AUTH`'s password half (default `rightsize-test`; the image requires at least 8 characters). */
|
|
62
|
+
withPassword(password) {
|
|
63
|
+
this.passwordState = password;
|
|
64
|
+
return this.withEnv("NEO4J_AUTH", `neo4j/${password}`);
|
|
65
|
+
}
|
|
66
|
+
/** The fixed admin username (`neo4j` — the image has no env var to change it). */
|
|
67
|
+
get username() {
|
|
68
|
+
return "neo4j";
|
|
69
|
+
}
|
|
70
|
+
/** The configured admin password (default `rightsize-test`). */
|
|
71
|
+
get password() {
|
|
72
|
+
return this.passwordState;
|
|
73
|
+
}
|
|
74
|
+
/** The HTTP interface's base URL (Cypher transactions via `POST {httpUrl}/db/neo4j/tx/commit`). */
|
|
75
|
+
get httpUrl() {
|
|
76
|
+
return `http://${this.host}:${this.getMappedPort(HTTP_PORT)}`;
|
|
77
|
+
}
|
|
78
|
+
/** The bolt interface's URI, for callers using a real bolt driver instead of the HTTP helpers. */
|
|
79
|
+
get boltUrl() {
|
|
80
|
+
return `bolt://${this.host}:${this.getMappedPort(BOLT_PORT)}`;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=neo4j.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"neo4j.js","sourceRoot":"","sources":["../../src/modules/neo4j.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAEvC,MAAM,SAAS,GAAG,IAAI,CAAC;AACvB,MAAM,SAAS,GAAG,IAAI,CAAC;AACvB,MAAM,gBAAgB,GAAG,gBAAgB,CAAC;AAE1C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AACH,MAAM,OAAO,cAAe,SAAQ,gBAAgB;IAC1C,aAAa,GAAG,gBAAgB,CAAC;IAEzC,YAAY,KAAK,GAAG,mBAAmB;QACrC,KAAK,CAAC,KAAK,CAAC,CAAC;QACb,IAAI,CAAC,gBAAgB,CAAC,SAAS,EAAE,SAAS,CAAC;aACxC,OAAO,CAAC,YAAY,EAAE,SAAS,IAAI,CAAC,aAAa,EAAE,CAAC;aACpD,eAAe,CAAC,IAAI,CAAC;aACrB,UAAU,CAAC,IAAI,CAAC,aAAa,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC,CAAC;IACrF,CAAC;IAED,MAAM,CAAU,KAAK,CAAC,KAAK,CAAC,KAAK,GAAG,mBAAmB;QACrD,OAAO,CAAC,MAAM,IAAI,cAAc,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,CAAmB,CAAC;IACrE,CAAC;IAED,mHAAmH;IACnH,YAAY,CAAC,QAAgB;QAC3B,IAAI,CAAC,aAAa,GAAG,QAAQ,CAAC;QAC9B,OAAO,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,SAAS,QAAQ,EAAE,CAAC,CAAC;IACzD,CAAC;IAED,kFAAkF;IAClF,IAAI,QAAQ;QACV,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,gEAAgE;IAChE,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,aAAa,CAAC;IAC5B,CAAC;IAED,mGAAmG;IACnG,IAAI,OAAO;QACT,OAAO,UAAU,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,EAAE,CAAC;IAChE,CAAC;IAED,kGAAkG;IAClG,IAAI,OAAO;QACT,OAAO,UAAU,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,EAAE,CAAC;IAChE,CAAC;CACF"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { GenericContainer } from "../core/generic-container.js";
|
|
2
|
+
/**
|
|
3
|
+
* A single-container Apache Pinot QuickStart cluster (controller + broker +
|
|
4
|
+
* server + ZooKeeper, all four JVMs colocated in one image, started with
|
|
5
|
+
* `QuickStart -type EMPTY` for a clean cluster with no demo tables).
|
|
6
|
+
*
|
|
7
|
+
* Two pins here correct guesses that turned out wrong against the real
|
|
8
|
+
* 1.5.1 image:
|
|
9
|
+
*
|
|
10
|
+
* - The broker's query port is **8000**, not 8099. The image exposes
|
|
11
|
+
* 8096–8099 (controller admin, and various internal ports) plus 9000, but
|
|
12
|
+
* QuickStart's broker binds 8000 for client queries; 8099 is never opened
|
|
13
|
+
* by this entrypoint.
|
|
14
|
+
* - The image bakes `-Xmx4G` into the QuickStart launch scripts, so it needs
|
|
15
|
+
* `withMemoryLimit(4096)` on msb regardless of how modest the workload is.
|
|
16
|
+
* Measured on this machine: 2048/2560MB microVMs get OOM-killed outright;
|
|
17
|
+
* 3072MB boots but runs at ~99% memory pressure with Helix RPC timeouts
|
|
18
|
+
* under any load; 4096MB is the first limit that boots AND stays stable
|
|
19
|
+
* (~74% steady-state utilization). This is a hard floor, not a tunable
|
|
20
|
+
* default — do not lower it.
|
|
21
|
+
*/
|
|
22
|
+
export declare class PinotContainer extends GenericContainer {
|
|
23
|
+
constructor(image?: string);
|
|
24
|
+
static start(image?: string): Promise<PinotContainer>;
|
|
25
|
+
/** The controller's REST base URL (schema/table admin, `/health`). */
|
|
26
|
+
get controllerUrl(): string;
|
|
27
|
+
/** The broker's query base URL. */
|
|
28
|
+
get brokerUrl(): string;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=pinot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pinot.d.ts","sourceRoot":"","sources":["../../src/modules/pinot.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAOhE;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,cAAe,SAAQ,gBAAgB;gBACtC,KAAK,SAA4B;WAWvB,KAAK,CAAC,KAAK,SAA4B,GAAG,OAAO,CAAC,cAAc,CAAC;IAIvF,sEAAsE;IACtE,IAAI,aAAa,IAAI,MAAM,CAE1B;IAED,mCAAmC;IACnC,IAAI,SAAS,IAAI,MAAM,CAEtB;CACF"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { GenericContainer } from "../core/generic-container.js";
|
|
2
|
+
import { Wait } from "../core/wait.js";
|
|
3
|
+
const CONTROLLER_PORT = 9000;
|
|
4
|
+
const BROKER_PORT = 8000;
|
|
5
|
+
const STARTUP_TIMEOUT_MS = 180_000;
|
|
6
|
+
/**
|
|
7
|
+
* A single-container Apache Pinot QuickStart cluster (controller + broker +
|
|
8
|
+
* server + ZooKeeper, all four JVMs colocated in one image, started with
|
|
9
|
+
* `QuickStart -type EMPTY` for a clean cluster with no demo tables).
|
|
10
|
+
*
|
|
11
|
+
* Two pins here correct guesses that turned out wrong against the real
|
|
12
|
+
* 1.5.1 image:
|
|
13
|
+
*
|
|
14
|
+
* - The broker's query port is **8000**, not 8099. The image exposes
|
|
15
|
+
* 8096–8099 (controller admin, and various internal ports) plus 9000, but
|
|
16
|
+
* QuickStart's broker binds 8000 for client queries; 8099 is never opened
|
|
17
|
+
* by this entrypoint.
|
|
18
|
+
* - The image bakes `-Xmx4G` into the QuickStart launch scripts, so it needs
|
|
19
|
+
* `withMemoryLimit(4096)` on msb regardless of how modest the workload is.
|
|
20
|
+
* Measured on this machine: 2048/2560MB microVMs get OOM-killed outright;
|
|
21
|
+
* 3072MB boots but runs at ~99% memory pressure with Helix RPC timeouts
|
|
22
|
+
* under any load; 4096MB is the first limit that boots AND stays stable
|
|
23
|
+
* (~74% steady-state utilization). This is a hard floor, not a tunable
|
|
24
|
+
* default — do not lower it.
|
|
25
|
+
*/
|
|
26
|
+
export class PinotContainer extends GenericContainer {
|
|
27
|
+
constructor(image = "apachepinot/pinot:1.5.1") {
|
|
28
|
+
super(image);
|
|
29
|
+
this.withExposedPorts(CONTROLLER_PORT, BROKER_PORT)
|
|
30
|
+
.withCommand("QuickStart", "-type", "EMPTY")
|
|
31
|
+
.withMemoryLimit(4096)
|
|
32
|
+
// A four-JVM cluster (controller+broker+server+ZK) cold-booting in one
|
|
33
|
+
// microVM/container is legitimately slow; 180s gives it room without
|
|
34
|
+
// masking a real hang.
|
|
35
|
+
.waitingFor(Wait.forHttp("/health").forPort(CONTROLLER_PORT).withStartupTimeout(STARTUP_TIMEOUT_MS));
|
|
36
|
+
}
|
|
37
|
+
static async start(image = "apachepinot/pinot:1.5.1") {
|
|
38
|
+
return (await new PinotContainer(image).start());
|
|
39
|
+
}
|
|
40
|
+
/** The controller's REST base URL (schema/table admin, `/health`). */
|
|
41
|
+
get controllerUrl() {
|
|
42
|
+
return `http://${this.host}:${this.getMappedPort(CONTROLLER_PORT)}`;
|
|
43
|
+
}
|
|
44
|
+
/** The broker's query base URL. */
|
|
45
|
+
get brokerUrl() {
|
|
46
|
+
return `http://${this.host}:${this.getMappedPort(BROKER_PORT)}`;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=pinot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pinot.js","sourceRoot":"","sources":["../../src/modules/pinot.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAEvC,MAAM,eAAe,GAAG,IAAI,CAAC;AAC7B,MAAM,WAAW,GAAG,IAAI,CAAC;AACzB,MAAM,kBAAkB,GAAG,OAAO,CAAC;AAEnC;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,OAAO,cAAe,SAAQ,gBAAgB;IAClD,YAAY,KAAK,GAAG,yBAAyB;QAC3C,KAAK,CAAC,KAAK,CAAC,CAAC;QACb,IAAI,CAAC,gBAAgB,CAAC,eAAe,EAAE,WAAW,CAAC;aAChD,WAAW,CAAC,YAAY,EAAE,OAAO,EAAE,OAAO,CAAC;aAC3C,eAAe,CAAC,IAAI,CAAC;YACtB,uEAAuE;YACvE,qEAAqE;YACrE,uBAAuB;aACtB,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,kBAAkB,CAAC,kBAAkB,CAAC,CAAC,CAAC;IACzG,CAAC;IAED,MAAM,CAAU,KAAK,CAAC,KAAK,CAAC,KAAK,GAAG,yBAAyB;QAC3D,OAAO,CAAC,MAAM,IAAI,cAAc,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,CAAmB,CAAC;IACrE,CAAC;IAED,sEAAsE;IACtE,IAAI,aAAa;QACf,OAAO,UAAU,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,aAAa,CAAC,eAAe,CAAC,EAAE,CAAC;IACtE,CAAC;IAED,mCAAmC;IACnC,IAAI,SAAS;QACX,OAAO,UAAU,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,aAAa,CAAC,WAAW,CAAC,EAAE,CAAC;IAClE,CAAC;CACF"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { GenericContainer } from "../core/generic-container.js";
|
|
2
|
+
/**
|
|
3
|
+
* A single-node PostgreSQL container. Defaults to a `test`/`test`/`test`
|
|
4
|
+
* user/password/database trio so `connectionString` is usable with zero
|
|
5
|
+
* configuration; call `withUsername`/`withPassword`/`withDatabase` before
|
|
6
|
+
* `start()` to override any of them.
|
|
7
|
+
*/
|
|
8
|
+
export declare class PostgresContainer extends GenericContainer {
|
|
9
|
+
private usernameState;
|
|
10
|
+
private passwordState;
|
|
11
|
+
private databaseState;
|
|
12
|
+
constructor(image?: string);
|
|
13
|
+
static start(image?: string): Promise<PostgresContainer>;
|
|
14
|
+
/** Overrides `POSTGRES_USER` (default `test`). */
|
|
15
|
+
withUsername(username: string): this;
|
|
16
|
+
/** Overrides `POSTGRES_PASSWORD` (default `test`). */
|
|
17
|
+
withPassword(password: string): this;
|
|
18
|
+
/** Overrides `POSTGRES_DB` (default `test`). */
|
|
19
|
+
withDatabase(database: string): this;
|
|
20
|
+
/** The configured database user (default `test`). */
|
|
21
|
+
get username(): string;
|
|
22
|
+
/** The configured database password (default `test`). */
|
|
23
|
+
get password(): string;
|
|
24
|
+
/** The configured database name (default `test`). */
|
|
25
|
+
get databaseName(): string;
|
|
26
|
+
/** A `postgres://` connection string for the running container's `databaseName`. */
|
|
27
|
+
get connectionString(): string;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=postgres.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postgres.d.ts","sourceRoot":"","sources":["../../src/modules/postgres.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAKhE;;;;;GAKG;AACH,qBAAa,iBAAkB,SAAQ,gBAAgB;IACrD,OAAO,CAAC,aAAa,CAAU;IAC/B,OAAO,CAAC,aAAa,CAAU;IAC/B,OAAO,CAAC,aAAa,CAAU;gBAEnB,KAAK,SAAuB;WAyBlB,KAAK,CAAC,KAAK,SAAuB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAIrF,kDAAkD;IAClD,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAKpC,sDAAsD;IACtD,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAKpC,gDAAgD;IAChD,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAKpC,qDAAqD;IACrD,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED,yDAAyD;IACzD,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED,qDAAqD;IACrD,IAAI,YAAY,IAAI,MAAM,CAEzB;IAED,oFAAoF;IACpF,IAAI,gBAAgB,IAAI,MAAM,CAE7B;CACF"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { GenericContainer } from "../core/generic-container.js";
|
|
2
|
+
import { Wait } from "../core/wait.js";
|
|
3
|
+
const GUEST_PORT = 5432;
|
|
4
|
+
/**
|
|
5
|
+
* A single-node PostgreSQL container. Defaults to a `test`/`test`/`test`
|
|
6
|
+
* user/password/database trio so `connectionString` is usable with zero
|
|
7
|
+
* configuration; call `withUsername`/`withPassword`/`withDatabase` before
|
|
8
|
+
* `start()` to override any of them.
|
|
9
|
+
*/
|
|
10
|
+
export class PostgresContainer extends GenericContainer {
|
|
11
|
+
usernameState = "test";
|
|
12
|
+
passwordState = "test";
|
|
13
|
+
databaseState = "test";
|
|
14
|
+
constructor(image = "postgres:18-alpine") {
|
|
15
|
+
super(image);
|
|
16
|
+
this.withExposedPorts(GUEST_PORT)
|
|
17
|
+
.withEnv("POSTGRES_USER", this.usernameState)
|
|
18
|
+
.withEnv("POSTGRES_PASSWORD", this.passwordState)
|
|
19
|
+
.withEnv("POSTGRES_DB", this.databaseState)
|
|
20
|
+
// The official postgres:*-alpine image bakes DOCKER_PG_LLVM_DEPS into
|
|
21
|
+
// its manifest with a literal tab character in the value (a
|
|
22
|
+
// package-list built with `\t\t` continuation). msb's krun VMM
|
|
23
|
+
// builder panics with InvalidAscii on that boot-env value before the
|
|
24
|
+
// guest ever starts (reproduced with zero rightsize-set env vars —
|
|
25
|
+
// it's the image, not us). Docker is unaffected. Overriding the var
|
|
26
|
+
// here wins over the image default in both backends' env-merge order
|
|
27
|
+
// and is a no-op for the build the image already baked, so it's a
|
|
28
|
+
// safe, backend-portable fix rather than an msb-only special case.
|
|
29
|
+
.withEnv("DOCKER_PG_LLVM_DEPS", "")
|
|
30
|
+
// The postgres entrypoint starts the server once to run initdb
|
|
31
|
+
// scripts against it, shuts it down, then starts it again for real —
|
|
32
|
+
// printing "database system is ready to accept connections" BOTH
|
|
33
|
+
// times. Waiting for the first occurrence races that restart: a
|
|
34
|
+
// client can connect to the init-time server just before it's torn
|
|
35
|
+
// down. times=2 waits for the second, durable listen.
|
|
36
|
+
.waitingFor(Wait.forLogMessage(".*database system is ready to accept connections.*", 2));
|
|
37
|
+
}
|
|
38
|
+
static async start(image = "postgres:18-alpine") {
|
|
39
|
+
return (await new PostgresContainer(image).start());
|
|
40
|
+
}
|
|
41
|
+
/** Overrides `POSTGRES_USER` (default `test`). */
|
|
42
|
+
withUsername(username) {
|
|
43
|
+
this.usernameState = username;
|
|
44
|
+
return this.withEnv("POSTGRES_USER", username);
|
|
45
|
+
}
|
|
46
|
+
/** Overrides `POSTGRES_PASSWORD` (default `test`). */
|
|
47
|
+
withPassword(password) {
|
|
48
|
+
this.passwordState = password;
|
|
49
|
+
return this.withEnv("POSTGRES_PASSWORD", password);
|
|
50
|
+
}
|
|
51
|
+
/** Overrides `POSTGRES_DB` (default `test`). */
|
|
52
|
+
withDatabase(database) {
|
|
53
|
+
this.databaseState = database;
|
|
54
|
+
return this.withEnv("POSTGRES_DB", database);
|
|
55
|
+
}
|
|
56
|
+
/** The configured database user (default `test`). */
|
|
57
|
+
get username() {
|
|
58
|
+
return this.usernameState;
|
|
59
|
+
}
|
|
60
|
+
/** The configured database password (default `test`). */
|
|
61
|
+
get password() {
|
|
62
|
+
return this.passwordState;
|
|
63
|
+
}
|
|
64
|
+
/** The configured database name (default `test`). */
|
|
65
|
+
get databaseName() {
|
|
66
|
+
return this.databaseState;
|
|
67
|
+
}
|
|
68
|
+
/** A `postgres://` connection string for the running container's `databaseName`. */
|
|
69
|
+
get connectionString() {
|
|
70
|
+
return `postgres://${this.usernameState}:${this.passwordState}@${this.host}:${this.getMappedPort(GUEST_PORT)}/${this.databaseState}`;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=postgres.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postgres.js","sourceRoot":"","sources":["../../src/modules/postgres.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAEvC,MAAM,UAAU,GAAG,IAAI,CAAC;AAExB;;;;;GAKG;AACH,MAAM,OAAO,iBAAkB,SAAQ,gBAAgB;IAC7C,aAAa,GAAG,MAAM,CAAC;IACvB,aAAa,GAAG,MAAM,CAAC;IACvB,aAAa,GAAG,MAAM,CAAC;IAE/B,YAAY,KAAK,GAAG,oBAAoB;QACtC,KAAK,CAAC,KAAK,CAAC,CAAC;QACb,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC;aAC9B,OAAO,CAAC,eAAe,EAAE,IAAI,CAAC,aAAa,CAAC;aAC5C,OAAO,CAAC,mBAAmB,EAAE,IAAI,CAAC,aAAa,CAAC;aAChD,OAAO,CAAC,aAAa,EAAE,IAAI,CAAC,aAAa,CAAC;YAC3C,sEAAsE;YACtE,4DAA4D;YAC5D,+DAA+D;YAC/D,qEAAqE;YACrE,mEAAmE;YACnE,oEAAoE;YACpE,qEAAqE;YACrE,kEAAkE;YAClE,mEAAmE;aAClE,OAAO,CAAC,qBAAqB,EAAE,EAAE,CAAC;YACnC,+DAA+D;YAC/D,qEAAqE;YACrE,iEAAiE;YACjE,gEAAgE;YAChE,mEAAmE;YACnE,sDAAsD;aACrD,UAAU,CAAC,IAAI,CAAC,aAAa,CAAC,oDAAoD,EAAE,CAAC,CAAC,CAAC,CAAC;IAC7F,CAAC;IAED,MAAM,CAAU,KAAK,CAAC,KAAK,CAAC,KAAK,GAAG,oBAAoB;QACtD,OAAO,CAAC,MAAM,IAAI,iBAAiB,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,CAAsB,CAAC;IAC3E,CAAC;IAED,kDAAkD;IAClD,YAAY,CAAC,QAAgB;QAC3B,IAAI,CAAC,aAAa,GAAG,QAAQ,CAAC;QAC9B,OAAO,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,QAAQ,CAAC,CAAC;IACjD,CAAC;IAED,sDAAsD;IACtD,YAAY,CAAC,QAAgB;QAC3B,IAAI,CAAC,aAAa,GAAG,QAAQ,CAAC;QAC9B,OAAO,IAAI,CAAC,OAAO,CAAC,mBAAmB,EAAE,QAAQ,CAAC,CAAC;IACrD,CAAC;IAED,gDAAgD;IAChD,YAAY,CAAC,QAAgB;QAC3B,IAAI,CAAC,aAAa,GAAG,QAAQ,CAAC;QAC9B,OAAO,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC;IAC/C,CAAC;IAED,qDAAqD;IACrD,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,aAAa,CAAC;IAC5B,CAAC;IAED,yDAAyD;IACzD,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,aAAa,CAAC;IAC5B,CAAC;IAED,qDAAqD;IACrD,IAAI,YAAY;QACd,OAAO,IAAI,CAAC,aAAa,CAAC;IAC5B,CAAC;IAED,oFAAoF;IACpF,IAAI,gBAAgB;QAClB,OAAO,cAAc,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;IACvI,CAAC;CACF"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { GenericContainer } from "../core/generic-container.js";
|
|
2
|
+
/**
|
|
3
|
+
* A single-node RabbitMQ container with the management plugin enabled.
|
|
4
|
+
* Defaults to the image's own `guest`/`guest` credentials; call
|
|
5
|
+
* `withUsername`/`withPassword` before `start()` to override either (sets
|
|
6
|
+
* `RABBITMQ_DEFAULT_USER`/`RABBITMQ_DEFAULT_PASS`).
|
|
7
|
+
*
|
|
8
|
+
* Readiness waits on the boot log line captured from a real
|
|
9
|
+
* `rabbitmq:4-management-alpine` run: `Server startup complete; N plugins
|
|
10
|
+
* started.` — NOT the shorter "Server startup complete" alone some older
|
|
11
|
+
* 3.x docs quote, since 4.x always appends the plugin-count clause on the
|
|
12
|
+
* same line. The wait regex (`.*Server startup complete.*`) only matches the
|
|
13
|
+
* stable "Server startup complete" substring anywhere on the line, so the
|
|
14
|
+
* trailing plugin-count clause — which varies by which plugins are
|
|
15
|
+
* enabled — never has to match exactly. The management HTTP API's own
|
|
16
|
+
* `/api/health/checks/...` endpoints require authenticated requests to
|
|
17
|
+
* probe, which would need this module to bake in an HTTP+auth wait
|
|
18
|
+
* strategy just to watch a JVM-style health check that AMQP's own boot log
|
|
19
|
+
* already answers for free — the log wait is simpler and exercises exactly
|
|
20
|
+
* the readiness rightsize's Wait strategies are for.
|
|
21
|
+
*
|
|
22
|
+
* RabbitMQ 4.x behavior note (not this module's concern to fix, but the
|
|
23
|
+
* reason the IT declares durable/exclusive queues): 4.x rejects declaring a
|
|
24
|
+
* transient (non-durable), non-exclusive queue — a behavior change from
|
|
25
|
+
* 3.x. Consumers of this container must declare durable or exclusive
|
|
26
|
+
* queues; a transient shared queue now errors at declare time.
|
|
27
|
+
*/
|
|
28
|
+
export declare class RabbitMQContainer extends GenericContainer {
|
|
29
|
+
private usernameState;
|
|
30
|
+
private passwordState;
|
|
31
|
+
constructor(image?: string);
|
|
32
|
+
static start(image?: string): Promise<RabbitMQContainer>;
|
|
33
|
+
/** Overrides `RABBITMQ_DEFAULT_USER` (default `guest`). */
|
|
34
|
+
withUsername(username: string): this;
|
|
35
|
+
/** Overrides `RABBITMQ_DEFAULT_PASS` (default `guest`). */
|
|
36
|
+
withPassword(password: string): this;
|
|
37
|
+
/** The configured AMQP username (default `guest`). */
|
|
38
|
+
get username(): string;
|
|
39
|
+
/** The configured AMQP password (default `guest`). */
|
|
40
|
+
get password(): string;
|
|
41
|
+
/** An `amqp://` connection URL for the running broker. */
|
|
42
|
+
get amqpUrl(): string;
|
|
43
|
+
/** The management HTTP API's base URL for the running broker. */
|
|
44
|
+
get managementUrl(): string;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=rabbitmq.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rabbitmq.d.ts","sourceRoot":"","sources":["../../src/modules/rabbitmq.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAMhE;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,qBAAa,iBAAkB,SAAQ,gBAAgB;IACrD,OAAO,CAAC,aAAa,CAAW;IAChC,OAAO,CAAC,aAAa,CAAW;gBAEpB,KAAK,SAAiC;WAO5B,KAAK,CAAC,KAAK,SAAiC,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAI/F,2DAA2D;IAC3D,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAKpC,2DAA2D;IAC3D,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAKpC,sDAAsD;IACtD,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED,sDAAsD;IACtD,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED,0DAA0D;IAC1D,IAAI,OAAO,IAAI,MAAM,CAEpB;IAED,iEAAiE;IACjE,IAAI,aAAa,IAAI,MAAM,CAE1B;CACF"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { GenericContainer } from "../core/generic-container.js";
|
|
2
|
+
import { Wait } from "../core/wait.js";
|
|
3
|
+
const AMQP_PORT = 5672;
|
|
4
|
+
const MANAGEMENT_PORT = 15672;
|
|
5
|
+
/**
|
|
6
|
+
* A single-node RabbitMQ container with the management plugin enabled.
|
|
7
|
+
* Defaults to the image's own `guest`/`guest` credentials; call
|
|
8
|
+
* `withUsername`/`withPassword` before `start()` to override either (sets
|
|
9
|
+
* `RABBITMQ_DEFAULT_USER`/`RABBITMQ_DEFAULT_PASS`).
|
|
10
|
+
*
|
|
11
|
+
* Readiness waits on the boot log line captured from a real
|
|
12
|
+
* `rabbitmq:4-management-alpine` run: `Server startup complete; N plugins
|
|
13
|
+
* started.` — NOT the shorter "Server startup complete" alone some older
|
|
14
|
+
* 3.x docs quote, since 4.x always appends the plugin-count clause on the
|
|
15
|
+
* same line. The wait regex (`.*Server startup complete.*`) only matches the
|
|
16
|
+
* stable "Server startup complete" substring anywhere on the line, so the
|
|
17
|
+
* trailing plugin-count clause — which varies by which plugins are
|
|
18
|
+
* enabled — never has to match exactly. The management HTTP API's own
|
|
19
|
+
* `/api/health/checks/...` endpoints require authenticated requests to
|
|
20
|
+
* probe, which would need this module to bake in an HTTP+auth wait
|
|
21
|
+
* strategy just to watch a JVM-style health check that AMQP's own boot log
|
|
22
|
+
* already answers for free — the log wait is simpler and exercises exactly
|
|
23
|
+
* the readiness rightsize's Wait strategies are for.
|
|
24
|
+
*
|
|
25
|
+
* RabbitMQ 4.x behavior note (not this module's concern to fix, but the
|
|
26
|
+
* reason the IT declares durable/exclusive queues): 4.x rejects declaring a
|
|
27
|
+
* transient (non-durable), non-exclusive queue — a behavior change from
|
|
28
|
+
* 3.x. Consumers of this container must declare durable or exclusive
|
|
29
|
+
* queues; a transient shared queue now errors at declare time.
|
|
30
|
+
*/
|
|
31
|
+
export class RabbitMQContainer extends GenericContainer {
|
|
32
|
+
usernameState = "guest";
|
|
33
|
+
passwordState = "guest";
|
|
34
|
+
constructor(image = "rabbitmq:4-management-alpine") {
|
|
35
|
+
super(image);
|
|
36
|
+
this.withExposedPorts(AMQP_PORT, MANAGEMENT_PORT).waitingFor(Wait.forLogMessage(".*Server startup complete.*"));
|
|
37
|
+
}
|
|
38
|
+
static async start(image = "rabbitmq:4-management-alpine") {
|
|
39
|
+
return (await new RabbitMQContainer(image).start());
|
|
40
|
+
}
|
|
41
|
+
/** Overrides `RABBITMQ_DEFAULT_USER` (default `guest`). */
|
|
42
|
+
withUsername(username) {
|
|
43
|
+
this.usernameState = username;
|
|
44
|
+
return this.withEnv("RABBITMQ_DEFAULT_USER", username);
|
|
45
|
+
}
|
|
46
|
+
/** Overrides `RABBITMQ_DEFAULT_PASS` (default `guest`). */
|
|
47
|
+
withPassword(password) {
|
|
48
|
+
this.passwordState = password;
|
|
49
|
+
return this.withEnv("RABBITMQ_DEFAULT_PASS", password);
|
|
50
|
+
}
|
|
51
|
+
/** The configured AMQP username (default `guest`). */
|
|
52
|
+
get username() {
|
|
53
|
+
return this.usernameState;
|
|
54
|
+
}
|
|
55
|
+
/** The configured AMQP password (default `guest`). */
|
|
56
|
+
get password() {
|
|
57
|
+
return this.passwordState;
|
|
58
|
+
}
|
|
59
|
+
/** An `amqp://` connection URL for the running broker. */
|
|
60
|
+
get amqpUrl() {
|
|
61
|
+
return `amqp://${this.usernameState}:${this.passwordState}@${this.host}:${this.getMappedPort(AMQP_PORT)}`;
|
|
62
|
+
}
|
|
63
|
+
/** The management HTTP API's base URL for the running broker. */
|
|
64
|
+
get managementUrl() {
|
|
65
|
+
return `http://${this.host}:${this.getMappedPort(MANAGEMENT_PORT)}`;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=rabbitmq.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rabbitmq.js","sourceRoot":"","sources":["../../src/modules/rabbitmq.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAEvC,MAAM,SAAS,GAAG,IAAI,CAAC;AACvB,MAAM,eAAe,GAAG,KAAK,CAAC;AAE9B;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,OAAO,iBAAkB,SAAQ,gBAAgB;IAC7C,aAAa,GAAG,OAAO,CAAC;IACxB,aAAa,GAAG,OAAO,CAAC;IAEhC,YAAY,KAAK,GAAG,8BAA8B;QAChD,KAAK,CAAC,KAAK,CAAC,CAAC;QACb,IAAI,CAAC,gBAAgB,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC,UAAU,CAC1D,IAAI,CAAC,aAAa,CAAC,6BAA6B,CAAC,CAClD,CAAC;IACJ,CAAC;IAED,MAAM,CAAU,KAAK,CAAC,KAAK,CAAC,KAAK,GAAG,8BAA8B;QAChE,OAAO,CAAC,MAAM,IAAI,iBAAiB,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,CAAsB,CAAC;IAC3E,CAAC;IAED,2DAA2D;IAC3D,YAAY,CAAC,QAAgB;QAC3B,IAAI,CAAC,aAAa,GAAG,QAAQ,CAAC;QAC9B,OAAO,IAAI,CAAC,OAAO,CAAC,uBAAuB,EAAE,QAAQ,CAAC,CAAC;IACzD,CAAC;IAED,2DAA2D;IAC3D,YAAY,CAAC,QAAgB;QAC3B,IAAI,CAAC,aAAa,GAAG,QAAQ,CAAC;QAC9B,OAAO,IAAI,CAAC,OAAO,CAAC,uBAAuB,EAAE,QAAQ,CAAC,CAAC;IACzD,CAAC;IAED,sDAAsD;IACtD,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,aAAa,CAAC;IAC5B,CAAC;IAED,sDAAsD;IACtD,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,aAAa,CAAC;IAC5B,CAAC;IAED,0DAA0D;IAC1D,IAAI,OAAO;QACT,OAAO,UAAU,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,EAAE,CAAC;IAC5G,CAAC;IAED,iEAAiE;IACjE,IAAI,aAAa;QACf,OAAO,UAAU,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,aAAa,CAAC,eAAe,CAAC,EAAE,CAAC;IACtE,CAAC;CACF"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { GenericContainer } from "../core/generic-container.js";
|
|
2
|
+
/**
|
|
3
|
+
* A single-node Redis container. Readiness is anchored on Redis's own
|
|
4
|
+
* "Ready to accept connections" log line rather than a TCP probe: on a loaded
|
|
5
|
+
* host the port forwarder can accept and hold a connection in the window
|
|
6
|
+
* between Redis binding its socket and actually serving, which a bare
|
|
7
|
+
* listening-port check cannot see through.
|
|
8
|
+
*/
|
|
9
|
+
export declare class RedisContainer extends GenericContainer {
|
|
10
|
+
constructor(image?: string);
|
|
11
|
+
static start(image?: string): Promise<RedisContainer>;
|
|
12
|
+
/** A `redis://` connection URI for the running container. */
|
|
13
|
+
get uri(): string;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=redis.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redis.d.ts","sourceRoot":"","sources":["../../src/modules/redis.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAKhE;;;;;;GAMG;AACH,qBAAa,cAAe,SAAQ,gBAAgB;gBACtC,KAAK,SAAqB;WAKhB,KAAK,CAAC,KAAK,SAAqB,GAAG,OAAO,CAAC,cAAc,CAAC;IAIhF,6DAA6D;IAC7D,IAAI,GAAG,IAAI,MAAM,CAEhB;CACF"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { GenericContainer } from "../core/generic-container.js";
|
|
2
|
+
import { Wait } from "../core/wait.js";
|
|
3
|
+
const GUEST_PORT = 6379;
|
|
4
|
+
/**
|
|
5
|
+
* A single-node Redis container. Readiness is anchored on Redis's own
|
|
6
|
+
* "Ready to accept connections" log line rather than a TCP probe: on a loaded
|
|
7
|
+
* host the port forwarder can accept and hold a connection in the window
|
|
8
|
+
* between Redis binding its socket and actually serving, which a bare
|
|
9
|
+
* listening-port check cannot see through.
|
|
10
|
+
*/
|
|
11
|
+
export class RedisContainer extends GenericContainer {
|
|
12
|
+
constructor(image = "redis:8.6-alpine") {
|
|
13
|
+
super(image);
|
|
14
|
+
this.withExposedPorts(GUEST_PORT).waitingFor(Wait.forLogMessage(".*Ready to accept connections.*", 1));
|
|
15
|
+
}
|
|
16
|
+
static async start(image = "redis:8.6-alpine") {
|
|
17
|
+
return (await new RedisContainer(image).start());
|
|
18
|
+
}
|
|
19
|
+
/** A `redis://` connection URI for the running container. */
|
|
20
|
+
get uri() {
|
|
21
|
+
return `redis://${this.host}:${this.getMappedPort(GUEST_PORT)}`;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=redis.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redis.js","sourceRoot":"","sources":["../../src/modules/redis.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAEvC,MAAM,UAAU,GAAG,IAAI,CAAC;AAExB;;;;;;GAMG;AACH,MAAM,OAAO,cAAe,SAAQ,gBAAgB;IAClD,YAAY,KAAK,GAAG,kBAAkB;QACpC,KAAK,CAAC,KAAK,CAAC,CAAC;QACb,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,aAAa,CAAC,iCAAiC,EAAE,CAAC,CAAC,CAAC,CAAC;IACzG,CAAC;IAED,MAAM,CAAU,KAAK,CAAC,KAAK,CAAC,KAAK,GAAG,kBAAkB;QACpD,OAAO,CAAC,MAAM,IAAI,cAAc,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,CAAmB,CAAC;IACrE,CAAC;IAED,6DAA6D;IAC7D,IAAI,GAAG;QACL,OAAO,WAAW,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC,EAAE,CAAC;IAClE,CAAC;CACF"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { GenericContainer } from "../core/generic-container.js";
|
|
2
|
+
import type { ContainerSpec } from "../core/model.js";
|
|
3
|
+
/**
|
|
4
|
+
* A single-node Redpanda broker (Kafka API-compatible) with its schema
|
|
5
|
+
* registry enabled. Pinned to a versioned tag rather than `:latest`:
|
|
6
|
+
* `docker.redpanda.com` rate-limits anonymous pulls (seed it into the msb
|
|
7
|
+
* image cache once with `docker save <img> | msb load` ahead of integration
|
|
8
|
+
* runs), and a versioned tag makes that seed step reproducible.
|
|
9
|
+
*/
|
|
10
|
+
export declare class RedpandaContainer extends GenericContainer {
|
|
11
|
+
constructor(image?: string);
|
|
12
|
+
static start(image?: string): Promise<RedpandaContainer>;
|
|
13
|
+
/**
|
|
14
|
+
* The advertised listener must carry the mapped host port, known only now
|
|
15
|
+
* (ports were allocated before boot) — the reason this hook exists at
|
|
16
|
+
* all. EXTERNAL advertises that mapped host port for host clients;
|
|
17
|
+
* INTERNAL advertises the fixed alias:port siblings resolve on the
|
|
18
|
+
* container network. See `KafkaContainer.customizeSpec` for the same
|
|
19
|
+
* trick applied to a single advertised listener.
|
|
20
|
+
*/
|
|
21
|
+
protected customizeSpec(spec: ContainerSpec, mapped: (guest: number) => number): ContainerSpec;
|
|
22
|
+
/** The `PLAINTEXT://` bootstrap-servers address for the running broker (EXTERNAL listener). */
|
|
23
|
+
get bootstrapServers(): string;
|
|
24
|
+
/** The schema registry's base URI for the running broker. */
|
|
25
|
+
get schemaRegistryUrl(): string;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=redpanda.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redpanda.d.ts","sourceRoot":"","sources":["../../src/modules/redpanda.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAEhE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAUtD;;;;;;GAMG;AACH,qBAAa,iBAAkB,SAAQ,gBAAgB;gBACzC,KAAK,SAAkC;WAO7B,KAAK,CACzB,KAAK,SAAkC,GACtC,OAAO,CAAC,iBAAiB,CAAC;IAI7B;;;;;;;OAOG;cACgB,aAAa,CAAC,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,GAAG,aAAa;IAkBvG,+FAA+F;IAC/F,IAAI,gBAAgB,IAAI,MAAM,CAE7B;IAED,6DAA6D;IAC7D,IAAI,iBAAiB,IAAI,MAAM,CAE9B;CACF"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { GenericContainer } from "../core/generic-container.js";
|
|
2
|
+
import { Wait } from "../core/wait.js";
|
|
3
|
+
const EXTERNAL_PORT = 9092;
|
|
4
|
+
const INTERNAL_PORT = 9093;
|
|
5
|
+
const SCHEMA_REGISTRY_PORT = 8081;
|
|
6
|
+
// The alias siblings resolve INTERNAL through — native docker networks, or
|
|
7
|
+
// the msb exec-tunnel alias emulation.
|
|
8
|
+
const INTERNAL_ALIAS = "redpanda";
|
|
9
|
+
/**
|
|
10
|
+
* A single-node Redpanda broker (Kafka API-compatible) with its schema
|
|
11
|
+
* registry enabled. Pinned to a versioned tag rather than `:latest`:
|
|
12
|
+
* `docker.redpanda.com` rate-limits anonymous pulls (seed it into the msb
|
|
13
|
+
* image cache once with `docker save <img> | msb load` ahead of integration
|
|
14
|
+
* runs), and a versioned tag makes that seed step reproducible.
|
|
15
|
+
*/
|
|
16
|
+
export class RedpandaContainer extends GenericContainer {
|
|
17
|
+
constructor(image = "redpandadata/redpanda:v24.2.4") {
|
|
18
|
+
super(image);
|
|
19
|
+
this.withExposedPorts(EXTERNAL_PORT, INTERNAL_PORT, SCHEMA_REGISTRY_PORT).waitingFor(Wait.forLogMessage(".*Successfully started Redpanda.*"));
|
|
20
|
+
}
|
|
21
|
+
static async start(image = "redpandadata/redpanda:v24.2.4") {
|
|
22
|
+
return (await new RedpandaContainer(image).start());
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* The advertised listener must carry the mapped host port, known only now
|
|
26
|
+
* (ports were allocated before boot) — the reason this hook exists at
|
|
27
|
+
* all. EXTERNAL advertises that mapped host port for host clients;
|
|
28
|
+
* INTERNAL advertises the fixed alias:port siblings resolve on the
|
|
29
|
+
* container network. See `KafkaContainer.customizeSpec` for the same
|
|
30
|
+
* trick applied to a single advertised listener.
|
|
31
|
+
*/
|
|
32
|
+
customizeSpec(spec, mapped) {
|
|
33
|
+
const command = [
|
|
34
|
+
"redpanda",
|
|
35
|
+
"start",
|
|
36
|
+
"--mode",
|
|
37
|
+
"dev-container",
|
|
38
|
+
"--smp",
|
|
39
|
+
"1",
|
|
40
|
+
"--kafka-addr",
|
|
41
|
+
`EXTERNAL://0.0.0.0:${EXTERNAL_PORT},INTERNAL://0.0.0.0:${INTERNAL_PORT}`,
|
|
42
|
+
"--advertise-kafka-addr",
|
|
43
|
+
`EXTERNAL://127.0.0.1:${mapped(EXTERNAL_PORT)},INTERNAL://${INTERNAL_ALIAS}:${INTERNAL_PORT}`,
|
|
44
|
+
"--schema-registry-addr",
|
|
45
|
+
`0.0.0.0:${SCHEMA_REGISTRY_PORT}`,
|
|
46
|
+
];
|
|
47
|
+
return { ...spec, command };
|
|
48
|
+
}
|
|
49
|
+
/** The `PLAINTEXT://` bootstrap-servers address for the running broker (EXTERNAL listener). */
|
|
50
|
+
get bootstrapServers() {
|
|
51
|
+
return `PLAINTEXT://${this.host}:${this.getMappedPort(EXTERNAL_PORT)}`;
|
|
52
|
+
}
|
|
53
|
+
/** The schema registry's base URI for the running broker. */
|
|
54
|
+
get schemaRegistryUrl() {
|
|
55
|
+
return `http://${this.host}:${this.getMappedPort(SCHEMA_REGISTRY_PORT)}`;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=redpanda.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redpanda.js","sourceRoot":"","sources":["../../src/modules/redpanda.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAGvC,MAAM,aAAa,GAAG,IAAI,CAAC;AAC3B,MAAM,aAAa,GAAG,IAAI,CAAC;AAC3B,MAAM,oBAAoB,GAAG,IAAI,CAAC;AAElC,2EAA2E;AAC3E,uCAAuC;AACvC,MAAM,cAAc,GAAG,UAAU,CAAC;AAElC;;;;;;GAMG;AACH,MAAM,OAAO,iBAAkB,SAAQ,gBAAgB;IACrD,YAAY,KAAK,GAAG,+BAA+B;QACjD,KAAK,CAAC,KAAK,CAAC,CAAC;QACb,IAAI,CAAC,gBAAgB,CAAC,aAAa,EAAE,aAAa,EAAE,oBAAoB,CAAC,CAAC,UAAU,CAClF,IAAI,CAAC,aAAa,CAAC,mCAAmC,CAAC,CACxD,CAAC;IACJ,CAAC;IAED,MAAM,CAAU,KAAK,CAAC,KAAK,CACzB,KAAK,GAAG,+BAA+B;QAEvC,OAAO,CAAC,MAAM,IAAI,iBAAiB,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,CAAsB,CAAC;IAC3E,CAAC;IAED;;;;;;;OAOG;IACgB,aAAa,CAAC,IAAmB,EAAE,MAAiC;QACrF,MAAM,OAAO,GAAG;YACd,UAAU;YACV,OAAO;YACP,QAAQ;YACR,eAAe;YACf,OAAO;YACP,GAAG;YACH,cAAc;YACd,sBAAsB,aAAa,uBAAuB,aAAa,EAAE;YACzE,wBAAwB;YACxB,wBAAwB,MAAM,CAAC,aAAa,CAAC,eAAe,cAAc,IAAI,aAAa,EAAE;YAC7F,wBAAwB;YACxB,WAAW,oBAAoB,EAAE;SAClC,CAAC;QACF,OAAO,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,CAAC;IAC9B,CAAC;IAED,+FAA+F;IAC/F,IAAI,gBAAgB;QAClB,OAAO,eAAe,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,aAAa,CAAC,aAAa,CAAC,EAAE,CAAC;IACzE,CAAC;IAED,6DAA6D;IAC7D,IAAI,iBAAiB;QACnB,OAAO,UAAU,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,aAAa,CAAC,oBAAoB,CAAC,EAAE,CAAC;IAC3E,CAAC;CACF"}
|