@todesktop/cli 1.21.0 → 1.23.0

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/cli.js CHANGED
@@ -1453,9 +1453,10 @@ var BuildProgress = ({
1453
1453
  };
1454
1454
  var BuildProgress_default = BuildProgress;
1455
1455
 
1456
- // src/components/ErrorDisplay.tsx
1457
- var import_ink9 = require("ink");
1458
- var import_react6 = require("react");
1456
+ // src/components/CancelBuild.tsx
1457
+ var import_ink10 = require("ink");
1458
+ var import_is_ci3 = __toESM(require("is-ci"));
1459
+ var import_react7 = require("react");
1459
1460
 
1460
1461
  // src/utilities/CliError.ts
1461
1462
  var CliError = class _CliError extends Error {
@@ -1473,8 +1474,26 @@ var CliError = class _CliError extends Error {
1473
1474
  }
1474
1475
  }
1475
1476
  };
1477
+ function toError(e, defaultMessage = "Unknown error") {
1478
+ if (e instanceof Error) {
1479
+ return e;
1480
+ }
1481
+ if (typeof e === "string") {
1482
+ return new Error(e);
1483
+ }
1484
+ if (e) {
1485
+ try {
1486
+ return new Error(JSON.stringify(e));
1487
+ } catch (serializeError) {
1488
+ return new Error(String(serializeError));
1489
+ }
1490
+ }
1491
+ return new Error(defaultMessage);
1492
+ }
1476
1493
 
1477
1494
  // src/components/ErrorDisplay.tsx
1495
+ var import_ink9 = require("ink");
1496
+ var import_react6 = require("react");
1478
1497
  var import_jsx_runtime7 = require("react/jsx-runtime");
1479
1498
  function ErrorDisplay({
1480
1499
  commandUsed,
@@ -1517,100 +1536,132 @@ function ErrorDisplay({
1517
1536
  ] });
1518
1537
  }
1519
1538
 
1520
- // src/components/MainLayout.tsx
1521
- var import_ink13 = require("ink");
1522
- var import_is_ci3 = __toESM(require("is-ci"));
1523
- var import_react8 = require("react");
1524
-
1525
1539
  // src/components/CancelBuild.tsx
1526
- var import_ink10 = require("ink");
1527
- var import_react7 = require("react");
1528
1540
  var import_jsx_runtime8 = require("react/jsx-runtime");
1529
- var cancelBuild = getCallableFirebaseFunction_default("cancelBuild");
1530
- var CancelBuild = ({
1541
+ var callCancelBuildCloudFn = getCallableFirebaseFunction_default("cancelBuild");
1542
+ function CancelBuild({
1543
+ buildId,
1544
+ cancellation,
1545
+ commandUsed
1546
+ }) {
1547
+ const { error, errorType, status } = cancellation;
1548
+ switch (status) {
1549
+ case "cancel-failed": {
1550
+ if (!error) {
1551
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1552
+ ErrorDisplay,
1553
+ {
1554
+ commandUsed,
1555
+ error: "Sorry, something went wrong while cancelling the build."
1556
+ }
1557
+ );
1558
+ }
1559
+ if (errorType === "internal") {
1560
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ErrorDisplay, { commandUsed, error });
1561
+ }
1562
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_ink10.Text, { children: [
1563
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_ink10.Text, { color: "red", children: [
1564
+ "Cannot cancel build (",
1565
+ buildId,
1566
+ ")."
1567
+ ] }),
1568
+ " ",
1569
+ error.message
1570
+ ] });
1571
+ }
1572
+ case "cancelled": {
1573
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_ink10.Text, { children: "Build cancelled" });
1574
+ }
1575
+ case "cancelling": {
1576
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_ink10.Text, { children: [
1577
+ "Cancelling build (",
1578
+ buildId,
1579
+ ")..."
1580
+ ] });
1581
+ }
1582
+ case "idle":
1583
+ default: {
1584
+ return null;
1585
+ }
1586
+ }
1587
+ }
1588
+ function useCancellation({
1589
+ abortController,
1531
1590
  appId,
1532
- children: postCancelContents,
1533
- commandUsed,
1534
- id
1535
- }) => {
1536
- logger_default.debug({ appId, buildId: id }, "CancelBuild component: render");
1591
+ autoExit = true,
1592
+ build
1593
+ }) {
1594
+ const { isRawModeSupported } = (0, import_ink10.useStdin)();
1537
1595
  const exit = useExit_default();
1538
- const [
1539
- { arbitraryMessageComponent, error, hasCompleted, hasStarted },
1540
- setState
1541
- ] = (0, import_react7.useState)({
1542
- arbitraryMessageComponent: null,
1543
- error: null,
1544
- hasCompleted: false,
1545
- hasStarted: false
1546
- });
1596
+ const [state, setState] = (0, import_react7.useState)({ status: "idle" });
1547
1597
  (0, import_react7.useEffect)(() => {
1548
- if (hasCompleted || hasStarted) {
1598
+ if (autoExit && state.status === "cancelled" && !state.error) {
1599
+ logger_default.debug("useCancellation: exiting now that build is cancelled");
1600
+ setTimeout(exit, 10);
1601
+ }
1602
+ }, [autoExit, exit, state.status, state.error]);
1603
+ const canCancel = Boolean(
1604
+ appId && !import_is_ci3.default && isRawModeSupported && state.status === "idle" && isBuildCancellable(build)
1605
+ );
1606
+ return {
1607
+ canCancel,
1608
+ cancel,
1609
+ error: state.error,
1610
+ errorType: state.errorType,
1611
+ executed: state.status !== "idle",
1612
+ status: state.status
1613
+ };
1614
+ async function cancel() {
1615
+ logger_default.debug("useCancellation: cancel() called");
1616
+ const buildId = build == null ? void 0 : build.id;
1617
+ if (!appId || !buildId) {
1618
+ logger_default.warn("useCancellation: can't run with:", { appId, buildId });
1549
1619
  return;
1550
1620
  }
1551
- setState((previousState) => ({ ...previousState, hasStarted: true }));
1621
+ abortController == null ? void 0 : abortController.abort(new CanceledError("Build was cancelled by user"));
1622
+ setState({ status: "cancelling" });
1552
1623
  logForCI("Cancelling build...");
1553
- cancelBuild({ appId, buildId: id }).then((result) => {
1624
+ try {
1625
+ const result = await callCancelBuildCloudFn({ appId, buildId });
1554
1626
  logger_default.debug(
1555
- { appId, buildId: id, result },
1556
- "CancelBuild component: cancellation request complete"
1627
+ { appId, buildId, result },
1628
+ "useCancellation: cancellation request complete"
1557
1629
  );
1558
- setState((previousState) => ({ ...previousState, hasCompleted: true }));
1559
- }).catch((e) => {
1630
+ setState({ status: "cancelled" });
1631
+ } catch (e) {
1632
+ const error = toError(e);
1560
1633
  logger_default.debug(
1561
- { appId, buildId: id, code: e.code },
1562
- "CancelBuild component: cancellation request failed"
1634
+ { appId, buildId, code: error.code },
1635
+ "useCancellation: cancellation request failed"
1563
1636
  );
1564
1637
  logger_default.error(e);
1565
- const stateUpdates = {
1566
- arbitraryMessageComponent: void 0,
1567
- error: void 0,
1568
- hasCompleted: true
1569
- };
1570
- if (e.code === "internal") {
1571
- stateUpdates.error = e;
1638
+ if (error.code === "internal") {
1639
+ setState({
1640
+ status: "cancel-failed",
1641
+ error: new Error(
1642
+ `Failed to cancel build (${buildId}). ${error.message}`
1643
+ ),
1644
+ errorType: "internal"
1645
+ });
1572
1646
  } else {
1573
- stateUpdates.arbitraryMessageComponent = /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_ink10.Text, { children: [
1574
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_ink10.Text, { color: "red", children: [
1575
- "Cannot cancel build (",
1576
- id,
1577
- ")."
1578
- ] }),
1579
- " ",
1580
- e.message
1581
- ] });
1647
+ setState({
1648
+ status: "cancel-failed",
1649
+ error,
1650
+ errorType: "other"
1651
+ });
1582
1652
  }
1583
- setState((prevState) => ({
1584
- ...prevState,
1585
- ...stateUpdates
1586
- }));
1587
- });
1588
- }, [appId, id, hasStarted, hasCompleted]);
1589
- (0, import_react7.useEffect)(() => {
1590
- if (hasCompleted && !postCancelContents) {
1591
- logger_default.debug(
1592
- "CancelBuild component: exiting now that build is cancelled"
1593
- );
1594
- exit();
1595
1653
  }
1596
- }, [postCancelContents, exit, hasCompleted]);
1597
- if (error) {
1598
- error.message = `Failed to cancel build (${id}). ${error.message}`;
1599
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ErrorDisplay, { commandUsed, error });
1600
- }
1601
- if (arbitraryMessageComponent) {
1602
- return arbitraryMessageComponent;
1603
1654
  }
