@todesktop/cli 1.22.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",
@@ -2987,11 +3077,13 @@ var schema_default = {
2987
3077
  },
2988
3078
  icon: {
2989
3079
  type: "string",
2990
- 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.",
2991
3081
  examples: ["./mac-icon.png"],
2992
3082
  file: {
2993
- extensions: ["icns", "png"],
2994
- mustBeFile: true
3083
+ extensions: ["icns", "png", "icon"],
3084
+ mustBeFile: true,
3085
+ allowDirectoryExtensions: ["icon"],
3086
+ mustBeDirectoryExtensions: ["icon"]
2995
3087
  },
2996
3088
  minLength: 3
2997
3089
  },
@@ -4796,10 +4888,12 @@ async function exists(filePath) {
4796
4888
  }
4797
4889
 
4798
4890
  // src/commands/build/utilities/runBuild.ts
4891
+ var callDeleteBuild = getCallableFirebaseFunction_default("deleteBuild");
4799
4892
  async function runBuild({
4800
4893
  configPath,
4801
- updateState,
4802
- flags
4894
+ flags,
4895
+ signal,
4896
+ updateState
4803
4897
  }) {
4804
4898
  var _a2, _b, _c, _d, _e;
4805
4899
  logForCI("Getting application information...");
@@ -4824,23 +4918,29 @@ async function runBuild({
4824
4918
  });
4825
4919
  logForCI("Preparing...");
4826
4920
  let buildId;
4921
+ signal == null ? void 0 : signal.throwIfAborted();
4827
4922
  try {
4828
- const prepareResult = await postToFirebaseFunction("prepareNewBuild", {
4829
- appPkgName: appPkgJson.name,
4830
- appPkgProductName: appPkgJson.productName,
4831
- appVersion: appPkgJson.version,
4832
- id: config.id,
4833
- onBuildFinishedWebhook: flags.onBuildFinishedWebhook,
4834
- projectConfig: unprocessedConfig,
4835
- shouldCodeSign: flags.shouldCodeSign !== false,
4836
- shouldRelease: false,
4837
- userId: primaryUserId,
4838
- versionControlInfo: await getVersionControlInfo_default(config.appPath),
4839
- introspect: flags.introspect,
4840
- breakpoints: (_b = flags.breakpointPlan) == null ? void 0 : _b.breakpoints,
4841
- idToken: await ((_c = currentUser()) == null ? void 0 : _c.getIdToken())
4842
- });
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
+ );
4843
4942
  buildId = prepareResult.appData.meta.currentBuildProgress.id;
4943
+ signal == null ? void 0 : signal.throwIfAborted();
4844
4944
  buildObserver.subscribe({ appId, buildId, userId: prepareResult.userId });
4845
4945
  await buildObserver.whenFirstUpdate();
4846
4946
  } catch (e) {
@@ -4853,6 +4953,7 @@ async function runBuild({
4853
4953
  });
4854
4954
  logForCI("Uploading...");
4855
4955
  let sourceArchiveDetails;
4956
+ signal == null ? void 0 : signal.throwIfAborted();
4856
4957
  try {
4857
4958
  sourceArchiveDetails = await uploadApplicationSource({
4858
4959
  appId,
@@ -4871,25 +4972,31 @@ async function runBuild({
4871
4972
  }
4872
4973
  });
4873
4974
  } catch (e) {
4975
+ await tryDeleteBuild(appId, buildId);
4874
4976
  throw addErrorMessage(e, "Failed while uploading application source");
4875
4977
  }
4876
4978
  updateState({ state: "building" });
4877
4979
  logForCI("Kicking off build...");
4980
+ signal == null ? void 0 : signal.throwIfAborted();
4878
4981
  try {
4879
- await postToFirebaseFunction("kickOffBuild", {
4880
- appBuilderLibVersion: config.appBuilderLibVersion,
4881
- appId,
4882
- appPkgName: appPkgJson.name,
4883
- appVersion: appPkgJson.version,
4884
- buildId,
4885
- idToken: await ((_d = currentUser()) == null ? void 0 : _d.getIdToken()),
4886
- linuxImageVersion: (_e = config.linux) == null ? void 0 : _e.imageVersion,
4887
- nodeVersion: config.nodeVersion,
4888
- npmVersion: config.npmVersion,
4889
- pnpmVersion: config.pnpmVersion,
4890
- sourceArchiveDetails,
4891
- userId: primaryUserId
4892
- });
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
+ );
4893
5000
  } catch (e) {
4894
5001
  throw addErrorMessage(e, "Failed while kicking off build");
4895
5002
  }
@@ -4897,6 +5004,7 @@ async function runBuild({
4897
5004
  updateState({ state: "exit-after-uploading" });
4898
5005
  return;
4899
5006
  }
5007
+ signal == null ? void 0 : signal.throwIfAborted();
4900
5008
  const build = await buildObserver.whenSettled();
4901
5009
  if ((build == null ? void 0 : build.status) === "failed" && shouldExitOnBuildFailure_default(build)) {
4902
5010
  updateState({ state: "build-failed" });
@@ -4904,6 +5012,9 @@ async function runBuild({
4904
5012
  }
4905
5013
  function addErrorMessage(e, message2) {
4906
5014
  var _a2, _b;
5015
+ if (CanceledError.isCanceled(e)) {
5016
+ return e;
5017
+ }
4907
5018
  let originalMessage = "";
4908
5019
  if (import_axios2.default.isAxiosError(e) && ((_b = (_a2 = e.response) == null ? void 0 : _a2.data) == null ? void 0 : _b.message)) {
4909
5020
  originalMessage = e.response.data.message;
@@ -4920,6 +5031,13 @@ function addErrorMessage(e, message2) {
4920
5031
  }
4921
5032
  return newError;
4922
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
+ }
4923
5041
 
4924
5042
  // src/commands/build/components/Build.tsx
4925
5043
  var import_jsx_runtime15 = require("react/jsx-runtime");
@@ -4931,11 +5049,19 @@ function Build({
4931
5049
  var _a2, _b, _c, _d, _e, _f;
4932
5050
  const exit = useExit_default();
4933
5051
  const [state, setState] = (0, import_react9.useState)({ state: "initializing" });
5052
+ const [abortController] = (0, import_react9.useState)(() => new AbortController());
4934
5053
  (0, import_react9.useEffect)(() => {
4935
- runBuild({ configPath, flags, updateState }).catch((e) => {
4936
- const error = e.response ? e.response.data : e;
4937
- logForCI(error);
4938
- 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
+ }
4939
5065
  });
4940
5066
  return () => {
4941
5067
  var _a3;
@@ -4960,8 +5086,10 @@ function Build({
4960
5086
  return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ErrorDisplay, { commandUsed, error: "No build is set" });
4961
5087
  }
4962
5088
  return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
4963
- MainLayout_default,
5089
+ MainLayout,
4964
5090
  {
5091
+ abortController,
5092
+ appId: state.appId,
4965
5093
  appName: state.build.appName || ((_a2 = state.appPkg) == null ? void 0 : _a2.name) || "",
4966
5094
  appVersion: state.build.appVersion || ((_b = state.appPkg) == null ? void 0 : _b.version) || "",
4967
5095
  build: state.build,
@@ -4984,8 +5112,10 @@ function Build({
4984
5112
  return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink16.Text, { children: "Getting app info..." });
4985
5113
  case "preparing":
4986
5114
  return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
4987
- MainLayout_default,
5115
+ MainLayout,
4988
5116
  {
5117
+ abortController,
5118
+ appId: state.appId,
4989
5119
  appName: ((_c = state.build) == null ? void 0 : _c.appName) || ((_d = state.appPkg) == null ? void 0 : _d.name) || "",
4990
5120
  appVersion: ((_e = state.build) == null ? void 0 : _e.appVersion) || ((_f = state.appPkg) == null ? void 0 : _f.version) || "",
4991
5121
  build: state.build,
@@ -5284,7 +5414,6 @@ var ErrorBoundary_default = ErrorBoundary;
5284
5414
  // src/commands/build/components/OngoingBuildGuard.tsx
5285
5415
  var import_ink23 = require("ink");
5286
5416
  var import_ink_select_input = __toESM(require("ink-select-input"));
5287
- var import_prop_types9 = __toESM(require("prop-types"));
5288
5417
  var import_react15 = require("react");
5289
5418
 
5290
5419
  // src/components/CustomSelectInputIndicator.tsx
@@ -5523,7 +5652,7 @@ var ViewBuild = ({ commandUsed, id, configPath }) => {
5523
5652
  }));
5524
5653
  };
5525
5654
  return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
5526
- MainLayout_default,
5655
+ MainLayout,
5527
5656
  {
5528
5657
  appId,
5529
5658
  appName: build.appName,
@@ -5558,11 +5687,11 @@ var ViewBuild_default = ViewBuild;
5558
5687
  var import_firestore15 = require("firebase/firestore");
5559
5688
  var import_is_ci5 = __toESM(require("is-ci"));
5560
5689
  var import_jsx_runtime23 = require("react/jsx-runtime");
5561
- var OngoingBuildGuard = ({
5690
+ function OngoingBuildGuard({
5562
5691
  children,
5563
5692
  commandUsed,
5564
5693
  configPath
5565
- }) => {
5694
+ }) {
5566
5695
  const { isRawModeSupported } = (0, import_ink23.useStdin)();
5567
5696
  const exit = useExit_default();
5568
5697
  const [{ appId, builds, error, isLoading, itemChosen }, setState] = (0, import_react15.useState)({
@@ -5572,6 +5701,11 @@ var OngoingBuildGuard = ({
5572
5701
  isLoading: true,
5573
5702
  itemChosen: null
5574
5703
  });
5704
+ const cancellation = useCancellation({
5705
+ appId: appId ?? void 0,
5706
+ build: builds.find(Boolean),
5707
+ autoExit: false
5708
+ });
5575
5709
  (0, import_react15.useEffect)(() => {
5576
5710
  if (!isLoading) {
5577
5711
  return;
@@ -5589,7 +5723,7 @@ var OngoingBuildGuard = ({
5589
5723
  firestore_default,
5590
5724
  `users/${id}/applications/${applicationId}/builds`
5591
5725
  ),
5592
- (0, import_firestore15.where)("createdAt", ">=", twentyFourHoursAgo),
5726
+ (0, import_firestore15.where)("createdAt", ">=", twentyFourHoursAgo.toISOString()),
5593
5727
  (0, import_firestore15.orderBy)("createdAt", "desc"),
5594
5728
  (0, import_firestore15.limit)(10)
5595
5729
  );
@@ -5639,7 +5773,17 @@ var OngoingBuildGuard = ({
5639
5773
  if (itemChosen.value === "view" && build) {
5640
5774
  return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ViewBuild_default, { commandUsed, id: build.id });
5641
5775
  } else if (itemChosen.value === "cancel" && build && appId) {
5642
- 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
+ );
5643
5787
  } else if (itemChosen.value === "concurrent") {
5644
5788
  return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_jsx_runtime23.Fragment, { children });
5645
5789
  } else {
@@ -5669,10 +5813,15 @@ var OngoingBuildGuard = ({
5669
5813
  label: "Exit",
5670
5814
  value: "exit"
5671
5815
  });
5672
- const handleSelect = (selectedItem) => setState((previousState) => ({
5673
- ...previousState,
5674
- itemChosen: selectedItem
5675
- }));
5816
+ const handleSelect = (selectedItem) => {
5817
+ if (selectedItem.value === "cancel") {
5818
+ cancellation.cancel();
5819
+ }
5820
+ setState((previousState) => ({
5821
+ ...previousState,
5822
+ itemChosen: selectedItem
5823
+ }));
5824
+ };
5676
5825
  return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
5677
5826
  /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_ink23.Box, { marginBottom: 1, children: [
5678
5827
  /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_ink23.Text, { bold: true, children: multiple ? "There are ongoing builds " : "There is an ongoing build " }),
@@ -5696,13 +5845,7 @@ var OngoingBuildGuard = ({
5696
5845
  } else {
5697
5846
  return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_jsx_runtime23.Fragment, { children });
5698
5847
  }
5699
- };
5700
- OngoingBuildGuard.propTypes = {
5701
- commandUsed: import_prop_types9.default.string.isRequired,
5702
- children: import_prop_types9.default.oneOfType([import_prop_types9.default.array, import_prop_types9.default.object]),
5703
- configPath: import_prop_types9.default.string
5704
- };
5705
- var OngoingBuildGuard_default = OngoingBuildGuard;
5848
+ }
5706
5849
 
5707
5850
  // src/utilities/useAnalytics.ts
5708
5851
  var import_react16 = require("react");
@@ -5760,7 +5903,7 @@ function BuildCommand({
5760
5903
  webhook: flags.onBuildFinishedWebhook
5761
5904
  });
5762
5905
  const commandUsed = "todesktop build";
5763
- 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)(
5764
5907
  Build,
5765
5908
  {
5766
5909
  commandUsed,
@@ -5772,16 +5915,16 @@ function BuildCommand({
5772
5915
 
5773
5916
  // src/components/ViewBuilds.tsx
5774
5917
  var import_ink29 = require("ink");
5775
- var import_prop_types15 = __toESM(require("prop-types"));
5918
+ var import_prop_types14 = __toESM(require("prop-types"));
5776
5919
  var import_react18 = require("react");
5777
5920
 
5778
5921
  // src/components/Table.tsx
5779
5922
  var import_ink27 = require("ink");
5780
- var import_prop_types14 = __toESM(require("prop-types"));
5923
+ var import_prop_types13 = __toESM(require("prop-types"));
5781
5924
 
5782
5925
  // src/components/TableEnd.tsx
5783
5926
  var import_ink24 = require("ink");
5784
- var import_prop_types10 = __toESM(require("prop-types"));
5927
+ var import_prop_types9 = __toESM(require("prop-types"));
5785
5928
  var import_jsx_runtime25 = require("react/jsx-runtime");
5786
5929
  var TableEnd = ({ keyDetails, ...props }) => {
5787
5930
  let content = "\u2514";
@@ -5790,13 +5933,13 @@ var TableEnd = ({ keyDetails, ...props }) => {
5790
5933
  return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_ink24.Box, { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_ink24.Text, { children: content }) });
5791
5934
  };
5792
5935
  TableEnd.propTypes = {
5793
- keyDetails: import_prop_types10.default.shape({}).isRequired
5936
+ keyDetails: import_prop_types9.default.shape({}).isRequired
5794
5937
  };
5795
5938
  var TableEnd_default = TableEnd;
5796
5939
 
5797
5940
  // src/components/TableHead.tsx
5798
5941
  var import_ink25 = require("ink");
5799
- var import_prop_types11 = __toESM(require("prop-types"));
5942
+ var import_prop_types10 = __toESM(require("prop-types"));
5800
5943
  var import_react17 = require("react");
5801
5944
  var import_jsx_runtime26 = require("react/jsx-runtime");
5802
5945
  var TableHead = ({ keyDetails, ...props }) => {
@@ -5821,17 +5964,17 @@ var TableHead = ({ keyDetails, ...props }) => {
5821
5964
  ] });
5822
5965
  };
5823
5966
  TableHead.propTypes = {
5824
- bottomLinePrefix: import_prop_types11.default.string,
5825
- keyDetails: import_prop_types11.default.shape({}).isRequired
5967
+ bottomLinePrefix: import_prop_types10.default.string,
5968
+ keyDetails: import_prop_types10.default.shape({}).isRequired
5826
5969
  };
5827
5970
  var TableHead_default = TableHead;
5828
5971
 
5829
5972
  // src/components/TableBody.tsx
5830
- var import_prop_types13 = __toESM(require("prop-types"));
5973
+ var import_prop_types12 = __toESM(require("prop-types"));
5831
5974
 
5832
5975
  // src/components/TableRow.tsx
5833
5976
  var import_ink26 = require("ink");
5834
- var import_prop_types12 = __toESM(require("prop-types"));
5977
+ var import_prop_types11 = __toESM(require("prop-types"));
5835
5978
  var import_jsx_runtime27 = require("react/jsx-runtime");
5836
5979
  var TableRow = ({
5837
5980
  data,
@@ -5869,10 +6012,10 @@ var TableRow = ({
5869
6012
  ] });
5870
6013
  };
5871
6014
  TableRow.propTypes = {
5872
- data: import_prop_types12.default.shape({}).isRequired,
5873
- getCellTextProps: import_prop_types12.default.func,
5874
- keyDetails: import_prop_types12.default.shape({}).isRequired,
5875
- 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({})
5876
6019
  };
5877
6020
  var TableRow_default = TableRow;
5878
6021
 
@@ -5903,8 +6046,8 @@ TableBody.propTypes = {
5903
6046
  );
5904
6047
  }
5905
6048
  },
5906
- getCellTextProps: import_prop_types13.default.func,
5907
- keyDetails: import_prop_types13.default.shape({}).isRequired
6049
+ getCellTextProps: import_prop_types12.default.func,
6050
+ keyDetails: import_prop_types12.default.shape({}).isRequired
5908
6051
  };
5909
6052
  var TableBody_default = TableBody;
5910
6053
 
@@ -5954,7 +6097,7 @@ Table.propTypes = {
5954
6097
  );
5955
6098
  }
5956
6099
  },
5957
- getCellTextProps: import_prop_types14.default.func
6100
+ getCellTextProps: import_prop_types13.default.func
5958
6101
  };
5959
6102
  var Table_default = Table;
5960
6103
 
@@ -6224,11 +6367,11 @@ var removeAppBuilderLibConfig = (builds) => {
6224
6367
  });
6225
6368
  };
6226
6369
  ViewBuilds.propTypes = {
6227
- commandUsed: import_prop_types15.default.string.isRequired,
6228
- configPath: import_prop_types15.default.string,
6229
- count: import_prop_types15.default.number,
6230
- format: import_prop_types15.default.string,
6231
- 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
6232
6375
  };
6233
6376
  var ViewBuilds_default = ViewBuilds;
6234
6377
 
@@ -6300,11 +6443,12 @@ function isFirebaseFunctionError(error) {
6300
6443
  typeof error === "object" && error && "code" in error && typeof error.code === "string"
6301
6444
  );
6302
6445
  }
6303
- async function startIntrospectionSession(buildId, platform) {
6446
+ async function startIntrospectionSession(buildId, platform, appId) {
6304
6447
  try {
6305
6448
  const result = await startIntrospectionSessionFn({
6306
6449
  buildId,
6307
- platform
6450
+ platform,
6451
+ appId
6308
6452
  });
6309
6453
  return result.data;
6310
6454
  } catch (error) {
@@ -6443,7 +6587,8 @@ var import_jsx_runtime33 = require("react/jsx-runtime");
6443
6587
  function IntrospectSession({
6444
6588
  buildId,
6445
6589
  platform,
6446
- verbose
6590
+ verbose,
6591
+ appId
6447
6592
  }) {
6448
6593
  const exit = useExit_default();
6449
6594
  const exitRef = (0, import_react19.useRef)(exit);
@@ -6548,7 +6693,8 @@ ${message2}`;
6548
6693
  setStatus("starting-session");
6549
6694
  const sessionResponse = await startIntrospectionSession(
6550
6695
  buildId,
6551
- platform
6696
+ platform,
6697
+ appId
6552
6698
  );
6553
6699
  setJti(sessionResponse.jti);
6554
6700
  if (verbose) {
@@ -6834,7 +6980,7 @@ var import_ink32 = require("ink");
6834
6980
  // src/components/SelectTable.tsx
6835
6981
  var import_ink31 = require("ink");
6836
6982
  var import_ink_select_input2 = __toESM(require("ink-select-input"));
6837
- var import_prop_types16 = __toESM(require("prop-types"));
6983
+ var import_prop_types15 = __toESM(require("prop-types"));
6838
6984
  var import_jsx_runtime34 = require("react/jsx-runtime");
6839
6985
  var CustomIndicator = (props) => /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(CustomSelectInputIndicator, { marginTop: 1, ...props });
6840
6986
  var SelectTable = ({ data, onSelect }) => {
@@ -6893,7 +7039,7 @@ SelectTable.propTypes = {
6893
7039
  );
6894
7040
  }
6895
7041
  },
6896
- onSelect: import_prop_types16.default.func
7042
+ onSelect: import_prop_types15.default.func
6897
7043
  };
6898
7044
  var SelectTable_default = SelectTable;
6899
7045
 
@@ -7389,6 +7535,13 @@ function IntrospectCommand({
7389
7535
  }) {
7390
7536
  const [buildId, setBuildId] = (0, import_react24.useState)(initialBuildId);
7391
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]);
7392
7545
  useAnalyticsCommand("introspect", {
7393
7546
  buildId,
7394
7547
  platform,
@@ -7431,7 +7584,8 @@ function IntrospectCommand({
7431
7584
  {
7432
7585
  buildId,
7433
7586
  platform: normalizedPlatform,
7434
- verbose: verbose ?? false
7587
+ verbose: verbose ?? false,
7588
+ appId
7435
7589
  }
7436
7590
  );
7437
7591
  };
@@ -8758,7 +8912,7 @@ var package_default = {
8758
8912
  access: "public"
8759
8913
  },
8760
8914
  name: "@todesktop/cli",
8761
- version: "1.22.0",
8915
+ version: "1.23.0",
8762
8916
  license: "MIT",
8763
8917
  author: "Dave Jeffery <dave@todesktop.com> (http://www.todesktop.com/)",
8764
8918
  homepage: "https://todesktop.com/cli",