UNPKG

dt-app

Version:

The Dynatrace App Toolkit is a tool you can use from your command line to create, develop, and deploy apps on your Dynatrace environment.

3,872 lines 124 kB
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
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 __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  // If the importer is in node compatibility mode or this is not an ESM
  // file that has been converted to a CommonJS file using a Babel-
  // compatible transform (i.e. "__esModule" has not been set), then set
  // "default" to the CommonJS "module.exports" for node compatibility.
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  mod
));

// src/migrations/0.130.0/index.ts
var import_fs16 = require("fs");
var import_devkit2 = require("@dynatrace/devkit");
var import_path18 = require("path");

// src/utils/config/get-dt-app-file-config.ts
var import_path9 = require("path");

// src/utils/config/extract-dt-app-config-from-ts.ts
var import_path7 = require("path");

// src/utils/logger.ts
var import_chalk = require("chalk");
var import_lodash = require("lodash");

// src/utils/logfile-stream.ts
var import_fs = require("fs");
var import_promises = require("fs/promises");
var import_path = require("path");
var fileNamePattern = new RegExp(/[0-9]{4}-[0-9]{2}-[0-9]{2}_log.txt/);
var pad = (num) => (num > 9 ? "" : "0") + num;
var fileNameGenerator = (time) => {
  return `${time.getFullYear()}-${pad(time.getMonth() + 1)}-${pad(
    time.getDate()
  )}_log.txt`;
};
var extractDateFromFileName = (filename) => {
  try {
    const parts = filename.split("-");
    return new Date(
      Number(parts[0]),
      Number(parts[1]),
      Number(parts[2].split("_")[0])
    );
  } catch (_err) {
    return void 0;
  }
};
var LogFileStreamStub = class {
  /** Stub for setup function */
  async setup(_root) {
    return Promise.resolve();
  }
  /** Stub that does not write to file */
  write(_text) {
  }
  // eslint-disable-line @typescript-eslint/no-empty-function
  /** Stub that returns empty string */
  getLogFile() {
    return "";
  }
};
var LogFileStreamImpl = class {
  /** Location where log files should be stored. */
  logFolder;
  /** Log file path used by the current process. */
  logFile;
  /** Actual stream that is used to write the logs into the file. */
  stream;
  /** Initialize file stream for logging. */
  async setup(root) {
    this.logFolder = (0, import_path.join)(root, ".dt-app/logs");
    if (!(0, import_fs.existsSync)(this.logFolder)) {
      (0, import_fs.mkdirSync)(this.logFolder, { recursive: true });
    }
    await this.rotate();
  }
  /** Rotate file. */
  async rotate() {
    this.logFile = (0, import_path.join)(this.logFolder, fileNameGenerator(/* @__PURE__ */ new Date()));
    if (!(0, import_fs.existsSync)(this.logFile)) {
      const files = (0, import_fs.readdirSync)(this.logFolder).map((f) => f.trim()).filter((f) => fileNamePattern.test(f));
      if (files.length >= 10) {
        const oldestFile = files.map((f) => {
          return {
            path: f,
            date: extractDateFromFileName(f)
          };
        }).filter((f) => f.date).sort((a, b) => a.date.getTime() - b.date.getTime())[0].path;
        (0, import_promises.unlink)((0, import_path.join)(this.logFolder, oldestFile));
      }
      (0, import_fs.closeSync)((0, import_fs.openSync)(this.logFile, "w"));
    }
    await new Promise((resolve2) => {
      this.stream = (0, import_fs.createWriteStream)(this.logFile, {
        encoding: "utf-8",
        flags: "a"
        // Append to file
      });
      this.stream.on("open", () => resolve2());
    });
  }
  /** Write log to file. */
  write(text) {
    if (this.stream) {
      this.stream.write(text);
    }
  }
  /** Returns the path to the current log file. */
  getLogFile() {
    return this.logFile;
  }
};
async function initLogFileStream(root) {
  logFileStream = new LogFileStreamImpl();
  return logFileStream.setup(root);
}
var logFileStream = new LogFileStreamStub();

// src/utils/logger.ts
var import_os = require("os");

// src/utils/spinner-service.ts
var import_ora = __toESM(require("ora"));

// src/utils/terminal-queue.ts
var queue = [];
var isProcessing = false;
function enqueue(func) {
  return new Promise((resolve2, reject) => {
    queue.push(async () => {
      try {
        const result = await func();
        resolve2(result);
      } catch (error) {
        reject(error);
      }
    });
    processQueue();
  });
}
async function processQueue() {
  if (isProcessing) {
    return;
  }
  isProcessing = true;
  while (queue.length > 0) {
    const queueItem = queue.shift();
    await queueItem();
  }
  isProcessing = false;
}
async function terminalAction(promptFunction) {
  return enqueue(promptFunction);
}

// src/utils/spinner-service.ts
var verbose = process.env.DT_APP_DEACTIVATE_SPINNER !== "true";
var spinnerDefaultConfig = {
  //    Frames: symbols,
  interval: 80
};
var concurrentSpinners = [];
var spinnerState = "idle";
var multiSpinner = (0, import_ora.default)({
  spinner: { frames: [""], interval: spinnerDefaultConfig.interval },
  isSilent: !verbose
});
var getMultiSpinnerFrame = () => `
${concurrentSpinners.map((s) => s.getFrame()).join("\n")}`;
function updateMultiSpinner() {
  multiSpinner.text = getMultiSpinnerFrame();
}
var multiSpinnerUpdateInterval = void 0;
function startMultiSpinner() {
  if (verbose && spinnerState !== "running" && !isProcessing) {
    if (multiSpinnerUpdateInterval === void 0) {
      multiSpinnerUpdateInterval = setInterval(
        updateMultiSpinner,
        spinnerDefaultConfig.interval
      );
    }
    multiSpinner.start();
    spinnerState = "running";
  }
}
function pauseMultiSpinner() {
  if (spinnerState === "running") {
    spinnerState = "paused";
    multiSpinner.stop();
  }
}
function resumeMultiSpinner() {
  if (spinnerState === "paused" && !isProcessing) {
    spinnerState = "running";
    multiSpinner.start();
  }
}
function stopMultiSpinner() {
  spinnerState = "idle";
  multiSpinner.stop();
  concurrentSpinners.forEach((s) => s.abort());
  if (multiSpinnerUpdateInterval !== void 0) {
    clearInterval(multiSpinnerUpdateInterval);
    multiSpinnerUpdateInterval = void 0;
  }
}
var SpinnerImpl = class {
  spinner;
  /**
   * @param options {@link ora.Options}
   */
  constructor(options) {
    this.spinner = (0, import_ora.default)({ ...options, isSilent: !verbose });
  }
  // Documented in interface
  // eslint-disable-next-line require-jsdoc
  get text() {
    return this.spinner.text;
  }
  // Documented in interface
  // eslint-disable-next-line require-jsdoc
  set text(text) {
    this.spinner.text = text;
  }
  /**
   * Stops the spinner and removes it from the concurrent spinner Array
   */
  cleanup() {
    const index = concurrentSpinners.indexOf(this);
    if (index > -1) {
      if (this.spinner.isSpinning) {
        this.spinner.stop();
      }
      concurrentSpinners.splice(index, 1);
    }
    if (concurrentSpinners.length === 0) {
      stopMultiSpinner();
    }
  }
  /**
   * @returns the next frame of the spinner
   */
  getFrame() {
    return this.spinner.frame();
  }
  // Documented in interface
  // eslint-disable-next-line require-jsdoc
  start(text) {
    if (text) {
      this.text = text;
    }
    if (!concurrentSpinners.includes(this)) {
      concurrentSpinners.push(this);
    }
    startMultiSpinner();
    return this;
  }
  /**
   * Stops the spinner and executes cleanup of this instance.
   * @param text stop text for the spinner
   * @param stopType either {@link SpinnerStopType} or {@link ora.PersistOptions}
   * @returns The spinner instance.
   */
  _stop(text, stopType = "abort") {
    this.text = text ?? this.text;
    pauseMultiSpinner();
    switch (stopType) {
      case "success":
        this.spinner.succeed(this.text);
        break;
      case "info":
        this.spinner.info(this.text);
        break;
      case "fail":
        this.spinner.fail(this.text);
        break;
      case "warn":
        this.spinner.warn(this.text);
        break;
      case "abort":
        this.spinner.stop();
        break;
      default:
        this.spinner.stopAndPersist(stopType);
    }
    this.cleanup();
    resumeMultiSpinner();
    return this;
  }
  // Documented in interface
  // eslint-disable-next-line require-jsdoc
  stop(text, stopOptions = {}) {
    return this._stop(text, stopOptions);
  }
  // Documented in interface
  // eslint-disable-next-line require-jsdoc
  abort() {
    return this._stop(void 0, "abort");
  }
  // Documented in interface
  // eslint-disable-next-line require-jsdoc
  info(text) {
    return this._stop(text, "info");
  }
  // Documented in interface
  // eslint-disable-next-line require-jsdoc
  succeed(text) {
    return this._stop(text, "success");
  }
  // Documented in interface
  // eslint-disable-next-line require-jsdoc
  fail(text) {
    return this._stop(text, "fail");
  }
  // Documented in interface
  // eslint-disable-next-line require-jsdoc
  warn(text) {
    return this._stop(text, "warn");
  }
};
var SpinnerService = {
  /**
   * Creates an inactive spinner.
   * @param options - Optional {@link Options} for the spinner.
   * @returns A new Spinner instance.
   */
  create: (options = {}) => new SpinnerImpl({ ...options, interval: spinnerDefaultConfig.interval }),
  /**
   * Creates and starts a new spinner.
   * @param text - Optional text to be displayed.
   * @param options - Optional {@link Options} for the spinner.
   * @returns A new Spinner instance.
   */
  start: (text, options = {}) => new SpinnerImpl({
    ...options,
    interval: spinnerDefaultConfig.interval
  }).start(text),
  /**
   * Pauses all running spinners.
   */
  pause: pauseMultiSpinner,
  /**
   * Resumes all paused spinners.
   */
  resume: resumeMultiSpinner,
  /**
   * Resets all running or idle spinners.
   */
  reset: stopMultiSpinner,
  /**
   * Marks all spinners as succeeded with optional text.
   * @param text - Optional text to be displayed.
   */
  successAll: (text) => concurrentSpinners.forEach((s) => s.succeed(text)),
  /**
   * Marks all spinners as failed with optional text.
   * @param text - Optional text to be displayed.
   */
  failAll: (text) => concurrentSpinners.forEach((s) => s.fail(text)),
  disable: () => {
    verbose = false;
    stopMultiSpinner();
  },
  enable: () => {
    verbose = true;
  },
  getInterval: () => spinnerDefaultConfig.interval,
  _getMockedSpinner: function(text) {
    const mockSpinner = {
      abort: (..._) => mockSpinner,
      fail: (..._) => mockSpinner,
      info: (..._) => mockSpinner,
      start: (..._) => mockSpinner,
      stop: (..._) => mockSpinner,
      succeed: (..._) => mockSpinner,
      text: text ?? "",
      warn: (..._) => mockSpinner
    };
    return mockSpinner;
  }
};

// src/utils/logger.ts
var WaveLogger = class {
  boxSize = 80;
  warningBoxSize = 90;
  /** Disables logging */
  disabled = false;
  /** Loading spinner instance */
  spinner = {
    create: () => SpinnerService.create(),
    disable: SpinnerService.disable,
    start: (text) => SpinnerService.start(text),
    pause: SpinnerService.pause,
    resume: SpinnerService.resume,
    abort: SpinnerService.reset
  };
  /** Toggle if the logger should log */
  disable() {
    this.disabled = true;
    SpinnerService.disable();
  }
  /** Log something to the cli */
  log(text) {
    this._log(`${this._padString(text, 1)}`, "INFO");
  }
  /** Prints a debug message */
  debug(text, context) {
    if (global.VERBOSE_MODE && context.startsWith(global.VERBOSE_MODE.replace("%", ""))) {
      this.spinner.pause();
      console.log(
        `${(0, import_chalk.yellow)("DEBUG")}${this._padString(`[${context}] ${text}`, 1)}`
      );
      this.debounceTimeout = setTimeout(() => {
        this.spinner.resume();
      }, SpinnerService.getInterval());
    }
    this._printToFile(`[${context}] ${text}`, "DEBUG");
  }
  /** Log level information (verbose output) */
  info(text, pad2) {
    this._log(
      pad2 === void 0 || pad2 ? this._padString(text, 0) : text,
      "INFO"
    );
  }
  /** Log level for successful tasks */
  success(text) {
    this._log((0, import_chalk.green)(this._padString(text, 0)), "INFO");
  }
  /** Log level information (verbose output) */
  error(text) {
    this._log((0, import_chalk.red)(this._padString(text, 0)), "ERROR");
  }
  /** Log level for warnings */
  warn(text) {
    const boxedText = `
${(0, import_chalk.yellow)(
      "Warning " + (0, import_lodash.repeat)("─", this.warningBoxSize - 8)
    )}

${(0, import_chalk.yellow)(this._padString(text))}

${(0, import_chalk.yellow)(
      (0, import_lodash.repeat)("─", this.warningBoxSize)
    )}
`;
    this._log(boxedText, "WARNING");
  }
  /** Logs the text in a box */
  logBox(text) {
    if (this.disabled) {
      return;
    }
    const boxedText = `
${(0, import_chalk.magenta)((0, import_lodash.repeat)("─", this.boxSize))}

${(0, import_chalk.magenta)(
      this._padString(text)
    )}

${(0, import_chalk.magenta)((0, import_lodash.repeat)("─", this.boxSize))}
`;
    this._log(boxedText, "INFO");
  }
  /** Cleanup logger. Used before system.exit() */
  clean() {
    this.spinner.abort();
  }
  /** Initialize log file stream */
  async initLogFile(root) {
    if (!this.disabled) {
      await initLogFileStream(root);
    }
  }
  debounceTimeout;
  /** Logs the text and pauses a loading spinner in between if there is one */
  _log(text, scope) {
    if (this.disabled) {
      return;
    }
    if (this.debounceTimeout) {
      clearTimeout(this.debounceTimeout);
    }
    this.spinner.pause();
    if (scope === "ERROR") {
      console.log(text);
    } else {
      terminalAction(() => Promise.resolve(console.log(text)));
    }
    this.debounceTimeout = setTimeout(() => {
      this.spinner.resume();
    }, SpinnerService.getInterval());
    this._printToFile(text, scope);
  }
  /** Logs the text with timestamp prefix to file */
  _printToFile(text, scope) {
    logFileStream.write(
      `${getOffsetTime().toISOString()} ${scope} ${stripAnsi(text)}
`
    );
  }
  /** Cleans a string and adds the necessary space */
  // eslint-disable-next-line require-jsdoc, @typescript-eslint/typedef
  _padString(text, start = 2) {
    return `${text}`.split(/[\n\r]/).map((line) => `${(0, import_lodash.repeat)(" ", start)}${line}`).join(import_os.EOL);
  }
};
function stripAnsi(text) {
  const pattern = [
    "[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)",
    "(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))"
  ].join("|");
  return text.replace(new RegExp(pattern, "g"), "");
}
function getOffsetTime() {
  const now = /* @__PURE__ */ new Date();
  const timezoneOffset = now.getTimezoneOffset() * 6e4;
  now.setTime(now.getTime() - timezoneOffset);
  return now;
}
var logger = new WaveLogger();

// src/utils/node-resolve-package.ts
function nodeResolvePackage(pck, cwd) {
  return require.resolve(pck, {
    paths: [cwd]
  });
}

