testcontainers 12.2.0 → 12.2.1

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.
Files changed (123) hide show
  1. package/build/common/file-lock.js +3 -3
  2. package/build/common/hash.js +2 -2
  3. package/build/common/index.d.ts +2 -3
  4. package/build/common/index.js +2 -4
  5. package/build/common/retry.d.ts +1 -1
  6. package/build/common/uuid.js +2 -2
  7. package/build/container-runtime/auth/auths.d.ts +2 -2
  8. package/build/container-runtime/auth/cred-helpers.d.ts +1 -1
  9. package/build/container-runtime/auth/credential-provider.d.ts +2 -2
  10. package/build/container-runtime/auth/credential-provider.js +3 -3
  11. package/build/container-runtime/auth/creds-store.d.ts +2 -2
  12. package/build/container-runtime/auth/creds-store.js +1 -1
  13. package/build/container-runtime/auth/get-auth-config.d.ts +1 -1
  14. package/build/container-runtime/auth/get-auth-config.js +7 -7
  15. package/build/container-runtime/auth/registry-auth-locator.d.ts +1 -1
  16. package/build/container-runtime/auth/registry-matches.js +1 -1
  17. package/build/container-runtime/clients/client.d.ts +5 -5
  18. package/build/container-runtime/clients/compose/compose-client.d.ts +1 -1
  19. package/build/container-runtime/clients/compose/compose-client.js +1 -3
  20. package/build/container-runtime/clients/compose/default-compose-options.d.ts +2 -2
  21. package/build/container-runtime/clients/compose/default-compose-options.js +5 -3
  22. package/build/container-runtime/clients/compose/types.d.ts +3 -2
  23. package/build/container-runtime/clients/container/container-client.d.ts +5 -4
  24. package/build/container-runtime/clients/container/docker-container-client.d.ts +6 -5
  25. package/build/container-runtime/clients/container/docker-container-client.js +8 -9
  26. package/build/container-runtime/clients/container/types.d.ts +1 -3
  27. package/build/container-runtime/clients/image/docker-image-client.d.ts +4 -3
  28. package/build/container-runtime/clients/image/docker-image-client.js +11 -10
  29. package/build/container-runtime/clients/image/image-client.d.ts +2 -2
  30. package/build/container-runtime/clients/network/docker-network-client.d.ts +3 -2
  31. package/build/container-runtime/clients/network/network-client.d.ts +1 -1
  32. package/build/container-runtime/image-name.js +2 -2
  33. package/build/container-runtime/index.d.ts +1 -1
  34. package/build/container-runtime/strategies/configuration-strategy.d.ts +2 -2
  35. package/build/container-runtime/strategies/configuration-strategy.js +7 -7
  36. package/build/container-runtime/strategies/npipe-socket-strategy.d.ts +2 -2
  37. package/build/container-runtime/strategies/rootless-unix-socket-strategy.d.ts +2 -2
  38. package/build/container-runtime/strategies/rootless-unix-socket-strategy.js +9 -9
  39. package/build/container-runtime/strategies/strategy.d.ts +1 -1
  40. package/build/container-runtime/strategies/testcontainers-host-strategy.d.ts +2 -2
  41. package/build/container-runtime/strategies/testcontainers-host-strategy.js +2 -2
  42. package/build/container-runtime/strategies/types.d.ts +1 -1
  43. package/build/container-runtime/strategies/unix-socket-strategy.d.ts +2 -2
  44. package/build/container-runtime/strategies/unix-socket-strategy.js +2 -2
  45. package/build/container-runtime/strategies/utils/config.js +12 -12
  46. package/build/container-runtime/utils/attach-container.d.ts +2 -2
  47. package/build/container-runtime/utils/demux-stream.d.ts +2 -2
  48. package/build/container-runtime/utils/demux-stream.js +2 -2
  49. package/build/container-runtime/utils/image-exists.d.ts +2 -2
  50. package/build/container-runtime/utils/lookup-host-ips.d.ts +1 -1
  51. package/build/container-runtime/utils/lookup-host-ips.js +4 -4
  52. package/build/container-runtime/utils/pull-image.d.ts +2 -2
  53. package/build/container-runtime/utils/remote-container-runtime-socket-path.d.ts +1 -1
  54. package/build/container-runtime/utils/remote-container-runtime-socket-path.js +2 -2
  55. package/build/container-runtime/utils/resolve-host.d.ts +2 -2
  56. package/build/container-runtime/utils/resolve-host.js +4 -4
  57. package/build/container-runtime/utils/run-in-container.d.ts +1 -1
  58. package/build/container-runtime/utils/run-in-container.js +2 -1
  59. package/build/container-runtime/utils/start-container.d.ts +1 -1
  60. package/build/docker-compose-environment/docker-compose-environment.d.ts +5 -5
  61. package/build/docker-compose-environment/docker-compose-environment.js +13 -7
  62. package/build/docker-compose-environment/started-docker-compose-environment.d.ts +2 -2
  63. package/build/docker-compose-environment/stopped-docker-compose-environment.d.ts +1 -1
  64. package/build/generic-container/abstract-started-container.d.ts +3 -3
  65. package/build/generic-container/abstract-stopped-container.d.ts +1 -1
  66. package/build/generic-container/generic-container-builder.d.ts +3 -3
  67. package/build/generic-container/generic-container-builder.js +5 -5
  68. package/build/generic-container/generic-container.d.ts +9 -9
  69. package/build/generic-container/generic-container.js +10 -4
  70. package/build/generic-container/inspect-container-util-ports-exposed.d.ts +1 -1
  71. package/build/generic-container/inspect-container-util-ports-exposed.js +1 -1
  72. package/build/generic-container/started-generic-container.d.ts +6 -5
  73. package/build/generic-container/started-generic-container.js +19 -16
  74. package/build/generic-container/stopped-generic-container.d.ts +2 -2
  75. package/build/index.d.ts +4 -4
  76. package/build/index.js +3 -3
  77. package/build/network/network.d.ts +3 -3
  78. package/build/port-forwarder/port-forwarder.d.ts +2 -3
  79. package/build/port-forwarder/port-forwarder.js +25 -19
  80. package/build/reaper/reaper.d.ts +1 -1
  81. package/build/reaper/reaper.js +21 -19
  82. package/build/socat/socat-container.d.ts +0 -2
  83. package/build/socat/socat-container.js +0 -3
  84. package/build/test-container.d.ts +6 -6
  85. package/build/test-containers.js +2 -1
  86. package/build/types.d.ts +3 -4
  87. package/build/utils/bound-ports.d.ts +3 -3
  88. package/build/utils/bound-ports.js +2 -2
  89. package/build/utils/dockerfile-parser.d.ts +1 -1
  90. package/build/utils/dockerfile-parser.js +2 -2
  91. package/build/utils/labels.d.ts +0 -2
  92. package/build/utils/labels.js +5 -5
  93. package/build/utils/map-inspect-result.d.ts +2 -2
  94. package/build/utils/map-inspect-result.js +12 -13
  95. package/build/utils/pull-policy.js +1 -0
  96. package/build/version.d.ts +1 -1
  97. package/build/version.js +1 -1
  98. package/build/wait-strategies/composite-wait-strategy.d.ts +3 -3
  99. package/build/wait-strategies/composite-wait-strategy.js +3 -1
  100. package/build/wait-strategies/health-check-wait-strategy.d.ts +1 -1
  101. package/build/wait-strategies/host-port-wait-strategy.d.ts +2 -2
  102. package/build/wait-strategies/http-wait-strategy.d.ts +2 -2
  103. package/build/wait-strategies/http-wait-strategy.js +4 -7
  104. package/build/wait-strategies/log-wait-strategy.d.ts +3 -3
  105. package/build/wait-strategies/log-wait-strategy.js +1 -1
  106. package/build/wait-strategies/one-shot-startup-startegy.d.ts +2 -2
  107. package/build/wait-strategies/shell-wait-strategy.d.ts +1 -1
  108. package/build/wait-strategies/startup-check-strategy.d.ts +1 -2
  109. package/build/wait-strategies/startup-check-strategy.js +0 -3
  110. package/build/wait-strategies/utils/health-check.d.ts +2 -4
  111. package/build/wait-strategies/utils/health-check.js +4 -6
  112. package/build/wait-strategies/utils/port-check.d.ts +2 -2
  113. package/build/wait-strategies/utils/port-check.js +2 -2
  114. package/build/wait-strategies/utils/undici-response-parser.d.ts +1 -1
  115. package/build/wait-strategies/utils/undici-response-parser.js +2 -2
  116. package/build/wait-strategies/utils/wait-strategy-selector.d.ts +4 -4
  117. package/build/wait-strategies/wait-for-container.d.ts +4 -4
  118. package/build/wait-strategies/wait-strategy.d.ts +2 -2
  119. package/build/wait-strategies/wait.d.ts +3 -3
  120. package/build/wait-strategies/wait.js +1 -0
  121. package/package.json +2 -3
  122. package/build/common/streams.d.ts +0 -6
  123. package/build/common/streams.js +0 -12
