obsidian-launcher 2.0.2 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -116,57 +116,19 @@ import fsAsync2 from "fs/promises";
116
116
  import readlineSync from "readline-sync";
117
117
  import dotenv from "dotenv";
118
118
  import path2 from "path";
119
+ import { Octokit } from "octokit";
119
120
  import { env } from "process";
120
- function parseLinkHeader(linkHeader) {
121
- function parseLinkData(linkData) {
122
- return Object.fromEntries(
123
- linkData.split(";").flatMap((x) => {
124
- const partMatch = x.trim().match(/^([^=]+?)\s*=\s*"?([^"]+)"?$/);
125
- return partMatch ? [[partMatch[1], partMatch[2]]] : [];
126
- })
127
- );
128
- }
129
- const linkDatas = linkHeader.split(/,\s*(?=<)/).flatMap((link) => {
130
- const linkMatch = link.trim().match(/^<([^>]*)>(.*)$/);
131
- if (linkMatch) {
132
- return [{
133
- url: linkMatch[1],
134
- ...parseLinkData(linkMatch[2])
135
- }];
136
- } else {
137
- return [];
138
- }
139
- }).filter((l) => l.rel);
140
- return Object.fromEntries(linkDatas.map((l) => [l.rel, l]));
141
- }
142
121
  function createURL(url, base, params = {}) {
143
- params = _2.pickBy(params, (x) => x !== void 0);
122
+ const cleanParams = _2(params).pickBy((x) => x !== void 0).mapValues((v) => String(v)).value();
144
123
  const urlObj = new URL(url, base);
145
- const searchParams = new URLSearchParams({ ...Object.fromEntries(urlObj.searchParams), ...params });
124
+ const searchParams = new URLSearchParams({ ...Object.fromEntries(urlObj.searchParams), ...cleanParams });
146
125
  if ([...searchParams].length > 0) {
147
126
  urlObj.search = "?" + searchParams;
148
127
  }
149
128
  return urlObj.toString();
150
129
  }