// src/utils/errors.ts
var import_path2 = require("path");
var import_chalk2 = require("chalk");
var ErrorCause = /* @__PURE__ */ ((ErrorCause2) => {
  ErrorCause2[ErrorCause2["POSIX_SIGNAL_BASE"] = 128] = "POSIX_SIGNAL_BASE";
  ErrorCause2[ErrorCause2["UNCAUGHT"] = 256] = "UNCAUGHT";
  ErrorCause2[ErrorCause2["INTERNAL"] = 257] = "INTERNAL";
  ErrorCause2[ErrorCause2["USER"] = 258] = "USER";
  ErrorCause2[ErrorCause2["AUTH"] = 259] = "AUTH";
  ErrorCause2[ErrorCause2["TIMEOUT"] = 260] = "TIMEOUT";
  ErrorCause2[ErrorCause2["COMPILATION"] = 261] = "COMPILATION";
  ErrorCause2[ErrorCause2["NETWORKING"] = 263] = "NETWORKING";
  ErrorCause2[ErrorCause2["VALIDATION"] = 264] = "VALIDATION";
  ErrorCause2[ErrorCause2["BUILD"] = 265] = "BUILD";
  ErrorCause2[ErrorCause2["APP_GATEWAY_COMMUNICATION"] = 266] = "APP_GATEWAY_COMMUNICATION";
  return ErrorCause2;
})(ErrorCause || {});
var CREDENTIALS_ERROR = `Authentication failed!

Please make sure that:
* The provided client ID and the secret are correct.
* The provided client ID has needed scopes.

Deploy scopes:
* app-engine:apps:run
* app-engine:apps:install
* app-engine:apps:delete

Uninstall scopes:
* app-engine:apps:delete

Telemetry scopes:
* app-engine:apps:run

Development server needs all the scopes specified in the app.config.

For more details on how you can configure authentication, see ${"https://dt-url.net/qw024j8" /* APP_TOOLKIT_CONFIGURATION */}
`;
function getCredentialsError(message) {
  const errorMessage = [message, CREDENTIALS_ERROR];
  return new Error(errorMessage.filter(Boolean).join("\n"), {
    cause: 259 /* AUTH */
  });
}
function sanitizeErrorMessage(rawErrorMessage) {
  if (!rawErrorMessage) {
    return "";
  }
  return rawErrorMessage.replace(/\(|\)/g, "").split(" ").filter(Boolean).map((element, i) => {
    if (i === 0 && element.toLocaleLowerCase() === "error:") {
      return "";
    }
    return element;
  }).map((element) => {
    if (element.includes("http") || element.includes("://")) {
      return "";
    }
    return element;
  }).map((element) => {
    if (element.includes(import_path2.sep)) {
      return `${element.replace(/["']/g, "").split(import_path2.sep).pop()}`;
    }
    return element;
  }).join(" ").substring(0, 200).trim();
}
function toError(e) {
  return e instanceof Error ? e : new Error(String(e));
}
function throwWithDynatraceErrorCode(error, errorCode) {
  throw new Error(`ERROR [${(0, import_chalk2.green)(errorCode)}]: ${error.message}`);
}

// src/plugin/require-plugins.ts
var DEBUG_CONTEXT = "PLUGIN";
function requirePlugins(options) {
  return options.plugins.map((p) => requirePlugin(p, options.root)).filter((p) => !!p);
}
function requirePlugin(plugin, root) {
  try {
    return require(nodeResolvePackage(plugin, root)).default;
  } catch (e) {
    logger.warn(`Could not require plugin ${plugin}. It will be ignored.`);
    logger.debug(toError(e).toString(), DEBUG_CONTEXT);
  }
  return void 0;
}

// src/build/diagnostic.ts
var import_path3 = require("path");

// src/utils/import-typescript.ts
var typescript;
function resolveTypescript(root) {
  if (!typescript) {
    typescript = require(nodeResolvePackage("typescript", root));
  }
  return typescript;
}

// src/build/diagnostic.ts
function fromEsbuildMessage(message, category) {
  return {
    category,
    text: message.text,
    filePath: message.location?.file ? (0, import_path3.resolve)(message.location.file) : void 0,
    line: message.location?.line ?? 1,
    column: (message.location?.column ?? 0) + 1
  };
}
function fromTypeScriptDiagnostic(tsDiagnostic, root) {
  const ts = resolveTypescript(root);
  const code = `TS${tsDiagnostic.code}`;
  const text = ts.flattenDiagnosticMessageText(tsDiagnostic.messageText, "\n");
  const category = tsDiagnostic.category === ts.DiagnosticCategory.Error ? "Error" /* error */ : "Warning" /* warning */;
  if (tsDiagnostic.file) {
    const { line, character } = ts.getLineAndCharacterOfPosition(
      tsDiagnostic.file,
      tsDiagnostic.start
    );
    return {
      code,
      category,
      text,
      filePath: tsDiagnostic.file.fileName,
      column: character + 1,
      line: line + 1
    };
  }
  return {
    code,
    category,
    text,
    filePath: void 0,
    line: 1,
    column: 1
  };
}

// src/build/compile.ts
var import_path5 = require("path");

// src/utils/run-esbuild.ts
var import_path4 = require("path");

// src/utils/exclude-vendor-from-source-map.ts
var import_fs2 = require("fs");
var EMPTY_SOURCEMAP = "//# sourceMappingURL=data:application/json;base64,ewogICJtYXBwaW5ncyI6ICJBQUFBQSIsCiAgInNvdXJjZXMiOiBbIiJdLAogICJzb3VyY2VzQ29udGVudCI6IFsiIl0sCiAgIm5hbWVzIjogWyIiXSwKICAidmVyc2lvbiI6IDMsCiAgImZpbGUiOiAiIgp9";
var excludeVendorFromSourceMapPlugin = () => ({
  name: "excludeVendorFromSourceMap",
  setup(build) {
    build.onLoad({ filter: /node_modules/ }, (args) => {
      if (args.path.endsWith(".js")) {
        return {
          contents: `${(0, import_fs2.readFileSync)(args.path, "utf8")}
${EMPTY_SOURCEMAP}`,
          loader: "default"
        };
      }
    });
  }
});

// src/utils/get-source-files.ts
var import_fast_glob = require("fast-glob");

