obsidian-launcher 0.2.0 → 0.2.2

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.
@@ -11,12 +11,12 @@ var _promises3 = require('stream/promises');
11
11
  var _get = require('@electron/get');
12
12
  var _child_process = require('child_process'); var _child_process2 = _interopRequireDefault(_child_process);
13
13
  var _semver = require('semver'); var _semver2 = _interopRequireDefault(_semver);
14
- var _chromeremoteinterface = require('chrome-remote-interface'); var _chromeremoteinterface2 = _interopRequireDefault(_chromeremoteinterface);
15
14
 
16
15
  // src/utils.ts
17
16
 
18
17
 
19
18
  var _promisepool = require('@supercharge/promise-pool');
19
+ var _lodash = require('lodash'); var _lodash2 = _interopRequireDefault(_lodash);
20
20
  async function fileExists(path5) {
21
21
  try {
22
22
  await _promises2.default.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 _lodash2.default.mergeWith(
76
+ object,
77
+ ...sources,
78
+ (objValue, srcValue, key, obj) => {
79
+ if (_lodash2.default.isPlainObject(obj) && objValue !== srcValue && srcValue === void 0) {
80
+ obj[key] = srcValue;
81
+ }
82
+ }
83
+ );
84
+ }
74
85
 
75
86
  // src/apis.ts
76
- var _lodash = require('lodash'); var _lodash2 = _interopRequireDefault(_lodash);
87
+
77
88
 
78
89
 
79
90
  var _url = require('url');
@@ -124,7 +135,7 @@ async function fetchGitHubAPIPaginated(url, params = {}) {
124
135
  while (next) {
125
136
  const response = await fetchGitHubAPI(next);
126
137
  results.push(...await response.json());
127
- next = _optionalChain([parseLinkHeader, 'call', _4 => _4(_nullishCoalesce(response.headers.get("link"), () => ( ""))), 'access', _5 => _5.next, 'optionalAccess', _6 => _6.url]);
138
+ next = _optionalChain([parseLinkHeader, 'call', _5 => _5(_nullishCoalesce(response.headers.get("link"), () => ( ""))), 'access', _6 => _6.next, 'optionalAccess', _7 => _7.url]);
128
139
  }
129
140
  return results;
130
141
  }
@@ -234,11 +245,13 @@ var ChromeLocalStorage = class {
234
245
  // src/launcherUtils.ts
235
246
 
236
247
 
248
+
237
249
  var _util = require('util');
238
250
 
239
251
  var _which = require('which'); var _which2 = _interopRequireDefault(_which);
240
252
 
241
253
 
254
+ var _chromeremoteinterface = require('chrome-remote-interface'); var _chromeremoteinterface2 = _interopRequireDefault(_chromeremoteinterface);
242
255
  var execFile = _util.promisify.call(void 0, _child_process2.default.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
@@ -311,12 +322,98 @@ function parseObsidianGithubRelease(gitHubRelease) {
311
322
  downloads: _lodash2.default.pickBy(downloads, (x) => x !== void 0)
312
323
  };
313
324
  }
325
+ async function getElectronVersionInfo(version, binaryPath) {
326
+ console.log(`${version}: Retrieving electron & chrome versions...`);
327
+ const configDir = await _promises2.default.mkdtemp(_path2.default.join(_os2.default.tmpdir(), `fetch-obsidian-versions-`));
328
+ const proc = _child_process2.default.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(_nullishCoalesce(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 = _optionalChain([data, 'access', _8 => _8.toString, 'call', _9 => _9(), 'access', _10 => _10.match, 'call', _11 => _11(/ws:\/\/[\w.]+?:(\d+)/), 'optionalAccess', _12 => _12[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 _chromeremoteinterface2.default.call(void 0, { 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 _promises2.default.rm(configDir, { recursive: true, force: true });
366
+ }
367
+ if (!_optionalChain([dependencyVersions, 'optionalAccess', _13 => _13.electron]) || !_optionalChain([dependencyVersions, 'optionalAccess', _14 => _14.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
374
+ };
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 = _nullishCoalesce(corrections.find((v) => v.version == versionInfo.version), () => ( {}));
316
390
  if (_semver2.default.gte(versionInfo.version, "1.5.3") && _semver2.default.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: _optionalChain([versionInfo, 'access', _15 => _15.downloads, 'optionalAccess', _16 => _16.asar]),
404
+ appImage: _optionalChain([versionInfo, 'access', _17 => _17.downloads, 'optionalAccess', _18 => _18.appImage]),
405
+ appImageArm: _optionalChain([versionInfo, 'access', _19 => _19.downloads, 'optionalAccess', _20 => _20.appImageArm]),
406
+ apk: _optionalChain([versionInfo, 'access', _21 => _21.downloads, 'optionalAccess', _22 => _22.apk]),
407
+ dmg: _optionalChain([versionInfo, 'access', _23 => _23.downloads, 'optionalAccess', _24 => _24.dmg]),
408
+ exe: _optionalChain([versionInfo, 'access', _25 => _25.downloads, 'optionalAccess', _26 => _26.exe])
409
+ },
410
+ electronVersion: versionInfo.electronVersion,
411
+ chromeVersion: versionInfo.chromeVersion,
412
+ nodeVersion: versionInfo.nodeVersion
413
+ };
414
+ versionInfo.downloads = _lodash2.default.omitBy(versionInfo.downloads, _lodash2.default.isUndefined);
415
+ versionInfo = _lodash2.default.omitBy(versionInfo, _lodash2.default.isUndefined);
416
+ return versionInfo;
320
417
  }
321
418
 
322
419
  // src/launcher.ts
@@ -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 _asyncOptionalChain([(await this.getRootManifest()), 'optionalAccess', async _7 => _7.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 = _nullishCoalesce(_semver2.default.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.default.lt(installerVersionInfo.version, appVersionInfo.minInstallerVersion)) {
527
+ if (_semver2.default.lt(installerVersionInfo.version, appVersionInfo.minInstallerVersion) || _semver2.default.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 _asyncOptionalChain([(await this.getRootManifest()), 'optionalAccess', async _27 => _27.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 = _nullishCoalesce(_semver2.default.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.
@@ -899,7 +1000,7 @@ 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
  */
@@ -933,11 +1034,11 @@ var ObsidianLauncher = class {
933
1034
  };
934
1035
  }
935
1036
  await _promises2.default.writeFile(_path2.default.join(configDir, "obsidian.json"), JSON.stringify(obsidianJson));
936
- if (params.appPath) {
937
- await linkOrCp(params.appPath, _path2.default.join(configDir, _path2.default.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, _path2.default.join(configDir, _path2.default.basename(appPath)));
941
1042
  const localStorage = new ChromeLocalStorage(configDir);
942
1043
  await localStorage.setItems("app://obsidian.md", localStorageData);
943
1044
  await localStorage.close();
@@ -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 _promises2.default.mkdtemp(_path2.default.join(_os2.default.tmpdir(), `fetch-obsidian-versions-`));
1011
- const proc = _child_process2.default.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(_nullishCoalesce(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 = _optionalChain([data, 'access', _8 => _8.toString, 'call', _9 => _9(), 'access', _10 => _10.match, 'call', _11 => _11(/ws:\/\/[\w.]+?:(\d+)/), 'optionalAccess', _12 => _12[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 _chromeremoteinterface2.default.call(void 0, { 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 _promises2.default.rm(configDir, { recursive: true, force: true });
1050
- }
1051
- if (!_optionalChain([dependencyVersions, 'optionalAccess', _13 => _13.electron]) || !_optionalChain([dependencyVersions, 'optionalAccess', _14 => _14.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
@@ -1067,7 +1111,7 @@ var ObsidianLauncher = class {
1067
1111
  const repo = "obsidianmd/obsidian-releases";
1068
1112
  let commitHistory = await fetchGitHubAPIPaginated(`repos/${repo}/commits`, {
1069
1113
  path: "desktop-releases.json",
1070
- since: _optionalChain([original, 'optionalAccess', _15 => _15.metadata, 'access', _16 => _16.commit_date])
1114
+ since: _optionalChain([original, 'optionalAccess', _28 => _28.metadata, 'access', _29 => _29.commit_date])
1071
1115
  });
1072
1116
  commitHistory.reverse();
1073
1117
  if (original) {
@@ -1080,7 +1124,7 @@ var ObsidianLauncher = class {
1080
1124
  );
1081
1125
  const githubReleases = await fetchGitHubAPIPaginated(`repos/${repo}/releases`);
1082
1126
  const versionMap = _lodash2.default.keyBy(
1083
- _nullishCoalesce(_optionalChain([original, 'optionalAccess', _17 => _17.versions]), () => ( [])),
1127
+ _nullishCoalesce(_optionalChain([original, 'optionalAccess', _30 => _30.versions]), () => ( [])),
1084
1128
  (v) => v.version
1085
1129
  );
1086
1130
  for (const { beta, ...current } of fileHistory) {
@@ -1104,37 +1148,46 @@ var ObsidianLauncher = class {
1104
1148
  }
1105
1149
  const dependencyVersions = await pool(
1106
1150
  maxInstances,
1107
- Object.values(versionMap).filter((v) => _optionalChain([v, 'access', _18 => _18.downloads, 'optionalAccess', _19 => _19.appImage]) && !v.chromeVersion),
1108
- (v) => this.getDependencyVersions(v)
1151
+ Object.values(versionMap).filter((v) => _optionalChain([v, 'access', _31 => _31.downloads, 'optionalAccess', _32 => _32.appImage]) && !v.chromeVersion),
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
1159
  versionMap[deps.version] = _lodash2.default.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.default.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] = _lodash2.default.merge(
1170
+ versionMap[version] = mergeKeepUndefined(
1119
1171
  {},
1120
1172
  versionMap[version],
1121
- correctObsidianVersionInfo(versionMap[version]),
1122
- { maxInstallerVersion }
1173
+ {
1174
+ minInstallerVersion: _nullishCoalesce(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.default.compare(a.version, b.version));
1127
1180
  const result = {
1128
1181
  metadata: {
1129
- commit_date: _nullishCoalesce(_optionalChain([commitHistory, 'access', _20 => _20.at, 'call', _21 => _21(-1), 'optionalAccess', _22 => _22.commit, 'access', _23 => _23.committer, 'access', _24 => _24.date]), () => ( _optionalChain([original, 'optionalAccess', _25 => _25.metadata, 'access', _26 => _26.commit_date]))),
1130
- commit_sha: _nullishCoalesce(_optionalChain([commitHistory, 'access', _27 => _27.at, 'call', _28 => _28(-1), 'optionalAccess', _29 => _29.sha]), () => ( _optionalChain([original, 'optionalAccess', _30 => _30.metadata, 'access', _31 => _31.commit_sha]))),
1131
- timestamp: _nullishCoalesce(_optionalChain([original, 'optionalAccess', _32 => _32.metadata, 'access', _33 => _33.timestamp]), () => ( ""))
1182
+ commit_date: _nullishCoalesce(_optionalChain([commitHistory, 'access', _33 => _33.at, 'call', _34 => _34(-1), 'optionalAccess', _35 => _35.commit, 'access', _36 => _36.committer, 'access', _37 => _37.date]), () => ( _optionalChain([original, 'optionalAccess', _38 => _38.metadata, 'access', _39 => _39.commit_date]))),
1183
+ commit_sha: _nullishCoalesce(_optionalChain([commitHistory, 'access', _40 => _40.at, 'call', _41 => _41(-1), 'optionalAccess', _42 => _42.sha]), () => ( _optionalChain([original, 'optionalAccess', _43 => _43.metadata, 'access', _44 => _44.commit_sha]))),
1184
+ timestamp: _nullishCoalesce(_optionalChain([original, 'optionalAccess', _45 => _45.metadata, 'access', _46 => _46.timestamp]), () => ( ""))
1132
1185
  // set down below
1133
1186
  },
1134
- versions: versionInfos
1187
+ versions: Object.values(versionMap).map(normalizeObsidianVersionInfo).sort((a, b) => _semver2.default.compare(a.version, b.version))
1135
1188
  };
1136
1189
  const dayMs = 24 * 60 * 60 * 1e3;
1137
- const timeSinceLastUpdate = (/* @__PURE__ */ new Date()).getTime() - new Date(_nullishCoalesce(_optionalChain([original, 'optionalAccess', _34 => _34.metadata, 'access', _35 => _35.timestamp]), () => ( 0))).getTime();
1190
+ const timeSinceLastUpdate = (/* @__PURE__ */ new Date()).getTime() - new Date(_nullishCoalesce(_optionalChain([original, 'optionalAccess', _47 => _47.metadata, 'access', _48 => _48.timestamp]), () => ( 0))).getTime();
1138
1191
  if (!_lodash2.default.isEqual(original, result) || timeSinceLastUpdate > 29 * dayMs) {
1139
1192
  result.metadata.timestamp = (/* @__PURE__ */ new Date()).toISOString();
1140
1193
  }
@@ -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
 
1174
1228
 
1175
1229
  exports.ObsidianLauncher = ObsidianLauncher;
1176
- //# sourceMappingURL=chunk-5W4LJ7AP.cjs.map
1230
+ //# sourceMappingURL=chunk-2DK4DOJU.cjs.map