151
- async function fetchGitHubAPI(url, params = {}) {
152
- url = createURL(url, "https://api.github.com", params);
153
- const token = env.GITHUB_TOKEN;
154
- const headers = token ? { Authorization: "Bearer " + token } : {};
155
- const response = await fetch(url, { headers });
156
- if (!response.ok) {
157
- throw new Error(`GitHub API error: ${await response.text()}`);
158
- }
159
- return response;
160
- }
161
- async function fetchGitHubAPIPaginated(url, params = {}) {
162
- const results = [];
163
- let next = createURL(url, "https://api.github.com", { per_page: 100, ...params });
164
- while (next) {
165
- const response = await fetchGitHubAPI(next);
166
- results.push(...await response.json());
167
- next = parseLinkHeader(response.headers.get("link") ?? "").next?.url;
168
- }
169
- return results;
130
+ function getGithubClient() {
131
+ return new Octokit({ auth: env.GITHUB_TOKEN });
170
132
  }
171
133
  async function obsidianApiLogin(opts) {
172
134
  const { interactive = false, savePath } = opts;
@@ -180,7 +142,7 @@ async function obsidianApiLogin(opts) {
180
142
  password = password || readlineSync.question("Obsidian password: ", { hideEchoBack: true });
181
143
  } else {
182
144
  throw Error(
183
- "Obsidian Insiders account is required to download Obsidian beta versions. Either set the OBSIDIAN_EMAIL and OBSIDIAN_PASSWORD env vars (.env file is supported) or pre-download the Obsidian beta with `npx obsidian-launcher download -v <version>`"
145
+ "Obsidian Insiders account is required to download Obsidian beta versions. Either set the OBSIDIAN_EMAIL and OBSIDIAN_PASSWORD env vars (.env file is supported) or pre-download the Obsidian beta with `npx obsidian-launcher download app -v <version>`"
184
146
  );
185
147
  }
186
148
  }
@@ -209,7 +171,7 @@ async function obsidianApiLogin(opts) {
209
171
  needsMfa = true;
210
172
  if (!interactive) {
211
173
  throw Error(
212
- "Can't login with 2FA in a non-interactive session. To download Obsidian beta versions, either disable 2FA on your account or pre-download the Obsidian beta with `npx obsidian-launcher download -v <version>`"
174
+ "Can't login with 2FA in a non-interactive session. To download Obsidian beta versions, either disable 2FA on your account or pre-download the Obsidian beta with `npx obsidian-launcher download app -v <version>`"
213
175
  );
214
176
  }
215
177
  } else if (["please wait", "try again"].some((m) => error?.includes(m))) {
@@ -219,9 +181,9 @@ async function obsidianApiLogin(opts) {
219
181
  throw Error(`Obsidian login failed: ${signin.error ?? "unknown error"}`);
220
182
  }
221
183
  }
222
- if (!signin.token) {
223
- throw Error(`Obsidian login failed: ${signin.error ?? "unknown error"}`);
224
- } else if (!signin.license) {
184
+ if (!signin?.token) {
185
+ throw Error(`Obsidian login failed: ${signin?.error ?? "unknown error"}`);
186
+ } else if (!signin?.license) {
225
187
  throw Error("Obsidian Insiders account is required to download Obsidian beta versions");
226
188
  }
227
189
  if (interactive && savePath && (!env.OBSIDIAN_EMAIL || !env.OBSIDIAN_PASSWORD)) {
@@ -233,8 +195,8 @@ async function obsidianApiLogin(opts) {
233
195
  OBSIDIAN_PASSWORD='${password}'
234
196
  `
235
197
  );
198
+ console.log(`Saved Obsidian credentials to ${path2.relative(process.cwd(), savePath)}`);
236
199
  }
237
- console.log(`Saved Obsidian credentials to ${path2.relative(process.cwd(), savePath)}`);
238
200
  }
239
201
  return signin.token;
240
202
  }
@@ -411,6 +373,39 @@ async function extractObsidianDmg(dmg, dest) {
411
373
  }
412
374
  });
413
375
  }
376
+ async function fetchObsidianDesktopReleases(sinceDate, sinceSha) {
377
+ const repo = "obsidianmd/obsidian-releases";
378
+ const github = getGithubClient();
379
+ let commitHistory = await github.paginate(github.rest.repos.listCommits, {
380
+ owner: "obsidianmd",
381
+ repo: "obsidian-releases",
382
+ path: "desktop-releases.json",
383
+ since: sinceDate,
384
+ per_page: 100
385
+ });
386
+ commitHistory.reverse();
387
+ if (sinceSha) {
388
+ commitHistory = _3.takeRightWhile(commitHistory, (c) => c.sha != sinceSha);
389
+ }
390
+ const fileHistory = await pool(
391
+ 4,
392
+ commitHistory,
393
+ (commit) => fetch(`https://raw.githubusercontent.com/${repo}/${commit.sha}/desktop-releases.json`).then((r) => r.json())
394
+ );
395
+ const commitDate = commitHistory.at(-1)?.commit.committer?.date ?? sinceDate;
396
+ const commitSha = commitHistory.at(-1)?.sha ?? sinceSha;
397
+ return [fileHistory, { commitDate, commitSha }];
398
+ }
399
+ async function fetchObsidianGitHubReleases() {
400
+ const github = getGithubClient();
401
+ let gitHubReleases = await github.paginate(github.rest.repos.listReleases, {
402
+ owner: "obsidianmd",
403
+ repo: "obsidian-releases",
404
+ per_page: 100
405
+ });
406
+ gitHubReleases = gitHubReleases.reverse();
407
+ return gitHubReleases;
408
+ }
414
409
  var BROKEN_ASSETS = [
415
410
  "https://releases.obsidian.md/release/obsidian-0.12.16.asar.gz",
416
411
  "https://github.com/obsidianmd/obsidian-releases/releases/download/v0.12.16/obsidian-0.12.16.asar.gz",
@@ -481,7 +476,59 @@ function parseObsidianGithubRelease(gitHubRelease) {
481
476
  }
482
477
  };
483
478
  }
484
- async function getInstallerInfo(installerKey, url) {
479
+ var INSTALLER_KEYS = [
480
+ "appImage",
481
+ "appImageArm",
482
+ "tar",
483
+ "tarArm",
484
+ "dmg",
485
+ "exe"
486
+ ];
487
+ function updateObsidianVersionList(args) {
488
+ const { original = [], destkopReleases = [], gitHubReleases = [], installerInfos = [] } = args;
489
+ const oldVersions = _3.keyBy(original, (v) => v.version);
490
+ const newVersions = _3.cloneDeep(oldVersions);
491
+ for (const destkopRelease of destkopReleases) {
492
+ const { current, beta } = parseObsidianDesktopRelease(destkopRelease);
493
+ if (beta) {
494
+ newVersions[beta.version] = _3.merge(newVersions[beta.version] ?? {}, beta);
495
+ }
496
+ newVersions[current.version] = _3.merge(newVersions[current.version] ?? {}, current);
497
+ }
498
+ for (const githubRelease of gitHubReleases) {
499
+ if (semver.valid(githubRelease.name) && !semver.prerelease(githubRelease.name)) {
500
+ const parsed = parseObsidianGithubRelease(githubRelease);
501
+ const newVersion = _3.merge(newVersions[parsed.version] ?? {}, parsed);
502
+ for (const installerKey of INSTALLER_KEYS) {
503
+ const oldDigest = oldVersions[parsed.version]?.installers[installerKey]?.digest;
504
+ const newDigest = newVersion.installers?.[installerKey]?.digest;
505
+ if (oldDigest && oldDigest != newDigest) {
506
+ newVersion.installers[installerKey] = { digest: newDigest };
507
+ }
508
+ }
509
+ newVersions[parsed.version] = newVersion;
510
+ }
511
+ }
512
+ let minInstallerVersion = void 0;
513
+ let maxInstallerVersion = void 0;
514
+ for (const version of Object.keys(newVersions).sort(semver.compare)) {
515
+ if (newVersions[version].downloads.appImage) {
516
+ maxInstallerVersion = version;
517
+ if (!minInstallerVersion) {
518
+ minInstallerVersion = version;
519
+ }
520
+ }
521
+ newVersions[version] = _3.merge({ minInstallerVersion, maxInstallerVersion }, newVersions[version]);
522
+ }
523
+ for (const installerInfo of installerInfos) {
524
+ newVersions[installerInfo.version] = _3.merge(newVersions[installerInfo.version] ?? {}, {
525
+ version: installerInfo.version,
526
+ installers: { [installerInfo.key]: installerInfo.installerInfo }
527
+ });
528
+ }
529
+ return Object.values(newVersions).map(normalizeObsidianVersionInfo).sort((a, b) => semver.compare(a.version, b.version));
530
+ }
531
+ async function extractInstallerInfo(installerKey, url) {
485
532
  const installerName = url.split("/").at(-1);
486
533
  console.log(`Extrating installer info for ${installerName}...`);
487
534
  const tmpDir = await makeTmpDir("obsidian-launcher-");
@@ -757,10 +804,11 @@ var ObsidianLauncher = class {
757
804
  } else if (appVersion == "latest") {
758
805
  appVersion = versions.filter((v) => !v.isBeta).at(-1).version;
759
806
  } else if (appVersion == "earliest") {
760
- appVersion = (await this.getRootManifest())?.minAppVersion;
761
- if (!appVersion) {
807
+ const manifest = await this.getRootManifest();
808
+ if (!manifest?.minAppVersion) {
762
809
  throw Error('Unable to resolve Obsidian appVersion "earliest", no manifest.json or minAppVersion found.');
763
810
  }
811
+ appVersion = manifest.minAppVersion;
764
812
  } else {
765
813
  appVersion = semver2.valid(appVersion) ?? appVersion;
766
814
  }
@@ -798,7 +846,7 @@ var ObsidianLauncher = class {
798
846
  return _4.uniqBy(resolvedVersions, (v) => v.join("/"));
799
847
  }
800
848
  getInstallerKey(installerVersionInfo, opts = {}) {
801
- const { platform, arch } = _4.merge({}, opts, currentPlatform);
849
+ const { platform, arch } = _4.defaults({}, opts, currentPlatform);
802
850
  const platformName = `${platform}-${arch}`;
803
851
  const key = _4.findKey(installerVersionInfo.installers, (v) => v && v.platforms.includes(platformName));
804
852
  return key;
@@ -810,7 +858,7 @@ var ObsidianLauncher = class {
810
858
  * @param opts.arch Architecture (defaults to host architecture)
811
859
  */
812
860
  async getInstallerInfo(installerVersion, opts = {}) {
813
- const { platform, arch } = _4.merge({}, opts, currentPlatform);
861
+ const { platform, arch } = _4.defaults({}, opts, currentPlatform);
814
862
  const versionInfo = await this.getVersionInfo(installerVersion);
815
863
  const key = this.getInstallerKey(versionInfo, { platform, arch });
816
864
  if (key) {
@@ -829,7 +877,7 @@ var ObsidianLauncher = class {
829
877
  * @param opts.arch Architecture of the installer to download (defaults to host architecture)
830
878
  */
831
879
  async downloadInstaller(installerVersion, opts = {}) {
832
- const { platform, arch } = _4.merge({}, opts, currentPlatform);
880
+ const { platform, arch } = _4.defaults({}, opts, currentPlatform);
833
881
  const versionInfo = await this.getVersionInfo(installerVersion);
834
882
  installerVersion = versionInfo.version;
835
883
  const installerInfo = await this.getInstallerInfo(installerVersion, { platform, arch });
@@ -865,7 +913,7 @@ var ObsidianLauncher = class {
865
913
  *
866
914
  * To download Obsidian beta versions you'll need to have an Obsidian Insiders account and either set the
867
915
  * `OBSIDIAN_EMAIL` and `OBSIDIAN_PASSWORD` env vars (`.env` file is supported) or pre-download the Obsidian beta
868
- * with `npx obsidian-launcher download -v latest-beta`
916
+ * with `npx obsidian-launcher download app -v latest-beta`
869
917
  *
870
918
  * @param appVersion Obsidian version to download
871
919
  */
@@ -913,7 +961,7 @@ var ObsidianLauncher = class {
913
961
  * @param installerVersion Obsidian installer version
914
962
  */
915
963
  async downloadChromedriver(installerVersion, opts = {}) {
916
- const { platform, arch } = _4.merge({}, opts, currentPlatform);
964
+ const { platform, arch } = _4.defaults({}, opts, currentPlatform);
917
965
  const installerInfo = await this.getInstallerInfo(installerVersion, { platform, arch });
918
966
  const cacheDir = path5.join(this.cacheDir, `electron-chromedriver/${platform}-${arch}/${installerInfo.electron}`);
919
967
  let chromedriverPath;
@@ -1073,6 +1121,60 @@ var ObsidianLauncher = class {
1073
1121
  })
1074
1122
  );
1075
1123
  }
1124
+ /**
1125
+ * Installs plugins into an Obsidian vault
1126
+ * @param vault Path to the vault to install the plugins in
1127
+ * @param plugins List plugins to install
1128
+ */
1129
+ async installPlugins(vault, plugins) {
1130
+ const downloadedPlugins = await this.downloadPlugins(plugins);
1131
+ const obsidianDir = path5.join(vault, ".obsidian");
1132
+ await fsAsync4.mkdir(obsidianDir, { recursive: true });
1133
+ const enabledPluginsPath = path5.join(obsidianDir, "community-plugins.json");
1134
+ let originalEnabledPlugins = [];
1135
+ if (await fileExists(enabledPluginsPath)) {
1136
+ originalEnabledPlugins = JSON.parse(await fsAsync4.readFile(enabledPluginsPath, "utf-8"));
1137
+ }
1138
+ let enabledPlugins = [...originalEnabledPlugins];
1139
+ for (const { path: pluginPath, enabled = true, originalType } of downloadedPlugins) {
1140
+ const manifestPath = path5.join(pluginPath, "manifest.json");
1141
+ const pluginId = JSON.parse(await fsAsync4.readFile(manifestPath, "utf8").catch(() => "{}")).id;
1142
+ if (!pluginId) {
1143
+ throw Error(`${manifestPath} missing or malformed.`);
1144
+ }
1145
+ const pluginDest = path5.join(obsidianDir, "plugins", pluginId);
1146
+ await fsAsync4.mkdir(pluginDest, { recursive: true });
1147
+ const files = {
1148
+ "manifest.json": true,
1149
+ "main.js": true,
1150
+ "styles.css": false
1151
+ };
1152
+ for (const [file, required] of Object.entries(files)) {
1153
+ if (await fileExists(path5.join(pluginPath, file))) {
1154
+ await linkOrCp(path5.join(pluginPath, file), path5.join(pluginDest, file));
1155
+ } else if (required) {
1156
+ throw Error(`${pluginPath}/${file} missing.`);
1157
+ } else {
1158
+ await fsAsync4.rm(path5.join(pluginDest, file), { force: true });
1159
+ }
1160
+ }
1161
+ if (await fileExists(path5.join(pluginPath, "data.json"))) {
1162
+ await fsAsync4.cp(path5.join(pluginPath, "data.json"), path5.join(pluginDest, "data.json"));
1163
+ }
1164
+ const pluginAlreadyListed = enabledPlugins.includes(pluginId);
1165
+ if (enabled && !pluginAlreadyListed) {
1166
+ enabledPlugins.push(pluginId);
1167
+ } else if (!enabled && pluginAlreadyListed) {
1168
+ enabledPlugins = enabledPlugins.filter((p) => p != pluginId);
1169
+ }
1170
+ if (originalType == "local") {
1171
+ await fsAsync4.writeFile(path5.join(pluginDest, ".hotreload"), "");
1172
+ }
1173
+ }
1174
+ if (!_4.isEqual(enabledPlugins, originalEnabledPlugins)) {
1175
+ await fsAsync4.writeFile(enabledPluginsPath, JSON.stringify(enabledPlugins, void 0, 2));
1176
+ }
1177
+ }
1076
1178
  /** Gets the latest version of a theme. */
1077
1179
  async getLatestThemeVersion(repo) {
1078
1180
  repo = normalizeGitHubRepo(repo);
@@ -1086,25 +1188,40 @@ var ObsidianLauncher = class {
1086
1188
  * @param repo Repo
1087
1189
  * @returns path to the downloaded theme
1088
1190
  */
1089
- async downloadGitHubTheme(repo) {
1191
+ async downloadGitHubTheme(repo, version = "latest") {
1090
1192
  repo = normalizeGitHubRepo(repo);
1091
- const version = await this.getLatestThemeVersion(repo);
1193
+ const latest = await this.getLatestThemeVersion(repo);
1194
+ if (version == "latest") {
1195
+ version = latest;
1196
+ }
1197
+ if (!semver2.valid(version)) {
1198
+ throw Error(`Invalid version "${version}"`);
1199
+ }
1200
+ version = semver2.valid(version);
1092
1201
  const themeDir = path5.join(this.cacheDir, "obsidian-themes", repo, version);
1093
1202
  if (!await fileExists(themeDir)) {
1094
1203
  await atomicCreate(themeDir, async (tmpDir) => {
1095
1204
  const assetsToDownload = ["manifest.json", "theme.css"];
1205
+ let baseUrl = `https://github.com/${repo}/releases/download/${version}`;
1206
+ if (!(await fetch(`${baseUrl}/manifest.json`)).ok) {
1207
+ if (version != latest) {
1208
+ throw Error(`No theme version "${version}" found`);
1209
+ }
1210
+ baseUrl = `https://raw.githubusercontent.com/${repo}/HEAD`;
1211
+ }
1096
1212
  await Promise.all(
1097
- assetsToDownload.map(async (file) => {
1098
- const url = `https://raw.githubusercontent.com/${repo}/HEAD/${file}`;
1099
- const response = await fetch(url);
1100
- if (response.ok) {
1101
- await downloadResponse(response, path5.join(tmpDir, file));
1102
- } else {
1103
- throw Error(`No ${file} found for ${repo}`);
1213
+ assetsToDownload.map(
1214
+ async (file) => {
1215
+ const url = `${baseUrl}/${file}`;
1216
+ const response = await fetch(url);
1217
+ if (response.ok) {
1218
+ await downloadResponse(response, path5.join(tmpDir, file));
1219
+ } else {
1220
+ throw Error(`No ${file} found for ${repo}`);
1221
+ }
1104
1222
  }
1105
- })
1223
+ )
1106
1224
  );
1107
- return tmpDir;
1108
1225
  });
1109
1226
  }
1110
1227
  return themeDir;
@@ -1114,13 +1231,13 @@ var ObsidianLauncher = class {
1114
1231
  * @param name name of the theme
1115
1232
  * @returns path to the downloaded theme
1116
1233
  */
1117
- async downloadCommunityTheme(name) {
1234
+ async downloadCommunityTheme(name, version = "latest") {
1118
1235
  const communityThemes = await this.getCommunityThemes();
1119
1236
  const themeInfo = communityThemes.find((p) => p.name == name);
1120
1237
  if (!themeInfo) {
1121
1238
  throw Error(`No theme with name ${name} found.`);
1122
1239
  }
1123
- return await this.downloadGitHubTheme(themeInfo.repo);
1240
+ return await this.downloadGitHubTheme(themeInfo.repo, version);
1124
1241
  }
1125
1242
  /**
1126
1243
  * Downloads a list of themes to the cache and returns a list of {@link DownloadedThemeEntry} with the downloaded
@@ -1147,10 +1264,10 @@ var ObsidianLauncher = class {
1147
1264
  themePath = path5.resolve(theme.path);
1148
1265
  originalType = "local";
1149
1266
  } else if ("repo" in theme) {
1150
- themePath = await this.downloadGitHubTheme(theme.repo);
1267
+ themePath = await this.downloadGitHubTheme(theme.repo, theme.version);
1151
1268
  originalType = "github";
1152
1269
  } else if ("name" in theme) {
1153
- themePath = await this.downloadCommunityTheme(theme.name);
1270
+ themePath = await this.downloadCommunityTheme(theme.name, theme.version);
1154
1271
  originalType = "community";
1155
1272
  } else {
1156
1273
  throw Error("You must specify one of theme path, repo, or name");
@@ -1181,58 +1298,6 @@ var ObsidianLauncher = class {
1181
1298
  );
1182
1299
  }
1183
1300
  /**
1184
- * Installs plugins into an Obsidian vault
1185
- * @param vault Path to the vault to install the plugins in
1186
- * @param plugins List plugins to install
1187
- */
1188
- async installPlugins(vault, plugins) {
1189
- const downloadedPlugins = await this.downloadPlugins(plugins);
1190
- const obsidianDir = path5.join(vault, ".obsidian");
1191
- await fsAsync4.mkdir(obsidianDir, { recursive: true });
1192
- const enabledPluginsPath = path5.join(obsidianDir, "community-plugins.json");
1193
- let originalEnabledPlugins = [];
1194
- if (await fileExists(enabledPluginsPath)) {
1195
- originalEnabledPlugins = JSON.parse(await fsAsync4.readFile(enabledPluginsPath, "utf-8"));
1196
- }
1197
- let enabledPlugins = [...originalEnabledPlugins];
1198
- for (const { path: pluginPath, enabled = true, originalType } of downloadedPlugins) {
1199
- const manifestPath = path5.join(pluginPath, "manifest.json");
1200
- const pluginId = JSON.parse(await fsAsync4.readFile(manifestPath, "utf8").catch(() => "{}")).id;
1201
- if (!pluginId) {
1202
- throw Error(`${manifestPath} missing or malformed.`);
1203
- }
1204
- const pluginDest = path5.join(obsidianDir, "plugins", pluginId);
1205
- await fsAsync4.mkdir(pluginDest, { recursive: true });
1206
- const files = {
1207
- "manifest.json": [true, true],
1208
- "main.js": [true, true],
1209
- "styles.css": [false, true],
1210
- "data.json": [false, false]
1211
- };
1212
- for (const [file, [required, deleteIfMissing]] of Object.entries(files)) {
1213
- if (await fileExists(path5.join(pluginPath, file))) {
1214
- await linkOrCp(path5.join(pluginPath, file), path5.join(pluginDest, file));
1215
- } else if (required) {
1216
- throw Error(`${pluginPath}/${file} missing.`);
1217
- } else if (deleteIfMissing) {
1218
- await fsAsync4.rm(path5.join(pluginDest, file), { force: true });
1219
- }
1220
- }
1221
- const pluginAlreadyListed = enabledPlugins.includes(pluginId);
1222
- if (enabled && !pluginAlreadyListed) {
1223
- enabledPlugins.push(pluginId);
1224
- } else if (!enabled && pluginAlreadyListed) {
1225
- enabledPlugins = enabledPlugins.filter((p) => p != pluginId);
1226
- }
1227
- if (originalType == "local") {
1228
- await fsAsync4.writeFile(path5.join(pluginDest, ".hotreload"), "");
1229
- }
1230
- }
1231
- if (!_4.isEqual(enabledPlugins, originalEnabledPlugins)) {
1232
- await fsAsync4.writeFile(enabledPluginsPath, JSON.stringify(enabledPlugins, void 0, 2));
1233
- }
1234
- }
1235
- /**
1236
1301
  * Installs themes into an Obsidian vault
1237
1302
  * @param vault Path to the theme to install the themes in
1238
1303
  * @param themes List of themes to install
@@ -1403,71 +1468,31 @@ var ObsidianLauncher = class {
1403
1468
  */
1404
1469
  async updateVersionList(original, opts = {}) {
1405
1470
  const { maxInstances = 1 } = opts;
1406
- const repo = "obsidianmd/obsidian-releases";
1407
- const originalVersions = _4.keyBy(original?.versions ?? [], (v) => v.version);
1408
- const versions = _4.cloneDeep(originalVersions);
1409
- let commitHistory = await fetchGitHubAPIPaginated(`repos/${repo}/commits`, {
1410
- path: "desktop-releases.json",
1411
- since: original?.metadata?.commitDate
1412
- });
1413
- commitHistory.reverse();
1414
- if (original?.metadata?.commitSha) {
1415
- commitHistory = _4.takeRightWhile(commitHistory, (c) => c.sha != original.metadata.commitSha);
1416
- }
1417
- const fileHistory = await pool(
1418
- maxInstances,
1419
- commitHistory,
1420
- (commit) => fetch(`https://raw.githubusercontent.com/${repo}/${commit.sha}/desktop-releases.json`).then((r) => r.json())
1471
+ const [destkopReleases, commitInfo] = await fetchObsidianDesktopReleases(
1472
+ original?.metadata.commitDate,
1473
+ original?.metadata.commitSha
1421
1474
  );
1422
- for (const fileVersion of fileHistory) {
1423
- const { current, beta } = parseObsidianDesktopRelease(fileVersion);
1424
- if (beta) {
1425
- versions[beta.version] = _4.merge(versions[beta.version] ?? {}, beta);
1426
- }
1427
- versions[current.version] = _4.merge(versions[current.version] ?? {}, current);
1428
- }
1429
- const githubReleases = (await fetchGitHubAPIPaginated(`repos/${repo}/releases`)).reverse();
1430
- for (const release of githubReleases) {
1431
- if (semver2.valid(release.name)) {
1432
- const parsed = parseObsidianGithubRelease(release);
1433
- versions[parsed.version] = _4.merge(versions[parsed.version] ?? {}, parsed);
1434
- }
1435
- }
1436
- const installerKeys = ["appImage", "appImageArm", "tar", "tarArm", "dmg", "exe"];
1437
- const newInstallers = Object.values(versions).flatMap((v) => installerKeys.map((k) => [v, k]));
1475
+ const gitHubReleases = await fetchObsidianGitHubReleases();
1476
+ let newVersions = updateObsidianVersionList({
1477
+ original: original?.versions,
1478
+ destkopReleases,
1479
+ gitHubReleases
1480
+ });
1481
+ const newInstallers = newVersions.flatMap((v) => INSTALLER_KEYS.map((k) => [v, k])).filter(([v, key]) => v.downloads?.[key] && !v.installers?.[key]?.chrome);
1438
1482
  const installerInfos = await pool(maxInstances, newInstallers, async ([v, key]) => {
1439
- let installerInfo;
1440
- const hasAsset = !!v.downloads?.[key];
1441
- const alreadyExtracted = !!v.installers?.[key]?.chrome;
1442
- const changed = v.installers?.[key]?.digest != originalVersions[v.version]?.installers[key]?.digest;
1443
- if (hasAsset && (!alreadyExtracted || changed)) {
1444
- installerInfo = await getInstallerInfo(key, v.downloads[key]);
1445
- }
1446
- return { version: v.version, installerInfo: { [key]: installerInfo } };
1483
+ const installerInfo = await extractInstallerInfo(key, v.downloads[key]);
1484
+ return { version: v.version, key, installerInfo };
1447
1485
  });
1448
- for (const installerInfo of installerInfos) {
1449
- versions[installerInfo.version] = _4.merge(versions[installerInfo.version] ?? {}, installerInfo);
1450
- }
1451
- let minInstallerVersion = void 0;
1452
- let maxInstallerVersion = void 0;
1453
- for (const version of Object.keys(versions).sort(semver2.compare)) {
1454
- if (!minInstallerVersion && versions[version].downloads.appImage) {
1455
- minInstallerVersion = version;
1456
- }
1457
- if (versions[version].downloads.appImage) {
1458
- maxInstallerVersion = version;
1459
- }
1460
- versions[version] = _4.merge({ minInstallerVersion, maxInstallerVersion }, versions[version]);
1461
- }
1486
+ newVersions = updateObsidianVersionList({ original: newVersions, installerInfos });
1462
1487
  const result = {
1463
1488
  metadata: {
1464
1489
  schemaVersion: obsidianVersionsSchemaVersion,
1465
- commitDate: commitHistory.at(-1)?.commit.committer.date ?? original?.metadata.commitDate,
1466
- commitSha: commitHistory.at(-1)?.sha ?? original?.metadata.commitSha,
1490
+ commitDate: commitInfo.commitDate,
1491
+ commitSha: commitInfo.commitSha,
1467
1492
  timestamp: original?.metadata.timestamp ?? ""
1468
1493
  // set down below
1469
1494
  },
1470
- versions: Object.values(versions).map(normalizeObsidianVersionInfo).sort((a, b) => semver2.compare(a.version, b.version))
1495
+ versions: newVersions
1471
1496
  };
1472
1497
  const dayMs = 24 * 60 * 60 * 1e3;
1473
1498
  const timeSinceLastUpdate = (/* @__PURE__ */ new Date()).getTime() - new Date(original?.metadata.timestamp ?? 0).getTime();
@@ -1516,4 +1541,4 @@ export {
1516
1541
  watchFiles,
1517
1542
  ObsidianLauncher
1518
1543
  };
1519
- //# sourceMappingURL=chunk-EVX5ML6K.js.map
1544
+ //# sourceMappingURL=chunk-OUPK2DAJ.js.map