obsidian-launcher 0.1.8 → 0.2.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.
@@ -3,7 +3,7 @@ import fsAsync4 from "fs/promises";
3
3
  import fs from "fs";
4
4
  import zlib from "zlib";
5
5
  import path4 from "path";
6
- import os from "os";
6
+ import os2 from "os";
7
7
  import crypto from "crypto";
8
8
  import fetch2 from "node-fetch";
9
9
  import extractZip from "extract-zip";
@@ -11,12 +11,12 @@ import { pipeline } from "stream/promises";
11
11
  import { downloadArtifact } from "@electron/get";
12
12
  import child_process2 from "child_process";
13
13
  import semver2 from "semver";
14
- import CDP from "chrome-remote-interface";
15
14
 
16
15
  // src/utils.ts
17
16
  import fsAsync from "fs/promises";
18
17
  import path from "path";
19
18
  import { PromisePool } from "@supercharge/promise-pool";
19
+ import _ from "lodash";
20
20
  async function fileExists(path5) {
21
21
  try {
22
22
  await fsAsync.access(path5);
@@ -71,9 +71,20 @@ async function pool(size, items, func) {
71
71
  async function maybe(promise) {
72
72
  return promise.then((r) => ({ success: true, result: r, error: void 0 })).catch((e) => ({ success: false, result: void 0, error: e }));
73
73
  }
74
+ function mergeKeepUndefined(object, ...sources) {
75
+ return _.mergeWith(
76
+ object,
77
+ ...sources,
78
+ (objValue, srcValue, key, obj) => {
79
+ if (_.isPlainObject(obj) && objValue !== srcValue && srcValue === void 0) {
80
+ obj[key] = srcValue;
81
+ }
82
+ }
83
+ );
84
+ }
74
85
 
75
86
  // src/apis.ts
76
- import _ from "lodash";
87
+ import _2 from "lodash";
77
88
  import fetch from "node-fetch";
78
89
  import fsAsync2 from "fs/promises";
79
90
  import { fileURLToPath } from "url";
@@ -100,7 +111,7 @@ function parseLinkHeader(linkHeader) {
100
111
  return Object.fromEntries(linkDatas.map((l) => [l.rel, l]));
101
112
  }
102
113
  function createURL(url, base, params = {}) {
103
- params = _.pickBy(params, (x) => x !== void 0);
114
+ params = _2.pickBy(params, (x) => x !== void 0);
104
115
  const urlObj = new URL(url, base);
105
116
  const searchParams = new URLSearchParams({ ...Object.fromEntries(urlObj.searchParams), ...params });
106
117
  if ([...searchParams].length > 0) {
@@ -234,11 +245,13 @@ var ChromeLocalStorage = class {
234
245
  // src/launcherUtils.ts
235
246
  import fsAsync3 from "fs/promises";
236
247
  import path3 from "path";
248
+ import os from "os";
237
249
  import { promisify } from "util";
238
250
  import child_process from "child_process";
239
251
  import which from "which";
240
252
  import semver from "semver";
241
- import _2 from "lodash";
253
+ import _3 from "lodash";
254
+ import CDP from "chrome-remote-interface";
242
255
  var execFile = promisify(child_process.execFile);
243
256
  function normalizeGitHubRepo(repo) {
244
257
  return repo.replace(/^(https?:\/\/)?(github.com\/)/, "");
@@ -285,9 +298,7 @@ async function extractObsidianDmg(dmg, dest) {
285
298
  function parseObsidianDesktopRelease(fileRelease, isBeta) {
286
299
  return {
287
300
  version: fileRelease.latestVersion,
288
- minInstallerVersion: fileRelease.minimumVersion,
289
- maxInstallerVersion: "",
290
- // Will be set later
301
+ minInstallerVersion: fileRelease.minimumVersion != "0.0.0" ? fileRelease.minimumVersion : void 0,
291
302
  isBeta,
292
303
  downloads: {
293
304
  asar: fileRelease.downloadUrl
@@ -308,19 +319,105 @@ function parseObsidianGithubRelease(gitHubRelease) {
308
319
  return {
309
320
  version,
310
321
  gitHubRelease: gitHubRelease.html_url,
311
- downloads: _2.pickBy(downloads, (x) => x !== void 0)
322
+ downloads: _3.pickBy(downloads, (x) => x !== void 0)
323
+ };
324
+ }
325
+ async function getElectronVersionInfo(version, binaryPath) {
326
+ console.log(`${version}: Retrieving electron & chrome versions...`);
327
+ const configDir = await fsAsync3.mkdtemp(path3.join(os.tmpdir(), `fetch-obsidian-versions-`));
328
+ const proc = child_process.spawn(binaryPath, [
329
+ `--remote-debugging-port=0`,
330
+ // 0 will make it choose a random available port
331
+ "--test-type=webdriver",
332
+ `--user-data-dir=${configDir}`,
333
+ "--no-sandbox"
334
+ // Workaround for SUID issue, see https://github.com/electron/electron/issues/42510
335
+ ]);
336
+ const procExit = new Promise((resolve) => proc.on("exit", (code) => resolve(code ?? -1)));
337
+ let dependencyVersions;
338
+ try {
339
+ const portPromise = new Promise((resolve, reject) => {
340
+ procExit.then(() => reject("Processed ended without opening a port"));
341
+ proc.stderr.on("data", (data) => {
342
+ const port2 = data.toString().match(/ws:\/\/[\w.]+?:(\d+)/)?.[1];
343
+ if (port2) {
344
+ resolve(Number(port2));
345
+ }
346
+ });
347
+ });
348
+ const port = await maybe(withTimeout(portPromise, 10 * 1e3));
349
+ if (!port.success) {
350
+ throw new Error("Timed out waiting for Chrome DevTools protocol port");
351
+ }
352
+ const client = await CDP({ port: port.result });
353
+ const response = await client.Runtime.evaluate({ expression: "JSON.stringify(process.versions)" });
354
+ dependencyVersions = JSON.parse(response.result.value);
355
+ await client.close();
356
+ } finally {
357
+ proc.kill("SIGTERM");
358
+ const timeout = await maybe(withTimeout(procExit, 4 * 1e3));
359
+ if (!timeout.success) {
360
+ console.log(`${version}: Stuck process ${proc.pid}, using SIGKILL`);
361
+ proc.kill("SIGKILL");
362
+ }
363
+ await procExit;
364
+ await sleep(1e3);
365
+ await fsAsync3.rm(configDir, { recursive: true, force: true });
366
+ }
367
+ if (!dependencyVersions?.electron || !dependencyVersions?.chrome) {
368
+ throw Error(`Failed to extract electron and chrome versions for ${version}`);
369
+ }
370
+ return {
371
+ electronVersion: dependencyVersions.electron,
372
+ chromeVersion: dependencyVersions.chrome,
373
+ nodeVersion: dependencyVersions.node
312
374
  };
313
375
  }
314
376
  function correctObsidianVersionInfo(versionInfo) {
315
- const corrections = {};
377
+ const corrections = [
378
+ // These version's downloads are missing or broken.
379
+ { version: "0.12.16", downloads: { asar: void 0 } },
380
+ { version: "1.4.7", downloads: { asar: void 0 } },
381
+ { version: "1.4.8", downloads: { asar: void 0 } },
382
+ // The minInstallerVersion here is incorrect
383
+ { version: "1.3.4", minInstallerVersion: "0.14.5" },
384
+ { version: "1.3.3", minInstallerVersion: "0.14.5" },
385
+ { version: "1.3.2", minInstallerVersion: "0.14.5" },
386
+ { version: "1.3.1", minInstallerVersion: "0.14.5" },
387
+ { version: "1.3.0", minInstallerVersion: "0.14.5" }
388
+ ];
389
+ const result = corrections.find((v) => v.version == versionInfo.version) ?? {};
316
390
  if (semver.gte(versionInfo.version, "1.5.3") && semver.lt(versionInfo.minInstallerVersion, "1.1.9")) {
317
- corrections.minInstallerVersion = "1.1.9";
391
+ result.minInstallerVersion = "1.1.9";
318
392
  }
319
- return corrections;
393
+ return result;
394
+ }
395
+ function normalizeObsidianVersionInfo(versionInfo) {
396
+ versionInfo = {
397
+ version: versionInfo.version,
398
+ minInstallerVersion: versionInfo.minInstallerVersion,
399
+ maxInstallerVersion: versionInfo.maxInstallerVersion,
400
+ isBeta: versionInfo.isBeta,
401
+ gitHubRelease: versionInfo.gitHubRelease,
402
+ downloads: {
403
+ asar: versionInfo.downloads?.asar,
404
+ appImage: versionInfo.downloads?.appImage,
405
+ appImageArm: versionInfo.downloads?.appImageArm,
406
+ apk: versionInfo.downloads?.apk,
407
+ dmg: versionInfo.downloads?.dmg,
408
+ exe: versionInfo.downloads?.exe
409
+ },
410
+ electronVersion: versionInfo.electronVersion,
411
+ chromeVersion: versionInfo.chromeVersion,
412
+ nodeVersion: versionInfo.nodeVersion
413
+ };
414
+ versionInfo.downloads = _3.omitBy(versionInfo.downloads, _3.isUndefined);
415
+ versionInfo = _3.omitBy(versionInfo, _3.isUndefined);
416
+ return versionInfo;
320
417
  }
321
418
 
322
419
  // src/launcher.ts
323
- import _3 from "lodash";
420
+ import _4 from "lodash";
324
421
  var ObsidianLauncher = class {
325
422
  /**
326
423
  * Construct an ObsidianLauncher.
@@ -403,8 +500,8 @@ var ObsidianLauncher = class {
403
500
  return await this.cachedFetch(this.communityThemesUrl, dest);
404
501
  }
405
502
  /**
406
- * Resolves Obsidian version strings to absolute obsidian versions.
407
- * @param appVersion Obsidian version string or "latest", "earliest", or "latest-beta". "earliest" will use the
503
+ * Resolves Obsidian app and installer version strings to absolute versions.
504
+ * @param appVersion Obsidian version string or "latest", "latest-beta" or "earliest". "earliest" will use the
408
505
  * minAppVersion set in your manifest.json.
409
506
  * @param installerVersion Obsidian version string or "latest" or "earliest". "earliest" will use the minimum
410
507
  * installer version compatible with the appVersion.
@@ -412,21 +509,9 @@ var ObsidianLauncher = class {
412
509
  */
413
510
  async resolveVersions(appVersion, installerVersion = "latest") {
414
511
  const versions = await this.getVersions();
415
- if (appVersion == "latest-beta") {
416
- appVersion = versions.at(-1).version;
417
- } else if (appVersion == "latest") {
418
- appVersion = versions.filter((v) => !v.isBeta).at(-1).version;
419
- } else if (appVersion == "earliest") {
420
- appVersion = (await this.getRootManifest())?.minAppVersion;
421
- if (!appVersion) {
422
- throw Error('Unable to resolve Obsidian app version "earliest", no manifest.json or minAppVersion found.');
423
- }
424
- } else {
425
- appVersion = semver2.valid(appVersion) ?? appVersion;
426
- }
427
- const appVersionInfo = versions.find((v) => v.version == appVersion);
428
- if (!appVersionInfo) {
429
- throw Error(`No Obsidian app version ${appVersion} found`);
512
+ const appVersionInfo = await this.getVersionInfo(appVersion);
513
+ if (!appVersionInfo.minInstallerVersion || !appVersionInfo.maxInstallerVersion) {
514
+ throw Error(`No compatible installers available for app version ${appVersion}`);
430
515
  }
431
516
  if (installerVersion == "latest") {
432
517
  installerVersion = appVersionInfo.maxInstallerVersion;
@@ -439,21 +524,37 @@ var ObsidianLauncher = class {
439
524
  if (!installerVersionInfo || !installerVersionInfo.chromeVersion) {
440
525
  throw Error(`No Obsidian installer for version ${installerVersion} found`);
441
526
  }
442
- if (semver2.lt(installerVersionInfo.version, appVersionInfo.minInstallerVersion)) {
527
+ if (semver2.lt(installerVersionInfo.version, appVersionInfo.minInstallerVersion) || semver2.gt(installerVersionInfo.version, appVersionInfo.maxInstallerVersion)) {
443
528
  throw Error(
444
- `Installer and app versions incompatible: minInstallerVersion of v${appVersionInfo.version} is ${appVersionInfo.minInstallerVersion}, but v${installerVersionInfo.version} specified`
529
+ `App and installer versions incompatible: app ${appVersionInfo.version} is compatible with installer >=${appVersionInfo.minInstallerVersion} <=${appVersionInfo.maxInstallerVersion} but ${installerVersionInfo.version} specified`
445
530
  );
446
531
  }
447
532
  return [appVersionInfo.version, installerVersionInfo.version];
448
533
  }
449
- /** Gets details about an Obsidian version */
534
+ /**
535
+ * Gets details about an Obsidian version.
536
+ * @param version Obsidian version string or "latest", "earliest", or "latest-beta". "earliest" will use the
537
+ * minAppVersion set in your manifest.json.
538
+ */
450
539
  async getVersionInfo(version) {
451
- version = (await this.resolveVersions(version))[0];
452
- const result = (await this.getVersions()).find((v) => v.version == version);
453
- if (!result) {
454
- throw Error(`No Obsidian version ${version} found`);
540
+ const versions = await this.getVersions();
541
+ if (version == "latest-beta") {
542
+ version = versions.at(-1).version;
543
+ } else if (version == "latest") {
544
+ version = versions.filter((v) => !v.isBeta).at(-1).version;
545
+ } else if (version == "earliest") {
546
+ version = (await this.getRootManifest())?.minAppVersion;
547
+ if (!version) {
548
+ throw Error('Unable to resolve Obsidian app version "earliest", no manifest.json or minAppVersion found.');
549
+ }
550
+ } else {
551
+ version = semver2.valid(version) ?? version;
455
552
  }
456
- return result;
553
+ const versionInfo = versions.find((v) => v.version == version);
554
+ if (!versionInfo) {
555
+ throw Error(`No Obsidian app version ${version} found`);
556
+ }
557
+ return versionInfo;
457
558
  }
458
559
  /**
459
560
  * Downloads the Obsidian installer for the given version and platform. Returns the file path.
@@ -850,7 +951,7 @@ var ObsidianLauncher = class {
850
951
  await fsAsync4.writeFile(path4.join(pluginDest, ".hotreload"), "");
851
952
  }
852
953
  }
853
- if (!_3.isEqual(enabledPlugins, originalEnabledPlugins)) {
954
+ if (!_4.isEqual(enabledPlugins, originalEnabledPlugins)) {
854
955
  await fsAsync4.writeFile(enabledPluginsPath, JSON.stringify(enabledPlugins, void 0, 2));
855
956
  }
856
957
  }
@@ -899,13 +1000,13 @@ var ObsidianLauncher = class {
899
1000
  *
900
1001
  * @param appVersion Obsidian version string.
901
1002
  * @param installerVersion Obsidian version string.
902
- * @param appPath Path to the asar file to install.
1003
+ * @param appPath Path to the asar file to install. Will download if omitted.
903
1004
  * @param vault Path to the vault to open in Obsidian.
904
1005
  * @param dest Destination path for the config dir. If omitted it will create it under `/tmp`.
905
1006
  */
906
1007
  async setupConfigDir(params) {
907
1008
  const [appVersion, installerVersion] = await this.resolveVersions(params.appVersion, params.installerVersion);
908
- const configDir = params.dest ?? await fsAsync4.mkdtemp(path4.join(os.tmpdir(), "obs-launcher-config-"));
1009
+ const configDir = params.dest ?? await fsAsync4.mkdtemp(path4.join(os2.tmpdir(), "obs-launcher-config-"));
909
1010
  let obsidianJson = {
910
1011
  updateDisabled: true
911
1012
  // Prevents Obsidian trying to auto-update on boot.
@@ -933,11 +1034,11 @@ var ObsidianLauncher = class {
933
1034
  };
934
1035
  }
935
1036
  await fsAsync4.writeFile(path4.join(configDir, "obsidian.json"), JSON.stringify(obsidianJson));
936
- if (params.appPath) {
937
- await linkOrCp(params.appPath, path4.join(configDir, path4.basename(params.appPath)));
938
- } else if (appVersion != installerVersion) {
939
- throw Error("You must specify app path if appVersion != installerVersion");
1037
+ let appPath = params.appPath;
1038
+ if (!appPath) {
1039
+ appPath = await this.downloadApp(appVersion);
940
1040
  }
1041
+ await linkOrCp(appPath, path4.join(configDir, path4.basename(appPath)));
941
1042
  const localStorage = new ChromeLocalStorage(configDir);
942
1043
  await localStorage.setItems("app://obsidian.md", localStorageData);
943
1044
  await localStorage.close();
@@ -955,7 +1056,7 @@ var ObsidianLauncher = class {
955
1056
  async setupVault(params) {
956
1057
  let vault = params.vault;
957
1058
  if (params.copy) {
958
- const dest = await fsAsync4.mkdtemp(path4.join(os.tmpdir(), "obs-launcher-vault-"));
1059
+ const dest = await fsAsync4.mkdtemp(path4.join(os2.tmpdir(), "obs-launcher-vault-"));
959
1060
  await fsAsync4.cp(vault, dest, { recursive: true });
960
1061
  vault = dest;
961
1062
  }
@@ -1001,63 +1102,6 @@ var ObsidianLauncher = class {
1001
1102
  });
1002
1103
  return { proc, configDir, vault };
1003
1104
  }
1004
- /**
1005
- * Extract electron and chrome versions for an Obsidian version.
1006
- */
1007
- async getDependencyVersions(versionInfo) {
1008
- const binary = await this.downloadInstallerFromVersionInfo(versionInfo);
1009
- console.log(`${versionInfo.version}: Extracting electron & chrome versions...`);
1010
- const configDir = await fsAsync4.mkdtemp(path4.join(os.tmpdir(), `fetch-obsidian-versions-`));
1011
- const proc = child_process2.spawn(binary, [
1012
- `--remote-debugging-port=0`,
1013
- // 0 will make it choose a random available port
1014
- "--test-type=webdriver",
1015
- `--user-data-dir=${configDir}`,
1016
- "--no-sandbox",
1017
- // Workaround for SUID issue, see https://github.com/electron/electron/issues/42510
1018
- "--headless"
1019
- ]);
1020
- const procExit = new Promise((resolve) => proc.on("exit", (code) => resolve(code ?? -1)));
1021
- let dependencyVersions;
1022
- try {
1023
- const portPromise = new Promise((resolve, reject) => {
1024
- procExit.then(() => reject("Processed ended without opening a port"));
1025
- proc.stderr.on("data", (data) => {
1026
- const port2 = data.toString().match(/ws:\/\/[\w.]+?:(\d+)/)?.[1];
1027
- if (port2) {
1028
- resolve(Number(port2));
1029
- }
1030
- });
1031
- });
1032
- const port = await maybe(withTimeout(portPromise, 10 * 1e3));
1033
- if (!port.success) {
1034
- throw new Error("Timed out waiting for Chrome DevTools protocol port");
1035
- }
1036
- const client = await CDP({ port: port.result });
1037
- const response = await client.Runtime.evaluate({ expression: "JSON.stringify(process.versions)" });
1038
- dependencyVersions = JSON.parse(response.result.value);
1039
- await client.close();
1040
- } finally {
1041
- proc.kill("SIGTERM");
1042
- const timeout = await maybe(withTimeout(procExit, 4 * 1e3));
1043
- if (!timeout.success) {
1044
- console.log(`${versionInfo.version}: Stuck process ${proc.pid}, using SIGKILL`);
1045
- proc.kill("SIGKILL");
1046
- }
1047
- await procExit;
1048
- await sleep(1e3);
1049
- await fsAsync4.rm(configDir, { recursive: true, force: true });
1050
- }
1051
- if (!dependencyVersions?.electron || !dependencyVersions?.chrome) {
1052
- throw Error(`Failed to extract electron and chrome versions for ${versionInfo.version}`);
1053
- }
1054
- return {
1055
- ...versionInfo,
1056
- electronVersion: dependencyVersions.electron,
1057
- chromeVersion: dependencyVersions.chrome,
1058
- nodeVersion: dependencyVersions.node
1059
- };
1060
- }
1061
1105
  /**
1062
1106
  * Updates the info obsidian-versions.json. The obsidian-versions.json file is used in other launcher commands
1063
1107
  * and in wdio-obsidian-service to get metadata about Obsidian versions in one place such as minInstallerVersion and
@@ -1071,7 +1115,7 @@ var ObsidianLauncher = class {
1071
1115
  });
1072
1116
  commitHistory.reverse();
1073
1117
  if (original) {
1074
- commitHistory = _3.takeRightWhile(commitHistory, (c) => c.sha != original.metadata.commit_sha);
1118
+ commitHistory = _4.takeRightWhile(commitHistory, (c) => c.sha != original.metadata.commit_sha);
1075
1119
  }
1076
1120
  const fileHistory = await pool(
1077
1121
  8,
@@ -1079,19 +1123,19 @@ var ObsidianLauncher = class {
1079
1123
  (commit) => fetch2(`https://raw.githubusercontent.com/${repo}/${commit.sha}/desktop-releases.json`).then((r) => r.json())
1080
1124
  );
1081
1125
  const githubReleases = await fetchGitHubAPIPaginated(`repos/${repo}/releases`);
1082
- const versionMap = _3.keyBy(
1126
+ const versionMap = _4.keyBy(
1083
1127
  original?.versions ?? [],
1084
1128
  (v) => v.version
1085
1129
  );
1086
1130
  for (const { beta, ...current } of fileHistory) {
1087
1131
  if (beta && (!versionMap[beta.latestVersion] || versionMap[beta.latestVersion].isBeta)) {
1088
- versionMap[beta.latestVersion] = _3.merge(
1132
+ versionMap[beta.latestVersion] = _4.merge(
1089
1133
  {},
1090
1134
  versionMap[beta.latestVersion],
1091
1135
  parseObsidianDesktopRelease(beta, true)
1092
1136
  );
1093
1137
  }
1094
- versionMap[current.latestVersion] = _3.merge(
1138
+ versionMap[current.latestVersion] = _4.merge(
1095
1139
  {},
1096
1140
  versionMap[current.latestVersion],
1097
1141
  parseObsidianDesktopRelease(current, false)
@@ -1099,31 +1143,40 @@ var ObsidianLauncher = class {
1099
1143
  }
1100
1144
  for (const release of githubReleases) {
1101
1145
  if (versionMap.hasOwnProperty(release.name)) {
1102
- versionMap[release.name] = _3.merge({}, versionMap[release.name], parseObsidianGithubRelease(release));
1146
+ versionMap[release.name] = _4.merge({}, versionMap[release.name], parseObsidianGithubRelease(release));
1103
1147
  }
1104
1148
  }
1105
1149
  const dependencyVersions = await pool(
1106
1150
  maxInstances,
1107
1151
  Object.values(versionMap).filter((v) => v.downloads?.appImage && !v.chromeVersion),
1108
- (v) => this.getDependencyVersions(v)
1152
+ async (v) => {
1153
+ const binaryPath = await this.downloadInstallerFromVersionInfo(v);
1154
+ const electronVersionInfo = await getElectronVersionInfo(v.version, binaryPath);
1155
+ return { ...v, ...electronVersionInfo };
1156
+ }
1109
1157
  );
1110
1158
  for (const deps of dependencyVersions) {
1111
- versionMap[deps.version] = _3.merge({}, versionMap[deps.version], deps);
1159
+ versionMap[deps.version] = _4.merge({}, versionMap[deps.version], deps);
1112
1160
  }
1113
- let maxInstallerVersion = "0.0.0";
1161
+ let minInstallerVersion = void 0;
1162
+ let maxInstallerVersion = void 0;
1114
1163
  for (const version of Object.keys(versionMap).sort(semver2.compare)) {
1164
+ if (!minInstallerVersion && versionMap[version].chromeVersion) {
1165
+ minInstallerVersion = version;
1166
+ }
1115
1167
  if (versionMap[version].downloads.appImage) {
1116
1168
  maxInstallerVersion = version;
1117
1169
  }
1118
- versionMap[version] = _3.merge(
1170
+ versionMap[version] = mergeKeepUndefined(
1119
1171
  {},
1120
1172
  versionMap[version],
1121
- correctObsidianVersionInfo(versionMap[version]),
1122
- { maxInstallerVersion }
1173
+ {
1174
+ minInstallerVersion: versionMap[version].minInstallerVersion ?? minInstallerVersion,
1175
+ maxInstallerVersion
1176
+ },
1177
+ correctObsidianVersionInfo(versionMap[version])
1123
1178
  );
1124
1179
  }
1125
- const versionInfos = Object.values(versionMap);
1126
- versionInfos.sort((a, b) => semver2.compare(a.version, b.version));
1127
1180
  const result = {
1128
1181
  metadata: {
1129
1182
  commit_date: commitHistory.at(-1)?.commit.committer.date ?? original?.metadata.commit_date,
@@ -1131,11 +1184,11 @@ var ObsidianLauncher = class {
1131
1184
  timestamp: original?.metadata.timestamp ?? ""
1132
1185
  // set down below
1133
1186
  },
1134
- versions: versionInfos
1187
+ versions: Object.values(versionMap).map(normalizeObsidianVersionInfo).sort((a, b) => semver2.compare(a.version, b.version))
1135
1188
  };
1136
1189
  const dayMs = 24 * 60 * 60 * 1e3;
1137
1190
  const timeSinceLastUpdate = (/* @__PURE__ */ new Date()).getTime() - new Date(original?.metadata.timestamp ?? 0).getTime();
1138
- if (!_3.isEqual(original, result) || timeSinceLastUpdate > 29 * dayMs) {
1191
+ if (!_4.isEqual(original, result) || timeSinceLastUpdate > 29 * dayMs) {
1139
1192
  result.metadata.timestamp = (/* @__PURE__ */ new Date()).toISOString();
1140
1193
  }
1141
1194
  return result;
@@ -1144,7 +1197,7 @@ var ObsidianLauncher = class {
1144
1197
  * Returns true if the Obsidian version is already in the cache.
1145
1198
  */
1146
1199
  async isInCache(type, version) {
1147
- version = (await this.resolveVersions(version))[0];
1200
+ version = (await this.getVersionInfo(version)).version;
1148
1201
  let dest;
1149
1202
  if (type == "app") {
1150
1203
  dest = `obsidian-app/obsidian-${version}.asar`;
@@ -1160,12 +1213,13 @@ var ObsidianLauncher = class {
1160
1213
  */
1161
1214
  async isAvailable(version) {
1162
1215
  const versionInfo = await this.getVersionInfo(version);
1216
+ const versionExists = !!(versionInfo.downloads.asar && versionInfo.minInstallerVersion);
1163
1217
  if (versionInfo.isBeta) {
1164
1218
  const hasCreds = !!(process.env["OBSIDIAN_USERNAME"] && process.env["OBSIDIAN_PASSWORD"]);
1165
1219
  const inCache = await this.isInCache("app", versionInfo.version);
1166
- return hasCreds || inCache;
1220
+ return versionExists && (hasCreds || inCache);
1167
1221
  } else {
1168
- return !!versionInfo.downloads.asar;
1222
+ return versionExists;
1169
1223
  }
1170
1224
  }
1171
1225
  };
@@ -1173,4 +1227,4 @@ var ObsidianLauncher = class {
1173
1227
  export {
1174
1228
  ObsidianLauncher
1175
1229
  };
1176
- //# sourceMappingURL=chunk-CNMICOMM.js.map
1230
+ //# sourceMappingURL=chunk-GYFCGBK2.js.map