trigger.dev 3.0.0-beta.2 → 3.0.0-beta.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -781,11 +781,12 @@ import { intro as intro3, log as log2, outro as outro3, spinner as spinner4 } fr
781
781
  import { depot } from "@depot/cli";
782
782
  import { context, trace as trace2 } from "@opentelemetry/api";
783
783
  import {
784
+ TaskMetadataFailedToParseData,
784
785
  detectDependencyVersion,
785
786
  flattenAttributes as flattenAttributes2,
786
787
  recordSpanException as recordSpanException4
787
788
  } from "@trigger.dev/core/v3";
788
- import chalk4 from "chalk";
789
+ import chalk5 from "chalk";
789
790
  import { Option as CommandOption } from "commander";
790
791
  import { build as build2 } from "esbuild";
791
792
  import { execa as execa2 } from "execa";
@@ -793,14 +794,14 @@ import { resolve as importResolve } from "import-meta-resolve";
793
794
  import { createHash } from "node:crypto";
794
795
  import { readFileSync as readFileSync2 } from "node:fs";
795
796
  import { copyFile, mkdir, readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises";
796
- import { dirname, join as join4, relative as relative2 } from "node:path";
797
+ import { dirname, join as join4, relative as relative3 } from "node:path";
797
798
  import { setTimeout as setTimeout2 } from "node:timers/promises";
798
799
  import terminalLink from "terminal-link";
799
800
  import invariant from "tiny-invariant";
800
801
  import { z as z4 } from "zod";
801
802
 
802
803
  // package.json
803
- var version = "3.0.0-beta.2";
804
+ var version = "3.0.0-beta.4";
804
805
  var dependencies = {
805
806
  "@clack/prompts": "^0.7.0",
806
807
  "@depot/cli": "0.0.1-cli.2.55.0",
@@ -816,7 +817,7 @@ var dependencies = {
816
817
  "@opentelemetry/sdk-trace-base": "^1.22.0",
817
818
  "@opentelemetry/sdk-trace-node": "^1.22.0",
818
819
  "@opentelemetry/semantic-conventions": "^1.22.0",
819
- "@trigger.dev/core": "workspace:^3.0.0-beta.1",
820
+ "@trigger.dev/core": "workspace:^3.0.0-beta.3",
820
821
  "@types/degit": "^2.8.3",
821
822
  chalk: "^5.2.0",
822
823
  chokidar: "^3.5.3",
@@ -1307,7 +1308,7 @@ var Logger = class {
1307
1308
  const kind = LOGGER_LEVEL_FORMAT_TYPE_MAP[level];
1308
1309
  if (kind) {
1309
1310
  const [firstLine, ...otherLines] = message.split("\n");
1310
- const notes = otherLines.length > 0 ? otherLines.map((text2) => ({ text: text2 })) : void 0;
1311
+ const notes = otherLines.length > 0 ? otherLines.map((text3) => ({ text: text3 })) : void 0;
1311
1312
  return formatMessagesSync([{ text: firstLine, notes }], {
1312
1313
  color: true,
1313
1314
  kind,
@@ -1322,6 +1323,58 @@ var logger = new Logger();
1322
1323
 
1323
1324
  // src/cli/common.ts
1324
1325
  import { outro } from "@clack/prompts";
1326
+
1327
+ // src/utilities/cliOutput.ts
1328
+ import chalk2 from "chalk";
1329
+ var green = "#4FFF54";
1330
+ var purple = "#735BF3";
1331
+ function chalkGreen(text3) {
1332
+ return chalk2.hex(green)(text3);
1333
+ }
1334
+ function chalkPurple(text3) {
1335
+ return chalk2.hex(purple)(text3);
1336
+ }
1337
+ function chalkGrey(text3) {
1338
+ return chalk2.hex("#878C99")(text3);
1339
+ }
1340
+ function chalkError(text3) {
1341
+ return chalk2.hex("#E11D48")(text3);
1342
+ }
1343
+ function chalkWarning(text3) {
1344
+ return chalk2.yellow(text3);
1345
+ }
1346
+ function chalkSuccess(text3) {
1347
+ return chalk2.hex("#28BF5C")(text3);
1348
+ }
1349
+ function chalkLink(text3) {
1350
+ return chalk2.underline.hex("#D7D9DD")(text3);
1351
+ }
1352
+ function chalkWorker(text3) {
1353
+ return chalk2.hex("#FFFF89")(text3);
1354
+ }
1355
+ function chalkTask(text3) {
1356
+ return chalk2.hex("#60A5FA")(text3);
1357
+ }
1358
+ function chalkRun(text3) {
1359
+ return chalk2.hex("#A78BFA")(text3);
1360
+ }
1361
+ function logo() {
1362
+ return `${chalk2.hex(green).bold("Trigger")}${chalk2.hex(purple).bold(".dev")}`;
1363
+ }
1364
+ function prettyPrintDate(date = /* @__PURE__ */ new Date()) {
1365
+ let formattedDate = new Intl.DateTimeFormat("en-US", {
1366
+ month: "short",
1367
+ day: "2-digit",
1368
+ hour: "2-digit",
1369
+ minute: "2-digit",
1370
+ second: "2-digit",
1371
+ hour12: false
1372
+ }).format(date);
1373
+ formattedDate += "." + ("00" + date.getMilliseconds()).slice(-3);
1374
+ return formattedDate;
1375
+ }
1376
+
1377
+ // src/cli/common.ts
1325
1378
  var CommonCommandOptions = z.object({
1326
1379
  apiUrl: z.string().optional(),
1327
1380
  logLevel: z.enum(["debug", "info", "log", "warn", "error", "none"]).default("log"),
@@ -1331,7 +1384,7 @@ var CommonCommandOptions = z.object({
1331
1384
  function commonOptions(command) {
1332
1385
  return command.option("--profile <profile>", "The login profile to use", "default").option("-a, --api-url <value>", "Override the API URL", "https://api.trigger.dev").option(
1333
1386
  "-l, --log-level <level>",
1334
- "The log level to use (debug, info, log, warn, error, none)",
1387
+ "The CLI log level to use (debug, info, log, warn, error, none). This does not effect the log level of your trigger.dev tasks.",
1335
1388
  "log"
1336
1389
  ).option("--skip-telemetry", "Opt-out of sending telemetry");
1337
1390
  }
@@ -1377,7 +1430,7 @@ async function wrapCommandAction(name, schema, options, action) {
1377
1430
  } else if (e instanceof SkipCommandError) {
1378
1431
  } else {
1379
1432
  recordSpanException(span, e);
1380
- logger.error(e instanceof Error ? e.message : String(e));
1433
+ logger.log(`${chalkError("X Error:")} ${e instanceof Error ? e.message : String(e)}`);
1381
1434
  }
1382
1435
  span.end();
1383
1436
  throw e;
@@ -1535,6 +1588,11 @@ function readAuthConfigProfile(profile = "default") {
1535
1588
  return void 0;
1536
1589
  }
1537
1590
  }
1591
+ function deleteAuthConfigProfile(profile = "default") {
1592
+ const existingConfig = readAuthConfigFile() || {};
1593
+ delete existingConfig[profile];
1594
+ writeAuthConfigFile(existingConfig);
1595
+ }
1538
1596
  function readAuthConfigFile() {
1539
1597
  try {
1540
1598
  const authConfigFilePath = getAuthConfigFilePath();
@@ -1639,53 +1697,6 @@ import chalk3 from "chalk";
1639
1697
  import supportsColor from "supports-color";
1640
1698
  import checkForUpdate from "update-check";
1641
1699
 
1642
- // src/utilities/cliOutput.ts
1643
- import chalk2 from "chalk";
1644
- var green = "#4FFF54";
1645
- var purple = "#735BF3";
1646
- function chalkPurple(text2) {
1647
- return chalk2.hex(purple)(text2);
1648
- }
1649
- function chalkGrey(text2) {
1650
- return chalk2.hex("#878C99")(text2);
1651
- }
1652
- function chalkError(text2) {
1653
- return chalk2.hex("#E11D48")(text2);
1654
- }
1655
- function chalkWarning(text2) {
1656
- return chalk2.yellow(text2);
1657
- }
1658
- function chalkSuccess(text2) {
1659
- return chalk2.hex("#28BF5C")(text2);
1660
- }
1661
- function chalkLink(text2) {
1662
- return chalk2.underline.hex("#D7D9DD")(text2);
1663
- }
1664
- function chalkWorker(text2) {
1665
- return chalk2.hex("#FFFF89")(text2);
1666
- }
1667
- function chalkTask(text2) {
1668
- return chalk2.hex("#60A5FA")(text2);
1669
- }
1670
- function chalkRun(text2) {
1671
- return chalk2.hex("#A78BFA")(text2);
1672
- }
1673
- function logo() {
1674
- return `${chalk2.hex(green).bold("Trigger")}${chalk2.hex(purple).bold(".dev")}`;
1675
- }
1676
- function prettyPrintDate(date = /* @__PURE__ */ new Date()) {
1677
- let formattedDate = new Intl.DateTimeFormat("en-US", {
1678
- month: "short",
1679
- day: "2-digit",
1680
- hour: "2-digit",
1681
- minute: "2-digit",
1682
- second: "2-digit",
1683
- hour12: false
1684
- }).format(date);
1685
- formattedDate += "." + ("00" + date.getMilliseconds()).slice(-3);
1686
- return formattedDate;
1687
- }
1688
-
1689
1700
  // src/utilities/getVersion.ts
1690
1701
  import path3 from "path";
1691
1702
  function getVersion() {
@@ -1697,10 +1708,10 @@ function getVersion() {
1697
1708
  // src/utilities/initialBanner.ts
1698
1709
  async function printInitialBanner(performUpdateCheck = true) {
1699
1710
  const packageVersion = getVersion();
1700
- const text2 = `
1711
+ const text3 = `
1701
1712
  ${logo()} ${chalkGrey(`(${packageVersion})`)}
1702
1713
  `;
1703
- logger.info(text2);
1714
+ logger.info(text3);
1704
1715
  let maybeNewVersion;
1705
1716
  if (performUpdateCheck) {
1706
1717
  const loadingSpinner = spinner();
@@ -1724,15 +1735,15 @@ After installation, run Trigger.dev with \`npx trigger.dev\`.`
1724
1735
  }
1725
1736
  async function printStandloneInitialBanner(performUpdateCheck = true) {
1726
1737
  const packageVersion = getVersion();
1727
- let text2 = `
1738
+ let text3 = `
1728
1739
  ${logo()} ${chalkGrey("(v3 Developer Preview)")}`;
1729
1740
  if (performUpdateCheck) {
1730
1741
  const maybeNewVersion = await updateCheck();
1731
1742
  if (maybeNewVersion !== void 0) {
1732
- text2 = `${text2} (update available ${chalk3.green(maybeNewVersion)})`;
1743
+ text3 = `${text3} (update available ${chalk3.green(maybeNewVersion)})`;
1733
1744
  }
1734
1745
  }
1735
- logger.log(text2 + "\n" + (supportsColor.stdout ? chalkGrey("-".repeat(54)) : "-".repeat(54)));
1746
+ logger.log(text3 + "\n" + (supportsColor.stdout ? chalkGrey("-".repeat(54)) : "-".repeat(54)));
1736
1747
  }
1737
1748
  function printDevBanner() {
1738
1749
  logger.log(
@@ -1764,20 +1775,14 @@ async function installPackages(packages, options) {
1764
1775
  const cwd = options?.cwd ?? process.cwd();
1765
1776
  logger.debug("Installing packages", { packages });
1766
1777
  await setPackageJsonDeps(join3(cwd, "package.json"), packages);
1767
- const childProcess2 = execa(
1778
+ await execa(
1768
1779
  "npm",
1769
1780
  ["install", "--install-strategy", "nested", "--ignore-scripts", "--no-audit", "--no-fund"],
1770
1781
  {
1771
1782
  cwd,
1772
- stderr: "inherit"
1783
+ stderr: "pipe"
1773
1784
  }
1774
1785
  );
1775
- await new Promise((res, rej) => {
1776
- childProcess2.on("error", (e) => rej(e));
1777
- childProcess2.on("close", () => res());
1778
- });
1779
- await childProcess2;
1780
- return;
1781
1786
  }
1782
1787
  function detectPackageNameFromImportPath(path6) {
1783
1788
  if (path6.startsWith("@")) {
@@ -2721,6 +2726,9 @@ ${authorizationCodeResult.error}`
2721
2726
  });
2722
2727
  }
2723
2728
 
2729
+ // src/commands/deploy.ts
2730
+ import { Glob } from "glob";
2731
+
2724
2732
  // src/utilities/build.ts
2725
2733
  import { readFileSync } from "node:fs";
2726
2734
  import { extname, isAbsolute } from "node:path";
@@ -2871,8 +2879,151 @@ function getLoaderForFile(file) {
2871
2879
  throw new Error(`Cannot get loader for file ${file}`);
2872
2880
  }
2873
2881
 
2882
+ // src/utilities/deployErrors.ts
2883
+ import chalk4 from "chalk";
2884
+ import { relative as relative2 } from "node:path";
2885
+ import { groupTaskMetadataIssuesByTask } from "@trigger.dev/core/v3";
2886
+ function errorIsErrorLike(error) {
2887
+ return error instanceof Error || typeof error === "object" && error !== null && "message" in error;
2888
+ }
2889
+ function parseBuildErrorStack(error) {
2890
+ if (typeof error === "string") {
2891
+ return error;
2892
+ }
2893
+ if (errorIsErrorLike(error)) {
2894
+ if (typeof error.stack === "string") {
2895
+ const isErrRequireEsm = error.stack.includes("ERR_REQUIRE_ESM");
2896
+ let moduleName = null;
2897
+ if (isErrRequireEsm) {
2898
+ const moduleRegex = /node_modules\/(@[^\/]+\/[^\/]+|[^\/]+)\/[^\/]+\s/;
2899
+ const match = moduleRegex.exec(error.stack);
2900
+ if (match) {
2901
+ moduleName = match[1];
2902
+ return {
2903
+ type: "esm-require-error",
2904
+ moduleName
2905
+ };
2906
+ }
2907
+ }
2908
+ } else {
2909
+ return error.message;
2910
+ }
2911
+ }
2912
+ return "Unknown error";
2913
+ }
2914
+ function logESMRequireError(parsedError, resolvedConfig) {
2915
+ logger.log(
2916
+ `
2917
+ ${chalkError("X Error:")} The ${chalkPurple(
2918
+ parsedError.moduleName
2919
+ )} module is being required even though it's ESM only, and builds only support CommonJS. There are two ${chalk4.underline(
2920
+ "possible"
2921
+ )} ways to fix this:`
2922
+ );
2923
+ logger.log(
2924
+ `
2925
+ ${chalkGrey("\u25CB")} Dynamically import the module in your code: ${chalkGrey(
2926
+ `const myModule = await import("${parsedError.moduleName}");`
2927
+ )}`
2928
+ );
2929
+ if (resolvedConfig.status === "file") {
2930
+ const relativePath = relative2(resolvedConfig.config.projectDir, resolvedConfig.path).replace(
2931
+ /\\/g,
2932
+ "/"
2933
+ );
2934
+ logger.log(
2935
+ `${chalkGrey("\u25CB")} ${chalk4.underline("Or")} add ${chalkPurple(
2936
+ parsedError.moduleName
2937
+ )} to the ${chalkGreen("dependenciesToBundle")} array in your config file ${chalkGrey(
2938
+ `(${relativePath})`
2939
+ )}. This will bundle the module with your code.
2940
+ `
2941
+ );
2942
+ } else {
2943
+ logger.log(
2944
+ `${chalkGrey("\u25CB")} ${chalk4.underline("Or")} add ${chalkPurple(
2945
+ parsedError.moduleName
2946
+ )} to the ${chalkGreen("dependenciesToBundle")} array in your config file ${chalkGrey(
2947
+ "(you'll need to create one)"
2948
+ )}. This will bundle the module with your code.
2949
+ `
2950
+ );
2951
+ }
2952
+ }
2953
+ function parseNpmInstallError(error) {
2954
+ if (typeof error === "string") {
2955
+ return error;
2956
+ }
2957
+ if (error instanceof Error) {
2958
+ if (typeof error.stack === "string") {
2959
+ const isPackageNotFoundError = error.stack.includes("ERR! 404 Not Found") && error.stack.includes("is not in this registry");
2960
+ let packageName = null;
2961
+ if (isPackageNotFoundError) {
2962
+ const packageNameRegex = /'([^']+)' is not in this registry/;
2963
+ const match = packageNameRegex.exec(error.stack);
2964
+ if (match) {
2965
+ packageName = match[1];
2966
+ }
2967
+ }
2968
+ if (packageName) {
2969
+ return {
2970
+ type: "package-not-found-error",
2971
+ packageName
2972
+ };
2973
+ }
2974
+ const noMatchingVersionRegex = /No matching version found for ([^\s]+)\s/;
2975
+ const noMatchingVersionMatch = noMatchingVersionRegex.exec(error.stack);
2976
+ if (noMatchingVersionMatch) {
2977
+ return {
2978
+ type: "no-matching-version-error",
2979
+ packageName: noMatchingVersionMatch[1].replace(/.$/, "")
2980
+ };
2981
+ }
2982
+ return error.message;
2983
+ } else {
2984
+ return error.message;
2985
+ }
2986
+ }
2987
+ return "Unknown error";
2988
+ }
2989
+ function logTaskMetadataParseError(zodIssues, tasks) {
2990
+ logger.log(
2991
+ `
2992
+ ${chalkError("X Error:")} Failed to start. The following ${zodIssues.length === 1 ? "task issue was" : "task issues were"} found:`
2993
+ );
2994
+ const groupedIssues = groupTaskMetadataIssuesByTask(tasks, zodIssues);
2995
+ for (const key in groupedIssues) {
2996
+ const taskWithIssues = groupedIssues[key];
2997
+ if (!taskWithIssues) {
2998
+ continue;
2999
+ }
3000
+ logger.log(
3001
+ `
3002
+ ${chalkWarning("\u276F")} ${taskWithIssues.exportName} ${chalkGrey("in")} ${taskWithIssues.filePath}`
3003
+ );
3004
+ for (const issue of taskWithIssues.issues) {
3005
+ if (issue.path) {
3006
+ logger.log(` ${chalkError("x")} ${issue.path} ${chalkGrey(issue.message)}`);
3007
+ } else {
3008
+ logger.log(` ${chalkError("x")} ${chalkGrey(issue.message)}`);
3009
+ }
3010
+ }
3011
+ }
3012
+ }
3013
+
3014
+ // src/utilities/safeJsonParse.ts
3015
+ function safeJsonParse(json) {
3016
+ if (!json) {
3017
+ return void 0;
3018
+ }
3019
+ try {
3020
+ return JSON.parse(json);
3021
+ } catch {
3022
+ return void 0;
3023
+ }
3024
+ }
3025
+
2874
3026
  // src/commands/deploy.ts
2875
- import { Glob } from "glob";
2876
3027
  var DeployCommandOptions = CommonCommandOptions.extend({
2877
3028
  skipTypecheck: z4.boolean().default(false),
2878
3029
  skipDeploy: z4.boolean().default(false),
@@ -3046,26 +3197,38 @@ async function _deployCommand(dir, options) {
3046
3197
  "Failed to initialize deployment. The deployment does not have any external build data. To deploy this project, you must use the --self-hosted flag to build and push the image yourself."
3047
3198
  );
3048
3199
  }
3049
- return buildAndPushImage({
3050
- registryHost,
3051
- auth: authorization.auth.accessToken,
3052
- imageTag: deploymentResponse.data.imageTag,
3053
- buildId: deploymentResponse.data.externalBuildData.buildId,
3054
- buildToken: deploymentResponse.data.externalBuildData.buildToken,
3055
- buildProjectId: deploymentResponse.data.externalBuildData.projectId,
3056
- cwd: compilation.path,
3057
- projectId: resolvedConfig.config.project,
3058
- deploymentId: deploymentResponse.data.id,
3059
- deploymentVersion: deploymentResponse.data.version,
3060
- contentHash: deploymentResponse.data.contentHash,
3061
- projectRef: resolvedConfig.config.project,
3062
- loadImage: options.loadImage,
3063
- buildPlatform: options.buildPlatform
3064
- });
3200
+ return buildAndPushImage(
3201
+ {
3202
+ registryHost,
3203
+ auth: authorization.auth.accessToken,
3204
+ imageTag: deploymentResponse.data.imageTag,
3205
+ buildId: deploymentResponse.data.externalBuildData.buildId,
3206
+ buildToken: deploymentResponse.data.externalBuildData.buildToken,
3207
+ buildProjectId: deploymentResponse.data.externalBuildData.projectId,
3208
+ cwd: compilation.path,
3209
+ projectId: resolvedConfig.config.project,
3210
+ deploymentId: deploymentResponse.data.id,
3211
+ deploymentVersion: deploymentResponse.data.version,
3212
+ contentHash: deploymentResponse.data.contentHash,
3213
+ projectRef: resolvedConfig.config.project,
3214
+ loadImage: options.loadImage,
3215
+ buildPlatform: options.buildPlatform
3216
+ },
3217
+ deploymentSpinner
3218
+ );
3065
3219
  };
3066
3220
  const image = await buildImage();
3067
3221
  if (!image.ok) {
3068
- deploymentSpinner.stop(`Failed to build project image: ${image.error}`);
3222
+ deploymentSpinner.stop(`Failed to build project.`);
3223
+ if (image.logs.trim() !== "") {
3224
+ const logPath = join4(await createTempDir(), `build-${deploymentResponse.data.shortCode}.log`);
3225
+ await writeFile2(logPath, image.logs);
3226
+ logger.log(
3227
+ `${chalkError("X Error:")} ${image.error}. Full build logs have been saved to ${logPath})`
3228
+ );
3229
+ } else {
3230
+ logger.log(`${chalkError("X Error:")} ${image.error}.`);
3231
+ }
3069
3232
  throw new SkipLoggingError(`Failed to build project image: ${image.error}`);
3070
3233
  }
3071
3234
  const imageReference = options.selfHosted ? `${selfHostedRegistryHost ? `${selfHostedRegistryHost}/` : ""}${image.image}${image.digest ? `@${image.digest}` : ""}` : `${registryHost}/${image.image}${image.digest ? `@${image.digest}` : ""}`;
@@ -3125,10 +3288,27 @@ async function _deployCommand(dir, options) {
3125
3288
  }
3126
3289
  case "FAILED": {
3127
3290
  if (finishedDeployment.errorData) {
3128
- deploymentSpinner.stop(
3129
- `Deployment encountered an error: ${finishedDeployment.errorData.name}. ${deploymentLink}`
3130
- );
3131
- logger.error(finishedDeployment.errorData.stack);
3291
+ if (finishedDeployment.errorData.name === "TaskMetadataParseError") {
3292
+ const errorJson = safeJsonParse(finishedDeployment.errorData.stack);
3293
+ if (errorJson) {
3294
+ const parsedError2 = TaskMetadataFailedToParseData.safeParse(errorJson);
3295
+ if (parsedError2.success) {
3296
+ deploymentSpinner.stop(`Deployment encountered an error. ${deploymentLink}`);
3297
+ logTaskMetadataParseError(parsedError2.data.zodIssues, parsedError2.data.tasks);
3298
+ throw new SkipLoggingError(
3299
+ `Deployment encountered an error: ${finishedDeployment.errorData.name}`
3300
+ );
3301
+ }
3302
+ }
3303
+ }
3304
+ const parsedError = finishedDeployment.errorData.stack ? parseBuildErrorStack(finishedDeployment.errorData) : finishedDeployment.errorData.message;
3305
+ if (typeof parsedError === "string") {
3306
+ deploymentSpinner.stop(`Deployment encountered an error. ${deploymentLink}`);
3307
+ logger.log(`${chalkError("X Error:")} ${parsedError}`);
3308
+ } else {
3309
+ deploymentSpinner.stop(`Deployment encountered an error. ${deploymentLink}`);
3310
+ logESMRequireError(parsedError, resolvedConfig);
3311
+ }
3132
3312
  throw new SkipLoggingError(
3133
3313
  `Deployment encountered an error: ${finishedDeployment.errorData.name}`
3134
3314
  );
@@ -3166,7 +3346,7 @@ async function checkEnvVars(envVars, config, options, environmentClient, apiUrl)
3166
3346
  environmentVariablesSpinner.stop(
3167
3347
  `Found missing env vars in ${options.env}: ${arrayToSentence(
3168
3348
  missingEnvironmentVariables
3169
- )}. ${options.ignoreEnvVarCheck ? "Continuing deployment because of --ignore-env-var-check. " : "Aborting deployment. "}${chalk4.bgBlueBright(
3349
+ )}. ${options.ignoreEnvVarCheck ? "Continuing deployment because of --ignore-env-var-check. " : "Aborting deployment. "}${chalk5.bgBlueBright(
3170
3350
  terminalLink(
3171
3351
  "Manage env vars",
3172
3352
  `${apiUrl}/projects/v3/${config.project}/environment-variables`
@@ -3227,7 +3407,7 @@ async function waitForDeploymentToFinish(deploymentId, client, timeoutInSeconds
3227
3407
  }
3228
3408
  });
3229
3409
  }
3230
- async function buildAndPushImage(options) {
3410
+ async function buildAndPushImage(options, updater) {
3231
3411
  return tracer.startActiveSpan("buildAndPushImage", async (span) => {
3232
3412
  span.setAttributes({
3233
3413
  "options.registryHost": options.registryHost,
@@ -3283,15 +3463,23 @@ async function buildAndPushImage(options) {
3283
3463
  });
3284
3464
  const errors = [];
3285
3465
  try {
3286
- await new Promise((res, rej) => {
3466
+ const processCode = await new Promise((res, rej) => {
3287
3467
  childProcess2.stderr?.on("data", (data) => {
3288
- const text2 = data.toString();
3289
- errors.push(text2);
3290
- logger.debug(text2);
3468
+ const text3 = data.toString();
3469
+ errors.push(text3);
3470
+ logger.debug(text3);
3291
3471
  });
3292
3472
  childProcess2.on("error", (e) => rej(e));
3293
- childProcess2.on("close", () => res());
3473
+ childProcess2.on("close", (code) => res(code));
3294
3474
  });
3475
+ const logs = extractLogs(errors);
3476
+ if (processCode !== 0) {
3477
+ return {
3478
+ ok: false,
3479
+ error: `Error building image`,
3480
+ logs
3481
+ };
3482
+ }
3295
3483
  const digest = extractImageDigest(errors);
3296
3484
  span.setAttributes({
3297
3485
  "image.digest": digest
@@ -3300,6 +3488,7 @@ async function buildAndPushImage(options) {
3300
3488
  return {
3301
3489
  ok: true,
3302
3490
  image: options.imageTag,
3491
+ logs,
3303
3492
  digest
3304
3493
  };
3305
3494
  } catch (e) {
@@ -3307,7 +3496,8 @@ async function buildAndPushImage(options) {
3307
3496
  span.end();
3308
3497
  return {
3309
3498
  ok: false,
3310
- error: e instanceof Error ? e.message : JSON.stringify(e)
3499
+ error: e instanceof Error ? e.message : JSON.stringify(e),
3500
+ logs: extractLogs(errors)
3311
3501
  };
3312
3502
  }
3313
3503
  });
@@ -3355,9 +3545,9 @@ async function buildAndPushSelfHostedImage(options) {
3355
3545
  try {
3356
3546
  await new Promise((res, rej) => {
3357
3547
  buildProcess.stderr?.on("data", (data) => {
3358
- const text2 = data.toString();
3359
- errors.push(text2);
3360
- logger.debug(text2);
3548
+ const text3 = data.toString();
3549
+ errors.push(text3);
3550
+ logger.debug(text3);
3361
3551
  });
3362
3552
  buildProcess.on("error", (e) => rej(e));
3363
3553
  buildProcess.on("close", () => res());
@@ -3371,7 +3561,8 @@ async function buildAndPushSelfHostedImage(options) {
3371
3561
  span.end();
3372
3562
  return {
3373
3563
  ok: false,
3374
- error: e instanceof Error ? e.message : JSON.stringify(e)
3564
+ error: e instanceof Error ? e.message : JSON.stringify(e),
3565
+ logs: extractLogs(errors)
3375
3566
  };
3376
3567
  }
3377
3568
  const pushArgs = ["push", imageRef].filter(Boolean);
@@ -3384,12 +3575,12 @@ async function buildAndPushSelfHostedImage(options) {
3384
3575
  try {
3385
3576
  await new Promise((res, rej) => {
3386
3577
  pushProcess.stdout?.on("data", (data) => {
3387
- const text2 = data.toString();
3388
- logger.debug(text2);
3578
+ const text3 = data.toString();
3579
+ logger.debug(text3);
3389
3580
  });
3390
3581
  pushProcess.stderr?.on("data", (data) => {
3391
- const text2 = data.toString();
3392
- logger.debug(text2);
3582
+ const text3 = data.toString();
3583
+ logger.debug(text3);
3393
3584
  });
3394
3585
  pushProcess.on("error", (e) => rej(e));
3395
3586
  pushProcess.on("close", () => res());
@@ -3400,7 +3591,8 @@ async function buildAndPushSelfHostedImage(options) {
3400
3591
  span.end();
3401
3592
  return {
3402
3593
  ok: false,
3403
- error: e instanceof Error ? e.message : JSON.stringify(e)
3594
+ error: e instanceof Error ? e.message : JSON.stringify(e),
3595
+ logs: extractLogs(errors)
3404
3596
  };
3405
3597
  }
3406
3598
  }
@@ -3408,7 +3600,8 @@ async function buildAndPushSelfHostedImage(options) {
3408
3600
  return {
3409
3601
  ok: true,
3410
3602
  image: options.imageTag,
3411
- digest
3603
+ digest,
3604
+ logs: extractLogs(errors)
3412
3605
  };
3413
3606
  });
3414
3607
  }
@@ -3423,6 +3616,10 @@ function extractImageDigest(outputs) {
3423
3616
  }
3424
3617
  }
3425
3618
  }
3619
+ function extractLogs(outputs) {
3620
+ const cleanedOutputs = outputs.map((line) => line.trim()).filter((line) => line !== "");
3621
+ return cleanedOutputs.map((line) => line.trim()).join("\n");
3622
+ }
3426
3623
  async function compileProject(config, options, configPath) {
3427
3624
  return await tracer.startActiveSpan("compileProject", async (span) => {
3428
3625
  try {
@@ -3607,7 +3804,7 @@ async function compileProject(config, options, configPath) {
3607
3804
  options
3608
3805
  );
3609
3806
  if (!resolvingDependenciesResult) {
3610
- throw new Error("Failed to resolve dependencies");
3807
+ throw new SkipLoggingError("Failed to resolve dependencies");
3611
3808
  }
3612
3809
  const containerFilePath = new URL(
3613
3810
  importResolve("./Containerfile.prod", import.meta.url)
@@ -3686,12 +3883,35 @@ async function resolveDependencies(projectDir, packageJsonContents, config, opti
3686
3883
  resolvingDepsSpinner.stop("Dependencies resolved");
3687
3884
  return true;
3688
3885
  } catch (installError) {
3689
- logger.debug(`Failed to resolve dependencies: ${JSON.stringify(installError)}`);
3690
3886
  recordSpanException4(span, installError);
3691
3887
  span.end();
3692
- resolvingDepsSpinner.stop(
3693
- "Failed to resolve dependencies. Rerun with --log-level=debug for more information"
3694
- );
3888
+ const parsedError = parseNpmInstallError(installError);
3889
+ if (typeof parsedError === "string") {
3890
+ resolvingDepsSpinner.stop(`Failed to resolve dependencies: ${parsedError}`);
3891
+ } else {
3892
+ switch (parsedError.type) {
3893
+ case "package-not-found-error": {
3894
+ resolvingDepsSpinner.stop(`Failed to resolve dependencies`);
3895
+ logger.log(
3896
+ `
3897
+ ${chalkError("X Error:")} The package ${chalkPurple(
3898
+ parsedError.packageName
3899
+ )} could not be found in the npm registry.`
3900
+ );
3901
+ break;
3902
+ }
3903
+ case "no-matching-version-error": {
3904
+ resolvingDepsSpinner.stop(`Failed to resolve dependencies`);
3905
+ logger.log(
3906
+ `
3907
+ ${chalkError("X Error:")} The package ${chalkPurple(
3908
+ parsedError.packageName
3909
+ )} could not resolve because the version doesn't exist`
3910
+ );
3911
+ break;
3912
+ }
3913
+ }
3914
+ }
3695
3915
  return false;
3696
3916
  }
3697
3917
  }
@@ -3773,8 +3993,10 @@ async function gatherRequiredDependencies(imports, config, projectPackageJson) {
3773
3993
  dependencies2[packageParts.name] = externalDependencyVersion;
3774
3994
  continue;
3775
3995
  } else {
3776
- logger.warn(
3777
- `Could not find version for package ${packageName}, add a version specifier to the package name (e.g. ${packageParts.name}@latest) or add it to your project's package.json`
3996
+ logger.log(
3997
+ `${chalkWarning("X Warning:")} Could not find version for package ${chalkPurple(
3998
+ packageName
3999
+ )}, add a version specifier to the package name (e.g. ${packageParts.name}@latest) or add it to your project's package.json`
3778
4000
  );
3779
4001
  }
3780
4002
  }
@@ -3808,7 +4030,7 @@ async function copyAdditionalFiles(config, tempDir) {
3808
4030
  for await (const file of glob) {
3809
4031
  const relativeDestinationPath = join4(
3810
4032
  tempDir,
3811
- relative2(config.projectDir, file.fullpath())
4033
+ relative3(config.projectDir, file.fullpath())
3812
4034
  );
3813
4035
  logger.debug(`Copying file ${file.fullpath()} to ${relativeDestinationPath}`);
3814
4036
  await mkdir(dirname(relativeDestinationPath), { recursive: true });
@@ -3888,6 +4110,14 @@ var UncaughtExceptionError = class extends Error {
3888
4110
  this.name = "UncaughtExceptionError";
3889
4111
  }
3890
4112
  };
4113
+ var TaskMetadataParseError = class extends Error {
4114
+ constructor(zodIssues, tasks) {
4115
+ super(`Failed to parse task metadata`);
4116
+ this.zodIssues = zodIssues;
4117
+ this.tasks = tasks;
4118
+ this.name = "TaskMetadataParseError";
4119
+ }
4120
+ };
3891
4121
 
3892
4122
  // src/workers/dev/backgroundWorker.ts
3893
4123
  import {
@@ -4133,6 +4363,11 @@ var BackgroundWorker = class {
4133
4363
  resolved = true;
4134
4364
  reject(new UncaughtExceptionError(message.payload.error, message.payload.origin));
4135
4365
  child.kill();
4366
+ } else if (message.type === "TASKS_FAILED_TO_PARSE") {
4367
+ clearTimeout(timeout);
4368
+ resolved = true;
4369
+ reject(new TaskMetadataParseError(message.payload.zodIssues, message.payload.tasks));
4370
+ child.kill();
4136
4371
  }
4137
4372
  });
4138
4373
  child.on("exit", (code) => {
@@ -4158,7 +4393,7 @@ var BackgroundWorker = class {
4158
4393
  }
4159
4394
  if (!this._taskRunProcesses.has(payload.execution.run.id)) {
4160
4395
  const taskRunProcess = new TaskRunProcess(
4161
- payload.execution.run.id,
4396
+ payload.execution,
4162
4397
  this.path,
4163
4398
  {
4164
4399
  ...this.params.env,
@@ -4268,8 +4503,8 @@ var BackgroundWorker = class {
4268
4503
  }
4269
4504
  };
4270
4505
  var TaskRunProcess = class {
4271
- constructor(runId, path6, env, metadata, worker) {
4272
- this.runId = runId;
4506
+ constructor(execution, path6, env, metadata, worker) {
4507
+ this.execution = execution;
4273
4508
  this.path = path6;
4274
4509
  this.env = env;
4275
4510
  this.metadata = metadata;
@@ -4300,8 +4535,17 @@ var TaskRunProcess = class {
4300
4535
  await this.cleanup(true);
4301
4536
  }
4302
4537
  async initialize() {
4303
- logger.debug(`[${this.runId}] initializing task run process`, {
4304
- env: this.env,
4538
+ const fullEnv = {
4539
+ ...this.execution.run.isTest ? { TRIGGER_LOG_LEVEL: "debug" } : {},
4540
+ ...this.env,
4541
+ OTEL_RESOURCE_ATTRIBUTES: JSON.stringify({
4542
+ [SemanticInternalAttributes.PROJECT_DIR]: this.worker.projectConfig.projectDir
4543
+ }),
4544
+ OTEL_EXPORTER_OTLP_COMPRESSION: "none",
4545
+ ...this.worker.debugOtel ? { OTEL_LOG_LEVEL: "debug" } : {}
4546
+ };
4547
+ logger.debug(`[${this.execution.run.id}] initializing task run process`, {
4548
+ env: fullEnv,
4305
4549
  path: this.path
4306
4550
  });
4307
4551
  this._child = fork(this.path, {
@@ -4315,14 +4559,7 @@ var TaskRunProcess = class {
4315
4559
  "ipc"
4316
4560
  ],
4317
4561
  cwd: dirname2(this.path),
4318
- env: {
4319
- ...this.env,
4320
- OTEL_RESOURCE_ATTRIBUTES: JSON.stringify({
4321
- [SemanticInternalAttributes.PROJECT_DIR]: this.worker.projectConfig.projectDir
4322
- }),
4323
- OTEL_EXPORTER_OTLP_COMPRESSION: "none",
4324
- ...this.worker.debugOtel ? { OTEL_LOG_LEVEL: "debug" } : {}
4325
- },
4562
+ env: fullEnv,
4326
4563
  execArgv: this.worker.debuggerOn ? ["--inspect-brk", "--trace-uncaught", "--no-warnings=ExperimentalWarning"] : ["--trace-uncaught", "--no-warnings=ExperimentalWarning"]
4327
4564
  });
4328
4565
  this._child.on("message", this.#handleMessage.bind(this));
@@ -4334,7 +4571,7 @@ var TaskRunProcess = class {
4334
4571
  if (kill && this._isBeingKilled) {
4335
4572
  return;
4336
4573
  }
4337
- logger.debug(`[${this.runId}] cleaning up task run process`, { kill });
4574
+ logger.debug(`[${this.execution.run.id}] cleaning up task run process`, { kill });
4338
4575
  await this._sender.send("CLEANUP", {
4339
4576
  flush: true,
4340
4577
  kill
@@ -4365,10 +4602,13 @@ var TaskRunProcess = class {
4365
4602
  if (!completion.ok && typeof completion.retry !== "undefined") {
4366
4603
  return;
4367
4604
  }
4368
- if (execution.run.id === this.runId) {
4605
+ if (execution.run.id === this.execution.run.id) {
4369
4606
  return;
4370
4607
  }
4371
- logger.debug(`[${this.runId}] task run completed notification`, { completion, execution });
4608
+ logger.debug(`[${this.execution.run.id}] task run completed notification`, {
4609
+ completion,
4610
+ execution
4611
+ });
4372
4612
  this._sender.send("TASK_RUN_COMPLETED_NOTIFICATION", {
4373
4613
  completion,
4374
4614
  execution
@@ -4406,7 +4646,7 @@ var TaskRunProcess = class {
4406
4646
  }
4407
4647
  }
4408
4648
  async #handleExit(code) {
4409
- logger.debug(`[${this.runId}] task run process exiting`, { code });
4649
+ logger.debug(`[${this.execution.run.id}] task run process exiting`, { code });
4410
4650
  for (const [id, status] of this._attemptStatuses.entries()) {
4411
4651
  if (status === "PENDING") {
4412
4652
  this._attemptStatuses.set(id, "REJECTED");
@@ -4453,6 +4693,25 @@ var TaskRunProcess = class {
4453
4693
  }
4454
4694
  };
4455
4695
 
4696
+ // src/utilities/runtimeCheck.ts
4697
+ function runtimeCheck(minimumMajor, minimumMinor) {
4698
+ if (typeof process === "undefined") {
4699
+ throw "The dev CLI can only be run in a Node.js compatible environment";
4700
+ }
4701
+ const [major = 0, minor = 0] = process.versions.node.split(".").map(Number);
4702
+ const isBun = typeof process.versions.bun === "string";
4703
+ if (major < minimumMajor || major === minimumMajor && minor < minimumMinor) {
4704
+ if (isBun) {
4705
+ throw `The dev CLI requires at least Node.js ${minimumMajor}.${minimumMinor}. You are running Bun ${process.versions.bun}, which is compatible with Node.js ${process.versions.node}`;
4706
+ } else {
4707
+ throw `The dev CLI requires at least Node.js ${minimumMajor}.${minimumMinor}. You are running Node.js ${process.versions.node}`;
4708
+ }
4709
+ }
4710
+ logger.debug(
4711
+ `Node.js version: ${process.versions.node}${isBun ? ` (Bun ${process.versions.bun})` : ""}`
4712
+ );
4713
+ }
4714
+
4456
4715
  // src/commands/dev.tsx
4457
4716
  var apiClient;
4458
4717
  var DevCommandOptions = CommonCommandOptions.extend({
@@ -4473,13 +4732,26 @@ function configureDevCommand(program2) {
4473
4732
  });
4474
4733
  });
4475
4734
  }
4735
+ var MINIMUM_NODE_MAJOR = 18;
4736
+ var MINIMUM_NODE_MINOR = 16;
4476
4737
  async function devCommand(dir, options) {
4738
+ try {
4739
+ runtimeCheck(MINIMUM_NODE_MAJOR, MINIMUM_NODE_MINOR);
4740
+ } catch (e) {
4741
+ logger.log(`${chalkError("X Error:")} ${e}`);
4742
+ process.exitCode = 1;
4743
+ return;
4744
+ }
4477
4745
  const authorization = await isLoggedIn(options.profile);
4478
4746
  if (!authorization.ok) {
4479
4747
  if (authorization.error === "fetch failed") {
4480
- logger.error("Fetch failed. Platform down?");
4748
+ logger.log(
4749
+ `${chalkError(
4750
+ "X Error:"
4751
+ )} Connecting to the server failed. Please check your internet connection or contact eric@trigger.dev for help.`
4752
+ );
4481
4753
  } else {
4482
- logger.error("You must login first. Use `trigger.dev login` to login.");
4754
+ logger.log(`${chalkError("X Error:")} You must login first. Use the \`login\` CLI command.`);
4483
4755
  }
4484
4756
  process.exitCode = 1;
4485
4757
  return;
@@ -4829,17 +5101,52 @@ function useDev({
4829
5101
  backgroundWorker
4830
5102
  );
4831
5103
  } catch (e) {
4832
- if (e instanceof UncaughtExceptionError) {
5104
+ if (e instanceof TaskMetadataParseError) {
5105
+ logTaskMetadataParseError(e.zodIssues, e.tasks);
5106
+ return;
5107
+ } else if (e instanceof UncaughtExceptionError) {
5108
+ const parsedBuildError = parseBuildErrorStack(e.originalError);
5109
+ if (typeof parsedBuildError !== "string") {
5110
+ logESMRequireError(
5111
+ parsedBuildError,
5112
+ configPath ? { status: "file", path: configPath, config } : { status: "in-memory", config }
5113
+ );
5114
+ return;
5115
+ } else {
5116
+ }
4833
5117
  if (e.originalError.stack) {
4834
- logger.error("Background worker failed to start", e.originalError.stack);
5118
+ logger.log(
5119
+ `${chalkError("X Error:")} Worker failed to start`,
5120
+ e.originalError.stack
5121
+ );
4835
5122
  }
4836
5123
  return;
4837
5124
  }
4838
- if (e instanceof Error) {
4839
- logger.error(`Background worker failed to start`, e.stack);
4840
- return;
5125
+ const parsedError = parseNpmInstallError(e);
5126
+ if (typeof parsedError === "string") {
5127
+ logger.log(`${chalkError("X Error:")} ${parsedError}`);
5128
+ } else {
5129
+ switch (parsedError.type) {
5130
+ case "package-not-found-error": {
5131
+ logger.log(
5132
+ `
5133
+ ${chalkError("X Error:")} The package ${chalkPurple(
5134
+ parsedError.packageName
5135
+ )} could not be found in the npm registry.`
5136
+ );
5137
+ break;
5138
+ }
5139
+ case "no-matching-version-error": {
5140
+ logger.log(
5141
+ `
5142
+ ${chalkError("X Error:")} The package ${chalkPurple(
5143
+ parsedError.packageName
5144
+ )} could not resolve because the version doesn't exist`
5145
+ );
5146
+ break;
5147
+ }
5148
+ }
4841
5149
  }
4842
- logger.error(`Background worker failed to start: ${e}`);
4843
5150
  }
4844
5151
  });
4845
5152
  }
@@ -4950,14 +5257,12 @@ async function gatherRequiredDependencies2(outputMeta, config) {
4950
5257
  function createDuplicateTaskIdOutputErrorMessage(duplicateTaskIds, taskResources) {
4951
5258
  const duplicateTable = duplicateTaskIds.map((id) => {
4952
5259
  const tasks = taskResources.filter((task) => task.id === id);
4953
- return `id "${chalkPurple(id)}" was found in:
4954
- ${tasks.map((task) => `${task.filePath} -> ${task.exportName}`).join("\n")}`;
4955
- }).join("\n\n");
4956
- return `Duplicate task ids detected:
4957
-
4958
- ${duplicateTable}
5260
+ return `
4959
5261
 
4960
- `;
5262
+ ${chalkTask(id)} was found in:${tasks.map((task) => `
5263
+ ${task.filePath} -> ${task.exportName}`).join("")}`;
5264
+ }).join("");
5265
+ return `Duplicate ${chalkTask("task id")} detected:${duplicateTable}`;
4961
5266
  }
4962
5267
  function gatherProcessEnv() {
4963
5268
  const env = {
@@ -4984,11 +5289,11 @@ import {
4984
5289
  flattenAttributes as flattenAttributes3,
4985
5290
  recordSpanException as recordSpanException5
4986
5291
  } from "@trigger.dev/core/v3";
4987
- import chalk5 from "chalk";
5292
+ import chalk6 from "chalk";
4988
5293
  import { execa as execa3 } from "execa";
4989
5294
  import { applyEdits, modify } from "jsonc-parser";
4990
5295
  import { writeFile as writeFile3 } from "node:fs/promises";
4991
- import { join as join6, relative as relative3, resolve as resolve3 } from "node:path";
5296
+ import { join as join6, relative as relative4, resolve as resolve3 } from "node:path";
4992
5297
  import terminalLink3 from "terminal-link";
4993
5298
  import { z as z6 } from "zod";
4994
5299
 
@@ -5167,7 +5472,7 @@ async function _initCommand(dir, options) {
5167
5472
  log3.success("Successfully initialized project for Trigger.dev v3 \u{1FAE1}");
5168
5473
  log3.info("Next steps:");
5169
5474
  log3.info(
5170
- ` 1. To start developing, run ${chalk5.green(
5475
+ ` 1. To start developing, run ${chalk6.green(
5171
5476
  `npx trigger.dev@${options.tag} dev`
5172
5477
  )} in your project directory`
5173
5478
  );
@@ -5182,7 +5487,7 @@ async function _initCommand(dir, options) {
5182
5487
  ` 4. Need help? Join our ${terminalLink3(
5183
5488
  "Discord community",
5184
5489
  "https://trigger.dev/discord"
5185
- )} or email us at ${chalk5.cyan("help@trigger.dev")}`
5490
+ )} or email us at ${chalk6.cyan("help@trigger.dev")}`
5186
5491
  );
5187
5492
  outro4(`Project initialized successfully. Happy coding!`);
5188
5493
  }
@@ -5236,7 +5541,7 @@ async function createTriggerDir(dir, options) {
5236
5541
  outputPath,
5237
5542
  replacements: {}
5238
5543
  });
5239
- const relativeOutputPath = relative3(process.cwd(), outputPath);
5544
+ const relativeOutputPath = relative4(process.cwd(), outputPath);
5240
5545
  log3.step(`Created example file at ${relativeOutputPath}`);
5241
5546
  span.end();
5242
5547
  return { location, isCustomValue: location !== defaultValue };
@@ -5390,7 +5695,7 @@ async function writeConfigFile(dir, project, options, triggerDir) {
5390
5695
  outputPath,
5391
5696
  override: options.overrideConfig
5392
5697
  });
5393
- const relativePathToOutput = relative3(process.cwd(), outputPath);
5698
+ const relativePathToOutput = relative4(process.cwd(), outputPath);
5394
5699
  spnnr.stop(
5395
5700
  result.success ? `Config file created at ${relativePathToOutput}` : `Failed to create config file: ${result.error}`
5396
5701
  );
@@ -5472,12 +5777,14 @@ async function selectProject(apiClient2, dashboardUrl, projectRef) {
5472
5777
  // src/commands/logout.ts
5473
5778
  var LogoutCommandOptions = CommonCommandOptions;
5474
5779
  function configureLogoutCommand(program2) {
5475
- return commonOptions(program2.command("logout").description("Logout of Trigger.dev")).action(async (options) => {
5476
- await handleTelemetry(async () => {
5477
- await printInitialBanner(false);
5478
- await logoutCommand(options);
5479
- });
5480
- });
5780
+ return commonOptions(program2.command("logout").description("Logout of Trigger.dev")).action(
5781
+ async (options) => {
5782
+ await handleTelemetry(async () => {
5783
+ await printInitialBanner(false);
5784
+ await logoutCommand(options);
5785
+ });
5786
+ }
5787
+ );
5481
5788
  }
5482
5789
  async function logoutCommand(options) {
5483
5790
  return await wrapCommandAction("logoutCommand", LogoutCommandOptions, options, async (opts) => {
@@ -5487,11 +5794,46 @@ async function logoutCommand(options) {
5487
5794
  async function logout(options) {
5488
5795
  const config = readAuthConfigProfile(options.profile);
5489
5796
  if (!config?.accessToken) {
5490
- logger.info(`You are already logged out [${options.profile ?? "default"}]`);
5797
+ logger.info(`You are already logged out [${options.profile}]`);
5491
5798
  return;
5492
5799
  }
5493
- writeAuthConfigProfile({ ...config, accessToken: void 0, apiUrl: void 0 }, options.profile);
5494
- logger.info(`Logged out of Trigger.dev [${options.profile ?? "default"}]`);
5800
+ deleteAuthConfigProfile(options.profile);
5801
+ logger.info(`Logged out of Trigger.dev [${options.profile}]`);
5802
+ }
5803
+
5804
+ // src/commands/list-profiles.ts
5805
+ import { log as log4, outro as outro5 } from "@clack/prompts";
5806
+ var ListProfilesOptions = CommonCommandOptions;
5807
+ function configureListProfilesCommand(program2) {
5808
+ return program2.command("list-profiles").description("List all of your CLI profiles").option(
5809
+ "-l, --log-level <level>",
5810
+ "The CLI log level to use (debug, info, log, warn, error, none). This does not effect the log level of your trigger.dev tasks.",
5811
+ "log"
5812
+ ).option("--skip-telemetry", "Opt-out of sending telemetry").action(async (options) => {
5813
+ await handleTelemetry(async () => {
5814
+ await printInitialBanner(true);
5815
+ await listProfilesCommand(options);
5816
+ });
5817
+ });
5818
+ }
5819
+ async function listProfilesCommand(options) {
5820
+ return await wrapCommandAction("listProfiles", ListProfilesOptions, options, async (opts) => {
5821
+ return await listProfiles(opts);
5822
+ });
5823
+ }
5824
+ async function listProfiles(options) {
5825
+ const authConfig = readAuthConfigFile();
5826
+ if (!authConfig) {
5827
+ logger.info("No profiles found");
5828
+ return;
5829
+ }
5830
+ const profiles = Object.keys(authConfig);
5831
+ log4.message("Profiles:");
5832
+ for (const profile of profiles) {
5833
+ const profileConfig = authConfig[profile];
5834
+ log4.info(`${profile}${profileConfig?.apiUrl ? ` - ${chalkGrey(profileConfig.apiUrl)}` : ""}`);
5835
+ }
5836
+ outro5("Retrieve account info by running whoami --profile <profile>");
5495
5837
  }
5496
5838
 
5497
5839
  // src/cli/index.ts
@@ -5503,6 +5845,7 @@ configureDevCommand(program);
5503
5845
  configureDeployCommand(program);
5504
5846
  configureWhoamiCommand(program);
5505
5847
  configureLogoutCommand(program);
5848
+ configureListProfilesCommand(program);
5506
5849
 
5507
5850
  // src/index.ts
5508
5851
  var main = async () => {