@todesktop/cli 1.14.0 → 1.15.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/README.md CHANGED
@@ -10,7 +10,7 @@ For more information, visit the project [landing page](https://www.todesktop.com
10
10
  - [Get started](#get-started)
11
11
  - [CLI commands](#cli-commands)
12
12
  - [Automating your builds (CI)](#automating-your-builds-ci)
13
- - [Project configuration (todesktop.json or todesktop.js)](#project-configuration-todesktopjson-or-todesktopjs)
13
+ - [Project configuration (todesktop.json, todesktop.js, or todesktop.ts)](#project-configuration-todesktopjson-todesktopjs-or-todesktops)
14
14
  - [Build lifecycle hooks (package.json scripts)](#build-lifecycle-hooks-packagejson-scripts)
15
15
  - [App package.json requirements](#app-packagejson-requirements)
16
16
  - [FAQs](#faqs)
@@ -42,7 +42,7 @@ Create a `todesktop.json` file in the root of your Electron project.
42
42
 
43
43
  ```json
44
44
  {
45
- "$schema": "https://unpkg.com/@todesktop/cli@1.13.0/schemas/schema.json",
45
+ "$schema": "https://unpkg.com/@todesktop/cli@1.14.0/schemas/schema.json",
46
46
  "schemaVersion": 1
47
47
  "id": "your-todesktop-id",
48
48
  "icon": "./desktop-icon.png",
@@ -62,7 +62,26 @@ module.exports = {
62
62
  };
63
63
  ```
64
64
 
65
- See [Project configuration](#project-configuration-todesktopjson-or-todesktopjs) for the full list of configuration options.
65
+ You can also create a `todesktop.ts` file for TypeScript projects with full type checking and IntelliSense:
66
+
67
+ ```typescript
68
+ import type { Schema } from "@todesktop/cli";
69
+ import path from "path";
70
+
71
+ const config: Schema = {
72
+ id: process.env.TODESKTOP_APP_ID || "your-default-todesktop-id",
73
+ icon: path.join(__dirname, "assets", "desktop-icon.png"),
74
+ schemaVersion: 1,
75
+ nodeVersion: "18.12.1",
76
+ mac: {
77
+ category: "public.app-category.productivity",
78
+ },
79
+ };
80
+
81
+ export default config;
82
+ ```
83
+
84
+ See [Project configuration](#project-configuration-todesktopjson-todesktopjs-or-todesktops) for the full list of configuration options.
66
85
 
67
86
  ### Step 3: Add @todesktop/runtime as a dependency
68
87
 
@@ -220,17 +239,27 @@ The webhook receives a POST request with the following JSON body:
220
239
  }
221
240
  ```
222
241
 
223
- ## Project configuration (todesktop.json or todesktop.js)
242
+ ## Project configuration (todesktop.json, todesktop.js, or todesktop.ts)
243
+
244
+ This describes all of the possible configuration options in your `todesktop.json`, `todesktop.js`, or `todesktop.ts` file.
245
+
246
+ You can use:
224
247
 
225
- This describes all of the possible configuration options in your `todesktop.json` or `todesktop.js` file.
248
+ - A standard JSON file (`todesktop.json`) for static configuration
249
+ - A JavaScript file (`todesktop.js`) that exports a configuration object for dynamic configuration
250
+ - A TypeScript file (`todesktop.ts`) that exports a configuration object with full type checking and IntelliSense
226
251
 
227
- You can use a standard JSON file (`todesktop.json`) for static configuration, or a JavaScript file (`todesktop.js`) that exports a configuration object. Using a `.js` file allows for dynamic configuration, such as setting values based on environment variables or computing paths.
252
+ Using `.js` or `.ts` files allows for dynamic configuration, such as setting values based on environment variables or computing paths.
228
253
 
229
- **Note:** Schema validation and IntelliSense (described under [Installation](#installation)) currently only work for `.json` files.
254
+ **Note:**
255
+
256
+ - Schema validation and IntelliSense for `.json` files are available through the JSON schema (described under [Installation](#installation))
257
+ - TypeScript files (`.ts`) provide full type checking and IntelliSense when using the exported `Schema` type from `@todesktop/cli`
258
+ - TypeScript compilation requires a local installation of TypeScript in your project
230
259
 
231
260
  To avoid confusion, the following terms will be used throughout this file:
232
261
 
233
- - "Project root": this is the parent directory of your `todesktop.json` or `todesktop.js`.
262
+ - "Project root": this is the parent directory of your `todesktop.json`, `todesktop.js`, or `todesktop.ts`.
234
263
 
235
264
  ### `$schema` - (optional) string
236
265
 
@@ -243,7 +272,7 @@ To enable JSON validation and IntelliSense for your `todesktop.json` file in com
243
272
  - For example, if using a hosted version of the schema:
244
273
  ```json
245
274
  {
246
- "$schema": "https://unpkg.com/@todesktop/cli@1.13.0/schemas/schema.json",
275
+ "$schema": "https://unpkg.com/@todesktop/cli@1.14.0/schemas/schema.json",
247
276
  "id": "your-todesktop-id"
248
277
  }
249
278
  ```
@@ -1305,6 +1334,12 @@ Now, when we build your app on ToDesktop servers, it will also run your custom `
1305
1334
 
1306
1335
  ## Changelog
1307
1336
 
1337
+ ### v1.15.0
1338
+
1339
+ - Add support for `todesktop.ts` configuration file with full TypeScript type checking and IntelliSense.
1340
+ - Export `Schema` type from `@todesktop/cli` for TypeScript configuration files.
1341
+ - TypeScript compilation uses user's local TypeScript installation (no production dependencies added).
1342
+
1308
1343
  ### v1.14.0
1309
1344
 
1310
1345
  - Add support for `todesktop.js` configuration file for dynamic configurations.
package/dist/cli.js CHANGED
@@ -344,9 +344,9 @@ var useExit_default = () => {
344
344
  logger_default.debug({ error }, "Exit called");
345
345
  let timeoutId;
346
346
  Promise.race([
347
- new Promise((resolve4) => flush(() => resolve4())),
347
+ new Promise((resolve5) => flush(() => resolve5())),
348
348
  new Promise(
349
- (resolve4) => timeoutId = setTimeout(() => resolve4(), 1e3)
349
+ (resolve5) => timeoutId = setTimeout(() => resolve5(), 1e3)
350
350
  )
351
351
  ]).catch(() => {
352
352
  }).finally(() => {
@@ -1025,10 +1025,101 @@ async function postToFirebaseFunction_default(functionName, body = {}, config2 =
1025
1025
  // src/utilities/projectConfig/getProjectConfig.ts
1026
1026
  var import_find_up = __toESM(require("find-up"));
1027
1027
  var import_fs = require("fs");
1028
+ var import_path5 = require("path");
1029
+
1030
+ // src/utilities/projectConfig/loadConfig.ts
1028
1031
  var import_path3 = require("path");
1029
1032
 
1033
+ // src/utilities/projectConfig/loadTypeScriptConfig.ts
1034
+ var import_path2 = require("path");
1035
+ function loadTypeScriptConfig(configPath) {
1036
+ const projectRoot = process.cwd();
1037
+ try {
1038
+ logger_default.debug(`Attempting to load TypeScript config from: ${configPath}`);
1039
+ let typescript;
1040
+ try {
1041
+ const tsPath = (0, import_path2.resolve)(projectRoot, "node_modules", "typescript");
1042
+ typescript = require(tsPath);
1043
+ logger_default.debug(`Found TypeScript in user's project at: ${tsPath}`);
1044
+ } catch (error) {
1045
+ try {
1046
+ typescript = require("typescript");
1047
+ logger_default.debug("Using globally available TypeScript installation");
1048
+ } catch (globalError) {
1049
+ throw new Error(
1050
+ `TypeScript is required to load .ts configuration files but was not found. Please install TypeScript in your project: npm install --save-dev typescript`
1051
+ );
1052
+ }
1053
+ }
1054
+ const fs6 = require("fs");
1055
+ const sourceCode = fs6.readFileSync(configPath, "utf8");
1056
+ const result = typescript.transpile(sourceCode, {
1057
+ target: typescript.ScriptTarget.ES2018,
1058
+ module: typescript.ModuleKind.CommonJS,
1059
+ moduleResolution: typescript.ModuleResolutionKind.NodeJs,
1060
+ esModuleInterop: true,
1061
+ allowSyntheticDefaultImports: true,
1062
+ resolveJsonModule: true,
1063
+ declaration: false,
1064
+ sourceMap: false
1065
+ });
1066
+ const module2 = { exports: {} };
1067
+ const moduleWrapper = new Function(
1068
+ "module",
1069
+ "exports",
1070
+ "require",
1071
+ "__filename",
1072
+ "__dirname",
1073
+ result
1074
+ );
1075
+ moduleWrapper(
1076
+ module2,
1077
+ module2.exports,
1078
+ (id) => {
1079
+ if (id.startsWith(".")) {
1080
+ return require((0, import_path2.resolve)(configPath, "..", id));
1081
+ }
1082
+ return require(id);
1083
+ },
1084
+ configPath,
1085
+ (0, import_path2.resolve)(configPath, "..")
1086
+ );
1087
+ const config2 = module2.exports.default || module2.exports;
1088
+ if (!config2 || typeof config2 !== "object") {
1089
+ throw new Error(
1090
+ `TypeScript configuration file must export a configuration object. Received: ${typeof config2}`
1091
+ );
1092
+ }
1093
+ logger_default.debug("Successfully loaded and compiled TypeScript configuration");
1094
+ return config2;
1095
+ } catch (error) {
1096
+ logger_default.error(
1097
+ `Failed to load TypeScript configuration from ${configPath}:`,
1098
+ error
1099
+ );
1100
+ if (error instanceof Error) {
1101
+ if (error.message.includes("Cannot find module")) {
1102
+ throw new Error(
1103
+ `Failed to load TypeScript configuration: ${error.message}. Make sure all imported modules are installed.`
1104
+ );
1105
+ } else if (error.message.includes("TypeScript is required")) {
1106
+ throw error;
1107
+ } else {
1108
+ throw new Error(
1109
+ `Failed to compile TypeScript configuration: ${error.message}. Please check your todesktop.ts file for syntax errors.`
1110
+ );
1111
+ }
1112
+ }
1113
+ throw error;
1114
+ }
1115
+ }
1116
+
1030
1117
  // src/utilities/projectConfig/loadConfig.ts
1031
1118
  function loadConfig(configPath) {
1119
+ const extension = (0, import_path3.extname)(configPath);
1120
+ if (extension === ".ts") {
1121
+ return loadTypeScriptConfig(configPath);
1122
+ }
1032
1123
  return require(configPath);
1033
1124
  }
1034
1125
 
@@ -2469,14 +2560,14 @@ ${output}`
2469
2560
 
2470
2561
  // src/utilities/projectConfig/computeFullProjectConfig.ts
2471
2562
  var import_lodash2 = __toESM(require("lodash.merge"));
2472
- var import_path2 = require("path");
2563
+ var import_path4 = require("path");
2473
2564
  function computeFullProjectConfig(partialConfig, projectRoot, flags) {
2474
2565
  if (!partialConfig.extends) {
2475
2566
  logger_default.debug("No extends field, returning partial config");
2476
2567
  return partialConfig;
2477
2568
  } else {
2478
2569
  logger_default.debug("Extends field found, resolving");
2479
- const parentConfigPath = (0, import_path2.resolve)(projectRoot, partialConfig.extends);
2570
+ const parentConfigPath = (0, import_path4.resolve)(projectRoot, partialConfig.extends);
2480
2571
  const parentConfig = loadConfig(parentConfigPath);
2481
2572
  parentConfig.appPath = parentConfig.appPath || ".";
2482
2573
  const parentFullConfig = computeFullProjectConfig(
@@ -2510,20 +2601,24 @@ You can disable this error by running todesktop build with the --ignore-extends-
2510
2601
  function getProjectConfig(configPath, flags) {
2511
2602
  if (!configPath) {
2512
2603
  logger_default.debug("No config path provided, searching for one");
2513
- configPath = import_find_up.default.sync(["todesktop.json", "todesktop.js"]);
2604
+ configPath = import_find_up.default.sync([
2605
+ "todesktop.json",
2606
+ "todesktop.js",
2607
+ "todesktop.ts"
2608
+ ]);
2514
2609
  if (!configPath) {
2515
2610
  throw new Error(
2516
- "Can not find todesktop.json or todesktop.js in this folder or any parent folders"
2611
+ "Can not find todesktop.json, todesktop.js, or todesktop.ts in this folder or any parent folders"
2517
2612
  );
2518
2613
  }
2519
2614
  } else {
2520
- configPath = (0, import_path3.resolve)(process.cwd(), configPath);
2615
+ configPath = (0, import_path5.resolve)(process.cwd(), configPath);
2521
2616
  if (!(0, import_fs.existsSync)(configPath)) {
2522
2617
  logger_default.error("Provided config path does not exist");
2523
2618
  throw new Error(`Config file not found at ${configPath}`);
2524
2619
  }
2525
2620
  }
2526
- const projectRoot = (0, import_path3.dirname)(configPath);
2621
+ const projectRoot = (0, import_path5.dirname)(configPath);
2527
2622
  const partialConfig = loadConfig(configPath);
2528
2623
  const config2 = computeFullProjectConfig(partialConfig, projectRoot, flags);
2529
2624
  validateConfig({ config: config2, projectRoot });
@@ -2544,7 +2639,7 @@ var shouldExitOnBuildFailure_default = (build) => {
2544
2639
 
2545
2640
  // src/commands/build/utilities/getPackageJson.ts
2546
2641
  var import_lodash3 = __toESM(require("lodash.merge"));
2547
- var import_path4 = __toESM(require("path"));
2642
+ var import_path6 = __toESM(require("path"));
2548
2643
  function deleteNullDeps(dep) {
2549
2644
  Object.keys(dep).forEach((key) => {
2550
2645
  if (dep[key] === null) {
@@ -2566,7 +2661,7 @@ function removeNullDependencies(pkgJson) {
2566
2661
  function getAppPkgJson({ config: config2 }) {
2567
2662
  const packageJsonFromConfig = config2.packageJson || {};
2568
2663
  const extendsFrom = packageJsonFromConfig.extends || "package.json";
2569
- const packageJsonFromFile = readJson(import_path4.default.join(config2.appPath, extendsFrom));
2664
+ const packageJsonFromFile = readJson(import_path6.default.join(config2.appPath, extendsFrom));
2570
2665
  return removeNullDependencies(
2571
2666
  (0, import_lodash3.default)({}, packageJsonFromFile, packageJsonFromConfig)
2572
2667
  );
@@ -2606,10 +2701,10 @@ function spyBuild() {
2606
2701
  if (latestBuildDoc && predicate(latestBuildDoc)) {
2607
2702
  return Promise.resolve(latestBuildDoc);
2608
2703
  }
2609
- return new Promise((resolve4, reject) => {
2704
+ return new Promise((resolve5, reject) => {
2610
2705
  emitter.on("update", ({ build }) => {
2611
2706
  if (predicate(build)) {
2612
- resolve4(build);
2707
+ resolve5(build);
2613
2708
  }
2614
2709
  }).once("error", (e) => reject(e));
2615
2710
  });
@@ -2645,8 +2740,8 @@ function spyBuild() {
2645
2740
  if (latestBuildDoc) {
2646
2741
  return Promise.resolve(latestBuildDoc);
2647
2742
  }
2648
- return new Promise((resolve4, reject) => {
2649
- emitter.once("update", (data) => resolve4(data)).once("error", (e) => reject(e));
2743
+ return new Promise((resolve5, reject) => {
2744
+ emitter.once("update", (data) => resolve5(data)).once("error", (e) => reject(e));
2650
2745
  });
2651
2746
  },
2652
2747
  async whenSettled() {
@@ -2677,7 +2772,7 @@ var import_stream_to_array = __toESM(require("stream-to-array"));
2677
2772
  var { TODESKTOP_CLI_S3_BUCKET } = getEnvironmentVariables_default();
2678
2773
  var MAX_RETRIES = 3;
2679
2774
  var RETRY_DELAY = 2e3;
2680
- var delay = (ms) => new Promise((resolve4) => setTimeout(resolve4, ms));
2775
+ var delay = (ms) => new Promise((resolve5) => setTimeout(resolve5, ms));
2681
2776
  var uploadToS3WithRetry = async (input, retries = MAX_RETRIES) => {
2682
2777
  try {
2683
2778
  return await uploadToS3(input);
@@ -2711,14 +2806,14 @@ var uploadToS3 = async ({
2711
2806
  (part) => Buffer.isBuffer(part) ? part : Buffer.from(part)
2712
2807
  );
2713
2808
  const body = Buffer.concat(buffers);
2714
- return new Promise((resolve4, reject) => {
2809
+ return new Promise((resolve5, reject) => {
2715
2810
  import_superagent.default.put(data.signedURL).send(body).set("content-type", "application/zip").on("progress", onProgress).end((err) => {
2716
2811
  logger_default.debug({ bucket, key, url: data.uploadURL }, "uploadToS3");
2717
2812
  if (err) {
2718
2813
  logger_default.error({ err }, "uploadToS3");
2719
2814
  return reject(err);
2720
2815
  }
2721
- return resolve4({ bucket, key, url: data.uploadURL });
2816
+ return resolve5({ bucket, key, url: data.uploadURL });
2722
2817
  });
2723
2818
  });
2724
2819
  };
@@ -2729,7 +2824,7 @@ var import_archiver = __toESM(require("archiver"));
2729
2824
  var import_du = __toESM(require("du"));
2730
2825
  var import_fs2 = __toESM(require("fs"));
2731
2826
  var import_chalk = __toESM(require("chalk"));
2732
- var import_path5 = __toESM(require("path"));
2827
+ var import_path7 = __toESM(require("path"));
2733
2828
  async function zip_default({
2734
2829
  files,
2735
2830
  fileSizeLimit = 20,
@@ -2784,7 +2879,7 @@ Your app is larger than ${fileSizeLimit}MB. Your app is ${import_chalk.default.b
2784
2879
  processedFiles.forEach(({ from, isDirectory, stats, to }) => {
2785
2880
  if (isDirectory) {
2786
2881
  stream.directory(from, to);
2787
- } else if (appPkgJson && to === import_path5.default.join("app", "package.json")) {
2882
+ } else if (appPkgJson && to === import_path7.default.join("app", "package.json")) {
2788
2883
  stream.append(JSON.stringify(appPkgJson), {
2789
2884
  name: to
2790
2885
  });
@@ -3583,7 +3678,7 @@ async function getLatestBuildId({
3583
3678
  // src/utilities/subscribeToFirebaseDoc.ts
3584
3679
  var import_firestore10 = require("firebase/firestore");
3585
3680
  async function subscribeToFirebaseDoc(key, receiver) {
3586
- return new Promise((resolve4, reject) => {
3681
+ return new Promise((resolve5, reject) => {
3587
3682
  logger_default.debug({ key }, "subscribeToFirebaseDoc");
3588
3683
  const unsubscribe = (0, import_firestore10.onSnapshot)(
3589
3684
  (0, import_firestore10.doc)(firestore_default, key),
@@ -3592,7 +3687,7 @@ async function subscribeToFirebaseDoc(key, receiver) {
3592
3687
  snapshot,
3593
3688
  data: snapshot.exists() ? snapshot.data() : void 0
3594
3689
  });
3595
- resolve4(unsubscribe);
3690
+ resolve5(unsubscribe);
3596
3691
  },
3597
3692
  (err) => {
3598
3693
  reject(err);
@@ -5689,7 +5784,7 @@ async function waitUntilFinished({
5689
5784
  userId
5690
5785
  }) {
5691
5786
  const docPath = `users/${userId}/applications/${appId}/builds/${buildId}`;
5692
- return new Promise((resolve4, reject) => {
5787
+ return new Promise((resolve5, reject) => {
5693
5788
  const unsubscribe = (0, import_firestore27.onSnapshot)(
5694
5789
  (0, import_firestore27.doc)(firestore_default, docPath),
5695
5790
  (snapshot) => {
@@ -5698,7 +5793,7 @@ async function waitUntilFinished({
5698
5793
  onProgress(progress);
5699
5794
  if (progress.isFinished) {
5700
5795
  unsubscribe();
5701
- resolve4(progress);
5796
+ resolve5(progress);
5702
5797
  }
5703
5798
  },
5704
5799
  (err) => {
@@ -5897,7 +5992,7 @@ var package_default = {
5897
5992
  access: "public"
5898
5993
  },
5899
5994
  name: "@todesktop/cli",
5900
- version: "1.13.0",
5995
+ version: "1.14.0",
5901
5996
  license: "MIT",
5902
5997
  author: "Dave Jeffery <dave@todesktop.com> (http://www.todesktop.com/)",
5903
5998
  homepage: "https://todesktop.com/cli",
@@ -5907,6 +6002,7 @@ var package_default = {
5907
6002
  bin: {
5908
6003
  todesktop: "./dist/cli.js"
5909
6004
  },
6005
+ types: "./dist/types.d.ts",
5910
6006
  engines: {
5911
6007
  node: ">=16"
5912
6008
  },
@@ -5914,14 +6010,15 @@ var package_default = {
5914
6010
  dev: "cp-cli dev.env .env && npm run build:dev && npm link",
5915
6011
  "dev:prod": "cp-cli prod.env .env && npm run build && npm link",
5916
6012
  "dev:local:prod": "cp-cli prod-local.env .env && npm run build && npm link && cp-cli prod-local.env .env",
5917
- build: "esbuild src/index.ts --packages=external --bundle --sourcemap --platform=node --outfile=dist/cli.js && cp-cli prod.env .env",
5918
- "build:dev": "esbuild src/index.ts --packages=external --bundle --sourcemap --platform=node --outfile=dist/cli.js && cp-cli dev.env .env",
6013
+ build: "npm run types:generate && esbuild src/index.ts --packages=external --bundle --sourcemap --platform=node --outfile=dist/cli.js && cp-cli prod.env .env",
6014
+ "build:dev": "npm run types:generate && esbuild src/index.ts --packages=external --bundle --sourcemap --platform=node --outfile=dist/cli.js && cp-cli dev.env .env",
5919
6015
  lint: "npm run lint:types && npm run lint:styles",
5920
6016
  "lint:styles": "eslint src test .eslintrc.js && prettier --check .",
5921
6017
  format: "prettier --write .",
5922
6018
  "lint:types": "tsc && tsc-strict",
5923
6019
  "lint--fix": "eslint src test --fix",
5924
6020
  "docs:generate": "node scripts/generate-readme.js",
6021
+ "types:generate": "node scripts/generate-types.js",
5925
6022
  release: "npm run docs:generate && npm run build && npx np --tag=latest",
5926
6023
  "release-beta": "npm run docs:generate && npm run build && npx np --any-branch --no-tests --tag=beta",
5927
6024
  test: "ava",
@@ -6005,6 +6102,7 @@ var package_default = {
6005
6102
  "fs-extra": "^9.0.1",
6006
6103
  husky: "^4.3.0",
6007
6104
  "ink-testing-library": "^2.1.0",
6105
+ "json-schema-to-typescript": "^15.0.4",
6008
6106
  "lint-staged": "^10.2.11",
6009
6107
  "package-json-type": "^1.0.3",
6010
6108
  prettier: "^2.8.1",