1604
- if (hasCompleted) {
1605
- return postCancelContents ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_jsx_runtime8.Fragment, { children: postCancelContents }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_ink10.Text, { children: "Build cancelled" });
1655
+ }
1656
+ var CanceledError = class _CanceledError extends Error {
1657
+ static isCanceled(e) {
1658
+ return e instanceof _CanceledError || e instanceof Error && e.name === "CanceledError";
1606
1659
  }
1607
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_ink10.Text, { children: [
1608
- "Cancelling build (",
1609
- id,
1610
- ")..."
1611
- ] });
1612
1660
  };
1613
- var CancelBuild_default = CancelBuild;
1661
+
1662
+ // src/components/MainLayout.tsx
1663
+ var import_ink13 = require("ink");
1664
+ var import_react8 = require("react");
1614
1665
 
1615
1666
  // src/components/Footer.tsx
1616
1667
  var import_ink11 = require("ink");
@@ -1688,7 +1739,8 @@ var Header_default = Header;
1688
1739
 
1689
1740
  // src/components/MainLayout.tsx
1690
1741
  var import_jsx_runtime11 = require("react/jsx-runtime");
1691
- var MainLayout = ({
1742
+ function MainLayout({
1743
+ abortController,
1692
1744
  appId,
1693
1745
  appName,
1694
1746
  appVersion,
@@ -1696,57 +1748,39 @@ var MainLayout = ({
1696
1748
  children,
1697
1749
  commandUsed,
1698
1750
  hasBuildEverFailed
1699
- }) => {
1700
- const { isRawModeSupported } = (0, import_ink13.useStdin)();
1701
- const [
1702
- { canCancelBuild, hasKickedOff, isCancellingBuild, wasCtrlCPressed },
1703
- setState
1704
- ] = (0, import_react8.useState)({
1705
- canCancelBuild: null,
1706
- hasKickedOff: false,
1707
- isCancellingBuild: false,
1708
- wasCtrlCPressed: false
1709
- });
1710
- (0, import_react8.useEffect)(() => {
1711
- setState((previousState) => ({
1712
- ...previousState,
1713
- hasKickedOff: hasBuildKickedOff(build)
1714
- }));
1715
- }, [build]);
1716
- (0, import_react8.useEffect)(() => {
1717
- setState((previousState) => ({
1718
- ...previousState,
1719
- canCancelBuild: !import_is_ci3.default && isRawModeSupported && !isCancellingBuild && isBuildCancellable(build)
1720
- }));
1721
- }, [build, isCancellingBuild, isRawModeSupported]);
1751
+ }) {
1752
+ const [wasCtrlCPressed, setWasCtrlCPressed] = (0, import_react8.useState)(false);
1753
+ const cancellation = useCancellation({ abortController, appId, build });
1754
+ const hasKickedOff = hasBuildKickedOff(build);
1722
1755
  useInput(
1723
1756
  async (_input, key) => {
1724
- if (key.escape && canCancelBuild) {
1757
+ if (key.escape && cancellation.canCancel) {
1725
1758
  logger_default.debug("MainLayout component: esc pressed, cancelling build");
1726
- setState((previousState) => ({
1727
- ...previousState,
1728
- isCancellingBuild: true
1729
- }));
1759
+ cancellation.cancel();
1730
1760
  }
1731
1761
  },
1732
1762
  {},
1733
1763
  {
1734
1764
  onCtrlCPressed: () => {
1735
- setState((previousState) => ({
1736
- ...previousState,
1737
- wasCtrlCPressed: true
1738
- }));
1765
+ setWasCtrlCPressed(true);
1739
1766
  }
1740
1767
  }
1741
1768
  );
1742
1769
  return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
1743
1770
  /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Header_default, { build, name: appName, version: appVersion }),
1744
- isCancellingBuild ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_ink13.Box, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(CancelBuild_default, { appId, commandUsed, id: build.id }) }) : children,
1771
+ cancellation.executed && build ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_ink13.Box, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1772
+ CancelBuild,
1773
+ {
1774
+ buildId: build.id,
1775
+ cancellation,
1776
+ commandUsed
1777
+ }
1778
+ ) }) : children,
1745
1779
  /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1746