@@ -4,11 +4,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.StartedGenericContainer = void 0;
7
+ const node_fs_1 = require("node:fs");
7
8
  const archiver_1 = __importDefault(require("archiver"));
8
9
  const async_lock_1 = __importDefault(require("async-lock"));
9
- const fs_1 = require("fs");
10
10
  const common_1 = require("../common");
11
11
  const container_runtime_1 = require("../container-runtime");
12
+ // biome-ignore lint/suspicious/noImportCycles: Ryuk and sshd run as GenericContainers; only dereferenced at runtime
12
13
  const reaper_1 = require("../reaper/reaper");
13
14
  const bound_ports_1 = require("../utils/bound-ports");
14
15
  const labels_1 = require("../utils/labels");
@@ -139,14 +140,13 @@ class StartedGenericContainer {
139
140
  return this.getNetworkSettings()[networkName].ipAddress;
140
141
  }
141
142
  getNetworkSettings() {
142
- return Object.entries(this.inspectResult.NetworkSettings.Networks)
143
- .map(([networkName, network]) => ({
144
- [networkName]: {
143
+ return Object.fromEntries(Object.entries(this.inspectResult.NetworkSettings.Networks).map(([networkName, network]) => [
144
+ networkName,
145
+ {
145
146
  networkId: network.NetworkID,
146
147
  ipAddress: network.IPAddress,
147
148
  },
148
- }))
149
- .reduce((prev, next) => ({ ...prev, ...next }), {});
149
+ ]));
150
150
  }
151
151
  async copyFilesToContainer(filesToCopy) {
152
152
  common_1.log.debug(`Copying files to container...`, { containerId: this.container.id });
@@ -154,29 +154,32 @@ class StartedGenericContainer {
154
154
  const tar = (0, archiver_1.default)("tar");
155
155
  const filesToCopyWithStats = await Promise.all(filesToCopy.map(async (fileToCopy) => ({
156
156
  ...fileToCopy,
157
- stats: await fs_1.promises.stat(fileToCopy.source),
157
+ stats: await node_fs_1.promises.stat(fileToCopy.source),
158
158
  })));
159
- filesToCopyWithStats.forEach(({ source, target, mode, stats }) => tar.file(source, { name: target, mode, stats }));
160
- tar.finalize();
161
- await client.container.putArchive(this.container, tar, "/");
159
+ filesToCopyWithStats.forEach(({ source, target, mode, stats }) => {
160
+ tar.file(source, { name: target, mode, stats });
161
+ });
162
+ await Promise.all([tar.finalize(), client.container.putArchive(this.container, tar, "/")]);
162
163
  common_1.log.debug(`Copied files to container`, { containerId: this.container.id });
163
164
  }
164
165
  async copyDirectoriesToContainer(directoriesToCopy) {
165
166
  common_1.log.debug(`Copying directories to container...`, { containerId: this.container.id });
166
167
  const client = await (0, container_runtime_1.getContainerRuntimeClient)();
167
168
  const tar = (0, archiver_1.default)("tar");
168
- directoriesToCopy.forEach(({ source, target }) => tar.directory(source, target));
169
- tar.finalize();
170
- await client.container.putArchive(this.container, tar, "/");
169
+ directoriesToCopy.forEach(({ source, target }) => {
170
+ tar.directory(source, target);
171
+ });
172
+ await Promise.all([tar.finalize(), client.container.putArchive(this.container, tar, "/")]);
171
173
  common_1.log.debug(`Copied directories to container`, { containerId: this.container.id });
172
174
  }
173
175
  async copyContentToContainer(contentsToCopy) {
174
176
  common_1.log.debug(`Copying content to container...`, { containerId: this.container.id });
175
177
  const client = await (0, container_runtime_1.getContainerRuntimeClient)();
176
178
  const tar = (0, archiver_1.default)("tar");
177
- contentsToCopy.forEach(({ content, target, mode }) => tar.append(content, { name: target, mode: mode }));
178
- tar.finalize();
179
- await client.container.putArchive(this.container, tar, "/");
179
+ contentsToCopy.forEach(({ content, target, mode }) => {
180
+ tar.append(content, { name: target, mode: mode });
181
+ });
182
+ await Promise.all([tar.finalize(), client.container.putArchive(this.container, tar, "/")]);
180
183
  common_1.log.debug(`Copied content to container`, { containerId: this.container.id });
181
184
  }
182
185
  async copyArchiveToContainer(tar, target = "/", options) {
@@ -1,5 +1,5 @@
1
- import Dockerode from "dockerode";
2
- import { StoppedTestContainer } from "../test-container";
1
+ import type Dockerode from "dockerode";
2
+ import type { StoppedTestContainer } from "../test-container";
3
3
  export declare class StoppedGenericContainer implements StoppedTestContainer {
4
4
  private readonly container;
5
5
  constructor(container: Dockerode.Container);
package/build/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- export { IntervalRetry, RandomUuid, Retry, Uuid, log, randomUuid } from "./common";
2
- export { ContainerRuntimeClient, ImageName, getContainerRuntimeClient } from "./container-runtime";
1
+ export { IntervalRetry, log, RandomUuid, Retry, randomUuid, Uuid } from "./common";
2
+ export { ContainerRuntimeClient, getContainerRuntimeClient, ImageName } from "./container-runtime";
3
3
  export { DockerComposeEnvironment } from "./docker-compose-environment/docker-compose-environment";
4
4
  export { DownedDockerComposeEnvironment } from "./docker-compose-environment/downed-docker-compose-environment";
5
5
  export { StartedDockerComposeEnvironment } from "./docker-compose-environment/started-docker-compose-environment";
@@ -13,10 +13,10 @@ export { getReaper } from "./reaper/reaper";
13
13
  export { SocatContainer, StartedSocatContainer } from "./socat/socat-container";
14
14
  export { RestartOptions, StartedTestContainer, StopOptions, StoppedTestContainer, TestContainer, } from "./test-container";
15
15
  export { TestContainers } from "./test-containers";
16
- export { CommitOptions, Content, CopyToContainerOptions, ExecOptions, ExecResult, InspectResult } from "./types";
16
+ export { BindMode, CommitOptions, Content, ContentToCopy, CopyToContainerOptions, Environment, ExecOptions, ExecResult, FileToCopy, HealthCheck, InspectResult, Labels, } from "./types";
17
17
  export { BoundPorts } from "./utils/bound-ports";
18
18
  export { LABEL_TESTCONTAINERS_SESSION_ID } from "./utils/labels";
19
- export { PortWithBinding, PortWithOptionalBinding, getContainerPort, hasHostBinding } from "./utils/port";
19
+ export { getContainerPort, hasHostBinding, PortWithBinding, PortWithOptionalBinding } from "./utils/port";
20
20
  export { PortGenerator, RandomPortGenerator } from "./utils/port-generator";
21
21
  export { ImagePullPolicy, PullPolicy } from "./utils/pull-policy";
22
22
  export { HttpWaitStrategyOptions } from "./wait-strategies/http-wait-strategy";
package/build/index.js CHANGED
@@ -1,15 +1,15 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.waitForContainer = exports.Wait = exports.StartupCheckStrategy = exports.PullPolicy = exports.RandomPortGenerator = exports.hasHostBinding = exports.getContainerPort = exports.LABEL_TESTCONTAINERS_SESSION_ID = exports.BoundPorts = exports.TestContainers = exports.StartedSocatContainer = exports.SocatContainer = exports.getReaper = exports.StoppedNetwork = exports.StartedNetwork = exports.Network = exports.GenericContainerBuilder = exports.GenericContainer = exports.AbstractStoppedContainer = exports.AbstractStartedContainer = exports.StoppedDockerComposeEnvironment = exports.StartedDockerComposeEnvironment = exports.DownedDockerComposeEnvironment = exports.DockerComposeEnvironment = exports.getContainerRuntimeClient = exports.ImageName = exports.ContainerRuntimeClient = exports.randomUuid = exports.log = exports.RandomUuid = exports.IntervalRetry = void 0;
3
+ exports.waitForContainer = exports.Wait = exports.StartupCheckStrategy = exports.PullPolicy = exports.RandomPortGenerator = exports.hasHostBinding = exports.getContainerPort = exports.LABEL_TESTCONTAINERS_SESSION_ID = exports.BoundPorts = exports.TestContainers = exports.StartedSocatContainer = exports.SocatContainer = exports.getReaper = exports.StoppedNetwork = exports.StartedNetwork = exports.Network = exports.GenericContainerBuilder = exports.GenericContainer = exports.AbstractStoppedContainer = exports.AbstractStartedContainer = exports.StoppedDockerComposeEnvironment = exports.StartedDockerComposeEnvironment = exports.DownedDockerComposeEnvironment = exports.DockerComposeEnvironment = exports.ImageName = exports.getContainerRuntimeClient = exports.ContainerRuntimeClient = exports.randomUuid = exports.RandomUuid = exports.log = exports.IntervalRetry = void 0;
4
4
  var common_1 = require("./common");
5
5
  Object.defineProperty(exports, "IntervalRetry", { enumerable: true, get: function () { return common_1.IntervalRetry; } });
6
- Object.defineProperty(exports, "RandomUuid", { enumerable: true, get: function () { return common_1.RandomUuid; } });
7
6
  Object.defineProperty(exports, "log", { enumerable: true, get: function () { return common_1.log; } });
7
+ Object.defineProperty(exports, "RandomUuid", { enumerable: true, get: function () { return common_1.RandomUuid; } });
8
8
  Object.defineProperty(exports, "randomUuid", { enumerable: true, get: function () { return common_1.randomUuid; } });
9
9
  var container_runtime_1 = require("./container-runtime");
10
10
  Object.defineProperty(exports, "ContainerRuntimeClient", { enumerable: true, get: function () { return container_runtime_1.ContainerRuntimeClient; } });
11
- Object.defineProperty(exports, "ImageName", { enumerable: true, get: function () { return container_runtime_1.ImageName; } });
12
11
  Object.defineProperty(exports, "getContainerRuntimeClient", { enumerable: true, get: function () { return container_runtime_1.getContainerRuntimeClient; } });
12
+ Object.defineProperty(exports, "ImageName", { enumerable: true, get: function () { return container_runtime_1.ImageName; } });
13
13
  var docker_compose_environment_1 = require("./docker-compose-environment/docker-compose-environment");
14
14
  Object.defineProperty(exports, "DockerComposeEnvironment", { enumerable: true, get: function () { return docker_compose_environment_1.DockerComposeEnvironment; } });
15
15
  var downed_docker_compose_environment_1 = require("./docker-compose-environment/downed-docker-compose-environment");
@@ -1,6 +1,6 @@
1
- import Dockerode from "dockerode";
2
- import { Uuid } from "../common";
3
- import { ContainerRuntimeClient } from "../container-runtime";
1
+ import type Dockerode from "dockerode";
2
+ import { type Uuid } from "../common";
3
+ import { type ContainerRuntimeClient } from "../container-runtime";
4
4
  export declare class Network {
5
5
  private readonly uuid;
6
6
  constructor(uuid?: Uuid);
@@ -1,12 +1,11 @@
1
- import { SshConnection } from "ssh-remote-port-forward";
1
+ import { type SshConnection } from "ssh-remote-port-forward";
2
2
  export declare const SSHD_IMAGE: string;
3
3
  declare class PortForwarder {
4
4
  private readonly sshConnection;
5
5
  private readonly containerId;
6
6
  private readonly networkId;
7
7
  private readonly ipAddress;
8
- private readonly networkName;
9
- constructor(sshConnection: SshConnection, containerId: string, networkId: string, ipAddress: string, networkName: string);
8
+ constructor(sshConnection: SshConnection, containerId: string, networkId: string, ipAddress: string);
10
9
  exposeHostPort(port: number): Promise<void>;
11
10
  getContainerId(): string;
12
11
  getNetworkId(): string;
@@ -4,24 +4,24 @@ exports.PortForwarderInstance = exports.SSHD_IMAGE = void 0;
4
4
  const ssh_remote_port_forward_1 = require("ssh-remote-port-forward");
5
5
  const common_1 = require("../common");
6
6
  const container_runtime_1 = require("../container-runtime");
7
+ // biome-ignore lint/suspicious/noImportCycles: Ryuk and sshd run as GenericContainers; only dereferenced at runtime
7
8
  const generic_container_1 = require("../generic-container/generic-container");
9
+ // biome-ignore lint/suspicious/noImportCycles: Ryuk and sshd run as GenericContainers; only dereferenced at runtime
8
10
  const reaper_1 = require("../reaper/reaper");
9
11
  const labels_1 = require("../utils/labels");
10
- exports.SSHD_IMAGE = process.env["SSHD_CONTAINER_IMAGE"]
11
- ? container_runtime_1.ImageName.fromString(process.env["SSHD_CONTAINER_IMAGE"]).string
12
+ exports.SSHD_IMAGE = process.env.SSHD_CONTAINER_IMAGE
13
+ ? container_runtime_1.ImageName.fromString(process.env.SSHD_CONTAINER_IMAGE).string
12
14
  : container_runtime_1.ImageName.fromString("testcontainers/sshd:1.4.0").string;
13
15
  class PortForwarder {
14
16
  sshConnection;
15
17
  containerId;
16
18
  networkId;
17
19
  ipAddress;
18
- networkName;
19
- constructor(sshConnection, containerId, networkId, ipAddress, networkName) {
20
+ constructor(sshConnection, containerId, networkId, ipAddress) {
20
21
  this.sshConnection = sshConnection;
21
22
  this.containerId = containerId;
22
23
  this.networkId = networkId;
23
24
  this.ipAddress = ipAddress;
24
- this.networkName = networkName;
25
25
  }
26
26
  async exposeHostPort(port) {
27
27
  common_1.log.info(`Exposing host port ${port}...`);
@@ -38,30 +38,31 @@ class PortForwarder {
38
38
  return this.ipAddress;
39
39
  }
40
40
  }
41
+ // biome-ignore lint/complexity/noStaticOnlyClass: singleton holder with private static state
41
42
  class PortForwarderInstance {
42
43
  static USERNAME = "root";
43
44
  static PASSWORD = "root";
44
45
  static instance;
45
46
  static isRunning() {
46
- return this.instance !== undefined;
47
+ return PortForwarderInstance.instance !== undefined;
47
48
  }
48
49
  static async getInstance() {
49
- if (!this.instance) {
50
+ if (!PortForwarderInstance.instance) {
50
51
  await (0, common_1.withFileLock)("testcontainers-node-sshd.lock", async () => {
51
52
  const client = await (0, container_runtime_1.getContainerRuntimeClient)();
52
53
  const reaper = await (0, reaper_1.getReaper)(client);
53
54
  const sessionId = reaper.sessionId;
54
- const portForwarderContainer = await this.findPortForwarderContainer(client, sessionId);
55
+ const portForwarderContainer = await PortForwarderInstance.findPortForwarderContainer(client, sessionId);
55
56
  if (portForwarderContainer) {
56
- this.instance = this.reuseInstance(client, portForwarderContainer, sessionId);
57
+ PortForwarderInstance.instance = PortForwarderInstance.reuseInstance(client, portForwarderContainer, sessionId);
57
58
  }
58
59
  else {
59
- this.instance = this.createInstance();
60
+ PortForwarderInstance.instance = PortForwarderInstance.createInstance();
60
61
  }
61
- await this.instance;
62
+ await PortForwarderInstance.instance;
62
63
  });
63
64
  }
64
- return this.instance;
65
+ return PortForwarderInstance.instance;
65
66
  }
66
67
  static async findPortForwarderContainer(client, sessionId) {
67
68
  const containers = await client.container.list();
@@ -72,7 +73,7 @@ class PortForwarderInstance {
72
73
  static async reuseInstance(client, container, sessionId) {
73
74
  common_1.log.debug(`Reusing existing PortForwarder for session "${sessionId}"...`);
74
75
  const host = client.info.containerRuntime.host;
75
- const port = container.Ports.find((port) => port.PrivatePort == 22)?.PublicPort;
76
+ const port = container.Ports.find((port) => port.PrivatePort === 22)?.PublicPort;
76
77
  if (!port) {
77
78
  throw new Error("Expected PortForwarder to map exposed port 22");
78
79
  }
@@ -91,32 +92,37 @@ class PortForwarderInstance {
91
92
  const networkName = networks[0][0];
92
93
  const networkId = container.NetworkSettings.Networks[networkName].NetworkID;
93
94
  const ipAddress = container.NetworkSettings.Networks[networkName].IPAddress;
94
- return new PortForwarder(connection, containerId, networkId, ipAddress, networkName);
95
+ return new PortForwarder(connection, containerId, networkId, ipAddress);
95
96
  }
96
97
  static async createInstance() {
97
98
  common_1.log.debug(`Creating new Port Forwarder...`);
98
99
  const client = await (0, container_runtime_1.getContainerRuntimeClient)();
99
100
  const reaper = await (0, reaper_1.getReaper)(client);
100
- const containerPort = process.env["TESTCONTAINERS_SSHD_PORT"]
101
- ? { container: 22, host: Number(process.env["TESTCONTAINERS_SSHD_PORT"]) }
101
+ const containerPort = process.env.TESTCONTAINERS_SSHD_PORT
102
+ ? { container: 22, host: Number(process.env.TESTCONTAINERS_SSHD_PORT) }
102
103
  : 22;
103
104
  const container = await new generic_container_1.GenericContainer(exports.SSHD_IMAGE)
104
105
  .withName(`testcontainers-port-forwarder-${reaper.sessionId}`)
105
106
  .withExposedPorts(containerPort)
106
- .withEnvironment({ PASSWORD: this.PASSWORD })
107
+ .withEnvironment({ PASSWORD: PortForwarderInstance.PASSWORD })
107
108
  .withLabels({ [labels_1.LABEL_TESTCONTAINERS_SSHD]: "true" })
108
109
  .start();
109
110
  const host = client.info.containerRuntime.host;
110
111
  const port = container.getMappedPort(22);
111
112
  common_1.log.debug(`Connecting to Port Forwarder on "${host}:${port}"...`);
112
- const connection = await (0, ssh_remote_port_forward_1.createSshConnection)({ host, port, username: this.USERNAME, password: this.PASSWORD });
113
+ const connection = await (0, ssh_remote_port_forward_1.createSshConnection)({
114
+ host,
115
+ port,
116
+ username: PortForwarderInstance.USERNAME,
117
+ password: PortForwarderInstance.PASSWORD,
118
+ });
113
119
  common_1.log.debug(`Connected to Port Forwarder on "${host}:${port}"`);
114
120
  connection.unref();
115
121
  const containerId = container.getId();
116
122
  const networkName = container.getNetworkNames()[0];
117
123
  const networkId = container.getNetworkId(networkName);
118
124
  const ipAddress = container.getIpAddress(networkName);
119
- return new PortForwarder(connection, containerId, networkId, ipAddress, networkName);
125
+ return new PortForwarder(connection, containerId, networkId, ipAddress);
120
126
  }
121
127
  }
122
128
  exports.PortForwarderInstance = PortForwarderInstance;
@@ -1,4 +1,4 @@
1
- import { ContainerRuntimeClient } from "../container-runtime";
1
+ import { type ContainerRuntimeClient } from "../container-runtime";
2
2
  /**
3
3
  * Resolve the Ryuk reaper image name. Read lazily so that callers (and tests)
4
4
  * can set `process.env.RYUK_CONTAINER_IMAGE` _after_ this module is imported —
@@ -2,10 +2,11 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getReaperImage = getReaperImage;
4
4
  exports.getReaper = getReaper;
5
- const net_1 = require("net");
6
- const os_1 = require("os");
5
+ const node_net_1 = require("node:net");
6
+ const node_os_1 = require("node:os");
7
7
  const common_1 = require("../common");
8
8
  const container_runtime_1 = require("../container-runtime");
9
+ // biome-ignore lint/suspicious/noImportCycles: Ryuk and sshd run as GenericContainers; only dereferenced at runtime
9
10
  const generic_container_1 = require("../generic-container/generic-container");
10
11
  const labels_1 = require("../utils/labels");
11
12
  const wait_1 = require("../wait-strategies/wait");
@@ -17,8 +18,8 @@ const wait_1 = require("../wait-strategies/wait");
17
18
  * See https://github.com/testcontainers/testcontainers-node/issues/1310.
18
19
  */
19
20
  function getReaperImage() {
20
- return process.env["RYUK_CONTAINER_IMAGE"]
21
- ? container_runtime_1.ImageName.fromString(process.env["RYUK_CONTAINER_IMAGE"]).string
21
+ return process.env.RYUK_CONTAINER_IMAGE
22
+ ? container_runtime_1.ImageName.fromString(process.env.RYUK_CONTAINER_IMAGE).string
22
23
  : container_runtime_1.ImageName.fromString("testcontainers/ryuk:0.14.0").string;
23
24
  }
24
25
  let reaper;
@@ -27,7 +28,7 @@ async function getReaper(client) {
27
28
  if (reaper) {
28
29
  return reaper;
29
30
  }
30
- const userId = (0, os_1.userInfo)().uid;
31
+ const userId = (0, node_os_1.userInfo)().uid;
31
32
  reaper = await (0, common_1.withFileLock)(`testcontainers-node-${userId}.lock`, async () => {
32
33
  const reaperContainers = await findReaperContainers(client);
33
34
  if (process.env.TESTCONTAINERS_RYUK_DISABLED === "true") {
@@ -35,9 +36,8 @@ async function getReaper(client) {
35
36
  return new DisabledReaper(sessionId, "");
36
37
  }
37
38
  for (const reaperContainer of reaperContainers) {
38
- const existingSessionId = reaperContainer.Labels[labels_1.LABEL_TESTCONTAINERS_SESSION_ID] ?? new common_1.RandomUuid().nextUuid();
39
39
  try {
40
- sessionId = existingSessionId;
40
+ sessionId = reaperContainer.Labels[labels_1.LABEL_TESTCONTAINERS_SESSION_ID];
41
41
  return await useExistingReaper(reaperContainer, sessionId, client.info.containerRuntime.host);
42
42
  }
43
43
  catch (error) {
@@ -58,12 +58,14 @@ async function findReaperContainers(client) {
58
58
  return containers
59
59
  .filter((container) => container.State === "running" &&
60
60
  container.Labels[labels_1.LABEL_TESTCONTAINERS_RYUK] === "true" &&
61
- container.Labels["TESTCONTAINERS_RYUK_TEST_LABEL"] !== "true")
61
+ container.Labels[labels_1.LABEL_TESTCONTAINERS_LANG] === "node" &&
62
+ !!container.Labels[labels_1.LABEL_TESTCONTAINERS_SESSION_ID] &&
63
+ container.Labels.TESTCONTAINERS_RYUK_TEST_LABEL !== "true")
62
64
  .sort((a, b) => b.Created - a.Created);
63
65
  }
64
66
  async function useExistingReaper(reaperContainer, sessionId, host) {
65
67
  common_1.log.debug(`Reusing existing Reaper for session "${sessionId}"...`);
66
- const reaperPort = reaperContainer.Ports.find((port) => port.PrivatePort == 8080)?.PublicPort;
68
+ const reaperPort = reaperContainer.Ports.find((port) => port.PrivatePort === 8080)?.PublicPort;
67
69
  if (!reaperPort) {
68
70
  throw new Error("Expected Reaper to map exposed port 8080");
69
71
  }
@@ -74,22 +76,22 @@ async function createNewReaper(sessionId, remoteSocketPath) {
74
76
  common_1.log.debug(`Creating new Reaper for session "${sessionId}" with socket path "${remoteSocketPath}"...`);
75
77
  const container = new generic_container_1.GenericContainer(getReaperImage())
76
78
  .withName(`testcontainers-ryuk-${sessionId}`)
77
- .withExposedPorts(process.env["TESTCONTAINERS_RYUK_PORT"]
78
- ? { container: 8080, host: parseInt(process.env["TESTCONTAINERS_RYUK_PORT"]) }
79
+ .withExposedPorts(process.env.TESTCONTAINERS_RYUK_PORT
80
+ ? { container: 8080, host: parseInt(process.env.TESTCONTAINERS_RYUK_PORT, 10) }
79
81
  : 8080)
80
82
  .withBindMounts([{ source: remoteSocketPath, target: "/var/run/docker.sock" }])
81
83
  .withLabels({ [labels_1.LABEL_TESTCONTAINERS_SESSION_ID]: sessionId })
82
84
  .withWaitStrategy(wait_1.Wait.forLogMessage(/.*Started.*/));
83
- if (process.env["TESTCONTAINERS_RYUK_VERBOSE"]) {
84
- container.withEnvironment({ RYUK_VERBOSE: process.env["TESTCONTAINERS_RYUK_VERBOSE"] });
85
+ if (process.env.TESTCONTAINERS_RYUK_VERBOSE) {
86
+ container.withEnvironment({ RYUK_VERBOSE: process.env.TESTCONTAINERS_RYUK_VERBOSE });
85
87
  }
86
- if (process.env["TESTCONTAINERS_RYUK_RECONNECTION_TIMEOUT"]) {
87
- container.withEnvironment({ RYUK_RECONNECTION_TIMEOUT: process.env["TESTCONTAINERS_RYUK_RECONNECTION_TIMEOUT"] });
88
+ if (process.env.TESTCONTAINERS_RYUK_RECONNECTION_TIMEOUT) {
89
+ container.withEnvironment({ RYUK_RECONNECTION_TIMEOUT: process.env.TESTCONTAINERS_RYUK_RECONNECTION_TIMEOUT });
88
90
  }
89
- if (process.env["TESTCONTAINERS_RYUK_PRIVILEGED"] === "true") {
91
+ if (process.env.TESTCONTAINERS_RYUK_PRIVILEGED === "true") {
90
92
  container.withPrivilegedMode();
91
93
  }
92
- if (process.env["TESTCONTAINERS_RYUK_TEST_LABEL"] === "true") {
94
+ if (process.env.TESTCONTAINERS_RYUK_TEST_LABEL === "true") {
93
95
  container.withLabels({ TESTCONTAINERS_RYUK_TEST_LABEL: "true" });
94
96
  }
95
97
  const startedContainer = await container.start();
@@ -100,7 +102,7 @@ async function connectToReaperSocket(host, port, containerId) {
100
102
  const retryResult = await new common_1.IntervalRetry(1000).retryUntil((attempt) => {
101
103
  return new Promise((resolve) => {
102
104
  common_1.log.debug(`Connecting to Reaper (attempt ${attempt + 1}) on "${host}:${port}"...`, { containerId });
103
- const socket = new net_1.Socket();
105
+ const socket = new node_net_1.Socket();
104
106
  socket
105
107
  .unref()
106
108
  .on("timeout", () => common_1.log.error(`Reaper ${containerId} socket timed out`))
@@ -124,7 +126,7 @@ async function connectToReaperSocket(host, port, containerId) {
124
126
  common_1.log.error(message, { containerId });
125
127
  return new Error(message);
126
128
  }, 4000);
127
- if (retryResult instanceof net_1.Socket) {
129
+ if (retryResult instanceof node_net_1.Socket) {
128
130
  return retryResult;
129
131
  }
130
132
  else {
@@ -1,6 +1,5 @@
1
1
  import { AbstractStartedContainer } from "../generic-container/abstract-started-container";
2
2
  import { GenericContainer } from "../generic-container/generic-container";
3
- import { StartedTestContainer } from "../test-container";
4
3
  export declare class SocatContainer extends GenericContainer {
5
4
  private targets;
6
5
  constructor(image?: string);
@@ -8,5 +7,4 @@ export declare class SocatContainer extends GenericContainer {
8
7
  start(): Promise<StartedSocatContainer>;
9
8
  }
10
9
  export declare class StartedSocatContainer extends AbstractStartedContainer {
11
- constructor(startedTestcontainers: StartedTestContainer);
12
10
  }
@@ -26,8 +26,5 @@ class SocatContainer extends generic_container_1.GenericContainer {
26
26
  }
27
27
  exports.SocatContainer = SocatContainer;
28
28
  class StartedSocatContainer extends abstract_started_container_1.AbstractStartedContainer {
29
- constructor(startedTestcontainers) {
30
- super(startedTestcontainers);
31
- }
32
29
  }
33
30
  exports.StartedSocatContainer = StartedSocatContainer;
@@ -1,9 +1,9 @@
1
- import { Readable } from "stream";
2
- import { StartedNetwork } from "./network/network";
3
- import { ArchiveToCopy, BindMount, CommitOptions, ContentToCopy, CopyToContainerOptions, DirectoryToCopy, Environment, ExecOptions, ExecResult, ExtraHost, FileToCopy, Labels, ResourcesQuota, TmpFs, Ulimits } from "./types";
4
- import { PortWithOptionalBinding } from "./utils/port";
5
- import { ImagePullPolicy } from "./utils/pull-policy";
6
- import { WaitStrategy } from "./wait-strategies/wait-strategy";
1
+ import type { Readable } from "node:stream";
2
+ import type { StartedNetwork } from "./network/network";
3
+ import type { ArchiveToCopy, BindMount, CommitOptions, ContentToCopy, CopyToContainerOptions, DirectoryToCopy, Environment, ExecOptions, ExecResult, ExtraHost, FileToCopy, Labels, ResourcesQuota, TmpFs, Ulimits } from "./types";
4
+ import type { PortWithOptionalBinding } from "./utils/port";
5
+ import type { ImagePullPolicy } from "./utils/pull-policy";
6
+ import type { WaitStrategy } from "./wait-strategies/wait-strategy";
7
7
  export interface TestContainer {
8
8
  start(): Promise<StartedTestContainer>;
9
9
  withEnvironment(environment: Environment): this;
@@ -4,11 +4,12 @@ exports.TestContainers = void 0;
4
4
  const common_1 = require("./common");
5
5
  const container_runtime_1 = require("./container-runtime");
6
6
  const port_forwarder_1 = require("./port-forwarder/port-forwarder");
7
+ // biome-ignore lint/complexity/noStaticOnlyClass: public API surface, kept as a class for backwards compatibility
7
8
  class TestContainers {
8
9
  static async exposeHostPorts(...ports) {
9
10
  const portForwarder = await port_forwarder_1.PortForwarderInstance.getInstance();
10
11
  await Promise.all(ports.map((port) => portForwarder.exposeHostPort(port).catch(async (err) => {
11
- if (await this.isHostPortExposed(portForwarder.getContainerId(), port)) {
12
+ if (await TestContainers.isHostPortExposed(portForwarder.getContainerId(), port)) {
12
13
  common_1.log.debug(`Host port ${port} is already exposed`);
13
14
  }
14
15
  else {
package/build/types.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { Readable } from "stream";
2
- import { AuthConfig } from "./container-runtime/auth/types";
3
- import { ContainerCommitOptions } from "./container-runtime/clients/container/types";
1
+ import type { Readable } from "node:stream";
2
+ import type { AuthConfig } from "./container-runtime/auth/types";
3
+ import type { ContainerCommitOptions } from "./container-runtime/clients/container/types";
4
4
  export type InspectResult = {
5
5
  name: string;
6
6
  hostname: string;
@@ -17,7 +17,6 @@ export type InspectResult = {
17
17
  };
18
18
  labels: Labels;
19
19
  };
20
- export type ContainerRuntime = "docker" | "podman";
21
20
  export type Environment = {
22
21
  [key in string]: string;
23
22
  };
@@ -1,6 +1,6 @@
1
- import { HostIp } from "../container-runtime";
2
- import { HostPortBindings, InspectResult } from "../types";
3
- import { PortWithOptionalBinding } from "./port";
1
+ import type { HostIp } from "../container-runtime";
2
+ import type { HostPortBindings, InspectResult } from "../types";
3
+ import { type PortWithOptionalBinding } from "./port";
4
4
  export declare class BoundPorts {
5
5
  private readonly ports;
6
6
  getBinding(port: number | string, protocol?: string): number;
@@ -4,7 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.resolveHostPortBinding = exports.BoundPorts = void 0;
7
- const net_1 = __importDefault(require("net"));
7
+ const node_net_1 = __importDefault(require("node:net"));
8
8
  const port_1 = require("./port");
9
9
  class BoundPorts {
10
10
  ports = new Map();
@@ -79,7 +79,7 @@ const resolveHostPortBinding = (hostIps, hostPortBindings) => {
79
79
  return hostPortBindings[0].hostPort;
80
80
  }
81
81
  for (const { family } of hostIps) {
82
- const hostPortBinding = hostPortBindings.find(({ hostIp }) => net_1.default.isIP(hostIp) === family);
82
+ const hostPortBinding = hostPortBindings.find(({ hostIp }) => node_net_1.default.isIP(hostIp) === family);
83
83
  if (hostPortBinding !== undefined) {
84
84
  return hostPortBinding.hostPort;
85
85
  }
@@ -1,3 +1,3 @@
1
1
  import { ImageName } from "../container-runtime";
2
- import { BuildArgs } from "../types";
2
+ import type { BuildArgs } from "../types";
3
3
  export declare function getDockerfileImages(dockerfile: string, buildArgs: BuildArgs): Promise<ImageName[]>;
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getDockerfileImages = getDockerfileImages;
4
- const fs_1 = require("fs");
4
+ const node_fs_1 = require("node:fs");
5
5
  const common_1 = require("../common");
6
6
  const container_runtime_1 = require("../container-runtime");
7
7
  const buildArgRegex = /\${([^{]+)}/g;
@@ -17,7 +17,7 @@ async function getDockerfileImages(dockerfile, buildArgs) {
17
17
  }
18
18
  }
19
19
  async function parseImages(dockerfile) {
20
- return Array.from((await fs_1.promises.readFile(dockerfile, "utf8"))
20
+ return Array.from((await node_fs_1.promises.readFile(dockerfile, "utf8"))
21
21
  .split(/\r?\n/)
22
22
  .filter((line) => line.toUpperCase().startsWith("FROM"))
23
23
  .map((line) => line.split(" ").filter(common_1.isNotEmptyString)[1])
@@ -1,6 +1,4 @@
1
- export declare const LABEL_TESTCONTAINERS = "org.testcontainers";
2
1
  export declare const LABEL_TESTCONTAINERS_LANG = "org.testcontainers.lang";
3
- export declare const LABEL_TESTCONTAINERS_VERSION = "org.testcontainers.version";
4
2
  export declare const LABEL_TESTCONTAINERS_SESSION_ID = "org.testcontainers.session-id";
5
3
  export declare const LABEL_TESTCONTAINERS_SSHD = "org.testcontainers.sshd";
6
4
  export declare const LABEL_TESTCONTAINERS_CONTAINER_HASH = "org.testcontainers.container-hash";
@@ -1,19 +1,19 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.LABEL_TESTCONTAINERS_RYUK = exports.LABEL_TESTCONTAINERS_CONTAINER_HASH = exports.LABEL_TESTCONTAINERS_SSHD = exports.LABEL_TESTCONTAINERS_SESSION_ID = exports.LABEL_TESTCONTAINERS_VERSION = exports.LABEL_TESTCONTAINERS_LANG = exports.LABEL_TESTCONTAINERS = void 0;
3
+ exports.LABEL_TESTCONTAINERS_RYUK = exports.LABEL_TESTCONTAINERS_CONTAINER_HASH = exports.LABEL_TESTCONTAINERS_SSHD = exports.LABEL_TESTCONTAINERS_SESSION_ID = exports.LABEL_TESTCONTAINERS_LANG = void 0;
4
4
  exports.createLabels = createLabels;
5
5
  const version_1 = require("../version");
6
- exports.LABEL_TESTCONTAINERS = "org.testcontainers";
6
+ const LABEL_TESTCONTAINERS = "org.testcontainers";
7
+ const LABEL_TESTCONTAINERS_VERSION = "org.testcontainers.version";
7
8
  exports.LABEL_TESTCONTAINERS_LANG = "org.testcontainers.lang";
8
- exports.LABEL_TESTCONTAINERS_VERSION = "org.testcontainers.version";
9
9
  exports.LABEL_TESTCONTAINERS_SESSION_ID = "org.testcontainers.session-id";
10
10
  exports.LABEL_TESTCONTAINERS_SSHD = "org.testcontainers.sshd";
11
11
  exports.LABEL_TESTCONTAINERS_CONTAINER_HASH = "org.testcontainers.container-hash";
12
12
  exports.LABEL_TESTCONTAINERS_RYUK = "org.testcontainers.ryuk";
13
13
  function createLabels() {
14
14
  return {
15
- [exports.LABEL_TESTCONTAINERS]: "true",
15
+ [LABEL_TESTCONTAINERS]: "true",
16
16
  [exports.LABEL_TESTCONTAINERS_LANG]: "node",
17
- [exports.LABEL_TESTCONTAINERS_VERSION]: version_1.LIB_VERSION,
17
+ [LABEL_TESTCONTAINERS_VERSION]: version_1.LIB_VERSION,
18
18
  };
19
19
  }
@@ -1,3 +1,3 @@
1
- import { ContainerInspectInfo } from "dockerode";
2
- import { InspectResult } from "../types";
1
+ import type { ContainerInspectInfo } from "dockerode";
2
+ import type { InspectResult } from "../types";
3
3
  export declare function mapInspectResult(inspectResult: ContainerInspectInfo): InspectResult;
@@ -20,19 +20,19 @@ function mapInspectResult(inspectResult) {
20
20
  };
21
21
  }
22
22
  function mapPorts(inspectInfo) {
23
- return Object.entries(inspectInfo.NetworkSettings.Ports)
23
+ return Object.fromEntries(Object.entries(inspectInfo.NetworkSettings.Ports)
24
24
  .filter(([, hostPorts]) => hostPorts !== null)
25
25
  .map(([containerPortAndProtocol, hostPorts]) => {
26
26
  const [port, protocol] = containerPortAndProtocol.split("/");
27
- const containerPort = parseInt(port);
28
- return {
29
- [`${containerPort}/${protocol}`]: hostPorts.map((hostPort) => ({
27
+ const containerPort = parseInt(port, 10);
28
+ return [
29
+ `${containerPort}/${protocol}`,
30
+ hostPorts.map((hostPort) => ({
30
31
  hostIp: hostPort.HostIp,
31
- hostPort: parseInt(hostPort.HostPort),
32
+ hostPort: parseInt(hostPort.HostPort, 10),
32
33
  })),
33
- };
34
- })
35
- .reduce((acc, curr) => ({ ...acc, ...curr }), {});
34
+ ];
35
+ }));
36
36
  }
37
37
  function mapHealthCheckStatus(inspectResult) {
38
38
  const status = (0, health_check_1.getHealthCheckStatusFromInspect)(inspectResult);
@@ -44,12 +44,11 @@ function mapHealthCheckStatus(inspectResult) {
44
44
  }
45
45
  }
46
46
  function mapNetworkSettings(inspectResult) {
47
- return Object.entries(inspectResult.NetworkSettings.Networks)
48
- .map(([networkName, network]) => ({
49
- [networkName]: {
47
+ return Object.fromEntries(Object.entries(inspectResult.NetworkSettings.Networks).map(([networkName, network]) => [
48
+ networkName,
49
+ {
50
50
  networkId: network.NetworkID,
51
51
  ipAddress: network.IPAddress,
52
52
  },
53
- }))
54
- .reduce((prev, next) => ({ ...prev, ...next }), {});
53
+ ]));
55
54
  }
@@ -16,6 +16,7 @@ class NeverPullPolicy {
16
16
  return "never";
17
17
  }
18
18
  }
19
+ // biome-ignore lint/complexity/noStaticOnlyClass: public API surface, kept as a class for backwards compatibility
19
20
  class PullPolicy {
20
21
  static defaultPolicy() {
21
22
  return new DefaultPullPolicy();
@@ -1 +1 @@
1
- export declare const LIB_VERSION = "12.2.0";
1
+ export declare const LIB_VERSION = "12.2.1";