@todesktop/cli 1.5.1 → 1.6.1
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 +4430 -0
- package/dist/cli.js.map +7 -0
- package/package.json +41 -41
- package/build/boot.js +0 -126
- package/build/cli.js +0 -11
- package/build/cli.js.bak +0 -11
- package/build/commands/build.js +0 -124
- package/build/commands/build.js.map +0 -1
- package/build/commands/builds.js +0 -116
- package/build/commands/builds.js.map +0 -1
- package/build/commands/logout.js +0 -60
- package/build/commands/logout.js.map +0 -1
- package/build/commands/release.js +0 -94
- package/build/commands/release.js.map +0 -1
- package/build/commands/whoami.js +0 -60
- package/build/commands/whoami.js.map +0 -1
- package/build/commands.json +0 -152
package/dist/cli.js
ADDED
|
@@ -0,0 +1,4430 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
10
|
+
for (let key of __getOwnPropNames(from))
|
|
11
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
12
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
13
|
+
}
|
|
14
|
+
return to;
|
|
15
|
+
};
|
|
16
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
17
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
18
|
+
mod
|
|
19
|
+
));
|
|
20
|
+
|
|
21
|
+
// src/index.ts
|
|
22
|
+
var import_commander = require("commander");
|
|
23
|
+
var import_ink33 = require("ink");
|
|
24
|
+
var import_react21 = require("react");
|
|
25
|
+
var import_register = require("source-map-support/register");
|
|
26
|
+
|
|
27
|
+
// src/components/Build.tsx
|
|
28
|
+
var import_react6 = require("react");
|
|
29
|
+
var import_prop_types9 = __toESM(require("prop-types"));
|
|
30
|
+
|
|
31
|
+
// src/components/BuildProgress.tsx
|
|
32
|
+
var import_ink4 = require("ink");
|
|
33
|
+
var import_prop_types3 = __toESM(require("prop-types"));
|
|
34
|
+
var import_react2 = require("react");
|
|
35
|
+
var import_lodash = __toESM(require("lodash.throttle"));
|
|
36
|
+
|
|
37
|
+
// src/components/BuildCompleteMessage.tsx
|
|
38
|
+
var import_ink2 = require("ink");
|
|
39
|
+
var import_ink_link = __toESM(require("ink-link"));
|
|
40
|
+
var import_prop_types = __toESM(require("prop-types"));
|
|
41
|
+
var import_react = require("react");
|
|
42
|
+
|
|
43
|
+
// src/utilities/logForCI.ts
|
|
44
|
+
var import_is_ci = __toESM(require("is-ci"));
|
|
45
|
+
|
|
46
|
+
// src/utilities/logger.ts
|
|
47
|
+
var import_bunyan = __toESM(require("bunyan"));
|
|
48
|
+
var fs = __toESM(require("fs"));
|
|
49
|
+
var os = __toESM(require("os"));
|
|
50
|
+
var path = __toESM(require("path"));
|
|
51
|
+
var Sentry = __toESM(require("@sentry/node"));
|
|
52
|
+
var logger;
|
|
53
|
+
try {
|
|
54
|
+
const name = "todesktop-cli";
|
|
55
|
+
let parentDirectory;
|
|
56
|
+
const homePath = os.homedir();
|
|
57
|
+
if (process.platform === "darwin") {
|
|
58
|
+
parentDirectory = path.join(homePath, "Library", "Logs", name);
|
|
59
|
+
} else if (process.platform === "win32") {
|
|
60
|
+
parentDirectory = path.join(
|
|
61
|
+
process.env.APPDATA || path.join(homePath, "AppData", "Roaming"),
|
|
62
|
+
name,
|
|
63
|
+
"logs"
|
|
64
|
+
);
|
|
65
|
+
} else {
|
|
66
|
+
parentDirectory = path.join(
|
|
67
|
+
process.env.XDG_CONFIG_HOME || path.join(homePath, ".config"),
|
|
68
|
+
name,
|
|
69
|
+
"logs"
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
fs.mkdirSync(parentDirectory, { recursive: true });
|
|
73
|
+
logger = import_bunyan.default.createLogger({
|
|
74
|
+
name,
|
|
75
|
+
src: true,
|
|
76
|
+
streams: [
|
|
77
|
+
{
|
|
78
|
+
level: "debug",
|
|
79
|
+
path: path.join(parentDirectory, "main.log")
|
|
80
|
+
}
|
|
81
|
+
]
|
|
82
|
+
});
|
|
83
|
+
} catch (e) {
|
|
84
|
+
const noOp = () => {
|
|
85
|
+
};
|
|
86
|
+
logger = {
|
|
87
|
+
debug: noOp,
|
|
88
|
+
error: noOp,
|
|
89
|
+
fatal: noOp,
|
|
90
|
+
info: noOp,
|
|
91
|
+
trace: noOp,
|
|
92
|
+
warn: noOp
|
|
93
|
+
};
|
|
94
|
+
try {
|
|
95
|
+
Sentry.captureException(e);
|
|
96
|
+
} catch (err) {
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
var logger_default = logger;
|
|
100
|
+
|
|
101
|
+
// src/utilities/logForCI.ts
|
|
102
|
+
var logForCI_default = (...args2) => {
|
|
103
|
+
logger_default.info({ args: args2 }, "logForCI");
|
|
104
|
+
if (import_is_ci.default || !process.stdin.isTTY) {
|
|
105
|
+
console.log(...args2);
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
// src/utilities/useExit.ts
|
|
110
|
+
var import_ink = require("ink");
|
|
111
|
+
|
|
112
|
+
// src/utilities/analytics.ts
|
|
113
|
+
var import_os = __toESM(require("os"));
|
|
114
|
+
var import_uuid = require("uuid");
|
|
115
|
+
var import_analytics_node = __toESM(require("analytics-node"));
|
|
116
|
+
|
|
117
|
+
// src/utilities/getEnvironmentVariables.ts
|
|
118
|
+
var import_dotenv = __toESM(require("dotenv"));
|
|
119
|
+
var import_path = __toESM(require("path"));
|
|
120
|
+
var hasInitialized = false;
|
|
121
|
+
var init = () => {
|
|
122
|
+
if (hasInitialized) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
import_dotenv.default.config({
|
|
126
|
+
path: import_path.default.resolve(__dirname, "../.env")
|
|
127
|
+
});
|
|
128
|
+
hasInitialized = true;
|
|
129
|
+
};
|
|
130
|
+
var getEnvironmentVariables_default = () => {
|
|
131
|
+
init();
|
|
132
|
+
return process.env;
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
// src/utilities/firestore.ts
|
|
136
|
+
var import_app = __toESM(require("firebase/app"));
|
|
137
|
+
var import_firestore = require("firebase/firestore");
|
|
138
|
+
var import_auth = require("firebase/auth");
|
|
139
|
+
var environmentVariables = getEnvironmentVariables_default();
|
|
140
|
+
var firebaseDB = import_app.default.initializeApp({
|
|
141
|
+
apiKey: environmentVariables.TODESKTOP_CLI_FIREBASE_API_KEY,
|
|
142
|
+
authDomain: environmentVariables.TODESKTOP_CLI_FIREBASE_AUTH_DOMAIN,
|
|
143
|
+
databaseURL: environmentVariables.TODESKTOP_CLI_FIREBASE_DATABASE_URL,
|
|
144
|
+
projectId: environmentVariables.TODESKTOP_CLI_FIREBASE_PROJECT_ID,
|
|
145
|
+
storageBucket: environmentVariables.TODESKTOP_CLI_FIREBASE_STORAGE_BUCKET,
|
|
146
|
+
messagingSenderId: environmentVariables.TODESKTOP_CLI_FIREBASE_MESSAGING_SENDER_ID,
|
|
147
|
+
appId: environmentVariables.TODESKTOP_CLI_FIREBASE_ID
|
|
148
|
+
});
|
|
149
|
+
var currentUser = () => import_app.default.auth().currentUser;
|
|
150
|
+
var signInWithCustomToken = async (token) => {
|
|
151
|
+
return import_app.default.auth().signInWithCustomToken(token);
|
|
152
|
+
};
|
|
153
|
+
var onUserAuth = (handler) => import_app.default.auth().onAuthStateChanged((user) => {
|
|
154
|
+
handler(user || {});
|
|
155
|
+
});
|
|
156
|
+
var firestore_default = firebaseDB.firestore();
|
|
157
|
+
|
|
158
|
+
// src/utilities/configStore.ts
|
|
159
|
+
var fs2 = __toESM(require("fs"));
|
|
160
|
+
var import_del = __toESM(require("del"));
|
|
161
|
+
var import_conf = __toESM(require("conf"));
|
|
162
|
+
var import_xdg_basedir = __toESM(require("xdg-basedir"));
|
|
163
|
+
var config = new import_conf.default({ configName: "todesktop-cli" });
|
|
164
|
+
var accessTokenConfigKey = "accessToken";
|
|
165
|
+
var emailConfigKey = "email";
|
|
166
|
+
var jwtTokenConfigKey = "jwtToken";
|
|
167
|
+
var setConfig = (key, value) => config.set(key, value);
|
|
168
|
+
var getConfig = (key) => config.get(key);
|
|
169
|
+
var setAuthConfig = (email, accessToken, jwtToken) => {
|
|
170
|
+
setConfig(emailConfigKey, email);
|
|
171
|
+
setConfig(accessTokenConfigKey, accessToken);
|
|
172
|
+
setConfig(jwtTokenConfigKey, jwtToken);
|
|
173
|
+
};
|
|
174
|
+
var getAuthConfig = () => {
|
|
175
|
+
const accessToken = getConfig(accessTokenConfigKey);
|
|
176
|
+
const jwtToken = getConfig(jwtTokenConfigKey);
|
|
177
|
+
const email = getConfig(emailConfigKey);
|
|
178
|
+
return { accessToken, jwtToken, email };
|
|
179
|
+
};
|
|
180
|
+
var deleteAuthConfig = () => {
|
|
181
|
+
config.delete(emailConfigKey);
|
|
182
|
+
config.delete(accessTokenConfigKey);
|
|
183
|
+
config.delete(jwtTokenConfigKey);
|
|
184
|
+
};
|
|
185
|
+
var oldConfigPath = `${import_xdg_basedir.default.config}/configstore/config.json.json`;
|
|
186
|
+
if (fs2.existsSync(oldConfigPath)) {
|
|
187
|
+
try {
|
|
188
|
+
const { email, accessToken, jwtToken } = require(oldConfigPath);
|
|
189
|
+
setAuthConfig(email, accessToken, jwtToken);
|
|
190
|
+
(0, import_del.default)(oldConfigPath, { force: true });
|
|
191
|
+
} catch (err) {
|
|
192
|
+
(0, import_del.default)(oldConfigPath, { force: true });
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// src/utilities/getToDesktopPackageJson.ts
|
|
197
|
+
var import_pkg_up = __toESM(require("pkg-up"));
|
|
198
|
+
|
|
199
|
+
// src/utilities/readJson.ts
|
|
200
|
+
function readJson(filePath) {
|
|
201
|
+
return require(filePath);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// src/utilities/getToDesktopPackageJson.ts
|
|
205
|
+
var packageJson = readJson(
|
|
206
|
+
import_pkg_up.default.sync({ cwd: __dirname })
|
|
207
|
+
);
|
|
208
|
+
function getToDesktopPackageJson() {
|
|
209
|
+
return packageJson;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// src/utilities/getCliVersion.ts
|
|
213
|
+
var cliVersion = getToDesktopPackageJson().version;
|
|
214
|
+
var getCliVersion_default = () => cliVersion;
|
|
215
|
+
|
|
216
|
+
// src/utilities/analytics.ts
|
|
217
|
+
var environmentVariables2 = getEnvironmentVariables_default();
|
|
218
|
+
var analytics = new import_analytics_node.default(environmentVariables2.SEGMENT_WRITE_KEY, {
|
|
219
|
+
flushAt: 1,
|
|
220
|
+
flushInterval: 1
|
|
221
|
+
});
|
|
222
|
+
var ANALYTICS_EVENT = {
|
|
223
|
+
CLI_COMMAND: "CLI Command"
|
|
224
|
+
};
|
|
225
|
+
function getAnalyticsBaseProperties() {
|
|
226
|
+
const baseProps = {
|
|
227
|
+
app: {
|
|
228
|
+
cliVersion: ""
|
|
229
|
+
},
|
|
230
|
+
client: "cli",
|
|
231
|
+
user: {
|
|
232
|
+
email: ""
|
|
233
|
+
},
|
|
234
|
+
os: {
|
|
235
|
+
name: "",
|
|
236
|
+
version: ""
|
|
237
|
+
},
|
|
238
|
+
runtime: {
|
|
239
|
+
name: "Node.js",
|
|
240
|
+
version: ""
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
try {
|
|
244
|
+
baseProps.os = {
|
|
245
|
+
name: import_os.default.platform(),
|
|
246
|
+
version: import_os.default.release()
|
|
247
|
+
};
|
|
248
|
+
} catch (err) {
|
|
249
|
+
}
|
|
250
|
+
try {
|
|
251
|
+
baseProps.user = {
|
|
252
|
+
email: getAuthConfig().email
|
|
253
|
+
};
|
|
254
|
+
} catch (err) {
|
|
255
|
+
}
|
|
256
|
+
try {
|
|
257
|
+
baseProps.app = {
|
|
258
|
+
cliVersion: getCliVersion_default()
|
|
259
|
+
};
|
|
260
|
+
} catch (err) {
|
|
261
|
+
}
|
|
262
|
+
try {
|
|
263
|
+
baseProps.runtime = {
|
|
264
|
+
name: "Node.js",
|
|
265
|
+
version: process.version
|
|
266
|
+
};
|
|
267
|
+
} catch (err) {
|
|
268
|
+
}
|
|
269
|
+
return baseProps;
|
|
270
|
+
}
|
|
271
|
+
var anonymousId = (0, import_uuid.v4)();
|
|
272
|
+
var track = (event, properties = {}, callback = () => {
|
|
273
|
+
}) => {
|
|
274
|
+
try {
|
|
275
|
+
const user = currentUser();
|
|
276
|
+
analytics.track(
|
|
277
|
+
{
|
|
278
|
+
event,
|
|
279
|
+
userId: user ? user.uid : void 0,
|
|
280
|
+
anonymousId,
|
|
281
|
+
properties: {
|
|
282
|
+
...properties,
|
|
283
|
+
...getAnalyticsBaseProperties()
|
|
284
|
+
}
|
|
285
|
+
},
|
|
286
|
+
callback
|
|
287
|
+
);
|
|
288
|
+
} catch (err) {
|
|
289
|
+
}
|
|
290
|
+
};
|
|
291
|
+
var identify = (id, traits = {}, callback = () => {
|
|
292
|
+
}) => {
|
|
293
|
+
try {
|
|
294
|
+
analytics.identify({ userId: id, anonymousId, traits }, callback);
|
|
295
|
+
} catch (err) {
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
var flush = (callback = () => {
|
|
299
|
+
}) => analytics.flush(callback);
|
|
300
|
+
|
|
301
|
+
// src/utilities/useExit.ts
|
|
302
|
+
var useExit_default = () => {
|
|
303
|
+
const { exit } = (0, import_ink.useApp)();
|
|
304
|
+
return (error = void 0) => {
|
|
305
|
+
logger_default.debug({ error }, "Exit called");
|
|
306
|
+
firestore_default.terminate().catch(
|
|
307
|
+
(e) => logger_default.error(e)
|
|
308
|
+
);
|
|
309
|
+
let timeoutId;
|
|
310
|
+
Promise.race([
|
|
311
|
+
new Promise((resolve4) => flush(() => resolve4())),
|
|
312
|
+
new Promise(
|
|
313
|
+
(resolve4) => timeoutId = setTimeout(() => resolve4(), 1e3)
|
|
314
|
+
)
|
|
315
|
+
]).catch(() => {
|
|
316
|
+
}).finally(() => {
|
|
317
|
+
clearTimeout(timeoutId);
|
|
318
|
+
try {
|
|
319
|
+
exit();
|
|
320
|
+
} catch (e) {
|
|
321
|
+
logger_default.error(e);
|
|
322
|
+
}
|
|
323
|
+
setTimeout(() => process.exit(error ? 1 : 0), 10);
|
|
324
|
+
});
|
|
325
|
+
};
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
// src/components/BuildCompleteMessage.tsx
|
|
329
|
+
var import_path2 = __toESM(require("path"));
|
|
330
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
331
|
+
var addTrailingSlash = (url) => {
|
|
332
|
+
return url.endsWith("/") ? url : `${url}/`;
|
|
333
|
+
};
|
|
334
|
+
var BuildCompleteMessage = ({ build }) => {
|
|
335
|
+
const exit = useExit_default();
|
|
336
|
+
let url = build.standardUniversalDownloadUrl;
|
|
337
|
+
if (process.platform === "darwin") {
|
|
338
|
+
url = new URL(
|
|
339
|
+
import_path2.default.posix.join("mac", "zip", process.arch),
|
|
340
|
+
addTrailingSlash(url)
|
|
341
|
+
).href;
|
|
342
|
+
}
|
|
343
|
+
logForCI_default(`Build complete! ${url}`);
|
|
344
|
+
(0, import_react.useEffect)(() => {
|
|
345
|
+
if (url) {
|
|
346
|
+
setTimeout(exit, 10);
|
|
347
|
+
}
|
|
348
|
+
}, [exit, url]);
|
|
349
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink2.Box, { marginBottom: 1, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink2.Text, { children: [
|
|
350
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink2.Text, { bold: true, children: "Build complete!" }),
|
|
351
|
+
" ",
|
|
352
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink_link.default, { fallback: false, url, children: url || "" })
|
|
353
|
+
] }) });
|
|
354
|
+
};
|
|
355
|
+
BuildCompleteMessage.propTypes = {
|
|
356
|
+
build: import_prop_types.default.object.isRequired
|
|
357
|
+
};
|
|
358
|
+
var BuildCompleteMessage_default = BuildCompleteMessage;
|
|
359
|
+
|
|
360
|
+
// src/components/PlatformProgress.tsx
|
|
361
|
+
var import_prop_types2 = __toESM(require("prop-types"));
|
|
362
|
+
var import_ink3 = require("ink");
|
|
363
|
+
var import_ink_link2 = __toESM(require("ink-link"));
|
|
364
|
+
var import_path3 = __toESM(require("path"));
|
|
365
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
366
|
+
var preLabelMaxWidth = "More info: ".length;
|
|
367
|
+
var getProgressPercentageLabel = (percentage, activityType) => {
|
|
368
|
+
let backgroundColor = "white";
|
|
369
|
+
let color = "black";
|
|
370
|
+
if (activityType === "error") {
|
|
371
|
+
backgroundColor = "red";
|
|
372
|
+
} else if (percentage === 100) {
|
|
373
|
+
backgroundColor = "green";
|
|
374
|
+
color = "black";
|
|
375
|
+
}
|
|
376
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
377
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink3.Text, { backgroundColor, color, children: [
|
|
378
|
+
" ",
|
|
379
|
+
Math.round(percentage).toString().padStart(2, "0"),
|
|
380
|
+
"%",
|
|
381
|
+
" "
|
|
382
|
+
] }),
|
|
383
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink3.Text, { children: " " })
|
|
384
|
+
] });
|
|
385
|
+
};
|
|
386
|
+
var PlatformProgress = ({
|
|
387
|
+
activityName,
|
|
388
|
+
activityType,
|
|
389
|
+
downloadUrl,
|
|
390
|
+
percent,
|
|
391
|
+
platform,
|
|
392
|
+
shouldShowReadyPrefix
|
|
393
|
+
}) => {
|
|
394
|
+
let progressIndicator;
|
|
395
|
+
if (activityType === "done") {
|
|
396
|
+
if (process.platform === "darwin") {
|
|
397
|
+
downloadUrl = import_path3.default.posix.join(downloadUrl, "mac", "zip", process.arch);
|
|
398
|
+
}
|
|
399
|
+
progressIndicator = /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink3.Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
400
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink3.Text, { children: [
|
|
401
|
+
getProgressPercentageLabel(100),
|
|
402
|
+
shouldShowReadyPrefix ? "Ready!" : ""
|
|
403
|
+
] }),
|
|
404
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink_link2.default, { fallback: false, url: downloadUrl, children: downloadUrl })
|
|
405
|
+
] });
|
|
406
|
+
} else {
|
|
407
|
+
let activityNameToDisplay = activityName.replace(
|
|
408
|
+
/(?:\r\n|\r|\n)\s*/g,
|
|
409
|
+
"\u21B5 "
|
|
410
|
+
);
|
|
411
|
+
if (activityNameToDisplay.length > 64) {
|
|
412
|
+
activityNameToDisplay = `${activityNameToDisplay.substr(0, 61)}...`;
|
|
413
|
+
}
|
|
414
|
+
progressIndicator = /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink3.Box, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink3.Text, { children: [
|
|
415
|
+
["preparation", "queue"].includes(activityType) ? void 0 : getProgressPercentageLabel(percent, activityType),
|
|
416
|
+
activityNameToDisplay,
|
|
417
|
+
activityType === "error" ? "" : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink3.Text, { children: "..." })
|
|
418
|
+
] }) }) });
|
|
419
|
+
}
|
|
420
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink3.Box, { children: [
|
|
421
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink3.Box, { width: preLabelMaxWidth, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink3.Text, { children: [
|
|
422
|
+
platform[0].toUpperCase() + platform.substr(1),
|
|
423
|
+
": "
|
|
424
|
+
] }) }),
|
|
425
|
+
progressIndicator
|
|
426
|
+
] });
|
|
427
|
+
};
|
|
428
|
+
PlatformProgress.propTypes = {
|
|
429
|
+
activityName: import_prop_types2.default.string.isRequired,
|
|
430
|
+
activityType: import_prop_types2.default.string.isRequired,
|
|
431
|
+
downloadUrl: import_prop_types2.default.string,
|
|
432
|
+
percent: import_prop_types2.default.number.isRequired,
|
|
433
|
+
platform: import_prop_types2.default.string.isRequired,
|
|
434
|
+
shouldShowReadyPrefix: import_prop_types2.default.bool
|
|
435
|
+
};
|
|
436
|
+
var PlatformProgress_default = PlatformProgress;
|
|
437
|
+
|
|
438
|
+
// src/utilities/buildStatus.ts
|
|
439
|
+
var hasBuildKickedOff = (build) => {
|
|
440
|
+
if (!build) {
|
|
441
|
+
return false;
|
|
442
|
+
}
|
|
443
|
+
return build.status && build.status !== "preparation";
|
|
444
|
+
};
|
|
445
|
+
var isBuildCancellable = (build) => hasBuildKickedOff(build) && isBuildRunning(build);
|
|
446
|
+
var isBuildRunning = (build) => {
|
|
447
|
+
if (!build) {
|
|
448
|
+
return false;
|
|
449
|
+
}
|
|
450
|
+
return !["cancelled", "succeeded"].includes(build.status) && ["linux", "mac", "windows"].some(
|
|
451
|
+
(platform) => isPlatformBuildRunning(build[platform])
|
|
452
|
+
);
|
|
453
|
+
};
|
|
454
|
+
var isPlatformBuildRunning = (platformBuild) => {
|
|
455
|
+
if (!platformBuild) {
|
|
456
|
+
return false;
|
|
457
|
+
}
|
|
458
|
+
return !platformBuild.shouldSkip && !["cancelled", "succeeded"].includes(platformBuild.status) && ("failed" !== platformBuild.status || platformBuild.numberOfAttemptedBuilds < 2);
|
|
459
|
+
};
|
|
460
|
+
|
|
461
|
+
// src/components/BuildProgress.tsx
|
|
462
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
463
|
+
var logForCIThrottled = (0, import_lodash.default)(logForCI_default, 60 * 1e3, { trailing: true });
|
|
464
|
+
var BuildProgress = ({ build, onBuildFailure }) => {
|
|
465
|
+
logger_default.debug("BuildProgress component: render");
|
|
466
|
+
const exit = useExit_default();
|
|
467
|
+
const [{ hasKickedOff }, setState] = (0, import_react2.useState)({
|
|
468
|
+
hasKickedOff: false
|
|
469
|
+
});
|
|
470
|
+
const platformsNotSkipped = ["windows", "mac", "linux"].filter(
|
|
471
|
+
(platform) => !build[platform].shouldSkip
|
|
472
|
+
);
|
|
473
|
+
(0, import_react2.useEffect)(() => {
|
|
474
|
+
setState((previousState) => ({
|
|
475
|
+
...previousState,
|
|
476
|
+
hasKickedOff: hasBuildKickedOff(build)
|
|
477
|
+
}));
|
|
478
|
+
}, [build]);
|
|
479
|
+
(0, import_react2.useEffect)(() => {
|
|
480
|
+
if (build.status === "failed") {
|
|
481
|
+
onBuildFailure(build.errorMessage);
|
|
482
|
+
} else if (build.status === "cancelled") {
|
|
483
|
+
setTimeout(exit, 10);
|
|
484
|
+
} else {
|
|
485
|
+
const ciPlatformProgress = platformsNotSkipped.map(
|
|
486
|
+
(platform) => `${platform.charAt(0).toUpperCase() + platform.slice(1)}: ${build[platform].progressActivityName} (${build[platform].progressPercentage}%)`
|
|
487
|
+
);
|
|
488
|
+
logForCIThrottled(ciPlatformProgress.join(", "));
|
|
489
|
+
}
|
|
490
|
+
}, [build, exit, onBuildFailure, platformsNotSkipped]);
|
|
491
|
+
if (build.status === "succeeded") {
|
|
492
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(BuildCompleteMessage_default, { build });
|
|
493
|
+
}
|
|
494
|
+
if (build.status === "cancelled") {
|
|
495
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_ink4.Box, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_ink4.Text, { children: "Build cancelled" }) });
|
|
496
|
+
}
|
|
497
|
+
if (!hasKickedOff) {
|
|
498
|
+
return null;
|
|
499
|
+
}
|
|
500
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_jsx_runtime3.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_ink4.Box, { flexDirection: "column", children: platformsNotSkipped.map((platform) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_ink4.Box, { flexDirection: "column", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
501
|
+
PlatformProgress_default,
|
|
502
|
+
{
|
|
503
|
+
activityName: build[platform].status === "failed" ? build[platform].errorMessage : build[platform].progressActivityName,
|
|
504
|
+
activityType: build[platform].status === "failed" ? "error" : build[platform].progressActivityType,
|
|
505
|
+
downloadUrl: build[platform].standardDownloadUrl,
|
|
506
|
+
percent: build[platform].progressPercentage,
|
|
507
|
+
platform,
|
|
508
|
+
shouldShowReadyPrefix: !(build && ["failed", "succeeded"].includes(build.status))
|
|
509
|
+
}
|
|
510
|
+
) }, platform)) }) });
|
|
511
|
+
};
|
|
512
|
+
BuildProgress.propTypes = {
|
|
513
|
+
build: import_prop_types3.default.object.isRequired,
|
|
514
|
+
onBuildFailure: import_prop_types3.default.func.isRequired
|
|
515
|
+
};
|
|
516
|
+
var BuildProgress_default = BuildProgress;
|
|
517
|
+
|
|
518
|
+
// src/components/ErrorDisplay.tsx
|
|
519
|
+
var import_ink5 = require("ink");
|
|
520
|
+
var import_prop_types4 = __toESM(require("prop-types"));
|
|
521
|
+
var import_react3 = require("react");
|
|
522
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
523
|
+
var ErrorDisplay = ({ commandUsed, error }) => {
|
|
524
|
+
const exit = useExit_default();
|
|
525
|
+
logger_default.error({ error });
|
|
526
|
+
(0, import_react3.useEffect)(() => {
|
|
527
|
+
if (!error) {
|
|
528
|
+
return;
|
|
529
|
+
}
|
|
530
|
+
setTimeout(() => exit(error), 10);
|
|
531
|
+
}, [exit, error]);
|
|
532
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
533
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ink5.Text, { backgroundColor: "red", color: "white", children: [
|
|
534
|
+
" ",
|
|
535
|
+
"ERROR",
|
|
536
|
+
" "
|
|
537
|
+
] }),
|
|
538
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_ink5.Text, { children: error.message || error.stack || error.toString() }),
|
|
539
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ink5.Box, { flexDirection: "column", marginTop: 1, children: [
|
|
540
|
+
commandUsed ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ink5.Text, { dimColor: true, color: "gray", children: [
|
|
541
|
+
"Command: ",
|
|
542
|
+
commandUsed
|
|
543
|
+
] }) : null,
|
|
544
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ink5.Text, { dimColor: true, color: "gray", children: [
|
|
545
|
+
"@todesktop/cli: ",
|
|
546
|
+
getCliVersion_default()
|
|
547
|
+
] }),
|
|
548
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ink5.Text, { dimColor: true, color: "gray", children: [
|
|
549
|
+
"Node: ",
|
|
550
|
+
process.version
|
|
551
|
+
] }),
|
|
552
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_ink5.Text, { dimColor: true, color: "gray", children: [
|
|
553
|
+
"cwd: ",
|
|
554
|
+
process.cwd()
|
|
555
|
+
] })
|
|
556
|
+
] })
|
|
557
|
+
] });
|
|
558
|
+
};
|
|
559
|
+
ErrorDisplay.propTypes = {
|
|
560
|
+
commandUsed: import_prop_types4.default.string,
|
|
561
|
+
error: import_prop_types4.default.object.isRequired
|
|
562
|
+
};
|
|
563
|
+
var ErrorDisplay_default = ErrorDisplay;
|
|
564
|
+
|
|
565
|
+
// src/components/Preparation.tsx
|
|
566
|
+
var import_ink7 = require("ink");
|
|
567
|
+
|
|
568
|
+
// src/components/ProgressBar.tsx
|
|
569
|
+
var import_prop_types5 = __toESM(require("prop-types"));
|
|
570
|
+
var import_ink_gradient = __toESM(require("ink-gradient"));
|
|
571
|
+
|
|
572
|
+
// src/libs/ink-progress-bar/index.tsx
|
|
573
|
+
var import_ink6 = require("ink");
|
|
574
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
575
|
+
var Bar = ({
|
|
576
|
+
percent = 1,
|
|
577
|
+
columns = 0,
|
|
578
|
+
left = 0,
|
|
579
|
+
right = 0,
|
|
580
|
+
character = "\u2588",
|
|
581
|
+
rightPad = false,
|
|
582
|
+
...rest
|
|
583
|
+
}) => {
|
|
584
|
+
const getString = () => {
|
|
585
|
+
const screen = columns || process.stdout.columns || 80;
|
|
586
|
+
const space = screen - right - left;
|
|
587
|
+
const max = Math.min(Math.floor(space * percent), space);
|
|
588
|
+
const chars = character.repeat(max);
|
|
589
|
+
if (!rightPad) {
|
|
590
|
+
return chars;
|
|
591
|
+
}
|
|
592
|
+
return chars + " ".repeat(space - max);
|
|
593
|
+
};
|
|
594
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_ink6.Text, { ...rest, children: getString() });
|
|
595
|
+
};
|
|
596
|
+
var ink_progress_bar_default = Bar;
|
|
597
|
+
|
|
598
|
+
// src/components/ProgressBar.tsx
|
|
599
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
600
|
+
var ProgressBar = ({ left, right, percent }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_ink_gradient.default, { colors: ["gray", "white"], children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ink_progress_bar_default, { left, right, percent }) });
|
|
601
|
+
ProgressBar.propTypes = {
|
|
602
|
+
left: import_prop_types5.default.number,
|
|
603
|
+
right: import_prop_types5.default.number,
|
|
604
|
+
percent: import_prop_types5.default.number.isRequired
|
|
605
|
+
};
|
|
606
|
+
var ProgressBar_default = ProgressBar;
|
|
607
|
+
|
|
608
|
+
// src/components/Preparation.tsx
|
|
609
|
+
var import_prop_types6 = __toESM(require("prop-types"));
|
|
610
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
611
|
+
var Preparation = ({ progressPercentage, stageLabel, uploadedSize }) => {
|
|
612
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_ink7.Box, { marginBottom: 1, children: [
|
|
613
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_ink7.Text, { children: [
|
|
614
|
+
stageLabel,
|
|
615
|
+
": "
|
|
616
|
+
] }),
|
|
617
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_ink7.Box, { flexDirection: "column", children: [
|
|
618
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ProgressBar_default, { left: 11, percent: progressPercentage }),
|
|
619
|
+
uploadedSize ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_ink7.Text, { children: uploadedSize }) : void 0
|
|
620
|
+
] })
|
|
621
|
+
] });
|
|
622
|
+
};
|
|
623
|
+
Preparation.propTypes = {
|
|
624
|
+
progressPercentage: import_prop_types6.default.number.isRequired,
|
|
625
|
+
stageLabel: import_prop_types6.default.string.isRequired,
|
|
626
|
+
uploadedSize: import_prop_types6.default.string
|
|
627
|
+
};
|
|
628
|
+
var Preparation_default = Preparation;
|
|
629
|
+
|
|
630
|
+
// src/components/InitialLoadingState.tsx
|
|
631
|
+
var import_ink8 = require("ink");
|
|
632
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
633
|
+
var InitialLoadingState = () => {
|
|
634
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_ink8.Text, { children: "Getting app info..." });
|
|
635
|
+
};
|
|
636
|
+
var InitialLoadingState_default = InitialLoadingState;
|
|
637
|
+
|
|
638
|
+
// src/components/MainLayout.tsx
|
|
639
|
+
var import_ink13 = require("ink");
|
|
640
|
+
var import_is_ci3 = __toESM(require("is-ci"));
|
|
641
|
+
var import_react5 = require("react");
|
|
642
|
+
|
|
643
|
+
// src/components/CancelBuild.tsx
|
|
644
|
+
var import_ink9 = require("ink");
|
|
645
|
+
var import_react4 = require("react");
|
|
646
|
+
|
|
647
|
+
// src/utilities/getCallableFirebaseFunction.ts
|
|
648
|
+
var import_firebase = __toESM(require("firebase"));
|
|
649
|
+
var import_functions = require("firebase/functions");
|
|
650
|
+
if (getEnvironmentVariables_default().TODESKTOP_CLI_ENV === "development") {
|
|
651
|
+
import_firebase.default.functions().useFunctionsEmulator("http://localhost:5000");
|
|
652
|
+
}
|
|
653
|
+
var getCallableFirebaseFunction_default = (functionName) => import_firebase.default.functions().httpsCallable(functionName);
|
|
654
|
+
|
|
655
|
+
// src/components/CancelBuild.tsx
|
|
656
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
657
|
+
var cancelBuild = getCallableFirebaseFunction_default("cancelBuild");
|
|
658
|
+
var CancelBuild = ({
|
|
659
|
+
appId,
|
|
660
|
+
children: postCancelContents,
|
|
661
|
+
commandUsed,
|
|
662
|
+
id
|
|
663
|
+
}) => {
|
|
664
|
+
logger_default.debug({ appId, buildId: id }, "CancelBuild component: render");
|
|
665
|
+
const exit = useExit_default();
|
|
666
|
+
const [
|
|
667
|
+
{ arbitraryMessageComponent, error, hasCompleted, hasStarted },
|
|
668
|
+
setState
|
|
669
|
+
] = (0, import_react4.useState)({
|
|
670
|
+
arbitraryMessageComponent: null,
|
|
671
|
+
error: null,
|
|
672
|
+
hasCompleted: false,
|
|
673
|
+
hasStarted: false
|
|
674
|
+
});
|
|
675
|
+
(0, import_react4.useEffect)(() => {
|
|
676
|
+
if (hasCompleted || hasStarted) {
|
|
677
|
+
return;
|
|
678
|
+
}
|
|
679
|
+
setState((previousState) => ({ ...previousState, hasStarted: true }));
|
|
680
|
+
logForCI_default("Cancelling build...");
|
|
681
|
+
cancelBuild({ appId, buildId: id }).then((result) => {
|
|
682
|
+
logger_default.debug(
|
|
683
|
+
{ appId, buildId: id, result },
|
|
684
|
+
"CancelBuild component: cancellation request complete"
|
|
685
|
+
);
|
|
686
|
+
setState((previousState) => ({ ...previousState, hasCompleted: true }));
|
|
687
|
+
}).catch((e) => {
|
|
688
|
+
logger_default.debug(
|
|
689
|
+
{ appId, buildId: id, code: e.code },
|
|
690
|
+
"CancelBuild component: cancellation request failed"
|
|
691
|
+
);
|
|
692
|
+
logger_default.error(e);
|
|
693
|
+
const stateUpdates = {
|
|
694
|
+
arbitraryMessageComponent: void 0,
|
|
695
|
+
error: void 0,
|
|
696
|
+
hasCompleted: true
|
|
697
|
+
};
|
|
698
|
+
if (e.code === "internal") {
|
|
699
|
+
stateUpdates.error = e;
|
|
700
|
+
} else {
|
|
701
|
+
stateUpdates.arbitraryMessageComponent = /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink9.Text, { children: [
|
|
702
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink9.Text, { color: "red", children: [
|
|
703
|
+
"Cannot cancel build (",
|
|
704
|
+
id,
|
|
705
|
+
")."
|
|
706
|
+
] }),
|
|
707
|
+
" ",
|
|
708
|
+
e.message
|
|
709
|
+
] });
|
|
710
|
+
}
|
|
711
|
+
setState((prevState) => ({
|
|
712
|
+
...prevState,
|
|
713
|
+
...stateUpdates
|
|
714
|
+
}));
|
|
715
|
+
});
|
|
716
|
+
}, [appId, id, hasStarted, hasCompleted]);
|
|
717
|
+
(0, import_react4.useEffect)(() => {
|
|
718
|
+
if (hasCompleted && !postCancelContents) {
|
|
719
|
+
logger_default.debug(
|
|
720
|
+
"CancelBuild component: exiting now that build is cancelled"
|
|
721
|
+
);
|
|
722
|
+
exit();
|
|
723
|
+
}
|
|
724
|
+
}, [postCancelContents, exit, hasCompleted]);
|
|
725
|
+
if (error) {
|
|
726
|
+
error.message = `Failed to cancel build (${id}). ${error.message}`;
|
|
727
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ErrorDisplay_default, { commandUsed, error });
|
|
728
|
+
}
|
|
729
|
+
if (arbitraryMessageComponent) {
|
|
730
|
+
return arbitraryMessageComponent;
|
|
731
|
+
}
|
|
732
|
+
if (hasCompleted) {
|
|
733
|
+
return postCancelContents ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_jsx_runtime9.Fragment, { children: postCancelContents }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ink9.Text, { children: "Build cancelled" });
|
|
734
|
+
}
|
|
735
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ink9.Text, { children: [
|
|
736
|
+
"Cancelling build (",
|
|
737
|
+
id,
|
|
738
|
+
")..."
|
|
739
|
+
] });
|
|
740
|
+
};
|
|
741
|
+
var CancelBuild_default = CancelBuild;
|
|
742
|
+
|
|
743
|
+
// src/components/Footer.tsx
|
|
744
|
+
var import_ink10 = require("ink");
|
|
745
|
+
var import_ink_link3 = __toESM(require("ink-link"));
|
|
746
|
+
var import_prop_types7 = __toESM(require("prop-types"));
|
|
747
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
748
|
+
var Footer = ({
|
|
749
|
+
hasBuildEverFailed,
|
|
750
|
+
shouldShowCancelBuildInstructions,
|
|
751
|
+
uiUrl
|
|
752
|
+
}) => {
|
|
753
|
+
if (!uiUrl) {
|
|
754
|
+
return null;
|
|
755
|
+
}
|
|
756
|
+
let buildFailedMessage;
|
|
757
|
+
if (hasBuildEverFailed) {
|
|
758
|
+
buildFailedMessage = /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_ink10.Text, { color: "red", children: "An error has occurred. " });
|
|
759
|
+
}
|
|
760
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_ink10.Box, { flexDirection: "column", children: [
|
|
761
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_ink10.Box, { flexDirection: "column", children: [
|
|
762
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_ink10.Text, { bold: true, children: [
|
|
763
|
+
buildFailedMessage,
|
|
764
|
+
"See web UI for more information: "
|
|
765
|
+
] }),
|
|
766
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_ink10.Text, { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_ink_link3.default, { fallback: false, url: uiUrl, children: uiUrl }) })
|
|
767
|
+
] }),
|
|
768
|
+
shouldShowCancelBuildInstructions ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_ink10.Text, { color: "gray", children: [
|
|
769
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_ink10.Text, { bold: true, children: "[esc]:" }),
|
|
770
|
+
" cancel build"
|
|
771
|
+
] }) : null
|
|
772
|
+
] });
|
|
773
|
+
};
|
|
774
|
+
Footer.propTypes = {
|
|
775
|
+
hasBuildEverFailed: import_prop_types7.default.bool,
|
|
776
|
+
shouldShowCancelBuildInstructions: import_prop_types7.default.bool,
|
|
777
|
+
uiUrl: import_prop_types7.default.string
|
|
778
|
+
};
|
|
779
|
+
var Footer_default = Footer;
|
|
780
|
+
|
|
781
|
+
// src/components/Header.tsx
|
|
782
|
+
var import_ink11 = require("ink");
|
|
783
|
+
var import_prop_types8 = __toESM(require("prop-types"));
|
|
784
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
785
|
+
var getText = (build, name, version) => {
|
|
786
|
+
const suffix = name + (version ? ` v${version}` : "");
|
|
787
|
+
if (build && ["cancelled", "succeeded", "failed"].includes(build.status)) {
|
|
788
|
+
if (build.status === "succeeded") {
|
|
789
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_ink11.Text, { children: [
|
|
790
|
+
"\u2705 ",
|
|
791
|
+
suffix
|
|
792
|
+
] });
|
|
793
|
+
} else if (build.status === "failed") {
|
|
794
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_ink11.Text, { children: [
|
|
795
|
+
"\u274C ",
|
|
796
|
+
suffix
|
|
797
|
+
] });
|
|
798
|
+
} else if (build.status === "cancelled") {
|
|
799
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_ink11.Text, { children: [
|
|
800
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_ink11.Text, { bold: true, color: "gray", children: "X" }),
|
|
801
|
+
" ",
|
|
802
|
+
suffix
|
|
803
|
+
] });
|
|
804
|
+
}
|
|
805
|
+
} else {
|
|
806
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_ink11.Text, { children: suffix });
|
|
807
|
+
}
|
|
808
|
+
};
|
|
809
|
+
var Header = ({ build, name, version }) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_ink11.Box, { marginBottom: 1, children: getText(build, name, version) });
|
|
810
|
+
Header.propTypes = {
|
|
811
|
+
build: import_prop_types8.default.object,
|
|
812
|
+
name: import_prop_types8.default.string.isRequired,
|
|
813
|
+
version: import_prop_types8.default.string
|
|
814
|
+
};
|
|
815
|
+
var Header_default = Header;
|
|
816
|
+
|
|
817
|
+
// src/utilities/useInput.ts
|
|
818
|
+
var import_is_ci2 = __toESM(require("is-ci"));
|
|
819
|
+
var import_ink12 = require("ink");
|
|
820
|
+
var hasSubscribed = false;
|
|
821
|
+
var ctrlCSubscriptions = [];
|
|
822
|
+
var onStdin = (data, exit) => {
|
|
823
|
+
let input = String(data);
|
|
824
|
+
let wasCtrlPressed = false;
|
|
825
|
+
if (input <= "" && input !== "\r") {
|
|
826
|
+
input = String.fromCharCode(input.charCodeAt(0) + "a".charCodeAt(0) - 1);
|
|
827
|
+
wasCtrlPressed = true;
|
|
828
|
+
}
|
|
829
|
+
if (wasCtrlPressed && input === "c") {
|
|
830
|
+
ctrlCSubscriptions.forEach((subscription) => subscription());
|
|
831
|
+
setTimeout(exit, 10);
|
|
832
|
+
}
|
|
833
|
+
};
|
|
834
|
+
var useInput_default = () => {
|
|
835
|
+
const exit = useExit_default();
|
|
836
|
+
const { stdin, isRawModeSupported } = (0, import_ink12.useStdin)();
|
|
837
|
+
if (import_is_ci2.default || !isRawModeSupported) {
|
|
838
|
+
return () => () => {
|
|
839
|
+
};
|
|
840
|
+
}
|
|
841
|
+
return (callback, useInputOptions = {}, { onCtrlCPressed = null } = {}) => {
|
|
842
|
+
const onStdinData = (data) => onStdin(data, exit);
|
|
843
|
+
if (onCtrlCPressed) {
|
|
844
|
+
ctrlCSubscriptions.push(onCtrlCPressed);
|
|
845
|
+
}
|
|
846
|
+
if (!hasSubscribed) {
|
|
847
|
+
hasSubscribed = true;
|
|
848
|
+
stdin.on("data", onStdinData);
|
|
849
|
+
}
|
|
850
|
+
const cleanUpInputHook = (0, import_ink12.useInput)(callback, useInputOptions);
|
|
851
|
+
return () => {
|
|
852
|
+
if (hasSubscribed) {
|
|
853
|
+
stdin.off("data", onStdinData);
|
|
854
|
+
}
|
|
855
|
+
cleanUpInputHook == null ? void 0 : cleanUpInputHook();
|
|
856
|
+
};
|
|
857
|
+
};
|
|
858
|
+
};
|
|
859
|
+
|
|
860
|
+
// src/components/MainLayout.tsx
|
|
861
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
862
|
+
var MainLayout = ({
|
|
863
|
+
appId,
|
|
864
|
+
appName,
|
|
865
|
+
appVersion,
|
|
866
|
+
build,
|
|
867
|
+
children,
|
|
868
|
+
commandUsed,
|
|
869
|
+
hasBuildEverFailed
|
|
870
|
+
}) => {
|
|
871
|
+
logger_default.debug("MainLayout component: render");
|
|
872
|
+
const onInput = useInput_default();
|
|
873
|
+
const { isRawModeSupported } = (0, import_ink13.useStdin)();
|
|
874
|
+
const [
|
|
875
|
+
{ canCancelBuild, hasKickedOff, isCancellingBuild, wasCtrlCPressed },
|
|
876
|
+
setState
|
|
877
|
+
] = (0, import_react5.useState)({
|
|
878
|
+
canCancelBuild: null,
|
|
879
|
+
hasKickedOff: false,
|
|
880
|
+
isCancellingBuild: false,
|
|
881
|
+
wasCtrlCPressed: false
|
|
882
|
+
});
|
|
883
|
+
(0, import_react5.useEffect)(() => {
|
|
884
|
+
setState((previousState) => ({
|
|
885
|
+
...previousState,
|
|
886
|
+
hasKickedOff: hasBuildKickedOff(build)
|
|
887
|
+
}));
|
|
888
|
+
}, [build]);
|
|
889
|
+
(0, import_react5.useEffect)(() => {
|
|
890
|
+
setState((previousState) => ({
|
|
891
|
+
...previousState,
|
|
892
|
+
canCancelBuild: !import_is_ci3.default && isRawModeSupported && !isCancellingBuild && isBuildCancellable(build)
|
|
893
|
+
}));
|
|
894
|
+
}, [build, isCancellingBuild]);
|
|
895
|
+
onInput(
|
|
896
|
+
async (input, key) => {
|
|
897
|
+
if (key.escape && canCancelBuild) {
|
|
898
|
+
logger_default.debug("MainLayout component: esc pressed, cancelling build");
|
|
899
|
+
setState((previousState) => ({
|
|
900
|
+
...previousState,
|
|
901
|
+
isCancellingBuild: true
|
|
902
|
+
}));
|
|
903
|
+
}
|
|
904
|
+
},
|
|
905
|
+
{},
|
|
906
|
+
{
|
|
907
|
+
onCtrlCPressed: () => {
|
|
908
|
+
setState((previousState) => ({
|
|
909
|
+
...previousState,
|
|
910
|
+
wasCtrlCPressed: true
|
|
911
|
+
}));
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
);
|
|
915
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
|
|
916
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Header_default, { build, name: appName, version: appVersion }),
|
|
917
|
+
isCancellingBuild ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_ink13.Box, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(CancelBuild_default, { appId, commandUsed, id: build.id }) }) : children,
|
|
918
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
919
|
+
Footer_default,
|
|
920
|
+
{
|
|
921
|
+
hasBuildEverFailed,
|
|
922
|
+
shouldShowCancelBuildInstructions: canCancelBuild && !wasCtrlCPressed,
|
|
923
|
+
uiUrl: build ? build.url : null
|
|
924
|
+
}
|
|
925
|
+
),
|
|
926
|
+
wasCtrlCPressed && hasKickedOff ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
|
|
927
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_ink13.Box, { flexDirection: "column", marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_ink13.Text, { color: "gray", children: "The build will continue in the background. To view it, run:" }) }),
|
|
928
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_ink13.Box, { children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_ink13.Text, { bold: true, color: "gray", children: [
|
|
929
|
+
"todesktop builds ",
|
|
930
|
+
build.id
|
|
931
|
+
] }) })
|
|
932
|
+
] }) : null
|
|
933
|
+
] });
|
|
934
|
+
};
|
|
935
|
+
var MainLayout_default = MainLayout;
|
|
936
|
+
|
|
937
|
+
// src/utilities/runBuild.ts
|
|
938
|
+
var import_pretty_bytes = __toESM(require("pretty-bytes"));
|
|
939
|
+
|
|
940
|
+
// src/utilities/getVersionControlInfo.ts
|
|
941
|
+
var gitRevSync = __toESM(require("git-rev-sync"));
|
|
942
|
+
var getVersionControlInfo_default = async (directory) => {
|
|
943
|
+
let result = {};
|
|
944
|
+
try {
|
|
945
|
+
const gitCommitHash = gitRevSync.long(directory);
|
|
946
|
+
if (gitCommitHash) {
|
|
947
|
+
result = {
|
|
948
|
+
branchName: gitRevSync.branch(directory),
|
|
949
|
+
commitDate: gitRevSync.date().toISOString(),
|
|
950
|
+
commitId: gitCommitHash,
|
|
951
|
+
commitMessage: gitRevSync.message(),
|
|
952
|
+
hasUncommittedChanges: gitRevSync.isDirty(),
|
|
953
|
+
repositoryRemoteUrl: gitRevSync.remoteUrl(),
|
|
954
|
+
versionControlSystemName: "git"
|
|
955
|
+
};
|
|
956
|
+
}
|
|
957
|
+
} catch (e) {
|
|
958
|
+
}
|
|
959
|
+
return result;
|
|
960
|
+
};
|
|
961
|
+
|
|
962
|
+
// src/utilities/projectConfig/getProjectConfig.ts
|
|
963
|
+
var import_path5 = require("path");
|
|
964
|
+
var import_fs = require("fs");
|
|
965
|
+
var import_find_up = __toESM(require("find-up"));
|
|
966
|
+
|
|
967
|
+
// src/utilities/projectConfig/loadConfig.ts
|
|
968
|
+
function loadConfig(configPath) {
|
|
969
|
+
return require(configPath);
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
// src/utilities/projectConfig/resolveConfigPaths.ts
|
|
973
|
+
var path5 = __toESM(require("path"));
|
|
974
|
+
function resolveConfigPaths({
|
|
975
|
+
config: config2,
|
|
976
|
+
projectRoot
|
|
977
|
+
}) {
|
|
978
|
+
const appRoot = config2.appPath ? path5.isAbsolute(config2.appPath) ? config2.appPath : path5.join(projectRoot, config2.appPath) : projectRoot;
|
|
979
|
+
const transformIfExists = (value, transformer) => value ? transformer(value) : void 0;
|
|
980
|
+
const resolvePath = (filePath) => path5.isAbsolute(filePath) ? filePath : path5.join(projectRoot, filePath);
|
|
981
|
+
const result = {
|
|
982
|
+
...config2,
|
|
983
|
+
appPath: appRoot,
|
|
984
|
+
icon: resolvePath(config2.icon)
|
|
985
|
+
};
|
|
986
|
+
if (config2.extraContentFiles) {
|
|
987
|
+
result.extraContentFiles = transformIfExists(
|
|
988
|
+
config2.extraContentFiles,
|
|
989
|
+
(extraContentFiles) => extraContentFiles.map((extraContentFile) => ({
|
|
990
|
+
...extraContentFile,
|
|
991
|
+
from: resolvePath(extraContentFile.from)
|
|
992
|
+
}))
|
|
993
|
+
);
|
|
994
|
+
}
|
|
995
|
+
if (config2.extraResources) {
|
|
996
|
+
result.extraResources = transformIfExists(
|
|
997
|
+
config2.extraResources,
|
|
998
|
+
(extraResources) => extraResources.map((extraResource) => ({
|
|
999
|
+
...extraResource,
|
|
1000
|
+
from: resolvePath(extraResource.from)
|
|
1001
|
+
}))
|
|
1002
|
+
);
|
|
1003
|
+
}
|
|
1004
|
+
if (config2.linux) {
|
|
1005
|
+
result.linux = { ...config2.linux };
|
|
1006
|
+
if (config2.linux.icon) {
|
|
1007
|
+
result.linux.icon = resolvePath(config2.linux.icon);
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
if (config2.mac) {
|
|
1011
|
+
result.mac = { ...config2.mac };
|
|
1012
|
+
if (config2.mac.entitlements) {
|
|
1013
|
+
result.mac.entitlements = resolvePath(config2.mac.entitlements);
|
|
1014
|
+
}
|
|
1015
|
+
if (config2.mac.icon) {
|
|
1016
|
+
result.mac.icon = resolvePath(config2.mac.icon);
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
if (config2.dmg) {
|
|
1020
|
+
if (config2.dmg.background) {
|
|
1021
|
+
result.dmg.background = resolvePath(config2.dmg.background);
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
if (config2.windows) {
|
|
1025
|
+
result.windows = { ...config2.windows };
|
|
1026
|
+
if (config2.windows.icon) {
|
|
1027
|
+
result.windows.icon = resolvePath(config2.windows.icon);
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
return result;
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
// src/utilities/projectConfig/validateConfig.ts
|
|
1034
|
+
var import_ajv3 = __toESM(require("ajv"));
|
|
1035
|
+
var import_ajv_formats2 = __toESM(require("ajv-formats"));
|
|
1036
|
+
var import_better_ajv_errors2 = __toESM(require("better-ajv-errors"));
|
|
1037
|
+
|
|
1038
|
+
// src/utilities/projectConfig/addCustomKeywords.ts
|
|
1039
|
+
var import_ajv2 = require("ajv");
|
|
1040
|
+
var import_email_regex = __toESM(require("email-regex"));
|
|
1041
|
+
var fs3 = __toESM(require("fs"));
|
|
1042
|
+
var path6 = __toESM(require("path"));
|
|
1043
|
+
var import_parse_author = __toESM(require("parse-author"));
|
|
1044
|
+
var semver = __toESM(require("semver"));
|
|
1045
|
+
|
|
1046
|
+
// src/utilities/projectConfig/validatePackageJSON.ts
|
|
1047
|
+
var import_ajv = __toESM(require("ajv"));
|
|
1048
|
+
var import_ajv_formats = __toESM(require("ajv-formats"));
|
|
1049
|
+
var import_better_ajv_errors = __toESM(require("better-ajv-errors"));
|
|
1050
|
+
|
|
1051
|
+
// src/utilities/projectConfig/schema/packageJSON.ts
|
|
1052
|
+
var packageJSON_default = (context) => {
|
|
1053
|
+
return {
|
|
1054
|
+
type: "object",
|
|
1055
|
+
required: [
|
|
1056
|
+
"author",
|
|
1057
|
+
"dependencies",
|
|
1058
|
+
"devDependencies",
|
|
1059
|
+
"homepage",
|
|
1060
|
+
"name",
|
|
1061
|
+
"version"
|
|
1062
|
+
],
|
|
1063
|
+
properties: {
|
|
1064
|
+
author: {
|
|
1065
|
+
npmAuthor: {}
|
|
1066
|
+
},
|
|
1067
|
+
dependencies: {
|
|
1068
|
+
type: "object",
|
|
1069
|
+
required: ["@todesktop/runtime"],
|
|
1070
|
+
excludedDependencies: {
|
|
1071
|
+
dependencyKey: "dependencies",
|
|
1072
|
+
blacklist: ["@todesktop/cli"]
|
|
1073
|
+
},
|
|
1074
|
+
properties: {
|
|
1075
|
+
"@todesktop/runtime": {
|
|
1076
|
+
type: "string"
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
},
|
|
1080
|
+
devDependencies: {
|
|
1081
|
+
type: "object",
|
|
1082
|
+
required: ["electron"],
|
|
1083
|
+
properties: {
|
|
1084
|
+
electron: {
|
|
1085
|
+
type: "string",
|
|
1086
|
+
semanticVersion: {
|
|
1087
|
+
packageName: "electron",
|
|
1088
|
+
mustBeExact: true
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
},
|
|
1093
|
+
name: {
|
|
1094
|
+
type: "string",
|
|
1095
|
+
minLength: 1
|
|
1096
|
+
},
|
|
1097
|
+
scripts: {
|
|
1098
|
+
type: "object",
|
|
1099
|
+
properties: {
|
|
1100
|
+
"todesktop:beforeInstall": {
|
|
1101
|
+
type: "string",
|
|
1102
|
+
file: {
|
|
1103
|
+
from: context.projectRoot,
|
|
1104
|
+
mustBeFile: true
|
|
1105
|
+
}
|
|
1106
|
+
},
|
|
1107
|
+
"todesktop:afterPack": {
|
|
1108
|
+
type: "string",
|
|
1109
|
+
file: {
|
|
1110
|
+
from: context.projectRoot,
|
|
1111
|
+
mustBeFile: true
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
},
|
|
1116
|
+
version: {
|
|
1117
|
+
type: "string",
|
|
1118
|
+
semanticVersion: {}
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
};
|
|
1122
|
+
};
|
|
1123
|
+
|
|
1124
|
+
// src/utilities/projectConfig/validatePackageJSON.ts
|
|
1125
|
+
var validatePackageJSON_default = (pkg, pkgPath, context) => {
|
|
1126
|
+
const ajv = new import_ajv.default({ allErrors: true });
|
|
1127
|
+
(0, import_ajv_formats.default)(ajv);
|
|
1128
|
+
addCustomKeywords_default(ajv, context);
|
|
1129
|
+
const schema = packageJSON_default(context);
|
|
1130
|
+
const validate = ajv.compile(schema);
|
|
1131
|
+
if (!validate(pkg)) {
|
|
1132
|
+
const output = (0, import_better_ajv_errors.default)(schema, pkg, validate.errors, {
|
|
1133
|
+
indent: 2
|
|
1134
|
+
});
|
|
1135
|
+
const error = new Error(`package.json invalid (${pkgPath});
|
|
1136
|
+
${output}`);
|
|
1137
|
+
error.isValidationError = true;
|
|
1138
|
+
throw error;
|
|
1139
|
+
}
|
|
1140
|
+
};
|
|
1141
|
+
|
|
1142
|
+
// src/utilities/projectConfig/addCustomKeywords.ts
|
|
1143
|
+
var addCustomKeywords_default = (ajv, context) => {
|
|
1144
|
+
const addKeyword = (def) => {
|
|
1145
|
+
const validate = (schema, data) => {
|
|
1146
|
+
try {
|
|
1147
|
+
return def.validate(schema, data);
|
|
1148
|
+
} catch (e) {
|
|
1149
|
+
if (e instanceof import_ajv2.ValidationError) {
|
|
1150
|
+
validate.errors = e.errors;
|
|
1151
|
+
return false;
|
|
1152
|
+
}
|
|
1153
|
+
throw e;
|
|
1154
|
+
}
|
|
1155
|
+
};
|
|
1156
|
+
ajv.addKeyword({ ...def, validate });
|
|
1157
|
+
};
|
|
1158
|
+
addKeyword({
|
|
1159
|
+
keyword: "excludedDependencies",
|
|
1160
|
+
validate: (schema, data) => {
|
|
1161
|
+
const matchingPackages = schema.blacklist.filter(
|
|
1162
|
+
(packageName) => data[packageName]
|
|
1163
|
+
);
|
|
1164
|
+
if (matchingPackages.length) {
|
|
1165
|
+
throw new import_ajv2.ValidationError([
|
|
1166
|
+
{
|
|
1167
|
+
keyword: "Dependency",
|
|
1168
|
+
message: `${matchingPackages.join(", ")} should not be in ${schema.dependencyKey}`,
|
|
1169
|
+
instancePath: `/${schema.dependencyKey}`
|
|
1170
|
+
}
|
|
1171
|
+
]);
|
|
1172
|
+
}
|
|
1173
|
+
return true;
|
|
1174
|
+
}
|
|
1175
|
+
});
|
|
1176
|
+
addKeyword({
|
|
1177
|
+
keyword: "email",
|
|
1178
|
+
type: "string",
|
|
1179
|
+
validate: (schema, data) => {
|
|
1180
|
+
if (!(0, import_email_regex.default)({ exact: true }).test(data)) {
|
|
1181
|
+
throw new import_ajv2.ValidationError([
|
|
1182
|
+
{
|
|
1183
|
+
keyword: "email",
|
|
1184
|
+
message: "invalid"
|
|
1185
|
+
}
|
|
1186
|
+
]);
|
|
1187
|
+
}
|
|
1188
|
+
return true;
|
|
1189
|
+
}
|
|
1190
|
+
});
|
|
1191
|
+
addKeyword({
|
|
1192
|
+
keyword: "file",
|
|
1193
|
+
type: "string",
|
|
1194
|
+
validate: (schema, data) => {
|
|
1195
|
+
const mustBeDirectory = schema.mustBeDirectory || schema.mustBeElectronApp;
|
|
1196
|
+
if (!data.trim().length) {
|
|
1197
|
+
if (schema.isOptional) {
|
|
1198
|
+
return true;
|
|
1199
|
+
}
|
|
1200
|
+
throw new import_ajv2.ValidationError([
|
|
1201
|
+
{
|
|
1202
|
+
keyword: schema.mustBeDirectory ? "Directory" : "File",
|
|
1203
|
+
message: "is empty"
|
|
1204
|
+
}
|
|
1205
|
+
]);
|
|
1206
|
+
}
|
|
1207
|
+
const filePath = path6.isAbsolute(data) ? data : path6.join(schema.from, data);
|
|
1208
|
+
if (path6.relative(schema.from, filePath).startsWith("..")) {
|
|
1209
|
+
throw new import_ajv2.ValidationError([
|
|
1210
|
+
{
|
|
1211
|
+
keyword: mustBeDirectory ? "Directory" : "File",
|
|
1212
|
+
message: `is not in project (${filePath})`
|
|
1213
|
+
}
|
|
1214
|
+
]);
|
|
1215
|
+
}
|
|
1216
|
+
if (schema.extensions && !schema.extensions.includes(path6.extname(filePath).substr(1))) {
|
|
1217
|
+
throw new import_ajv2.ValidationError([
|
|
1218
|
+
{
|
|
1219
|
+
keyword: "File extension",
|
|
1220
|
+
message: `invalid. ${path6.extname(data)} Must be${schema.extensions > 1 ? "one of the following:" : ""} "${schema.extensions.join('", "')}"`
|
|
1221
|
+
}
|
|
1222
|
+
]);
|
|
1223
|
+
}
|
|
1224
|
+
if (!fs3.existsSync(filePath)) {
|
|
1225
|
+
throw new import_ajv2.ValidationError([
|
|
1226
|
+
{
|
|
1227
|
+
keyword: mustBeDirectory ? "Directory" : "File",
|
|
1228
|
+
message: `does not exist (${filePath})`
|
|
1229
|
+
}
|
|
1230
|
+
]);
|
|
1231
|
+
}
|
|
1232
|
+
const stats = fs3.statSync(filePath);
|
|
1233
|
+
if (mustBeDirectory && stats.isFile()) {
|
|
1234
|
+
throw new import_ajv2.ValidationError([
|
|
1235
|
+
{
|
|
1236
|
+
keyword: "Directory",
|
|
1237
|
+
message: `must be a directory, not a file (${filePath})`
|
|
1238
|
+
}
|
|
1239
|
+
]);
|
|
1240
|
+
} else if (schema.mustBeFile && stats.isDirectory()) {
|
|
1241
|
+
throw new import_ajv2.ValidationError([
|
|
1242
|
+
{
|
|
1243
|
+
keyword: "File",
|
|
1244
|
+
message: `must be a file, not a directory (${filePath})`
|
|
1245
|
+
}
|
|
1246
|
+
]);
|
|
1247
|
+
}
|
|
1248
|
+
if (schema.mustBeElectronApp) {
|
|
1249
|
+
const appRoot = path6.resolve(filePath);
|
|
1250
|
+
const pkgPath = path6.join(appRoot, "package.json");
|
|
1251
|
+
if (!fs3.existsSync(pkgPath)) {
|
|
1252
|
+
throw new import_ajv2.ValidationError([
|
|
1253
|
+
{
|
|
1254
|
+
keyword: "App",
|
|
1255
|
+
message: `invalid. There is no package.json at ${pkgPath}`
|
|
1256
|
+
}
|
|
1257
|
+
]);
|
|
1258
|
+
}
|
|
1259
|
+
let pkg;
|
|
1260
|
+
try {
|
|
1261
|
+
pkg = require(pkgPath);
|
|
1262
|
+
} catch (e) {
|
|
1263
|
+
throw new import_ajv2.ValidationError([
|
|
1264
|
+
{
|
|
1265
|
+
keyword: "App",
|
|
1266
|
+
message: `invalid. Invalid JSON in package.json (${pkgPath})`
|
|
1267
|
+
}
|
|
1268
|
+
]);
|
|
1269
|
+
}
|
|
1270
|
+
context.projectRoot = appRoot;
|
|
1271
|
+
validatePackageJSON_default(pkg, pkgPath, context);
|
|
1272
|
+
const mainFilePath = pkg.main;
|
|
1273
|
+
if (mainFilePath) {
|
|
1274
|
+
const resolvedMainFilePath = path6.join(appRoot, mainFilePath);
|
|
1275
|
+
if (!fs3.existsSync(resolvedMainFilePath)) {
|
|
1276
|
+
throw new import_ajv2.ValidationError([
|
|
1277
|
+
{
|
|
1278
|
+
keyword: "App",
|
|
1279
|
+
message: `invalid. The "main" file specified in your package.json (${mainFilePath}) does not exist (${resolvedMainFilePath})`
|
|
1280
|
+
}
|
|
1281
|
+
]);
|
|
1282
|
+
}
|
|
1283
|
+
} else {
|
|
1284
|
+
if (!fs3.existsSync(path6.join(appRoot, "index.js"))) {
|
|
1285
|
+
throw new import_ajv2.ValidationError([
|
|
1286
|
+
{
|
|
1287
|
+
keyword: "App",
|
|
1288
|
+
message: 'invalid. There is neither a "main" property in your package.json nor an index.js at the root of your app'
|
|
1289
|
+
}
|
|
1290
|
+
]);
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
}
|
|
1294
|
+
return true;
|
|
1295
|
+
},
|
|
1296
|
+
errors: true
|
|
1297
|
+
});
|
|
1298
|
+
addKeyword({
|
|
1299
|
+
keyword: "npmAuthor",
|
|
1300
|
+
validate: (schema, data) => {
|
|
1301
|
+
const dataType = typeof data;
|
|
1302
|
+
if (dataType === "undefined") {
|
|
1303
|
+
return true;
|
|
1304
|
+
} else if (dataType === "string") {
|
|
1305
|
+
const parsedAuthor = (0, import_parse_author.default)(data);
|
|
1306
|
+
if (!parsedAuthor || !parsedAuthor.email) {
|
|
1307
|
+
throw new import_ajv2.ValidationError([
|
|
1308
|
+
{
|
|
1309
|
+
keyword: "author",
|
|
1310
|
+
message: `invalid. If you're using a string, it must look something like "Barney Rubble <b@rubble.com>", see https://docs.npmjs.com/files/package.json#people-fields-author-contributors`
|
|
1311
|
+
}
|
|
1312
|
+
]);
|
|
1313
|
+
}
|
|
1314
|
+
} else if (dataType === "object") {
|
|
1315
|
+
if (typeof data.name === "undefined") {
|
|
1316
|
+
throw new import_ajv2.ValidationError([
|
|
1317
|
+
{
|
|
1318
|
+
keyword: "author",
|
|
1319
|
+
message: `invalid. "name" property is missing.`
|
|
1320
|
+
}
|
|
1321
|
+
]);
|
|
1322
|
+
} else {
|
|
1323
|
+
if (typeof data.name !== "string") {
|
|
1324
|
+
throw new import_ajv2.ValidationError([
|
|
1325
|
+
{
|
|
1326
|
+
keyword: "author",
|
|
1327
|
+
message: `.name invalid. It must be a string`
|
|
1328
|
+
}
|
|
1329
|
+
]);
|
|
1330
|
+
}
|
|
1331
|
+
if (typeof data.email === "undefined") {
|
|
1332
|
+
throw new import_ajv2.ValidationError([
|
|
1333
|
+
{
|
|
1334
|
+
keyword: "author",
|
|
1335
|
+
message: `invalid. "email" property is missing.`
|
|
1336
|
+
}
|
|
1337
|
+
]);
|
|
1338
|
+
} else {
|
|
1339
|
+
if (typeof data.email === "string") {
|
|
1340
|
+
if (!(0, import_email_regex.default)({ exact: true }).test(data.email)) {
|
|
1341
|
+
throw new import_ajv2.ValidationError([
|
|
1342
|
+
{
|
|
1343
|
+
keyword: "author",
|
|
1344
|
+
message: `.email invalid. It does not look like an email.`
|
|
1345
|
+
}
|
|
1346
|
+
]);
|
|
1347
|
+
}
|
|
1348
|
+
} else {
|
|
1349
|
+
throw new import_ajv2.ValidationError([
|
|
1350
|
+
{
|
|
1351
|
+
keyword: "author",
|
|
1352
|
+
message: `.email invalid. It must be a string.`
|
|
1353
|
+
}
|
|
1354
|
+
]);
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
} else {
|
|
1359
|
+
throw new import_ajv2.ValidationError([
|
|
1360
|
+
{
|
|
1361
|
+
keyword: "author",
|
|
1362
|
+
message: "invalid. It must either be an object or string. See https://docs.npmjs.com/files/package.json#people-fields-author-contributors"
|
|
1363
|
+
}
|
|
1364
|
+
]);
|
|
1365
|
+
}
|
|
1366
|
+
return true;
|
|
1367
|
+
},
|
|
1368
|
+
errors: true
|
|
1369
|
+
});
|
|
1370
|
+
addKeyword({
|
|
1371
|
+
keyword: "semanticVersion",
|
|
1372
|
+
type: "string",
|
|
1373
|
+
validate: (schema, data) => {
|
|
1374
|
+
const keyword = (schema.packageName ? `${schema.packageName} ` : "") + "version";
|
|
1375
|
+
if (!(semver.valid(data) || semver.validRange(data))) {
|
|
1376
|
+
throw new import_ajv2.ValidationError([
|
|
1377
|
+
{
|
|
1378
|
+
keyword,
|
|
1379
|
+
message: "invalid. It must be a semantic version (see https://semver.org/)"
|
|
1380
|
+
}
|
|
1381
|
+
]);
|
|
1382
|
+
}
|
|
1383
|
+
if (schema.mustBeExact && (data.startsWith("~") || data.startsWith("^"))) {
|
|
1384
|
+
throw new import_ajv2.ValidationError([
|
|
1385
|
+
{
|
|
1386
|
+
keyword,
|
|
1387
|
+
message: "invalid. It must be an exact version. Good: 9.0.0. Bad: ^9.0.0"
|
|
1388
|
+
}
|
|
1389
|
+
]);
|
|
1390
|
+
}
|
|
1391
|
+
return true;
|
|
1392
|
+
}
|
|
1393
|
+
});
|
|
1394
|
+
};
|
|
1395
|
+
|
|
1396
|
+
// src/utilities/projectConfig/schema/full.ts
|
|
1397
|
+
var getItemOrArrayOfItemsSchema = (itemSchema) => {
|
|
1398
|
+
return {
|
|
1399
|
+
oneOf: [
|
|
1400
|
+
itemSchema,
|
|
1401
|
+
{
|
|
1402
|
+
type: "array",
|
|
1403
|
+
items: itemSchema
|
|
1404
|
+
}
|
|
1405
|
+
]
|
|
1406
|
+
};
|
|
1407
|
+
};
|
|
1408
|
+
var full_default = (context) => {
|
|
1409
|
+
const getIconSchema = (additionalAllowedExtensions = []) => {
|
|
1410
|
+
return {
|
|
1411
|
+
type: "string",
|
|
1412
|
+
file: {
|
|
1413
|
+
from: context.projectRoot,
|
|
1414
|
+
extensions: ["icns", "png", ...additionalAllowedExtensions],
|
|
1415
|
+
mustBeFile: true
|
|
1416
|
+
},
|
|
1417
|
+
minLength: 3
|
|
1418
|
+
};
|
|
1419
|
+
};
|
|
1420
|
+
return {
|
|
1421
|
+
type: "object",
|
|
1422
|
+
required: ["id", "icon", "schemaVersion"],
|
|
1423
|
+
properties: {
|
|
1424
|
+
appId: { type: "string", minLength: 1 },
|
|
1425
|
+
appFiles: {
|
|
1426
|
+
type: "array",
|
|
1427
|
+
items: {
|
|
1428
|
+
type: "string",
|
|
1429
|
+
minLength: 1
|
|
1430
|
+
},
|
|
1431
|
+
minItems: 1
|
|
1432
|
+
},
|
|
1433
|
+
appProtocolScheme: { type: "string", minLength: 1 },
|
|
1434
|
+
appPath: {
|
|
1435
|
+
type: "string",
|
|
1436
|
+
file: {
|
|
1437
|
+
from: context.projectRoot,
|
|
1438
|
+
isOptional: true,
|
|
1439
|
+
mustBeElectronApp: true
|
|
1440
|
+
}
|
|
1441
|
+
},
|
|
1442
|
+
asarUnpack: {
|
|
1443
|
+
oneOf: [
|
|
1444
|
+
{ type: "boolean" },
|
|
1445
|
+
{
|
|
1446
|
+
type: "array",
|
|
1447
|
+
items: {
|
|
1448
|
+
type: "string",
|
|
1449
|
+
minLength: 1
|
|
1450
|
+
},
|
|
1451
|
+
minItems: 1
|
|
1452
|
+
}
|
|
1453
|
+
]
|
|
1454
|
+
},
|
|
1455
|
+
copyright: { type: "string", minLength: 1 },
|
|
1456
|
+
electronMirror: {
|
|
1457
|
+
type: "string",
|
|
1458
|
+
format: "uri"
|
|
1459
|
+
},
|
|
1460
|
+
electronVersion: {
|
|
1461
|
+
type: "string",
|
|
1462
|
+
minLength: 1
|
|
1463
|
+
},
|
|
1464
|
+
extraContentFiles: {
|
|
1465
|
+
type: "array",
|
|
1466
|
+
items: {
|
|
1467
|
+
type: "object",
|
|
1468
|
+
required: ["from"],
|
|
1469
|
+
properties: {
|
|
1470
|
+
from: {
|
|
1471
|
+
type: "string",
|
|
1472
|
+
file: { from: context.projectRoot }
|
|
1473
|
+
},
|
|
1474
|
+
to: { type: "string" }
|
|
1475
|
+
}
|
|
1476
|
+
}
|
|
1477
|
+
},
|
|
1478
|
+
extraResources: {
|
|
1479
|
+
type: "array",
|
|
1480
|
+
items: {
|
|
1481
|
+
type: "object",
|
|
1482
|
+
required: ["from"],
|
|
1483
|
+
properties: {
|
|
1484
|
+
from: {
|
|
1485
|
+
type: "string",
|
|
1486
|
+
file: { from: context.projectRoot }
|
|
1487
|
+
},
|
|
1488
|
+
to: { type: "string" }
|
|
1489
|
+
}
|
|
1490
|
+
}
|
|
1491
|
+
},
|
|
1492
|
+
fileAssociations: {
|
|
1493
|
+
type: "array",
|
|
1494
|
+
items: {
|
|
1495
|
+
type: "object",
|
|
1496
|
+
required: ["ext"],
|
|
1497
|
+
properties: {
|
|
1498
|
+
ext: getItemOrArrayOfItemsSchema({
|
|
1499
|
+
type: "string",
|
|
1500
|
+
minLength: 1
|
|
1501
|
+
}),
|
|
1502
|
+
description: {
|
|
1503
|
+
type: "string",
|
|
1504
|
+
minLength: 1
|
|
1505
|
+
},
|
|
1506
|
+
name: {
|
|
1507
|
+
type: "string",
|
|
1508
|
+
minLength: 1
|
|
1509
|
+
},
|
|
1510
|
+
mimeType: {
|
|
1511
|
+
type: "string",
|
|
1512
|
+
minLength: 1
|
|
1513
|
+
},
|
|
1514
|
+
icon: {
|
|
1515
|
+
type: "string",
|
|
1516
|
+
minLength: 1
|
|
1517
|
+
},
|
|
1518
|
+
role: {
|
|
1519
|
+
type: "string",
|
|
1520
|
+
minLength: 1
|
|
1521
|
+
},
|
|
1522
|
+
isPackage: {
|
|
1523
|
+
type: "boolean"
|
|
1524
|
+
},
|
|
1525
|
+
rank: {
|
|
1526
|
+
type: "string",
|
|
1527
|
+
minLength: 1
|
|
1528
|
+
}
|
|
1529
|
+
}
|
|
1530
|
+
},
|
|
1531
|
+
minItems: 1
|
|
1532
|
+
},
|
|
1533
|
+
filesForDistribution: {
|
|
1534
|
+
type: "array",
|
|
1535
|
+
items: {
|
|
1536
|
+
type: "string",
|
|
1537
|
+
minLength: 1
|
|
1538
|
+
},
|
|
1539
|
+
minItems: 1
|
|
1540
|
+
},
|
|
1541
|
+
icon: getIconSchema(),
|
|
1542
|
+
linux: {
|
|
1543
|
+
type: "object",
|
|
1544
|
+
properties: {
|
|
1545
|
+
category: { type: "string", minLength: 1 },
|
|
1546
|
+
icon: getIconSchema(),
|
|
1547
|
+
noSandbox: { type: "boolean" }
|
|
1548
|
+
}
|
|
1549
|
+
},
|
|
1550
|
+
id: { type: "string", minLength: 1 },
|
|
1551
|
+
mac: {
|
|
1552
|
+
type: "object",
|
|
1553
|
+
properties: {
|
|
1554
|
+
category: { type: "string", minLength: 1 },
|
|
1555
|
+
additionalBinariesToSign: {
|
|
1556
|
+
type: "array",
|
|
1557
|
+
items: {
|
|
1558
|
+
type: "string",
|
|
1559
|
+
minLength: 1
|
|
1560
|
+
}
|
|
1561
|
+
},
|
|
1562
|
+
entitlements: {
|
|
1563
|
+
type: "string",
|
|
1564
|
+
file: {
|
|
1565
|
+
from: context.projectRoot,
|
|
1566
|
+
extensions: ["plist"],
|
|
1567
|
+
mustBeFile: true
|
|
1568
|
+
},
|
|
1569
|
+
minLength: 1
|
|
1570
|
+
},
|
|
1571
|
+
extendInfo: {
|
|
1572
|
+
type: "object"
|
|
1573
|
+
},
|
|
1574
|
+
icon: getIconSchema()
|
|
1575
|
+
}
|
|
1576
|
+
},
|
|
1577
|
+
dmg: {
|
|
1578
|
+
type: "object",
|
|
1579
|
+
properties: {
|
|
1580
|
+
background: {
|
|
1581
|
+
type: "string",
|
|
1582
|
+
file: {
|
|
1583
|
+
from: context.projectRoot,
|
|
1584
|
+
extensions: ["tiff"],
|
|
1585
|
+
mustBeFile: true
|
|
1586
|
+
},
|
|
1587
|
+
minLength: 1
|
|
1588
|
+
},
|
|
1589
|
+
artifactName: { type: "string", minLength: 1 },
|
|
1590
|
+
backgroundColor: { type: "string", minLength: 1 },
|
|
1591
|
+
iconSize: { type: "number" },
|
|
1592
|
+
iconTextSize: { type: "number" },
|
|
1593
|
+
title: { type: "string", minLength: 1 },
|
|
1594
|
+
contents: {
|
|
1595
|
+
type: "array",
|
|
1596
|
+
items: {
|
|
1597
|
+
type: "object",
|
|
1598
|
+
properties: {
|
|
1599
|
+
x: { type: "number" },
|
|
1600
|
+
y: { type: "number" }
|
|
1601
|
+
}
|
|
1602
|
+
}
|
|
1603
|
+
},
|
|
1604
|
+
window: {
|
|
1605
|
+
type: "object",
|
|
1606
|
+
properties: {
|
|
1607
|
+
x: { type: "number" },
|
|
1608
|
+
y: { type: "number" },
|
|
1609
|
+
width: { type: "number" },
|
|
1610
|
+
height: { type: "number" }
|
|
1611
|
+
}
|
|
1612
|
+
}
|
|
1613
|
+
}
|
|
1614
|
+
},
|
|
1615
|
+
schemaVersion: { type: "number", minimum: 1, maximum: 1 },
|
|
1616
|
+
snap: {
|
|
1617
|
+
type: "object",
|
|
1618
|
+
properties: {
|
|
1619
|
+
after: {
|
|
1620
|
+
type: "array",
|
|
1621
|
+
items: {
|
|
1622
|
+
type: "string",
|
|
1623
|
+
minLength: 1
|
|
1624
|
+
}
|
|
1625
|
+
},
|
|
1626
|
+
appPartStage: {
|
|
1627
|
+
type: "array",
|
|
1628
|
+
items: {
|
|
1629
|
+
type: "string",
|
|
1630
|
+
minLength: 1
|
|
1631
|
+
}
|
|
1632
|
+
},
|
|
1633
|
+
assumes: getItemOrArrayOfItemsSchema({
|
|
1634
|
+
type: "string",
|
|
1635
|
+
minLength: 1
|
|
1636
|
+
}),
|
|
1637
|
+
autoStart: {
|
|
1638
|
+
type: "boolean"
|
|
1639
|
+
},
|
|
1640
|
+
buildPackages: {
|
|
1641
|
+
type: "array",
|
|
1642
|
+
items: {
|
|
1643
|
+
type: "string",
|
|
1644
|
+
minLength: 1
|
|
1645
|
+
}
|
|
1646
|
+
},
|
|
1647
|
+
confinement: {
|
|
1648
|
+
type: "string",
|
|
1649
|
+
enum: ["classic", "devmode", "strict"]
|
|
1650
|
+
},
|
|
1651
|
+
environment: {
|
|
1652
|
+
type: "object"
|
|
1653
|
+
},
|
|
1654
|
+
grade: {
|
|
1655
|
+
type: "string",
|
|
1656
|
+
enum: ["devel", "stable"]
|
|
1657
|
+
},
|
|
1658
|
+
layout: {
|
|
1659
|
+
type: "object"
|
|
1660
|
+
},
|
|
1661
|
+
plugs: {
|
|
1662
|
+
type: "array",
|
|
1663
|
+
items: {
|
|
1664
|
+
anyOf: [
|
|
1665
|
+
{
|
|
1666
|
+
type: "string",
|
|
1667
|
+
minLength: 1
|
|
1668
|
+
},
|
|
1669
|
+
{
|
|
1670
|
+
type: "object"
|
|
1671
|
+
}
|
|
1672
|
+
]
|
|
1673
|
+
}
|
|
1674
|
+
},
|
|
1675
|
+
stagePackages: {
|
|
1676
|
+
type: "array",
|
|
1677
|
+
items: {
|
|
1678
|
+
type: "string",
|
|
1679
|
+
minLength: 1
|
|
1680
|
+
}
|
|
1681
|
+
},
|
|
1682
|
+
summary: {
|
|
1683
|
+
type: "string",
|
|
1684
|
+
maxLength: 78
|
|
1685
|
+
},
|
|
1686
|
+
useTemplateApp: {
|
|
1687
|
+
type: "boolean"
|
|
1688
|
+
}
|
|
1689
|
+
}
|
|
1690
|
+
},
|
|
1691
|
+
uploadSizeLimit: {
|
|
1692
|
+
type: "number"
|
|
1693
|
+
},
|
|
1694
|
+
windows: {
|
|
1695
|
+
type: "object",
|
|
1696
|
+
properties: {
|
|
1697
|
+
icon: getIconSchema(["ico"])
|
|
1698
|
+
}
|
|
1699
|
+
}
|
|
1700
|
+
}
|
|
1701
|
+
};
|
|
1702
|
+
};
|
|
1703
|
+
|
|
1704
|
+
// src/utilities/projectConfig/validateConfig.ts
|
|
1705
|
+
function validateConfig({
|
|
1706
|
+
config: config2,
|
|
1707
|
+
projectRoot
|
|
1708
|
+
}) {
|
|
1709
|
+
const context = { projectRoot };
|
|
1710
|
+
const schema = full_default(context);
|
|
1711
|
+
const ajv = new import_ajv3.default({ allErrors: true });
|
|
1712
|
+
(0, import_ajv_formats2.default)(ajv);
|
|
1713
|
+
addCustomKeywords_default(ajv, context);
|
|
1714
|
+
const validate = ajv.compile(schema);
|
|
1715
|
+
if (!validate(config2)) {
|
|
1716
|
+
const output = (0, import_better_ajv_errors2.default)(schema, config2, validate.errors, {
|
|
1717
|
+
indent: 2
|
|
1718
|
+
});
|
|
1719
|
+
throw new Error(
|
|
1720
|
+
`todesktop.json invalid.
|
|
1721
|
+
Learn more here: https://www.npmjs.com/package/@todesktop/cli#project-configuration-todesktopjson
|
|
1722
|
+
|
|
1723
|
+
${output}`
|
|
1724
|
+
);
|
|
1725
|
+
}
|
|
1726
|
+
if (config2.productName) {
|
|
1727
|
+
throw new Error(
|
|
1728
|
+
`todesktop.json invalid.
|
|
1729
|
+
|
|
1730
|
+
The "productName" property is no longer supported in todesktop.json. Please remove it and add it to your app's package.json instead.
|
|
1731
|
+
|
|
1732
|
+
We made this change because Electron also uses the "productName" if it exists in your app's package.json. If you do not add it to your package.json, your app name will default to the value of the "name" property in your package.json.`
|
|
1733
|
+
);
|
|
1734
|
+
}
|
|
1735
|
+
}
|
|
1736
|
+
|
|
1737
|
+
// src/utilities/projectConfig/computeFullProjectConfig.ts
|
|
1738
|
+
var import_path4 = require("path");
|
|
1739
|
+
var import_lodash2 = __toESM(require("lodash.merge"));
|
|
1740
|
+
function computeFullProjectConfig(partialConfig, projectRoot) {
|
|
1741
|
+
if (!partialConfig.extends) {
|
|
1742
|
+
logger_default.debug("No extends field, returning partial config");
|
|
1743
|
+
return partialConfig;
|
|
1744
|
+
} else {
|
|
1745
|
+
logger_default.debug("Extends field found, resolving");
|
|
1746
|
+
const parentConfigPath = (0, import_path4.resolve)(projectRoot, partialConfig.extends);
|
|
1747
|
+
const parentConfig = loadConfig(parentConfigPath);
|
|
1748
|
+
const parentFullConfig = computeFullProjectConfig(
|
|
1749
|
+
parentConfig,
|
|
1750
|
+
projectRoot
|
|
1751
|
+
);
|
|
1752
|
+
const result = (0, import_lodash2.default)({}, parentFullConfig, partialConfig);
|
|
1753
|
+
delete result.extends;
|
|
1754
|
+
return result;
|
|
1755
|
+
}
|
|
1756
|
+
}
|
|
1757
|
+
|
|
1758
|
+
// src/utilities/projectConfig/getProjectConfig.ts
|
|
1759
|
+
function getProjectConfig(configPath = null) {
|
|
1760
|
+
if (configPath === null) {
|
|
1761
|
+
logger_default.debug("No config path provided, searching for one");
|
|
1762
|
+
configPath = import_find_up.default.sync("todesktop.json");
|
|
1763
|
+
if (!configPath) {
|
|
1764
|
+
throw new Error(
|
|
1765
|
+
"Can not find todesktop.json in this folder or any parent folders"
|
|
1766
|
+
);
|
|
1767
|
+
}
|
|
1768
|
+
} else {
|
|
1769
|
+
if (typeof configPath === "undefined" || configPath === "") {
|
|
1770
|
+
logger_default.error("Provided config path is empty");
|
|
1771
|
+
throw new Error("No config path provided");
|
|
1772
|
+
}
|
|
1773
|
+
configPath = (0, import_path5.resolve)(process.cwd(), configPath);
|
|
1774
|
+
if (!(0, import_fs.existsSync)(configPath)) {
|
|
1775
|
+
logger_default.error("Provided config path does not exist");
|
|
1776
|
+
throw new Error(`Config file not found at ${configPath}`);
|
|
1777
|
+
}
|
|
1778
|
+
}
|
|
1779
|
+
const projectRoot = (0, import_path5.dirname)(configPath);
|
|
1780
|
+
const partialConfig = loadConfig(configPath);
|
|
1781
|
+
partialConfig.appPath = partialConfig.appPath || ".";
|
|
1782
|
+
const config2 = computeFullProjectConfig(partialConfig, projectRoot);
|
|
1783
|
+
validateConfig({ config: config2, projectRoot });
|
|
1784
|
+
const result = resolveConfigPaths({ config: config2, projectRoot });
|
|
1785
|
+
return { config: result, unprocessedConfig: config2, projectRoot };
|
|
1786
|
+
}
|
|
1787
|
+
|
|
1788
|
+
// src/utilities/postToFirebaseFunction.ts
|
|
1789
|
+
var import_axios = __toESM(require("axios"));
|
|
1790
|
+
var { TODESKTOP_CLI_FIREBASE_FUNCTIONS_BASE } = getEnvironmentVariables_default();
|
|
1791
|
+
async function postToFirebaseFunction_default(functionName, body = {}, config2 = {}) {
|
|
1792
|
+
logger_default.debug({ functionName, body, config: config2 }, "postToFirebaseFunction");
|
|
1793
|
+
try {
|
|
1794
|
+
const response = await import_axios.default.post(
|
|
1795
|
+
`${TODESKTOP_CLI_FIREBASE_FUNCTIONS_BASE}${functionName}`,
|
|
1796
|
+
body,
|
|
1797
|
+
config2
|
|
1798
|
+
);
|
|
1799
|
+
logger_default.debug(
|
|
1800
|
+
{ responseData: response.data },
|
|
1801
|
+
"postToFirebaseFunction: success"
|
|
1802
|
+
);
|
|
1803
|
+
return response.data;
|
|
1804
|
+
} catch (e) {
|
|
1805
|
+
logger_default.error({ error: e }, "postToFirebaseFunction: error");
|
|
1806
|
+
throw e;
|
|
1807
|
+
}
|
|
1808
|
+
}
|
|
1809
|
+
|
|
1810
|
+
// src/utilities/subscribeToFirebaseDoc.ts
|
|
1811
|
+
var subscribeToFirebaseDoc_default = async (key, receiver) => {
|
|
1812
|
+
const hasResolved = false;
|
|
1813
|
+
return new Promise((resolve4, reject) => {
|
|
1814
|
+
logger_default.debug({ key }, "subscribeToFirebaseDoc");
|
|
1815
|
+
firestore_default.doc(key).onSnapshot(
|
|
1816
|
+
(snapshot) => {
|
|
1817
|
+
receiver({
|
|
1818
|
+
snapshot,
|
|
1819
|
+
data: snapshot.exists ? snapshot.data() : void 0
|
|
1820
|
+
});
|
|
1821
|
+
if (!hasResolved) {
|
|
1822
|
+
resolve4();
|
|
1823
|
+
}
|
|
1824
|
+
},
|
|
1825
|
+
(err) => {
|
|
1826
|
+
reject(err);
|
|
1827
|
+
}
|
|
1828
|
+
);
|
|
1829
|
+
});
|
|
1830
|
+
};
|
|
1831
|
+
|
|
1832
|
+
// src/utilities/subscribeToBuild.ts
|
|
1833
|
+
var subscribeToBuild_default = async ({ appId, buildId, onDataReceived, userId }) => {
|
|
1834
|
+
try {
|
|
1835
|
+
return await subscribeToFirebaseDoc_default(
|
|
1836
|
+
`users/${userId}/applications/${appId}/builds/${buildId}`,
|
|
1837
|
+
async ({ data }) => {
|
|
1838
|
+
onDataReceived(data);
|
|
1839
|
+
}
|
|
1840
|
+
);
|
|
1841
|
+
} catch (e) {
|
|
1842
|
+
e.message = `Failed while subscribing to build; ${e.message}`;
|
|
1843
|
+
throw e;
|
|
1844
|
+
}
|
|
1845
|
+
};
|
|
1846
|
+
|
|
1847
|
+
// src/utilities/uploadApplicationSource.ts
|
|
1848
|
+
var import_fast_glob = __toESM(require("fast-glob"));
|
|
1849
|
+
var fs5 = __toESM(require("fs"));
|
|
1850
|
+
var path8 = __toESM(require("path"));
|
|
1851
|
+
|
|
1852
|
+
// src/utilities/generateS3Key.ts
|
|
1853
|
+
var generateS3Key_default = ({ appId, buildId, filenameSuffix }) => `${appId}/sourceArchives/${buildId}--${filenameSuffix}`;
|
|
1854
|
+
|
|
1855
|
+
// src/utilities/uploadToS3.ts
|
|
1856
|
+
var import_superagent = __toESM(require("superagent"));
|
|
1857
|
+
var import_util = __toESM(require("util"));
|
|
1858
|
+
var import_stream_to_array = __toESM(require("stream-to-array"));
|
|
1859
|
+
var { TODESKTOP_CLI_S3_BUCKET } = getEnvironmentVariables_default();
|
|
1860
|
+
var uploadToS3_default = async ({
|
|
1861
|
+
bucket = TODESKTOP_CLI_S3_BUCKET,
|
|
1862
|
+
inputStream,
|
|
1863
|
+
key,
|
|
1864
|
+
onProgress = () => {
|
|
1865
|
+
}
|
|
1866
|
+
}) => {
|
|
1867
|
+
const { data } = await getCallableFirebaseFunction_default("getSignedURL")({
|
|
1868
|
+
key
|
|
1869
|
+
});
|
|
1870
|
+
const body = await new Promise((resolve4) => {
|
|
1871
|
+
(0, import_stream_to_array.default)(inputStream).then(function(parts) {
|
|
1872
|
+
const buffers = parts.map(
|
|
1873
|
+
(part) => import_util.default.isBuffer(part) ? part : Buffer.from(part)
|
|
1874
|
+
);
|
|
1875
|
+
return resolve4(Buffer.concat(buffers));
|
|
1876
|
+
});
|
|
1877
|
+
});
|
|
1878
|
+
return new Promise((resolve4) => {
|
|
1879
|
+
import_superagent.default.put(data.signedURL).send(body).set("content-type", "application/zip").on("progress", (event) => onProgress(event)).end(() => {
|
|
1880
|
+
logger_default.debug({ bucket, key, url: data.uploadURL }, "uploadToS3");
|
|
1881
|
+
resolve4({ bucket, key, url: data.uploadURL });
|
|
1882
|
+
});
|
|
1883
|
+
return { bucket, key, url: data.uploadURL };
|
|
1884
|
+
});
|
|
1885
|
+
};
|
|
1886
|
+
|
|
1887
|
+
// src/utilities/zip.ts
|
|
1888
|
+
var import_archiver = __toESM(require("archiver"));
|
|
1889
|
+
var import_du = __toESM(require("du"));
|
|
1890
|
+
var import_fs2 = __toESM(require("fs"));
|
|
1891
|
+
var import_chalk = __toESM(require("chalk"));
|
|
1892
|
+
var import_path6 = __toESM(require("path"));
|
|
1893
|
+
async function zip_default({
|
|
1894
|
+
files,
|
|
1895
|
+
fileSizeLimit = 20,
|
|
1896
|
+
onError,
|
|
1897
|
+
onProgress,
|
|
1898
|
+
appPkgJson
|
|
1899
|
+
}) {
|
|
1900
|
+
logger_default.debug({ files }, "zip");
|
|
1901
|
+
const stream = (0, import_archiver.default)("zip");
|
|
1902
|
+
stream.on("warning", function(err) {
|
|
1903
|
+
if (err.code === "ENOENT") {
|
|
1904
|
+
console.warn(err);
|
|
1905
|
+
logger_default.warn({ err }, "zip: stream warning ENOENT");
|
|
1906
|
+
} else {
|
|
1907
|
+
onError(err);
|
|
1908
|
+
}
|
|
1909
|
+
});
|
|
1910
|
+
stream.on("error", function(err) {
|
|
1911
|
+
onError(err);
|
|
1912
|
+
});
|
|
1913
|
+
const processedFiles = await Promise.all(
|
|
1914
|
+
files.map(async (file) => {
|
|
1915
|
+
const stats = import_fs2.default.lstatSync(file.from);
|
|
1916
|
+
const isDirectory = stats.isDirectory();
|
|
1917
|
+
return {
|
|
1918
|
+
...file,
|
|
1919
|
+
isDirectory,
|
|
1920
|
+
stats,
|
|
1921
|
+
size: isDirectory ? await (0, import_du.default)(file.from) : stats.size
|
|
1922
|
+
};
|
|
1923
|
+
})
|
|
1924
|
+
);
|
|
1925
|
+
const totalFileSize = processedFiles.reduce((sum, b) => sum + b.size, 0);
|
|
1926
|
+
if (totalFileSize > fileSizeLimit * 1e6) {
|
|
1927
|
+
onError(
|
|
1928
|
+
new Error(
|
|
1929
|
+
[
|
|
1930
|
+
`
|
|
1931
|
+
|
|
1932
|
+
Your app is larger than ${fileSizeLimit}MB. Your app is ${import_chalk.default.bold.red.underline(
|
|
1933
|
+
(totalFileSize / 1e6).toFixed(1) + "MB"
|
|
1934
|
+
)}.
|
|
1935
|
+
`,
|
|
1936
|
+
`You may be including unnecessary files in your app(see the \`appPath\` and \`appFiles\` options).`,
|
|
1937
|
+
`If not, this limit can be raised by setting the \`uploadSizeLimit\` option.`,
|
|
1938
|
+
`Learn more at https://www.npmjs.com/package/@todesktop/cli#uploadsizelimit---optional-number`
|
|
1939
|
+
].join("\n")
|
|
1940
|
+
)
|
|
1941
|
+
);
|
|
1942
|
+
return stream;
|
|
1943
|
+
}
|
|
1944
|
+
processedFiles.forEach(({ from, isDirectory, stats, to }) => {
|
|
1945
|
+
if (isDirectory) {
|
|
1946
|
+
stream.directory(from, to);
|
|
1947
|
+
} else if (appPkgJson && to === import_path6.default.join("app", "package.json")) {
|
|
1948
|
+
stream.append(JSON.stringify(appPkgJson), {
|
|
1949
|
+
name: to
|
|
1950
|
+
});
|
|
1951
|
+
} else {
|
|
1952
|
+
stream.file(from, { name: to, mode: stats.mode });
|
|
1953
|
+
}
|
|
1954
|
+
});
|
|
1955
|
+
stream.finalize();
|
|
1956
|
+
stream.on(
|
|
1957
|
+
"progress",
|
|
1958
|
+
(progress) => onProgress({
|
|
1959
|
+
...progress,
|
|
1960
|
+
percentage: progress.entries.processed / progress.entries.total * 100
|
|
1961
|
+
})
|
|
1962
|
+
);
|
|
1963
|
+
return stream;
|
|
1964
|
+
}
|
|
1965
|
+
|
|
1966
|
+
// src/utilities/uploadApplicationSource.ts
|
|
1967
|
+
var getAppFiles = async (globsInput, appPath, appPkgJson) => {
|
|
1968
|
+
const globs = ["!node_modules", "!**/node_modules", "!.git", "!**/.git"];
|
|
1969
|
+
if (globsInput && globsInput.length) {
|
|
1970
|
+
globs.push(
|
|
1971
|
+
...globsInput,
|
|
1972
|
+
path8.join(appPath, "package.json"),
|
|
1973
|
+
path8.join(appPath, "package-lock.json"),
|
|
1974
|
+
path8.join(appPath, "yarn.lock"),
|
|
1975
|
+
path8.join(appPath, "pnpm-lock.yaml"),
|
|
1976
|
+
path8.join(appPath, "shrinkwrap.yaml")
|
|
1977
|
+
);
|
|
1978
|
+
} else {
|
|
1979
|
+
globs.push("**");
|
|
1980
|
+
}
|
|
1981
|
+
for (const hookName of ["todesktop:beforeInstall", "todesktop:afterPack"]) {
|
|
1982
|
+
if (appPkgJson.scripts && appPkgJson.scripts[hookName]) {
|
|
1983
|
+
globs.push(path8.join(appPath, appPkgJson.scripts[hookName]));
|
|
1984
|
+
}
|
|
1985
|
+
}
|
|
1986
|
+
const normalizedGlobs = globs.map((glob) => {
|
|
1987
|
+
const globToUse = path8.isAbsolute(glob) ? path8.relative(appPath, glob) : glob;
|
|
1988
|
+
return globToUse.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
1989
|
+
}).filter((glob) => !glob.startsWith("..") && !glob.startsWith("!.."));
|
|
1990
|
+
let absolutePaths = await (0, import_fast_glob.default)(normalizedGlobs, {
|
|
1991
|
+
absolute: true,
|
|
1992
|
+
cwd: appPath,
|
|
1993
|
+
dot: true,
|
|
1994
|
+
followSymbolicLinks: false,
|
|
1995
|
+
onlyDirectories: false,
|
|
1996
|
+
onlyFiles: true,
|
|
1997
|
+
globstar: true,
|
|
1998
|
+
unique: true
|
|
1999
|
+
});
|
|
2000
|
+
if (process.platform === "win32") {
|
|
2001
|
+
absolutePaths = absolutePaths.map(
|
|
2002
|
+
(absolutePath) => absolutePath.replace(/\//g, path8.sep)
|
|
2003
|
+
);
|
|
2004
|
+
}
|
|
2005
|
+
if (!absolutePaths || !absolutePaths.length) {
|
|
2006
|
+
throw new Error("No files found to upload");
|
|
2007
|
+
} else if (!absolutePaths.filter((absolutePath) => absolutePath.endsWith(".js")).length) {
|
|
2008
|
+
throw new Error(
|
|
2009
|
+
`No .js files found to upload (${absolutePaths[0]}). There's likely an issue with the appFiles option. Learn more at https://www.npmjs.com/package/@todesktop/cli#appfiles----optional-array-of-glob-patterns. If this is not the case, please contact us.`
|
|
2010
|
+
);
|
|
2011
|
+
} else {
|
|
2012
|
+
let mainFilePath = appPath;
|
|
2013
|
+
if (appPkgJson.main) {
|
|
2014
|
+
mainFilePath = path8.join(mainFilePath, appPkgJson.main);
|
|
2015
|
+
}
|
|
2016
|
+
if (fs5.statSync(mainFilePath).isDirectory()) {
|
|
2017
|
+
mainFilePath = path8.join(mainFilePath, "index.js");
|
|
2018
|
+
}
|
|
2019
|
+
if (!absolutePaths.includes(mainFilePath)) {
|
|
2020
|
+
throw new Error(
|
|
2021
|
+
`The "main" file specified in your package.json (${appPkgJson.main ? path8.relative(appPath, mainFilePath) : "defaults to index.js"}) is not set to be uploaded to our servers. This is likely due to how you have configured the \`appFiles\` option. Learn more at https://www.npmjs.com/package/@todesktop/cli#appfiles----optional-array-of-glob-patterns. If this is not the case, please contact us.`
|
|
2022
|
+
);
|
|
2023
|
+
}
|
|
2024
|
+
}
|
|
2025
|
+
return absolutePaths.map((absolutePath) => {
|
|
2026
|
+
return {
|
|
2027
|
+
from: absolutePath,
|
|
2028
|
+
to: path8.join("app", path8.relative(appPath, absolutePath))
|
|
2029
|
+
};
|
|
2030
|
+
});
|
|
2031
|
+
};
|
|
2032
|
+
var uploadApplicationSource_default = async ({ appId, appPkgJson, buildId, config: config2, onProgress }) => {
|
|
2033
|
+
logger_default.debug(
|
|
2034
|
+
{
|
|
2035
|
+
appId,
|
|
2036
|
+
appPkgJson,
|
|
2037
|
+
buildId,
|
|
2038
|
+
config: config2,
|
|
2039
|
+
onProgress
|
|
2040
|
+
},
|
|
2041
|
+
"uploadApplicationSource"
|
|
2042
|
+
);
|
|
2043
|
+
let totalBytes = 0;
|
|
2044
|
+
const files = [
|
|
2045
|
+
...await getAppFiles(config2.appFiles, config2.appPath, appPkgJson),
|
|
2046
|
+
...(config2.extraContentFiles || []).map(({ from, to = "." }) => {
|
|
2047
|
+
return {
|
|
2048
|
+
from,
|
|
2049
|
+
to: path8.join("extraContentFiles", to, path8.basename(from))
|
|
2050
|
+
};
|
|
2051
|
+
}),
|
|
2052
|
+
...(config2.extraResources || []).map(({ from, to = "." }) => {
|
|
2053
|
+
return {
|
|
2054
|
+
from,
|
|
2055
|
+
to: path8.join("extraResources", to, path8.basename(from))
|
|
2056
|
+
};
|
|
2057
|
+
}),
|
|
2058
|
+
{
|
|
2059
|
+
from: config2.icon,
|
|
2060
|
+
to: path8.join("icons", "appIcon" + path8.extname(config2.icon))
|
|
2061
|
+
}
|
|
2062
|
+
];
|
|
2063
|
+
if (config2.linux) {
|
|
2064
|
+
if (config2.linux.icon) {
|
|
2065
|
+
files.push({
|
|
2066
|
+
from: config2.linux.icon,
|
|
2067
|
+
to: path8.join(
|
|
2068
|
+
"icons",
|
|
2069
|
+
"appIcon-linux" + path8.extname(config2.linux.icon)
|
|
2070
|
+
)
|
|
2071
|
+
});
|
|
2072
|
+
}
|
|
2073
|
+
}
|
|
2074
|
+
if (config2.mac) {
|
|
2075
|
+
if (config2.mac.entitlements) {
|
|
2076
|
+
files.push({
|
|
2077
|
+
from: config2.mac.entitlements,
|
|
2078
|
+
to: path8.join("other", "mac", "entitlements.mac.plist")
|
|
2079
|
+
});
|
|
2080
|
+
}
|
|
2081
|
+
if (config2.mac.icon) {
|
|
2082
|
+
files.push({
|
|
2083
|
+
from: config2.mac.icon,
|
|
2084
|
+
to: path8.join("icons", "appIcon-mac" + path8.extname(config2.mac.icon))
|
|
2085
|
+
});
|
|
2086
|
+
}
|
|
2087
|
+
}
|
|
2088
|
+
if (config2.dmg) {
|
|
2089
|
+
if (config2.dmg.background) {
|
|
2090
|
+
files.push({
|
|
2091
|
+
from: config2.dmg.background,
|
|
2092
|
+
to: path8.join("other", "mac", "dmg-background.tiff")
|
|
2093
|
+
});
|
|
2094
|
+
}
|
|
2095
|
+
}
|
|
2096
|
+
if (config2.windows) {
|
|
2097
|
+
if (config2.windows.icon) {
|
|
2098
|
+
files.push({
|
|
2099
|
+
from: config2.windows.icon,
|
|
2100
|
+
to: path8.join(
|
|
2101
|
+
"icons",
|
|
2102
|
+
"appIcon-windows" + path8.extname(config2.windows.icon)
|
|
2103
|
+
)
|
|
2104
|
+
});
|
|
2105
|
+
}
|
|
2106
|
+
}
|
|
2107
|
+
return uploadToS3_default({
|
|
2108
|
+
bucket: config2.bucket || void 0,
|
|
2109
|
+
inputStream: await zip_default({
|
|
2110
|
+
files,
|
|
2111
|
+
fileSizeLimit: config2.uploadSizeLimit,
|
|
2112
|
+
onError: (e) => {
|
|
2113
|
+
throw e;
|
|
2114
|
+
},
|
|
2115
|
+
onProgress({ fs: fs6 }) {
|
|
2116
|
+
totalBytes = fs6.totalBytes;
|
|
2117
|
+
},
|
|
2118
|
+
appPkgJson
|
|
2119
|
+
}),
|
|
2120
|
+
key: generateS3Key_default({
|
|
2121
|
+
appId,
|
|
2122
|
+
buildId,
|
|
2123
|
+
filenameSuffix: `${appPkgJson.name}.zip`
|
|
2124
|
+
}),
|
|
2125
|
+
onProgress({ loaded, total }) {
|
|
2126
|
+
onProgress(loaded / total * 100, loaded);
|
|
2127
|
+
}
|
|
2128
|
+
});
|
|
2129
|
+
};
|
|
2130
|
+
|
|
2131
|
+
// src/utilities/getPackageJson.ts
|
|
2132
|
+
var import_lodash3 = __toESM(require("lodash.merge"));
|
|
2133
|
+
var import_path7 = __toESM(require("path"));
|
|
2134
|
+
function deleteNullDeps(dep) {
|
|
2135
|
+
Object.keys(dep).forEach((key) => {
|
|
2136
|
+
if (dep[key] === null) {
|
|
2137
|
+
delete dep[key];
|
|
2138
|
+
}
|
|
2139
|
+
});
|
|
2140
|
+
return dep;
|
|
2141
|
+
}
|
|
2142
|
+
function removeNullDependencies(pkgJson) {
|
|
2143
|
+
const { dependencies, devDependencies } = pkgJson;
|
|
2144
|
+
if (dependencies) {
|
|
2145
|
+
pkgJson.dependencies = deleteNullDeps(dependencies);
|
|
2146
|
+
}
|
|
2147
|
+
if (devDependencies) {
|
|
2148
|
+
pkgJson.devDependencies = deleteNullDeps(devDependencies);
|
|
2149
|
+
}
|
|
2150
|
+
return pkgJson;
|
|
2151
|
+
}
|
|
2152
|
+
function getAppPkgJson({ config: config2 }) {
|
|
2153
|
+
const packageJsonFromConfig = config2.packageJson || {};
|
|
2154
|
+
const extendsFrom = packageJsonFromConfig.extends || "package.json";
|
|
2155
|
+
const packageJsonFromFile = readJson(import_path7.default.join(config2.appPath, extendsFrom));
|
|
2156
|
+
return removeNullDependencies(
|
|
2157
|
+
(0, import_lodash3.default)({}, packageJsonFromFile, packageJsonFromConfig)
|
|
2158
|
+
);
|
|
2159
|
+
}
|
|
2160
|
+
var getPackageJson_default = getAppPkgJson;
|
|
2161
|
+
|
|
2162
|
+
// src/utilities/runBuild.ts
|
|
2163
|
+
var runBuild_default = async ({ onEvent, shouldCodeSign = true, configPath }) => {
|
|
2164
|
+
logForCI_default("Getting application information...");
|
|
2165
|
+
const primaryUserId = currentUser().uid;
|
|
2166
|
+
const { config: config2, unprocessedConfig } = getProjectConfig(configPath);
|
|
2167
|
+
const appId = config2.id;
|
|
2168
|
+
const appPkgJson = getPackageJson_default({ config: config2 });
|
|
2169
|
+
onEvent("progress", {
|
|
2170
|
+
appId,
|
|
2171
|
+
appPkg: appPkgJson,
|
|
2172
|
+
preparationProgress: 0.02
|
|
2173
|
+
});
|
|
2174
|
+
logForCI_default("Preparing...");
|
|
2175
|
+
let buildId;
|
|
2176
|
+
try {
|
|
2177
|
+
const prepareResult = await postToFirebaseFunction_default("prepareNewBuild", {
|
|
2178
|
+
appPkgName: appPkgJson.name,
|
|
2179
|
+
appPkgProductName: appPkgJson.productName,
|
|
2180
|
+
appVersion: appPkgJson.version,
|
|
2181
|
+
id: config2.id,
|
|
2182
|
+
projectConfig: unprocessedConfig,
|
|
2183
|
+
shouldCodeSign: shouldCodeSign !== false,
|
|
2184
|
+
shouldRelease: false,
|
|
2185
|
+
userId: primaryUserId,
|
|
2186
|
+
versionControlInfo: await getVersionControlInfo_default(config2.appPath)
|
|
2187
|
+
});
|
|
2188
|
+
buildId = prepareResult.appData.meta.currentBuildProgress.id;
|
|
2189
|
+
const firebaseUnsubscribe = await subscribeToBuild_default({
|
|
2190
|
+
appId,
|
|
2191
|
+
buildId,
|
|
2192
|
+
onDataReceived: (data) => onEvent("progress", { build: data }),
|
|
2193
|
+
userId: prepareResult.userId
|
|
2194
|
+
});
|
|
2195
|
+
onEvent("firebase-subscribed", { firebaseUnsubscribe });
|
|
2196
|
+
} catch (e) {
|
|
2197
|
+
e.message = `Failed while preparing new build; ${e.message}`;
|
|
2198
|
+
throw e;
|
|
2199
|
+
}
|
|
2200
|
+
onEvent("progress", {
|
|
2201
|
+
preparationProgress: 0.05,
|
|
2202
|
+
preparationStageLabel: "Uploading"
|
|
2203
|
+
});
|
|
2204
|
+
logForCI_default("Uploading...");
|
|
2205
|
+
let sourceArchiveDetails;
|
|
2206
|
+
try {
|
|
2207
|
+
const uploadAppSourceResult = await uploadApplicationSource_default({
|
|
2208
|
+
appId,
|
|
2209
|
+
appPkgJson,
|
|
2210
|
+
buildId,
|
|
2211
|
+
config: config2,
|
|
2212
|
+
onProgress(progress, uploadedSize) {
|
|
2213
|
+
const dataToEmit = {
|
|
2214
|
+
preparationProgress: 0.05 + progress / 100 * 0.95,
|
|
2215
|
+
preparationUploadedSize: ""
|
|
2216
|
+
};
|
|
2217
|
+
if (uploadedSize) {
|
|
2218
|
+
dataToEmit.preparationUploadedSize = (0, import_pretty_bytes.default)(uploadedSize);
|
|
2219
|
+
}
|
|
2220
|
+
onEvent("progress", dataToEmit);
|
|
2221
|
+
}
|
|
2222
|
+
});
|
|
2223
|
+
sourceArchiveDetails = uploadAppSourceResult;
|
|
2224
|
+
} catch (e) {
|
|
2225
|
+
e.message = `Failed while uploading application source; ${e.message}`;
|
|
2226
|
+
throw e;
|
|
2227
|
+
}
|
|
2228
|
+
onEvent("progress", { isPreparationComplete: true });
|
|
2229
|
+
logForCI_default("Kicking off build...");
|
|
2230
|
+
try {
|
|
2231
|
+
await postToFirebaseFunction_default("kickOffBuild", {
|
|
2232
|
+
appId,
|
|
2233
|
+
appPkgName: appPkgJson.name,
|
|
2234
|
+
appVersion: appPkgJson.version,
|
|
2235
|
+
buildId,
|
|
2236
|
+
userId: primaryUserId,
|
|
2237
|
+
sourceArchiveDetails
|
|
2238
|
+
});
|
|
2239
|
+
} catch (e) {
|
|
2240
|
+
e.message = `Failed while kicking off build; ${e.message}`;
|
|
2241
|
+
throw e;
|
|
2242
|
+
}
|
|
2243
|
+
};
|
|
2244
|
+
|
|
2245
|
+
// src/utilities/shouldExitOnBuildFailure.ts
|
|
2246
|
+
var shouldExitOnBuildFailure_default = (build) => {
|
|
2247
|
+
const hasBuildSettled = ["linux", "mac", "windows"].every(
|
|
2248
|
+
(platform) => build[platform].shouldSkip || "succeeded" === build[platform].status || "failed" === build[platform].status && build[platform].numberOfAttemptedBuilds === 2
|
|
2249
|
+
);
|
|
2250
|
+
const hasSettledWithError = ["linux", "mac", "windows"].some(
|
|
2251
|
+
(platform) => "failed" === build[platform].status
|
|
2252
|
+
);
|
|
2253
|
+
return hasBuildSettled && hasSettledWithError;
|
|
2254
|
+
};
|
|
2255
|
+
|
|
2256
|
+
// src/components/Build.tsx
|
|
2257
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
2258
|
+
var initalState = {
|
|
2259
|
+
appId: null,
|
|
2260
|
+
appPkg: null,
|
|
2261
|
+
build: null,
|
|
2262
|
+
error: null,
|
|
2263
|
+
hasBuildEverFailed: false,
|
|
2264
|
+
isPreparationComplete: false,
|
|
2265
|
+
preparationStageLabel: "Preparing",
|
|
2266
|
+
preparationProgress: 0,
|
|
2267
|
+
preparationUploadedSize: null
|
|
2268
|
+
};
|
|
2269
|
+
var Build = ({ commandUsed, shouldCodeSign = true, configPath }) => {
|
|
2270
|
+
const exit = useExit_default();
|
|
2271
|
+
const [
|
|
2272
|
+
{
|
|
2273
|
+
appId,
|
|
2274
|
+
appPkg,
|
|
2275
|
+
build,
|
|
2276
|
+
error,
|
|
2277
|
+
hasBuildEverFailed,
|
|
2278
|
+
isPreparationComplete,
|
|
2279
|
+
preparationStageLabel,
|
|
2280
|
+
preparationProgress,
|
|
2281
|
+
preparationUploadedSize
|
|
2282
|
+
},
|
|
2283
|
+
setState
|
|
2284
|
+
] = (0, import_react6.useState)(initalState);
|
|
2285
|
+
const onError = (e) => {
|
|
2286
|
+
const error2 = e.response ? e.response.data : e;
|
|
2287
|
+
logForCI_default(error2);
|
|
2288
|
+
setState((prevState) => ({
|
|
2289
|
+
...prevState,
|
|
2290
|
+
error: error2
|
|
2291
|
+
}));
|
|
2292
|
+
};
|
|
2293
|
+
(0, import_react6.useEffect)(() => {
|
|
2294
|
+
let firebaseUnsubscribe;
|
|
2295
|
+
runBuild_default({
|
|
2296
|
+
onEvent: (eventName, data) => {
|
|
2297
|
+
logger_default.debug({ eventName, data }, "Build component: runBuild.onEvent");
|
|
2298
|
+
if (eventName === "firebase-subscribed") {
|
|
2299
|
+
firebaseUnsubscribe = data.firebaseUnsubscribe;
|
|
2300
|
+
} else if (eventName === "progress") {
|
|
2301
|
+
setState((prevState) => ({ ...prevState, ...data }));
|
|
2302
|
+
}
|
|
2303
|
+
},
|
|
2304
|
+
shouldCodeSign,
|
|
2305
|
+
configPath
|
|
2306
|
+
}).catch(onError);
|
|
2307
|
+
return () => {
|
|
2308
|
+
if (firebaseUnsubscribe) {
|
|
2309
|
+
firebaseUnsubscribe();
|
|
2310
|
+
}
|
|
2311
|
+
};
|
|
2312
|
+
}, [commandUsed, shouldCodeSign, configPath]);
|
|
2313
|
+
(0, import_react6.useEffect)(() => {
|
|
2314
|
+
if (hasBuildEverFailed && shouldExitOnBuildFailure_default(build)) {
|
|
2315
|
+
setTimeout(() => exit(new Error("Build has failed")), 10);
|
|
2316
|
+
}
|
|
2317
|
+
}, [build, exit, hasBuildEverFailed]);
|
|
2318
|
+
if (error) {
|
|
2319
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ErrorDisplay_default, { commandUsed, error });
|
|
2320
|
+
}
|
|
2321
|
+
if (!appPkg) {
|
|
2322
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(InitialLoadingState_default, {});
|
|
2323
|
+
}
|
|
2324
|
+
const onBuildFailure = () => {
|
|
2325
|
+
if (hasBuildEverFailed) {
|
|
2326
|
+
return;
|
|
2327
|
+
}
|
|
2328
|
+
setState((prevState) => ({
|
|
2329
|
+
...prevState,
|
|
2330
|
+
hasBuildEverFailed: true
|
|
2331
|
+
}));
|
|
2332
|
+
};
|
|
2333
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2334
|
+
MainLayout_default,
|
|
2335
|
+
{
|
|
2336
|
+
appId,
|
|
2337
|
+
appName: build && build.appName || appPkg.name,
|
|
2338
|
+
appVersion: build && build.appVersion || appPkg.version,
|
|
2339
|
+
build,
|
|
2340
|
+
commandUsed,
|
|
2341
|
+
hasBuildEverFailed,
|
|
2342
|
+
children: isPreparationComplete ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(BuildProgress_default, { build, onBuildFailure }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2343
|
+
Preparation_default,
|
|
2344
|
+
{
|
|
2345
|
+
progressPercentage: preparationProgress,
|
|
2346
|
+
stageLabel: preparationStageLabel,
|
|
2347
|
+
uploadedSize: preparationUploadedSize
|
|
2348
|
+
}
|
|
2349
|
+
)
|
|
2350
|
+
}
|
|
2351
|
+
);
|
|
2352
|
+
};
|
|
2353
|
+
Build.propTypes = {
|
|
2354
|
+
commandUsed: import_prop_types9.default.string.isRequired,
|
|
2355
|
+
shouldCodeSign: import_prop_types9.default.bool,
|
|
2356
|
+
configPath: import_prop_types9.default.string
|
|
2357
|
+
};
|
|
2358
|
+
var Build_default = Build;
|
|
2359
|
+
|
|
2360
|
+
// src/utilities/checkIfReactIsUsable.ts
|
|
2361
|
+
var import_react7 = require("react");
|
|
2362
|
+
var checkIfReactIsUsable_default = ({ cons = console, proc = process } = {}) => {
|
|
2363
|
+
try {
|
|
2364
|
+
(0, import_react7.useState)(null);
|
|
2365
|
+
} catch (e) {
|
|
2366
|
+
cons.error(e);
|
|
2367
|
+
proc.exit(1);
|
|
2368
|
+
}
|
|
2369
|
+
};
|
|
2370
|
+
|
|
2371
|
+
// src/components/LoginHOC.tsx
|
|
2372
|
+
var import_ink16 = require("ink");
|
|
2373
|
+
var import_react10 = require("react");
|
|
2374
|
+
var import_prop_types11 = __toESM(require("prop-types"));
|
|
2375
|
+
var import_is_ci4 = __toESM(require("is-ci"));
|
|
2376
|
+
|
|
2377
|
+
// src/components/Login.tsx
|
|
2378
|
+
var import_ink14 = require("ink");
|
|
2379
|
+
var import_prop_types10 = __toESM(require("prop-types"));
|
|
2380
|
+
var import_react9 = require("react");
|
|
2381
|
+
var import_react_final_form = require("react-final-form");
|
|
2382
|
+
|
|
2383
|
+
// src/components/TextInput.tsx
|
|
2384
|
+
var import_ink_text_input = __toESM(require("ink-text-input"));
|
|
2385
|
+
var import_react8 = __toESM(require("react"));
|
|
2386
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
2387
|
+
var TextInput = ({ onBlur, onFocus, ...props }) => {
|
|
2388
|
+
import_react8.default.useEffect(() => {
|
|
2389
|
+
onFocus();
|
|
2390
|
+
return onBlur;
|
|
2391
|
+
}, [onFocus, onBlur]);
|
|
2392
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_ink_text_input.default, { ...props, showCursor: true });
|
|
2393
|
+
};
|
|
2394
|
+
var TextInput_default = TextInput;
|
|
2395
|
+
|
|
2396
|
+
// src/components/Login.tsx
|
|
2397
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
2398
|
+
var loginFields = [
|
|
2399
|
+
{
|
|
2400
|
+
name: "email",
|
|
2401
|
+
label: "Your email",
|
|
2402
|
+
placeholder: "name@email.com",
|
|
2403
|
+
Input: TextInput_default,
|
|
2404
|
+
validate: (value) => {
|
|
2405
|
+
if (!value)
|
|
2406
|
+
return "Required";
|
|
2407
|
+
}
|
|
2408
|
+
},
|
|
2409
|
+
{
|
|
2410
|
+
name: "accessToken",
|
|
2411
|
+
label: "Your access token",
|
|
2412
|
+
placeholder: "********",
|
|
2413
|
+
Input: TextInput_default,
|
|
2414
|
+
validate: (value) => {
|
|
2415
|
+
if (!value)
|
|
2416
|
+
return "Required";
|
|
2417
|
+
},
|
|
2418
|
+
mask: "*"
|
|
2419
|
+
}
|
|
2420
|
+
];
|
|
2421
|
+
var Login = ({ setIsLoggedIn }) => {
|
|
2422
|
+
const [activeField, setActiveField] = (0, import_react9.useState)(0);
|
|
2423
|
+
const [error, setError] = (0, import_react9.useState)(null);
|
|
2424
|
+
const [failureMessage, setFailureMessage] = (0, import_react9.useState)(null);
|
|
2425
|
+
const [isSubmittingForm, setIsSubmittingForm] = (0, import_react9.useState)(false);
|
|
2426
|
+
const onFailure = (message2) => {
|
|
2427
|
+
setIsSubmittingForm(false);
|
|
2428
|
+
setFailureMessage(message2);
|
|
2429
|
+
setActiveField(0);
|
|
2430
|
+
};
|
|
2431
|
+
const onSubmitLogin = async ({ email, accessToken }) => {
|
|
2432
|
+
setFailureMessage(null);
|
|
2433
|
+
setIsSubmittingForm(true);
|
|
2434
|
+
try {
|
|
2435
|
+
const jwtToken = await postToFirebaseFunction_default("loginWithAccessToken", {
|
|
2436
|
+
email,
|
|
2437
|
+
accessToken
|
|
2438
|
+
});
|
|
2439
|
+
if (jwtToken) {
|
|
2440
|
+
await signInWithCustomToken(jwtToken);
|
|
2441
|
+
setAuthConfig(email, accessToken, jwtToken);
|
|
2442
|
+
setIsLoggedIn(true);
|
|
2443
|
+
} else {
|
|
2444
|
+
onFailure("Incorrrect credentials. Try again");
|
|
2445
|
+
}
|
|
2446
|
+
} catch (err) {
|
|
2447
|
+
if (err.code === 500) {
|
|
2448
|
+
setError(err);
|
|
2449
|
+
} else {
|
|
2450
|
+
onFailure(`Login unsuccessful: ${err.message}`);
|
|
2451
|
+
}
|
|
2452
|
+
}
|
|
2453
|
+
};
|
|
2454
|
+
if (error)
|
|
2455
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ErrorDisplay_default, { error });
|
|
2456
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
|
|
2457
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink14.Text, { children: "You are not currently logged in." }),
|
|
2458
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink14.Text, { children: "Log in below:" }),
|
|
2459
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink14.Box, { marginBottom: 1 }),
|
|
2460
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_final_form.Form, { onSubmit: onSubmitLogin, children: ({ handleSubmit, validating }) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink14.Box, { flexDirection: "column", children: loginFields.map(
|
|
2461
|
+
({ name, label, placeholder, validate, Input, mask }, index) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_final_form.Field, { name, validate, children: ({ input, meta }) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink14.Box, { flexDirection: "column", children: activeField >= index ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink14.Box, { children: [
|
|
2462
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_ink14.Text, { bold: activeField === index, children: [
|
|
2463
|
+
label,
|
|
2464
|
+
": "
|
|
2465
|
+
] }),
|
|
2466
|
+
activeField === index ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2467
|
+
Input,
|
|
2468
|
+
{
|
|
2469
|
+
...input,
|
|
2470
|
+
mask,
|
|
2471
|
+
placeholder,
|
|
2472
|
+
onSubmit: () => {
|
|
2473
|
+
if (meta.valid && !validating) {
|
|
2474
|
+
setActiveField((value) => value + 1);
|
|
2475
|
+
if (activeField === loginFields.length - 1) {
|
|
2476
|
+
handleSubmit();
|
|
2477
|
+
}
|
|
2478
|
+
} else {
|
|
2479
|
+
input.onBlur();
|
|
2480
|
+
}
|
|
2481
|
+
}
|
|
2482
|
+
}
|
|
2483
|
+
) : input.value && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink14.Text, { children: name === "accessToken" ? input.value.replace(/./gi, "*") : input.value }) || placeholder && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink14.Text, { color: "gray", children: placeholder }),
|
|
2484
|
+
meta.invalid && meta.touched && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink14.Box, { marginLeft: 2, marginRight: 1, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink14.Text, { color: "red", children: "\u2716" }) }),
|
|
2485
|
+
meta.error && meta.touched && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Error2, { errorMessage: meta.error })
|
|
2486
|
+
] }) : null }) }, name)
|
|
2487
|
+
) }) }),
|
|
2488
|
+
isSubmittingForm && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink14.Box, { marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink14.Text, { children: "Logging in..." }) }),
|
|
2489
|
+
failureMessage && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Error2, { errorMessage: failureMessage, marginTop: true })
|
|
2490
|
+
] });
|
|
2491
|
+
};
|
|
2492
|
+
var Error2 = ({ errorMessage, marginTop }) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink14.Box, { marginTop: marginTop ? 1 : 0, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ink14.Text, { color: "red", children: errorMessage }) });
|
|
2493
|
+
Error2.propTypes = {
|
|
2494
|
+
errorMessage: import_prop_types10.default.string.isRequired,
|
|
2495
|
+
marginTop: import_prop_types10.default.bool
|
|
2496
|
+
};
|
|
2497
|
+
Login.propTypes = {
|
|
2498
|
+
setIsLoggedIn: import_prop_types10.default.func.isRequired
|
|
2499
|
+
};
|
|
2500
|
+
var Login_default = Login;
|
|
2501
|
+
|
|
2502
|
+
// src/components/LoadingText.tsx
|
|
2503
|
+
var import_ink15 = require("ink");
|
|
2504
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
2505
|
+
var LoadingText = () => {
|
|
2506
|
+
const { stdout } = (0, import_ink15.useStdout)();
|
|
2507
|
+
const stdOutRedirected = !stdout.isTTY;
|
|
2508
|
+
if (stdOutRedirected) {
|
|
2509
|
+
return null;
|
|
2510
|
+
}
|
|
2511
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_ink15.Text, { children: "Loading..." });
|
|
2512
|
+
};
|
|
2513
|
+
var LoadingText_default = LoadingText;
|
|
2514
|
+
|
|
2515
|
+
// src/components/LoginHOC.tsx
|
|
2516
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
2517
|
+
var LoginHOC = ({ children, isInteractive = true }) => {
|
|
2518
|
+
const [isLoggedIn, setIsLoggedIn] = (0, import_react10.useState)(false);
|
|
2519
|
+
const [isEffectDone, setEffectDone] = (0, import_react10.useState)(false);
|
|
2520
|
+
const [error, setError] = (0, import_react10.useState)(null);
|
|
2521
|
+
const { isRawModeSupported } = (0, import_ink16.useStdin)();
|
|
2522
|
+
const { stdout } = (0, import_ink16.useStdout)();
|
|
2523
|
+
const stdOutRedirected = !stdout.isTTY;
|
|
2524
|
+
const onFailure = (message2, err = {}) => {
|
|
2525
|
+
setError({
|
|
2526
|
+
...err,
|
|
2527
|
+
message: message2
|
|
2528
|
+
});
|
|
2529
|
+
};
|
|
2530
|
+
(0, import_react10.useEffect)(() => {
|
|
2531
|
+
async function isAccessTokenValid() {
|
|
2532
|
+
const { accessToken, email, jwtToken } = getAuthConfig();
|
|
2533
|
+
let userCreds = null;
|
|
2534
|
+
const { TODESKTOP_ACCESS_TOKEN, TODESKTOP_EMAIL } = getEnvironmentVariables_default();
|
|
2535
|
+
try {
|
|
2536
|
+
if (TODESKTOP_ACCESS_TOKEN && TODESKTOP_EMAIL) {
|
|
2537
|
+
const newJwtToken = await postToFirebaseFunction_default(
|
|
2538
|
+
"loginWithAccessToken",
|
|
2539
|
+
{
|
|
2540
|
+
email: TODESKTOP_EMAIL,
|
|
2541
|
+
accessToken: TODESKTOP_ACCESS_TOKEN
|
|
2542
|
+
}
|
|
2543
|
+
);
|
|
2544
|
+
if (newJwtToken) {
|
|
2545
|
+
userCreds = await signInWithCustomToken(newJwtToken);
|
|
2546
|
+
if (userCreds.user)
|
|
2547
|
+
setIsLoggedIn(true);
|
|
2548
|
+
}
|
|
2549
|
+
} else if (!isRawModeSupported || import_is_ci4.default) {
|
|
2550
|
+
onFailure(
|
|
2551
|
+
"ToDesktop environment variables not found. When automating builds with your CI provider, you need to specify environment variables for TODESKTOP_EMAIL and TODESKTOP_ACCESS_TOKEN."
|
|
2552
|
+
);
|
|
2553
|
+
}
|
|
2554
|
+
} catch (err) {
|
|
2555
|
+
onFailure("Log in with environment variables failed.", err);
|
|
2556
|
+
}
|
|
2557
|
+
try {
|
|
2558
|
+
if (!userCreds && jwtToken) {
|
|
2559
|
+
userCreds = await signInWithCustomToken(jwtToken);
|
|
2560
|
+
if (userCreds.user)
|
|
2561
|
+
setIsLoggedIn(true);
|
|
2562
|
+
}
|
|
2563
|
+
} catch (err) {
|
|
2564
|
+
}
|
|
2565
|
+
try {
|
|
2566
|
+
if (!userCreds && accessToken && email) {
|
|
2567
|
+
const newJwtToken = await postToFirebaseFunction_default(
|
|
2568
|
+
"loginWithAccessToken",
|
|
2569
|
+
{ email, accessToken }
|
|
2570
|
+
);
|
|
2571
|
+
if (newJwtToken) {
|
|
2572
|
+
userCreds = await signInWithCustomToken(newJwtToken);
|
|
2573
|
+
setAuthConfig(email, accessToken, newJwtToken);
|
|
2574
|
+
if (userCreds.user)
|
|
2575
|
+
setIsLoggedIn(true);
|
|
2576
|
+
}
|
|
2577
|
+
}
|
|
2578
|
+
} catch (err) {
|
|
2579
|
+
}
|
|
2580
|
+
setEffectDone(true);
|
|
2581
|
+
}
|
|
2582
|
+
isAccessTokenValid();
|
|
2583
|
+
}, []);
|
|
2584
|
+
if (error && isInteractive) {
|
|
2585
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ErrorDisplay_default, { error });
|
|
2586
|
+
}
|
|
2587
|
+
if (!isEffectDone) {
|
|
2588
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(LoadingText_default, {});
|
|
2589
|
+
}
|
|
2590
|
+
if (!isLoggedIn && isInteractive) {
|
|
2591
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Login_default, { setIsLoggedIn });
|
|
2592
|
+
}
|
|
2593
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_jsx_runtime17.Fragment, { children });
|
|
2594
|
+
};
|
|
2595
|
+
LoginHOC.propTypes = {
|
|
2596
|
+
children: import_prop_types11.default.object,
|
|
2597
|
+
isInteractive: import_prop_types11.default.bool
|
|
2598
|
+
};
|
|
2599
|
+
var LoginHOC_default = LoginHOC;
|
|
2600
|
+
|
|
2601
|
+
// src/components/ErrorBoundary.tsx
|
|
2602
|
+
var import_react11 = __toESM(require("react"));
|
|
2603
|
+
var Sentry2 = __toESM(require("@sentry/node"));
|
|
2604
|
+
var ErrorBoundary = class extends import_react11.default.Component {
|
|
2605
|
+
constructor(props) {
|
|
2606
|
+
super(props);
|
|
2607
|
+
this.state = { eventId: null, error: null };
|
|
2608
|
+
}
|
|
2609
|
+
static getDerivedStateFromError(error) {
|
|
2610
|
+
return { error };
|
|
2611
|
+
}
|
|
2612
|
+
componentDidCatch(error, errorInfo) {
|
|
2613
|
+
Sentry2.withScope((scope) => {
|
|
2614
|
+
scope.setExtras(errorInfo);
|
|
2615
|
+
const eventId = Sentry2.captureException(error);
|
|
2616
|
+
this.setState({ eventId });
|
|
2617
|
+
});
|
|
2618
|
+
}
|
|
2619
|
+
render() {
|
|
2620
|
+
if (this.state.error) {
|
|
2621
|
+
throw this.state.error;
|
|
2622
|
+
}
|
|
2623
|
+
return this.props.children;
|
|
2624
|
+
}
|
|
2625
|
+
};
|
|
2626
|
+
var ErrorBoundary_default = ErrorBoundary;
|
|
2627
|
+
|
|
2628
|
+
// src/components/OngoingBuildGuard.tsx
|
|
2629
|
+
var import_ink20 = require("ink");
|
|
2630
|
+
var import_ink_select_input = __toESM(require("ink-select-input"));
|
|
2631
|
+
var import_prop_types15 = __toESM(require("prop-types"));
|
|
2632
|
+
var import_react13 = require("react");
|
|
2633
|
+
|
|
2634
|
+
// src/components/CustomSelectInputIndicator.tsx
|
|
2635
|
+
var import_ink17 = require("ink");
|
|
2636
|
+
var import_prop_types12 = __toESM(require("prop-types"));
|
|
2637
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
2638
|
+
var CustomSelectInputIndicator = ({ isSelected, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_ink17.Box, { marginRight: 1, ...props, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_ink17.Text, { children: isSelected ? process.platform === "win32" ? ">" : "\u276F" : " " }) });
|
|
2639
|
+
CustomSelectInputIndicator.propTypes = {
|
|
2640
|
+
isSelected: import_prop_types12.default.bool.isRequired
|
|
2641
|
+
};
|
|
2642
|
+
var CustomSelectInputIndicator_default = CustomSelectInputIndicator;
|
|
2643
|
+
|
|
2644
|
+
// src/components/CustomSelectInputItem.tsx
|
|
2645
|
+
var import_ink18 = require("ink");
|
|
2646
|
+
var import_prop_types13 = __toESM(require("prop-types"));
|
|
2647
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
2648
|
+
var CustomSelectInputItem = ({ isSelected, label, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_ink18.Text, { bold: isSelected, color: isSelected ? void 0 : "gray", ...props, children: label });
|
|
2649
|
+
CustomSelectInputItem.propTypes = {
|
|
2650
|
+
isSelected: import_prop_types13.default.bool.isRequired,
|
|
2651
|
+
label: import_prop_types13.default.string.isRequired
|
|
2652
|
+
};
|
|
2653
|
+
var CustomSelectInputItem_default = CustomSelectInputItem;
|
|
2654
|
+
|
|
2655
|
+
// src/components/ViewBuild.tsx
|
|
2656
|
+
var import_ink19 = require("ink");
|
|
2657
|
+
var import_prop_types14 = __toESM(require("prop-types"));
|
|
2658
|
+
var import_react12 = require("react");
|
|
2659
|
+
|
|
2660
|
+
// src/utilities/getLatestBuildId.ts
|
|
2661
|
+
var getLatestBuildId_default = async ({ appId, userId }) => {
|
|
2662
|
+
logger_default.debug({ appId }, "getLatestBuildId");
|
|
2663
|
+
const appRef = firestore_default.doc(`users/${userId}/applications/${appId}`);
|
|
2664
|
+
const appSnapshot = await appRef.get();
|
|
2665
|
+
if (!appSnapshot.exists) {
|
|
2666
|
+
throw new Error(`Application with ID of ${appId} doesn't exist.`);
|
|
2667
|
+
}
|
|
2668
|
+
const buildsResult = await appRef.collection("builds").orderBy("createdAt", "desc").limit(1).get();
|
|
2669
|
+
if (buildsResult.empty) {
|
|
2670
|
+
return null;
|
|
2671
|
+
} else {
|
|
2672
|
+
return buildsResult.docs[0].id;
|
|
2673
|
+
}
|
|
2674
|
+
};
|
|
2675
|
+
|
|
2676
|
+
// src/utilities/findAppUserId.ts
|
|
2677
|
+
var getCollection = (collectionRef) => {
|
|
2678
|
+
return collectionRef.get().then((resp) => {
|
|
2679
|
+
const result = [];
|
|
2680
|
+
resp.forEach((doc) => result.push(doc.data()));
|
|
2681
|
+
return result;
|
|
2682
|
+
});
|
|
2683
|
+
};
|
|
2684
|
+
var acceptedUsersCollection = (id) => firestore_default.collection(`users/${id}/acceptedUsers`);
|
|
2685
|
+
var findAppUserId = async (appId) => {
|
|
2686
|
+
const { uid, email } = currentUser();
|
|
2687
|
+
const acceptedUsers = await getCollection(acceptedUsersCollection(uid));
|
|
2688
|
+
const primaryUser = { id: uid, label: email };
|
|
2689
|
+
const users = [
|
|
2690
|
+
primaryUser,
|
|
2691
|
+
...acceptedUsers.map((user) => ({ id: user.id, label: user.email }))
|
|
2692
|
+
];
|
|
2693
|
+
for (const user of users) {
|
|
2694
|
+
try {
|
|
2695
|
+
const doc = await firestore_default.doc(`users/${user.id}/applications/${appId}`).get();
|
|
2696
|
+
if (doc.exists)
|
|
2697
|
+
return user;
|
|
2698
|
+
} catch (err) {
|
|
2699
|
+
}
|
|
2700
|
+
}
|
|
2701
|
+
return primaryUser;
|
|
2702
|
+
};
|
|
2703
|
+
var findAppUserId_default = findAppUserId;
|
|
2704
|
+
|
|
2705
|
+
// src/components/ViewBuild.tsx
|
|
2706
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
2707
|
+
var ViewBuild = ({ commandUsed, id, configPath }) => {
|
|
2708
|
+
const exit = useExit_default();
|
|
2709
|
+
const [
|
|
2710
|
+
{
|
|
2711
|
+
appId,
|
|
2712
|
+
arbitraryMessageComponent,
|
|
2713
|
+
build,
|
|
2714
|
+
error,
|
|
2715
|
+
hasBuildEverFailed,
|
|
2716
|
+
isLoading
|
|
2717
|
+
},
|
|
2718
|
+
setState
|
|
2719
|
+
] = (0, import_react12.useState)({
|
|
2720
|
+
appId: null,
|
|
2721
|
+
arbitraryMessageComponent: null,
|
|
2722
|
+
build: null,
|
|
2723
|
+
error: null,
|
|
2724
|
+
hasBuildEverFailed: false,
|
|
2725
|
+
isLoading: true
|
|
2726
|
+
});
|
|
2727
|
+
const onError = (e) => {
|
|
2728
|
+
const error2 = e.response ? e.response.data : e;
|
|
2729
|
+
logForCI_default(error2);
|
|
2730
|
+
setState((prevState) => ({
|
|
2731
|
+
...prevState,
|
|
2732
|
+
error: error2
|
|
2733
|
+
}));
|
|
2734
|
+
};
|
|
2735
|
+
(0, import_react12.useEffect)(() => {
|
|
2736
|
+
let firebaseUnsubscribe;
|
|
2737
|
+
async function viewBuild() {
|
|
2738
|
+
let config2;
|
|
2739
|
+
try {
|
|
2740
|
+
config2 = getProjectConfig(configPath).config;
|
|
2741
|
+
} catch (e) {
|
|
2742
|
+
setState((previousState) => ({ ...previousState, error: e }));
|
|
2743
|
+
return;
|
|
2744
|
+
}
|
|
2745
|
+
const { id: userId } = await findAppUserId_default(config2.id);
|
|
2746
|
+
const subscribe = (buildId) => {
|
|
2747
|
+
subscribeToBuild_default({
|
|
2748
|
+
appId: config2.id,
|
|
2749
|
+
buildId,
|
|
2750
|
+
onDataReceived: (data) => {
|
|
2751
|
+
if (!data) {
|
|
2752
|
+
onError(
|
|
2753
|
+
new Error(
|
|
2754
|
+
`No such build exists (${buildId}). Please contact us if this is an error`
|
|
2755
|
+
)
|
|
2756
|
+
);
|
|
2757
|
+
}
|
|
2758
|
+
setState((prevState) => ({
|
|
2759
|
+
...prevState,
|
|
2760
|
+
appId: config2.id,
|
|
2761
|
+
build: data,
|
|
2762
|
+
isLoading: false
|
|
2763
|
+
}));
|
|
2764
|
+
},
|
|
2765
|
+
userId
|
|
2766
|
+
}).then((firebaseUnsubscribeResult) => {
|
|
2767
|
+
firebaseUnsubscribe = firebaseUnsubscribeResult;
|
|
2768
|
+
}).catch(onError);
|
|
2769
|
+
};
|
|
2770
|
+
if (id) {
|
|
2771
|
+
subscribe(id);
|
|
2772
|
+
} else {
|
|
2773
|
+
getLatestBuildId_default({ appId: config2.id, userId }).catch(onError).then((latestBuildId) => {
|
|
2774
|
+
if (!latestBuildId) {
|
|
2775
|
+
setState((previousState) => ({
|
|
2776
|
+
...previousState,
|
|
2777
|
+
arbitraryMessageComponent: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_ink19.Text, { children: "There are no builds yet" })
|
|
2778
|
+
}));
|
|
2779
|
+
return;
|
|
2780
|
+
}
|
|
2781
|
+
return subscribe(latestBuildId);
|
|
2782
|
+
});
|
|
2783
|
+
}
|
|
2784
|
+
}
|
|
2785
|
+
viewBuild();
|
|
2786
|
+
return () => {
|
|
2787
|
+
if (firebaseUnsubscribe) {
|
|
2788
|
+
firebaseUnsubscribe();
|
|
2789
|
+
}
|
|
2790
|
+
};
|
|
2791
|
+
}, [id]);
|
|
2792
|
+
(0, import_react12.useEffect)(() => {
|
|
2793
|
+
if (hasBuildEverFailed && shouldExitOnBuildFailure_default(build)) {
|
|
2794
|
+
setTimeout(() => exit(new Error("Build has failed")), 10);
|
|
2795
|
+
}
|
|
2796
|
+
}, [build, exit, hasBuildEverFailed]);
|
|
2797
|
+
(0, import_react12.useEffect)(() => {
|
|
2798
|
+
if (arbitraryMessageComponent) {
|
|
2799
|
+
setTimeout(() => exit(new Error("Validation failed")), 10);
|
|
2800
|
+
}
|
|
2801
|
+
}, [arbitraryMessageComponent, exit]);
|
|
2802
|
+
if (error) {
|
|
2803
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ErrorDisplay_default, { commandUsed, error });
|
|
2804
|
+
}
|
|
2805
|
+
if (arbitraryMessageComponent) {
|
|
2806
|
+
return arbitraryMessageComponent;
|
|
2807
|
+
}
|
|
2808
|
+
if (isLoading) {
|
|
2809
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(LoadingText_default, {});
|
|
2810
|
+
}
|
|
2811
|
+
const onBuildFailure = () => {
|
|
2812
|
+
if (hasBuildEverFailed) {
|
|
2813
|
+
return;
|
|
2814
|
+
}
|
|
2815
|
+
setState((prevState) => ({
|
|
2816
|
+
...prevState,
|
|
2817
|
+
hasBuildEverFailed: true
|
|
2818
|
+
}));
|
|
2819
|
+
};
|
|
2820
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
2821
|
+
MainLayout_default,
|
|
2822
|
+
{
|
|
2823
|
+
appId,
|
|
2824
|
+
appName: build.appName,
|
|
2825
|
+
appVersion: build.appVersion,
|
|
2826
|
+
build,
|
|
2827
|
+
commandUsed,
|
|
2828
|
+
hasBuildEverFailed,
|
|
2829
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(BuildProgress_default, { build, onBuildFailure })
|
|
2830
|
+
}
|
|
2831
|
+
);
|
|
2832
|
+
};
|
|
2833
|
+
ViewBuild.propTypes = {
|
|
2834
|
+
id: (props, propName, componentName) => {
|
|
2835
|
+
if ([props.id, props.shouldViewLatest].filter(Boolean).length !== 1) {
|
|
2836
|
+
return new Error(
|
|
2837
|
+
`Exactly one of 'id' and 'shouldViewLatest' must be specified in '${componentName}'`
|
|
2838
|
+
);
|
|
2839
|
+
}
|
|
2840
|
+
const type = typeof props.id;
|
|
2841
|
+
if (!["string", "undefined"].includes(type)) {
|
|
2842
|
+
return new Error(
|
|
2843
|
+
`'id' is a '${type}', not a string, in '${componentName}'.`
|
|
2844
|
+
);
|
|
2845
|
+
}
|
|
2846
|
+
},
|
|
2847
|
+
commandUsed: import_prop_types14.default.string.isRequired,
|
|
2848
|
+
shouldViewLatest: (props, propName, componentName) => {
|
|
2849
|
+
if ([props.id, props.shouldViewLatest].filter(Boolean).length !== 1) {
|
|
2850
|
+
return new Error(
|
|
2851
|
+
`Exactly one of 'id' and 'shouldViewLatest' must be specified in '${componentName}'`
|
|
2852
|
+
);
|
|
2853
|
+
}
|
|
2854
|
+
const type = typeof props.shouldViewLatest;
|
|
2855
|
+
if (!["boolean", "undefined"].includes(type)) {
|
|
2856
|
+
return new Error(
|
|
2857
|
+
`'shouldViewLatest' is a '${type}', not a boolean, in '${componentName}'.`
|
|
2858
|
+
);
|
|
2859
|
+
}
|
|
2860
|
+
},
|
|
2861
|
+
configPath: import_prop_types14.default.string
|
|
2862
|
+
};
|
|
2863
|
+
var ViewBuild_default = ViewBuild;
|
|
2864
|
+
|
|
2865
|
+
// src/components/OngoingBuildGuard.tsx
|
|
2866
|
+
var import_is_ci5 = __toESM(require("is-ci"));
|
|
2867
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
2868
|
+
var OngoingBuildGuard = ({ children, commandUsed, configPath }) => {
|
|
2869
|
+
const { isRawModeSupported } = (0, import_ink20.useStdin)();
|
|
2870
|
+
const onInput = useInput_default();
|
|
2871
|
+
const exit = useExit_default();
|
|
2872
|
+
const [{ appId, builds, error, isLoading, itemChosen }, setState] = (0, import_react13.useState)({
|
|
2873
|
+
appId: null,
|
|
2874
|
+
builds: [],
|
|
2875
|
+
error: null,
|
|
2876
|
+
isLoading: true,
|
|
2877
|
+
itemChosen: null
|
|
2878
|
+
});
|
|
2879
|
+
(0, import_react13.useEffect)(() => {
|
|
2880
|
+
if (!isLoading) {
|
|
2881
|
+
return;
|
|
2882
|
+
}
|
|
2883
|
+
(async () => {
|
|
2884
|
+
try {
|
|
2885
|
+
const applicationId = getProjectConfig(configPath).config.id;
|
|
2886
|
+
const { id } = await findAppUserId_default(applicationId);
|
|
2887
|
+
const buildsResult = await firestore_default.doc(`users/${id}/applications/${applicationId}`).collection("builds").orderBy("createdAt", "desc").limit(10).get();
|
|
2888
|
+
const stateUpdates = {
|
|
2889
|
+
appId: applicationId,
|
|
2890
|
+
isLoading: false,
|
|
2891
|
+
builds: []
|
|
2892
|
+
};
|
|
2893
|
+
if (!buildsResult.empty) {
|
|
2894
|
+
const latestBuild = buildsResult.docs[0].data();
|
|
2895
|
+
const isRunning = isBuildRunning(latestBuild) && latestBuild.status !== "preparation";
|
|
2896
|
+
logger_default.debug(
|
|
2897
|
+
{ isRunning },
|
|
2898
|
+
"OngoingBuildGuard component: got latest build"
|
|
2899
|
+
);
|
|
2900
|
+
stateUpdates.builds = buildsResult.docs.map((doc) => doc.data()).filter((build) => {
|
|
2901
|
+
if (isBuildRunning(build) && build.status !== "preparation") {
|
|
2902
|
+
return true;
|
|
2903
|
+
}
|
|
2904
|
+
return false;
|
|
2905
|
+
});
|
|
2906
|
+
}
|
|
2907
|
+
setState((previousState) => ({
|
|
2908
|
+
...previousState,
|
|
2909
|
+
...stateUpdates
|
|
2910
|
+
}));
|
|
2911
|
+
} catch (e) {
|
|
2912
|
+
setState((previousState) => ({
|
|
2913
|
+
...previousState,
|
|
2914
|
+
error: e
|
|
2915
|
+
}));
|
|
2916
|
+
}
|
|
2917
|
+
})();
|
|
2918
|
+
}, [builds, itemChosen, isLoading, isRawModeSupported]);
|
|
2919
|
+
if (isRawModeSupported) {
|
|
2920
|
+
onInput(() => {
|
|
2921
|
+
});
|
|
2922
|
+
}
|
|
2923
|
+
if (error) {
|
|
2924
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ErrorDisplay_default, { commandUsed, error });
|
|
2925
|
+
}
|
|
2926
|
+
if (isLoading) {
|
|
2927
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_ink20.Text, { children: "..." });
|
|
2928
|
+
}
|
|
2929
|
+
if (itemChosen) {
|
|
2930
|
+
logger_default.debug({ itemChosen }, "OngoingBuildGuard component: item chosen");
|
|
2931
|
+
const build = builds.find(Boolean);
|
|
2932
|
+
if (itemChosen.value === "view") {
|
|
2933
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ViewBuild_default, { commandUsed, id: build.id });
|
|
2934
|
+
} else if (itemChosen.value === "cancel") {
|
|
2935
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(CancelBuild_default, { appId, commandUsed, id: build.id, children });
|
|
2936
|
+
} else if (itemChosen.value === "concurrent") {
|
|
2937
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_jsx_runtime21.Fragment, { children });
|
|
2938
|
+
} else {
|
|
2939
|
+
setTimeout(exit, 10);
|
|
2940
|
+
}
|
|
2941
|
+
}
|
|
2942
|
+
if (builds.length && import_is_ci5.default === false && isRawModeSupported) {
|
|
2943
|
+
const latestBuild = builds.find(Boolean);
|
|
2944
|
+
const multiple = builds.length > 1;
|
|
2945
|
+
const items = [
|
|
2946
|
+
{
|
|
2947
|
+
label: `View ${multiple ? "latest" : "it"}`,
|
|
2948
|
+
value: "view"
|
|
2949
|
+
}
|
|
2950
|
+
];
|
|
2951
|
+
if (builds.some((build) => isBuildCancellable(build))) {
|
|
2952
|
+
items.push({
|
|
2953
|
+
label: `Cancel ${multiple ? "latest" : "it"} and start a new build`,
|
|
2954
|
+
value: "cancel"
|
|
2955
|
+
});
|
|
2956
|
+
items.push({
|
|
2957
|
+
label: "Start a concurrent build",
|
|
2958
|
+
value: "concurrent"
|
|
2959
|
+
});
|
|
2960
|
+
}
|
|
2961
|
+
items.push({
|
|
2962
|
+
label: "Exit",
|
|
2963
|
+
value: "exit"
|
|
2964
|
+
});
|
|
2965
|
+
const handleSelect = (itemChosen2) => setState((previousState) => ({ ...previousState, itemChosen: itemChosen2 }));
|
|
2966
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
|
|
2967
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_ink20.Box, { marginBottom: 1, children: [
|
|
2968
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_ink20.Text, { bold: true, children: multiple ? "There are ongoing builds " : "There is an ongoing build " }),
|
|
2969
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_ink20.Text, { children: [
|
|
2970
|
+
"(",
|
|
2971
|
+
latestBuild.appName,
|
|
2972
|
+
latestBuild.appVersion ? ` v${latestBuild.appVersion}` : "",
|
|
2973
|
+
")"
|
|
2974
|
+
] })
|
|
2975
|
+
] }),
|
|
2976
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
2977
|
+
import_ink_select_input.default,
|
|
2978
|
+
{
|
|
2979
|
+
indicatorComponent: CustomSelectInputIndicator_default,
|
|
2980
|
+
itemComponent: CustomSelectInputItem_default,
|
|
2981
|
+
items,
|
|
2982
|
+
onSelect: handleSelect
|
|
2983
|
+
}
|
|
2984
|
+
)
|
|
2985
|
+
] });
|
|
2986
|
+
} else {
|
|
2987
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_jsx_runtime21.Fragment, { children });
|
|
2988
|
+
}
|
|
2989
|
+
};
|
|
2990
|
+
OngoingBuildGuard.propTypes = {
|
|
2991
|
+
commandUsed: import_prop_types15.default.string.isRequired,
|
|
2992
|
+
children: import_prop_types15.default.oneOfType([import_prop_types15.default.array, import_prop_types15.default.object]),
|
|
2993
|
+
configPath: import_prop_types15.default.string
|
|
2994
|
+
};
|
|
2995
|
+
var OngoingBuildGuard_default = OngoingBuildGuard;
|
|
2996
|
+
|
|
2997
|
+
// src/utilities/useAnalytics.ts
|
|
2998
|
+
var import_react14 = require("react");
|
|
2999
|
+
var useAnalyticsCommand = (command, flags = {}, properties = {}) => {
|
|
3000
|
+
const [hasAttemptedTracking, setTrackingAttempt] = (0, import_react14.useState)(false);
|
|
3001
|
+
logger_default.info({ command, flags, properties }, "useAnalyticsCommand");
|
|
3002
|
+
try {
|
|
3003
|
+
if (flags.projectPath) {
|
|
3004
|
+
properties = {
|
|
3005
|
+
...properties,
|
|
3006
|
+
...getProjectConfig()
|
|
3007
|
+
};
|
|
3008
|
+
}
|
|
3009
|
+
} catch (err) {
|
|
3010
|
+
}
|
|
3011
|
+
(0, import_react14.useEffect)(() => {
|
|
3012
|
+
const authUnsubscribe = onUserAuth(async (user) => {
|
|
3013
|
+
if (user.uid) {
|
|
3014
|
+
identify(
|
|
3015
|
+
user.uid,
|
|
3016
|
+
{
|
|
3017
|
+
email: user.email,
|
|
3018
|
+
displayName: user.displayName
|
|
3019
|
+
},
|
|
3020
|
+
() => {
|
|
3021
|
+
track(
|
|
3022
|
+
ANALYTICS_EVENT.CLI_COMMAND,
|
|
3023
|
+
{
|
|
3024
|
+
...properties,
|
|
3025
|
+
flags,
|
|
3026
|
+
command
|
|
3027
|
+
},
|
|
3028
|
+
() => setTrackingAttempt(true)
|
|
3029
|
+
);
|
|
3030
|
+
authUnsubscribe && authUnsubscribe();
|
|
3031
|
+
}
|
|
3032
|
+
);
|
|
3033
|
+
}
|
|
3034
|
+
});
|
|
3035
|
+
setTimeout(() => setTrackingAttempt(true), 5e3);
|
|
3036
|
+
}, []);
|
|
3037
|
+
return { hasAttemptedTracking };
|
|
3038
|
+
};
|
|
3039
|
+
|
|
3040
|
+
// src/commands/BuildCommand.tsx
|
|
3041
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
3042
|
+
var BuildCommand = ({
|
|
3043
|
+
shouldCodeSign = true,
|
|
3044
|
+
configPath = null
|
|
3045
|
+
}) => {
|
|
3046
|
+
checkIfReactIsUsable_default();
|
|
3047
|
+
useAnalyticsCommand("build", {
|
|
3048
|
+
codeSign: shouldCodeSign,
|
|
3049
|
+
config: configPath
|
|
3050
|
+
});
|
|
3051
|
+
const commandUsed = "todesktop build";
|
|
3052
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ErrorBoundary_default, { children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(LoginHOC_default, { children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(OngoingBuildGuard_default, { configPath, commandUsed, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
3053
|
+
Build_default,
|
|
3054
|
+
{
|
|
3055
|
+
commandUsed,
|
|
3056
|
+
shouldCodeSign,
|
|
3057
|
+
configPath
|
|
3058
|
+
}
|
|
3059
|
+
) }) }) });
|
|
3060
|
+
};
|
|
3061
|
+
var BuildCommand_default = BuildCommand;
|
|
3062
|
+
|
|
3063
|
+
// src/components/ViewBuilds.tsx
|
|
3064
|
+
var import_ink26 = require("ink");
|
|
3065
|
+
var import_prop_types21 = __toESM(require("prop-types"));
|
|
3066
|
+
var import_react16 = require("react");
|
|
3067
|
+
|
|
3068
|
+
// src/components/Table.tsx
|
|
3069
|
+
var import_ink24 = require("ink");
|
|
3070
|
+
var import_prop_types20 = __toESM(require("prop-types"));
|
|
3071
|
+
|
|
3072
|
+
// src/components/TableEnd.tsx
|
|
3073
|
+
var import_ink21 = require("ink");
|
|
3074
|
+
var import_prop_types16 = __toESM(require("prop-types"));
|
|
3075
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
3076
|
+
var TableEnd = ({ keyDetails, ...props }) => {
|
|
3077
|
+
let content = "\u2514";
|
|
3078
|
+
content += Object.values(keyDetails).map(({ width }) => "\u2500".repeat(width + 2)).join("\u2534");
|
|
3079
|
+
content += "\u2518";
|
|
3080
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_ink21.Box, { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_ink21.Text, { children: content }) });
|
|
3081
|
+
};
|
|
3082
|
+
TableEnd.propTypes = {
|
|
3083
|
+
keyDetails: import_prop_types16.default.object.isRequired
|
|
3084
|
+
};
|
|
3085
|
+
var TableEnd_default = TableEnd;
|
|
3086
|
+
|
|
3087
|
+
// src/components/TableHead.tsx
|
|
3088
|
+
var import_ink22 = require("ink");
|
|
3089
|
+
var import_prop_types17 = __toESM(require("prop-types"));
|
|
3090
|
+
var import_react15 = require("react");
|
|
3091
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
3092
|
+
var TableHead = ({ keyDetails, ...props }) => {
|
|
3093
|
+
let topLine = "\u250C";
|
|
3094
|
+
topLine += Object.values(keyDetails).map(({ width }) => "\u2500".repeat(width + 2)).join("\u252C");
|
|
3095
|
+
topLine += "\u2510";
|
|
3096
|
+
const contentLineElements = Object.values(keyDetails).map(
|
|
3097
|
+
({ key, width }, index) => {
|
|
3098
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_react15.Fragment, { children: [
|
|
3099
|
+
index > 0 ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_ink22.Text, { children: " \u2502 " }) : null,
|
|
3100
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_ink22.Box, { width, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_ink22.Text, { bold: true, children: key }) })
|
|
3101
|
+
] }, key);
|
|
3102
|
+
}
|
|
3103
|
+
);
|
|
3104
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_ink22.Box, { flexDirection: "column", ...props, children: [
|
|
3105
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_ink22.Box, { children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_ink22.Text, { children: topLine }) }),
|
|
3106
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_ink22.Box, { children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_ink22.Box, { children: [
|
|
3107
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_ink22.Text, { children: "\u2502 " }),
|
|
3108
|
+
contentLineElements,
|
|
3109
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_ink22.Text, { children: " \u2502" })
|
|
3110
|
+
] }) })
|
|
3111
|
+
] });
|
|
3112
|
+
};
|
|
3113
|
+
TableHead.propTypes = {
|
|
3114
|
+
bottomLinePrefix: import_prop_types17.default.string,
|
|
3115
|
+
keyDetails: import_prop_types17.default.object.isRequired
|
|
3116
|
+
};
|
|
3117
|
+
var TableHead_default = TableHead;
|
|
3118
|
+
|
|
3119
|
+
// src/components/TableBody.tsx
|
|
3120
|
+
var import_prop_types19 = __toESM(require("prop-types"));
|
|
3121
|
+
|
|
3122
|
+
// src/components/TableRow.tsx
|
|
3123
|
+
var import_ink23 = require("ink");
|
|
3124
|
+
var import_prop_types18 = __toESM(require("prop-types"));
|
|
3125
|
+
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
3126
|
+
var TableRow = ({
|
|
3127
|
+
data,
|
|
3128
|
+
getCellTextProps = ({ props }) => props,
|
|
3129
|
+
keyDetails,
|
|
3130
|
+
textProps = {}
|
|
3131
|
+
}) => {
|
|
3132
|
+
let topLine = "\u251C";
|
|
3133
|
+
topLine += Object.values(keyDetails).map(({ width }) => "\u2500".repeat(width + 2)).join("\u253C");
|
|
3134
|
+
topLine += "\u2524";
|
|
3135
|
+
const content = /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_jsx_runtime25.Fragment, { children: [
|
|
3136
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_ink23.Text, { children: "\u2502 " }),
|
|
3137
|
+
Object.entries(data).map(([key, value], index) => {
|
|
3138
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_ink23.Box, { children: [
|
|
3139
|
+
index > 0 ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_ink23.Text, { children: " \u2502 " }) : null,
|
|
3140
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_ink23.Box, { width: keyDetails[key].width, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
3141
|
+
import_ink23.Text,
|
|
3142
|
+
{
|
|
3143
|
+
...getCellTextProps({
|
|
3144
|
+
key,
|
|
3145
|
+
props: textProps,
|
|
3146
|
+
rowData: data,
|
|
3147
|
+
value
|
|
3148
|
+
}),
|
|
3149
|
+
children: value
|
|
3150
|
+
}
|
|
3151
|
+
) })
|
|
3152
|
+
] }, key);
|
|
3153
|
+
}),
|
|
3154
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_ink23.Text, { children: " \u2502" })
|
|
3155
|
+
] });
|
|
3156
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_jsx_runtime25.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_ink23.Box, { flexDirection: "column", children: [
|
|
3157
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_ink23.Text, { children: topLine }),
|
|
3158
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_ink23.Box, { children: content })
|
|
3159
|
+
] }) });
|
|
3160
|
+
};
|
|
3161
|
+
TableRow.propTypes = {
|
|
3162
|
+
data: import_prop_types18.default.object.isRequired,
|
|
3163
|
+
getCellTextProps: import_prop_types18.default.func,
|
|
3164
|
+
keyDetails: import_prop_types18.default.object.isRequired,
|
|
3165
|
+
textProps: import_prop_types18.default.object
|
|
3166
|
+
};
|
|
3167
|
+
var TableRow_default = TableRow;
|
|
3168
|
+
|
|
3169
|
+
// src/components/TableBody.tsx
|
|
3170
|
+
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
3171
|
+
var TableBody = ({ data, getCellTextProps, keyDetails }) => {
|
|
3172
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_jsx_runtime26.Fragment, { children: data.map((rowData, index) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
3173
|
+
TableRow_default,
|
|
3174
|
+
{
|
|
3175
|
+
data: rowData,
|
|
3176
|
+
getCellTextProps,
|
|
3177
|
+
keyDetails
|
|
3178
|
+
},
|
|
3179
|
+
index
|
|
3180
|
+
)) });
|
|
3181
|
+
};
|
|
3182
|
+
TableBody.propTypes = {
|
|
3183
|
+
data: (props, propName, componentName) => {
|
|
3184
|
+
const type = typeof props.data;
|
|
3185
|
+
if (Array.isArray("array")) {
|
|
3186
|
+
return new Error(
|
|
3187
|
+
`'data' prop must be an array ('${type}' given) in ${componentName} component`
|
|
3188
|
+
);
|
|
3189
|
+
}
|
|
3190
|
+
if (props.data.length === 0) {
|
|
3191
|
+
return new Error(
|
|
3192
|
+
`'data' prop must not be empty, in ${componentName} component`
|
|
3193
|
+
);
|
|
3194
|
+
}
|
|
3195
|
+
},
|
|
3196
|
+
getCellTextProps: import_prop_types19.default.func,
|
|
3197
|
+
keyDetails: import_prop_types19.default.object.isRequired
|
|
3198
|
+
};
|
|
3199
|
+
var TableBody_default = TableBody;
|
|
3200
|
+
|
|
3201
|
+
// src/utilities/getKeyDetails.ts
|
|
3202
|
+
var getKeyDetails_default = (data) => {
|
|
3203
|
+
const result = {};
|
|
3204
|
+
Object.keys(data[0]).forEach((key) => {
|
|
3205
|
+
result[key] = {
|
|
3206
|
+
key,
|
|
3207
|
+
width: Math.max(
|
|
3208
|
+
key.length,
|
|
3209
|
+
data.map((item) => item[key].toString().length).sort((a, b) => b - a)[0]
|
|
3210
|
+
)
|
|
3211
|
+
};
|
|
3212
|
+
});
|
|
3213
|
+
return result;
|
|
3214
|
+
};
|
|
3215
|
+
|
|
3216
|
+
// src/components/Table.tsx
|
|
3217
|
+
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
3218
|
+
var Table = ({ data, getCellTextProps }) => {
|
|
3219
|
+
const keyDetails = getKeyDetails_default(data);
|
|
3220
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_ink24.Box, { flexDirection: "column", children: [
|
|
3221
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(TableHead_default, { keyDetails }),
|
|
3222
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3223
|
+
TableBody_default,
|
|
3224
|
+
{
|
|
3225
|
+
data,
|
|
3226
|
+
getCellTextProps,
|
|
3227
|
+
keyDetails
|
|
3228
|
+
}
|
|
3229
|
+
),
|
|
3230
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(TableEnd_default, { keyDetails })
|
|
3231
|
+
] });
|
|
3232
|
+
};
|
|
3233
|
+
Table.propTypes = {
|
|
3234
|
+
data: (props, propName, componentName) => {
|
|
3235
|
+
const type = typeof props.data;
|
|
3236
|
+
if (Array.isArray("array")) {
|
|
3237
|
+
return new Error(
|
|
3238
|
+
`'data' prop must be an array ('${type}' given) in ${componentName} component`
|
|
3239
|
+
);
|
|
3240
|
+
}
|
|
3241
|
+
if (props.data.length === 0) {
|
|
3242
|
+
return new Error(
|
|
3243
|
+
`'data' prop must not be empty, in ${componentName} component`
|
|
3244
|
+
);
|
|
3245
|
+
}
|
|
3246
|
+
},
|
|
3247
|
+
getCellTextProps: import_prop_types20.default.func
|
|
3248
|
+
};
|
|
3249
|
+
var Table_default = Table;
|
|
3250
|
+
|
|
3251
|
+
// src/utilities/capitalize.ts
|
|
3252
|
+
var capitalize_default = (input) => {
|
|
3253
|
+
if (typeof input !== "string") {
|
|
3254
|
+
return "";
|
|
3255
|
+
}
|
|
3256
|
+
return input.charAt(0).toUpperCase() + input.slice(1);
|
|
3257
|
+
};
|
|
3258
|
+
|
|
3259
|
+
// src/utilities/getBuilds.ts
|
|
3260
|
+
var getBuilds_default = async ({
|
|
3261
|
+
addWhereClauses = (query) => query,
|
|
3262
|
+
userId,
|
|
3263
|
+
appId,
|
|
3264
|
+
limit = 5,
|
|
3265
|
+
startAfter = null
|
|
3266
|
+
}) => {
|
|
3267
|
+
logger_default.debug({ appId, limit, startAfter }, "getBuilds");
|
|
3268
|
+
const appRef = firestore_default.doc(`users/${userId}/applications/${appId}`);
|
|
3269
|
+
const appSnapshot = await appRef.get();
|
|
3270
|
+
if (!appSnapshot.exists) {
|
|
3271
|
+
throw new Error(`Application with ID of ${appId} doesn't exist.`);
|
|
3272
|
+
}
|
|
3273
|
+
let query = addWhereClauses(appRef.collection("builds")).orderBy(
|
|
3274
|
+
"createdAt",
|
|
3275
|
+
"desc"
|
|
3276
|
+
);
|
|
3277
|
+
if (startAfter) {
|
|
3278
|
+
query = query.startAfter(startAfter);
|
|
3279
|
+
}
|
|
3280
|
+
const buildsResult = await query.limit(limit).get();
|
|
3281
|
+
if (buildsResult.empty) {
|
|
3282
|
+
return [];
|
|
3283
|
+
}
|
|
3284
|
+
return buildsResult.docs.map((doc) => doc.data());
|
|
3285
|
+
};
|
|
3286
|
+
|
|
3287
|
+
// src/utilities/getRelativeDateFromDateString.ts
|
|
3288
|
+
var dateFns = __toESM(require("date-fns"));
|
|
3289
|
+
var getRelativeDateFromDateString_default = (input) => dateFns.formatDistance(new Date(input), new Date()) + " ago";
|
|
3290
|
+
|
|
3291
|
+
// src/components/SyntaxHighlight.tsx
|
|
3292
|
+
var import_chalk2 = __toESM(require("chalk"));
|
|
3293
|
+
var React3 = __toESM(require("react"));
|
|
3294
|
+
var import_ink25 = require("ink");
|
|
3295
|
+
var import_util2 = __toESM(require("util"));
|
|
3296
|
+
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
3297
|
+
var supportsColor = import_chalk2.default.stderr.supportsColor;
|
|
3298
|
+
var SyntaxHighlight = ({
|
|
3299
|
+
object,
|
|
3300
|
+
colors = supportsColor == null ? void 0 : supportsColor.hasBasic
|
|
3301
|
+
}) => {
|
|
3302
|
+
const { stdout } = (0, import_ink25.useStdout)();
|
|
3303
|
+
const highlightedCode = React3.useMemo(() => {
|
|
3304
|
+
return stdout.isTTY ? import_util2.default.inspect(object, { colors, depth: 6 }) : JSON.stringify(object, null, 2);
|
|
3305
|
+
}, [colors, object, stdout.isTTY]);
|
|
3306
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_ink25.Text, { wrap: "end", children: highlightedCode });
|
|
3307
|
+
};
|
|
3308
|
+
var SyntaxHighlight_default = SyntaxHighlight;
|
|
3309
|
+
|
|
3310
|
+
// src/components/ViewBuilds.tsx
|
|
3311
|
+
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
3312
|
+
var ViewBuilds = ({
|
|
3313
|
+
commandUsed,
|
|
3314
|
+
configPath,
|
|
3315
|
+
count,
|
|
3316
|
+
format,
|
|
3317
|
+
exit: shouldExitAfterViewingBuilds = false
|
|
3318
|
+
}) => {
|
|
3319
|
+
const exit = useExit_default();
|
|
3320
|
+
const [
|
|
3321
|
+
{
|
|
3322
|
+
builds,
|
|
3323
|
+
error,
|
|
3324
|
+
hasMoreToLoad,
|
|
3325
|
+
isInitialLoadComplete,
|
|
3326
|
+
isLoading,
|
|
3327
|
+
projectConfig,
|
|
3328
|
+
startAfter,
|
|
3329
|
+
user
|
|
3330
|
+
},
|
|
3331
|
+
setState
|
|
3332
|
+
] = (0, import_react16.useState)({
|
|
3333
|
+
builds: [],
|
|
3334
|
+
error: null,
|
|
3335
|
+
hasMoreToLoad: true,
|
|
3336
|
+
isInitialLoadComplete: false,
|
|
3337
|
+
isLoading: false,
|
|
3338
|
+
projectConfig: null,
|
|
3339
|
+
startAfter: null,
|
|
3340
|
+
user: null
|
|
3341
|
+
});
|
|
3342
|
+
const onInput = useInput_default();
|
|
3343
|
+
onInput((input, key) => {
|
|
3344
|
+
if (key.escape) {
|
|
3345
|
+
exit();
|
|
3346
|
+
}
|
|
3347
|
+
if (input === " " || key.downArrow || key.pageDown || key.return) {
|
|
3348
|
+
if (!isInitialLoadComplete || !hasMoreToLoad) {
|
|
3349
|
+
return;
|
|
3350
|
+
}
|
|
3351
|
+
setState((previousState) => ({
|
|
3352
|
+
...previousState,
|
|
3353
|
+
startAfter: builds[builds.length - 1].createdAt
|
|
3354
|
+
}));
|
|
3355
|
+
}
|
|
3356
|
+
});
|
|
3357
|
+
(0, import_react16.useEffect)(() => {
|
|
3358
|
+
async function viewBuilds() {
|
|
3359
|
+
if (error || isLoading || isInitialLoadComplete && (!hasMoreToLoad || !startAfter)) {
|
|
3360
|
+
return;
|
|
3361
|
+
}
|
|
3362
|
+
if (!["table", "json"].includes(format)) {
|
|
3363
|
+
setState((previousState) => ({
|
|
3364
|
+
...previousState,
|
|
3365
|
+
error: new Error(
|
|
3366
|
+
`Invalid output format "${format}". Valid formats are "table" and "json".`
|
|
3367
|
+
)
|
|
3368
|
+
}));
|
|
3369
|
+
return;
|
|
3370
|
+
}
|
|
3371
|
+
setState((previousState) => ({
|
|
3372
|
+
...previousState,
|
|
3373
|
+
isLoading: true
|
|
3374
|
+
}));
|
|
3375
|
+
let config2;
|
|
3376
|
+
try {
|
|
3377
|
+
config2 = projectConfig || getProjectConfig(configPath).config;
|
|
3378
|
+
} catch (e) {
|
|
3379
|
+
setState((previousState) => ({ ...previousState, error: e }));
|
|
3380
|
+
return;
|
|
3381
|
+
}
|
|
3382
|
+
const pageSize = count || 5;
|
|
3383
|
+
const user2 = await findAppUserId_default(config2.id);
|
|
3384
|
+
getBuilds_default({
|
|
3385
|
+
appId: config2.id,
|
|
3386
|
+
limit: pageSize + 1,
|
|
3387
|
+
startAfter,
|
|
3388
|
+
userId: user2.id
|
|
3389
|
+
}).then((buildsResult) => {
|
|
3390
|
+
setState((previousState) => {
|
|
3391
|
+
const stateUpdates = {
|
|
3392
|
+
builds: [],
|
|
3393
|
+
hasMoreToLoad: buildsResult.length > pageSize,
|
|
3394
|
+
isInitialLoadComplete: true,
|
|
3395
|
+
isLoading: false,
|
|
3396
|
+
projectConfig: config2,
|
|
3397
|
+
startAfter: null,
|
|
3398
|
+
user: user2
|
|
3399
|
+
};
|
|
3400
|
+
if (buildsResult.length) {
|
|
3401
|
+
stateUpdates.builds = [
|
|
3402
|
+
...previousState.builds,
|
|
3403
|
+
...buildsResult.slice(0, pageSize)
|
|
3404
|
+
];
|
|
3405
|
+
}
|
|
3406
|
+
return {
|
|
3407
|
+
...previousState,
|
|
3408
|
+
...stateUpdates
|
|
3409
|
+
};
|
|
3410
|
+
});
|
|
3411
|
+
}).catch((e) => {
|
|
3412
|
+
logForCI_default(e);
|
|
3413
|
+
setState((previousState) => ({
|
|
3414
|
+
...previousState,
|
|
3415
|
+
error: e,
|
|
3416
|
+
isLoading: false
|
|
3417
|
+
}));
|
|
3418
|
+
});
|
|
3419
|
+
}
|
|
3420
|
+
viewBuilds();
|
|
3421
|
+
}, [
|
|
3422
|
+
error,
|
|
3423
|
+
hasMoreToLoad,
|
|
3424
|
+
isInitialLoadComplete,
|
|
3425
|
+
isLoading,
|
|
3426
|
+
projectConfig,
|
|
3427
|
+
startAfter
|
|
3428
|
+
]);
|
|
3429
|
+
(0, import_react16.useEffect)(() => {
|
|
3430
|
+
if (!hasMoreToLoad) {
|
|
3431
|
+
setTimeout(exit, 10);
|
|
3432
|
+
}
|
|
3433
|
+
}, [exit, hasMoreToLoad]);
|
|
3434
|
+
(0, import_react16.useEffect)(() => {
|
|
3435
|
+
if (!isLoading && isInitialLoadComplete && shouldExitAfterViewingBuilds) {
|
|
3436
|
+
setTimeout(exit, 10);
|
|
3437
|
+
}
|
|
3438
|
+
}, [exit, isLoading, shouldExitAfterViewingBuilds, isInitialLoadComplete]);
|
|
3439
|
+
if (error) {
|
|
3440
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(ErrorDisplay_default, { commandUsed, error });
|
|
3441
|
+
}
|
|
3442
|
+
if (!isInitialLoadComplete) {
|
|
3443
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(LoadingText_default, {});
|
|
3444
|
+
}
|
|
3445
|
+
if (builds.length) {
|
|
3446
|
+
const formatData = (builds2) => builds2.map((build) => ({
|
|
3447
|
+
ID: build.id,
|
|
3448
|
+
Version: build.appVersion || "n/a",
|
|
3449
|
+
"Creation date": getRelativeDateFromDateString_default(build.createdAt),
|
|
3450
|
+
Status: capitalize_default(build.status),
|
|
3451
|
+
"Release date": build.releasedAt ? getRelativeDateFromDateString_default(build.releasedAt) : "Unreleased",
|
|
3452
|
+
Owner: user ? user.label : "unknown"
|
|
3453
|
+
}));
|
|
3454
|
+
const getCellTextProps = ({ key, props, value }) => {
|
|
3455
|
+
const result = { ...props };
|
|
3456
|
+
if (key === "Status") {
|
|
3457
|
+
const status = value.toLowerCase();
|
|
3458
|
+
if (status === "succeeded") {
|
|
3459
|
+
result.color = "green";
|
|
3460
|
+
} else if (status === "failed") {
|
|
3461
|
+
result.color = "red";
|
|
3462
|
+
} else if (status === "cancelled") {
|
|
3463
|
+
result.dimColor = true;
|
|
3464
|
+
}
|
|
3465
|
+
} else if (key === "Version" && value.toLowerCase() === "n/a") {
|
|
3466
|
+
result.dimColor = true;
|
|
3467
|
+
} else if (key === "Release date" && value.toLowerCase() === "unreleased") {
|
|
3468
|
+
result.dimColor = true;
|
|
3469
|
+
}
|
|
3470
|
+
return result;
|
|
3471
|
+
};
|
|
3472
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_jsx_runtime29.Fragment, { children: [
|
|
3473
|
+
format === "table" ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
3474
|
+
Table_default,
|
|
3475
|
+
{
|
|
3476
|
+
getCellTextProps,
|
|
3477
|
+
data: formatData(builds)
|
|
3478
|
+
}
|
|
3479
|
+
) : null,
|
|
3480
|
+
format === "json" ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(SyntaxHighlight_default, { object: removeAppBuilderLibConfig(builds) }) : null,
|
|
3481
|
+
!shouldExitAfterViewingBuilds && builds.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_ink26.Box, { children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_ink26.Text, { color: "gray", dimColor: true, children: isLoading ? "Loading more..." : hasMoreToLoad ? `Showing the latest ${builds.length} builds. Press space/down to load more.` : `Showing all (${builds.length}) builds` }) }) : null
|
|
3482
|
+
] });
|
|
3483
|
+
} else {
|
|
3484
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_ink26.Text, { children: "There are no builds yet" });
|
|
3485
|
+
}
|
|
3486
|
+
};
|
|
3487
|
+
var removeAppBuilderLibConfig = (builds) => {
|
|
3488
|
+
return builds.map((build) => {
|
|
3489
|
+
if (build.mac && build.mac.appBuilderLibConfig) {
|
|
3490
|
+
delete build.mac.appBuilderLibConfig;
|
|
3491
|
+
}
|
|
3492
|
+
if (build.windows && build.windows.appBuilderLibConfig) {
|
|
3493
|
+
delete build.windows.appBuilderLibConfig;
|
|
3494
|
+
}
|
|
3495
|
+
if (build.linux && build.linux.appBuilderLibConfig) {
|
|
3496
|
+
delete build.linux.appBuilderLibConfig;
|
|
3497
|
+
}
|
|
3498
|
+
return build;
|
|
3499
|
+
});
|
|
3500
|
+
};
|
|
3501
|
+
ViewBuilds.propTypes = {
|
|
3502
|
+
commandUsed: import_prop_types21.default.string.isRequired,
|
|
3503
|
+
configPath: import_prop_types21.default.string,
|
|
3504
|
+
count: import_prop_types21.default.number,
|
|
3505
|
+
format: import_prop_types21.default.string,
|
|
3506
|
+
exit: import_prop_types21.default.bool
|
|
3507
|
+
};
|
|
3508
|
+
var ViewBuilds_default = ViewBuilds;
|
|
3509
|
+
|
|
3510
|
+
// src/commands/BuildsCommand.tsx
|
|
3511
|
+
var import_jsx_runtime30 = require("react/jsx-runtime");
|
|
3512
|
+
var BuildsCommand = ({
|
|
3513
|
+
id,
|
|
3514
|
+
shouldViewLatest,
|
|
3515
|
+
configPath = null,
|
|
3516
|
+
count,
|
|
3517
|
+
format = "table",
|
|
3518
|
+
exit
|
|
3519
|
+
}) => {
|
|
3520
|
+
checkIfReactIsUsable_default();
|
|
3521
|
+
useAnalyticsCommand("builds", {
|
|
3522
|
+
id,
|
|
3523
|
+
shouldViewLatest,
|
|
3524
|
+
configPath,
|
|
3525
|
+
count,
|
|
3526
|
+
format,
|
|
3527
|
+
exit
|
|
3528
|
+
});
|
|
3529
|
+
const getContents = () => {
|
|
3530
|
+
let commandUsed = "todesktop builds";
|
|
3531
|
+
if (id) {
|
|
3532
|
+
commandUsed += " <id>";
|
|
3533
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(ViewBuild_default, { commandUsed, id, configPath });
|
|
3534
|
+
} else if (shouldViewLatest) {
|
|
3535
|
+
commandUsed += " --latest";
|
|
3536
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
3537
|
+
ViewBuild_default,
|
|
3538
|
+
{
|
|
3539
|
+
commandUsed,
|
|
3540
|
+
shouldViewLatest: true,
|
|
3541
|
+
configPath
|
|
3542
|
+
}
|
|
3543
|
+
);
|
|
3544
|
+
} else {
|
|
3545
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
3546
|
+
ViewBuilds_default,
|
|
3547
|
+
{
|
|
3548
|
+
commandUsed,
|
|
3549
|
+
configPath,
|
|
3550
|
+
count,
|
|
3551
|
+
format,
|
|
3552
|
+
exit
|
|
3553
|
+
}
|
|
3554
|
+
);
|
|
3555
|
+
}
|
|
3556
|
+
};
|
|
3557
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(ErrorBoundary_default, { children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(LoginHOC_default, { children: getContents() }) });
|
|
3558
|
+
};
|
|
3559
|
+
var BuildsCommand_default = BuildsCommand;
|
|
3560
|
+
|
|
3561
|
+
// src/commands/LogoutCommand.tsx
|
|
3562
|
+
var import_react17 = require("react");
|
|
3563
|
+
var import_ink27 = require("ink");
|
|
3564
|
+
var import_jsx_runtime31 = require("react/jsx-runtime");
|
|
3565
|
+
var Logout = () => {
|
|
3566
|
+
const exit = useExit_default();
|
|
3567
|
+
const { hasAttemptedTracking } = useAnalyticsCommand("logout");
|
|
3568
|
+
checkIfReactIsUsable_default();
|
|
3569
|
+
deleteAuthConfig();
|
|
3570
|
+
(0, import_react17.useEffect)(() => {
|
|
3571
|
+
if (hasAttemptedTracking) {
|
|
3572
|
+
exit();
|
|
3573
|
+
}
|
|
3574
|
+
}, [exit, hasAttemptedTracking]);
|
|
3575
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_ink27.Text, { children: "Log out successful" });
|
|
3576
|
+
};
|
|
3577
|
+
var LogoutWrapper = () => {
|
|
3578
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(ErrorBoundary_default, { children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(LoginHOC_default, { isInteractive: false, children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(Logout, {}) }) });
|
|
3579
|
+
};
|
|
3580
|
+
var LogoutCommand_default = LogoutWrapper;
|
|
3581
|
+
|
|
3582
|
+
// src/commands/ReleaseCommand.tsx
|
|
3583
|
+
var import_ink31 = require("ink");
|
|
3584
|
+
|
|
3585
|
+
// src/components/ReleaseBuild.tsx
|
|
3586
|
+
var import_ink28 = require("ink");
|
|
3587
|
+
var import_ink_link4 = __toESM(require("ink-link"));
|
|
3588
|
+
var import_ink_select_input2 = __toESM(require("ink-select-input"));
|
|
3589
|
+
var import_prop_types22 = __toESM(require("prop-types"));
|
|
3590
|
+
var import_react18 = require("react");
|
|
3591
|
+
|
|
3592
|
+
// src/utilities/getBuildById.ts
|
|
3593
|
+
var getBuildById_default = async ({ appId, buildId, userId }) => {
|
|
3594
|
+
logger_default.debug({ appId, buildId }, "getBuildById");
|
|
3595
|
+
const snapshot = await firestore_default.doc(`users/${userId}/applications/${appId}/builds/${buildId}`).get();
|
|
3596
|
+
if (!snapshot.exists) {
|
|
3597
|
+
return null;
|
|
3598
|
+
}
|
|
3599
|
+
return snapshot.data();
|
|
3600
|
+
};
|
|
3601
|
+
|
|
3602
|
+
// src/components/ReleaseBuild.tsx
|
|
3603
|
+
var import_jsx_runtime32 = require("react/jsx-runtime");
|
|
3604
|
+
var getValidationErrorMessageDisplay = (build, validationMessage) => {
|
|
3605
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(import_ink28.Box, { flexDirection: "column", children: [
|
|
3606
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(import_ink28.Text, { bold: true, color: "red", children: [
|
|
3607
|
+
"Can't release ",
|
|
3608
|
+
build.appName,
|
|
3609
|
+
" v",
|
|
3610
|
+
build.appVersion
|
|
3611
|
+
] }),
|
|
3612
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_ink28.Box, { marginBottom: 1, marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_ink28.Text, { children: validationMessage }) }),
|
|
3613
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_ink28.Text, { bold: true, children: "See web UI for more information: " }),
|
|
3614
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_ink28.Text, { children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_ink_link4.default, { fallback: false, url: build.url, children: build.url }) })
|
|
3615
|
+
] });
|
|
3616
|
+
};
|
|
3617
|
+
var ReleaseBuild = ({ commandUsed, id, shouldConfirm, configPath }) => {
|
|
3618
|
+
const exit = useExit_default();
|
|
3619
|
+
const [
|
|
3620
|
+
{
|
|
3621
|
+
appId,
|
|
3622
|
+
arbitraryMessageComponent,
|
|
3623
|
+
build,
|
|
3624
|
+
error,
|
|
3625
|
+
hasConfirmed,
|
|
3626
|
+
hasBeenValidatedSuccesfully,
|
|
3627
|
+
isComplete,
|
|
3628
|
+
isReleasing
|
|
3629
|
+
},
|
|
3630
|
+
setState
|
|
3631
|
+
] = (0, import_react18.useState)({
|
|
3632
|
+
appId: null,
|
|
3633
|
+
build: null,
|
|
3634
|
+
error: null,
|
|
3635
|
+
hasConfirmed: false,
|
|
3636
|
+
hasBeenValidatedSuccesfully: false,
|
|
3637
|
+
isComplete: false,
|
|
3638
|
+
isReleasing: false,
|
|
3639
|
+
arbitraryMessageComponent: null
|
|
3640
|
+
});
|
|
3641
|
+
const onError = (e) => {
|
|
3642
|
+
const error2 = e.response ? e.response.data : e;
|
|
3643
|
+
logForCI_default(error2);
|
|
3644
|
+
setState((prevState) => ({
|
|
3645
|
+
...prevState,
|
|
3646
|
+
error: error2
|
|
3647
|
+
}));
|
|
3648
|
+
};
|
|
3649
|
+
(0, import_react18.useEffect)(() => {
|
|
3650
|
+
async function releaseBuild() {
|
|
3651
|
+
if (build) {
|
|
3652
|
+
return;
|
|
3653
|
+
}
|
|
3654
|
+
const config2 = getProjectConfig(configPath).config;
|
|
3655
|
+
const appId2 = config2.id;
|
|
3656
|
+
const { id: userId } = await findAppUserId_default(appId2);
|
|
3657
|
+
const loadBuild = (buildId) => {
|
|
3658
|
+
getBuildById_default({ appId: appId2, buildId, userId }).then((buildResult) => {
|
|
3659
|
+
if (!buildResult) {
|
|
3660
|
+
throw new Error(
|
|
3661
|
+
`No such build ${buildId} for application ${appId2}`
|
|
3662
|
+
);
|
|
3663
|
+
}
|
|
3664
|
+
setState((previousState) => ({
|
|
3665
|
+
...previousState,
|
|
3666
|
+
appId: appId2,
|
|
3667
|
+
build: buildResult
|
|
3668
|
+
}));
|
|
3669
|
+
}).catch(onError);
|
|
3670
|
+
};
|
|
3671
|
+
if (id) {
|
|
3672
|
+
loadBuild(id);
|
|
3673
|
+
} else {
|
|
3674
|
+
getLatestBuildId_default({ appId: appId2, userId }).catch(onError).then((buildId) => {
|
|
3675
|
+
if (!buildId) {
|
|
3676
|
+
setState((previousState) => ({
|
|
3677
|
+
...previousState,
|
|
3678
|
+
arbitraryMessageComponent: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_ink28.Text, { children: "There are no builds yet" })
|
|
3679
|
+
}));
|
|
3680
|
+
return;
|
|
3681
|
+
}
|
|
3682
|
+
return loadBuild(buildId);
|
|
3683
|
+
});
|
|
3684
|
+
}
|
|
3685
|
+
}
|
|
3686
|
+
releaseBuild();
|
|
3687
|
+
}, [build, id]);
|
|
3688
|
+
(0, import_react18.useEffect)(() => {
|
|
3689
|
+
if (!build || hasBeenValidatedSuccesfully || arbitraryMessageComponent) {
|
|
3690
|
+
return;
|
|
3691
|
+
}
|
|
3692
|
+
let validationMessage;
|
|
3693
|
+
if (build.releasedAt) {
|
|
3694
|
+
validationMessage = `It has already been released.`;
|
|
3695
|
+
} else if (build.status !== "succeeded") {
|
|
3696
|
+
validationMessage = `The build must have completed successfully. Actual build status: ${build.status}`;
|
|
3697
|
+
}
|
|
3698
|
+
if (validationMessage) {
|
|
3699
|
+
setState((previousState) => ({
|
|
3700
|
+
...previousState,
|
|
3701
|
+
arbitraryMessageComponent: getValidationErrorMessageDisplay(
|
|
3702
|
+
build,
|
|
3703
|
+
validationMessage
|
|
3704
|
+
),
|
|
3705
|
+
hasBeenValidatedSuccesfully: false
|
|
3706
|
+
}));
|
|
3707
|
+
} else {
|
|
3708
|
+
setState((previousState) => ({
|
|
3709
|
+
...previousState,
|
|
3710
|
+
hasBeenValidatedSuccesfully: true
|
|
3711
|
+
}));
|
|
3712
|
+
}
|
|
3713
|
+
}, [arbitraryMessageComponent, build, hasBeenValidatedSuccesfully]);
|
|
3714
|
+
(0, import_react18.useEffect)(() => {
|
|
3715
|
+
if (!hasBeenValidatedSuccesfully || shouldConfirm && !hasConfirmed || isReleasing || isComplete) {
|
|
3716
|
+
return;
|
|
3717
|
+
}
|
|
3718
|
+
setState((previousState) => ({
|
|
3719
|
+
...previousState,
|
|
3720
|
+
isReleasing: true
|
|
3721
|
+
}));
|
|
3722
|
+
getCallableFirebaseFunction_default("releaseBuild")({
|
|
3723
|
+
appId,
|
|
3724
|
+
buildId: build.id
|
|
3725
|
+
}).then(() => {
|
|
3726
|
+
logForCI_default("Released!");
|
|
3727
|
+
setState((previousState) => ({
|
|
3728
|
+
...previousState,
|
|
3729
|
+
isReleasing: false,
|
|
3730
|
+
isComplete: true
|
|
3731
|
+
}));
|
|
3732
|
+
}).catch((e) => {
|
|
3733
|
+
if (["failed-precondition", "not-found"].includes(e.code)) {
|
|
3734
|
+
setState((previousState) => ({
|
|
3735
|
+
...previousState,
|
|
3736
|
+
arbitraryMessageComponent: getValidationErrorMessageDisplay(
|
|
3737
|
+
build,
|
|
3738
|
+
e.message
|
|
3739
|
+
),
|
|
3740
|
+
isReleasing: false
|
|
3741
|
+
}));
|
|
3742
|
+
} else {
|
|
3743
|
+
onError(new Error("Unexpected internal error while releasing build"));
|
|
3744
|
+
}
|
|
3745
|
+
});
|
|
3746
|
+
}, [
|
|
3747
|
+
appId,
|
|
3748
|
+
build,
|
|
3749
|
+
hasConfirmed,
|
|
3750
|
+
hasBeenValidatedSuccesfully,
|
|
3751
|
+
id,
|
|
3752
|
+
isComplete,
|
|
3753
|
+
isReleasing,
|
|
3754
|
+
shouldConfirm
|
|
3755
|
+
]);
|
|
3756
|
+
(0, import_react18.useEffect)(() => {
|
|
3757
|
+
if (isComplete) {
|
|
3758
|
+
setTimeout(exit, 10);
|
|
3759
|
+
return;
|
|
3760
|
+
}
|
|
3761
|
+
if (arbitraryMessageComponent) {
|
|
3762
|
+
setTimeout(() => exit(new Error("Validation failed")), 10);
|
|
3763
|
+
}
|
|
3764
|
+
}, [arbitraryMessageComponent, exit, isComplete]);
|
|
3765
|
+
if (error) {
|
|
3766
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(ErrorDisplay_default, { commandUsed, error });
|
|
3767
|
+
}
|
|
3768
|
+
if (arbitraryMessageComponent) {
|
|
3769
|
+
return arbitraryMessageComponent;
|
|
3770
|
+
}
|
|
3771
|
+
if (hasBeenValidatedSuccesfully && shouldConfirm && !hasConfirmed) {
|
|
3772
|
+
const items = [
|
|
3773
|
+
{
|
|
3774
|
+
label: "Yes",
|
|
3775
|
+
value: "yes"
|
|
3776
|
+
},
|
|
3777
|
+
{
|
|
3778
|
+
label: "No",
|
|
3779
|
+
value: "no"
|
|
3780
|
+
}
|
|
3781
|
+
];
|
|
3782
|
+
const onSubmit = (item) => {
|
|
3783
|
+
if (item.value === "no") {
|
|
3784
|
+
setTimeout(exit, 10);
|
|
3785
|
+
return;
|
|
3786
|
+
}
|
|
3787
|
+
setState((previousState) => ({
|
|
3788
|
+
...previousState,
|
|
3789
|
+
hasConfirmed: true
|
|
3790
|
+
}));
|
|
3791
|
+
};
|
|
3792
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(import_ink28.Box, { flexDirection: "column", children: [
|
|
3793
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(import_ink28.Box, { children: [
|
|
3794
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(import_ink28.Text, { children: [
|
|
3795
|
+
"This will release build ",
|
|
3796
|
+
build.id,
|
|
3797
|
+
" as "
|
|
3798
|
+
] }),
|
|
3799
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(import_ink28.Text, { bold: true, children: [
|
|
3800
|
+
build.appName,
|
|
3801
|
+
" v",
|
|
3802
|
+
build.appVersion
|
|
3803
|
+
] }),
|
|
3804
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_ink28.Text, { children: ", are you sure?" })
|
|
3805
|
+
] }),
|
|
3806
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_ink28.Box, { marginBottom: 1, marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
3807
|
+
import_ink_select_input2.default,
|
|
3808
|
+
{
|
|
3809
|
+
indicatorComponent: CustomSelectInputIndicator_default,
|
|
3810
|
+
initialIndex: 1,
|
|
3811
|
+
itemComponent: CustomSelectInputItem_default,
|
|
3812
|
+
items,
|
|
3813
|
+
onSelect: onSubmit
|
|
3814
|
+
}
|
|
3815
|
+
) }),
|
|
3816
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_ink28.Text, { dimColor: true, children: "Your users will be auto-updated to this version. You can use --force to bypass this confirmation in future" })
|
|
3817
|
+
] });
|
|
3818
|
+
}
|
|
3819
|
+
if (isReleasing) {
|
|
3820
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_ink28.Text, { children: "Releasing..." });
|
|
3821
|
+
}
|
|
3822
|
+
if (isComplete) {
|
|
3823
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_ink28.Text, { bold: true, color: "greenBright", children: "Released!" });
|
|
3824
|
+
}
|
|
3825
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_ink28.Text, { children: "..." });
|
|
3826
|
+
};
|
|
3827
|
+
ReleaseBuild.propTypes = {
|
|
3828
|
+
id: (props, propName, componentName) => {
|
|
3829
|
+
if ([props.id, props.shouldReleaseLatest].filter(Boolean).length !== 1) {
|
|
3830
|
+
return new Error(
|
|
3831
|
+
`Exactly one of 'id' and 'shouldReleaseLatest' must be specified in '${componentName}'`
|
|
3832
|
+
);
|
|
3833
|
+
}
|
|
3834
|
+
const type = typeof props.id;
|
|
3835
|
+
if (!["string", "undefined"].includes(type)) {
|
|
3836
|
+
return new Error(
|
|
3837
|
+
`'id' is a '${type}', not a string, in '${componentName}'.`
|
|
3838
|
+
);
|
|
3839
|
+
}
|
|
3840
|
+
},
|
|
3841
|
+
commandUsed: import_prop_types22.default.string.isRequired,
|
|
3842
|
+
shouldReleaseLatest: (props, propName, componentName) => {
|
|
3843
|
+
if ([props.id, props.shouldReleaseLatest].filter(Boolean).length !== 1) {
|
|
3844
|
+
return new Error(
|
|
3845
|
+
`Exactly one of 'id' and 'shouldReleaseLatest' must be specified in '${componentName}'`
|
|
3846
|
+
);
|
|
3847
|
+
}
|
|
3848
|
+
const type = typeof props.shouldReleaseLatest;
|
|
3849
|
+
if (!["boolean", "undefined"].includes(type)) {
|
|
3850
|
+
return new Error(
|
|
3851
|
+
`'shouldReleaseLatest' is a '${type}', not a boolean, in '${componentName}'.`
|
|
3852
|
+
);
|
|
3853
|
+
}
|
|
3854
|
+
},
|
|
3855
|
+
shouldConfirm: import_prop_types22.default.bool.isRequired,
|
|
3856
|
+
configPath: import_prop_types22.default.string
|
|
3857
|
+
};
|
|
3858
|
+
var ReleaseBuild_default = ReleaseBuild;
|
|
3859
|
+
|
|
3860
|
+
// src/components/PickBuildForRelease.tsx
|
|
3861
|
+
var import_ink30 = require("ink");
|
|
3862
|
+
var import_prop_types24 = __toESM(require("prop-types"));
|
|
3863
|
+
var import_react19 = require("react");
|
|
3864
|
+
|
|
3865
|
+
// src/components/SelectTable.tsx
|
|
3866
|
+
var import_ink29 = require("ink");
|
|
3867
|
+
var import_ink_select_input3 = __toESM(require("ink-select-input"));
|
|
3868
|
+
var import_prop_types23 = __toESM(require("prop-types"));
|
|
3869
|
+
var import_jsx_runtime33 = require("react/jsx-runtime");
|
|
3870
|
+
var CustomIndicator = (props) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(CustomSelectInputIndicator_default, { marginTop: 1, ...props });
|
|
3871
|
+
var SelectTable = ({ data, onSelect }) => {
|
|
3872
|
+
const keyDetails = getKeyDetails_default(data);
|
|
3873
|
+
const getSelectItems = () => {
|
|
3874
|
+
return data.map((rowData, index) => {
|
|
3875
|
+
return {
|
|
3876
|
+
index,
|
|
3877
|
+
key: index,
|
|
3878
|
+
value: rowData
|
|
3879
|
+
};
|
|
3880
|
+
});
|
|
3881
|
+
};
|
|
3882
|
+
const ItemComponent = ({
|
|
3883
|
+
label,
|
|
3884
|
+
index,
|
|
3885
|
+
isSelected
|
|
3886
|
+
}) => {
|
|
3887
|
+
return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
3888
|
+
TableRow_default,
|
|
3889
|
+
{
|
|
3890
|
+
data: data[index],
|
|
3891
|
+
keyDetails,
|
|
3892
|
+
textProps: { bold: isSelected, color: isSelected ? void 0 : "gray" }
|
|
3893
|
+
},
|
|
3894
|
+
index
|
|
3895
|
+
);
|
|
3896
|
+
};
|
|
3897
|
+
return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_ink29.Box, { flexDirection: "column", children: [
|
|
3898
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(TableHead_default, { keyDetails, marginLeft: 2 }),
|
|
3899
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
3900
|
+
import_ink_select_input3.default,
|
|
3901
|
+
{
|
|
3902
|
+
indicatorComponent: CustomIndicator,
|
|
3903
|
+
itemComponent: ItemComponent,
|
|
3904
|
+
items: getSelectItems(),
|
|
3905
|
+
onSelect
|
|
3906
|
+
}
|
|
3907
|
+
),
|
|
3908
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(TableEnd_default, { keyDetails, marginLeft: 2 })
|
|
3909
|
+
] });
|
|
3910
|
+
};
|
|
3911
|
+
SelectTable.propTypes = {
|
|
3912
|
+
data: (props, propName, componentName) => {
|
|
3913
|
+
const type = typeof props.data;
|
|
3914
|
+
if (Array.isArray("array")) {
|
|
3915
|
+
return new Error(
|
|
3916
|
+
`'data' prop must be an array ('${type}' given) in ${componentName} component`
|
|
3917
|
+
);
|
|
3918
|
+
}
|
|
3919
|
+
if (props.data.length === 0) {
|
|
3920
|
+
return new Error(
|
|
3921
|
+
`'data' prop must not be empty, in ${componentName} component`
|
|
3922
|
+
);
|
|
3923
|
+
}
|
|
3924
|
+
},
|
|
3925
|
+
onSelect: import_prop_types23.default.func
|
|
3926
|
+
};
|
|
3927
|
+
var SelectTable_default = SelectTable;
|
|
3928
|
+
|
|
3929
|
+
// src/components/PickBuildForRelease.tsx
|
|
3930
|
+
var import_jsx_runtime34 = require("react/jsx-runtime");
|
|
3931
|
+
var PickBuildForRelease = ({ commandUsed, shouldConfirm, configPath }) => {
|
|
3932
|
+
const exit = useExit_default();
|
|
3933
|
+
const [{ error, builds, chosenBuildId, isLoading, user }, setState] = (0, import_react19.useState)({
|
|
3934
|
+
error: null,
|
|
3935
|
+
builds: null,
|
|
3936
|
+
chosenBuildId: null,
|
|
3937
|
+
isLoading: true,
|
|
3938
|
+
user: null
|
|
3939
|
+
});
|
|
3940
|
+
const onInput = useInput_default();
|
|
3941
|
+
(0, import_react19.useEffect)(() => {
|
|
3942
|
+
async function pickBuildForRelease() {
|
|
3943
|
+
if (builds) {
|
|
3944
|
+
return;
|
|
3945
|
+
}
|
|
3946
|
+
let config2;
|
|
3947
|
+
try {
|
|
3948
|
+
config2 = getProjectConfig(configPath).config;
|
|
3949
|
+
} catch (e) {
|
|
3950
|
+
setState((previousState) => ({ ...previousState, error: e }));
|
|
3951
|
+
return;
|
|
3952
|
+
}
|
|
3953
|
+
const user2 = await findAppUserId_default(config2.id);
|
|
3954
|
+
getBuilds_default({
|
|
3955
|
+
addWhereClauses: (query) => query.where("status", "==", "succeeded"),
|
|
3956
|
+
appId: config2.id,
|
|
3957
|
+
limit: 50,
|
|
3958
|
+
userId: user2.id
|
|
3959
|
+
}).then((buildsResult) => {
|
|
3960
|
+
setState((previousState) => ({
|
|
3961
|
+
...previousState,
|
|
3962
|
+
user: user2,
|
|
3963
|
+
builds: buildsResult.filter((buildResult) => !buildResult.releasedAt).slice(0, 5),
|
|
3964
|
+
isLoading: false
|
|
3965
|
+
}));
|
|
3966
|
+
}).catch((e) => {
|
|
3967
|
+
logForCI_default(e);
|
|
3968
|
+
setState((previousState) => ({
|
|
3969
|
+
...previousState,
|
|
3970
|
+
error: e,
|
|
3971
|
+
isLoading: false
|
|
3972
|
+
}));
|
|
3973
|
+
});
|
|
3974
|
+
}
|
|
3975
|
+
pickBuildForRelease();
|
|
3976
|
+
}, [builds]);
|
|
3977
|
+
onInput((input, key) => {
|
|
3978
|
+
if (!builds || !builds.length || chosenBuildId) {
|
|
3979
|
+
return;
|
|
3980
|
+
}
|
|
3981
|
+
if (key.escape) {
|
|
3982
|
+
exit();
|
|
3983
|
+
}
|
|
3984
|
+
});
|
|
3985
|
+
if (error) {
|
|
3986
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ErrorDisplay_default, { commandUsed, error });
|
|
3987
|
+
}
|
|
3988
|
+
if (isLoading) {
|
|
3989
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(LoadingText_default, {});
|
|
3990
|
+
}
|
|
3991
|
+
if (chosenBuildId) {
|
|
3992
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
3993
|
+
ReleaseBuild_default,
|
|
3994
|
+
{
|
|
3995
|
+
commandUsed,
|
|
3996
|
+
id: chosenBuildId,
|
|
3997
|
+
shouldConfirm
|
|
3998
|
+
}
|
|
3999
|
+
);
|
|
4000
|
+
}
|
|
4001
|
+
if (builds.length) {
|
|
4002
|
+
const data = builds.map((build) => ({
|
|
4003
|
+
ID: build.id,
|
|
4004
|
+
Version: build.appVersion || "unknown",
|
|
4005
|
+
"Creation date": getRelativeDateFromDateString_default(build.createdAt),
|
|
4006
|
+
Owner: user ? user.label : "unknown"
|
|
4007
|
+
}));
|
|
4008
|
+
const onSelect = (item) => setState((previousState) => ({
|
|
4009
|
+
...previousState,
|
|
4010
|
+
chosenBuildId: item.value.ID
|
|
4011
|
+
}));
|
|
4012
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_jsx_runtime34.Fragment, { children: [
|
|
4013
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_ink30.Box, { children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_ink30.Text, { children: "Which build would you like to release?" }) }),
|
|
4014
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(SelectTable_default, { data, onSelect }),
|
|
4015
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_ink30.Box, { children: /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_ink30.Text, { dimColor: true, children: [
|
|
4016
|
+
"Showing the latest ",
|
|
4017
|
+
builds.length,
|
|
4018
|
+
" unreleased successful builds"
|
|
4019
|
+
] }) })
|
|
4020
|
+
] });
|
|
4021
|
+
} else {
|
|
4022
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_ink30.Box, { children: [
|
|
4023
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_ink30.Text, { children: "No elligible builds found " }),
|
|
4024
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_ink30.Text, { dimColor: true, children: "(i.e. unreleased and successful)" })
|
|
4025
|
+
] });
|
|
4026
|
+
}
|
|
4027
|
+
};
|
|
4028
|
+
PickBuildForRelease.propTypes = {
|
|
4029
|
+
commandUsed: import_prop_types24.default.string.isRequired,
|
|
4030
|
+
shouldConfirm: import_prop_types24.default.bool.isRequired,
|
|
4031
|
+
configPath: import_prop_types24.default.string
|
|
4032
|
+
};
|
|
4033
|
+
var PickBuildForRelease_default = PickBuildForRelease;
|
|
4034
|
+
|
|
4035
|
+
// src/commands/ReleaseCommand.tsx
|
|
4036
|
+
var import_jsx_runtime35 = require("react/jsx-runtime");
|
|
4037
|
+
var ReleaseCommand = ({
|
|
4038
|
+
id,
|
|
4039
|
+
force,
|
|
4040
|
+
shouldReleaseLatest,
|
|
4041
|
+
configPath
|
|
4042
|
+
}) => {
|
|
4043
|
+
checkIfReactIsUsable_default();
|
|
4044
|
+
useAnalyticsCommand("release", {
|
|
4045
|
+
id,
|
|
4046
|
+
force,
|
|
4047
|
+
shouldReleaseLatest,
|
|
4048
|
+
config: configPath
|
|
4049
|
+
});
|
|
4050
|
+
if (id && id.startsWith(".")) {
|
|
4051
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(import_jsx_runtime35.Fragment, { children: [
|
|
4052
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(import_ink31.Box, { children: [
|
|
4053
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_ink31.Text, { bold: true, color: "red", children: "todesktop release <project-path>" }),
|
|
4054
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_ink31.Text, { children: " is no longer supported. Run this instead:" })
|
|
4055
|
+
] }),
|
|
4056
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_ink31.Text, { bold: true, color: "greenBright", children: "todesktop build && todesktop release --latest --force" })
|
|
4057
|
+
] });
|
|
4058
|
+
}
|
|
4059
|
+
const getContents = () => {
|
|
4060
|
+
if (id) {
|
|
4061
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
|
|
4062
|
+
ReleaseBuild_default,
|
|
4063
|
+
{
|
|
4064
|
+
configPath,
|
|
4065
|
+
commandUsed: "todesktop release <id>",
|
|
4066
|
+
id,
|
|
4067
|
+
shouldConfirm: !force
|
|
4068
|
+
}
|
|
4069
|
+
);
|
|
4070
|
+
} else if (shouldReleaseLatest) {
|
|
4071
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
|
|
4072
|
+
ReleaseBuild_default,
|
|
4073
|
+
{
|
|
4074
|
+
configPath,
|
|
4075
|
+
commandUsed: "todesktop release --latest",
|
|
4076
|
+
shouldReleaseLatest: true,
|
|
4077
|
+
shouldConfirm: !force
|
|
4078
|
+
}
|
|
4079
|
+
);
|
|
4080
|
+
} else {
|
|
4081
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
|
|
4082
|
+
PickBuildForRelease_default,
|
|
4083
|
+
{
|
|
4084
|
+
configPath,
|
|
4085
|
+
commandUsed: "todesktop builds",
|
|
4086
|
+
shouldConfirm: !force
|
|
4087
|
+
}
|
|
4088
|
+
);
|
|
4089
|
+
}
|
|
4090
|
+
};
|
|
4091
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ErrorBoundary_default, { children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(LoginHOC_default, { children: getContents() }) });
|
|
4092
|
+
};
|
|
4093
|
+
var ReleaseCommand_default = ReleaseCommand;
|
|
4094
|
+
|
|
4095
|
+
// src/commands/WhoamiCommand.tsx
|
|
4096
|
+
var import_react20 = require("react");
|
|
4097
|
+
var import_ink32 = require("ink");
|
|
4098
|
+
var import_jsx_runtime36 = require("react/jsx-runtime");
|
|
4099
|
+
var WhoAmI = () => {
|
|
4100
|
+
const exit = useExit_default();
|
|
4101
|
+
checkIfReactIsUsable_default();
|
|
4102
|
+
const auth = getAuthConfig();
|
|
4103
|
+
const { hasAttemptedTracking } = useAnalyticsCommand("whoami", {}, {});
|
|
4104
|
+
(0, import_react20.useEffect)(() => {
|
|
4105
|
+
if (hasAttemptedTracking) {
|
|
4106
|
+
exit();
|
|
4107
|
+
}
|
|
4108
|
+
}, [exit, hasAttemptedTracking]);
|
|
4109
|
+
if (!auth || !auth.email) {
|
|
4110
|
+
return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_ink32.Text, { children: "You're not signed in" });
|
|
4111
|
+
}
|
|
4112
|
+
return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_ink32.Text, { children: auth.email });
|
|
4113
|
+
};
|
|
4114
|
+
var WhoAmIWrapper = () => /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ErrorBoundary_default, { children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(LoginHOC_default, { isInteractive: false, children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(WhoAmI, {}) }) });
|
|
4115
|
+
var WhoamiCommand_default = WhoAmIWrapper;
|
|
4116
|
+
|
|
4117
|
+
// src/utilities/exitIfCLIOutOfDate.ts
|
|
4118
|
+
var import_chalk3 = __toESM(require("chalk"));
|
|
4119
|
+
var import_is_installed_globally = __toESM(require("is-installed-globally"));
|
|
4120
|
+
var import_latest_version = __toESM(require("latest-version"));
|
|
4121
|
+
var import_semver = __toESM(require("semver"));
|
|
4122
|
+
var exitIfCLIOutOfDate_default = () => {
|
|
4123
|
+
if (process.env.AVA_PATH) {
|
|
4124
|
+
return;
|
|
4125
|
+
}
|
|
4126
|
+
const pkg = getToDesktopPackageJson();
|
|
4127
|
+
(0, import_latest_version.default)(pkg.name).then((latest) => {
|
|
4128
|
+
if (import_semver.default.gt(latest, pkg.version)) {
|
|
4129
|
+
const commandToUpdate = import_chalk3.default.greenBright(
|
|
4130
|
+
`npm install ${import_is_installed_globally.default ? "--location=global" : "--save-dev"} @todesktop/cli`
|
|
4131
|
+
);
|
|
4132
|
+
console.log(
|
|
4133
|
+
`Your version of @todesktop/cli is out of date.
|
|
4134
|
+
Run ${commandToUpdate} to update to v${latest}.`
|
|
4135
|
+
);
|
|
4136
|
+
if (!import_semver.default.satisfies(latest, `^${pkg.version}`)) {
|
|
4137
|
+
console.log(`CLI is exiting because it is out out of date.`);
|
|
4138
|
+
process.exit(1);
|
|
4139
|
+
}
|
|
4140
|
+
}
|
|
4141
|
+
});
|
|
4142
|
+
};
|
|
4143
|
+
|
|
4144
|
+
// src/utilities/initSentry.ts
|
|
4145
|
+
var Sentry3 = __toESM(require("@sentry/node"));
|
|
4146
|
+
var import_os2 = __toESM(require("os"));
|
|
4147
|
+
|
|
4148
|
+
// package.json
|
|
4149
|
+
var package_default = {
|
|
4150
|
+
private: false,
|
|
4151
|
+
publishConfig: {
|
|
4152
|
+
access: "public"
|
|
4153
|
+
},
|
|
4154
|
+
name: "@todesktop/cli",
|
|
4155
|
+
version: "1.6.0",
|
|
4156
|
+
license: "MIT",
|
|
4157
|
+
author: "Dave Jeffery <dave@todesktop.com> (http://www.todesktop.com/)",
|
|
4158
|
+
homepage: "https://todesktop.com/cli",
|
|
4159
|
+
bugs: {
|
|
4160
|
+
email: "dave@todesktop.com"
|
|
4161
|
+
},
|
|
4162
|
+
bin: {
|
|
4163
|
+
todesktop: "./dist/cli.js"
|
|
4164
|
+
},
|
|
4165
|
+
engines: {
|
|
4166
|
+
node: ">=12"
|
|
4167
|
+
},
|
|
4168
|
+
scripts: {
|
|
4169
|
+
dev: "cp-cli dev.env .env && npm run build:dev && npm link",
|
|
4170
|
+
"dev:prod": "cp-cli prod.env .env && npm run build && npm link",
|
|
4171
|
+
build: "esbuild src/index.ts --packages=external --bundle --sourcemap --platform=node --outfile=dist/cli.js && cp-cli prod.env .env",
|
|
4172
|
+
"build:dev": "esbuild src/index.ts --packages=external --bundle --sourcemap --platform=node --outfile=dist/cli.js && cp-cli prod.env .env",
|
|
4173
|
+
lint: "npm run lint:types && npm run lint:styles",
|
|
4174
|
+
"lint:styles": "eslint src test .eslintrc.js",
|
|
4175
|
+
"lint:types": "tsc",
|
|
4176
|
+
"lint--fix": "eslint src test --fix",
|
|
4177
|
+
release: "npm run build && npx np --tag=latest",
|
|
4178
|
+
"release-beta": "npm run build && npx np --any-branch --no-tests --tag=beta",
|
|
4179
|
+
test: "ava",
|
|
4180
|
+
"test--watch": "npm test -- --watch"
|
|
4181
|
+
},
|
|
4182
|
+
files: [
|
|
4183
|
+
"dist",
|
|
4184
|
+
"docs",
|
|
4185
|
+
".env",
|
|
4186
|
+
"LICENSE",
|
|
4187
|
+
"README.md"
|
|
4188
|
+
],
|
|
4189
|
+
dependencies: {
|
|
4190
|
+
"@sentry/node": "^5.27.2",
|
|
4191
|
+
ajv: "^8.11.2",
|
|
4192
|
+
"ajv-formats": "^2.1.1",
|
|
4193
|
+
"analytics-node": "^4.0.1",
|
|
4194
|
+
archiver: "^5.2.0",
|
|
4195
|
+
axios: "^0.21.1",
|
|
4196
|
+
"better-ajv-errors": "^1.2.0",
|
|
4197
|
+
bunyan: "^1.8.14",
|
|
4198
|
+
chalk: "^4.1.0",
|
|
4199
|
+
commander: "^9.4.1",
|
|
4200
|
+
conf: "^7.1.2",
|
|
4201
|
+
"date-fns": "^2.28.0",
|
|
4202
|
+
del: "^6.0.0",
|
|
4203
|
+
dotenv: "^8.2.0",
|
|
4204
|
+
du: "^1.0.0",
|
|
4205
|
+
"email-regex": "^4.0.0",
|
|
4206
|
+
"fast-glob": "^3.2.4",
|
|
4207
|
+
"final-form": "^4.20.1",
|
|
4208
|
+
"find-up": "^5.0.0",
|
|
4209
|
+
firebase: "^7.24.0",
|
|
4210
|
+
"git-rev-sync": "^3.0.2",
|
|
4211
|
+
ink: "^3.2.0",
|
|
4212
|
+
"ink-gradient": "^2.0.0",
|
|
4213
|
+
"ink-link": "^2.0.0",
|
|
4214
|
+
"ink-select-input": "^4.2.1",
|
|
4215
|
+
"ink-text-input": "^4.0.1",
|
|
4216
|
+
"is-ci": "^3.0.1",
|
|
4217
|
+
"is-installed-globally": "^0.3.2",
|
|
4218
|
+
"latest-version": "^5.1.0",
|
|
4219
|
+
"lodash.merge": "^4.6.2",
|
|
4220
|
+
"lodash.throttle": "^4.1.1",
|
|
4221
|
+
"parse-author": "^2.0.0",
|
|
4222
|
+
"pkg-up": "^3.1.0",
|
|
4223
|
+
"pretty-bytes": "^5.4.1",
|
|
4224
|
+
"prop-types": "^15.7.2",
|
|
4225
|
+
react: "^17.0.2",
|
|
4226
|
+
"react-final-form": "^6.5.1",
|
|
4227
|
+
semver: "^7.3.2",
|
|
4228
|
+
"source-map-support": "^0.5.21",
|
|
4229
|
+
"stream-to-array": "^2.3.0",
|
|
4230
|
+
superagent: "^7.1.3",
|
|
4231
|
+
uuid: "^8.3.1",
|
|
4232
|
+
"xdg-basedir": "^4.0.0"
|
|
4233
|
+
},
|
|
4234
|
+
devDependencies: {
|
|
4235
|
+
"@todesktop/shared": "^7.147.0",
|
|
4236
|
+
"@types/bunyan": "^1.8.6",
|
|
4237
|
+
"@types/react": "^18.0.26",
|
|
4238
|
+
"@typescript-eslint/eslint-plugin": "^5.46.1",
|
|
4239
|
+
"@typescript-eslint/parser": "^5.46.1",
|
|
4240
|
+
ava: "^4.3.1",
|
|
4241
|
+
"cp-cli": "^2.0.0",
|
|
4242
|
+
esbuild: "^0.16.5",
|
|
4243
|
+
"esbuild-register": "^3.4.1",
|
|
4244
|
+
eslint: "^8.29.0",
|
|
4245
|
+
"eslint-config-prettier": "^8.5.0",
|
|
4246
|
+
"eslint-plugin-import": "^2.26.0",
|
|
4247
|
+
"eslint-plugin-node": "^11.1.0",
|
|
4248
|
+
"eslint-plugin-prettier": "^4.2.1",
|
|
4249
|
+
"eslint-plugin-promise": "^6.1.1",
|
|
4250
|
+
"eslint-plugin-react": "^7.31.11",
|
|
4251
|
+
"eslint-plugin-react-hooks": "^4.6.0",
|
|
4252
|
+
"eslint-plugin-standard": "^4.1.0",
|
|
4253
|
+
execa: "^4.0.3",
|
|
4254
|
+
"extract-zip": "^2.0.1",
|
|
4255
|
+
"fs-extra": "^9.0.1",
|
|
4256
|
+
husky: "^4.3.0",
|
|
4257
|
+
"lint-staged": "^10.2.11",
|
|
4258
|
+
prettier: "^2.8.1",
|
|
4259
|
+
proxyquire: "^2.1.3",
|
|
4260
|
+
sinon: "^9.0.3",
|
|
4261
|
+
typescript: "^4.9.4"
|
|
4262
|
+
},
|
|
4263
|
+
ava: {
|
|
4264
|
+
extensions: [
|
|
4265
|
+
"ts"
|
|
4266
|
+
],
|
|
4267
|
+
files: [
|
|
4268
|
+
"test/**/*.ts",
|
|
4269
|
+
"!test/fixtures/**/*",
|
|
4270
|
+
"!test/utilities/**/*"
|
|
4271
|
+
],
|
|
4272
|
+
require: [
|
|
4273
|
+
"esbuild-register"
|
|
4274
|
+
],
|
|
4275
|
+
timeout: "10m"
|
|
4276
|
+
},
|
|
4277
|
+
"lint-staged": {
|
|
4278
|
+
"**/*.{js,ts,tsx}": [
|
|
4279
|
+
"eslint src --fix",
|
|
4280
|
+
"git add"
|
|
4281
|
+
]
|
|
4282
|
+
},
|
|
4283
|
+
husky: {
|
|
4284
|
+
hooks: {
|
|
4285
|
+
"pre-commit": "lint-staged"
|
|
4286
|
+
}
|
|
4287
|
+
},
|
|
4288
|
+
overrides: {
|
|
4289
|
+
pastel: {
|
|
4290
|
+
"parcel-bundler": {
|
|
4291
|
+
deasync: "0.1.27"
|
|
4292
|
+
}
|
|
4293
|
+
}
|
|
4294
|
+
},
|
|
4295
|
+
resolutions: {
|
|
4296
|
+
"pastel/parcel-bundler/deasync": "0.1.24",
|
|
4297
|
+
ink: "3.2.0",
|
|
4298
|
+
react: "17.0.2"
|
|
4299
|
+
},
|
|
4300
|
+
packageExtensions: {
|
|
4301
|
+
"ink-progress-bar@*": {
|
|
4302
|
+
dependencies: {
|
|
4303
|
+
react: "*",
|
|
4304
|
+
ink: "*"
|
|
4305
|
+
}
|
|
4306
|
+
}
|
|
4307
|
+
}
|
|
4308
|
+
};
|
|
4309
|
+
|
|
4310
|
+
// src/utilities/initSentry.ts
|
|
4311
|
+
var initSentry_default = () => {
|
|
4312
|
+
const { TODESKTOP_CLI_SENTRY_DSN } = getEnvironmentVariables_default();
|
|
4313
|
+
if (!TODESKTOP_CLI_SENTRY_DSN) {
|
|
4314
|
+
return;
|
|
4315
|
+
}
|
|
4316
|
+
Sentry3.init({
|
|
4317
|
+
dsn: TODESKTOP_CLI_SENTRY_DSN
|
|
4318
|
+
});
|
|
4319
|
+
Sentry3.configureScope((scope) => {
|
|
4320
|
+
try {
|
|
4321
|
+
scope.setUser({ email: getAuthConfig().email });
|
|
4322
|
+
} catch (err) {
|
|
4323
|
+
}
|
|
4324
|
+
try {
|
|
4325
|
+
scope.setContext("os", {
|
|
4326
|
+
name: import_os2.default.platform(),
|
|
4327
|
+
version: import_os2.default.release()
|
|
4328
|
+
});
|
|
4329
|
+
} catch (err) {
|
|
4330
|
+
}
|
|
4331
|
+
try {
|
|
4332
|
+
scope.setContext("runtime", {
|
|
4333
|
+
name: "Node.js",
|
|
4334
|
+
version: process.version
|
|
4335
|
+
});
|
|
4336
|
+
} catch (err) {
|
|
4337
|
+
}
|
|
4338
|
+
try {
|
|
4339
|
+
scope.setContext("app", {
|
|
4340
|
+
app_name: package_default.name,
|
|
4341
|
+
app_version: package_default.version
|
|
4342
|
+
});
|
|
4343
|
+
} catch (err) {
|
|
4344
|
+
}
|
|
4345
|
+
try {
|
|
4346
|
+
const configResult = getProjectConfig();
|
|
4347
|
+
scope.setExtra("config", configResult);
|
|
4348
|
+
} catch (err) {
|
|
4349
|
+
}
|
|
4350
|
+
});
|
|
4351
|
+
};
|
|
4352
|
+
|
|
4353
|
+
// src/utilities/onCommand.ts
|
|
4354
|
+
var onCommand_default = ({ sentry = true, exitIfOutOfDate = true } = {}) => {
|
|
4355
|
+
if (sentry) {
|
|
4356
|
+
initSentry_default();
|
|
4357
|
+
}
|
|
4358
|
+
if (exitIfOutOfDate) {
|
|
4359
|
+
exitIfCLIOutOfDate_default();
|
|
4360
|
+
}
|
|
4361
|
+
};
|
|
4362
|
+
|
|
4363
|
+
// src/index.ts
|
|
4364
|
+
var parseCount = (value) => {
|
|
4365
|
+
const parsedValue = Number.parseInt(value, 10);
|
|
4366
|
+
if (parsedValue > 0) {
|
|
4367
|
+
return parsedValue;
|
|
4368
|
+
}
|
|
4369
|
+
throw new import_commander.InvalidArgumentError("Should be a positive number");
|
|
4370
|
+
};
|
|
4371
|
+
import_commander.program.name("todekstop").version(getCliVersion_default());
|
|
4372
|
+
import_commander.program.command("build").description(
|
|
4373
|
+
"Build an Electron app with native installers, code signing baked-in, etc. but without releasing it (existing users won't get an auto-update). For quicker builds, you can append `--code-sign=false` to disablecode-signing and notarization."
|
|
4374
|
+
).option(
|
|
4375
|
+
"--code-sign [bool]",
|
|
4376
|
+
"Whether or not code-signing and notarization should be performed. Disable this for quicker builds"
|
|
4377
|
+
).option(
|
|
4378
|
+
"--config [string]",
|
|
4379
|
+
"Path to a different configuration file. If not specified, `todesktop.json` in the project root will be used"
|
|
4380
|
+
).action(({ codeSign, config: config2 }) => {
|
|
4381
|
+
runCommand(BuildCommand_default, {
|
|
4382
|
+
shouldCodeSign: codeSign,
|
|
4383
|
+
configPath: config2
|
|
4384
|
+
});
|
|
4385
|
+
});
|
|
4386
|
+
import_commander.program.command("builds").description("View your builds").argument("[id]", "View a specific build by ID").option("--latest", "View the latest build").option(
|
|
4387
|
+
"--config [string]",
|
|
4388
|
+
"Path to a different configuration file. If not specified, `todesktop.json` in the project root will be used"
|
|
4389
|
+
).option("--count [number]", "Number of builds to show per page", parseCount).addOption(
|
|
4390
|
+
new import_commander.Option("--format <type>", "Format to output the build details in").choices(["json", "table"]).default("table")
|
|
4391
|
+
).option("--exit", "View the latest build").action((id, { config: config2, count, exit, format, latest }) => {
|
|
4392
|
+
runCommand(BuildsCommand_default, {
|
|
4393
|
+
configPath: config2,
|
|
4394
|
+
count,
|
|
4395
|
+
exit,
|
|
4396
|
+
format,
|
|
4397
|
+
id,
|
|
4398
|
+
shouldViewLatest: latest
|
|
4399
|
+
});
|
|
4400
|
+
});
|
|
4401
|
+
import_commander.program.command("logout").description("Logs you out").action(() => {
|
|
4402
|
+
runCommand(LogoutCommand_default, null, { exitIfOutOfDate: false });
|
|
4403
|
+
});
|
|
4404
|
+
import_commander.program.command("release").description("Release a build").argument("[id]", "A specific build ID to release").option("--force", "Skips interactive confirmation step").option("--latest", "Release the latest build").option(
|
|
4405
|
+
"--config [string]",
|
|
4406
|
+
"Path to a different configuration file. If not specified, `todesktop.json` in the project root will be used"
|
|
4407
|
+
).action((id, { config: config2, force, latest }) => {
|
|
4408
|
+
runCommand(ReleaseCommand_default, {
|
|
4409
|
+
configPath: config2,
|
|
4410
|
+
force,
|
|
4411
|
+
id,
|
|
4412
|
+
shouldReleaseLatest: latest
|
|
4413
|
+
});
|
|
4414
|
+
});
|
|
4415
|
+
import_commander.program.command("whoami").description("Prints the email of the account you're signed into").action(() => {
|
|
4416
|
+
runCommand(WhoamiCommand_default);
|
|
4417
|
+
});
|
|
4418
|
+
var runCommand = (component, props = null, { exitIfOutOfDate = true } = {}) => {
|
|
4419
|
+
onCommand_default({ exitIfOutOfDate });
|
|
4420
|
+
const { waitUntilExit } = (0, import_ink33.render)((0, import_react21.createElement)(component, props));
|
|
4421
|
+
waitUntilExit().catch((error) => {
|
|
4422
|
+
console.error(error.stack);
|
|
4423
|
+
});
|
|
4424
|
+
};
|
|
4425
|
+
var args = [...process.argv];
|
|
4426
|
+
if (args.length === 2) {
|
|
4427
|
+
args.push("help");
|
|
4428
|
+
}
|
|
4429
|
+
import_commander.program.parse(args);
|
|
4430
|
+
//# sourceMappingURL=cli.js.map
|