1780
  Footer_default,
1747
1781
  {
1748
1782
  hasBuildEverFailed,
1749
- shouldShowCancelBuildInstructions: canCancelBuild && !wasCtrlCPressed,
1783
+ shouldShowCancelBuildInstructions: cancellation.canCancel && !wasCtrlCPressed,
1750
1784
  uiUrl: build ? build.url : null
1751
1785
  }
1752
1786
  ),
@@ -1758,8 +1792,7 @@ var MainLayout = ({
1758
1792
  ] }) })
1759
1793
  ] }) : null
1760
1794
  ] });
1761
- };
1762
- var MainLayout_default = MainLayout;
1795
+ }
1763
1796
 
1764
1797
  // src/commands/build/components/Preparation.tsx
1765
1798
  var import_ink15 = require("ink");
@@ -2212,6 +2245,24 @@ var addCustomKeywords_default = (ajv, context) => {
2212
2245
  return true;
2213
2246
  }
2214
2247
  });
2248
+ addKeyword({
2249
+ keyword: "validSemverOrLatest",
2250
+ type: "string",
2251
+ validate: (_schema, data) => {
2252
+ if (data === "latest") {
2253
+ return true;
2254
+ }
2255
+ if (!(0, import_valid.default)(data)) {
2256
+ throw new import_ajv2.ValidationError([
2257
+ {
2258
+ keyword: "validSemverOrLatest",
2259
+ message: `${data} must be "latest" or a valid semantic version or version range`
2260
+ }
2261
+ ]);
2262
+ }
2263
+ return true;
2264
+ }
2265
+ });
2215
2266
  addKeyword({
2216
2267
  keyword: "excludedDependencies",
2217
2268
  validate: (schema, data) => {
@@ -2287,6 +2338,13 @@ var addCustomKeywords_default = (ajv, context) => {
2287
2338
  ]);
2288
2339
  }
2289
2340
  const stats = fs2.statSync(filePath);
2341
+ const extension = path4.extname(filePath).substr(1).toLowerCase();
2342
+ const allowDirectoryExtensions = Array.isArray(
2343
+ schema.allowDirectoryExtensions
2344
+ ) ? schema.allowDirectoryExtensions : [];
2345
+ const mustBeDirectoryExtensions = Array.isArray(
2346
+ schema.mustBeDirectoryExtensions
2347
+ ) ? schema.mustBeDirectoryExtensions : [];
2290
2348
  if (mustBeDirectory && stats.isFile()) {
2291
2349
  throw new import_ajv2.ValidationError([
2292
2350
  {
@@ -2294,7 +2352,14 @@ var addCustomKeywords_default = (ajv, context) => {
2294
2352
  message: `must be a directory, not a file (${filePath})`
2295
2353
  }
2296
2354
  ]);
2297
- } else if (schema.mustBeFile && stats.isDirectory()) {
2355
+ } else if (mustBeDirectoryExtensions.includes(extension) && stats.isFile()) {
2356
+ throw new import_ajv2.ValidationError([
2357
+ {
2358
+ keyword: "Directory",
2359
+ message: `must be a directory, not a file (${filePath})`
2360
+ }
2361
+ ]);
2362
+ } else if (schema.mustBeFile && stats.isDirectory() && !allowDirectoryExtensions.includes(extension)) {
2298
2363
  throw new import_ajv2.ValidationError([
2299
2364
  {
2300
2365
  keyword: "File",
@@ -2444,6 +2509,30 @@ var addCustomKeywords_default = (ajv, context) => {
2444
2509
  return true;
2445
2510
  }
2446
2511
  });
2512
+ addKeyword({
2513
+ keyword: "macIconComposerAppBuilderLibVersion",
2514
+ type: "object",
2515
+ validate: (_schema, data) => {
2516
+ var _a2;
2517
+ const macIcon = (_a2 = data == null ? void 0 : data.mac) == null ? void 0 : _a2.icon;
2518
+ if (typeof macIcon !== "string" || path4.extname(macIcon).toLowerCase() !== ".icon") {
2519
+ return true;
2520
+ }
2521
+ const minSupportedVersion = "26.8.1";
2522
+ const configuredVersion = data == null ? void 0 : data.appBuilderLibVersion;
2523
+ const resolvedVersion = configuredVersion ? semver.minVersion(configuredVersion) : null;
2524
+ if (!resolvedVersion || !semver.gte(resolvedVersion, minSupportedVersion)) {
2525
+ throw new import_ajv2.ValidationError([
2526
+ {
2527
+ keyword: "appBuilderLibVersion",
2528
+ message: `must be set to ${minSupportedVersion} or later when using mac.icon as an Apple .icon package`,
2529
+ instancePath: "/mac/icon"
2530
+ }
2531
+ ]);
2532
+ }
2533
+ return true;
2534
+ }
2535
+ });
2447
2536
  };
2448
2537
 
2449
2538
  // schemas/schema.json
@@ -2459,6 +2548,7 @@ var schema_default = {
2459
2548
  else: {
2460
2549
  required: ["id", "icon", "schemaVersion"]
2461
2550
  },
2551
+ macIconComposerAppBuilderLibVersion: {},
2462
2552
  properties: {
2463
2553
  $schema: {
2464
2554
  type: "string",
@@ -2572,10 +2662,10 @@ var schema_default = {
2572
2662
  definitions: {
2573
2663
  appBuilderLibVersionProperty: {
2574
2664
  type: "string",
2575
- validSemver: {},
2665
+ validSemverOrLatest: {},
2576
2666
  minLength: 1,
2577
- description: "The version of app-builder-lib that ToDesktop should use for building your app. This can be useful if you need to use a specific version that includes certain features or fixes.",
2578
- examples: ["22.14.13"]
2667
+ description: 'The version of app-builder-lib that ToDesktop should use for building your app. This can be a specific version, a semantic version range, or "latest". This can be useful if you need to use a specific version that includes certain features or fixes.',
2668
+ examples: ["22.14.13", "latest"]
2579
2669
  },
2580
2670
  appIdProperty: {
2581
2671
  type: "string",
@@ -2902,6 +2992,27 @@ var schema_default = {
2902
2992
  ["--enable-features=UseOzonePlatform", "--ozone-platform=x11"]
2903
2993
  ]
2904
2994
  },
2995
+ deb: {
2996
+ type: "object",
2997
+ description: "Configuration for Debian (.deb) packaging.",
2998
+ additionalProperties: false,
2999
+ properties: {
3000
+ additionalDepends: {
3001
+ type: "array",
3002
+ items: {
3003
+ type: "string"
3004
+ },
3005
+ description: "Additional package dependencies to append to ToDesktop's default .deb dependencies."
3006
+ },
3007
+ depends: {
3008
+ type: "array",
3009
+ items: {
3010
+ type: "string"
3011
+ },
3012
+ description: "The list of package dependencies for the .deb package. This overwrites ToDesktop's default dependency list and linux.deb.additionalDepends."
3013
+ }
3014
+ }
3015
+ },
2905
3016
  noSandbox: {
2906
3017
  type: "boolean",
2907
3018
  description: "This option allows you to configure whether your app should run in a sandboxed environment.",
@@ -2966,11 +3077,13 @@ var schema_default = {
2966
3077
  },
2967
3078
  icon: {
2968
3079
  type: "string",
2969
- description: "The path to your application's Mac desktop icon. It must be an ICNS or PNG.",
3080
+ description: "The path to your application's Mac desktop icon. It must be an ICNS, PNG, or Apple `.icon` package directory.",
2970
3081
  examples: ["./mac-icon.png"],
2971
3082
  file: {
2972
- extensions: ["icns", "png"],
2973
- mustBeFile: true
3083
+ extensions: ["icns", "png", "icon"],
3084
+ mustBeFile: true,
3085
+ allowDirectoryExtensions: ["icon"],
3086
+ mustBeDirectoryExtensions: ["icon"]
2974
3087
  },
2975
3088
  minLength: 3
2976
3089
  },
@@ -4775,10 +4888,12 @@ async function exists(filePath) {
4775
4888
  }
4776
4889
 
4777
4890
  // src/commands/build/utilities/runBuild.ts
4891
+ var callDeleteBuild = getCallableFirebaseFunction_default("deleteBuild");
4778
4892
  async function runBuild({
4779
4893
  configPath,
4780
- updateState,
4781
- flags
4894
+ flags,
4895
+ signal,
4896
+ updateState
4782
4897
  }) {
4783
4898
  var _a2, _b, _c, _d, _e;
4784
4899
  logForCI("Getting application information...");
@@ -4803,23 +4918,29 @@ async function runBuild({
4803
4918
  });
4804
4919
  logForCI("Preparing...");
4805
4920
  let buildId;
4921
+ signal == null ? void 0 : signal.throwIfAborted();
4806
4922
  try {
4807
- const prepareResult = await postToFirebaseFunction("prepareNewBuild", {
4808
- appPkgName: appPkgJson.name,
4809
- appPkgProductName: appPkgJson.productName,
4810
- appVersion: appPkgJson.version,
4811
- id: config.id,
4812
- onBuildFinishedWebhook: flags.onBuildFinishedWebhook,
4813
- projectConfig: unprocessedConfig,
4814
- shouldCodeSign: flags.shouldCodeSign !== false,
4815
- shouldRelease: false,
4816
- userId: primaryUserId,
4817
- versionControlInfo: await getVersionControlInfo_default(config.appPath),
4818
- introspect: flags.introspect,
4819
- breakpoints: (_b = flags.breakpointPlan) == null ? void 0 : _b.breakpoints,
4820
- idToken: await ((_c = currentUser()) == null ? void 0 : _c.getIdToken())
4821
- });
4923
+ const prepareResult = await postToFirebaseFunction(
4924
+ "prepareNewBuild",
4925
+ {
4926
+ appPkgName: appPkgJson.name,
4927
+ appPkgProductName: appPkgJson.productName,
4928
+ appVersion: appPkgJson.version,
4929
+ id: config.id,
4930
+ onBuildFinishedWebhook: flags.onBuildFinishedWebhook,
4931
+ projectConfig: unprocessedConfig,
4932
+ shouldCodeSign: flags.shouldCodeSign !== false,
4933
+ shouldRelease: false,
4934
+ userId: primaryUserId,
4935
+ versionControlInfo: await getVersionControlInfo_default(config.appPath),
4936
+ introspect: flags.introspect,
4937
+ breakpoints: (_b = flags.breakpointPlan) == null ? void 0 : _b.breakpoints,
4938
+ idToken: await ((_c = currentUser()) == null ? void 0 : _c.getIdToken())
4939
+ },
4940
+ { signal }
4941
+ );
4822
4942
  buildId = prepareResult.appData.meta.currentBuildProgress.id;
4943
+ signal == null ? void 0 : signal.throwIfAborted();
4823
4944
  buildObserver.subscribe({ appId, buildId, userId: prepareResult.userId });
4824
4945
  await buildObserver.whenFirstUpdate();
4825
4946
  } catch (e) {
@@ -4832,6 +4953,7 @@ async function runBuild({
4832
4953
  });
4833
4954
  logForCI("Uploading...");
4834
4955
  let sourceArchiveDetails;
4956
+ signal == null ? void 0 : signal.throwIfAborted();
4835
4957
  try {
4836
4958
  sourceArchiveDetails = await uploadApplicationSource({
4837
4959
  appId,
@@ -4850,25 +4972,31 @@ async function runBuild({
4850
4972
  }
4851
4973
  });
4852
4974
  } catch (e) {
4975
+ await tryDeleteBuild(appId, buildId);
4853
4976
  throw addErrorMessage(e, "Failed while uploading application source");
4854
4977
  }
4855
4978
  updateState({ state: "building" });
4856
4979
  logForCI("Kicking off build...");
4980
+ signal == null ? void 0 : signal.throwIfAborted();
4857
4981
  try {
4858
- await postToFirebaseFunction("kickOffBuild", {
4859
- appBuilderLibVersion: config.appBuilderLibVersion,
4860
- appId,
4861
- appPkgName: appPkgJson.name,
4862
- appVersion: appPkgJson.version,
4863
- buildId,
4864
- idToken: await ((_d = currentUser()) == null ? void 0 : _d.getIdToken()),
4865
- linuxImageVersion: (_e = config.linux) == null ? void 0 : _e.imageVersion,
4866
- nodeVersion: config.nodeVersion,
4867
- npmVersion: config.npmVersion,
4868
- pnpmVersion: config.pnpmVersion,
4869
- sourceArchiveDetails,
4870
- userId: primaryUserId
4871
- });
4982
+ await postToFirebaseFunction(
4983
+ "kickOffBuild",
4984
+ {
4985
+ appBuilderLibVersion: config.appBuilderLibVersion,
4986
+ appId,
4987
+ appPkgName: appPkgJson.name,
4988
+ appVersion: appPkgJson.version,
4989
+ buildId,
4990
+ idToken: await ((_d = currentUser()) == null ? void 0 : _d.getIdToken()),
4991
+ linuxImageVersion: (_e = config.linux) == null ? void 0 : _e.imageVersion,
4992
+ nodeVersion: config.nodeVersion,
4993
+ npmVersion: config.npmVersion,
4994
+ pnpmVersion: config.pnpmVersion,
4995
+ sourceArchiveDetails,
4996
+ userId: primaryUserId
4997
+ },
4998
+ { signal }
4999
+ );
4872
5000
  } catch (e) {
4873
5001
  throw addErrorMessage(e, "Failed while kicking off build");
4874
5002
  }
@@ -4876,6 +5004,7 @@ async function runBuild({
4876
5004
  updateState({ state: "exit-after-uploading" });
4877
5005
  return;
4878
5006
  }
5007
+ signal == null ? void 0 : signal.throwIfAborted();
4879
5008
  const build = await buildObserver.whenSettled();
4880
5009
  if ((build == null ? void 0 : build.status) === "failed" && shouldExitOnBuildFailure_default(build)) {
4881
5010
  updateState({ state: "build-failed" });
@@ -4883,6 +5012,9 @@ async function runBuild({
4883
5012
  }
4884
5013
  function addErrorMessage(e, message2) {
4885
5014
  var _a2, _b;
5015
+ if (CanceledError.isCanceled(e)) {
5016
+ return e;
5017
+ }
4886
5018
  let originalMessage = "";
4887
5019
  if (import_axios2.default.isAxiosError(e) && ((_b = (_a2 = e.response) == null ? void 0 : _a2.data) == null ? void 0 : _b.message)) {
4888
5020
  originalMessage = e.response.data.message;
@@ -4899,6 +5031,13 @@ function addErrorMessage(e, message2) {
4899
5031
  }
4900
5032
  return newError;
4901
5033
  }
5034
+ async function tryDeleteBuild(appId, buildId) {
5035
+ try {
5036
+ await callDeleteBuild({ appId, buildId });
5037
+ } catch (e) {
5038
+ logger_default.error(e, "Failed to delete build after error");
5039
+ }
5040
+ }
4902
5041
 
4903
5042
  // src/commands/build/components/Build.tsx
4904
5043
  var import_jsx_runtime15 = require("react/jsx-runtime");
@@ -4910,11 +5049,19 @@ function Build({
4910
5049
  var _a2, _b, _c, _d, _e, _f;
4911
5050
  const exit = useExit_default();
4912
5051
  const [state, setState] = (0, import_react9.useState)({ state: "initializing" });
5052
+ const [abortController] = (0, import_react9.useState)(() => new AbortController());
4913
5053
  (0, import_react9.useEffect)(() => {
4914
- runBuild({ configPath, flags, updateState }).catch((e) => {
4915
- const error = e.response ? e.response.data : e;
4916
- logForCI(error);
4917
- updateState({ state: "error", error });
5054
+ runBuild({
5055
+ configPath,
5056
+ flags,
5057
+ signal: abortController.signal,
5058
+ updateState
5059
+ }).catch((e) => {
5060
+ if (!CanceledError.isCanceled(e)) {
5061
+ const error = e.response ? e.response.data : e;
5062
+ logForCI(error);
5063
+ updateState({ state: "error", error });
5064
+ }
4918
5065
  });
4919
5066
  return () => {
4920
5067
  var _a3;
@@ -4939,8 +5086,10 @@ function Build({
4939
5086
  return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ErrorDisplay, { commandUsed, error: "No build is set" });
4940
5087
  }
4941
5088
  return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
4942
- MainLayout_default,
5089
+ MainLayout,
4943
5090
  {
5091
+ abortController,
5092
+ appId: state.appId,
4944
5093
  appName: state.build.appName || ((_a2 = state.appPkg) == null ? void 0 : _a2.name) || "",
4945
5094
  appVersion: state.build.appVersion || ((_b = state.appPkg) == null ? void 0 : _b.version) || "",
4946
5095
  build: state.build,
@@ -4963,8 +5112,10 @@ function Build({
4963
5112
  return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink16.Text, { children: "Getting app info..." });
4964
5113
  case "preparing":
4965
5114
  return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
4966
- MainLayout_default,
5115
+ MainLayout,
4967
5116
  {
5117
+ abortController,
5118
+ appId: state.appId,
4968
5119
  appName: ((_c = state.build) == null ? void 0 : _c.appName) || ((_d = state.appPkg) == null ? void 0 : _d.name) || "",
4969
5120
  appVersion: ((_e = state.build) == null ? void 0 : _e.appVersion) || ((_f = state.appPkg) == null ? void 0 : _f.version) || "",
4970
5121
  build: state.build,
@@ -5263,7 +5414,6 @@ var ErrorBoundary_default = ErrorBoundary;
5263
5414
  // src/commands/build/components/OngoingBuildGuard.tsx
5264
5415
  var import_ink23 = require("ink");
5265
5416
  var import_ink_select_input = __toESM(require("ink-select-input"));
5266
- var import_prop_types9 = __toESM(require("prop-types"));
5267
5417
  var import_react15 = require("react");
5268
5418
 
5269
5419
  // src/components/CustomSelectInputIndicator.tsx
@@ -5502,7 +5652,7 @@ var ViewBuild = ({ commandUsed, id, configPath }) => {
5502
5652
  }));
5503
5653
  };
5504
5654
  return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
5505
- MainLayout_default,
5655
+ MainLayout,
5506
5656
  {
5507
5657
  appId,
5508
5658
  appName: build.appName,
@@ -5537,11 +5687,11 @@ var ViewBuild_default = ViewBuild;
5537
5687
  var import_firestore15 = require("firebase/firestore");
5538
5688
  var import_is_ci5 = __toESM(require("is-ci"));
5539
5689
  var import_jsx_runtime23 = require("react/jsx-runtime");
5540
- var OngoingBuildGuard = ({
5690
+ function OngoingBuildGuard({
5541
5691
  children,
5542
5692
  commandUsed,
5543
5693
  configPath
5544
- }) => {
5694
+ }) {
5545
5695
  const { isRawModeSupported } = (0, import_ink23.useStdin)();
5546
5696
  const exit = useExit_default();
5547
5697
  const [{ appId, builds, error, isLoading, itemChosen }, setState] = (0, import_react15.useState)({
@@ -5551,6 +5701,11 @@ var OngoingBuildGuard = ({
5551
5701
  isLoading: true,
5552
5702
  itemChosen: null
5553
5703
  });
5704
+ const cancellation = useCancellation({
5705
+ appId: appId ?? void 0,
5706
+ build: builds.find(Boolean),
5707
+ autoExit: false
5708
+ });
5554
5709
  (0, import_react15.useEffect)(() => {
5555
5710
  if (!isLoading) {
5556
5711
  return;
@@ -5568,7 +5723,7 @@ var OngoingBuildGuard = ({
5568
5723
  firestore_default,
5569
5724
  `users/${id}/applications/${applicationId}/builds`
5570
5725
  ),
5571
- (0, import_firestore15.where)("createdAt", ">=", twentyFourHoursAgo),
5726
+ (0, import_firestore15.where)("createdAt", ">=", twentyFourHoursAgo.toISOString()),
5572
5727
  (0, import_firestore15.orderBy)("createdAt", "desc"),
5573
5728
  (0, import_firestore15.limit)(10)
5574
5729
  );
@@ -5618,7 +5773,17 @@ var OngoingBuildGuard = ({
5618
5773
  if (itemChosen.value === "view" && build) {
5619
5774
  return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ViewBuild_default, { commandUsed, id: build.id });
5620
5775
  } else if (itemChosen.value === "cancel" && build && appId) {
5621
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(CancelBuild_default, { appId, commandUsed, id: build.id, children });
5776
+ if (cancellation.status === "cancelled") {
5777
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_jsx_runtime23.Fragment, { children });
5778
+ }
5779
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5780
+ CancelBuild,
5781
+ {
5782
+ buildId: build.id,
5783
+ cancellation,
5784
+ commandUsed
5785
+ }
5786
+ );
5622
5787
  } else if (itemChosen.value === "concurrent") {
5623
5788
  return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_jsx_runtime23.Fragment, { children });
5624
5789
  } else {
@@ -5648,10 +5813,15 @@ var OngoingBuildGuard = ({
5648
5813
  label: "Exit",
5649
5814
  value: "exit"
5650
5815
  });
5651
- const handleSelect = (selectedItem) => setState((previousState) => ({
5652
- ...previousState,
5653
- itemChosen: selectedItem
5654
- }));
5816
+ const handleSelect = (selectedItem) => {
5817
+ if (selectedItem.value === "cancel") {
5818
+ cancellation.cancel();
5819
+ }
5820
+ setState((previousState) => ({
5821
+ ...previousState,
5822
+ itemChosen: selectedItem
5823
+ }));
5824
+ };
5655
5825
  return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
5656
5826
  /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_ink23.Box, { marginBottom: 1, children: [
5657
5827
  /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_ink23.Text, { bold: true, children: multiple ? "There are ongoing builds " : "There is an ongoing build " }),
@@ -5675,13 +5845,7 @@ var OngoingBuildGuard = ({
5675
5845
  } else {
5676
5846
  return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_jsx_runtime23.Fragment, { children });
5677
5847
  }
5678
- };
5679
- OngoingBuildGuard.propTypes = {
5680
- commandUsed: import_prop_types9.default.string.isRequired,
5681
- children: import_prop_types9.default.oneOfType([import_prop_types9.default.array, import_prop_types9.default.object]),
5682
- configPath: import_prop_types9.default.string
5683
- };
5684
- var OngoingBuildGuard_default = OngoingBuildGuard;
5848
+ }
5685
5849
 
5686
5850
  // src/utilities/useAnalytics.ts
5687
5851
  var import_react16 = require("react");
@@ -5739,7 +5903,7 @@ function BuildCommand({
5739
5903
  webhook: flags.onBuildFinishedWebhook
5740
5904
  });
5741
5905
  const commandUsed = "todesktop build";
5742
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ErrorBoundary_default, { children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(LoginHOC_default, { children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(OngoingBuildGuard_default, { configPath, commandUsed, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
5906
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ErrorBoundary_default, { children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(LoginHOC_default, { children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(OngoingBuildGuard, { configPath, commandUsed, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
5743
5907
  Build,
5744
5908
  {
5745
5909
  commandUsed,
@@ -5751,16 +5915,16 @@ function BuildCommand({
5751
5915
 
5752
5916
  // src/components/ViewBuilds.tsx
5753
5917
  var import_ink29 = require("ink");
5754
- var import_prop_types15 = __toESM(require("prop-types"));
5918
+ var import_prop_types14 = __toESM(require("prop-types"));
5755
5919
  var import_react18 = require("react");
5756
5920
 
5757
5921
  // src/components/Table.tsx
5758
5922
  var import_ink27 = require("ink");
5759
- var import_prop_types14 = __toESM(require("prop-types"));
5923
+ var import_prop_types13 = __toESM(require("prop-types"));
5760
5924
 
5761
5925
  // src/components/TableEnd.tsx
5762
5926
  var import_ink24 = require("ink");
5763
- var import_prop_types10 = __toESM(require("prop-types"));
5927
+ var import_prop_types9 = __toESM(require("prop-types"));
5764
5928
  var import_jsx_runtime25 = require("react/jsx-runtime");
5765
5929
  var TableEnd = ({ keyDetails, ...props }) => {
5766
5930
  let content = "\u2514";
@@ -5769,13 +5933,13 @@ var TableEnd = ({ keyDetails, ...props }) => {
5769
5933
  return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_ink24.Box, { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_ink24.Text, { children: content }) });
5770
5934
  };
5771
5935
  TableEnd.propTypes = {
5772
- keyDetails: import_prop_types10.default.shape({}).isRequired
5936
+ keyDetails: import_prop_types9.default.shape({}).isRequired
5773
5937
  };
5774
5938
  var TableEnd_default = TableEnd;
5775
5939
 
5776
5940
  // src/components/TableHead.tsx
5777
5941
  var import_ink25 = require("ink");
5778
- var import_prop_types11 = __toESM(require("prop-types"));
5942
+ var import_prop_types10 = __toESM(require("prop-types"));
5779
5943
  var import_react17 = require("react");
5780
5944
  var import_jsx_runtime26 = require("react/jsx-runtime");
5781
5945
  var TableHead = ({ keyDetails, ...props }) => {
@@ -5800,17 +5964,17 @@ var TableHead = ({ keyDetails, ...props }) => {
5800
5964
  ] });
5801
5965
  };
5802
5966
  TableHead.propTypes = {
5803
- bottomLinePrefix: import_prop_types11.default.string,
5804
- keyDetails: import_prop_types11.default.shape({}).isRequired
5967
+ bottomLinePrefix: import_prop_types10.default.string,
5968
+ keyDetails: import_prop_types10.default.shape({}).isRequired
5805
5969
  };
5806
5970
  var TableHead_default = TableHead;
5807
5971
 
5808
5972
  // src/components/TableBody.tsx
5809
- var import_prop_types13 = __toESM(require("prop-types"));
5973
+ var import_prop_types12 = __toESM(require("prop-types"));
5810
5974
 
5811
5975
  // src/components/TableRow.tsx
5812
5976
  var import_ink26 = require("ink");
5813
- var import_prop_types12 = __toESM(require("prop-types"));
5977
+ var import_prop_types11 = __toESM(require("prop-types"));
5814
5978
  var import_jsx_runtime27 = require("react/jsx-runtime");
5815
5979
  var TableRow = ({
5816
5980
  data,
@@ -5848,10 +6012,10 @@ var TableRow = ({
5848
6012
  ] });
5849
6013
  };
5850
6014
  TableRow.propTypes = {
5851
- data: import_prop_types12.default.shape({}).isRequired,
5852
- getCellTextProps: import_prop_types12.default.func,
5853
- keyDetails: import_prop_types12.default.shape({}).isRequired,
5854
- textProps: import_prop_types12.default.shape({})
6015
+ data: import_prop_types11.default.shape({}).isRequired,
6016
+ getCellTextProps: import_prop_types11.default.func,
6017
+ keyDetails: import_prop_types11.default.shape({}).isRequired,
6018
+ textProps: import_prop_types11.default.shape({})
5855
6019
  };
5856
6020
  var TableRow_default = TableRow;
5857
6021
 
@@ -5882,8 +6046,8 @@ TableBody.propTypes = {
5882
6046
  );
5883
6047
  }
5884
6048
  },
5885
- getCellTextProps: import_prop_types13.default.func,
5886
- keyDetails: import_prop_types13.default.shape({}).isRequired
6049
+ getCellTextProps: import_prop_types12.default.func,
6050
+ keyDetails: import_prop_types12.default.shape({}).isRequired
5887
6051
  };
5888
6052
  var TableBody_default = TableBody;
5889
6053
 
@@ -5933,7 +6097,7 @@ Table.propTypes = {
5933
6097
  );
5934
6098
  }
5935
6099
  },
5936
- getCellTextProps: import_prop_types14.default.func
6100
+ getCellTextProps: import_prop_types13.default.func
5937
6101
  };
5938
6102
  var Table_default = Table;
5939
6103
 
@@ -6203,11 +6367,11 @@ var removeAppBuilderLibConfig = (builds) => {
6203
6367
  });
6204
6368
  };
6205
6369
  ViewBuilds.propTypes = {
6206
- commandUsed: import_prop_types15.default.string.isRequired,
6207
- configPath: import_prop_types15.default.string,
6208
- count: import_prop_types15.default.number,
6209
- format: import_prop_types15.default.string,
6210
- exit: import_prop_types15.default.bool
6370
+ commandUsed: import_prop_types14.default.string.isRequired,
6371
+ configPath: import_prop_types14.default.string,
6372
+ count: import_prop_types14.default.number,
6373
+ format: import_prop_types14.default.string,
6374
+ exit: import_prop_types14.default.bool
6211
6375
  };
6212
6376
  var ViewBuilds_default = ViewBuilds;
6213
6377
 
@@ -6279,11 +6443,12 @@ function isFirebaseFunctionError(error) {
6279
6443
  typeof error === "object" && error && "code" in error && typeof error.code === "string"
6280
6444
  );
6281
6445
  }
6282
- async function startIntrospectionSession(buildId, platform) {
6446
+ async function startIntrospectionSession(buildId, platform, appId) {
6283
6447
  try {
6284
6448
  const result = await startIntrospectionSessionFn({
6285
6449
  buildId,
6286
- platform
6450
+ platform,
6451
+ appId
6287
6452
  });
6288
6453
  return result.data;
6289
6454
  } catch (error) {
@@ -6422,7 +6587,8 @@ var import_jsx_runtime33 = require("react/jsx-runtime");
6422
6587
  function IntrospectSession({
6423
6588
  buildId,
6424
6589
  platform,
6425
- verbose
6590
+ verbose,
6591
+ appId
6426
6592
  }) {
6427
6593
  const exit = useExit_default();
6428
6594
  const exitRef = (0, import_react19.useRef)(exit);
@@ -6527,7 +6693,8 @@ ${message2}`;
6527
6693
  setStatus("starting-session");
6528
6694
  const sessionResponse = await startIntrospectionSession(
6529
6695
  buildId,
6530
- platform
6696
+ platform,
6697
+ appId
6531
6698
  );
6532
6699
  setJti(sessionResponse.jti);
6533
6700
  if (verbose) {
@@ -6813,7 +6980,7 @@ var import_ink32 = require("ink");
6813
6980
  // src/components/SelectTable.tsx
6814
6981
  var import_ink31 = require("ink");
6815
6982
  var import_ink_select_input2 = __toESM(require("ink-select-input"));
6816
- var import_prop_types16 = __toESM(require("prop-types"));
6983
+ var import_prop_types15 = __toESM(require("prop-types"));
6817
6984
  var import_jsx_runtime34 = require("react/jsx-runtime");
6818
6985
  var CustomIndicator = (props) => /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(CustomSelectInputIndicator, { marginTop: 1, ...props });
6819
6986
  var SelectTable = ({ data, onSelect }) => {
@@ -6872,7 +7039,7 @@ SelectTable.propTypes = {
6872
7039
  );
6873
7040
  }
6874
7041
  },
6875
- onSelect: import_prop_types16.default.func
7042
+ onSelect: import_prop_types15.default.func
6876
7043
  };
6877
7044
  var SelectTable_default = SelectTable;
6878
7045
 
@@ -7368,6 +7535,13 @@ function IntrospectCommand({
7368
7535
  }) {
7369
7536
  const [buildId, setBuildId] = (0, import_react24.useState)(initialBuildId);
7370
7537
  const [platform, setPlatform] = (0, import_react24.useState)(initialPlatform);
7538
+ const appId = (0, import_react24.useMemo)(() => {
7539
+ try {
7540
+ return getProjectConfig(configPath).config.id;
7541
+ } catch {
7542
+ return void 0;
7543
+ }
7544
+ }, [configPath]);
7371
7545
  useAnalyticsCommand("introspect", {
7372
7546
  buildId,
7373
7547
  platform,
@@ -7410,7 +7584,8 @@ function IntrospectCommand({
7410
7584
  {
7411
7585
  buildId,
7412
7586
  platform: normalizedPlatform,
7413
- verbose: verbose ?? false
7587
+ verbose: verbose ?? false,
7588
+ appId
7414
7589
  }
7415
7590
  );
7416
7591
  };
@@ -8737,7 +8912,7 @@ var package_default = {
8737
8912
  access: "public"
8738
8913
  },
8739
8914
  name: "@todesktop/cli",
8740
- version: "1.21.0",
8915
+ version: "1.23.0",
8741
8916
  license: "MIT",
8742
8917
  author: "Dave Jeffery <dave@todesktop.com> (http://www.todesktop.com/)",
8743
8918
  homepage: "https://todesktop.com/cli",