// src/utils/unix-join.ts
function unixJoin(parts, options) {
  const arrayParts = Array.isArray(parts) ? parts : parts.split(/[\/\\]/g);
  const result = arrayParts.map((part) => part ? part.replace(/\\/g, "/") : "").join("/").replace(/\/\.\//g, "/").replace(/(?<!:)\/{2,}/g, "/").replace(/^.\//, "");
  if (options?.keepFullPath) {
    return result;
  } else {
    return result.replace(/^([a-zA-Z]):/, "");
  }
}

// src/build/build-watchers/utils.ts
function getDefaultEsbuildOptions() {
  return {
    sourcemap: true,
    color: true,
    loader: {
      // Esbuild should not bundle .node files but also not throw an error if .node files are required
      ".node": "empty"
    },
    bundle: true,
    logLevel: "silent",
    charset: "utf8",
    write: false
  };
}

// src/utils/run-esbuild.ts
async function runEsbuild(outdir, options, abortSignal) {
  const esbuild = require(nodeResolvePackage(
    "esbuild",
    options.cwd
  ));
  if (!esbuild.context) {
    throw new Error(
      `esbuild context function not found. This is likely happening because you may have dependencies in your project that are installing an older version of esbuild. Please fix your dependencies and try again. ${esbuild.version ? `Your current esbuild version being used is ${esbuild.version}.` : ""}`,
      {
        cause: 258 /* USER */
      }
    );
  }
  const { context } = esbuild;
  const sourcemap = options.sourcemapOptions?.sourcemap ?? false;
  if (sourcemap && !options.sourcemapOptions?.includeVendorSourceMaps) {
    options.plugins = [
      ...options.plugins ?? [],
      excludeVendorFromSourceMapPlugin()
    ];
  }
  const ctx = await context({
    ...getDefaultEsbuildOptions(),
    entryPoints: options.entryPoints.map(
      (entryPoint) => (0, import_path4.isAbsolute)(entryPoint) ? entryPoint : (0, import_path4.join)(options.cwd, entryPoint)
    ),
    outbase: options.outbase,
    target: options.target,
    minify: options.minify ?? false,
    sourcemap,
    platform: options.platform || "browser",
    plugins: options.plugins || [],
    external: options.external || [],
    sourceRoot: options.sourceRoot,
    tsconfig: (0, import_path4.isAbsolute)(options.tsconfig) ? options.tsconfig : (0, import_path4.join)(options.cwd, options.tsconfig),
    outdir,
    format: options.format,
    globalName: options.globalName,
    metafile: options.metafile,
    write: false,
    // Necessary for type safety.
    define: options.define
  });
  abortSignal?.addEventListener("abort", () => ctx.cancel());
  const resultPromise = ctx.rebuild();
  try {
    return await resultPromise;
  } finally {
    ctx.dispose();
  }
}

// src/build/compile.ts
async function compile(options, abortSignal) {
  const timerStart = Date.now();
  try {
    const tmpOutDir = (0, import_path5.join)(options.cwd, "dist");
    const buildResult = await runEsbuild(tmpOutDir, options, abortSignal);
    const timerEnd = Date.now();
    const diagnostics = buildResult.warnings.map((message) => fromEsbuildMessage(message, "Warning" /* warning */)).filter((diagnostic) => !diagnostic.filePath?.includes("node_modules/"));
    const outDir = options.outDir ?? "dist";
    const fileMap = buildResult.outputFiles.reduce((prev, file) => {
      const filepath = `${import_path5.sep}${(0, import_path5.join)(
        outDir,
        file.path.replace(tmpOutDir, "")
      )}`;
      return {
        ...prev,
        [filepath]: {
          content: Buffer.from(file.contents)
        }
      };
    }, {});
    return {
      fileMap,
      diagnostics,
      duration: timerEnd - timerStart,
      metafile: buildResult.metafile
    };
  } catch (e) {
    const timerEnd = Date.now();
    if (isBuildFailure(e)) {
      const diagnostics = [
        // Convert esbuild errors
        ...e.errors.map(
          (message) => fromEsbuildMessage(message, "Error" /* error */)
        ),
        // Convert esbuild warnings, but ignore warnings in node_modules
        ...e.warnings.map(
          (message) => fromEsbuildMessage(message, "Warning" /* warning */)
        ).filter(
          (diagnostic) => !diagnostic.filePath?.includes("node_modules/")
        )
      ];
      return {
        fileMap: {},
        diagnostics,
        duration: timerEnd - timerStart
      };
    }
    const error = e instanceof Error ? e : new Error(String(e), {
      cause: 261 /* COMPILATION */
    });
    throw error;
  }
}
function isBuildFailure(error) {
  return typeof error === "object" && typeof error?.errors !== "undefined";
}

// src/dev/pretty-error.ts
var import_code_frame = require("@babel/code-frame");
var import_chalk3 = require("chalk");
var import_fs3 = require("fs");
var import_ansi_to_html = __toESM(require("ansi-to-html"));
var ansiToHtmlConverter = new import_ansi_to_html.default({});
function logDiagnostics(diagnostics) {
  for (const diagnostic of diagnostics) {
    logger.info(prettyConsoleError(diagnostic));
  }
}
var prettyConsoleError = (diagnostic) => {
  const file = diagnostic.filePath ? `${(0, import_chalk3.cyan)(diagnostic.filePath)}:${(0, import_chalk3.yellow)(diagnostic.line)}:${(0, import_chalk3.yellow)(
    diagnostic.column
  )}` : "<no file>";
  const category = diagnostic.category === "Error" /* error */ ? (0, import_chalk3.red)("Error:") : (0, import_chalk3.yellow)("Warning:");
  const code = diagnostic.code ? (0, import_chalk3.gray)(` ${diagnostic.code}`) : "";
  const header = `> ${file} - ${category}${code} ${diagnostic.text}`;
  const codeFrame = (0, import_chalk3.bold)(`${createCodeFrame(diagnostic)}`);
  return `${header}
${codeFrame}`;
};
var createCodeFrame = (error) => {
  try {
    if (!error.filePath) {
      return "";
    }
    const fileString = (0, import_fs3.readFileSync)(error.filePath, "utf-8");
    const isFileEmpty = fileString === "";
    const location = {
      start: {
        line: error.line,
        column: isFileEmpty ? 1 : error.column
      }
    };
    return (0, import_code_frame.codeFrameColumns)(isFileEmpty ? " " : fileString, location, {
      forceColor: true
    });
  } catch (error2) {
    console.error(error2);
  }
  return "";
};

// src/utils/config/extract-dt-app-config-from-ts.ts
var import_fs5 = require("fs");

// src/utils/config/native-node-modules-plugin.ts
var nativeNodeModulesPlugin = {
  name: "native-node-modules",
  setup(build) {
    build.onResolve({ filter: /\.node$/, namespace: "file" }, (args) => ({
      path: require.resolve(args.path, { paths: [args.resolveDir] }),
      namespace: "node-file"
    }));
    build.onLoad({ filter: /.*/, namespace: "node-file" }, (args) => ({
      contents: `
        import path from ${JSON.stringify(args.path)}
        try { module.exports = require(path) }
        catch {}
      `
    }));
    build.onResolve({ filter: /\.node$/, namespace: "node-file" }, (args) => ({
      path: args.path,
      namespace: "file"
    }));
    const opts = build.initialOptions;
    opts.loader = opts.loader || {};
    opts.loader[".node"] = "file";
  }
};

// src/utils/config/extract-dt-app-config-from-ts.ts
var import_crypto = __toESM(require("crypto"));

// src/build/type-checker.ts
var import_lodash2 = require("lodash");
var import_micromatch = require("micromatch");
var import_fs4 = require("fs");
var import_path6 = require("path");

// src/build/fixed-build-type-options.ts
var fixedGeneralOptions = {
  noEmit: true,
  skipLibCheck: true
};
function getFixedBuildTypeOptions(root) {
  const { ScriptTarget } = resolveTypescript(root);
  return {
    ["ui" /* UI */]: {
      target: ScriptTarget.ES2021,
      ...fixedGeneralOptions
    },
    ["functions" /* FUNCTIONS */]: {
      target: ScriptTarget.ESNext,
      ...fixedGeneralOptions
    },
    ["actions" /* ACTIONS */]: {
      target: ScriptTarget.ESNext,
      ...fixedGeneralOptions
    },
    ["widgets" /* WIDGETS */]: {
      target: ScriptTarget.ESNext,
      ...fixedGeneralOptions
    }
  };
}

// src/build/type-checker.ts
function check(options) {
  const { createCompilerHost, createProgram } = resolveTypescript(
    options.srcRoot
  );
  const { tsConfigContents, tsConfigFileDiagnostics: fileDiagnostics } = getTsConfig(options.srcRoot, options.tsConfigFullPath);
  const compilerOptions = {
    ...tsConfigContents.options,
    ...getFixedBuildTypeOptions(options.srcRoot)[options.buildType],
    incremental: false
  };
  const host = createCompilerHost(tsConfigContents.options);
  let entryFiles = [];
  const purgedEntryFiles = (0, import_micromatch.not)(
    options.entrypoints,
    tsConfigContents.raw.exclude
  ).map(
    (filepath) => (0, import_path6.isAbsolute)(filepath) ? filepath : (0, import_path6.join)(options.srcRoot, filepath)
  );
  if (tsConfigContents.options.composite) {
    entryFiles = [
      .../* @__PURE__ */ new Set([...purgedEntryFiles, ...tsConfigContents.fileNames])
    ];
  } else {
    const typeDefinitions = tsConfigContents.fileNames.filter(
      (fileName) => fileName.endsWith(".d.ts")
    );
    const purgedTypeDefs = (0, import_micromatch.not)(
      typeDefinitions,
      tsConfigContents.raw.exclude
    ).map(
      (filepath) => (0, import_path6.isAbsolute)(filepath) ? filepath : (0, import_path6.join)(options.srcRoot, filepath)
    );
    entryFiles = [.../* @__PURE__ */ new Set([...purgedEntryFiles, ...purgedTypeDefs])];
  }
  const program2 = createProgram({
    rootNames: entryFiles,
    options: compilerOptions,
    host,
    configFileParsingDiagnostics: fileDiagnostics,
    projectReferences: tsConfigContents.projectReferences
  });
  const results = program2.emit();
  const allDiagnostics = [
    ...program2.getSyntacticDiagnostics(),
    ...program2.getSemanticDiagnostics(),
    ...program2.getConfigFileParsingDiagnostics(),
    ...program2.getGlobalDiagnostics(),
    ...program2.getDeclarationDiagnostics(),
    ...results.diagnostics
  ];
  return allDiagnostics.map(
    (d) => fromTypeScriptDiagnostic(d, options.appRoot)
  );
}
function getTsConfig(cwd, tsConfigPath) {
  const { sys, readConfigFile, parseJsonConfigFileContent } = resolveTypescript(cwd);
  const configFile = readConfigFile(
    tsConfigPath,
    (path) => (0, import_fs4.readFileSync)(path).toString()
  );
  let tsConfigFileDiagnostics = [];
  if (configFile.error && (0, import_lodash2.has)(configFile.error.file, "parseDiagnostics")) {
    tsConfigFileDiagnostics = (0, import_lodash2.get)(
      configFile.error?.file,
      "parseDiagnostics"
    );
  }
  const tsConfigContents = parseJsonConfigFileContent(
    configFile.config,
    sys,
    (0, import_path6.dirname)(tsConfigPath)
  );
  tsConfigFileDiagnostics.push(...tsConfigContents.errors);
  return { tsConfigContents, tsConfigFileDiagnostics };
}

// src/utils/config/extract-dt-app-config-from-ts.ts
async function extractDtAppConfigFromTs(root, configFilePath, tsconfigPath, skipTypeCheck, format = "cjs") {
  logger.debug(
    "Perform build and type-check on configuration file",
    DEBUG_CONTEXT
  );
  const externalPackages = getProjectDependencies(format, root);
  const buildPromise = compile({
    cwd: (0, import_path7.dirname)(configFilePath),
    tsconfig: tsconfigPath,
    entryPoints: [configFilePath],
    external: ["esbuild", ...externalPackages],
    platform: "node",
    target: "node16",
    format,
    outDir: "dist",
    plugins: [nativeNodeModulesPlugin],
    define: {}
    // Overwrite define to not break esbuild plugins defined in app.config
  });
  let typeCheckDiagnostics = [];
  if (!skipTypeCheck) {
    typeCheckDiagnostics = check({
      appRoot: root,
      srcRoot: root,
      entrypoints: [configFilePath],
      tsConfigFullPath: tsconfigPath,
      buildType: "ui" /* UI */
    });
  }
  const buildResult = await buildPromise;
  const diagnostics = [...buildResult.diagnostics, ...typeCheckDiagnostics];
  logDiagnostics(diagnostics);
  if (diagnostics.some(
    (diagnostic) => diagnostic.category === "Error" /* error */
  )) {
    throw new Error("Reading your configuration file failed.", {
      cause: 258 /* USER */
    });
  }
  logger.debug("Successfully prepared configuration to be read", DEBUG_CONTEXT);
  const randomTmpDir = generateRandomDirectoryName(configFilePath, ".dt-app");
  const dtAppConfigJsPath = (0, import_path7.join)(
    randomTmpDir,
    format === "cjs" ? "app.config.js" : "app.config.mjs"
  );
  if (!(0, import_fs5.existsSync)(randomTmpDir)) {
    (0, import_fs5.mkdirSync)(randomTmpDir, { recursive: true });
  }
  (0, import_fs5.writeFileSync)(
    dtAppConfigJsPath,
    buildResult.fileMap[(0, import_path7.join)(import_path7.sep, "dist", "app.config.js")].content.toString(
      "utf-8"
    )
  );
  try {
    const result = format === "cjs" ? await require(dtAppConfigJsPath) : (await import(dtAppConfigJsPath)).default;
    return result;
  } catch (error) {
    throw new Error(`Error at resolving of app.config: ${error}`, {
      cause: 258 /* USER */
    });
  } finally {
    try {
      (0, import_fs5.rmSync)(randomTmpDir, { recursive: true });
    } catch (e) {
      logger.debug(
        `A temporary file can't be cleaned up: ${dtAppConfigJsPath}. Error: ${toError(e).message}`,
        DEBUG_CONTEXT
      );
    }
  }
}
function getProjectDependencies(format, root) {
  if (format !== "esm") {
    return [];
  }
  const externalPackages = [];
  try {
    const packageJsonPath = (0, import_path7.join)(root, "package.json");
    const packageJson = JSON.parse((0, import_fs5.readFileSync)(packageJsonPath, "utf-8"));
    const dependencies = Object.keys(packageJson?.dependencies || {});
    const devDependencies = Object.keys(packageJson?.devDependencies || {});
    externalPackages.push(...dependencies, ...devDependencies);
  } catch (error) {
    logger.debug(
      "Failed to read package.json for external packages",
      DEBUG_CONTEXT
    );
  }
  return externalPackages;
}
function generateRandomDirectoryName(filePath, dir) {
  const randomString = import_crypto.default.randomBytes(4).toString("hex");
  return (0, import_path7.join)((0, import_path7.dirname)(filePath), `${dir}/${randomString}`);
}

// src/utils/read-json.ts
var import_fs6 = require("fs");
function readJson(file) {
  if (!(0, import_fs6.existsSync)(file) && !(0, import_fs6.lstatSync)(file, { throwIfNoEntry: false })?.isFile()) {
    throw new Error(`[read-json.ts] File does not exist: ${file}`, {
      cause: 257 /* INTERNAL */
    });
  }
  const content = (0, import_fs6.readFileSync)(file, "utf-8");
  return JSON.parse(content);
}

// src/utils/file-operations.ts
var import_node_path = require("node:path");
var import_fs8 = require("fs");
var import_inquirer = require("inquirer");

// src/utils/file-utils.ts
var import_path8 = require("path");
var import_fs7 = require("fs");
function mkdirp(path) {
  if (!(0, import_fs7.existsSync)(path)) {
    (0, import_fs7.mkdirSync)(path);
  }
}
function nameToFileName({
  name,
  suffix,
  allowNested = true
}) {
  const { name: nameWithoutExtension, dir, base } = (0, import_path8.parse)(name);
  const parsedName = allowNested ? nameWithoutExtension : base;
  const fileName = `${parsedName}.${suffix}`;
  if (allowNested) {
    return (0, import_path8.join)(dir, fileName);
  }
  return fileName;
}

// src/utils/file-operations.ts
function checkIfFileExists(fileSearch) {
  const { filePath } = getFileNameAndPath(fileSearch);
  return (0, import_fs8.existsSync)(filePath);
}
function getFileNameAndPath({
  allowNested = true,
  ...options
}) {
  let fileName = options.suffix ? nameToFileName({
    name: options.name,
    suffix: options.suffix,
    allowNested
  }) : options.name;
  let filePath = "";
  if (options.folder) {
    filePath = (0, import_node_path.join)(options.cwd, options.folder, fileName);
  } else {
    filePath = (0, import_node_path.join)(options.cwd, fileName);
  }
  if (!options.suffix) {
    fileName = (0, import_node_path.basename)(filePath);
  }
  return { fileName, filePath };
}
async function checkIfExistsAndPromptIfNot(FileSearchOption, template, errorCauseType) {
  const isFilePresent = checkIfFileExists(FileSearchOption);
  if (isFilePresent) {
    return true;
  }
  logger.spinner.pause();
  const { fileName, filePath } = getFileNameAndPath(FileSearchOption);
  let createFile;
  if (process.argv.includes("--non-interactive")) {
    createFile = true;
  } else {
    createFile = await terminalAction(async () => {
      const { createFile: createFile2 } = await (0, import_inquirer.prompt)([
        {
          name: "createFile",
          type: "confirm",
          message: `${filePath} is missing${errorCauseType ? ", and it is required" : ""}. Do you want to generate the file?`
        }
      ]);
      return createFile2;
    });
  }
  logger.spinner.resume();
  const fileTemplate = JSON.stringify(template, null, 2);
  if (!createFile && errorCauseType) {
    throw new Error(
      `Failed to continue

      Please create a ${fileName} file in the ${filePath} directory.

      Example ${filePath}:

      ${fileTemplate}

      `,
      { cause: ErrorCause[errorCauseType] }
    );
  }
  if (createFile) {
    (0, import_fs8.writeFileSync)(filePath, fileTemplate);
    logger.log(`${filePath} created!`);
    return true;
  }
  return false;
}

// src/utils/config/get-dt-app-file-config.ts
var import_fs9 = require("fs");
async function getDtAppFileConfig(root, skipTypeCheck = false) {
  logger.debug("Searching for configuration file", DEBUG_CONTEXT);
  const configFileName = await getConfigFileName(root) ?? await createDefaultConfig(root);
  if (configFileName) {
    const fullPath = (0, import_path9.join)(root, configFileName);
    logger.debug(`Found ${fullPath}`, DEBUG_CONTEXT);
    const fileExtension = (0, import_path9.extname)(configFileName);
    switch (fileExtension) {
      case ".js": {
        return require(fullPath);
      }
      case ".json": {
        try {
          return readJson(fullPath);
        } catch (e) {
          if (e instanceof Error) {
            throw new Error(e.message, { cause: 258 /* USER */ });
          } else {
            throw new Error(String(e), { cause: 258 /* USER */ });
          }
        }
      }
      case ".ts":
      case ".cts": {
        const tsconfigPath = findTsConfigPath(root);
        return await extractDtAppConfigFromTs(
          root,
          fullPath,
          tsconfigPath,
          skipTypeCheck,
          fileExtension === ".ts" ? "esm" : "cjs"
        );
      }
    }
  }
}
function findTsConfigPath(root) {
  const isFilePresent = checkIfFileExists({
    cwd: root,
    name: "tsconfig",
    suffix: "json"
  });
  if (isFilePresent) {
    return (0, import_path9.join)(root, "tsconfig.json");
  }
  mkdirp(".dt-app");
  const tempTsConfigPath = (0, import_path9.join)(root, ".dt-app", "tmp-app-tsconfig.json");
  const tempTsConfig = {
    compilerOptions: {
      target: "ESNext",
      module: "ESNext",
      moduleResolution: "node",
      allowSyntheticDefaultImports: true,
      esModuleInterop: true,
      strict: true,
      skipLibCheck: true,
      resolveJsonModule: true,
      types: ["node"],
      typeRoots: ["../node_modules/@types", "../node_modules/@dynatrace"]
    },
    include: ["../app.config.ts", "../app.config.cts"],
    exclude: ["../node_modules", "../dist"]
  };
  try {
    (0, import_fs9.writeFileSync)(tempTsConfigPath, JSON.stringify(tempTsConfig, null, 2));
  } catch (error) {
    logger.debug(
      "Could not write temporary tsconfig, using fallback approach",
      "APP-TSCONFIG"
    );
  }
  return tempTsConfigPath;
}
async function getConfigFileName(cwd) {
  const configFileExtensionList = ["cts", "ts", "js", "json"];
  const configFiles = configFileExtensionList.filter(
    (ext) => checkIfFileExists({
      name: "app",
      suffix: `config.${ext}`,
      cwd
    })
  ).map((ext) => `app.config.${ext}`);
  if (configFiles.length > 1) {
    logger.warn(`Multiple app.config files have been detected. (${configFiles.join(
      ", "
    )})
      ${configFiles[0]} will be used.`);
  }
  return configFiles[0];
}
async function createDefaultConfig(cwd) {
  const template = JSON.parse(`{
      "environmentUrl": "https://<your-tenant>.apps.dynatrace.com/",
      "app": {
        "name": "some-new-app",
        "version": "0.0.0",
        "description": "A starting project with routing, fetching data, and charting",
        "id": "my.some.new.app",
        "scopes": [
          { "name": "storage:logs:read", "comment": "default template" },
          { "name": "storage:buckets:read", "comment": "default template" }
        ]
      }
    }`);
  if (await checkIfExistsAndPromptIfNot(
    {
      name: "app",
      suffix: "config.json",
      cwd
    },
    template,
    "USER"
  )) {
    return "app.config.json";
  }
  return void 0;
}

// src/utils/config/cli-options.ts
var import_path17 = require("path");

// src/utils/config/validate-actions.ts
var import_fs10 = require("fs");
var import_path10 = require("path");
var import_fast_glob2 = __toESM(require("fast-glob"));
function validateActions(actions, options) {
  return actions.map((action) => validateAction(action, options));
}
async function validateAction(action, options) {
  const validatedAction = action;
  const actionExists = (0, import_fs10.existsSync)(
    (0, import_path10.join)(options.root, options.actionsDir, `${action.name}.action.ts`)
  ) || (0, import_fs10.existsSync)(
    (0, import_path10.join)(
      options.root,
      options.actionsDir,
      `${action.name}.resumable.action.ts`
    )
  ) || (0, import_fs10.existsSync)(
    (0, import_path10.join)(
      options.root,
      options.actionsDir,
      `${action.name}.stateful-action.ts`
    )
  );
  if (actionExists) {
    validatedAction.isUiAction = false;
    return validatedAction;
  }
  if (!(await (0, import_fast_glob2.default)("api/**/" + action.name + "*.ts", { cwd: options.root })).length) {
    throw new Error(
      action.name + " has no UI and no function implementation!",
      {
        cause: 257 /* INTERNAL */
      }
    );
  }
  validatedAction.isUiAction = false;
  return validatedAction;
}

// src/utils/config/validate-wave-config.ts
var import_ajv_errors = __toESM(require("ajv-errors"));
var import__ = __toESM(require("ajv/dist/2019"));
var import_chalk4 = require("chalk");
var import_path13 = require("path");

// src/auth/get-automation-token.ts
var import_url = require("url");

// src/utils/request.ts
var import_undici = require("undici");
async function dtFetch(url, options) {
  return (0, import_undici.fetch)(url, options);
}

// src/auth/get-automation-token.ts
async function getAutomationToken({ clientID, clientSecret, accountURN }, oauthUrl, oAuthScopes) {
  if (!clientID || !clientSecret) {
    throw new Error(
      '"clientID" and "clientSecret" are required to fetch an automation token..',
      { cause: 259 /* AUTH */ }
    );
  }
  const parameters = new import_url.URLSearchParams();
  parameters.append("grant_type", "client_credentials");
  if (oAuthScopes) {
    parameters.append(
      "scope",
      oAuthScopes.map((scope) => scope.name).join(" ")
    );
  }
  parameters.append("client_id", clientID);
  parameters.append("client_secret", clientSecret);
  if (accountURN) {
    parameters.append("resource", accountURN);
  }
  try {
    const response = await dtFetch(
      `${new URL(oauthUrl).origin}/sso/oauth2/token`,
      {
        method: "POST",
        body: Buffer.from(parameters.toString()),
        headers: {
          "content-type": "application/x-www-form-urlencoded"
        }
      }
    );
    const body = await response.json();
    if (response.ok) {
      return body;
    } else {
      throw getCredentialsError(
        JSON.stringify(body) ?? "Could not get token from authentication provider"
      );
    }
  } catch (e) {
    const fetchError = e;
    const fetchErrorOutput = fetchError.cause && typeof fetchError.cause !== "number" ? fetchError.cause : fetchError;
    logger.debug(
      `Failed to get automation token! Backend responded with: ${fetchErrorOutput.message}`,
      "AUTH"
    );
    throw new Error(`${fetchErrorOutput.message}`, { cause: 259 /* AUTH */ });
  }
}

// src/utils/get-sso-url.ts
var import_url2 = require("url");

// src/utils/get-url-from-location-header.ts
var linkCache = /* @__PURE__ */ new Map();
async function getUrlFromLocationHeader(url) {
  if (linkCache.has(url)) {
    const resolved2 = linkCache.get(url);
    logger.debug(
      `Found resolved URL in cache: ${resolved2.toString()}`,
      "HTTP(S)"
    );
    return resolved2;
  }
  logger.debug(
    `Execute GET request without allowing redirection to '${url}'`,
    "HTTP(S)"
  );
  const response = await dtFetch(url, {
    redirect: "follow"
  });
  let resolved;
  const headerLocation = response.headers.get("location");
  if (headerLocation) {
    resolved = new URL(headerLocation);
  } else {
    resolved = new URL(response.url);
  }
  logger.debug(`Resolved URL is ${resolved.toString()}`, "HTTP(S)");
  linkCache.set(url, resolved);
  return resolved;
}

// src/utils/get-sso-url.ts
async function getSSOUrl(environmentUrl) {
  try {
    const reqUrl = new import_url2.URL(environmentUrl);
    reqUrl.pathname = "platform/oauth2/authorization/dynatrace-sso";
    logger.debug(
      `Retrieving SSO-URL for environment '${environmentUrl}'`,
      "AUTH"
    );
    const resolved = (await getUrlFromLocationHeader(reqUrl.toString())).origin;
    logger.debug(`Using SSO-URL '${resolved}'`, "AUTH");
    return resolved;
  } catch (e) {
    const error = toError(e);
    logger.debug(
      `SSO-URL for '${environmentUrl}' could not be processed.`,
      "AUTH"
    );
    logger.debug(`Error: ${error.message}`, "AUTH");
    throwWithDynatraceErrorCode(
      new Error(
        `SSO-URL for '${environmentUrl}' could not be processed.
${error.message}
If you need further assistance visit the connectivity troubleshooting guide here: ${"https://dt-url.net/c4jp0s12" /* TROUBLESHOOT_CONNECTIVITY */}`,
        { cause: 258 /* USER */ }
      ),
      "DEC:DA" /* CONNECTION_ERROR */
    );
  }
}

// src/auth/get-bearer-token.ts
var import_path12 = require("path");
var import_fs13 = require("fs");

// src/auth/get-access-token.ts
var import_fastify = __toESM(require("fastify"));
var import_open = __toESM(require("open"));
var import_mime_types = require("mime-types");
var import_querystring = require("querystring");

// src/auth/constants.ts
var import_crypto2 = require("crypto");
var MINIMAL_SCOPES = [
  { name: "app-engine:apps:run", comment: "cli-scope" }
];
function base64URLEncode(buffer) {
  return buffer.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
}
function sha256(content) {
  return (0, import_crypto2.createHash)("sha256").update(content).digest();
}
var OAUTH_CODE_VERIFIER = base64URLEncode((0, import_crypto2.randomBytes)(46));
var OAUTH_CODE_CHALLENGE = base64URLEncode(
  sha256(OAUTH_CODE_VERIFIER)
);
var OAUTH_STATE_PARAMETER = (0, import_crypto2.randomBytes)(20).toString("hex");

// src/auth/request-oauth2-token.ts
async function requestOauth2Token(oauthUrl, clientId, code, callbackUrl) {
  const url = new URL(oauthUrl);
  url.pathname = "/sso/oauth2/token";
  url.searchParams.append("grant_type", "authorization_code");
  url.searchParams.append("code", code);
  url.searchParams.append("client_id", clientId);
  url.searchParams.append("redirect_uri", callbackUrl.toString());
  url.searchParams.append("code_verifier", OAUTH_CODE_VERIFIER);
  const response = await dtFetch(url.toString(), {
    method: "POST",
    headers: {
      "content-type": "application/x-www-form-urlencoded"
    }
  });
  if (!response.ok) {
    throw new Error(response.statusText, { cause: 259 /* AUTH */ });
  }
  return await response.json();
}

// src/utils/clouddev/codespaces.ts
var codespacesEnv = process.env.CODESPACE_NAME && process.env.CODESPACE_NAME.trim() !== "" ? process.env.CODESPACE_NAME : void 0;
function getPublicUrl(port) {
  if (!codespacesEnv) {
    return;
  }
  const domain = process.env.GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN;
  return `${codespacesEnv}-${port}.${domain}`;
}

// src/utils/clouddev/gitpod.ts
var gitpodEnv = process.env.GITPOD_WORKSPACE_URL && process.env.GITPOD_WORKSPACE_URL.trim() !== "" ? process.env.GITPOD_WORKSPACE_URL : void 0;
function getPublicUrl2(port) {
  if (!gitpodEnv) {
    return;
  }
  const hostname = new URL(gitpodEnv).hostname;
  return `${port}-${hostname}`;
}

// src/utils/clouddev/cloud-dev.ts
var customEnv = process.env.DT_APP_DEV_ENVIRONMENT_URL && process.env.DT_APP_DEV_ENVIRONMENT_URL.trim() !== "" ? process.env.DT_APP_DEV_ENVIRONMENT_URL : void 0;
var isCloudDevEnv = gitpodEnv || codespacesEnv || customEnv;
function cloudDevEnvPublicUrl(port) {
  if (!isCloudDevEnv) {
    return;
  }
  if (customEnv) {
    return customEnv.replace(/^https?:\/\//, "");
  }
  return gitpodEnv ? getPublicUrl2(port) : getPublicUrl(port);
}

// src/auth/utils.ts
async function getDtAppCliCallbackUrl(port, environmentUrl) {
  if (isCloudDevEnv) {
    const cloudDevAuthUrl = `https://${cloudDevEnvPublicUrl(port)}/auth/login`;
    return `${environmentUrl}/platform-reserved/app-registry/v1/cde-auth?cde-uri=${encodeURIComponent(
      cloudDevAuthUrl
    )}`;
  }
  return `http://localhost:${port}/auth/login`;
}

// src/utils/is-docker.ts
var import_fs11 = __toESM(require("fs"));
var isDockerCached;
function hasDockerEnv() {
  try {
    import_fs11.default.statSync("/.dockerenv");
    return true;
  } catch {
    return false;
  }
}
function hasDockerCGroup() {
  try {
    return import_fs11.default.readFileSync("/proc/self/cgroup", "utf8").includes("docker");
  } catch {
    return false;
  }
}
function isDocker() {
  if (isDockerCached === void 0) {
    isDockerCached = hasDockerEnv() || hasDockerCGroup();
  }
  return isDockerCached;
}

// src/auth/get-access-token.ts
var import_devkit = require("@dynatrace/devkit");

// src/auth/successful-auth-page.ts
var successfulAuthPageHtml = (
  /* html */
  `<html>
<head>
  <meta charset="utf-8" />
  <title>dt-app - Dynatrace</title>
  <meta name="viewport" content="width=device-width, initial-scale=1" />
</head>
<style>
  @font-face {
    font-family: 'DynatraceFlow';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url(https://dt-cdn.net/fonts/DTFlow-Regular-v002.woff2)
      format('woff2');
  }
  @font-face {
    font-family: 'DynatraceFlow';
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url(https://dt-cdn.net/fonts/DTFlow-Medium-v002.woff2)
      format('woff2');
  }
  @font-face {
    font-family: 'DynatraceFlow';
    font-style: normal;
    font-weight: 600;
    font-display: swap;
    src: url(https://dt-cdn.net/fonts/DTFlow-Semibold-v002.woff2)
      format('woff2');
  }

  :root {
    --bg-color: rgb(243, 243, 247);
    --line-color: #d2d3e1;
    --text-color: rgb(43, 42, 88);
    --text-link-color: rgb(69, 76, 201);
    --text-accent-color: rgb(244, 244, 251);
    --primary-color: rgb(71, 78, 207);
    --font-family: DynatraceFlow, Roboto, Helvetica, sans-serif;


  }

  @media (prefers-color-scheme: dark) {
    :root {
      --bg-color: rgb(25, 25, 44);
      --text-color: rgb(235, 236, 255);
      --line-color: rgb(59, 59, 82);
      --primary-color: rgb(153, 155, 237);
      --text-accent-color: rgb(31, 32, 55);
      --text-link-color: rgb(173, 176, 255);


    }
  }
  body {
    font-family: DynatraceFlow, Roboto, Helvetica, sans-serif;
    color: var(--text-color);
    background-color: var(--bg-color);
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    gap: 16px;
    height: 100%;
    text-align: center;
  }
  * {
    overflow-wrap: break-word;
    font-style: normal;
    color: inherit;
    margin: 0px;
  }
  h1 {
    font-size: 32px;
    font-weight: 600;
    line-height: 1.25;
  }
  p,div,a {
    font-size: 14px;
    font-weight: 400;
    line-height: 20px;
  }
  .divider {
    width: 100%;
    height: 1px;
    border: none;
    margin: 0;
    background-color: var(--line-color);
    max-width: 512px;

  }
  button {
    width: fit-content;
    font-weight: 500;
    font-size: 14px;
    padding: 6px 8px;
    background-color: var(--primary-color);
    color: var(--text-accent-color);
    cursor: pointer;
    height: 32px;
    border-radius: 8px;
    border: 0;
    outline-color: var(--text-accent-color);
  }
  button:disabled {
    --primary-color: #54558780;
    --text-accent-color: #dadbe780;
    cursor: not-allowed;
  }

  a {
    color: var(--text-link-color);
    outline-color: var(--text-link-color);
    text-decoration-color: var(--text-link-color);
  }
  a > span {
    text-decoration: none;
  }
  a > span > svg {
    margin-left: var(--dt-spacings-size-2, 2px);
    width: 1lh;
    height: 1lh;
    max-height: min(1.5em, var(--dt-spacings-size-40, 40px));
    max-width: min(1.5em, var(--dt-spacings-size-40, 40px));
    vertical-align: middle;
    margin-bottom: -0.1em;
    margin-top: -0.1em;
  }

</style>
<body>
<img style="max-width: 256px;"
  ${/** cSpell: disable-next-line */
  ""}
    src="data:image/svg+xml,%3Csvg width='128' height='128' viewBox='0 0 73 73' fill='none' xmlns='http://www.w3.org/2000/svg' %3E%3Cpath d='M24.736 6.39229C23.83 11.1739 22.7227 18.2708 22.1187 25.4684C21.0617 38.1523 21.716 46.6585 21.716 46.6585L3.84787 63.6207C3.84787 63.6207 2.48888 54.1078 1.78422 43.3869C1.38156 36.743 1.23056 30.9044 1.23056 27.3811C1.23056 27.1797 1.33123 26.9784 1.33123 26.7771C1.33123 26.5254 1.63322 24.1598 3.94853 21.9451C6.46517 19.5291 25.038 4.98297 24.736 6.39229Z' fill='%231496FF' /%3E%3Cpath d='M24.736 6.39226C23.83 11.1739 22.7227 18.2708 22.1187 25.4684C22.1187 25.4684 2.33788 23.1028 1.23056 27.8844C1.23056 27.6327 1.58289 24.7134 3.8982 22.4988C6.41484 20.0828 25.038 4.98294 24.736 6.39226Z' fill='%231284EA' /%3E%3Cpath d='M1.23057 26.7267C1.23057 27.0791 1.23057 27.4314 1.23057 27.834C1.4319 26.9784 1.78423 26.3744 2.48889 25.4181C3.94854 23.5558 6.31418 23.0524 7.2705 22.9518C12.1025 22.2974 19.2497 21.5424 26.4473 21.3411C39.1815 20.9385 47.5871 21.9954 47.5871 21.9954L65.4552 5.03329C65.4552 5.03329 56.0933 3.27164 45.4228 2.01332C38.4265 1.15766 32.2859 0.70467 28.8129 0.503339C28.5613 0.503339 26.095 0.201342 23.7797 2.41598C21.263 4.83196 8.47849 16.9622 3.34455 21.8444C1.02924 24.0591 1.23057 26.5254 1.23057 26.7267Z' fill='%23B4DC00' /%3E%3Cpath d='M64.8009 48.4202C59.9689 49.0745 52.8217 49.8798 45.6241 50.1315C32.8899 50.5341 24.434 49.4771 24.434 49.4771L6.56584 66.4896C6.56584 66.4896 16.0284 68.3519 26.699 69.5599C33.2422 70.3149 39.0305 70.7176 42.5538 70.9189C42.8055 70.9189 43.2081 70.7176 43.4598 70.7176C43.7114 70.7176 46.1777 70.2646 48.4931 68.0499C51.0097 65.634 66.2102 48.2692 64.8009 48.4202Z' fill='%236F2DA8' /%3E%3Cpath d='M64.8009 48.4202C59.969 49.0745 52.8217 49.8798 45.6241 50.1315C45.6241 50.1315 46.9831 70.0129 42.2015 70.8686C42.4531 70.8686 45.7248 70.7176 48.0401 68.503C50.5567 66.087 66.2102 48.2692 64.8009 48.4202Z' fill='%23591F91' /%3E%3Cpath d='M43.2584 70.9693C42.9061 70.9693 42.5538 70.9189 42.1511 70.9189C43.0571 70.7679 43.6611 70.4659 44.6174 69.7613C46.5301 68.4023 47.1341 66.0367 47.3354 65.0803C48.1911 60.2987 49.3487 53.2018 49.9024 46.0042C50.909 33.3203 50.305 24.8644 50.305 24.8644L68.1732 7.85194C68.1732 7.85194 69.4818 17.3145 70.2368 28.0354C70.6898 35.0317 70.8408 41.2226 70.8911 44.6452C70.8911 44.8969 71.0925 47.3632 68.7772 49.5778C66.2605 51.9938 53.476 64.1743 48.3924 69.0566C45.9764 71.2713 43.5101 70.9693 43.2584 70.9693Z' fill='%2373BE28' /%3E%3C/svg%3E"
  />
  <h1>App Toolkit: Successfully authenticated</h1>
  <p>You have been successfully authenticated!</p>
  <div style="display: flex; gap: 8px; flex-direction: column; align-items: center;">
    <button id="closeButton" onclick="closeTab()">Close tab</button>
  </div>
  <div class="divider"></div>
  <div>
    Explore our
    <a href="${"https://dt-url.net/bm034a8" /* QUICKSTART_APP_TOOLKIT */}">
      Documentation<span><svg focusable="false" role="img" aria-hidden="false" fill="currentColor" width="20" height="20" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" aria-label="Opening the link in a new window"><path d="M17.0003 3L17.0003 9H15.5003L15.5003 5.62104L11.0607 10.0607L10 9L14.5 4.5L11.0003 4.5V3H17.0003Z"></path><path d="M8 3H4C3.44772 3 3 3.44772 3 4V16C3 16.5523 3.44772 17 4 17H16C16.5523 17 17 16.5523 17 16V12H15.5V15.5H4.5V4.5H8V3Z"></path></svg></span></a>.
  </div>
  <script>
    const infoText = "The page could not be closed, please close it manually."
    const button = document.querySelector("#closeButton")

    function closeTab() {
      window.close();
      window.top.close();

      const isClosed = window.closed || window.top.closed;
      if (!isClosed) {
        button.title = infoText;
        button.disabled = true;
        const infoP = document.createElement("p")
        infoP.textContent = infoText;
        button.parentElement?.append(infoP)
        alert(infoText)
      }
    }
  </script>
</body>
</html>
`
);

// src/auth/get-access-token.ts
var pendingOauthRequest = null;
async function getAccessToken(oauthUrl, clientId, oAuthScopes, openAuthUrl, environmentUrl) {
  if (pendingOauthRequest !== null) {
    return pendingOauthRequest;
  }
  logger.debug("Authenticate with Dynatrace SSO", "AUTH");
  pendingOauthRequest = fetchAccessToken(
    oauthUrl,
    clientId,
    oAuthScopes,
    openAuthUrl,
    environmentUrl
  ).then((code) => {
    pendingOauthRequest = null;
    return code;
  });
  return pendingOauthRequest;
}
async function fetchAccessToken(oauthUrl, clientId, oAuthScopes, openAuthUrl, environmentUrl) {
  const server = (0, import_fastify.default)({ forceCloseConnections: true });
  server.addHttpMethod("PROPFIND");
  const port = await (0, import_devkit.findPortInRange)("localhost", 5343, 5363);
  const callbackUrl = new URL(
    await getDtAppCliCallbackUrl(port, environmentUrl)
  );
  const params = (0, import_querystring.stringify)({
    client_id: clientId,
    redirect_uri: callbackUrl.toString(),
    state: OAUTH_STATE_PARAMETER,
    response_type: "code",
    code_challenge_method: "S256",
    code_challenge: OAUTH_CODE_CHALLENGE,
    ...oAuthScopes ? { scope: oAuthScopes.map((scope) => scope.name).join(" ") } : {}
  });
  const ssoBaseUrl = new URL(oauthUrl).origin;
  let resolveCode;
  const codePromise = new Promise((_resolve) => {
    resolveCode = _resolve;
  });
  server.get(
    "/auth/login",
    async (request, reply) => {
      const { code: code2, state } = request.query;
      logger.debug("Received authorized code for oAuth", "AUTH");
      resolveCode({ code: code2, state });
      return reply.code(200).header("Content-Type", (0, import_mime_types.contentType)(".html")).send(successfulAuthPageHtml);
    }
  );
  const ssoUrl = unixJoin([ssoBaseUrl, `oauth2/authorize?${params}`]);
  const response = await dtFetch(ssoUrl);
  if (!response.ok) {
    pendingOauthRequest = null;
    logger.debug(response.statusText, "AUTH");
    throw new Error(
      "Authentication failed! Please check if the scopes you specified are valid and if the user has permissions for all of those scopes.",
      { cause: 259 /* AUTH */ }
    );
  }
  await server.listen({
    port,
    ...isDocker() && { host: "0.0.0.0" }
  });
  logger.debug(`SSO-link ${ssoUrl}`, "AUTH");
  if (openAuthUrl) {
    await (0, import_open.default)(ssoUrl);
  } else {
    logger.log(`Open this url to authenticate: ${ssoUrl}`);
  }
  const { code } = await codePromise;
  server.close();
  return requestOauth2Token(oauthUrl, clientId, code, callbackUrl);
}

// src/auth/refresh-oauth2-tokens.ts
async function refreshOauth2Token(oauthUrl, clientId, refreshToken2) {
  const url = new URL(oauthUrl);
  url.pathname = "/sso/oauth2/token";
  url.searchParams.append("grant_type", "refresh_token");
  url.searchParams.append("client_id", clientId);
  url.searchParams.append("refresh_token", refreshToken2);
  const response = await dtFetch(url.toString(), {
    method: "POST",
    headers: {
      "content-type": "application/x-www-form-urlencoded"
    }
  });
  if (!response.ok) {
    const data = await response.json();
    throw new Error(
      data.error_description ? `${data.error_description} (traceId: ${data.issueId})` : response.statusText,
      {
        cause: 259 /* AUTH */
      }
    );
  }
  return await response.json();
}

// src/auth/token-handling-utils.ts
var import_fs12 = require("fs");
var import_path11 = require("path");

// src/utils/array-utils.ts
var import_lodash3 = require("lodash");
function areEqual(array1, array2) {
  if (array1.length !== array2.length) {
    return false;
  }
  return isPartOf(array1, array2);
}
function isPartOf(array1, array2) {
  return array1.every((element) => {
    if (typeof element === "object") {
      return !!array2.find((element2) => (0, import_lodash3.isEqual)(element, element2));
    }
    return array2.includes(element);
  });
}

// src/auth/check-oauth2-token-validity.ts
var import_jsonwebtoken = require("jsonwebtoken");
var LOGGER_PREFIX = "AUTH";
function checkIfTokenIsCorrect(token, environmentUrl, oauthUrl, oauthClientId, oAuthScopes) {
  const requestedScopes = oAuthScopes?.map((scope) => scope.name) || [];
  const grantedScopes = token.scope?.split(" ") || [];
  const areScopesCorrect = oAuthScopes ? areEqual(requestedScopes, grantedScopes) : true;
  const sth = token.environment_url === environmentUrl && token.oauth_url === oauthUrl && token.oauth_client_id === oauthClientId && areScopesCorrect;
  return sth;
}
function isTokenValid(token) {
  try {
    const decodedAccessToken = (0, import_jsonwebtoken.decode)(token);
    const expirationTimestamp = decodedAccessToken.exp;
    const expirationDate = new Date(expirationTimestamp * 1e3);
    const now = /* @__PURE__ */ new Date();
    const expiresInMilliSeconds = expirationDate.getTime() - now.getTime();
    const expiresInSeconds = expiresInMilliSeconds * 1e-3;
    if (expiresInSeconds < 60) {
      logger.debug(
        `OAuth2 token expired with a value of: ${expiresInSeconds} seconds`,
        LOGGER_PREFIX
      );
      return false;
    }
    return true;
  } catch (error) {
    return false;
  }
}

// src/auth/token-handling-utils.ts
async function validateToken(bearerTokenContext) {
  const {
    currentAuthWorkflow,
    tokenFilePath,
    environmentUrl,
    oauthUrl,
    oauthClientId,
    appScopes,
    tokenInformation
  } = bearerTokenContext;
  const tokenExists = (0, import_fs12.existsSync)(tokenFilePath);
  if (!tokenInformation || !tokenExists) {
    return "invalid" /* INVALID */;
  }
  if (tokenInformation.authentication_flow !== currentAuthWorkflow) {
    return "invalid" /* INVALID */;
  }
  const isCorrect = checkIfTokenIsCorrect(
    tokenInformation,
    environmentUrl,
    oauthUrl,
    oauthClientId,
    appScopes
  );
  const isValid = isTokenValid(tokenInformation.access_token);
  if (!isCorrect) {
    return "invalid" /* INVALID */;
  }
  if (isValid) {
    return "valid" /* VALID */;
  }
  if (!isValid) {
    return "refresh-required" /* REFRESH_REQUIRED */;
  }
  return "invalid" /* INVALID */;
}
function writeTokenFile(tokenFilePath, fileContent) {
  if (!(0, import_fs12.existsSync)((0, import_path11.dirname)(tokenFilePath))) {
    (0, import_fs12.mkdirSync)((0, import_path11.dirname)(tokenFilePath), { recursive: true });
  }
  (0, import_fs12.writeFileSync)(tokenFilePath, JSON.stringify(fileContent, null, 2));
}

// src/utils/promise-utils.ts
var promiseStore = /* @__PURE__ */ new Map();
async function singlePromise(promiseFn, key) {
  if (promiseStore.has(key)) {
    logger.debug(
      `Promise with key ${key} meant to be run once at a time. Initial promise will be returned!`,
      "promise"
    );
    return promiseStore.get(key);
  }
  const promise = promiseFn();
  promiseStore.set(key, promise);
  try {
    return await promise;
  } catch (e) {
    promiseStore.delete(key);
    throw e;
  } finally {
    promiseStore.delete(key);
  }
}

// src/auth/get-bearer-token.ts
var SSO_CLIENT_ID = "dt0s08.dt-app-local";
var defaultGetBearerOptions = (cwd) => {
  return {
    openAuthUrl: true,
    tokenFilePath: (0, import_path12.join)(cwd, ".dt-app/.tokens.json")
  };
};
async function getBearerToken(options, appScopes) {
  const bearerTokenContext = await createTokenContext(options, appScopes);
  const tokenValidity = await validateToken(bearerTokenContext);
  if (tokenValidity === "refresh-required" /* REFRESH_REQUIRED */) {
    return singlePromise(async () => {
      try {
        const token = await refreshToken(bearerTokenContext);
        return token;
      } catch (error) {
        logger.debug(
          `Refresh process for token ${bearerTokenContext.tokenType} has failed with: ${error}. Proceeding with SSO flow instead.`,
          "AUTH"
        );
        return getAutomationOrAccessToken(
          bearerTokenContext,
          "invalid" /* INVALID */
        );
      }
    }, bearerTokenContext.tokenType);
  }
  return getAutomationOrAccessToken(bearerTokenContext, tokenValidity);
}
async function getAutomationOrAccessToken(bearerTokenContext, tokenValidity) {
  if (process.env.DT_APP_PLATFORM_TOKEN) {
    logger.debug("Using DT_APP_PLATFORM_TOKEN for authentication.", "AUTH");
    return process.env.DT_APP_PLATFORM_TOKEN;
  }
  const {
    currentAuthWorkflow,
    tokenFilePath,
    environmentUrl,
    oauthUrl,
    oauthClientId,
    appScopes,
    tokenType,
    currentTokenFileContent,
    tokenInformation,
    openAuthUrl
  } = bearerTokenContext;
  if (tokenValidity === "valid" /* VALID */) {
    return tokenInformation.access_token;
  }
  let token = "";
  let tokenFileContent = currentTokenFileContent;
  if (currentAuthWorkflow === "automation" /* AUTOMATION */) {
    try {
      [tokenFileContent, token] = await processAutomationToken(
        tokenFileContent,
        tokenType,
        environmentUrl,
        oauthClientId,
        process.env.DT_APP_OAUTH_CLIENT_SECRET,
        oauthUrl,
        appScopes
      );
    } catch (e) {
      const permissions = await Promise.all(
        (appScopes || []).map(
          (appScope) => processAutomationToken(
            tokenFileContent,
            tokenType,
            environmentUrl,
            oauthClientId,
            process.env.DT_APP_OAUTH_CLIENT_SECRET,
            oauthUrl,
            [appScope]
          ).then(() => ({ appScope, granted: true })).catch(() => ({ appScope, granted: false }))
        )
      );
      const missing = permissions.filter(({ granted }) => !granted).map(({ appScope }) => appScope.name).join(",");
      if (missing) {
        throw new Error(
          `Could not authenticate using the automation token! missing permissions: ${missing}`
        );
      } else {
        throw e;
      }
    }
  }
  if (tokenValidity === "invalid" /* INVALID */ && currentAuthWorkflow === "sso" /* SSO */) {
    [tokenFileContent, token] = await processAccessToken(
      tokenFileContent,
      tokenType,
      environmentUrl,
      oauthUrl,
      oauthClientId,
      appScopes,
      openAuthUrl
    );
  }
  writeTokenFile(tokenFilePath, tokenFileContent);
  return token;
}
async function refreshToken(bearerTokenContext) {
  const {
    currentTokenFileContent,
    tokenType,
    environmentUrl,
    oauthUrl,
    oauthClientId,
    tokenFilePath
  } = bearerTokenContext;
  const [tokenFileContent, token] = await processRefreshOauth2Token(
    currentTokenFileContent,
    tokenType,
    environmentUrl,
    oauthUrl,
    oauthClientId
  );
  writeTokenFile(tokenFilePath, tokenFileContent);
  return token;
}
async function createTokenContext(options, appScopes) {
  const { tokenType, tokenFilePath, environmentUrl, openAuthUrl } = {
    ...defaultGetBearerOptions(options.cwd),
    ...options
  };
  if (appScopes) {
    appScopes = enrichAppScopes(appScopes, MINIMAL_SCOPES);
  }
  const oauthUrl = options.ssoPublishUrl ?? await getSSOUrl(environmentUrl);
  const oauthClientId = options.customClientId ?? process.env.DT_APP_OAUTH_CLIENT_ID ?? SSO_CLIENT_ID;
  const currentAuthWorkflow = getCurrentAuthWorkflow();
  let currentTokenFileContent = {};
  let tokenInformation;
  if ((0, import_fs13.existsSync)(tokenFilePath)) {
    currentTokenFileContent = readJson(tokenFilePath);
    if (tokenType === "toolkit" /* TOOLKIT_TOKEN */) {
      tokenInformation = currentTokenFileContent.toolkit_token;
    } else {
      tokenInformation = currentTokenFileContent.app_token;
    }
  }
  return {
    currentAuthWorkflow,
    tokenType,
    tokenFilePath,
    environmentUrl,
    openAuthUrl,
    appScopes,
    oauthUrl,
    oauthClientId,
    currentTokenFileContent,
    tokenInformation
  };
}
async function processAutomationToken(tokenJson, tokenType, environmentUrl, clientId, clientSecret, oauthUrl, appScopes) {
  const tokenResponse = await getAutomationToken(
    {
      clientID: clientId,
      clientSecret
    },
    oauthUrl,
    appScopes
  );
  const tokenInformation = {
    ...tokenResponse,
    environment_url: environmentUrl,
    oauth_url: oauthUrl,
    oauth_client_id: clientId,
    authentication_flow: "automation" /* AUTOMATION */
  };
  tokenJson = addTokenInformation(tokenJson, tokenInformation, tokenType);
  return [tokenJson, tokenInformation.access_token];
}
async function processRefreshOauth2Token(tokenJson, tokenType, environmentUrl, oauthUrl, clientId) {
  let tokenRawData;
  if (tokenType === "toolkit" /* TOOLKIT_TOKEN */) {
    tokenRawData = tokenJson.toolkit_token;
  } else {
    tokenRawData = tokenJson.app_token;
  }
  const tokenResponse = await refreshOauth2Token(
    oauthUrl,
    clientId,
    tokenRawData.refresh_token
  );
  const tokenInformation = {
    ...tokenResponse,
    environment_url: environmentUrl,
    oauth_url: oauthUrl,
    oauth_client_id: clientId,
    authentication_flow: "sso" /* SSO */
  };
  tokenJson = addTokenInformation(tokenJson, tokenInformation, tokenType);
  return [tokenJson, tokenInformation.access_token];
}
async function processAccessToken(tokenJson, tokenType, environmentUrl, oauthUrl, clientId, appScopes, openAuthUrl) {
  const tokenResponse = await getAccessToken(
    oauthUrl,
    clientId,
    appScopes,
    openAuthUrl,
    environmentUrl
  );
  const tokenInformation = {
    ...tokenResponse,
    environment_url: environmentUrl,
    oauth_url: oauthUrl,
    oauth_client_id: clientId,
    authentication_flow: "sso" /* SSO */
  };
  tokenJson = addTokenInformation(tokenJson, tokenInformation, tokenType);
  return [tokenJson, tokenInformation.access_token];
}
function addTokenInformation(tokenJson, tokenInformation, tokenType) {
  if (tokenType === "toolkit" /* TOOLKIT_TOKEN */) {
    tokenJson.toolkit_token = tokenInformation;
  } else {
    tokenJson.app_token = tokenInformation;
  }
  return tokenJson;
}
function enrichAppScopes(scopes, scopesToAdd) {
  const allScopes = scopesToAdd.concat(scopes);
  return [...new Map(allScopes.map((v) => [v.name, v])).values()];
}
function getCurrentAuthWorkflow() {
  if (process.env.DT_APP_OAUTH_CLIENT_ID && process.env.DT_APP_OAUTH_CLIENT_SECRET) {
    return "automation" /* AUTOMATION */;
  }
  return "sso" /* SSO */;
}

// src/utils/gateway-communication.ts
var APP_REGISTRY_BASE_URL = "/platform/app-engine/registry/v1";

// src/utils/config/validate-wave-config.ts
var additionalPropErrorMessage = "contains unknown property ${0#}. Please check if there is a typo or remove it";
var extraAppOptionSchema = {
  properties: {
    id: {
      type: "string",
      pattern: "^[a-z0-9]+(\\.[a-z0-9]+)*$",
      maxLength: 50
    },
    name: {
      type: "string",
      maxLength: 40
    },
    selfMonitoringAgent: {
      description: "Agentless real user monitoring url",
      type: "string"
    }
  }
};
var defaultAppOptionSchema = {
  $schema: "https://json-schema.org/draft/2019-09/schema",
  $id: "https://example.com/app.manifest.default.schema.json",
  type: "object",
  properties: {
    id: {
      type: "string",
      pattern: "^[a-z0-9\\.]*$"
    },
    name: {
      type: "string"
    },
    description: {
      type: "string"
    },
    version: {
      type: "string"
    },
    icon: {
      nullable: true,
      type: "string",
      format: "relative-path",
      errorMessage: "must be a relative path"
    }
  },
  additionalProperties: true,
  required: ["id", "name", "version", "description"]
};
var appOptionsErrorMessages = {
  errorMessage: {
    required: {
      name: "must contain property 'name'. Please specify 'app.name' in your 'app.config.(json|js|ts)' file",
      description: "must contain property 'description'. Please specify 'app.description' in your 'app.config.(json|js|ts)' file",
      version: "must contain property 'version'. Please specify 'app.version' in your 'app.config.(json|js|ts)' file"
    },
    properties: {
      id: `is invalid. There could be multiple reasons for that:
If unspecified, the app ID is generated by joining all segments of 'app.name' (separated with a dot). In this case, please check 'app.name' for special characters or try a shorter name.
If you specified an id, please make sure it does not contain special characters or try a shorter one.`,
      version: "must be a valid semver (MAJOR.MINOR.PATCH)"
    }
  }
};
var pluginsSchema = {
  $schema: "https://json-schema.org/draft/2019-09/schema",
  $id: "https://example.com/plugins.schema",
  type: "array",
  uniqueItems: true,
  items: {
    type: "object",
    // eslint-disable-next-line @typescript-eslint/ban-ts-comment
    // @ts-ignore
    additionalProperties: {
      not: true,
      errorMessage: additionalPropErrorMessage
    },
    properties: {
      name: {
        type: "string"
      },
      setup: {}
    }
  }
};
var sourceMapSchema = {
  $schema: "https://json-schema.org/draft/2019-09/schema",
  $id: "https://example.com/sourcemap.schema",
  enum: [true, false, "all"],
  errorMessage: "must be a boolean value or 'all'"
};
var assetsSchema = {
  $schema: "https://json-schema.org/draft/2019-09/schema",
  $id: "https://example.com/assets.schema",
  type: "array",
  items: {
    type: "object",
    // eslint-disable-next-line @typescript-eslint/ban-ts-comment
    // @ts-ignore
    additionalProperties: {
      not: true,
      errorMessage: additionalPropErrorMessage
    },
    properties: {
      glob: {
        type: "string",
        format: "valid-glob",
        errorMessage: "has to be a glob pattern"
      },
      ignore: {
        type: "array",
        items: {
          type: "string",
          format: "valid-glob",
          errorMessage: "has to be a glob pattern"
        }
      },
      input: { type: "string" },
      output: {
        type: "string",
        format: "relative-path",
        errorMessage: "must be a relative path"
      }
    },
    required: ["glob", "ignore", "input", "output"],
    errorMessage: {
      required: {
        glob: "must contain property 'glob'",
        ignore: "must contain property 'ignore'",
        input: "must contain property 'input'",
        output: "must contain property 'output'"
      }
    }
  }
};
function initSchema(appSchema, sourceRoot) {
  const ajv = new import__.default({
    allErrors: true,
    formats: {
      "absolute-path": {
        type: "string",
        validate: (val) => (0, import_path13.isAbsolute)(val)
      },
      "relative-path": {
        type: "string",
        validate: (val) => !(0, import_path13.isAbsolute)(val)
      },
      "valid-glob": {
        type: "string",
        validate: (val) => {
          return val !== null && val.length > 0;
        }
      }
    },
    strict: false
  });
  (0, import_ajv_errors.default)(ajv);
  ajv.addSchema(pluginsSchema);
  ajv.addSchema(assetsSchema);
  ajv.addSchema(appSchema);
  ajv.addSchema(sourceMapSchema);
  const schema = {
    // Incomplete typings
    type: "object",
    required: [
      "root",
      "environmentUrl",
      "distDir",
      "injectSdk",
      "dryRun",
      "deploy",
      "app",
      "server",
      "build",
      "plugins"
    ],
    // eslint-disable-next-line @typescript-eslint/ban-ts-comment
    // @ts-ignore
    additionalProperties: {
      not: true,
      errorMessage: additionalPropErrorMessage
    },
    errorMessage: {
      required: {
        environmentUrl: "must contain a valid 'environmentUrl'. Please specify one in your 'app.config.(json|js|ts)' file"
      }
    },
    properties: {
      executionMode: {
        type: "string"
      },
      appFunctionsBuildPlatform: {
        type: "string"
      },
      root: {
        type: "string",
        format: "absolute-path",
        errorMessage: "must be an absolute path"
      },
      environmentUrl: {
        type: "string"
      },
      oauthClientId: {
        type: "string"
      },
      oauthClientSecret: {
        type: "string"
      },
      oauthScopes: {
        type: "array",
        items: {
          type: "string"
        }
      },
      distDir: {
        type: "string",
        format: "relative-path",
        errorMessage: "must be a relative path"
      },
      oauth2File: { type: "string" },
      icon: {
        nullable: true,
        type: "string",
        format: "relative-path",
        errorMessage: "must be a relative path"
      },
      injectSdk: { type: "boolean" },
      dryRun: { type: "boolean" },
      noLiveReload: { type: "boolean" },
      deploy: {
        type: "object",
        required: ["build"],
        // eslint-disable-next-line @typescript-eslint/ban-ts-comment
        // @ts-ignore
        additionalProperties: {
          not: true,
          errorMessage: additionalPropErrorMessage
        },
        // eslint-disable-next-line @typescript-eslint/ban-ts-comment
        // @ts-ignore
        properties: {
          // eslint-disable-next-line @typescript-eslint/ban-ts-comment
          // @ts-ignore
          build: { type: "boolean" },
          // eslint-disable-next-line @typescript-eslint/ban-ts-comment
          // @ts-ignore
          manifest: { type: "string", nullable: true }
        }
      },
      server: {
        type: "object",
        required: ["open", "port", "host"],
        // eslint-disable-next-line @typescript-eslint/ban-ts-comment
        // @ts-ignore
        additionalProperties: {
          not: true,
          errorMessage: additionalPropErrorMessage
        },
        properties: {
          open: { type: "boolean" },
          port: { type: "number" },
          host: { type: "string" },
          showWarnings: { type: "boolean" },
          enableCSP: { type: "boolean" },
          https: {
            nullable: true,
            type: "object",
            required: ["key", "cert"],
            properties: {
              key: { type: "string" },
              cert: { type: "string" }
            }
          }
        }
      },
      dev: {
        type: "object",
        required: ["fileWatcher"],
        // eslint-disable-next-line @typescript-eslint/ban-ts-comment
        // @ts-ignore
        additionalProperties: {
          not: true,
          errorMessage: additionalPropErrorMessage
        },
        properties: {
          fileWatcher: {
            type: "object",
            required: ["ignore"],
            // eslint-disable-next-line @typescript-eslint/ban-ts-comment
            // @ts-ignore
            additionalProperties: {
              not: true,
              errorMessage: additionalPropErrorMessage
            },
            properties: {
              ignore: {
                type: "array",
                items: {
                  type: "string",
                  format: "valid-glob",
                  errorMessage: "has to be a glob pattern"
                }
              },
              include: {
                type: "array",
                items: {
                  type: "string",
                  format: "valid-glob",
                  errorMessage: "has to be a glob pattern"
                }
              }
            }
          }
        }
      },
      app: { $ref: appSchema.$id },
      build: {
        type: "object",
        required: ["index", "mode", "baseHref", "ui", "functions"],
        // eslint-disable-next-line @typescript-eslint/ban-ts-comment
        // @ts-ignore
        additionalProperties: {
          not: true,
          errorMessage: additionalPropErrorMessage
        },
        properties: {
          index: {
            type: "string",
            format: "relative-path",
            errorMessage: "must be a relative path"
          },
          sourceRoot: { type: "string" },
          sourceMaps: {
            $ref: sourceMapSchema.$id
          },
          mode: { type: "string" },
          settingsPath: { type: "string" },
          baseHref: { type: "string" },
          typeCheck: { type: "boolean" },
          ui: {
            type: "object",
            required: ["entryPoint", "tsconfig", "assets"],
            // eslint-disable-next-line @typescript-eslint/ban-ts-comment
            // @ts-ignore
            additionalProperties: {
              not: true,
              errorMessage: additionalPropErrorMessage
            },
            properties: {
              entryPoint: {
                type: "string",
                format: "relative-path",
                errorMessage: 'must be a relative path to a TypeScript file inside the "src" directory',
                pattern: `^src\\/|\\\\.*|ui\\/|\\\\.*|${sourceRoot}\\/|\\\\.*`
                // Must be inside the src/ or /ui directory
              },
              additionalEntryPoints: {
                type: "array",
                items: {
                  type: "string",
                  format: "relative-path",
                  errorMessage: 'must be a relative path to a TypeScript file inside the "src" directory',
                  pattern: "^src\\/|\\\\.*"
                  // Must be inside the src/ directory
                }
              },
              sourceMaps: {
                $ref: sourceMapSchema.$id
              },
              tsconfig: {
                type: "string",
                format: "relative-path",
                errorMessage: "must be a relative path"
              },
              plugins: {
                $ref: pluginsSchema.$id
              },
              assets: {
                $ref: assetsSchema.$id
              }
            }
          },
          functions: {
            type: "object",
            required: ["input", "glob", "tsconfig"],
            // eslint-disable-next-line @typescript-eslint/ban-ts-comment
            // @ts-ignore
            additionalProperties: {
              not: true,
              errorMessage: additionalPropErrorMessage
            },
            properties: {
              input: {
                type: "string",
                format: "relative-path",
                errorMessage: "must be a relative path"
              },
              glob: {
                type: "string",
                format: "valid-glob",
                errorMessage: "has to be a glob pattern"
              },
              sourceMaps: {
                $ref: sourceMapSchema.$id
              },
              tsconfig: {
                type: "string",
                format: "relative-path",
                errorMessage: "must be a relative path"
              },
              plugins: {
                $ref: pluginsSchema.$id
              }
            }
          },
          api: {
            type: "object",
            // eslint-disable-next-line @typescript-eslint/ban-ts-comment
            // @ts-ignore
            additionalProperties: {
              not: true,
              errorMessage: additionalPropErrorMessage
            },
            properties: {
              sourceMaps: {
                $ref: sourceMapSchema.$id
              }
            }
          },
          widgets: {
            type: "object",
            required: [],
            // eslint-disable-next-line @typescript-eslint/ban-ts-comment
            // @ts-ignore
            additionalProperties: {
              not: true,
              errorMessage: additionalPropErrorMessage
            },
            properties: {
              plugins: {
                $ref: pluginsSchema.$id
              }
            }
          },
          selfMonitoringAgent: {
            type: "string"
          },
          actions: {
            type: "object",
            required: [],
            // eslint-disable-next-line @typescript-eslint/ban-ts-comment
            // @ts-ignore
            additionalProperties: {
              not: true,
              errorMessage: additionalPropErrorMessage
            },
            properties: {
              plugins: {
                $ref: pluginsSchema.$id
              }
            }
          },
          dynatraceDependencies: {
            type: "object",
            required: [],
            // eslint-disable-next-line @typescript-eslint/ban-ts-comment
            // @ts-ignore
            additionalProperties: {
              not: true,
              errorMessage: additionalPropErrorMessage
            },
            properties: {
              addOrOverride: {
                type: "object",
                required: [],
                nullable: true,
                additionalProperties: {
                  type: "string"
                }
              },
              ignore: {
                nullable: true,
                type: "array",
                items: {
                  type: "string"
                }
              }
            }
          }
        }
      },
      plugins: {
        type: "array",
        items: {
          type: "string"
        }
      }
    }
  };
  return ajv.compile(schema);
}
async function validateConfig(config, validationLevel = "default") {
  const requiredOptions = checkRequiredOptions(config);
  const appSchema = requiredOptions && validationLevel === "deployment" ? await getAppOptionSchema({
    ...requiredOptions,
    oauthClientSecret: config.oauthClientSecret,
    oauthClientId: config.oauthClientId,
    scopes: config.app.scopes,
    open: config?.server?.open
  }) : defaultAppOptionSchema;
  const validate = initSchema(
    mergeRecursively(
      mergeRecursively(appSchema, extraAppOptionSchema),
      appOptionsErrorMessages
    ),
    config?.build?.sourceRoot
  );
  if (validationLevel === "none" || validate(config)) {
    return config;
  } else {
    for (const err of validate.errors) {
      logger.info(prettyConsoleError2(err));
    }
    throw new Error("App config validation failed", {
      cause: 264 /* VALIDATION */
    });
  }
}
async function getAppOptionSchema(options) {
  try {
    const token = await getBearerToken({
      tokenType: "toolkit" /* TOOLKIT_TOKEN */,
      cwd: options.root,
      environmentUrl: options.environmentUrl,
      openAuthUrl: options.open,
      tokenFilePath: options.oauth2File
    });
    const response = await dtFetch(
      `${options.environmentUrl}${APP_REGISTRY_BASE_URL}/app.manifest.schema.json`,
      {
        method: "GET",
        headers: {
          Authorization: `Bearer ${token}`
        }
      }
    );
    if (response.ok) {
      const schema = await response.json();
      delete schema.properties.documents;
      delete schema.properties.icon;
      schema.additionalProperties = true;
      return schema;
    }
    logger.debug(
      `Error code: ${response.status}. Error message: ${response.statusText}. Request Url: ${response.url}`,
      "DEPLOY"
    );
  } catch (_err) {
  }
  logger.info(
    `> ${import_chalk4.bold`CLI configuration`}: ${import_chalk4.yellow`warning`} Could not fetch JSON schema for validating option 'app' from specified environment '${options.environmentUrl}'. Validation for this option can not be performed according to this environment.`
  );
  return defaultAppOptionSchema;
}
function checkRequiredOptions(options) {
  const requiredOptions = {
    environmentUrl: options.environmentUrl,
    appName: options.app ? options.app.name : void 0,
    root: options.root,
    oauth2File: options.oauth2File
  };
  const schema = {
    type: "object",
    required: ["root", "environmentUrl", "appName"],
    additionalProperties: false,
    properties: {
      root: {
        type: "string"
      },
      environmentUrl: {
        type: "string"
      },
      oauth2File: {
        type: "string"
      },
      appName: {
        type: "string"
      }
    }
  };
  const validate = new import__.default().compile(schema);
  if (validate(requiredOptions)) {
    return requiredOptions;
  }
  return void 0;
}
function prettyConsoleError2(error) {
  const type = import_chalk4.red`error:`;
  let instancePath = error.instancePath ?? "";
  if (error.schemaPath && error.schemaPath.indexOf("additionalProperties") >= 0 && instancePath.indexOf("app") < 0) {
    instancePath = instancePath?.substr(0, error.instancePath.lastIndexOf("/"));
  }
  const prop = instancePath ? instancePath.split("/").reduce((acc, cur) => {
    if (!acc) {
      return cur;
    }
    if (!isNaN(+cur)) {
      return `${acc}[${cur}]`;
    }
    return `${acc}.${cur}`;
  }) : "CliOptions";
  const message = error.message ? error.message.replace(/"/gi, "'") : "";
  return `> ${import_chalk4.bold`CLI configuration`}: ${type} '${prop}' ${message}.`;
}

// src/plugin/plugin-provider.ts
var registeredHooks = {
  "before-build": [],
  "before-serve": []
};
async function invoke(hook, args) {
  for (const h of get2(hook)) {
    logger.debug(
      `Running '${hook}' hook of plugin '${h.name}'...`,
      DEBUG_CONTEXT
    );
    try {
      await h.callBack(...args);
    } catch (e) {
      logger.error(
        `An error occurred during the '${hook}' hook of plugin '${h.name}':
${toError(e).toString()}`
      );
      continue;
    }
    logger.debug(
      `Finished '${hook}' hook of plugin '${h.name}'.`,
      DEBUG_CONTEXT
    );
  }
}
function get2(hook) {
  return registeredHooks[hook];
}
function register(plugin) {
  const pluginHooks = {
    "before-build": [],
    "before-serve": []
  };
  const stub = {
    beforeBuild(callBack) {
      pluginHooks["before-build"].push({
        name: plugin.name,
        callBack
      });
    },
    beforeServe(callBack) {
      pluginHooks["before-serve"].push({
        name: plugin.name,
        callBack
      });
    }
  };
  try {
    plugin.setup(stub);
  } catch (e) {
    logger.error(
      `An error occurred during the setup of plugin '${plugin.name}':
${toError(e).toString()}`
    );
    return;
  }
  Object.keys(pluginHooks).forEach((key) => {
    if (isHook(key)) {
      registeredHooks[key].push(...pluginHooks[key]);
    }
  });
}
function isHook(value) {
  const validHooks = ["before-build", "before-serve"];
  return validHooks.includes(value);
}
function registerAll(pluginArray) {
  for (const plugin of pluginArray) {
    register(plugin);
  }
}
var pluginProvider = {
  registeredHooks,
  register,
  registerAll,
  invoke
};

// src/dev/server.ts
var import_fastify2 = __toESM(require("fastify"));
var import_ws = __toESM(require("ws"));

// src/utils/generator/generator.ts
var selfmonScriptContentCache;
async function selfmonAgentScript(url) {
  if (selfmonScriptContentCache) {
    return selfmonScriptContentCache;
  }
  const response = await dtFetch(url);
  selfmonScriptContentCache = await response.text();
  return selfmonScriptContentCache;
}

// src/utils/generator/utility.ts
var import_chalk5 = __toESM(require("chalk"));
async function isUrlReachable(url) {
  try {
    if (!url.includes("http")) {
      return 3 /* MisconfiguredURL */;
    }
    const response = await dtFetch(url);
    const responseCode = response.status;
    const contentType2 = response.headers.get("content-type");
    const isJavascript = contentType2?.includes("javascript");
    const content = await response.text();
    const includesCUC = content.includes("cuc=");
    if (responseCode === 404) {
      return 2 /* NotFound */;
    }
    if (!isJavascript) {
      return 2 /* NotFound */;
    }
    if (!includesCUC) {
      return 2 /* NotFound */;
    }
    await selfmonAgentScript(url);
    return 0 /* Reachable */;
  } catch (e) {
    return 1 /* Unreachable */;
  }
}

// src/utils/config/cli-options.ts
var import_chalk10 = require("chalk");

// src/utils/prepare-manifest.ts
var import_fast_glob5 = __toESM(require("fast-glob"));
var import_lodash5 = require("lodash");

// src/build/utils.ts
var import_fast_glob4 = __toESM(require("fast-glob"));

// src/utils/layout.ts
var import_chalk6 = __toESM(require("chalk"));

// src/utils/file-map/file-map.ts
var import_chalk7 = __toESM(require("chalk"));
var import_path16 = require("path");
var import_promises2 = require("fs/promises");

// src/utils/file-map/utils.ts
function normalizeUnixFilePath(path) {
  if (path.startsWith("../")) {
    return path;
  }
  if (path.startsWith("./")) {
    return path.slice(1);
  }
  return path.startsWith("/") ? path : "/" + path;
}

// src/utils/reporting/reporting.ts
var import_openkit_js = require("@dynatrace/openkit-js");
var import_lodash4 = require("lodash");
var import_os3 = require("os");
var import_path15 = require("path");

// src/utils/execute-command.ts
var import_commander = require("commander");

// src/dev/csp/csp.ts
function getTenantAndHostNameFromEnvUrl(environmentUrl) {
  const parsed = new URL(environmentUrl);
  const [tenant, ...hostnameParts] = parsed.hostname.split(".");
  if (!hostnameParts || hostnameParts.length < 1) {
    throw new Error(`Invalid environment URL: "${environmentUrl}"`, {
      cause: 258 /* USER */
    });
  }
  return { tenant, hostname: hostnameParts.join(".") };
}

// src/utils/reporting/reporting.ts
var import_jsonwebtoken2 = require("jsonwebtoken");

// src/utils/reporting/reporting-utils.ts
var import_path14 = require("path");
var import_os2 = require("os");
var SESSION_FILE = (0, import_path14.join)((0, import_os2.homedir)(), ".dt-app", ".session");
function transformToObjectIfError(obj) {
  if (obj instanceof Error) {
    return {
      error: {
        name: obj.name,
        message: obj.message,
        stack: obj.stack,
        cause: obj.cause
      }
    };
  } else {
    return obj;
  }
}
function deepCleanTelemetryPayload(obj) {
  return Object.fromEntries(
    Object.entries(obj).map(([key, value]) => [
      key,
      cleanValueOfTelemetryPayloadObject(value)
    ])
  );
}
function cleanValueOfTelemetryPayloadObject(value) {
  if (value === null || value === void 0) {
    return value;
  }
  if (Array.isArray(value)) {
    return value.map((item) => cleanValueOfTelemetryPayloadObject(item));
  }
  if (typeof value === "object") {
    return deepCleanTelemetryPayload(value);
  }
  if (typeof value === "string") {
    return sanitizeErrorMessage(value);
  }
  return value;
}
function extractSessionTypeFromEnvUrl(url) {
  if (url.includes("dev")) {
    return "dev";
  } else if (url.includes("hardening")) {
    return "hardening";
  } else {
    return "prod";
  }
}

// src/utils/reporting/reporting.ts
var UUID_FILE = (0, import_path15.join)((0, import_os3.homedir)(), ".dt-app", ".uuid");
var disableTelemetry = process.env.NODE_ENV === "test";
var session;
var sessionId;
var userId;
var isInitialized = false;
var cachedTelemetryConfig;
function sendTelemetryBizEvent(bizEvent, options) {
  if (!isInitialized || !session || !sessionId) {
    return;
  }
  const processedPayload = deepCleanTelemetryPayload(
    transformToObjectIfError(bizEvent.payload || {})
  );
  const environmentUrl = options?.environmentUrl || cachedTelemetryConfig?.environmentUrl || "";
  const appId = options?.app?.id || cachedTelemetryConfig.appId || "";
  const appVersion = options?.app?.version || cachedTelemetryConfig.appVersion || "";
  const nodejsVersion = process.version.charAt(0) === "v" ? process.version.substring(1) : process.version;
  const tenantInformation = environmentUrl ? {
    tenantId: getTenantAndHostNameFromEnvUrl(environmentUrl).tenant,
    sessionType: extractSessionTypeFromEnvUrl(environmentUrl)
  } : { tenantId: "", sessionType: "" };
  const userInformation = {
    ...userId && { userId },
    userType: cachedTelemetryConfig.userType || ""
  };
  const enrichedBizEvent = {
    sessionId: sessionId.toString(),
    "event.type": `dt-app.${bizEvent["event.category"]}.${bizEvent.name}`,
    "event.category": bizEvent["event.category"],
    "event.provider": "dt-app",
    operatingSystemVersion: (0, import_os3.version)(),
    nodejsVersion,
    appId,
    appVersion,
    cliVersion: global.DT_APP_VERSION,
    ...tenantInformation,
    ...userInformation,
    ...processedPayload
  };
  session.sendBizEvent(enrichedBizEvent["event.type"], enrichedBizEvent);
}

// src/utils/file-map/file-map.ts
var import_fast_glob3 = __toESM(require("fast-glob"));
var import_fs14 = require("fs");
var renderFileModeLabel = {
  created: import_chalk7.default.green`CREATED:`,
  updated: "UPDATED:",
  deleted: import_chalk7.default.red`DELETED:`,
  copied: "COPIED:"
};
function createFileManager(initFileMap) {
  let fileMap = {};
  const fileManager = {
    fileExists,
    throwIfFileDoesNotExist,
    getFile,
    getFilePathsByRegex,
    getFileMap,
    getFileName,
    setFile,
    setFiles,
    mapEsbuildOutputFiles,
    deleteFile,
    writeFileToDisc,
    writeFileMapToDisc,
    addAssetFiles,
    resetFileMap
  };
  if (initFileMap) {
    setFiles(initFileMap);
  }
  return fileManager;
  function fileExists(filepath) {
    const path = normalizeUnixFilePath(filepath);
    const file = fileMap[path];
    return !!file;
  }
  function throwIfFileDoesNotExist(filepath) {
    const path = normalizeUnixFilePath(filepath);
    if (!fileExists(filepath)) {
      sendTelemetryBizEvent({
        "event.category": "crash" /* CRASH */,
        name: "fileManager.setFile",
        payload: {
          error: `Failed to set file ${filepath} with fileManager.`
        }
      });
      throw new Error(`File ${path} does not exist in fileMap!`);
    }
  }
  function getFile(filepath) {
    filepath = normalizeUnixFilePath(unixJoin(filepath));
    throwIfFileDoesNotExist(filepath);
    return fileMap[filepath];
  }
  function getFilePathsByRegex(regex) {
    return Object.keys(fileMap).filter((filePath) => filePath.match(regex));
  }
  function getFileMap() {
    return fileMap;
  }
  function getFileName(filepath) {
    filepath = normalizeUnixFilePath(unixJoin(filepath));
    throwIfFileDoesNotExist(filepath);
    return (0, import_path16.basename)(filepath);
  }
  function setFile(filepath, content) {
    filepath = normalizeUnixFilePath(unixJoin(filepath));
    fileMap[filepath] = { content };
  }
  function setFiles(files) {
    for (const path in files) {
      setFile(path, files[path].content);
    }
  }
  function mapEsbuildOutputFiles(outputFiles, root, outdir = "dist") {
    const tmpOutDir = unixJoin([root, "dist"]);
    (outputFiles || []).forEach((file) => {
      const unixFilePath = unixJoin(file.path);
      const filepath = unixJoin([outdir, unixFilePath.replace(tmpOutDir, "")]);
      const path = normalizeUnixFilePath(filepath);
      fileMap[path] = { content: Buffer.from(file.contents) };
    });
    return fileManager;
  }
  function deleteFile(filepath) {
    filepath = normalizeUnixFilePath(unixJoin(filepath));
    delete fileMap[filepath];
  }
  async function writeFileToDisc(filepath) {
    filepath = normalizeUnixFilePath(unixJoin(filepath));
    throwIfFileDoesNotExist(filepath);
    await (0, import_promises2.writeFile)((0, import_path16.join)(filepath), fileMap[filepath].content);
  }
  async function writeFileMapToDisc(discDestinationDir) {
    await Promise.all(
      Object.entries(fileMap).map(async ([filepath, { content, mode }]) => {
        const fileSize = (Buffer.byteLength(content, "utf8") / Math.pow(2, 10)).toFixed(2);
        const fileSystemFullPath = (0, import_path16.join)(discDestinationDir, filepath);
        logger.debug(
          `${mode !== void 0 ? renderFileModeLabel[mode] : renderFileModeLabel.created} ${fileSystemFullPath} ${`(${fileSize} KB)`}`,
          "FILES"
        );
        await (0, import_promises2.mkdir)((0, import_path16.dirname)(fileSystemFullPath), { recursive: true });
        return (0, import_promises2.writeFile)(fileSystemFullPath, content);
      })
    );
  }
  async function addAssetFiles(options) {
    for (const asset of options.assetConfigs) {
      const currDir = (0, import_path16.isAbsolute)(asset.input) ? asset.input : (0, import_path16.join)(options.root, asset.input);
      const files = await (0, import_fast_glob3.default)(asset.glob, {
        cwd: currDir,
        dot: true,
        ignore: asset.ignore
      });
      for (const file of files) {
        const filePath = unixJoin([options.distDir, asset.output, file]);
        setFile(filePath, (0, import_fs14.readFileSync)((0, import_path16.join)(currDir, file)));
      }
    }
  }
  function resetFileMap() {
    fileMap = {};
  }
}
var fileMapManagerSingleton = createFileManager();

// src/utils/dynatrace-deps-metadata/get-dynatrace-deps-metadata.ts
var import_chalk8 = require("chalk");

// src/utils/app-icon/generate-app-icon.ts
var Random = class _Random {
  static A = 5182453;
  static C = 1013904223;
  static M = Number.MAX_SAFE_INTEGER;
  seed;
  /** Random class constructor */
  constructor(seed) {
    this.seed = Math.abs(seed);
  }
  /** Get the next random number */
  next() {
    this.seed = (_Random.A * this.seed + _Random.C) % _Random.M;
    return this.seed / _Random.M;
  }
};

// src/dev/fastify/appfw-plugin.ts
var APPFW_STUB_DATE = (/* @__PURE__ */ new Date(0)).toISOString();

// src/dev/fastify/app-function-plugin.ts
var import_runtime_simulator = require("@dynatrace/runtime-simulator");
var import_chalk9 = require("chalk");

// src/utils/config/cli-options.ts
var import_lodash6 = require("lodash");
var import_fs15 = require("fs");
var arrayObjectDefaults = {
  assets: {
    ignore: []
  },
  actions: {
    build: {
      entryPoint: (0, import_path17.join)("src/main.tsx"),
      sourceMaps: void 0,
      tsconfig: "tsconfig.json"
    }
  }
};
async function mergeOptions(argsConfig, fileConfig, envConfig, validationLevel = "default", isDev = false) {
  if (fileConfig.build?.sourceRoot) {
    const propertiesToDelete = {
      "build.settingsPath": fileConfig.build.settingsPath,
      "build.ui.entryPoint": fileConfig.build?.ui?.entryPoint,
      "build.ui.tsconfig": fileConfig.build?.ui?.tsconfig,
      "build.ui.assets": fileConfig.build?.ui?.assets,
      "build.functions.input": fileConfig.build?.functions?.input,
      "build.functions.glob": fileConfig.build?.functions?.glob,
      "build.functions.tsconfig": fileConfig.build?.functions?.tsconfig
    };
    const definedProperties = Object.fromEntries(
      Object.entries(propertiesToDelete).filter(
        ([_, value]) => value !== void 0
      )
    );
    Object.keys(definedProperties).forEach((property) => {
      (0, import_lodash6.unset)(fileConfig, property);
    });
    const paths = Object.keys(definedProperties).join(", ");
    if (paths) {
      logger.warn(
        `The ${Object.keys(definedProperties).join(
          ", "
        )} configuration is ignored because it can't be used in combination with build.sourceRoot`
      );
    }
  }
  const defaultCliOptions = getDefaultCliOptions(
    isDev,
    fileConfig.build?.sourceRoot
  );
  const root = argsConfig.root ? argsConfig.root : fileConfig.root ? fileConfig.root : defaultCliOptions.root;
  printPathConfigurationsWarnings(
    fileConfig,
    argsConfig,
    root,
    fileConfig.build?.sourceRoot
  );
  await logger.initLogFile(root);
  const options = mergeRecursively(
    mergeRecursively(
      mergeRecursively(defaultCliOptions, fileConfig),
      getEnvOptions(envConfig)
    ),
    argsConfig
  );
  options.build.functions.input = (0, import_path17.join)(
    options.build.sourceRoot,
    options.build.functions.input
  );
  options.build.settingsPath = (0, import_path17.join)(
    options.build.sourceRoot,
    options.build.settingsPath
  );
  const resolvedUiPaths = resolveLegacyUiFilePaths({
    root,
    sourceRoot: options.build.sourceRoot,
    buildUi: fileConfig?.build?.ui
  });
  options.build.ui.entryPoint = resolvedUiPaths?.entryPoint ?? options.build.ui.entryPoint;
  options.build.ui.assets[0].input = resolvedUiPaths?.assetsInput ?? options.build.ui.assets[0].input;
  const uiTsconfig = (0, import_fs15.existsSync)((0, import_path17.join)(root, options.build.ui.tsconfig)) ? options.build.ui.tsconfig : "tsconfig.json";
  options.build.ui.tsconfig = resolvedUiPaths?.tsConfig ? resolvedUiPaths?.tsConfig : uiTsconfig;
  if (uiTsconfig === "tsconfig.json" && !resolvedUiPaths) {
    logger.warn(
      "Ui tsconfig.json is in the root of your project, please move it to the ui directory"
    );
  }
  if (options.oauth2File && !(0, import_path17.isAbsolute)(options.oauth2File)) {
    options.oauth2File = (0, import_path17.join)(options.root, options.oauth2File);
  }
  if (!options.oauth2File) {
    options.oauth2File = (0, import_path17.join)(options.root, "/.dt-app/.tokens.json");
  }
  if (options.environmentUrl) {
    options.environmentUrl = tryNormalizeUrl(options.environmentUrl);
  }
  if (options.app?.actions) {
    const actionsDir = options.build.sourceRoot ? (0, import_path17.join)(options.build.sourceRoot, "actions") : "actions";
    options.app.actions = await Promise.all(
      validateActions(options.app.actions, { root, actionsDir })
    );
  }
  if (options.app?.selfMonitoringAgent) {
    const agentUrl = options.app.selfMonitoringAgent;
    const reachability = await isUrlReachable(agentUrl);
    if (reachability === 3 /* MisconfiguredURL */) {
      const errorMessage = `Failed to configure self monitoring agent. Self monitoring agent url missing ${(0, import_chalk10.green)(
        "https://"
      )}. Please prepend to the url in the ${(0, import_chalk10.blue)("app.config.ts")}.`;
      logger.warn(errorMessage);
      options.app.selfMonitoringAgent = void 0;
    }
    if (reachability === 1 /* Unreachable */) {
      const errorMessage = `Failed to configure self monitoring agent. Could not reach ${agentUrl}. Please make sure its accessible from the environment you're running.`;
      logger.warn(errorMessage);
      options.app.selfMonitoringAgent = void 0;
    }
    if (reachability === 2 /* NotFound */) {
      const errorMessage = `Failed to configure self monitoring agent. Could not find a self monitoring script at the configured url ${agentUrl}. Please make sure you've configured the right url and that it is reachable.`;
      logger.warn(errorMessage);
      options.app.selfMonitoringAgent = void 0;
    }
    if (options.build.mode === "production" && reachability !== 0 /* Reachable */) {
      logger.error(
        `Exiting production build. If you wish to build anyways, please set the ${(0, import_chalk10.blue)(
          "build.mode"
        )} to ${(0, import_chalk10.green)("'development'")} in your app config.`
      );
      process.exit(1);
    }
  }
  if (options.icon) {
    logger.warn(
      'The configuration "icon" is deprecated and will be removed in dt-app v1.0. To specify an icon please use "app.icon".'
    );
  }
  const validatedOptions = await validateConfig(options, validationLevel);
  pluginProvider.registerAll(
    await requirePlugins({
      root: validatedOptions.root,
      plugins: validatedOptions.plugins
    })
  );
  return validatedOptions;
}
function resolveLegacyUiFilePaths(options) {
  const { root, sourceRoot, buildUi } = options;
  const hasNewUiStructure = (0, import_fs15.existsSync)(
    (0, import_path17.join)(root, sourceRoot ?? "./", "ui", "main.tsx")
  );
  if (hasNewUiStructure) {
    return void 0;
  }
  const hasLegacyUiStructure = (0, import_fs15.existsSync)((0, import_path17.join)(root, sourceRoot, "main.tsx"));
  if (hasLegacyUiStructure && sourceRoot !== "./") {
    logger.debug(
      `main.tsx file is placed in legacy project structure: ${(0, import_path17.join)(
        sourceRoot,
        "main.tsx"
      )}`,
      "UI"
    );
    return {
      entryPoint: (0, import_path17.join)(sourceRoot, "main.tsx"),
      assetsInput: (0, import_path17.join)(sourceRoot, "assets"),
      tsConfig: resolveTsConfigForLegacy(root, sourceRoot)
    };
  }
  return {
    entryPoint: buildUi?.entryPoint ?? (0, import_path17.join)("src/main.tsx"),
    assetsInput: buildUi?.assets?.[0]?.input ?? (0, import_path17.join)("src/assets"),
    tsConfig: resolveTsConfigForOld(root, buildUi?.tsconfig)
  };
}
function resolveTsConfigForLegacy(root, sourceRoot) {
  const legacyTsConfig = (0, import_path17.join)(sourceRoot, "tsconfig.json");
  if ((0, import_fs15.existsSync)((0, import_path17.join)(root, legacyTsConfig))) {
    logger.debug(
      `Using UI tsconfig.json for the legacy project structure that is placed: ${legacyTsConfig}`,
      "UI CONFIG"
    );
    return legacyTsConfig;
  }
  logger.debug(
    "Using UI tsconfig.json for the legacy project structure that is placed in the root of the project",
    "UI CONFIG"
  );
  return "tsconfig.json";
}
function resolveTsConfigForOld(root, configuredTsConfig) {
  if (configuredTsConfig) {
    logger.debug(
      `Using tsconfig.json for the UI that is configured in app.config: ${configuredTsConfig}`,
      "UI CONFIG"
    );
    return configuredTsConfig;
  }
  const srcTsConfig = "src/tsconfig.json";
  if ((0, import_fs15.existsSync)((0, import_path17.join)(root, srcTsConfig))) {
    logger.debug(
      `Using tsconfig.json for the UI that is placed inside src directory: ${srcTsConfig}`,
      "UI CONFIG"
    );
    return (0, import_path17.join)(srcTsConfig);
  }
  logger.debug(
    "Using tsconfig.json for the UI that is placed in the root of the project",
    "UI CONFIG"
  );
  return "tsconfig.json";
}
function printPathConfigurationsWarnings(fileConfig, argsConfig, root, sourceRoot) {
  const warningOutput = [];
  if (fileConfig.build?.settingsPath) {
    warningOutput.push(
      'The configuration "build.settingsPath" is deprecated and will be removed in dt-app v1.0. The settings have to be inside <source_root>/settings/schemas directory. The current default location is ./settings/schemas/'
    );
  }
  if (fileConfig.build?.ui?.additionalEntryPoints) {
    warningOutput.push(
      'The configuration "build.ui.additionalEntryPoints" is deprecated and will be removed in dt-app v1.0. The additionalEntryPoints for the ui have to be inside <source_root>/ui directory. The current default location is ./ui/'
    );
  }
  if (fileConfig.build?.ui?.entryPoint) {
    warningOutput.push(
      'The configuration "build.ui.entryPoint" is deprecated and will be removed in dt-app v1.0. The main entry point for the ui has to be inside <source_root>/ui directory. The current default location is ./ui/main.tsx.'
    );
  }
  if (fileConfig.build?.ui?.tsconfig) {
    warningOutput.push(
      'The configuration "build.ui.tsconfig" is deprecated and will be removed in dt-app v1.0. The tsconfig for the ui has to be inside <source_root>/ui directory. The current default location is ./ui/tsconfig.json.'
    );
  }
  if (!sourceRoot && (0, import_fs15.existsSync)((0, import_path17.join)(root, "src"))) {
    warningOutput.push(
      `In dt-app v1.0, UI sources are expected to be located in the project's root directory. To specify a different source root, please use the "build.sourceRoot" configuration.`
    );
  }
  if (fileConfig.build?.functions) {
    warningOutput.push(
      'The configuration "build.functions" is deprecated and will be removed in dt-app v1.0. To configure your App Functions please use "build.api" instead.'
    );
  }
  if (fileConfig.build?.functions?.input) {
    warningOutput.push(
      'The configuration "build.functions.input" is deprecated and will be removed in dt-app v1.0. To specify the location of your App Functions, please use "build.sourceRoot" instead.'
    );
  }
  if (fileConfig.build?.functions?.glob) {
    warningOutput.push(
      'All the app functions in v1.0 will have to have a postfix ".function.ts". will be removed in dt-app v1.0. To specify the glob for your app functions, please use "build.sourceRoot" instead. All the app functions in v1.0 will have to have a postfix ".function.ts".'
    );
  }
  if (fileConfig.build?.functions?.tsconfig) {
    warningOutput.push(
      'The configuration "build.functions.tsconfig" is deprecated and will be removed in dt-app v1.0. The App Functions tsconfig has to be inside the <source_root>/api directory'
    );
  }
  if (fileConfig.build?.functions?.plugins) {
    warningOutput.push(
      'The "build.functions.plugins" are deprecated and will be removed in the next major release of App Toolkit'
    );
  }
  if (fileConfig.build?.actions?.plugins) {
    warningOutput.push(
      'The "build.actions.plugins" are deprecated and will be removed in the next major release of App Toolkit'
    );
  }
  if (fileConfig.build?.widgets?.plugins) {
    warningOutput.push(
      'The "build.widgets.plugins" are deprecated and will be removed in the next major release of App Toolkit'
    );
  }
  if (fileConfig.root) {
    warningOutput.push(
      'The configuration "root" is deprecated and will be removed in dt-app v1.0. To specify the root of your project, please use the flag `--cwd` instead.'
    );
  }
  if (fileConfig.oauthClientId) {
    warningOutput.push(
      'The configuration "oauthClientId" is deprecated and will be removed in dt-app v1.0.'
    );
  }
  if (fileConfig.distDir) {
    warningOutput.push(
      'The configuration "distDir" is deprecated and will be removed in dt-app v1.0. Default value "./dist" will be used.'
    );
  }
  if (fileConfig.oauth2File) {
    warningOutput.push(
      'The configuration "oauth2File" is deprecated and will be removed in dt-app v1.0. Default value "./dt-app/.tokens.json" will be used.'
    );
  }
  if (fileConfig.dev?.fileWatcher?.ignore) {
    warningOutput.push(
      'The configuration "dev.fileWatcher.ignore" is deprecated and will be removed in dt-app v1.0. Development server will ignore redundant files by default.'
    );
  }
  if (fileConfig.dev?.fileWatcher?.include) {
    warningOutput.push(
      'The configuration "dev.fileWatcher.include" is deprecated and will be removed in dt-app v1.0. Development server will include all required files by default.'
    );
  }
  if (fileConfig.server?.open) {
    warningOutput.push(
      'The configuration "server.open" is deprecated and will be removed in dt-app v1.0. To specify if the project should be opened, please use the flag `--open` instead.'
    );
  }
  if (process.env.DT_APP_SIGNING_PK) {
    warningOutput.push(
      'The env variable "DT_APP_SIGNING_PK" is deprecated and will be removed in dt-app v1.0.'
    );
  }
  if (process.env.DT_APP_SIGNING_CERT) {
    warningOutput.push(
      'The env variable "DT_APP_SIGNING_CERT" is deprecated and will be removed in dt-app v1.0.'
    );
  }
  if (process.env.DEBUG) {
    warningOutput.push(
      'The env variable "DEBUG" is deprecated and will be removed in dt-app v1.0. Please user --verbose flag instead.'
    );
  }
  if (process.env.DT_APP_SERVERLESS_MAX_CONNECTIONS) {
    warningOutput.push(
      'The env variable "DT_APP_SERVERLESS_MAX_CONNECTIONS " is deprecated and will be removed in dt-app v1.0. Default value of 128 will be used instead.'
    );
  }
  if (argsConfig?.injectSdk !== void 0) {
    warningOutput.push(
      'The flag "--no-sdk-injection" is deprecated and will be removed in dt-app v1.0. Please use app.config instead'
    );
  }
  if (fileConfig.oauthClientId) {
    warningOutput.push(
      'The configuration "oauthClientId" is deprecated and will be removed in dt-app v1.0.'
    );
  }
  if (argsConfig.global) {
    warningOutput.push(
      'The flag "--global" is deprecated and will be removed in dt-app v1.0.'
    );
  }
  if (fileConfig.build?.ui?.sourceMaps) {
    warningOutput.push(
      'The configuration "build.ui.sourceMaps" is deprecated and will be removed in dt-app v1.0. Please use centralize "build.sourceMaps" configuration instead.'
    );
  }
  if (fileConfig.build?.functions?.sourceMaps) {
    warningOutput.push(
      'The configuration "build.functions.sourceMaps" is deprecated and will be removed in dt-app v1.0. Please use centralize "build.sourceMaps" configuration instead.'
    );
  }
  if (argsConfig.build?.mode === "development") {
    warningOutput.push(
      'The flags "--prod" and "--no-prod" are deprecated and will be removed in dt-app v1.0. Please use "build.mode" configuration instead.'
    );
  }
  if (warningOutput.length) {
    logger.warn(warningOutput.join("\n\n"));
  }
}
function getDefaultCliOptions(isDev, sourceRoot) {
  return {
    executionMode: "js-runtime" /* RUNTIME */,
    appFunctionsBuildPlatform: "browser" /* BROWSER */,
    root: process.cwd(),
    distDir: "dist",
    dryRun: false,
    noLiveReload: false,
    injectSdk: true,
    deploy: {
      build: true
    },
    build: {
      index: (0, import_path17.join)("src/index.html"),
      sourceRoot: sourceRoot ?? "./",
      sourceMaps: void 0,
      settingsPath: (0, import_path17.join)("settings/schemas"),
      ui: {
        entryPoint: sourceRoot ? (0, import_path17.join)(sourceRoot, "ui/main.tsx") : (0, import_path17.join)("ui/main.tsx"),
        additionalEntryPoints: [],
        sourceMaps: void 0,
        tsconfig: sourceRoot ? (0, import_path17.join)(sourceRoot, "ui/tsconfig.json") : (0, import_path17.join)("ui/tsconfig.json"),
        assets: [
          {
            glob: "**/*",
            ignore: [],
            input: sourceRoot ? (0, import_path17.join)(sourceRoot, "ui/assets") : (0, import_path17.join)("ui/assets"),
            output: "assets"
          }
        ]
      },
      functions: {
        input: "api",
        // 1.0 deprecation
        glob: "**/!(*.test).ts",
        sourceMaps: void 0,
        tsconfig: "tsconfig.json"
      },
      api: { sourceMaps: void 0 },
      mode: isDev ? "development" : "production",
      baseHref: "/ui/",
      widgets: {},
      actions: {},
      dynatraceDependencies: {
        addOrOverride: {},
        ignore: []
      },
      typeCheck: true
    },
    server: {
      open: true,
      port: 3e3,
      host: "127.0.0.1",
      showWarnings: false,
      enableCSP: true
    },
    dev: {
      fileWatcher: {
        ignore: ["**/*.spec.{ts,tsx}", "**/*.test.ts"],
        include: []
      }
    },
    plugins: []
  };
}
function getEnvOptions(env) {
  const check2 = (envVar) => envVar && envVar.trim() !== "";
  const envOptions = {};
  if (check2(env.DT_APP_ENVIRONMENT_URL)) {
    envOptions.environmentUrl = env.DT_APP_ENVIRONMENT_URL;
  }
  if (check2(env.DT_APP_OAUTH_CLIENT_ID)) {
    envOptions.oauthClientId = env.DT_APP_OAUTH_CLIENT_ID;
  }
  if (check2(env.DT_APP_OAUTH_CLIENT_SECRET)) {
    envOptions.oauthClientSecret = env.DT_APP_OAUTH_CLIENT_SECRET;
  }
  return envOptions;
}
function tryNormalizeUrl(url) {
  try {
    return new URL(url).origin;
  } catch (error) {
    return url;
  }
}
function mergeRecursively(a, b) {
  const merged = { ...a };
  for (const property in b) {
    if (b[property] === void 0) {
      continue;
    }
    if (isObject(b[property])) {
      merged[property] = mergeRecursively(a[property] ?? {}, b[property]);
    } else {
      if (
        // Property is a non-empty array of objects
        Array.isArray(b[property]) && b[property].length > 0 && isObject(b[property][0])
      ) {
        if (Object.keys(arrayObjectDefaults).indexOf(property) >= 0) {
          for (let i = 0; i < b[property].length; i++) {
            b[property][i] = mergeRecursively(
              arrayObjectDefaults[property],
              b[property][i]
            );
          }
        }
      }
      merged[property] = b[property];
    }
  }
  return merged;
}
function isObject(value) {
  return Object.prototype.toString.call(value) === "[object Object]";
}

// src/migrations/0.130.0/index.ts
var MINIMAL_SUPPORTED_TYPESCRIPT_VERSION = "4.9.5";
var migration = async (fileMap, options) => {
  const packageJsonPath = (0, import_path18.join)(options.root, "package.json");
  const packageJsonContent = (0, import_fs16.readFileSync)(packageJsonPath, "utf-8");
  const packageJson = JSON.parse(packageJsonContent);
  const hasTypescriptDependency = packageJson.dependencies?.["typescript"] || packageJson.devDependencies?.["typescript"];
  if (!hasTypescriptDependency) {
    packageJson.dependencies = {
      ...packageJson.dependencies,
      typescript: MINIMAL_SUPPORTED_TYPESCRIPT_VERSION
    };
    fileMap["package.json"].content = Buffer.from(JSON.stringify(packageJson));
  }
  const fileConfig = await getDtAppFileConfig(options.root, true);
  const config = await mergeOptions({}, fileConfig, {});
  if ((0, import_fs16.existsSync)(
    (0, import_path18.join)(
      options.root,
      config.build.functions.input,
      config.build.functions.tsconfig
    )
  )) {
    updateTsConfig(
      fileMap,
      (0, import_path18.join)(config.build.functions.input, config.build.functions.tsconfig)
    );
  }
  if ((0, import_fs16.existsSync)((0, import_path18.join)(options.root, "actions/tsconfig.action.json"))) {
    updateTsConfig(fileMap, (0, import_path18.join)("actions/tsconfig.action.json"));
  }
  const testFiles = (0, import_devkit2.findFiles)(fileMap, "**/*.{test,spec}.ts");
  Object.keys(testFiles).forEach((filePath) => {
    (0, import_devkit2.updateFile)(fileMap, filePath, (oldContent) => {
      return oldContent.replaceAll(
        "@jest-environment @dynatrace/runtime-simulator/lib/test-environment",
        "@jest-environment @dynatrace/js-runtime/lib/test-environment"
      );
    });
  });
  const jestConfigFiles = (0, import_devkit2.findFiles)(fileMap, "**/jest.config.js");
  Object.keys(jestConfigFiles).forEach((filePath) => {
    (0, import_devkit2.updateFile)(fileMap, filePath, (oldContent) => {
      return oldContent.replaceAll(
        "@dynatrace/runtime-simulator/lib/test-environment",
        "@dynatrace/js-runtime/lib/test-environment"
      );
    });
  });
  return fileMap;
};
function updateTsConfig(fileMap, tsconfigPath) {
  (0, import_devkit2.updateFile)(fileMap, tsconfigPath, (content) => {
    return content.replaceAll(
      "@dynatrace/runtime-simulator/types",
      "@dynatrace/js-runtime/types"
    );
  });
}
module.exports = migration;
/**
 * @license
 * Copyright 2022 Dynatrace LLC
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
//# sourceMappingURL=index.js.map