"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var composition_exports = {};
__export(composition_exports, {
  Composition: () => Composition
});
module.exports = __toCommonJS(composition_exports);
/**
 * @license
 * Copyright 2022-2026 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
class Composition {
  #docker;
  #name;
  #abort = new AbortController();
  #parts = {};
  #defaultConfig;
  constructor(docker, name, defaultConfig) {
    this.#docker = docker;
    this.#name = name;
    this.#defaultConfig = defaultConfig ?? {};
  }
  get closed() {
    return Promise.allSettled(Object.values(this.#parts).map((part) => part.closed)).then((result) => {
      const errors = result.map((r) => r.status === "rejected" ? r.reason : void 0).filter((cause) => cause !== void 0);
      if (errors.length) {
        const error = new AggregateError(`Error in composition ${this.#name} containers`);
        error.errors = errors;
      }
    });
  }
  get(name) {
    const part = this.#parts[name];
    if (this.#abort.signal.aborted) {
      throw new Error(`Cannot access container ${name} because composition ${this.#name} is closed`);
    }
    if (part === void 0) {
      throw new Error(`Container ${name} does not exist in composition ${this.#name}`);
    }
    const { ct } = part;
    if (ct === void 0) {
      throw new Error(`Container ${name} in composition ${this.#name} is not ready`);
    }
    return ct;
  }
  close() {
    if (this.#abort.signal.aborted) {
      return this.closed;
    }
    this.#abort.abort();
    return this.closed;
  }
  async add(config) {
    const { name, recreate, autoKill, waitForStartup, onExit, onError } = config;
    if (this.#abort.signal.aborted) {
      throw new Error(`Cannot start container ${name} because composition ${this.#name} is closed`);
    }
    if (name in this.#parts) {
      throw new Error(`Container ${name} is already defined in composition ${this.#name}`);
    }
    config = { ...this.#defaultConfig, ...config, name: `${this.#name}-${name}` };
    if (config.image === void 0) {
      throw new Error(
        `No image specified for container ${name} and there is no default image for composition ${this.#name}`
      );
    }
    let ct;
    if (recreate) {
      ct = await this.#docker.erase(config.name).then(() => this.#docker.start(config));
    } else {
      ct = await this.#docker.open(config);
    }
    if (waitForStartup) {
      await waitForStartup(ct);
    }
    const closed = ct.wait({ condition: "not-running", abortSignal: this.#abort.signal }).then(async () => {
      if (autoKill) {
        try {
          await ct.kill();
        } catch (e) {
        }
        return onExit?.();
      }
    }).catch((cause) => {
      cause.message = `Error in ${config.name}: ${cause.message}`;
      if (onError) {
        return onError(cause);
      } else {
        throw cause;
      }
    }).finally(() => delete this.#parts[name]);
    this.#parts[name] = {
      ct,
      closed
    };
    return ct;
  }
}
//# sourceMappingURL=composition.js.map
