trigger.dev 0.0.0-v3-canary-20240325172431 → 0.0.0-v3-pnpm-fix-20240403154252

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 = "0.0.0-v3-canary-20240325172431";
804
+ var version = "0.0.0-v3-pnpm-fix-20240403154252";
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:0.0.0-v3-canary-20240325172431",
820
+ "@trigger.dev/core": "workspace:0.0.0-v3-pnpm-fix-20240403154252",
820
821
  "@types/degit": "^2.8.3",
821
822
  chalk: "^5.2.0",
822
823
  chokidar: "^3.5.3",
@@ -840,6 +841,7 @@ var dependencies = {
840
841
  "node-fetch": "^3.3.0",
841
842
  "npm-check-updates": "^16.12.2",
842
843
  "object-hash": "^3.0.0",
844
+ "p-debounce": "^4.0.0",
843
845
  "p-throttle": "^6.1.0",
844
846
  partysocket: "^0.0.17",
845
847
  "proxy-agent": "^6.3.0",
@@ -1306,7 +1308,7 @@ var Logger = class {
1306
1308
  const kind = LOGGER_LEVEL_FORMAT_TYPE_MAP[level];
1307
1309
  if (kind) {
1308
1310
  const [firstLine, ...otherLines] = message.split("\n");
1309
- 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;
1310
1312
  return formatMessagesSync([{ text: firstLine, notes }], {
1311
1313
  color: true,
1312
1314
  kind,
@@ -1321,6 +1323,58 @@ var logger = new Logger();
1321
1323
 
1322
1324
  // src/cli/common.ts
1323
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
1324
1378
  var CommonCommandOptions = z.object({
1325
1379
  apiUrl: z.string().optional(),
1326
1380
  logLevel: z.enum(["debug", "info", "log", "warn", "error", "none"]).default("log"),
@@ -1330,7 +1384,7 @@ var CommonCommandOptions = z.object({
1330
1384
  function commonOptions(command) {
1331
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(
1332
1386
  "-l, --log-level <level>",
1333
- "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.",
1334
1388
  "log"
1335
1389
  ).option("--skip-telemetry", "Opt-out of sending telemetry");
1336
1390
  }
@@ -1376,7 +1430,7 @@ async function wrapCommandAction(name, schema, options, action) {
1376
1430
  } else if (e instanceof SkipCommandError) {
1377
1431
  } else {
1378
1432
  recordSpanException(span, e);
1379
- logger.error(e instanceof Error ? e.message : String(e));
1433
+ logger.log(`${chalkError("X Error:")} ${e instanceof Error ? e.message : String(e)}`);
1380
1434
  }
1381
1435
  span.end();
1382
1436
  throw e;
@@ -1534,6 +1588,11 @@ function readAuthConfigProfile(profile = "default") {
1534
1588
  return void 0;
1535
1589
  }
1536
1590
  }
1591
+ function deleteAuthConfigProfile(profile = "default") {
1592
+ const existingConfig = readAuthConfigFile() || {};
1593
+ delete existingConfig[profile];
1594
+ writeAuthConfigFile(existingConfig);
1595
+ }
1537
1596
  function readAuthConfigFile() {
1538
1597
  try {
1539
1598
  const authConfigFilePath = getAuthConfigFilePath();
@@ -1638,23 +1697,6 @@ import chalk3 from "chalk";
1638
1697
  import supportsColor from "supports-color";
1639
1698
  import checkForUpdate from "update-check";
1640
1699
 
1641
- // src/utilities/colors.ts
1642
- import chalk2 from "chalk";
1643
- var green = "#4FFF54";
1644
- var purple = "#735BF3";
1645
- function chalkPurple(text2) {
1646
- return chalk2.hex(purple)(text2);
1647
- }
1648
- function chalkGrey(text2) {
1649
- return chalk2.hex("#666")(text2);
1650
- }
1651
- function chalkLink(text2) {
1652
- return chalk2.underline.blue(text2);
1653
- }
1654
- function logo() {
1655
- return `${chalk2.hex(green).bold("Trigger")}${chalk2.hex(purple).bold(".dev")}`;
1656
- }
1657
-
1658
1700
  // src/utilities/getVersion.ts
1659
1701
  import path3 from "path";
1660
1702
  function getVersion() {
@@ -1666,10 +1708,10 @@ function getVersion() {
1666
1708
  // src/utilities/initialBanner.ts
1667
1709
  async function printInitialBanner(performUpdateCheck = true) {
1668
1710
  const packageVersion = getVersion();
1669
- const text2 = `
1711
+ const text3 = `
1670
1712
  ${logo()} ${chalkGrey(`(${packageVersion})`)}
1671
1713
  `;
1672
- logger.info(text2);
1714
+ logger.info(text3);
1673
1715
  let maybeNewVersion;
1674
1716
  if (performUpdateCheck) {
1675
1717
  const loadingSpinner = spinner();
@@ -1693,17 +1735,23 @@ After installation, run Trigger.dev with \`npx trigger.dev\`.`
1693
1735
  }
1694
1736
  async function printStandloneInitialBanner(performUpdateCheck = true) {
1695
1737
  const packageVersion = getVersion();
1696
- let text2 = `
1738
+ let text3 = `
1697
1739
  ${logo()} ${chalkGrey("(v3 Developer Preview)")}`;
1698
1740
  if (performUpdateCheck) {
1699
1741
  const maybeNewVersion = await updateCheck();
1700
1742
  if (maybeNewVersion !== void 0) {
1701
- text2 = `${text2} (update available ${chalk3.green(maybeNewVersion)})`;
1743
+ text3 = `${text3} (update available ${chalk3.green(maybeNewVersion)})`;
1702
1744
  }
1703
1745
  }
1746
+ logger.log(text3 + "\n" + (supportsColor.stdout ? chalkGrey("-".repeat(54)) : "-".repeat(54)));
1747
+ }
1748
+ function printDevBanner() {
1704
1749
  logger.log(
1705
- text2 + "\n" + (supportsColor.stdout ? chalk3.hex(green)("-".repeat(54)) : "-".repeat(54))
1750
+ `${chalkGrey("Key:")} ${chalkWorker("Version")} ${chalkGrey("|")} ${chalkTask(
1751
+ "Task"
1752
+ )} ${chalkGrey("|")} ${chalkRun("Run")}`
1706
1753
  );
1754
+ logger.log(chalkGrey("-".repeat(54)));
1707
1755
  }
1708
1756
  async function doUpdateCheck() {
1709
1757
  let update = null;
@@ -1727,20 +1775,14 @@ async function installPackages(packages, options) {
1727
1775
  const cwd = options?.cwd ?? process.cwd();
1728
1776
  logger.debug("Installing packages", { packages });
1729
1777
  await setPackageJsonDeps(join3(cwd, "package.json"), packages);
1730
- const childProcess2 = execa(
1778
+ await execa(
1731
1779
  "npm",
1732
1780
  ["install", "--install-strategy", "nested", "--ignore-scripts", "--no-audit", "--no-fund"],
1733
1781
  {
1734
1782
  cwd,
1735
- stderr: "inherit"
1783
+ stderr: "pipe"
1736
1784
  }
1737
1785
  );
1738
- await new Promise((res, rej) => {
1739
- childProcess2.on("error", (e) => rej(e));
1740
- childProcess2.on("close", () => res());
1741
- });
1742
- await childProcess2;
1743
- return;
1744
1786
  }
1745
1787
  function detectPackageNameFromImportPath(path6) {
1746
1788
  if (path6.startsWith("@")) {
@@ -2392,7 +2434,9 @@ async function isLoggedIn(profile = "default") {
2392
2434
  // src/commands/whoami.ts
2393
2435
  var WhoamiCommandOptions = CommonCommandOptions;
2394
2436
  function configureWhoamiCommand(program2) {
2395
- return commonOptions(program2.command("whoami").description("display the current logged in user and project details")).action(async (options) => {
2437
+ return commonOptions(
2438
+ program2.command("whoami").description("display the current logged in user and project details")
2439
+ ).action(async (options) => {
2396
2440
  await handleTelemetry(async () => {
2397
2441
  await printInitialBanner(false);
2398
2442
  await whoAmICommand(options);
@@ -2415,7 +2459,9 @@ async function whoAmI(options, embedded = false) {
2415
2459
  if (authentication.error === "fetch failed") {
2416
2460
  loadingSpinner.stop("Fetch failed. Platform down?");
2417
2461
  } else {
2418
- loadingSpinner.stop(`You must login first. Use \`trigger.dev login --profile ${options?.profile ?? "default"}\` to login.`);
2462
+ loadingSpinner.stop(
2463
+ `You must login first. Use \`trigger.dev login --profile ${options?.profile ?? "default"}\` to login.`
2464
+ );
2419
2465
  }
2420
2466
  return {
2421
2467
  success: false,
@@ -2482,7 +2528,14 @@ async function login(options) {
2482
2528
  }
2483
2529
  const authConfig = readAuthConfigProfile(options?.profile);
2484
2530
  if (authConfig && authConfig.accessToken) {
2485
- const whoAmIResult = await whoAmI({ profile: options?.profile ?? "default", skipTelemetry: !span.isRecording(), logLevel: logger.loggerLevel }, opts.embedded);
2531
+ const whoAmIResult = await whoAmI(
2532
+ {
2533
+ profile: options?.profile ?? "default",
2534
+ skipTelemetry: !span.isRecording(),
2535
+ logLevel: logger.loggerLevel
2536
+ },
2537
+ opts.embedded
2538
+ );
2486
2539
  if (!whoAmIResult.success) {
2487
2540
  throw new Error(whoAmIResult.error);
2488
2541
  } else {
@@ -2565,8 +2618,18 @@ ${chalkLink(authorizationCodeResult.url)}`
2565
2618
  }
2566
2619
  );
2567
2620
  getPersonalAccessTokenSpinner.stop(`Logged in with token ${indexResult.obfuscatedToken}`);
2568
- writeAuthConfigProfile({ accessToken: indexResult.token, apiUrl: opts.defaultApiUrl }, options?.profile);
2569
- const whoAmIResult = await whoAmI({ profile: options?.profile ?? "default", skipTelemetry: !span.isRecording(), logLevel: logger.loggerLevel }, opts.embedded);
2621
+ writeAuthConfigProfile(
2622
+ { accessToken: indexResult.token, apiUrl: opts.defaultApiUrl },
2623
+ options?.profile
2624
+ );
2625
+ const whoAmIResult = await whoAmI(
2626
+ {
2627
+ profile: options?.profile ?? "default",
2628
+ skipTelemetry: !span.isRecording(),
2629
+ logLevel: logger.loggerLevel
2630
+ },
2631
+ opts.embedded
2632
+ );
2570
2633
  if (!whoAmIResult.success) {
2571
2634
  throw new Error(whoAmIResult.error);
2572
2635
  }
@@ -2663,10 +2726,45 @@ ${authorizationCodeResult.error}`
2663
2726
  });
2664
2727
  }
2665
2728
 
2729
+ // src/commands/deploy.ts
2730
+ import { Glob } from "glob";
2731
+
2666
2732
  // src/utilities/build.ts
2733
+ import { readFileSync } from "node:fs";
2667
2734
  import { extname, isAbsolute } from "node:path";
2668
2735
  import tsConfigPaths from "tsconfig-paths";
2669
- import { readFileSync } from "node:fs";
2736
+ function bundleTriggerDevCore(buildIdentifier, tsconfigPath) {
2737
+ return {
2738
+ name: "trigger-bundle-core",
2739
+ setup(build3) {
2740
+ build3.onResolve({ filter: /.*/ }, (args) => {
2741
+ if (args.path !== "@trigger.dev/core/v3") {
2742
+ return void 0;
2743
+ }
2744
+ const triggerSdkPath = __require.resolve("@trigger.dev/sdk/v3", { paths: [process.cwd()] });
2745
+ logger.debug(`[${buildIdentifier}][trigger-bundle-core] Resolved @trigger.dev/sdk/v3`, {
2746
+ ...args,
2747
+ triggerSdkPath
2748
+ });
2749
+ const resolvedPath = __require.resolve("@trigger.dev/core/v3", {
2750
+ paths: [triggerSdkPath]
2751
+ });
2752
+ logger.debug(
2753
+ `[${buildIdentifier}][trigger-bundle-core] Externalizing @trigger.dev/core/v3`,
2754
+ {
2755
+ ...args,
2756
+ triggerSdkPath,
2757
+ resolvedPath
2758
+ }
2759
+ );
2760
+ return {
2761
+ path: resolvedPath,
2762
+ external: false
2763
+ };
2764
+ });
2765
+ }
2766
+ };
2767
+ }
2670
2768
  function workerSetupImportConfigPlugin(configPath) {
2671
2769
  return {
2672
2770
  name: "trigger-worker-setup",
@@ -2693,8 +2791,8 @@ function workerSetupImportConfigPlugin(configPath) {
2693
2791
  }
2694
2792
  };
2695
2793
  }
2696
- function bundleDependenciesPlugin(config) {
2697
- const matchPath = config.tsconfigPath ? createMatchPath(config.tsconfigPath) : void 0;
2794
+ function bundleDependenciesPlugin(buildIdentifier, dependenciesToBundle, tsconfigPath) {
2795
+ const matchPath = tsconfigPath ? createMatchPath(tsconfigPath) : void 0;
2698
2796
  function resolvePath(id) {
2699
2797
  if (!matchPath) {
2700
2798
  return id;
@@ -2706,20 +2804,7 @@ function bundleDependenciesPlugin(config) {
2706
2804
  setup(build3) {
2707
2805
  build3.onResolve({ filter: /.*/ }, (args) => {
2708
2806
  const resolvedPath = resolvePath(args.path);
2709
- logger.ignore(`Checking if ${args.path} should be bundled or external`, {
2710
- ...args,
2711
- resolvedPath
2712
- });
2713
2807
  if (!isBareModuleId(resolvedPath)) {
2714
- logger.ignore(`Bundling ${args.path} because its not a bareModuleId`, {
2715
- ...args
2716
- });
2717
- return void 0;
2718
- }
2719
- if (args.path.startsWith("@trigger.dev/")) {
2720
- logger.ignore(`Bundling ${args.path} because its a trigger.dev package`, {
2721
- ...args
2722
- });
2723
2808
  return void 0;
2724
2809
  }
2725
2810
  let loader;
@@ -2733,12 +2818,12 @@ function bundleDependenciesPlugin(config) {
2733
2818
  if (loader === "file") {
2734
2819
  return void 0;
2735
2820
  }
2736
- for (let pattern of config.dependenciesToBundle ?? []) {
2821
+ for (let pattern of dependenciesToBundle ?? []) {
2737
2822
  if (typeof pattern === "string" ? args.path === pattern : pattern.test(args.path)) {
2738
2823
  return void 0;
2739
2824
  }
2740
2825
  }
2741
- logger.ignore(`Externalizing ${args.path}`, {
2826
+ logger.ignore(`[${buildIdentifier}] Externalizing ${args.path}`, {
2742
2827
  ...args
2743
2828
  });
2744
2829
  return {
@@ -2826,8 +2911,151 @@ function getLoaderForFile(file) {
2826
2911
  throw new Error(`Cannot get loader for file ${file}`);
2827
2912
  }
2828
2913
 
2914
+ // src/utilities/deployErrors.ts
2915
+ import chalk4 from "chalk";
2916
+ import { relative as relative2 } from "node:path";
2917
+ import { groupTaskMetadataIssuesByTask } from "@trigger.dev/core/v3";
2918
+ function errorIsErrorLike(error) {
2919
+ return error instanceof Error || typeof error === "object" && error !== null && "message" in error;
2920
+ }
2921
+ function parseBuildErrorStack(error) {
2922
+ if (typeof error === "string") {
2923
+ return error;
2924
+ }
2925
+ if (errorIsErrorLike(error)) {
2926
+ if (typeof error.stack === "string") {
2927
+ const isErrRequireEsm = error.stack.includes("ERR_REQUIRE_ESM");
2928
+ let moduleName = null;
2929
+ if (isErrRequireEsm) {
2930
+ const moduleRegex = /node_modules\/(@[^\/]+\/[^\/]+|[^\/]+)\/[^\/]+\s/;
2931
+ const match = moduleRegex.exec(error.stack);
2932
+ if (match) {
2933
+ moduleName = match[1];
2934
+ return {
2935
+ type: "esm-require-error",
2936
+ moduleName
2937
+ };
2938
+ }
2939
+ }
2940
+ } else {
2941
+ return error.message;
2942
+ }
2943
+ }
2944
+ return "Unknown error";
2945
+ }
2946
+ function logESMRequireError(parsedError, resolvedConfig) {
2947
+ logger.log(
2948
+ `
2949
+ ${chalkError("X Error:")} The ${chalkPurple(
2950
+ parsedError.moduleName
2951
+ )} module is being required even though it's ESM only, and builds only support CommonJS. There are two ${chalk4.underline(
2952
+ "possible"
2953
+ )} ways to fix this:`
2954
+ );
2955
+ logger.log(
2956
+ `
2957
+ ${chalkGrey("\u25CB")} Dynamically import the module in your code: ${chalkGrey(
2958
+ `const myModule = await import("${parsedError.moduleName}");`
2959
+ )}`
2960
+ );
2961
+ if (resolvedConfig.status === "file") {
2962
+ const relativePath = relative2(resolvedConfig.config.projectDir, resolvedConfig.path).replace(
2963
+ /\\/g,
2964
+ "/"
2965
+ );
2966
+ logger.log(
2967
+ `${chalkGrey("\u25CB")} ${chalk4.underline("Or")} add ${chalkPurple(
2968
+ parsedError.moduleName
2969
+ )} to the ${chalkGreen("dependenciesToBundle")} array in your config file ${chalkGrey(
2970
+ `(${relativePath})`
2971
+ )}. This will bundle the module with your code.
2972
+ `
2973
+ );
2974
+ } else {
2975
+ logger.log(
2976
+ `${chalkGrey("\u25CB")} ${chalk4.underline("Or")} add ${chalkPurple(
2977
+ parsedError.moduleName
2978
+ )} to the ${chalkGreen("dependenciesToBundle")} array in your config file ${chalkGrey(
2979
+ "(you'll need to create one)"
2980
+ )}. This will bundle the module with your code.
2981
+ `
2982
+ );
2983
+ }
2984
+ }
2985
+ function parseNpmInstallError(error) {
2986
+ if (typeof error === "string") {
2987
+ return error;
2988
+ }
2989
+ if (error instanceof Error) {
2990
+ if (typeof error.stack === "string") {
2991
+ const isPackageNotFoundError = error.stack.includes("ERR! 404 Not Found") && error.stack.includes("is not in this registry");
2992
+ let packageName = null;
2993
+ if (isPackageNotFoundError) {
2994
+ const packageNameRegex = /'([^']+)' is not in this registry/;
2995
+ const match = packageNameRegex.exec(error.stack);
2996
+ if (match) {
2997
+ packageName = match[1];
2998
+ }
2999
+ }
3000
+ if (packageName) {
3001
+ return {
3002
+ type: "package-not-found-error",
3003
+ packageName
3004
+ };
3005
+ }
3006
+ const noMatchingVersionRegex = /No matching version found for ([^\s]+)\s/;
3007
+ const noMatchingVersionMatch = noMatchingVersionRegex.exec(error.stack);
3008
+ if (noMatchingVersionMatch) {
3009
+ return {
3010
+ type: "no-matching-version-error",
3011
+ packageName: noMatchingVersionMatch[1].replace(/.$/, "")
3012
+ };
3013
+ }
3014
+ return error.message;
3015
+ } else {
3016
+ return error.message;
3017
+ }
3018
+ }
3019
+ return "Unknown error";
3020
+ }
3021
+ function logTaskMetadataParseError(zodIssues, tasks) {
3022
+ logger.log(
3023
+ `
3024
+ ${chalkError("X Error:")} Failed to start. The following ${zodIssues.length === 1 ? "task issue was" : "task issues were"} found:`
3025
+ );
3026
+ const groupedIssues = groupTaskMetadataIssuesByTask(tasks, zodIssues);
3027
+ for (const key in groupedIssues) {
3028
+ const taskWithIssues = groupedIssues[key];
3029
+ if (!taskWithIssues) {
3030
+ continue;
3031
+ }
3032
+ logger.log(
3033
+ `
3034
+ ${chalkWarning("\u276F")} ${taskWithIssues.exportName} ${chalkGrey("in")} ${taskWithIssues.filePath}`
3035
+ );
3036
+ for (const issue of taskWithIssues.issues) {
3037
+ if (issue.path) {
3038
+ logger.log(` ${chalkError("x")} ${issue.path} ${chalkGrey(issue.message)}`);
3039
+ } else {
3040
+ logger.log(` ${chalkError("x")} ${chalkGrey(issue.message)}`);
3041
+ }
3042
+ }
3043
+ }
3044
+ }
3045
+
3046
+ // src/utilities/safeJsonParse.ts
3047
+ function safeJsonParse(json) {
3048
+ if (!json) {
3049
+ return void 0;
3050
+ }
3051
+ try {
3052
+ return JSON.parse(json);
3053
+ } catch {
3054
+ return void 0;
3055
+ }
3056
+ }
3057
+
2829
3058
  // src/commands/deploy.ts
2830
- import { Glob } from "glob";
2831
3059
  var DeployCommandOptions = CommonCommandOptions.extend({
2832
3060
  skipTypecheck: z4.boolean().default(false),
2833
3061
  skipDeploy: z4.boolean().default(false),
@@ -3001,26 +3229,38 @@ async function _deployCommand(dir, options) {
3001
3229
  "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."
3002
3230
  );
3003
3231
  }
3004
- return buildAndPushImage({
3005
- registryHost,
3006
- auth: authorization.auth.accessToken,
3007
- imageTag: deploymentResponse.data.imageTag,
3008
- buildId: deploymentResponse.data.externalBuildData.buildId,
3009
- buildToken: deploymentResponse.data.externalBuildData.buildToken,
3010
- buildProjectId: deploymentResponse.data.externalBuildData.projectId,
3011
- cwd: compilation.path,
3012
- projectId: resolvedConfig.config.project,
3013
- deploymentId: deploymentResponse.data.id,
3014
- deploymentVersion: deploymentResponse.data.version,
3015
- contentHash: deploymentResponse.data.contentHash,
3016
- projectRef: resolvedConfig.config.project,
3017
- loadImage: options.loadImage,
3018
- buildPlatform: options.buildPlatform
3019
- });
3232
+ return buildAndPushImage(
3233
+ {
3234
+ registryHost,
3235
+ auth: authorization.auth.accessToken,
3236
+ imageTag: deploymentResponse.data.imageTag,
3237
+ buildId: deploymentResponse.data.externalBuildData.buildId,
3238
+ buildToken: deploymentResponse.data.externalBuildData.buildToken,
3239
+ buildProjectId: deploymentResponse.data.externalBuildData.projectId,
3240
+ cwd: compilation.path,
3241
+ projectId: resolvedConfig.config.project,
3242
+ deploymentId: deploymentResponse.data.id,
3243
+ deploymentVersion: deploymentResponse.data.version,
3244
+ contentHash: deploymentResponse.data.contentHash,
3245
+ projectRef: resolvedConfig.config.project,
3246
+ loadImage: options.loadImage,
3247
+ buildPlatform: options.buildPlatform
3248
+ },
3249
+ deploymentSpinner
3250
+ );
3020
3251
  };
3021
3252
  const image = await buildImage();
3022
3253
  if (!image.ok) {
3023
- deploymentSpinner.stop(`Failed to build project image: ${image.error}`);
3254
+ deploymentSpinner.stop(`Failed to build project.`);
3255
+ if (image.logs.trim() !== "") {
3256
+ const logPath = join4(await createTempDir(), `build-${deploymentResponse.data.shortCode}.log`);
3257
+ await writeFile2(logPath, image.logs);
3258
+ logger.log(
3259
+ `${chalkError("X Error:")} ${image.error}. Full build logs have been saved to ${logPath})`
3260
+ );
3261
+ } else {
3262
+ logger.log(`${chalkError("X Error:")} ${image.error}.`);
3263
+ }
3024
3264
  throw new SkipLoggingError(`Failed to build project image: ${image.error}`);
3025
3265
  }
3026
3266
  const imageReference = options.selfHosted ? `${selfHostedRegistryHost ? `${selfHostedRegistryHost}/` : ""}${image.image}${image.digest ? `@${image.digest}` : ""}` : `${registryHost}/${image.image}${image.digest ? `@${image.digest}` : ""}`;
@@ -3080,10 +3320,27 @@ async function _deployCommand(dir, options) {
3080
3320
  }
3081
3321
  case "FAILED": {
3082
3322
  if (finishedDeployment.errorData) {
3083
- deploymentSpinner.stop(
3084
- `Deployment encountered an error: ${finishedDeployment.errorData.name}. ${deploymentLink}`
3085
- );
3086
- logger.error(finishedDeployment.errorData.stack);
3323
+ if (finishedDeployment.errorData.name === "TaskMetadataParseError") {
3324
+ const errorJson = safeJsonParse(finishedDeployment.errorData.stack);
3325
+ if (errorJson) {
3326
+ const parsedError2 = TaskMetadataFailedToParseData.safeParse(errorJson);
3327
+ if (parsedError2.success) {
3328
+ deploymentSpinner.stop(`Deployment encountered an error. ${deploymentLink}`);
3329
+ logTaskMetadataParseError(parsedError2.data.zodIssues, parsedError2.data.tasks);
3330
+ throw new SkipLoggingError(
3331
+ `Deployment encountered an error: ${finishedDeployment.errorData.name}`
3332
+ );
3333
+ }
3334
+ }
3335
+ }
3336
+ const parsedError = finishedDeployment.errorData.stack ? parseBuildErrorStack(finishedDeployment.errorData) : finishedDeployment.errorData.message;
3337
+ if (typeof parsedError === "string") {
3338
+ deploymentSpinner.stop(`Deployment encountered an error. ${deploymentLink}`);
3339
+ logger.log(`${chalkError("X Error:")} ${parsedError}`);
3340
+ } else {
3341
+ deploymentSpinner.stop(`Deployment encountered an error. ${deploymentLink}`);
3342
+ logESMRequireError(parsedError, resolvedConfig);
3343
+ }
3087
3344
  throw new SkipLoggingError(
3088
3345
  `Deployment encountered an error: ${finishedDeployment.errorData.name}`
3089
3346
  );
@@ -3121,7 +3378,7 @@ async function checkEnvVars(envVars, config, options, environmentClient, apiUrl)
3121
3378
  environmentVariablesSpinner.stop(
3122
3379
  `Found missing env vars in ${options.env}: ${arrayToSentence(
3123
3380
  missingEnvironmentVariables
3124
- )}. ${options.ignoreEnvVarCheck ? "Continuing deployment because of --ignore-env-var-check. " : "Aborting deployment. "}${chalk4.bgBlueBright(
3381
+ )}. ${options.ignoreEnvVarCheck ? "Continuing deployment because of --ignore-env-var-check. " : "Aborting deployment. "}${chalk5.bgBlueBright(
3125
3382
  terminalLink(
3126
3383
  "Manage env vars",
3127
3384
  `${apiUrl}/projects/v3/${config.project}/environment-variables`
@@ -3182,7 +3439,7 @@ async function waitForDeploymentToFinish(deploymentId, client, timeoutInSeconds
3182
3439
  }
3183
3440
  });
3184
3441
  }
3185
- async function buildAndPushImage(options) {
3442
+ async function buildAndPushImage(options, updater) {
3186
3443
  return tracer.startActiveSpan("buildAndPushImage", async (span) => {
3187
3444
  span.setAttributes({
3188
3445
  "options.registryHost": options.registryHost,
@@ -3238,15 +3495,23 @@ async function buildAndPushImage(options) {
3238
3495
  });
3239
3496
  const errors = [];
3240
3497
  try {
3241
- await new Promise((res, rej) => {
3498
+ const processCode = await new Promise((res, rej) => {
3242
3499
  childProcess2.stderr?.on("data", (data) => {
3243
- const text2 = data.toString();
3244
- errors.push(text2);
3245
- logger.debug(text2);
3500
+ const text3 = data.toString();
3501
+ errors.push(text3);
3502
+ logger.debug(text3);
3246
3503
  });
3247
3504
  childProcess2.on("error", (e) => rej(e));
3248
- childProcess2.on("close", () => res());
3505
+ childProcess2.on("close", (code) => res(code));
3249
3506
  });
3507
+ const logs = extractLogs(errors);
3508
+ if (processCode !== 0) {
3509
+ return {
3510
+ ok: false,
3511
+ error: `Error building image`,
3512
+ logs
3513
+ };
3514
+ }
3250
3515
  const digest = extractImageDigest(errors);
3251
3516
  span.setAttributes({
3252
3517
  "image.digest": digest
@@ -3255,6 +3520,7 @@ async function buildAndPushImage(options) {
3255
3520
  return {
3256
3521
  ok: true,
3257
3522
  image: options.imageTag,
3523
+ logs,
3258
3524
  digest
3259
3525
  };
3260
3526
  } catch (e) {
@@ -3262,7 +3528,8 @@ async function buildAndPushImage(options) {
3262
3528
  span.end();
3263
3529
  return {
3264
3530
  ok: false,
3265
- error: e instanceof Error ? e.message : JSON.stringify(e)
3531
+ error: e instanceof Error ? e.message : JSON.stringify(e),
3532
+ logs: extractLogs(errors)
3266
3533
  };
3267
3534
  }
3268
3535
  });
@@ -3310,9 +3577,9 @@ async function buildAndPushSelfHostedImage(options) {
3310
3577
  try {
3311
3578
  await new Promise((res, rej) => {
3312
3579
  buildProcess.stderr?.on("data", (data) => {
3313
- const text2 = data.toString();
3314
- errors.push(text2);
3315
- logger.debug(text2);
3580
+ const text3 = data.toString();
3581
+ errors.push(text3);
3582
+ logger.debug(text3);
3316
3583
  });
3317
3584
  buildProcess.on("error", (e) => rej(e));
3318
3585
  buildProcess.on("close", () => res());
@@ -3326,7 +3593,8 @@ async function buildAndPushSelfHostedImage(options) {
3326
3593
  span.end();
3327
3594
  return {
3328
3595
  ok: false,
3329
- error: e instanceof Error ? e.message : JSON.stringify(e)
3596
+ error: e instanceof Error ? e.message : JSON.stringify(e),
3597
+ logs: extractLogs(errors)
3330
3598
  };
3331
3599
  }
3332
3600
  const pushArgs = ["push", imageRef].filter(Boolean);
@@ -3339,12 +3607,12 @@ async function buildAndPushSelfHostedImage(options) {
3339
3607
  try {
3340
3608
  await new Promise((res, rej) => {
3341
3609
  pushProcess.stdout?.on("data", (data) => {
3342
- const text2 = data.toString();
3343
- logger.debug(text2);
3610
+ const text3 = data.toString();
3611
+ logger.debug(text3);
3344
3612
  });
3345
3613
  pushProcess.stderr?.on("data", (data) => {
3346
- const text2 = data.toString();
3347
- logger.debug(text2);
3614
+ const text3 = data.toString();
3615
+ logger.debug(text3);
3348
3616
  });
3349
3617
  pushProcess.on("error", (e) => rej(e));
3350
3618
  pushProcess.on("close", () => res());
@@ -3355,7 +3623,8 @@ async function buildAndPushSelfHostedImage(options) {
3355
3623
  span.end();
3356
3624
  return {
3357
3625
  ok: false,
3358
- error: e instanceof Error ? e.message : JSON.stringify(e)
3626
+ error: e instanceof Error ? e.message : JSON.stringify(e),
3627
+ logs: extractLogs(errors)
3359
3628
  };
3360
3629
  }
3361
3630
  }
@@ -3363,7 +3632,8 @@ async function buildAndPushSelfHostedImage(options) {
3363
3632
  return {
3364
3633
  ok: true,
3365
3634
  image: options.imageTag,
3366
- digest
3635
+ digest,
3636
+ logs: extractLogs(errors)
3367
3637
  };
3368
3638
  });
3369
3639
  }
@@ -3378,6 +3648,10 @@ function extractImageDigest(outputs) {
3378
3648
  }
3379
3649
  }
3380
3650
  }
3651
+ function extractLogs(outputs) {
3652
+ const cleanedOutputs = outputs.map((line) => line.trim()).filter((line) => line !== "");
3653
+ return cleanedOutputs.map((line) => line.trim()).join("\n");
3654
+ }
3381
3655
  async function compileProject(config, options, configPath) {
3382
3656
  return await tracer.startActiveSpan("compileProject", async (span) => {
3383
3657
  try {
@@ -3435,7 +3709,14 @@ async function compileProject(config, options, configPath) {
3435
3709
  TRIGGER_API_URL: `"${config.triggerUrl}"`,
3436
3710
  __PROJECT_CONFIG__: JSON.stringify(config)
3437
3711
  },
3438
- plugins: [bundleDependenciesPlugin(config), workerSetupImportConfigPlugin(configPath)]
3712
+ plugins: [
3713
+ bundleDependenciesPlugin(
3714
+ "workerFacade",
3715
+ config.dependenciesToBundle,
3716
+ config.tsconfigPath
3717
+ ),
3718
+ workerSetupImportConfigPlugin(configPath)
3719
+ ]
3439
3720
  });
3440
3721
  if (result.errors.length > 0) {
3441
3722
  compileSpinner.stop("Build failed, aborting deployment");
@@ -3467,17 +3748,23 @@ async function compileProject(config, options, configPath) {
3467
3748
  write: false,
3468
3749
  minify: false,
3469
3750
  sourcemap: false,
3470
- packages: "external",
3471
- // https://esbuild.github.io/api/#packages
3472
3751
  logLevel: "error",
3473
3752
  platform: "node",
3753
+ packages: "external",
3474
3754
  format: "cjs",
3475
3755
  // This is needed to support opentelemetry instrumentation that uses module patching
3476
3756
  target: ["node18", "es2020"],
3477
3757
  outdir: "out",
3478
3758
  define: {
3479
3759
  __PROJECT_CONFIG__: JSON.stringify(config)
3480
- }
3760
+ },
3761
+ plugins: [
3762
+ bundleDependenciesPlugin(
3763
+ "entryPoint.ts",
3764
+ config.dependenciesToBundle,
3765
+ config.tsconfigPath
3766
+ )
3767
+ ]
3481
3768
  });
3482
3769
  if (entryPointResult.errors.length > 0) {
3483
3770
  compileSpinner.stop("Build failed, aborting deployment");
@@ -3519,6 +3806,10 @@ async function compileProject(config, options, configPath) {
3519
3806
  );
3520
3807
  await writeFile2(join4(tempDir, "worker.js.map"), workerSourcemapFile.text);
3521
3808
  await writeFile2(join4(tempDir, "index.js"), entryPointOutputFile.text);
3809
+ logger.debug("Getting the imports for the worker and entryPoint builds", {
3810
+ workerImports: metaOutput.imports,
3811
+ entryPointImports: entryPointMetaOutput.imports
3812
+ });
3522
3813
  const allImports = [...metaOutput.imports, ...entryPointMetaOutput.imports];
3523
3814
  const externalPackageJson = await readJSONFile(join4(config.projectDir, "package.json"));
3524
3815
  const dependencies2 = await gatherRequiredDependencies(
@@ -3545,7 +3836,7 @@ async function compileProject(config, options, configPath) {
3545
3836
  options
3546
3837
  );
3547
3838
  if (!resolvingDependenciesResult) {
3548
- throw new Error("Failed to resolve dependencies");
3839
+ throw new SkipLoggingError("Failed to resolve dependencies");
3549
3840
  }
3550
3841
  const containerFilePath = new URL(
3551
3842
  importResolve("./Containerfile.prod", import.meta.url)
@@ -3624,12 +3915,35 @@ async function resolveDependencies(projectDir, packageJsonContents, config, opti
3624
3915
  resolvingDepsSpinner.stop("Dependencies resolved");
3625
3916
  return true;
3626
3917
  } catch (installError) {
3627
- logger.debug(`Failed to resolve dependencies: ${JSON.stringify(installError)}`);
3628
3918
  recordSpanException4(span, installError);
3629
3919
  span.end();
3630
- resolvingDepsSpinner.stop(
3631
- "Failed to resolve dependencies. Rerun with --log-level=debug for more information"
3632
- );
3920
+ const parsedError = parseNpmInstallError(installError);
3921
+ if (typeof parsedError === "string") {
3922
+ resolvingDepsSpinner.stop(`Failed to resolve dependencies: ${parsedError}`);
3923
+ } else {
3924
+ switch (parsedError.type) {
3925
+ case "package-not-found-error": {
3926
+ resolvingDepsSpinner.stop(`Failed to resolve dependencies`);
3927
+ logger.log(
3928
+ `
3929
+ ${chalkError("X Error:")} The package ${chalkPurple(
3930
+ parsedError.packageName
3931
+ )} could not be found in the npm registry.`
3932
+ );
3933
+ break;
3934
+ }
3935
+ case "no-matching-version-error": {
3936
+ resolvingDepsSpinner.stop(`Failed to resolve dependencies`);
3937
+ logger.log(
3938
+ `
3939
+ ${chalkError("X Error:")} The package ${chalkPurple(
3940
+ parsedError.packageName
3941
+ )} could not resolve because the version doesn't exist`
3942
+ );
3943
+ break;
3944
+ }
3945
+ }
3946
+ }
3633
3947
  return false;
3634
3948
  }
3635
3949
  }
@@ -3676,7 +3990,7 @@ async function typecheckProject(config, options) {
3676
3990
  async function gatherRequiredDependencies(imports, config, projectPackageJson) {
3677
3991
  const dependencies2 = {};
3678
3992
  for (const file of imports) {
3679
- if (file.kind !== "require-call" || !file.external) {
3993
+ if (file.kind !== "require-call" && file.kind !== "dynamic-import" || !file.external) {
3680
3994
  continue;
3681
3995
  }
3682
3996
  const packageName = detectPackageNameFromImportPath(file.path);
@@ -3711,8 +4025,10 @@ async function gatherRequiredDependencies(imports, config, projectPackageJson) {
3711
4025
  dependencies2[packageParts.name] = externalDependencyVersion;
3712
4026
  continue;
3713
4027
  } else {
3714
- logger.warn(
3715
- `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`
4028
+ logger.log(
4029
+ `${chalkWarning("X Warning:")} Could not find version for package ${chalkPurple(
4030
+ packageName
4031
+ )}, add a version specifier to the package name (e.g. ${packageParts.name}@latest) or add it to your project's package.json`
3716
4032
  );
3717
4033
  }
3718
4034
  }
@@ -3746,7 +4062,7 @@ async function copyAdditionalFiles(config, tempDir) {
3746
4062
  for await (const file of glob) {
3747
4063
  const relativeDestinationPath = join4(
3748
4064
  tempDir,
3749
- relative2(config.projectDir, file.fullpath())
4065
+ relative3(config.projectDir, file.fullpath())
3750
4066
  );
3751
4067
  logger.debug(`Copying file ${file.fullpath()} to ${relativeDestinationPath}`);
3752
4068
  await mkdir(dirname(relativeDestinationPath), { recursive: true });
@@ -3778,7 +4094,7 @@ async function findAllEnvironmentVariableReferencesInFile(filePath) {
3778
4094
  const fileContents = await readFile2(filePath, "utf-8");
3779
4095
  return findAllEnvironmentVariableReferences(fileContents);
3780
4096
  }
3781
- var IGNORED_ENV_VARS = ["NODE_ENV", "SHELL", "HOME", "PWD", "LOGNAME", "USER", "PATH"];
4097
+ var IGNORED_ENV_VARS = ["NODE_ENV", "SHELL", "HOME", "PWD", "LOGNAME", "USER", "PATH", "DEBUG"];
3782
4098
  function findAllEnvironmentVariableReferences(code) {
3783
4099
  const regex = /\bprocess\.env\.([a-zA-Z_][a-zA-Z0-9_]*)\b/g;
3784
4100
  const matches = code.matchAll(regex);
@@ -3804,7 +4120,6 @@ import {
3804
4120
  detectDependencyVersion as detectDependencyVersion2,
3805
4121
  serverWebsocketMessages
3806
4122
  } from "@trigger.dev/core/v3";
3807
- import chalk6 from "chalk";
3808
4123
  import { watch } from "chokidar";
3809
4124
  import { context as context2 } from "esbuild";
3810
4125
  import { resolve as importResolve2 } from "import-meta-resolve";
@@ -3812,7 +4127,7 @@ import { render, useInput } from "ink";
3812
4127
  import { createHash as createHash2 } from "node:crypto";
3813
4128
  import fs7, { readFileSync as readFileSync3 } from "node:fs";
3814
4129
  import { basename, dirname as dirname3, join as join5 } from "node:path";
3815
- import pThrottle from "p-throttle";
4130
+ import pDebounce from "p-debounce";
3816
4131
  import { WebSocket } from "partysocket";
3817
4132
  import React, { Suspense, useEffect } from "react";
3818
4133
  import { WebSocket as wsWebSocket } from "ws";
@@ -3827,6 +4142,14 @@ var UncaughtExceptionError = class extends Error {
3827
4142
  this.name = "UncaughtExceptionError";
3828
4143
  }
3829
4144
  };
4145
+ var TaskMetadataParseError = class extends Error {
4146
+ constructor(zodIssues, tasks) {
4147
+ super(`Failed to parse task metadata`);
4148
+ this.zodIssues = zodIssues;
4149
+ this.tasks = tasks;
4150
+ this.name = "TaskMetadataParseError";
4151
+ }
4152
+ };
3830
4153
 
3831
4154
  // src/workers/dev/backgroundWorker.ts
3832
4155
  import {
@@ -3836,9 +4159,9 @@ import {
3836
4159
  ZodMessageSender,
3837
4160
  childToWorkerMessages,
3838
4161
  correctErrorStackTrace,
4162
+ formatDurationMilliseconds,
3839
4163
  workerToChildMessages
3840
4164
  } from "@trigger.dev/core/v3";
3841
- import chalk5 from "chalk";
3842
4165
  import dotenv from "dotenv";
3843
4166
  import { Evt } from "evt";
3844
4167
  import { fork } from "node:child_process";
@@ -3897,7 +4220,7 @@ var BackgroundWorkerCoordinator = class {
3897
4220
  this._records.clear();
3898
4221
  }
3899
4222
  async handleMessage(id, message) {
3900
- logger.debug(`Received message from worker ${id}`, { workerMessage: message });
4223
+ logger.debug(`Received message from worker ${id}`, JSON.stringify({ workerMessage: message }));
3901
4224
  switch (message.type) {
3902
4225
  case "EXECUTE_RUNS": {
3903
4226
  await Promise.all(message.payloads.map((payload) => this.#executeTaskRun(id, payload)));
@@ -3926,23 +4249,32 @@ var BackgroundWorkerCoordinator = class {
3926
4249
  }
3927
4250
  const { execution } = payload;
3928
4251
  const logsUrl = `${this.baseURL}/runs/${execution.run.id}`;
3929
- const link = chalk5.bgBlueBright(terminalLink2("view logs", logsUrl));
3930
- let timestampPrefix = chalk5.gray((/* @__PURE__ */ new Date()).toISOString());
3931
- const workerPrefix = chalk5.green(`[worker:${record.version}]`);
3932
- const taskPrefix = chalk5.yellow(`[task:${execution.task.id}]`);
3933
- const runId = chalk5.blue(execution.run.id);
3934
- const attempt = chalk5.blue(`.${execution.attempt.number}`);
3935
- logger.log(`${timestampPrefix} ${workerPrefix}${taskPrefix} ${runId}${attempt} ${link}`);
4252
+ const pipe = chalkGrey("|");
4253
+ const bullet = chalkGrey("\u25CB");
4254
+ const link = chalkLink(terminalLink2("View logs", logsUrl));
4255
+ let timestampPrefix = chalkGrey(prettyPrintDate(payload.execution.attempt.startedAt));
4256
+ const workerPrefix = chalkWorker(record.version);
4257
+ const taskPrefix = chalkTask(execution.task.id);
4258
+ const runId = chalkRun(`${execution.run.id}.${execution.attempt.number}`);
4259
+ logger.log(
4260
+ `${bullet} ${timestampPrefix} ${chalkGrey(
4261
+ "->"
4262
+ )} ${link} ${pipe} ${workerPrefix} ${pipe} ${taskPrefix} ${pipe} ${runId}`
4263
+ );
3936
4264
  const now = performance.now();
3937
4265
  const completion = await worker.executeTaskRun(payload);
3938
4266
  const elapsed = performance.now() - now;
3939
- const retryingText = !completion.ok && completion.skippedRetrying ? " (retrying skipped)" : !completion.ok && completion.retry !== void 0 ? ` (retrying in ${completion.retry.delay}ms)` : "";
3940
- const resultText = !completion.ok ? completion.error.type === "INTERNAL_ERROR" && (completion.error.code === TaskRunErrorCodes.TASK_EXECUTION_ABORTED || completion.error.code === TaskRunErrorCodes.TASK_RUN_CANCELLED) ? chalk5.yellow("cancelled") : chalk5.red(`error${retryingText}`) : chalk5.green("success");
4267
+ const retryingText = chalkGrey(
4268
+ !completion.ok && completion.skippedRetrying ? " (retrying skipped)" : !completion.ok && completion.retry !== void 0 ? ` (retrying in ${completion.retry.delay}ms)` : ""
4269
+ );
4270
+ const resultText = !completion.ok ? completion.error.type === "INTERNAL_ERROR" && (completion.error.code === TaskRunErrorCodes.TASK_EXECUTION_ABORTED || completion.error.code === TaskRunErrorCodes.TASK_RUN_CANCELLED) ? chalkWarning("Cancelled") : `${chalkError("Error")}${retryingText}` : chalkSuccess("Success");
3941
4271
  const errorText = !completion.ok ? this.#formatErrorLog(completion.error) : "retry" in completion ? `retry in ${completion.retry}ms` : "";
3942
- const elapsedText = chalk5.dim(`(${elapsed.toFixed(2)}ms)`);
3943
- timestampPrefix = chalk5.gray((/* @__PURE__ */ new Date()).toISOString());
4272
+ const elapsedText = chalkGrey(`(${formatDurationMilliseconds(elapsed, { style: "short" })})`);
4273
+ timestampPrefix = chalkGrey(prettyPrintDate());
3944
4274
  logger.log(
3945
- `${timestampPrefix} ${workerPrefix}${taskPrefix} ${runId}${attempt} ${resultText} ${elapsedText} ${link}${errorText}`
4275
+ `${bullet} ${timestampPrefix} ${chalkGrey(
4276
+ "->"
4277
+ )} ${link} ${pipe} ${workerPrefix} ${pipe} ${taskPrefix} ${pipe} ${runId} ${pipe} ${resultText} ${elapsedText}${errorText}`
3946
4278
  );
3947
4279
  this.onTaskCompleted.post({ completion, execution, worker, backgroundWorkerId: id });
3948
4280
  }
@@ -3954,19 +4286,19 @@ var BackgroundWorkerCoordinator = class {
3954
4286
  case "STRING_ERROR": {
3955
4287
  return `
3956
4288
 
3957
- ${error.raw}
4289
+ ${chalkError("X Error:")} ${error.raw}
3958
4290
  `;
3959
4291
  }
3960
4292
  case "CUSTOM_ERROR": {
3961
4293
  return `
3962
4294
 
3963
- ${error.raw}
4295
+ ${chalkError("X Error:")} ${error.raw}
3964
4296
  `;
3965
4297
  }
3966
4298
  case "BUILT_IN_ERROR": {
3967
4299
  return `
3968
4300
 
3969
- ${error.stackTrace}
4301
+ ${error.stackTrace.replace(/^Error: /, chalkError("X Error: "))}
3970
4302
  `;
3971
4303
  }
3972
4304
  }
@@ -4063,6 +4395,11 @@ var BackgroundWorker = class {
4063
4395
  resolved = true;
4064
4396
  reject(new UncaughtExceptionError(message.payload.error, message.payload.origin));
4065
4397
  child.kill();
4398
+ } else if (message.type === "TASKS_FAILED_TO_PARSE") {
4399
+ clearTimeout(timeout);
4400
+ resolved = true;
4401
+ reject(new TaskMetadataParseError(message.payload.zodIssues, message.payload.tasks));
4402
+ child.kill();
4066
4403
  }
4067
4404
  });
4068
4405
  child.on("exit", (code) => {
@@ -4088,7 +4425,7 @@ var BackgroundWorker = class {
4088
4425
  }
4089
4426
  if (!this._taskRunProcesses.has(payload.execution.run.id)) {
4090
4427
  const taskRunProcess = new TaskRunProcess(
4091
- payload.execution.run.id,
4428
+ payload.execution,
4092
4429
  this.path,
4093
4430
  {
4094
4431
  ...this.params.env,
@@ -4198,8 +4535,8 @@ var BackgroundWorker = class {
4198
4535
  }
4199
4536
  };
4200
4537
  var TaskRunProcess = class {
4201
- constructor(runId, path6, env, metadata, worker) {
4202
- this.runId = runId;
4538
+ constructor(execution, path6, env, metadata, worker) {
4539
+ this.execution = execution;
4203
4540
  this.path = path6;
4204
4541
  this.env = env;
4205
4542
  this.metadata = metadata;
@@ -4230,8 +4567,17 @@ var TaskRunProcess = class {
4230
4567
  await this.cleanup(true);
4231
4568
  }
4232
4569
  async initialize() {
4233
- logger.debug(`[${this.runId}] initializing task run process`, {
4234
- env: this.env,
4570
+ const fullEnv = {
4571
+ ...this.execution.run.isTest ? { TRIGGER_LOG_LEVEL: "debug" } : {},
4572
+ ...this.env,
4573
+ OTEL_RESOURCE_ATTRIBUTES: JSON.stringify({
4574
+ [SemanticInternalAttributes.PROJECT_DIR]: this.worker.projectConfig.projectDir
4575
+ }),
4576
+ OTEL_EXPORTER_OTLP_COMPRESSION: "none",
4577
+ ...this.worker.debugOtel ? { OTEL_LOG_LEVEL: "debug" } : {}
4578
+ };
4579
+ logger.debug(`[${this.execution.run.id}] initializing task run process`, {
4580
+ env: fullEnv,
4235
4581
  path: this.path
4236
4582
  });
4237
4583
  this._child = fork(this.path, {
@@ -4245,14 +4591,7 @@ var TaskRunProcess = class {
4245
4591
  "ipc"
4246
4592
  ],
4247
4593
  cwd: dirname2(this.path),
4248
- env: {
4249
- ...this.env,
4250
- OTEL_RESOURCE_ATTRIBUTES: JSON.stringify({
4251
- [SemanticInternalAttributes.PROJECT_DIR]: this.worker.projectConfig.projectDir
4252
- }),
4253
- OTEL_EXPORTER_OTLP_COMPRESSION: "none",
4254
- ...this.worker.debugOtel ? { OTEL_LOG_LEVEL: "debug" } : {}
4255
- },
4594
+ env: fullEnv,
4256
4595
  execArgv: this.worker.debuggerOn ? ["--inspect-brk", "--trace-uncaught", "--no-warnings=ExperimentalWarning"] : ["--trace-uncaught", "--no-warnings=ExperimentalWarning"]
4257
4596
  });
4258
4597
  this._child.on("message", this.#handleMessage.bind(this));
@@ -4264,7 +4603,7 @@ var TaskRunProcess = class {
4264
4603
  if (kill && this._isBeingKilled) {
4265
4604
  return;
4266
4605
  }
4267
- logger.debug(`[${this.runId}] cleaning up task run process`, { kill });
4606
+ logger.debug(`[${this.execution.run.id}] cleaning up task run process`, { kill });
4268
4607
  await this._sender.send("CLEANUP", {
4269
4608
  flush: true,
4270
4609
  kill
@@ -4295,10 +4634,13 @@ var TaskRunProcess = class {
4295
4634
  if (!completion.ok && typeof completion.retry !== "undefined") {
4296
4635
  return;
4297
4636
  }
4298
- if (execution.run.id === this.runId) {
4637
+ if (execution.run.id === this.execution.run.id) {
4299
4638
  return;
4300
4639
  }
4301
- logger.debug(`[${this.runId}] task run completed notification`, { completion, execution });
4640
+ logger.debug(`[${this.execution.run.id}] task run completed notification`, {
4641
+ completion,
4642
+ execution
4643
+ });
4302
4644
  this._sender.send("TASK_RUN_COMPLETED_NOTIFICATION", {
4303
4645
  completion,
4304
4646
  execution
@@ -4336,7 +4678,7 @@ var TaskRunProcess = class {
4336
4678
  }
4337
4679
  }
4338
4680
  async #handleExit(code) {
4339
- logger.debug(`[${this.runId}] task run process exiting`, { code });
4681
+ logger.debug(`[${this.execution.run.id}] task run process exiting`, { code });
4340
4682
  for (const [id, status] of this._attemptStatuses.entries()) {
4341
4683
  if (status === "PENDING") {
4342
4684
  this._attemptStatuses.set(id, "REJECTED");
@@ -4383,6 +4725,25 @@ var TaskRunProcess = class {
4383
4725
  }
4384
4726
  };
4385
4727
 
4728
+ // src/utilities/runtimeCheck.ts
4729
+ function runtimeCheck(minimumMajor, minimumMinor) {
4730
+ if (typeof process === "undefined") {
4731
+ throw "The dev CLI can only be run in a Node.js compatible environment";
4732
+ }
4733
+ const [major = 0, minor = 0] = process.versions.node.split(".").map(Number);
4734
+ const isBun = typeof process.versions.bun === "string";
4735
+ if (major < minimumMajor || major === minimumMajor && minor < minimumMinor) {
4736
+ if (isBun) {
4737
+ 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}`;
4738
+ } else {
4739
+ throw `The dev CLI requires at least Node.js ${minimumMajor}.${minimumMinor}. You are running Node.js ${process.versions.node}`;
4740
+ }
4741
+ }
4742
+ logger.debug(
4743
+ `Node.js version: ${process.versions.node}${isBun ? ` (Bun ${process.versions.bun})` : ""}`
4744
+ );
4745
+ }
4746
+
4386
4747
  // src/commands/dev.tsx
4387
4748
  var apiClient;
4388
4749
  var DevCommandOptions = CommonCommandOptions.extend({
@@ -4393,7 +4754,7 @@ var DevCommandOptions = CommonCommandOptions.extend({
4393
4754
  });
4394
4755
  function configureDevCommand(program2) {
4395
4756
  return commonOptions(
4396
- program2.command("dev").description("Run your Trigger.dev tasks locally").argument("[path]", "The path to the project", ".").option("-c, --config <config file>", "The name of the config file, found at [path]").option(
4757
+ program2.command("dev").description("Run your Trigger.dev tasks locally").argument("[path]", "The path to the project", ".").option("-c, --config <config file>", "The name of the config file, found at [path].").option(
4397
4758
  "-p, --project-ref <project ref>",
4398
4759
  "The project ref. Required if there is no config file."
4399
4760
  ).option("--debugger", "Enable the debugger").option("--debug-otel", "Enable OpenTelemetry debugging")
@@ -4403,13 +4764,26 @@ function configureDevCommand(program2) {
4403
4764
  });
4404
4765
  });
4405
4766
  }
4767
+ var MINIMUM_NODE_MAJOR = 18;
4768
+ var MINIMUM_NODE_MINOR = 16;
4406
4769
  async function devCommand(dir, options) {
4770
+ try {
4771
+ runtimeCheck(MINIMUM_NODE_MAJOR, MINIMUM_NODE_MINOR);
4772
+ } catch (e) {
4773
+ logger.log(`${chalkError("X Error:")} ${e}`);
4774
+ process.exitCode = 1;
4775
+ return;
4776
+ }
4407
4777
  const authorization = await isLoggedIn(options.profile);
4408
4778
  if (!authorization.ok) {
4409
4779
  if (authorization.error === "fetch failed") {
4410
- logger.error("Fetch failed. Platform down?");
4780
+ logger.log(
4781
+ `${chalkError(
4782
+ "X Error:"
4783
+ )} Connecting to the server failed. Please check your internet connection or contact eric@trigger.dev for help.`
4784
+ );
4411
4785
  } else {
4412
- logger.error("You must login first. Use `trigger.dev login` to login.");
4786
+ logger.log(`${chalkError("X Error:")} You must login first. Use the \`login\` CLI command.`);
4413
4787
  }
4414
4788
  process.exitCode = 1;
4415
4789
  return;
@@ -4425,6 +4799,7 @@ async function startDev(dir, options, authorization) {
4425
4799
  logger.loggerLevel = options.logLevel;
4426
4800
  }
4427
4801
  await printStandloneInitialBanner(true);
4802
+ printDevBanner();
4428
4803
  logger.debug("Starting dev session", { dir, options, authorization });
4429
4804
  let config = await readConfig(dir, {
4430
4805
  projectRef: options.projectRef,
@@ -4611,7 +4986,7 @@ function useDev({
4611
4986
  );
4612
4987
  }
4613
4988
  let firstBuild = true;
4614
- logger.log(chalk6.dim("\u2394 Building background worker..."));
4989
+ logger.log(chalkGrey("\u25CB Building background worker\u2026"));
4615
4990
  ctx = await context2({
4616
4991
  stdin: {
4617
4992
  contents: entryPointContents,
@@ -4635,7 +5010,12 @@ function useDev({
4635
5010
  __PROJECT_CONFIG__: JSON.stringify(config)
4636
5011
  },
4637
5012
  plugins: [
4638
- bundleDependenciesPlugin(config),
5013
+ bundleTriggerDevCore("workerFacade", config.tsconfigPath),
5014
+ bundleDependenciesPlugin(
5015
+ "workerFacade",
5016
+ (config.dependenciesToBundle ?? []).concat([/^@trigger.dev/]),
5017
+ config.tsconfigPath
5018
+ ),
4639
5019
  workerSetupImportConfigPlugin(configPath),
4640
5020
  {
4641
5021
  name: "trigger.dev v3",
@@ -4648,7 +5028,7 @@ function useDev({
4648
5028
  return;
4649
5029
  }
4650
5030
  if (!firstBuild) {
4651
- logger.log(chalk6.dim("\u2394 Rebuilding background worker..."));
5031
+ logger.log(chalkGrey("\u25CB Building background worker\u2026"));
4652
5032
  }
4653
5033
  const metaOutputKey = join5("out", `stdin.js`);
4654
5034
  const metaOutput = result.metafile.outputs[metaOutputKey];
@@ -4670,8 +5050,7 @@ function useDev({
4670
5050
  md5Hasher.update(Buffer.from(outputFile.contents.buffer));
4671
5051
  const contentHash = md5Hasher.digest("hex");
4672
5052
  if (latestWorkerContentHash === contentHash) {
4673
- logger.log(chalk6.dim("\u2394 No changes detected, skipping build..."));
4674
- logger.debug(`No changes detected, skipping build`);
5053
+ logger.log(chalkGrey("\u25CB No changes detected, skipping build\u2026"));
4675
5054
  return;
4676
5055
  }
4677
5056
  const fullPath = join5(config.projectDir, ".trigger", `${contentHash}.js`);
@@ -4742,36 +5121,65 @@ function useDev({
4742
5121
  throw new Error(backgroundWorkerRecord.error);
4743
5122
  }
4744
5123
  backgroundWorker.metadata = backgroundWorkerRecord.data;
4745
- if (firstBuild) {
4746
- logger.log(
4747
- chalk6.green(
4748
- `Background worker started (${backgroundWorkerRecord.data.version})`
4749
- )
4750
- );
4751
- } else {
4752
- logger.log(
4753
- chalk6.dim(
4754
- `Background worker rebuilt (${backgroundWorkerRecord.data.version})`
4755
- )
4756
- );
4757
- }
5124
+ logger.log(
5125
+ `${chalkGrey(
5126
+ `\u25CB Background worker started -> ${chalkWorker(
5127
+ backgroundWorkerRecord.data.version
5128
+ )}`
5129
+ )}`
5130
+ );
4758
5131
  firstBuild = false;
4759
5132
  await backgroundWorkerCoordinator.registerWorker(
4760
5133
  backgroundWorkerRecord.data,
4761
5134
  backgroundWorker
4762
5135
  );
4763
5136
  } catch (e) {
4764
- if (e instanceof UncaughtExceptionError) {
5137
+ if (e instanceof TaskMetadataParseError) {
5138
+ logTaskMetadataParseError(e.zodIssues, e.tasks);
5139
+ return;
5140
+ } else if (e instanceof UncaughtExceptionError) {
5141
+ const parsedBuildError = parseBuildErrorStack(e.originalError);
5142
+ if (typeof parsedBuildError !== "string") {
5143
+ logESMRequireError(
5144
+ parsedBuildError,
5145
+ configPath ? { status: "file", path: configPath, config } : { status: "in-memory", config }
5146
+ );
5147
+ return;
5148
+ } else {
5149
+ }
4765
5150
  if (e.originalError.stack) {
4766
- logger.error("Background worker failed to start", e.originalError.stack);
5151
+ logger.log(
5152
+ `${chalkError("X Error:")} Worker failed to start`,
5153
+ e.originalError.stack
5154
+ );
4767
5155
  }
4768
5156
  return;
4769
5157
  }
4770
- if (e instanceof Error) {
4771
- logger.error(`Background worker failed to start`, e.stack);
4772
- return;
5158
+ const parsedError = parseNpmInstallError(e);
5159
+ if (typeof parsedError === "string") {
5160
+ logger.log(`${chalkError("X Error:")} ${parsedError}`);
5161
+ } else {
5162
+ switch (parsedError.type) {
5163
+ case "package-not-found-error": {
5164
+ logger.log(
5165
+ `
5166
+ ${chalkError("X Error:")} The package ${chalkPurple(
5167
+ parsedError.packageName
5168
+ )} could not be found in the npm registry.`
5169
+ );
5170
+ break;
5171
+ }
5172
+ case "no-matching-version-error": {
5173
+ logger.log(
5174
+ `
5175
+ ${chalkError("X Error:")} The package ${chalkPurple(
5176
+ parsedError.packageName
5177
+ )} could not resolve because the version doesn't exist`
5178
+ );
5179
+ break;
5180
+ }
5181
+ }
4773
5182
  }
4774
- logger.error(`Background worker failed to start: ${e}`);
4775
5183
  }
4776
5184
  });
4777
5185
  }
@@ -4780,19 +5188,14 @@ function useDev({
4780
5188
  });
4781
5189
  await ctx.watch();
4782
5190
  }
4783
- const throttle = pThrottle({
4784
- limit: 1,
4785
- interval: 1e3,
4786
- strict: true
4787
- });
4788
- const throttledRebuild = throttle(runBuild);
5191
+ const throttledRebuild = pDebounce(runBuild, 250, { before: true });
4789
5192
  const taskFileWatcher = watch(
4790
5193
  config.triggerDirectories.map((triggerDir) => `${triggerDir}/*.ts`),
4791
5194
  {
4792
5195
  ignoreInitial: true
4793
5196
  }
4794
5197
  );
4795
- taskFileWatcher.on("change", async (path6) => {
5198
+ taskFileWatcher.on("add", async (path6) => {
4796
5199
  throttledRebuild().catch((error) => {
4797
5200
  logger.error(error);
4798
5201
  });
@@ -4840,8 +5243,11 @@ function WebsocketFactory(apiKey) {
4840
5243
  }
4841
5244
  async function gatherRequiredDependencies2(outputMeta, config) {
4842
5245
  const dependencies2 = {};
5246
+ logger.debug("Gathering required dependencies from imports", {
5247
+ imports: outputMeta.imports
5248
+ });
4843
5249
  for (const file of outputMeta.imports) {
4844
- if (file.kind !== "require-call" || !file.external) {
5250
+ if (file.kind !== "require-call" && file.kind !== "dynamic-import" || !file.external) {
4845
5251
  continue;
4846
5252
  }
4847
5253
  const packageName = detectPackageNameFromImportPath(file.path);
@@ -4884,14 +5290,12 @@ async function gatherRequiredDependencies2(outputMeta, config) {
4884
5290
  function createDuplicateTaskIdOutputErrorMessage(duplicateTaskIds, taskResources) {
4885
5291
  const duplicateTable = duplicateTaskIds.map((id) => {
4886
5292
  const tasks = taskResources.filter((task) => task.id === id);
4887
- return `id "${chalkPurple(id)}" was found in:
4888
- ${tasks.map((task) => `${task.filePath} -> ${task.exportName}`).join("\n")}`;
4889
- }).join("\n\n");
4890
- return `Duplicate task ids detected:
5293
+ return `
4891
5294
 
4892
- ${duplicateTable}
4893
-
4894
- `;
5295
+ ${chalkTask(id)} was found in:${tasks.map((task) => `
5296
+ ${task.filePath} -> ${task.exportName}`).join("")}`;
5297
+ }).join("");
5298
+ return `Duplicate ${chalkTask("task id")} detected:${duplicateTable}`;
4895
5299
  }
4896
5300
  function gatherProcessEnv() {
4897
5301
  const env = {
@@ -4918,11 +5322,11 @@ import {
4918
5322
  flattenAttributes as flattenAttributes3,
4919
5323
  recordSpanException as recordSpanException5
4920
5324
  } from "@trigger.dev/core/v3";
4921
- import chalk7 from "chalk";
5325
+ import chalk6 from "chalk";
4922
5326
  import { execa as execa3 } from "execa";
4923
5327
  import { applyEdits, modify } from "jsonc-parser";
4924
5328
  import { writeFile as writeFile3 } from "node:fs/promises";
4925
- import { join as join6, relative as relative3, resolve as resolve3 } from "node:path";
5329
+ import { join as join6, relative as relative4, resolve as resolve3 } from "node:path";
4926
5330
  import terminalLink3 from "terminal-link";
4927
5331
  import { z as z6 } from "zod";
4928
5332
 
@@ -5016,7 +5420,7 @@ function resolveInternalFilePath(filePath) {
5016
5420
  var InitCommandOptions = CommonCommandOptions.extend({
5017
5421
  projectRef: z6.string().optional(),
5018
5422
  overrideConfig: z6.boolean().default(false),
5019
- tag: z6.string().default("latest"),
5423
+ tag: z6.string().default("beta"),
5020
5424
  skipPackageInstall: z6.boolean().default(false)
5021
5425
  });
5022
5426
  function configureInitCommand(program2) {
@@ -5027,7 +5431,7 @@ function configureInitCommand(program2) {
5027
5431
  ).option(
5028
5432
  "-t, --tag <package tag>",
5029
5433
  "The version of the @trigger.dev/sdk package to install",
5030
- "latest"
5434
+ "beta"
5031
5435
  ).option("--skip-package-install", "Skip installing the @trigger.dev/sdk package").option("--override-config", "Override the existing config file if it exists")
5032
5436
  ).action(async (path6, options) => {
5033
5437
  await handleTelemetry(async () => {
@@ -5101,7 +5505,7 @@ async function _initCommand(dir, options) {
5101
5505
  log3.success("Successfully initialized project for Trigger.dev v3 \u{1FAE1}");
5102
5506
  log3.info("Next steps:");
5103
5507
  log3.info(
5104
- ` 1. To start developing, run ${chalk7.green(
5508
+ ` 1. To start developing, run ${chalk6.green(
5105
5509
  `npx trigger.dev@${options.tag} dev`
5106
5510
  )} in your project directory`
5107
5511
  );
@@ -5116,7 +5520,7 @@ async function _initCommand(dir, options) {
5116
5520
  ` 4. Need help? Join our ${terminalLink3(
5117
5521
  "Discord community",
5118
5522
  "https://trigger.dev/discord"
5119
- )} or email us at ${chalk7.cyan("help@trigger.dev")}`
5523
+ )} or email us at ${chalk6.cyan("help@trigger.dev")}`
5120
5524
  );
5121
5525
  outro4(`Project initialized successfully. Happy coding!`);
5122
5526
  }
@@ -5170,7 +5574,7 @@ async function createTriggerDir(dir, options) {
5170
5574
  outputPath,
5171
5575
  replacements: {}
5172
5576
  });
5173
- const relativeOutputPath = relative3(process.cwd(), outputPath);
5577
+ const relativeOutputPath = relative4(process.cwd(), outputPath);
5174
5578
  log3.step(`Created example file at ${relativeOutputPath}`);
5175
5579
  span.end();
5176
5580
  return { location, isCustomValue: location !== defaultValue };
@@ -5324,7 +5728,7 @@ async function writeConfigFile(dir, project, options, triggerDir) {
5324
5728
  outputPath,
5325
5729
  override: options.overrideConfig
5326
5730
  });
5327
- const relativePathToOutput = relative3(process.cwd(), outputPath);
5731
+ const relativePathToOutput = relative4(process.cwd(), outputPath);
5328
5732
  spnnr.stop(
5329
5733
  result.success ? `Config file created at ${relativePathToOutput}` : `Failed to create config file: ${result.error}`
5330
5734
  );
@@ -5406,12 +5810,14 @@ async function selectProject(apiClient2, dashboardUrl, projectRef) {
5406
5810
  // src/commands/logout.ts
5407
5811
  var LogoutCommandOptions = CommonCommandOptions;
5408
5812
  function configureLogoutCommand(program2) {
5409
- return commonOptions(program2.command("logout").description("Logout of Trigger.dev")).action(async (options) => {
5410
- await handleTelemetry(async () => {
5411
- await printInitialBanner(false);
5412
- await logoutCommand(options);
5413
- });
5414
- });
5813
+ return commonOptions(program2.command("logout").description("Logout of Trigger.dev")).action(
5814
+ async (options) => {
5815
+ await handleTelemetry(async () => {
5816
+ await printInitialBanner(false);
5817
+ await logoutCommand(options);
5818
+ });
5819
+ }
5820
+ );
5415
5821
  }
5416
5822
  async function logoutCommand(options) {
5417
5823
  return await wrapCommandAction("logoutCommand", LogoutCommandOptions, options, async (opts) => {
@@ -5421,11 +5827,46 @@ async function logoutCommand(options) {
5421
5827
  async function logout(options) {
5422
5828
  const config = readAuthConfigProfile(options.profile);
5423
5829
  if (!config?.accessToken) {
5424
- logger.info(`You are already logged out [${options.profile ?? "default"}]`);
5830
+ logger.info(`You are already logged out [${options.profile}]`);
5831
+ return;
5832
+ }
5833
+ deleteAuthConfigProfile(options.profile);
5834
+ logger.info(`Logged out of Trigger.dev [${options.profile}]`);
5835
+ }
5836
+
5837
+ // src/commands/list-profiles.ts
5838
+ import { log as log4, outro as outro5 } from "@clack/prompts";
5839
+ var ListProfilesOptions = CommonCommandOptions;
5840
+ function configureListProfilesCommand(program2) {
5841
+ return program2.command("list-profiles").description("List all of your CLI profiles").option(
5842
+ "-l, --log-level <level>",
5843
+ "The CLI log level to use (debug, info, log, warn, error, none). This does not effect the log level of your trigger.dev tasks.",
5844
+ "log"
5845
+ ).option("--skip-telemetry", "Opt-out of sending telemetry").action(async (options) => {
5846
+ await handleTelemetry(async () => {
5847
+ await printInitialBanner(true);
5848
+ await listProfilesCommand(options);
5849
+ });
5850
+ });
5851
+ }
5852
+ async function listProfilesCommand(options) {
5853
+ return await wrapCommandAction("listProfiles", ListProfilesOptions, options, async (opts) => {
5854
+ return await listProfiles(opts);
5855
+ });
5856
+ }
5857
+ async function listProfiles(options) {
5858
+ const authConfig = readAuthConfigFile();
5859
+ if (!authConfig) {
5860
+ logger.info("No profiles found");
5425
5861
  return;
5426
5862
  }
5427
- writeAuthConfigProfile({ ...config, accessToken: void 0, apiUrl: void 0 }, options.profile);
5428
- logger.info(`Logged out of Trigger.dev [${options.profile ?? "default"}]`);
5863
+ const profiles = Object.keys(authConfig);
5864
+ log4.message("Profiles:");
5865
+ for (const profile of profiles) {
5866
+ const profileConfig = authConfig[profile];
5867
+ log4.info(`${profile}${profileConfig?.apiUrl ? ` - ${chalkGrey(profileConfig.apiUrl)}` : ""}`);
5868
+ }
5869
+ outro5("Retrieve account info by running whoami --profile <profile>");
5429
5870
  }
5430
5871
 
5431
5872
  // src/cli/index.ts
@@ -5437,6 +5878,7 @@ configureDevCommand(program);
5437
5878
  configureDeployCommand(program);
5438
5879
  configureWhoamiCommand(program);
5439
5880
  configureLogoutCommand(program);
5881
+ configureListProfilesCommand(program);
5440
5882
 
5441
5883
  // src/index.ts
5442
5884
  var main = async () => {