obsidian-integration-testing 4.4.0 → 5.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.
- package/README.md +51 -54
- package/dist/lib/cjs/eval-in-obsidian.cjs +1 -1
- package/dist/lib/cjs/eval-in-obsidian.d.cts +36 -1
- package/dist/lib/cjs/global-setup-core.cjs +13 -9
- package/dist/lib/cjs/global-setup-core.d.cts +1 -1
- package/dist/lib/cjs/index.cjs +1 -4
- package/dist/lib/cjs/index.d.cts +3 -4
- package/dist/lib/cjs/kill-process-tree.cjs +57 -0
- package/dist/lib/cjs/kill-process-tree.d.cts +16 -0
- package/dist/lib/cjs/library.cjs +1 -1
- package/dist/lib/cjs/namespace-bootstrap.cjs +21 -2
- package/dist/lib/cjs/obsidian-config.cjs +11 -85
- package/dist/lib/cjs/obsidian-config.d.cts +12 -72
- package/dist/lib/cjs/obsidian-installer.cjs +180 -0
- package/dist/lib/cjs/obsidian-installer.d.cts +45 -0
- package/dist/lib/cjs/obsidian-instance.cjs +100 -0
- package/dist/lib/cjs/obsidian-instance.d.cts +55 -0
- package/dist/lib/cjs/obsidian-version-switch.cjs +105 -0
- package/dist/lib/cjs/obsidian-version-switch.d.cts +63 -0
- package/dist/lib/cjs/obsidian-version.cjs +85 -0
- package/dist/lib/cjs/obsidian-version.d.cts +111 -0
- package/dist/lib/cjs/transport-desktop-cdp.cjs +121 -7
- package/dist/lib/cjs/transport-desktop-cdp.d.cts +75 -14
- package/dist/lib/cjs/transport-factory.cjs +63 -32
- package/dist/lib/cjs/transport-options.cjs +1 -1
- package/dist/lib/cjs/transport-options.d.cts +37 -14
- package/dist/lib/cjs/transport.cjs +1 -1
- package/dist/lib/cjs/transport.d.cts +1 -1
- package/dist/lib/cjs/vitest/global-setup.cjs +2 -2
- package/dist/lib/cjs/vitest/typings.d.cts +1 -1
- package/dist/lib/esm/eval-in-obsidian.d.mts +36 -1
- package/dist/lib/esm/eval-in-obsidian.mjs +1 -1
- package/dist/lib/esm/global-setup-core.d.mts +1 -1
- package/dist/lib/esm/global-setup-core.mjs +13 -9
- package/dist/lib/esm/index.d.mts +3 -4
- package/dist/lib/esm/index.mjs +1 -3
- package/dist/lib/esm/kill-process-tree.d.mts +16 -0
- package/dist/lib/esm/kill-process-tree.mjs +23 -0
- package/dist/lib/esm/library.mjs +1 -1
- package/dist/lib/esm/namespace-bootstrap.mjs +21 -2
- package/dist/lib/esm/obsidian-config.d.mts +12 -72
- package/dist/lib/esm/obsidian-config.mjs +10 -78
- package/dist/lib/esm/obsidian-installer.d.mts +45 -0
- package/dist/lib/esm/obsidian-installer.mjs +158 -0
- package/dist/lib/esm/obsidian-instance.d.mts +55 -0
- package/dist/lib/esm/obsidian-instance.mjs +75 -0
- package/dist/lib/esm/obsidian-version-switch.d.mts +63 -0
- package/dist/lib/esm/obsidian-version-switch.mjs +89 -0
- package/dist/lib/esm/obsidian-version.d.mts +111 -0
- package/dist/lib/esm/obsidian-version.mjs +55 -0
- package/dist/lib/esm/transport-desktop-cdp.d.mts +75 -14
- package/dist/lib/esm/transport-desktop-cdp.mjs +125 -7
- package/dist/lib/esm/transport-factory.mjs +68 -28
- package/dist/lib/esm/transport-options.d.mts +37 -14
- package/dist/lib/esm/transport.d.mts +1 -1
- package/dist/lib/esm/vitest/global-setup.mjs +2 -2
- package/dist/lib/esm/vitest/typings.d.mts +1 -1
- package/dist/obsidian-integration-testing-5.1.0.tgz +0 -0
- package/package.json +16 -15
- package/dist/lib/cjs/transport-desktop-cli.cjs +0 -540
- package/dist/lib/cjs/transport-desktop-cli.d.cts +0 -154
- package/dist/lib/esm/transport-desktop-cli.d.mts +0 -154
- package/dist/lib/esm/transport-desktop-cli.mjs +0 -520
- package/dist/obsidian-integration-testing-4.4.0.tgz +0 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { createServer } from "node:net";
|
|
3
|
+
import { killProcessTree } from "./kill-process-tree.mjs";
|
|
4
|
+
import { log } from "./log.mjs";
|
|
5
|
+
const DEFAULT_CDP_HOST = "127.0.0.1";
|
|
6
|
+
const CDP_READY_POLL_INTERVAL_IN_MILLISECONDS = 1e3;
|
|
7
|
+
const CDP_READY_TIMEOUT_IN_MILLISECONDS = 6e4;
|
|
8
|
+
async function launchOwnedObsidianInstance(params) {
|
|
9
|
+
const cdpHost = params.cdpHost ?? DEFAULT_CDP_HOST;
|
|
10
|
+
const port = await pickFreePort();
|
|
11
|
+
const cdpUrl = `http://${cdpHost}:${String(port)}`;
|
|
12
|
+
log(`[obsidian-instance] Launching owned Obsidian: userData=${params.userDataDir}, cdpPort=${String(port)}`);
|
|
13
|
+
const child = spawn(
|
|
14
|
+
params.exePath,
|
|
15
|
+
[`--user-data-dir=${params.userDataDir}`, `--remote-debugging-port=${String(port)}`],
|
|
16
|
+
{ detached: true, stdio: "ignore" }
|
|
17
|
+
);
|
|
18
|
+
child.unref();
|
|
19
|
+
try {
|
|
20
|
+
await waitForCdpReady(cdpUrl);
|
|
21
|
+
log(`[obsidian-instance] Owned Obsidian is serving CDP at ${cdpUrl}.`);
|
|
22
|
+
return { cdpUrl, kill, port };
|
|
23
|
+
} catch (error) {
|
|
24
|
+
kill();
|
|
25
|
+
throw error;
|
|
26
|
+
}
|
|
27
|
+
function kill() {
|
|
28
|
+
killProcessTree(child);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function pickFreePort() {
|
|
32
|
+
return new Promise((resolve, reject) => {
|
|
33
|
+
const server = createServer();
|
|
34
|
+
server.once("error", reject);
|
|
35
|
+
server.listen(0, DEFAULT_CDP_HOST, () => {
|
|
36
|
+
const address = server.address();
|
|
37
|
+
if (address === null || typeof address === "string") {
|
|
38
|
+
server.close();
|
|
39
|
+
reject(new Error("Failed to determine a free port."));
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const { port } = address;
|
|
43
|
+
server.close(() => {
|
|
44
|
+
resolve(port);
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
function delay(ms) {
|
|
50
|
+
return new Promise((resolve) => {
|
|
51
|
+
setTimeout(resolve, ms);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
async function waitForCdpReady(cdpUrl) {
|
|
55
|
+
const deadline = Date.now() + CDP_READY_TIMEOUT_IN_MILLISECONDS;
|
|
56
|
+
while (Date.now() < deadline) {
|
|
57
|
+
try {
|
|
58
|
+
const response = await fetch(`${cdpUrl}/json`);
|
|
59
|
+
const targets = await response.json();
|
|
60
|
+
if (targets.some((target) => target.type === "page")) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
} catch {
|
|
64
|
+
}
|
|
65
|
+
await delay(CDP_READY_POLL_INTERVAL_IN_MILLISECONDS);
|
|
66
|
+
}
|
|
67
|
+
throw new Error(
|
|
68
|
+
`Owned Obsidian instance did not expose CDP at ${cdpUrl} within ${String(CDP_READY_TIMEOUT_IN_MILLISECONDS)}ms.`
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
export {
|
|
72
|
+
launchOwnedObsidianInstance,
|
|
73
|
+
pickFreePort
|
|
74
|
+
};
|
|
75
|
+
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vc3JjL29ic2lkaWFuLWluc3RhbmNlLnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyIvKipcbiAqIEBmaWxlXG4gKlxuICogTGF1bmNoZXMgYW5kIG1hbmFnZXMgYSBoYXJuZXNzLW93bmVkLCBpc29sYXRlZCBPYnNpZGlhbiBkZXNrdG9wIGluc3RhbmNlLlxuICpcbiAqIFRoZSBpbnN0YW5jZSBydW5zIGFnYWluc3QgYSBkZWRpY2F0ZWQgYC0tdXNlci1kYXRhLWRpcmAgKHNvIGl0IG5ldmVyIHRvdWNoZXNcbiAqIHRoZSB1c2VyJ3MgT2JzaWRpYW4gY29uZmlnLCByZWdpc3RyeSwgb3IgcnVubmluZyB3aW5kb3cpIGFuZCBleHBvc2VzIENEUCBvbiBhXG4gKiBkZWRpY2F0ZWQgYC0tcmVtb3RlLWRlYnVnZ2luZy1wb3J0YC4gQmVjYXVzZSBFbGVjdHJvbidzIHNpbmdsZS1pbnN0YW5jZSBsb2NrXG4gKiBpcyBrZXllZCB0byB0aGUgdXNlci1kYXRhIGRpciwgdGhlIG93bmVkIGluc3RhbmNlIHJ1bnMgaW4gcGFyYWxsZWwgd2l0aCB0aGVcbiAqIHVzZXIncyBvd24gT2JzaWRpYW4uIENvbmZpcm1lZCBieSB0aGUgUGhhc2UgMCBzcGlrZSAoc2VlIHRoZSBwcm9qZWN0IHBsYW4pLlxuICovXG5cbi8qIHY4IGlnbm9yZSBzdGFydCAtLSBJbnRlZ3JhdGlvbi10aW1lIHByb2Nlc3MgbWFuYWdlbWVudCBjb3ZlcmVkIGJ5IGludGVncmF0aW9uIHRlc3RzLCBub3QgdW5pdCB0ZXN0cy4gKi9cblxuaW1wb3J0IHsgc3Bhd24gfSBmcm9tICdub2RlOmNoaWxkX3Byb2Nlc3MnO1xuaW1wb3J0IHsgY3JlYXRlU2VydmVyIH0gZnJvbSAnbm9kZTpuZXQnO1xuXG5pbXBvcnQgeyBraWxsUHJvY2Vzc1RyZWUgfSBmcm9tICcuL2tpbGwtcHJvY2Vzcy10cmVlLm1qcyc7XG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuL2xvZy5tanMnO1xuXG4vKipcbiAqIFBhcmFtZXRlcnMgZm9yIHtAbGluayBsYXVuY2hPd25lZE9ic2lkaWFuSW5zdGFuY2V9LlxuICovXG5leHBvcnQgaW50ZXJmYWNlIExhdW5jaE93bmVkT2JzaWRpYW5JbnN0YW5jZVBhcmFtcyB7XG4gIC8qKlxuICAgKiBDRFAgaG9zdCB0byBiaW5kL3BvbGwuXG4gICAqXG4gICAqIEBkZWZhdWx0IGAnMTI3LjAuMC4xJ2BcbiAgICovXG4gIHJlYWRvbmx5IGNkcEhvc3Q/OiBzdHJpbmc7XG5cbiAgLyoqIEFic29sdXRlIHBhdGggdG8gdGhlIE9ic2lkaWFuIGV4ZWN1dGFibGUgKHNoZWxsKSB0byBsYXVuY2guICovXG4gIHJlYWRvbmx5IGV4ZVBhdGg6IHN0cmluZztcblxuICAvKiogQWJzb2x1dGUgcGF0aCB0byB0aGUgaXNvbGF0ZWQgdXNlci1kYXRhIGRpciB0byBwYXNzIHZpYSBgLS11c2VyLWRhdGEtZGlyYC4gKi9cbiAgcmVhZG9ubHkgdXNlckRhdGFEaXI6IHN0cmluZztcbn1cblxuLyoqXG4gKiBBIHJ1bm5pbmcsIGhhcm5lc3Mtb3duZWQgT2JzaWRpYW4gaW5zdGFuY2UuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgT3duZWRPYnNpZGlhbkluc3RhbmNlIHtcbiAgLyoqIEJhc2UgQ0RQIFVSTCwgZS5nLiBgaHR0cDovLzEyNy4wLjAuMTo1MTg4OGAuICovXG4gIHJlYWRvbmx5IGNkcFVybDogc3RyaW5nO1xuXG4gIC8qKiBLaWxscyB0aGUgaW5zdGFuY2UgYW5kIGl0cyBlbnRpcmUgcHJvY2VzcyB0cmVlLiAqL1xuICBraWxsKCk6IHZvaWQ7XG5cbiAgLyoqIFRoZSBDRFAgcmVtb3RlLWRlYnVnZ2luZyBwb3J0IHRoZSBpbnN0YW5jZSB3YXMgbGF1bmNoZWQgd2l0aC4gKi9cbiAgcmVhZG9ubHkgcG9ydDogbnVtYmVyO1xufVxuXG5jb25zdCBERUZBVUxUX0NEUF9IT1NUID0gJzEyNy4wLjAuMSc7XG5jb25zdCBDRFBfUkVBRFlfUE9MTF9JTlRFUlZBTF9JTl9NSUxMSVNFQ09ORFMgPSAxMDAwO1xuY29uc3QgQ0RQX1JFQURZX1RJTUVPVVRfSU5fTUlMTElTRUNPTkRTID0gNjAwMDA7XG5cbmludGVyZmFjZSBDZHBUYXJnZXQge1xuICB0eXBlOiBzdHJpbmc7XG59XG5cbi8qKlxuICogTGF1bmNoZXMgYW4gaXNvbGF0ZWQsIGhhcm5lc3Mtb3duZWQgT2JzaWRpYW4gaW5zdGFuY2UgYW5kIHdhaXRzIHVudGlsIGl0cyBDRFBcbiAqIGVuZHBvaW50IGlzIHNlcnZpbmcgcGFnZSB0YXJnZXRzLlxuICpcbiAqIEBwYXJhbSBwYXJhbXMgLSBMYXVuY2ggcGFyYW1ldGVycy5cbiAqIEByZXR1cm5zIFRoZSBydW5uaW5nIG93bmVkIGluc3RhbmNlLlxuICogQHRocm93cyBFcnJvciBpZiBDRFAgZG9lcyBub3QgYmVjb21lIHJlYWNoYWJsZSB3aXRoaW4gdGhlIHRpbWVvdXQuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBsYXVuY2hPd25lZE9ic2lkaWFuSW5zdGFuY2UoXG4gIHBhcmFtczogTGF1bmNoT3duZWRPYnNpZGlhbkluc3RhbmNlUGFyYW1zXG4pOiBQcm9taXNlPE93bmVkT2JzaWRpYW5JbnN0YW5jZT4ge1xuICBjb25zdCBjZHBIb3N0ID0gcGFyYW1zLmNkcEhvc3QgPz8gREVGQVVMVF9DRFBfSE9TVDtcbiAgY29uc3QgcG9ydCA9IGF3YWl0IHBpY2tGcmVlUG9ydCgpO1xuICBjb25zdCBjZHBVcmwgPSBgaHR0cDovLyR7Y2RwSG9zdH06JHtTdHJpbmcocG9ydCl9YDtcblxuICBsb2coYFtvYnNpZGlhbi1pbnN0YW5jZV0gTGF1bmNoaW5nIG93bmVkIE9ic2lkaWFuOiB1c2VyRGF0YT0ke3BhcmFtcy51c2VyRGF0YURpcn0sIGNkcFBvcnQ9JHtTdHJpbmcocG9ydCl9YCk7XG4gIGNvbnN0IGNoaWxkID0gc3Bhd24oXG4gICAgcGFyYW1zLmV4ZVBhdGgsXG4gICAgW2AtLXVzZXItZGF0YS1kaXI9JHtwYXJhbXMudXNlckRhdGFEaXJ9YCwgYC0tcmVtb3RlLWRlYnVnZ2luZy1wb3J0PSR7U3RyaW5nKHBvcnQpfWBdLFxuICAgIHsgZGV0YWNoZWQ6IHRydWUsIHN0ZGlvOiAnaWdub3JlJyB9XG4gICk7XG4gIGNoaWxkLnVucmVmKCk7XG5cbiAgdHJ5IHtcbiAgICBhd2FpdCB3YWl0Rm9yQ2RwUmVhZHkoY2RwVXJsKTtcbiAgICBsb2coYFtvYnNpZGlhbi1pbnN0YW5jZV0gT3duZWQgT2JzaWRpYW4gaXMgc2VydmluZyBDRFAgYXQgJHtjZHBVcmx9LmApO1xuICAgIHJldHVybiB7IGNkcFVybCwga2lsbCwgcG9ydCB9O1xuICB9IGNhdGNoIChlcnJvcjogdW5rbm93bikge1xuICAgIGtpbGwoKTtcbiAgICB0aHJvdyBlcnJvcjtcbiAgfVxuXG4gIGZ1bmN0aW9uIGtpbGwoKTogdm9pZCB7XG4gICAga2lsbFByb2Nlc3NUcmVlKGNoaWxkKTtcbiAgfVxufVxuXG4vKipcbiAqIFBpY2tzIGEgZnJlZSBUQ1AgcG9ydCBieSBiaW5kaW5nIHRvIHBvcnQgYDBgIGFuZCByZWFkaW5nIHRoZSBhc3NpZ25lZCBwb3J0LlxuICpcbiAqIFRoZXJlIGlzIGEgc21hbGwgdGltZS1vZi1jaGVjay90aW1lLW9mLXVzZSB3aW5kb3cgYmV0d2VlbiByZWxlYXNpbmcgdGhlIHBvcnRcbiAqIGhlcmUgYW5kIE9ic2lkaWFuIGJpbmRpbmcgaXQ7IGluIHByYWN0aWNlIGl0IGlzIG5lZ2xpZ2libGUgZm9yIHRlc3QgcnVucy5cbiAqXG4gKiBAcmV0dXJucyBBIGZyZWUgVENQIHBvcnQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBwaWNrRnJlZVBvcnQoKTogUHJvbWlzZTxudW1iZXI+IHtcbiAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICBjb25zdCBzZXJ2ZXIgPSBjcmVhdGVTZXJ2ZXIoKTtcbiAgICBzZXJ2ZXIub25jZSgnZXJyb3InLCByZWplY3QpO1xuICAgIHNlcnZlci5saXN0ZW4oMCwgREVGQVVMVF9DRFBfSE9TVCwgKCkgPT4ge1xuICAgICAgY29uc3QgYWRkcmVzcyA9IHNlcnZlci5hZGRyZXNzKCk7XG4gICAgICBpZiAoYWRkcmVzcyA9PT0gbnVsbCB8fCB0eXBlb2YgYWRkcmVzcyA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgc2VydmVyLmNsb3NlKCk7XG4gICAgICAgIHJlamVjdChuZXcgRXJyb3IoJ0ZhaWxlZCB0byBkZXRlcm1pbmUgYSBmcmVlIHBvcnQuJykpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICBjb25zdCB7IHBvcnQgfSA9IGFkZHJlc3M7XG4gICAgICBzZXJ2ZXIuY2xvc2UoKCkgPT4ge1xuICAgICAgICByZXNvbHZlKHBvcnQpO1xuICAgICAgfSk7XG4gICAgfSk7XG4gIH0pO1xufVxuXG4vKipcbiAqIFJldHVybnMgYSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgYWZ0ZXIgdGhlIGdpdmVuIGRlbGF5LlxuICpcbiAqIEBwYXJhbSBtcyAtIFRoZSBkZWxheSBpbiBtaWxsaXNlY29uZHMuXG4gKiBAcmV0dXJucyBBIHByb21pc2UgdGhhdCByZXNvbHZlcyBhZnRlciB0aGUgZGVsYXkuXG4gKi9cbmZ1bmN0aW9uIGRlbGF5KG1zOiBudW1iZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiB7XG4gICAgc2V0VGltZW91dChyZXNvbHZlLCBtcyk7XG4gIH0pO1xufVxuXG4vKipcbiAqIFBvbGxzIHRoZSBDRFAgYC9qc29uYCBlbmRwb2ludCB1bnRpbCBhdCBsZWFzdCBvbmUgcGFnZSB0YXJnZXQgYXBwZWFycy5cbiAqXG4gKiBAcGFyYW0gY2RwVXJsIC0gVGhlIGJhc2UgQ0RQIFVSTC5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gd2FpdEZvckNkcFJlYWR5KGNkcFVybDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IGRlYWRsaW5lID0gRGF0ZS5ub3coKSArIENEUF9SRUFEWV9USU1FT1VUX0lOX01JTExJU0VDT05EUztcbiAgd2hpbGUgKERhdGUubm93KCkgPCBkZWFkbGluZSkge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGZldGNoKGAke2NkcFVybH0vanNvbmApO1xuICAgICAgY29uc3QgdGFyZ2V0cyA9IGF3YWl0IHJlc3BvbnNlLmpzb24oKSBhcyBDZHBUYXJnZXRbXTtcbiAgICAgIGlmICh0YXJnZXRzLnNvbWUoKHRhcmdldCkgPT4gdGFyZ2V0LnR5cGUgPT09ICdwYWdlJykpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgIH0gY2F0Y2gge1xuICAgICAgLy8gRW5kcG9pbnQgbm90IHVwIHlldCBcdTIwMTQga2VlcCBwb2xsaW5nLlxuICAgIH1cbiAgICBhd2FpdCBkZWxheShDRFBfUkVBRFlfUE9MTF9JTlRFUlZBTF9JTl9NSUxMSVNFQ09ORFMpO1xuICB9XG4gIHRocm93IG5ldyBFcnJvcihcbiAgICBgT3duZWQgT2JzaWRpYW4gaW5zdGFuY2UgZGlkIG5vdCBleHBvc2UgQ0RQIGF0ICR7Y2RwVXJsfSB3aXRoaW4gJHtTdHJpbmcoQ0RQX1JFQURZX1RJTUVPVVRfSU5fTUlMTElTRUNPTkRTKX1tcy5gXG4gICk7XG59XG5cbi8qIHY4IGlnbm9yZSBzdG9wICovXG4iXSwKICAibWFwcGluZ3MiOiAiQUFjQSxTQUFTLGFBQWE7QUFDdEIsU0FBUyxvQkFBb0I7QUFFN0IsU0FBUyx1QkFBdUI7QUFDaEMsU0FBUyxXQUFXO0FBa0NwQixNQUFNLG1CQUFtQjtBQUN6QixNQUFNLDBDQUEwQztBQUNoRCxNQUFNLG9DQUFvQztBQWMxQyxlQUFzQiw0QkFDcEIsUUFDZ0M7QUFDaEMsUUFBTSxVQUFVLE9BQU8sV0FBVztBQUNsQyxRQUFNLE9BQU8sTUFBTSxhQUFhO0FBQ2hDLFFBQU0sU0FBUyxVQUFVLE9BQU8sSUFBSSxPQUFPLElBQUksQ0FBQztBQUVoRCxNQUFJLDBEQUEwRCxPQUFPLFdBQVcsYUFBYSxPQUFPLElBQUksQ0FBQyxFQUFFO0FBQzNHLFFBQU0sUUFBUTtBQUFBLElBQ1osT0FBTztBQUFBLElBQ1AsQ0FBQyxtQkFBbUIsT0FBTyxXQUFXLElBQUksMkJBQTJCLE9BQU8sSUFBSSxDQUFDLEVBQUU7QUFBQSxJQUNuRixFQUFFLFVBQVUsTUFBTSxPQUFPLFNBQVM7QUFBQSxFQUNwQztBQUNBLFFBQU0sTUFBTTtBQUVaLE1BQUk7QUFDRixVQUFNLGdCQUFnQixNQUFNO0FBQzVCLFFBQUksd0RBQXdELE1BQU0sR0FBRztBQUNyRSxXQUFPLEVBQUUsUUFBUSxNQUFNLEtBQUs7QUFBQSxFQUM5QixTQUFTLE9BQWdCO0FBQ3ZCLFNBQUs7QUFDTCxVQUFNO0FBQUEsRUFDUjtBQUVBLFdBQVMsT0FBYTtBQUNwQixvQkFBZ0IsS0FBSztBQUFBLEVBQ3ZCO0FBQ0Y7QUFVTyxTQUFTLGVBQWdDO0FBQzlDLFNBQU8sSUFBSSxRQUFRLENBQUMsU0FBUyxXQUFXO0FBQ3RDLFVBQU0sU0FBUyxhQUFhO0FBQzVCLFdBQU8sS0FBSyxTQUFTLE1BQU07QUFDM0IsV0FBTyxPQUFPLEdBQUcsa0JBQWtCLE1BQU07QUFDdkMsWUFBTSxVQUFVLE9BQU8sUUFBUTtBQUMvQixVQUFJLFlBQVksUUFBUSxPQUFPLFlBQVksVUFBVTtBQUNuRCxlQUFPLE1BQU07QUFDYixlQUFPLElBQUksTUFBTSxrQ0FBa0MsQ0FBQztBQUNwRDtBQUFBLE1BQ0Y7QUFDQSxZQUFNLEVBQUUsS0FBSyxJQUFJO0FBQ2pCLGFBQU8sTUFBTSxNQUFNO0FBQ2pCLGdCQUFRLElBQUk7QUFBQSxNQUNkLENBQUM7QUFBQSxJQUNILENBQUM7QUFBQSxFQUNILENBQUM7QUFDSDtBQVFBLFNBQVMsTUFBTSxJQUEyQjtBQUN4QyxTQUFPLElBQUksUUFBUSxDQUFDLFlBQVk7QUFDOUIsZUFBVyxTQUFTLEVBQUU7QUFBQSxFQUN4QixDQUFDO0FBQ0g7QUFPQSxlQUFlLGdCQUFnQixRQUErQjtBQUM1RCxRQUFNLFdBQVcsS0FBSyxJQUFJLElBQUk7QUFDOUIsU0FBTyxLQUFLLElBQUksSUFBSSxVQUFVO0FBQzVCLFFBQUk7QUFDRixZQUFNLFdBQVcsTUFBTSxNQUFNLEdBQUcsTUFBTSxPQUFPO0FBQzdDLFlBQU0sVUFBVSxNQUFNLFNBQVMsS0FBSztBQUNwQyxVQUFJLFFBQVEsS0FBSyxDQUFDLFdBQVcsT0FBTyxTQUFTLE1BQU0sR0FBRztBQUNwRDtBQUFBLE1BQ0Y7QUFBQSxJQUNGLFFBQVE7QUFBQSxJQUVSO0FBQ0EsVUFBTSxNQUFNLHVDQUF1QztBQUFBLEVBQ3JEO0FBQ0EsUUFBTSxJQUFJO0FBQUEsSUFDUixpREFBaUQsTUFBTSxXQUFXLE9BQU8saUNBQWlDLENBQUM7QUFBQSxFQUM3RztBQUNGOyIsCiAgIm5hbWVzIjogW10KfQo=
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file
|
|
3
|
+
*
|
|
4
|
+
* Integration-time helpers for provisioning a specific Obsidian **asar** (the
|
|
5
|
+
* app code) into an isolated user-data dir.
|
|
6
|
+
*
|
|
7
|
+
* Obsidian's bootstrap loads the highest of (its shell's bundled
|
|
8
|
+
* `resources/obsidian.asar`, the `obsidian-<version>.asar` files in the
|
|
9
|
+
* user-data dir). So placing an asar here only takes effect when its version is
|
|
10
|
+
* **>= the shell's bundled version** (upgrade-only — confirmed by the Phase 0
|
|
11
|
+
* spike). Running an older version requires pinning the installer/shell instead
|
|
12
|
+
* (see `obsidian-installer.ts`).
|
|
13
|
+
*/
|
|
14
|
+
import type { DesktopReleasesManifest } from './obsidian-version.mjs';
|
|
15
|
+
/**
|
|
16
|
+
* A discovered `obsidian-<version>.asar` file.
|
|
17
|
+
*/
|
|
18
|
+
export interface DiscoveredAsar {
|
|
19
|
+
/** Absolute path to the asar file. */
|
|
20
|
+
readonly path: string;
|
|
21
|
+
/** The `x.y.z` version parsed from the file name. */
|
|
22
|
+
readonly version: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Copies an asar file into a user-data dir under its canonical
|
|
26
|
+
* `obsidian-<version>.asar` name.
|
|
27
|
+
*
|
|
28
|
+
* @param asarPath - Source asar path.
|
|
29
|
+
* @param version - The asar's version (used for the destination file name).
|
|
30
|
+
* @param userDataDir - Destination user-data dir.
|
|
31
|
+
*/
|
|
32
|
+
export declare function copyAsarIntoUserData(asarPath: string, version: string, userDataDir: string): void;
|
|
33
|
+
/**
|
|
34
|
+
* Ensures the asar for a concrete version is present in the local cache,
|
|
35
|
+
* downloading and decompressing it if necessary.
|
|
36
|
+
*
|
|
37
|
+
* @param version - A concrete `x.y.z` version.
|
|
38
|
+
* @returns The absolute path to the cached asar.
|
|
39
|
+
* @throws Error if the download fails.
|
|
40
|
+
*/
|
|
41
|
+
export declare function ensureAsarCached(version: string): Promise<string>;
|
|
42
|
+
/**
|
|
43
|
+
* Fetches and parses Obsidian's desktop releases manifest.
|
|
44
|
+
*
|
|
45
|
+
* @returns The parsed manifest.
|
|
46
|
+
* @throws Error if the manifest cannot be fetched.
|
|
47
|
+
*/
|
|
48
|
+
export declare function fetchDesktopReleasesManifest(): Promise<DesktopReleasesManifest>;
|
|
49
|
+
/**
|
|
50
|
+
* Finds the newest `obsidian-<version>.asar` in a directory.
|
|
51
|
+
*
|
|
52
|
+
* @param dir - The directory to scan (e.g. the user's Obsidian config dir).
|
|
53
|
+
* @returns The newest discovered asar, or `undefined` if none / the dir is unreadable.
|
|
54
|
+
*/
|
|
55
|
+
export declare function findNewestAsar(dir: string): DiscoveredAsar | undefined;
|
|
56
|
+
/**
|
|
57
|
+
* Resolves a version specifier (explicit or channel alias) to a concrete
|
|
58
|
+
* `x.y.z` version, fetching the manifest only when a channel alias is used.
|
|
59
|
+
*
|
|
60
|
+
* @param spec - The version specifier.
|
|
61
|
+
* @returns The concrete version.
|
|
62
|
+
*/
|
|
63
|
+
export declare function resolveConcreteVersion(spec: string): Promise<string>;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import {
|
|
2
|
+
copyFileSync,
|
|
3
|
+
existsSync,
|
|
4
|
+
mkdirSync,
|
|
5
|
+
readdirSync,
|
|
6
|
+
writeFileSync
|
|
7
|
+
} from "node:fs";
|
|
8
|
+
import { tmpdir } from "node:os";
|
|
9
|
+
import { join } from "node:path";
|
|
10
|
+
import { gunzipSync } from "node:zlib";
|
|
11
|
+
import { log } from "./log.mjs";
|
|
12
|
+
import {
|
|
13
|
+
compareVersions,
|
|
14
|
+
DESKTOP_RELEASES_MANIFEST_URL,
|
|
15
|
+
getVersionAsarFileName,
|
|
16
|
+
parseVersionSpec,
|
|
17
|
+
resolveVersionFromManifest
|
|
18
|
+
} from "./obsidian-version.mjs";
|
|
19
|
+
const DOWNLOAD_USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.183 Safari/537.36";
|
|
20
|
+
const CACHE_ROOT = join(tmpdir(), "obsidian-integration-testing");
|
|
21
|
+
const ASAR_CACHE_DIR = join(CACHE_ROOT, "asar-cache");
|
|
22
|
+
const ASAR_FILE_PATTERN = /^obsidian-(?<version>\d+\.\d+\.\d+)\.asar$/;
|
|
23
|
+
function copyAsarIntoUserData(asarPath, version, userDataDir) {
|
|
24
|
+
mkdirSync(userDataDir, { recursive: true });
|
|
25
|
+
const dest = join(userDataDir, getVersionAsarFileName(version));
|
|
26
|
+
copyFileSync(asarPath, dest);
|
|
27
|
+
log(`[version-switch] Provisioned ${getVersionAsarFileName(version)} into ${userDataDir}.`);
|
|
28
|
+
}
|
|
29
|
+
async function ensureAsarCached(version) {
|
|
30
|
+
mkdirSync(ASAR_CACHE_DIR, { recursive: true });
|
|
31
|
+
const cachedPath = join(ASAR_CACHE_DIR, getVersionAsarFileName(version));
|
|
32
|
+
if (existsSync(cachedPath)) {
|
|
33
|
+
log(`[version-switch] Using cached asar for ${version}.`);
|
|
34
|
+
return cachedPath;
|
|
35
|
+
}
|
|
36
|
+
const url = `https://releases.obsidian.md/release/${getVersionAsarFileName(version)}.gz`;
|
|
37
|
+
log(`[version-switch] Downloading asar ${version} from ${url} ...`);
|
|
38
|
+
const response = await fetch(url, { headers: { "User-Agent": DOWNLOAD_USER_AGENT } });
|
|
39
|
+
if (!response.ok) {
|
|
40
|
+
throw new Error(`Failed to download Obsidian asar ${version}: HTTP ${String(response.status)} from ${url}`);
|
|
41
|
+
}
|
|
42
|
+
const gz = Buffer.from(await response.arrayBuffer());
|
|
43
|
+
writeFileSync(cachedPath, gunzipSync(gz));
|
|
44
|
+
log(`[version-switch] Cached asar ${version} (${String(gz.length)} bytes compressed) -> ${cachedPath}`);
|
|
45
|
+
return cachedPath;
|
|
46
|
+
}
|
|
47
|
+
async function fetchDesktopReleasesManifest() {
|
|
48
|
+
const response = await fetch(DESKTOP_RELEASES_MANIFEST_URL);
|
|
49
|
+
if (!response.ok) {
|
|
50
|
+
throw new Error(`Failed to fetch desktop releases manifest: HTTP ${String(response.status)}`);
|
|
51
|
+
}
|
|
52
|
+
return await response.json();
|
|
53
|
+
}
|
|
54
|
+
function findNewestAsar(dir) {
|
|
55
|
+
let entries;
|
|
56
|
+
try {
|
|
57
|
+
entries = readdirSync(dir);
|
|
58
|
+
} catch {
|
|
59
|
+
return void 0;
|
|
60
|
+
}
|
|
61
|
+
let newest;
|
|
62
|
+
for (const entry of entries) {
|
|
63
|
+
const match = ASAR_FILE_PATTERN.exec(entry);
|
|
64
|
+
if (!match) {
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
const version = match.groups?.["version"] ?? "";
|
|
68
|
+
if (!newest || compareVersions(version, newest.version) > 0) {
|
|
69
|
+
newest = { path: join(dir, entry), version };
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return newest;
|
|
73
|
+
}
|
|
74
|
+
async function resolveConcreteVersion(spec) {
|
|
75
|
+
const parsed = parseVersionSpec(spec);
|
|
76
|
+
if (parsed.kind === "explicit") {
|
|
77
|
+
return parsed.version;
|
|
78
|
+
}
|
|
79
|
+
const manifest = await fetchDesktopReleasesManifest();
|
|
80
|
+
return resolveVersionFromManifest(manifest, parsed.channel);
|
|
81
|
+
}
|
|
82
|
+
export {
|
|
83
|
+
copyAsarIntoUserData,
|
|
84
|
+
ensureAsarCached,
|
|
85
|
+
fetchDesktopReleasesManifest,
|
|
86
|
+
findNewestAsar,
|
|
87
|
+
resolveConcreteVersion
|
|
88
|
+
};
|
|
89
|
+
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vc3JjL29ic2lkaWFuLXZlcnNpb24tc3dpdGNoLnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyIvKipcbiAqIEBmaWxlXG4gKlxuICogSW50ZWdyYXRpb24tdGltZSBoZWxwZXJzIGZvciBwcm92aXNpb25pbmcgYSBzcGVjaWZpYyBPYnNpZGlhbiAqKmFzYXIqKiAodGhlXG4gKiBhcHAgY29kZSkgaW50byBhbiBpc29sYXRlZCB1c2VyLWRhdGEgZGlyLlxuICpcbiAqIE9ic2lkaWFuJ3MgYm9vdHN0cmFwIGxvYWRzIHRoZSBoaWdoZXN0IG9mIChpdHMgc2hlbGwncyBidW5kbGVkXG4gKiBgcmVzb3VyY2VzL29ic2lkaWFuLmFzYXJgLCB0aGUgYG9ic2lkaWFuLTx2ZXJzaW9uPi5hc2FyYCBmaWxlcyBpbiB0aGVcbiAqIHVzZXItZGF0YSBkaXIpLiBTbyBwbGFjaW5nIGFuIGFzYXIgaGVyZSBvbmx5IHRha2VzIGVmZmVjdCB3aGVuIGl0cyB2ZXJzaW9uIGlzXG4gKiAqKj49IHRoZSBzaGVsbCdzIGJ1bmRsZWQgdmVyc2lvbioqICh1cGdyYWRlLW9ubHkgXHUyMDE0IGNvbmZpcm1lZCBieSB0aGUgUGhhc2UgMFxuICogc3Bpa2UpLiBSdW5uaW5nIGFuIG9sZGVyIHZlcnNpb24gcmVxdWlyZXMgcGlubmluZyB0aGUgaW5zdGFsbGVyL3NoZWxsIGluc3RlYWRcbiAqIChzZWUgYG9ic2lkaWFuLWluc3RhbGxlci50c2ApLlxuICovXG5cbi8qIHY4IGlnbm9yZSBzdGFydCAtLSBJbnRlZ3JhdGlvbi10aW1lIGRvd25sb2FkL2ZpbGVzeXN0ZW0gZ2x1ZSBjb3ZlcmVkIGJ5IGludGVncmF0aW9uIHRlc3RzLCBub3QgdW5pdCB0ZXN0cy4gKi9cblxuaW1wb3J0IHtcbiAgY29weUZpbGVTeW5jLFxuICBleGlzdHNTeW5jLFxuICBta2RpclN5bmMsXG4gIHJlYWRkaXJTeW5jLFxuICB3cml0ZUZpbGVTeW5jXG59IGZyb20gJ25vZGU6ZnMnO1xuaW1wb3J0IHsgdG1wZGlyIH0gZnJvbSAnbm9kZTpvcyc7XG5pbXBvcnQgeyBqb2luIH0gZnJvbSAnbm9kZTpwYXRoJztcbmltcG9ydCB7IGd1bnppcFN5bmMgfSBmcm9tICdub2RlOnpsaWInO1xuXG5pbXBvcnQgdHlwZSB7IERlc2t0b3BSZWxlYXNlc01hbmlmZXN0IH0gZnJvbSAnLi9vYnNpZGlhbi12ZXJzaW9uLm1qcyc7XG5cbmltcG9ydCB7IGxvZyB9IGZyb20gJy4vbG9nLm1qcyc7XG5pbXBvcnQge1xuICBjb21wYXJlVmVyc2lvbnMsXG4gIERFU0tUT1BfUkVMRUFTRVNfTUFOSUZFU1RfVVJMLFxuICBnZXRWZXJzaW9uQXNhckZpbGVOYW1lLFxuICBwYXJzZVZlcnNpb25TcGVjLFxuICByZXNvbHZlVmVyc2lvbkZyb21NYW5pZmVzdFxufSBmcm9tICcuL29ic2lkaWFuLXZlcnNpb24ubWpzJztcblxuLyoqXG4gKiBCcm93c2VyIFVzZXItQWdlbnQgcmVxdWlyZWQgdG8gZmV0Y2ggYXNhciBwYWNrYWdlcyBmcm9tXG4gKiBgcmVsZWFzZXMub2JzaWRpYW4ubWRgICh0aGUgZW5kcG9pbnQgaXMgQ2xvdWRmbGFyZS1nYXRlZCBhZ2FpbnN0IG5vbi1icm93c2VyXG4gKiBjbGllbnRzKS4gTWF0Y2hlcyB0aGUgVUEgZG9jdW1lbnRlZCBpbiB0aGUgb2JzaWRpYW4tdmVyc2lvbnMgcmVwby5cbiAqL1xuY29uc3QgRE9XTkxPQURfVVNFUl9BR0VOVCA9ICdNb3ppbGxhLzUuMCAoV2luZG93cyBOVCAxMC4wOyBXaW42NDsgeDY0KSBBcHBsZVdlYktpdC81MzcuMzYgKEtIVE1MLCBsaWtlIEdlY2tvKSBDaHJvbWUvODYuMC40MjQwLjE4MyBTYWZhcmkvNTM3LjM2JztcblxuY29uc3QgQ0FDSEVfUk9PVCA9IGpvaW4odG1wZGlyKCksICdvYnNpZGlhbi1pbnRlZ3JhdGlvbi10ZXN0aW5nJyk7XG5jb25zdCBBU0FSX0NBQ0hFX0RJUiA9IGpvaW4oQ0FDSEVfUk9PVCwgJ2FzYXItY2FjaGUnKTtcbmNvbnN0IEFTQVJfRklMRV9QQVRURVJOID0gL15vYnNpZGlhbi0oPzx2ZXJzaW9uPlxcZCtcXC5cXGQrXFwuXFxkKylcXC5hc2FyJC87XG5cbi8qKlxuICogQSBkaXNjb3ZlcmVkIGBvYnNpZGlhbi08dmVyc2lvbj4uYXNhcmAgZmlsZS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBEaXNjb3ZlcmVkQXNhciB7XG4gIC8qKiBBYnNvbHV0ZSBwYXRoIHRvIHRoZSBhc2FyIGZpbGUuICovXG4gIHJlYWRvbmx5IHBhdGg6IHN0cmluZztcblxuICAvKiogVGhlIGB4LnkuemAgdmVyc2lvbiBwYXJzZWQgZnJvbSB0aGUgZmlsZSBuYW1lLiAqL1xuICByZWFkb25seSB2ZXJzaW9uOiBzdHJpbmc7XG59XG5cbi8qKlxuICogQ29waWVzIGFuIGFzYXIgZmlsZSBpbnRvIGEgdXNlci1kYXRhIGRpciB1bmRlciBpdHMgY2Fub25pY2FsXG4gKiBgb2JzaWRpYW4tPHZlcnNpb24+LmFzYXJgIG5hbWUuXG4gKlxuICogQHBhcmFtIGFzYXJQYXRoIC0gU291cmNlIGFzYXIgcGF0aC5cbiAqIEBwYXJhbSB2ZXJzaW9uIC0gVGhlIGFzYXIncyB2ZXJzaW9uICh1c2VkIGZvciB0aGUgZGVzdGluYXRpb24gZmlsZSBuYW1lKS5cbiAqIEBwYXJhbSB1c2VyRGF0YURpciAtIERlc3RpbmF0aW9uIHVzZXItZGF0YSBkaXIuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjb3B5QXNhckludG9Vc2VyRGF0YShhc2FyUGF0aDogc3RyaW5nLCB2ZXJzaW9uOiBzdHJpbmcsIHVzZXJEYXRhRGlyOiBzdHJpbmcpOiB2b2lkIHtcbiAgbWtkaXJTeW5jKHVzZXJEYXRhRGlyLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcbiAgY29uc3QgZGVzdCA9IGpvaW4odXNlckRhdGFEaXIsIGdldFZlcnNpb25Bc2FyRmlsZU5hbWUodmVyc2lvbikpO1xuICBjb3B5RmlsZVN5bmMoYXNhclBhdGgsIGRlc3QpO1xuICBsb2coYFt2ZXJzaW9uLXN3aXRjaF0gUHJvdmlzaW9uZWQgJHtnZXRWZXJzaW9uQXNhckZpbGVOYW1lKHZlcnNpb24pfSBpbnRvICR7dXNlckRhdGFEaXJ9LmApO1xufVxuXG4vKipcbiAqIEVuc3VyZXMgdGhlIGFzYXIgZm9yIGEgY29uY3JldGUgdmVyc2lvbiBpcyBwcmVzZW50IGluIHRoZSBsb2NhbCBjYWNoZSxcbiAqIGRvd25sb2FkaW5nIGFuZCBkZWNvbXByZXNzaW5nIGl0IGlmIG5lY2Vzc2FyeS5cbiAqXG4gKiBAcGFyYW0gdmVyc2lvbiAtIEEgY29uY3JldGUgYHgueS56YCB2ZXJzaW9uLlxuICogQHJldHVybnMgVGhlIGFic29sdXRlIHBhdGggdG8gdGhlIGNhY2hlZCBhc2FyLlxuICogQHRocm93cyBFcnJvciBpZiB0aGUgZG93bmxvYWQgZmFpbHMuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBlbnN1cmVBc2FyQ2FjaGVkKHZlcnNpb246IHN0cmluZyk6IFByb21pc2U8c3RyaW5nPiB7XG4gIG1rZGlyU3luYyhBU0FSX0NBQ0hFX0RJUiwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gIGNvbnN0IGNhY2hlZFBhdGggPSBqb2luKEFTQVJfQ0FDSEVfRElSLCBnZXRWZXJzaW9uQXNhckZpbGVOYW1lKHZlcnNpb24pKTtcbiAgaWYgKGV4aXN0c1N5bmMoY2FjaGVkUGF0aCkpIHtcbiAgICBsb2coYFt2ZXJzaW9uLXN3aXRjaF0gVXNpbmcgY2FjaGVkIGFzYXIgZm9yICR7dmVyc2lvbn0uYCk7XG4gICAgcmV0dXJuIGNhY2hlZFBhdGg7XG4gIH1cblxuICBjb25zdCB1cmwgPSBgaHR0cHM6Ly9yZWxlYXNlcy5vYnNpZGlhbi5tZC9yZWxlYXNlLyR7Z2V0VmVyc2lvbkFzYXJGaWxlTmFtZSh2ZXJzaW9uKX0uZ3pgO1xuICBsb2coYFt2ZXJzaW9uLXN3aXRjaF0gRG93bmxvYWRpbmcgYXNhciAke3ZlcnNpb259IGZyb20gJHt1cmx9IC4uLmApO1xuICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGZldGNoKHVybCwgeyBoZWFkZXJzOiB7ICdVc2VyLUFnZW50JzogRE9XTkxPQURfVVNFUl9BR0VOVCB9IH0pO1xuICBpZiAoIXJlc3BvbnNlLm9rKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBGYWlsZWQgdG8gZG93bmxvYWQgT2JzaWRpYW4gYXNhciAke3ZlcnNpb259OiBIVFRQICR7U3RyaW5nKHJlc3BvbnNlLnN0YXR1cyl9IGZyb20gJHt1cmx9YCk7XG4gIH1cblxuICBjb25zdCBneiA9IEJ1ZmZlci5mcm9tKGF3YWl0IHJlc3BvbnNlLmFycmF5QnVmZmVyKCkpO1xuICB3cml0ZUZpbGVTeW5jKGNhY2hlZFBhdGgsIGd1bnppcFN5bmMoZ3opKTtcbiAgbG9nKGBbdmVyc2lvbi1zd2l0Y2hdIENhY2hlZCBhc2FyICR7dmVyc2lvbn0gKCR7U3RyaW5nKGd6Lmxlbmd0aCl9IGJ5dGVzIGNvbXByZXNzZWQpIC0+ICR7Y2FjaGVkUGF0aH1gKTtcbiAgcmV0dXJuIGNhY2hlZFBhdGg7XG59XG5cbi8qKlxuICogRmV0Y2hlcyBhbmQgcGFyc2VzIE9ic2lkaWFuJ3MgZGVza3RvcCByZWxlYXNlcyBtYW5pZmVzdC5cbiAqXG4gKiBAcmV0dXJucyBUaGUgcGFyc2VkIG1hbmlmZXN0LlxuICogQHRocm93cyBFcnJvciBpZiB0aGUgbWFuaWZlc3QgY2Fubm90IGJlIGZldGNoZWQuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBmZXRjaERlc2t0b3BSZWxlYXNlc01hbmlmZXN0KCk6IFByb21pc2U8RGVza3RvcFJlbGVhc2VzTWFuaWZlc3Q+IHtcbiAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaChERVNLVE9QX1JFTEVBU0VTX01BTklGRVNUX1VSTCk7XG4gIGlmICghcmVzcG9uc2Uub2spIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYEZhaWxlZCB0byBmZXRjaCBkZXNrdG9wIHJlbGVhc2VzIG1hbmlmZXN0OiBIVFRQICR7U3RyaW5nKHJlc3BvbnNlLnN0YXR1cyl9YCk7XG4gIH1cbiAgcmV0dXJuIGF3YWl0IHJlc3BvbnNlLmpzb24oKSBhcyBEZXNrdG9wUmVsZWFzZXNNYW5pZmVzdDtcbn1cblxuLyoqXG4gKiBGaW5kcyB0aGUgbmV3ZXN0IGBvYnNpZGlhbi08dmVyc2lvbj4uYXNhcmAgaW4gYSBkaXJlY3RvcnkuXG4gKlxuICogQHBhcmFtIGRpciAtIFRoZSBkaXJlY3RvcnkgdG8gc2NhbiAoZS5nLiB0aGUgdXNlcidzIE9ic2lkaWFuIGNvbmZpZyBkaXIpLlxuICogQHJldHVybnMgVGhlIG5ld2VzdCBkaXNjb3ZlcmVkIGFzYXIsIG9yIGB1bmRlZmluZWRgIGlmIG5vbmUgLyB0aGUgZGlyIGlzIHVucmVhZGFibGUuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmaW5kTmV3ZXN0QXNhcihkaXI6IHN0cmluZyk6IERpc2NvdmVyZWRBc2FyIHwgdW5kZWZpbmVkIHtcbiAgbGV0IGVudHJpZXM6IHN0cmluZ1tdO1xuICB0cnkge1xuICAgIGVudHJpZXMgPSByZWFkZGlyU3luYyhkaXIpO1xuICB9IGNhdGNoIHtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG5cbiAgbGV0IG5ld2VzdDogRGlzY292ZXJlZEFzYXIgfCB1bmRlZmluZWQ7XG4gIGZvciAoY29uc3QgZW50cnkgb2YgZW50cmllcykge1xuICAgIGNvbnN0IG1hdGNoID0gQVNBUl9GSUxFX1BBVFRFUk4uZXhlYyhlbnRyeSk7XG4gICAgaWYgKCFtYXRjaCkge1xuICAgICAgY29udGludWU7XG4gICAgfVxuICAgIGNvbnN0IHZlcnNpb24gPSBtYXRjaC5ncm91cHM/LlsndmVyc2lvbiddID8/ICcnO1xuICAgIGlmICghbmV3ZXN0IHx8IGNvbXBhcmVWZXJzaW9ucyh2ZXJzaW9uLCBuZXdlc3QudmVyc2lvbikgPiAwKSB7XG4gICAgICBuZXdlc3QgPSB7IHBhdGg6IGpvaW4oZGlyLCBlbnRyeSksIHZlcnNpb24gfTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIG5ld2VzdDtcbn1cblxuLyoqXG4gKiBSZXNvbHZlcyBhIHZlcnNpb24gc3BlY2lmaWVyIChleHBsaWNpdCBvciBjaGFubmVsIGFsaWFzKSB0byBhIGNvbmNyZXRlXG4gKiBgeC55LnpgIHZlcnNpb24sIGZldGNoaW5nIHRoZSBtYW5pZmVzdCBvbmx5IHdoZW4gYSBjaGFubmVsIGFsaWFzIGlzIHVzZWQuXG4gKlxuICogQHBhcmFtIHNwZWMgLSBUaGUgdmVyc2lvbiBzcGVjaWZpZXIuXG4gKiBAcmV0dXJucyBUaGUgY29uY3JldGUgdmVyc2lvbi5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJlc29sdmVDb25jcmV0ZVZlcnNpb24oc3BlYzogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgY29uc3QgcGFyc2VkID0gcGFyc2VWZXJzaW9uU3BlYyhzcGVjKTtcbiAgaWYgKHBhcnNlZC5raW5kID09PSAnZXhwbGljaXQnKSB7XG4gICAgcmV0dXJuIHBhcnNlZC52ZXJzaW9uO1xuICB9XG4gIGNvbnN0IG1hbmlmZXN0ID0gYXdhaXQgZmV0Y2hEZXNrdG9wUmVsZWFzZXNNYW5pZmVzdCgpO1xuICByZXR1cm4gcmVzb2x2ZVZlcnNpb25Gcm9tTWFuaWZlc3QobWFuaWZlc3QsIHBhcnNlZC5jaGFubmVsKTtcbn1cblxuLyogdjggaWdub3JlIHN0b3AgKi9cbiJdLAogICJtYXBwaW5ncyI6ICJBQWdCQTtBQUFBLEVBQ0U7QUFBQSxFQUNBO0FBQUEsRUFDQTtBQUFBLEVBQ0E7QUFBQSxFQUNBO0FBQUEsT0FDSztBQUNQLFNBQVMsY0FBYztBQUN2QixTQUFTLFlBQVk7QUFDckIsU0FBUyxrQkFBa0I7QUFJM0IsU0FBUyxXQUFXO0FBQ3BCO0FBQUEsRUFDRTtBQUFBLEVBQ0E7QUFBQSxFQUNBO0FBQUEsRUFDQTtBQUFBLEVBQ0E7QUFBQSxPQUNLO0FBT1AsTUFBTSxzQkFBc0I7QUFFNUIsTUFBTSxhQUFhLEtBQUssT0FBTyxHQUFHLDhCQUE4QjtBQUNoRSxNQUFNLGlCQUFpQixLQUFLLFlBQVksWUFBWTtBQUNwRCxNQUFNLG9CQUFvQjtBQXFCbkIsU0FBUyxxQkFBcUIsVUFBa0IsU0FBaUIsYUFBMkI7QUFDakcsWUFBVSxhQUFhLEVBQUUsV0FBVyxLQUFLLENBQUM7QUFDMUMsUUFBTSxPQUFPLEtBQUssYUFBYSx1QkFBdUIsT0FBTyxDQUFDO0FBQzlELGVBQWEsVUFBVSxJQUFJO0FBQzNCLE1BQUksZ0NBQWdDLHVCQUF1QixPQUFPLENBQUMsU0FBUyxXQUFXLEdBQUc7QUFDNUY7QUFVQSxlQUFzQixpQkFBaUIsU0FBa0M7QUFDdkUsWUFBVSxnQkFBZ0IsRUFBRSxXQUFXLEtBQUssQ0FBQztBQUM3QyxRQUFNLGFBQWEsS0FBSyxnQkFBZ0IsdUJBQXVCLE9BQU8sQ0FBQztBQUN2RSxNQUFJLFdBQVcsVUFBVSxHQUFHO0FBQzFCLFFBQUksMENBQTBDLE9BQU8sR0FBRztBQUN4RCxXQUFPO0FBQUEsRUFDVDtBQUVBLFFBQU0sTUFBTSx3Q0FBd0MsdUJBQXVCLE9BQU8sQ0FBQztBQUNuRixNQUFJLHFDQUFxQyxPQUFPLFNBQVMsR0FBRyxNQUFNO0FBQ2xFLFFBQU0sV0FBVyxNQUFNLE1BQU0sS0FBSyxFQUFFLFNBQVMsRUFBRSxjQUFjLG9CQUFvQixFQUFFLENBQUM7QUFDcEYsTUFBSSxDQUFDLFNBQVMsSUFBSTtBQUNoQixVQUFNLElBQUksTUFBTSxvQ0FBb0MsT0FBTyxVQUFVLE9BQU8sU0FBUyxNQUFNLENBQUMsU0FBUyxHQUFHLEVBQUU7QUFBQSxFQUM1RztBQUVBLFFBQU0sS0FBSyxPQUFPLEtBQUssTUFBTSxTQUFTLFlBQVksQ0FBQztBQUNuRCxnQkFBYyxZQUFZLFdBQVcsRUFBRSxDQUFDO0FBQ3hDLE1BQUksZ0NBQWdDLE9BQU8sS0FBSyxPQUFPLEdBQUcsTUFBTSxDQUFDLHlCQUF5QixVQUFVLEVBQUU7QUFDdEcsU0FBTztBQUNUO0FBUUEsZUFBc0IsK0JBQWlFO0FBQ3JGLFFBQU0sV0FBVyxNQUFNLE1BQU0sNkJBQTZCO0FBQzFELE1BQUksQ0FBQyxTQUFTLElBQUk7QUFDaEIsVUFBTSxJQUFJLE1BQU0sbURBQW1ELE9BQU8sU0FBUyxNQUFNLENBQUMsRUFBRTtBQUFBLEVBQzlGO0FBQ0EsU0FBTyxNQUFNLFNBQVMsS0FBSztBQUM3QjtBQVFPLFNBQVMsZUFBZSxLQUF5QztBQUN0RSxNQUFJO0FBQ0osTUFBSTtBQUNGLGNBQVUsWUFBWSxHQUFHO0FBQUEsRUFDM0IsUUFBUTtBQUNOLFdBQU87QUFBQSxFQUNUO0FBRUEsTUFBSTtBQUNKLGFBQVcsU0FBUyxTQUFTO0FBQzNCLFVBQU0sUUFBUSxrQkFBa0IsS0FBSyxLQUFLO0FBQzFDLFFBQUksQ0FBQyxPQUFPO0FBQ1Y7QUFBQSxJQUNGO0FBQ0EsVUFBTSxVQUFVLE1BQU0sU0FBUyxTQUFTLEtBQUs7QUFDN0MsUUFBSSxDQUFDLFVBQVUsZ0JBQWdCLFNBQVMsT0FBTyxPQUFPLElBQUksR0FBRztBQUMzRCxlQUFTLEVBQUUsTUFBTSxLQUFLLEtBQUssS0FBSyxHQUFHLFFBQVE7QUFBQSxJQUM3QztBQUFBLEVBQ0Y7QUFDQSxTQUFPO0FBQ1Q7QUFTQSxlQUFzQix1QkFBdUIsTUFBK0I7QUFDMUUsUUFBTSxTQUFTLGlCQUFpQixJQUFJO0FBQ3BDLE1BQUksT0FBTyxTQUFTLFlBQVk7QUFDOUIsV0FBTyxPQUFPO0FBQUEsRUFDaEI7QUFDQSxRQUFNLFdBQVcsTUFBTSw2QkFBNkI7QUFDcEQsU0FBTywyQkFBMkIsVUFBVSxPQUFPLE9BQU87QUFDNUQ7IiwKICAibmFtZXMiOiBbXQp9Cg==
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file
|
|
3
|
+
*
|
|
4
|
+
* Pure helpers for resolving Obsidian desktop version specifiers.
|
|
5
|
+
*
|
|
6
|
+
* A version specifier is either an explicit `x.y.z` string or one of the
|
|
7
|
+
* channel aliases {@link PUBLIC_LATEST} / {@link CATALYST_LATEST}, which resolve
|
|
8
|
+
* against Obsidian's published desktop releases manifest.
|
|
9
|
+
*
|
|
10
|
+
* The network call that fetches the manifest lives in the integration-time
|
|
11
|
+
* version-switch module; everything here is pure and unit-tested.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Version specifier alias resolving to the latest **public** desktop release
|
|
15
|
+
* (the manifest's `latestVersion`).
|
|
16
|
+
*/
|
|
17
|
+
export declare const PUBLIC_LATEST = "public-latest";
|
|
18
|
+
/**
|
|
19
|
+
* Version specifier alias resolving to the latest **catalyst** (early access /
|
|
20
|
+
* insider) desktop release (the manifest's `beta.latestVersion`).
|
|
21
|
+
*/
|
|
22
|
+
export declare const CATALYST_LATEST = "catalyst-latest";
|
|
23
|
+
/**
|
|
24
|
+
* URL of Obsidian's desktop releases manifest (raw JSON).
|
|
25
|
+
*/
|
|
26
|
+
export declare const DESKTOP_RELEASES_MANIFEST_URL = "https://raw.githubusercontent.com/obsidianmd/obsidian-releases/master/desktop-releases.json";
|
|
27
|
+
/**
|
|
28
|
+
* A version specifier resolved against a release channel.
|
|
29
|
+
*/
|
|
30
|
+
export interface ChannelVersionSpec {
|
|
31
|
+
/** The channel to resolve against the manifest. */
|
|
32
|
+
readonly channel: ReleaseChannel;
|
|
33
|
+
/** Discriminant. */
|
|
34
|
+
readonly kind: 'channel';
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* The `beta` (catalyst) entry of {@link DesktopReleasesManifest}.
|
|
38
|
+
*/
|
|
39
|
+
export interface DesktopReleasesBeta {
|
|
40
|
+
/** The latest catalyst version, e.g. `'1.13.1'`. */
|
|
41
|
+
readonly latestVersion: string;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* The subset of Obsidian's `desktop-releases.json` this library reads.
|
|
45
|
+
*/
|
|
46
|
+
export interface DesktopReleasesManifest {
|
|
47
|
+
/**
|
|
48
|
+
* The latest catalyst (early access / insider) release, when present.
|
|
49
|
+
*/
|
|
50
|
+
readonly beta?: DesktopReleasesBeta;
|
|
51
|
+
/**
|
|
52
|
+
* The latest public (stable) version, e.g. `'1.12.7'`.
|
|
53
|
+
*/
|
|
54
|
+
readonly latestVersion: string;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* A version specifier naming a concrete `x.y.z` version.
|
|
58
|
+
*/
|
|
59
|
+
export interface ExplicitVersionSpec {
|
|
60
|
+
/** Discriminant. */
|
|
61
|
+
readonly kind: 'explicit';
|
|
62
|
+
/** The concrete `x.y.z` version. */
|
|
63
|
+
readonly version: string;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* A release channel resolved from a channel-alias specifier.
|
|
67
|
+
*
|
|
68
|
+
* - `public` — the latest stable release.
|
|
69
|
+
* - `catalyst` — the latest early access / insider release.
|
|
70
|
+
*/
|
|
71
|
+
export type ReleaseChannel = 'catalyst' | 'public';
|
|
72
|
+
/**
|
|
73
|
+
* The parsed form of a version specifier.
|
|
74
|
+
*
|
|
75
|
+
* - `explicit` — a concrete `x.y.z` version.
|
|
76
|
+
* - `channel` — a channel alias to be resolved against the manifest.
|
|
77
|
+
*/
|
|
78
|
+
export type VersionSpec = ChannelVersionSpec | ExplicitVersionSpec;
|
|
79
|
+
/**
|
|
80
|
+
* Compares two `x.y.z` version strings numerically, segment by segment.
|
|
81
|
+
*
|
|
82
|
+
* @param a - The first version.
|
|
83
|
+
* @param b - The second version.
|
|
84
|
+
* @returns A negative number if `a < b`, `0` if equal, a positive number if `a > b`.
|
|
85
|
+
*/
|
|
86
|
+
export declare function compareVersions(a: string, b: string): number;
|
|
87
|
+
/**
|
|
88
|
+
* Returns the user-data asar file name for a given version, matching the name
|
|
89
|
+
* Obsidian itself uses when it downloads an update (`obsidian-<version>.asar`).
|
|
90
|
+
*
|
|
91
|
+
* @param version - A concrete `x.y.z` version.
|
|
92
|
+
* @returns The asar file name.
|
|
93
|
+
*/
|
|
94
|
+
export declare function getVersionAsarFileName(version: string): string;
|
|
95
|
+
/**
|
|
96
|
+
* Parses a version specifier into either an explicit version or a channel alias.
|
|
97
|
+
*
|
|
98
|
+
* @param spec - The specifier: an `x.y.z` string, {@link PUBLIC_LATEST}, or {@link CATALYST_LATEST}.
|
|
99
|
+
* @returns The parsed {@link VersionSpec}.
|
|
100
|
+
* @throws Error if the specifier is neither a valid `x.y.z` version nor a known alias.
|
|
101
|
+
*/
|
|
102
|
+
export declare function parseVersionSpec(spec: string): VersionSpec;
|
|
103
|
+
/**
|
|
104
|
+
* Resolves a channel to a concrete version using a desktop releases manifest.
|
|
105
|
+
*
|
|
106
|
+
* @param manifest - The parsed manifest.
|
|
107
|
+
* @param channel - The channel to resolve.
|
|
108
|
+
* @returns The concrete `x.y.z` version for the channel.
|
|
109
|
+
* @throws Error if the catalyst channel is requested but the manifest has no `beta` entry.
|
|
110
|
+
*/
|
|
111
|
+
export declare function resolveVersionFromManifest(manifest: DesktopReleasesManifest, channel: ReleaseChannel): string;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
const PUBLIC_LATEST = "public-latest";
|
|
2
|
+
const CATALYST_LATEST = "catalyst-latest";
|
|
3
|
+
const DESKTOP_RELEASES_MANIFEST_URL = "https://raw.githubusercontent.com/obsidianmd/obsidian-releases/master/desktop-releases.json";
|
|
4
|
+
const EXPLICIT_VERSION_PATTERN = /^\d+\.\d+\.\d+$/;
|
|
5
|
+
const VERSION_SEGMENT_COUNT = 3;
|
|
6
|
+
function compareVersions(a, b) {
|
|
7
|
+
const aSegments = parseVersionSegments(a);
|
|
8
|
+
const bSegments = parseVersionSegments(b);
|
|
9
|
+
for (let i = 0; i < VERSION_SEGMENT_COUNT; i++) {
|
|
10
|
+
const diff = (aSegments[i] ?? 0) - (bSegments[i] ?? 0);
|
|
11
|
+
if (diff !== 0) {
|
|
12
|
+
return diff;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return 0;
|
|
16
|
+
}
|
|
17
|
+
function getVersionAsarFileName(version) {
|
|
18
|
+
return `obsidian-${version}.asar`;
|
|
19
|
+
}
|
|
20
|
+
function parseVersionSpec(spec) {
|
|
21
|
+
if (spec === PUBLIC_LATEST) {
|
|
22
|
+
return { channel: "public", kind: "channel" };
|
|
23
|
+
}
|
|
24
|
+
if (spec === CATALYST_LATEST) {
|
|
25
|
+
return { channel: "catalyst", kind: "channel" };
|
|
26
|
+
}
|
|
27
|
+
if (EXPLICIT_VERSION_PATTERN.test(spec)) {
|
|
28
|
+
return { kind: "explicit", version: spec };
|
|
29
|
+
}
|
|
30
|
+
throw new Error(
|
|
31
|
+
`Invalid Obsidian version "${spec}". Expected an "x.y.z" version, "${PUBLIC_LATEST}", or "${CATALYST_LATEST}".`
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
function resolveVersionFromManifest(manifest, channel) {
|
|
35
|
+
if (channel === "public") {
|
|
36
|
+
return manifest.latestVersion;
|
|
37
|
+
}
|
|
38
|
+
if (!manifest.beta) {
|
|
39
|
+
throw new Error("Desktop releases manifest has no catalyst (beta) release.");
|
|
40
|
+
}
|
|
41
|
+
return manifest.beta.latestVersion;
|
|
42
|
+
}
|
|
43
|
+
function parseVersionSegments(version) {
|
|
44
|
+
return version.split(".").map((segment) => Number.parseInt(segment, 10));
|
|
45
|
+
}
|
|
46
|
+
export {
|
|
47
|
+
CATALYST_LATEST,
|
|
48
|
+
DESKTOP_RELEASES_MANIFEST_URL,
|
|
49
|
+
PUBLIC_LATEST,
|
|
50
|
+
compareVersions,
|
|
51
|
+
getVersionAsarFileName,
|
|
52
|
+
parseVersionSpec,
|
|
53
|
+
resolveVersionFromManifest
|
|
54
|
+
};
|
|
55
|
+
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vc3JjL29ic2lkaWFuLXZlcnNpb24udHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbIi8qKlxuICogQGZpbGVcbiAqXG4gKiBQdXJlIGhlbHBlcnMgZm9yIHJlc29sdmluZyBPYnNpZGlhbiBkZXNrdG9wIHZlcnNpb24gc3BlY2lmaWVycy5cbiAqXG4gKiBBIHZlcnNpb24gc3BlY2lmaWVyIGlzIGVpdGhlciBhbiBleHBsaWNpdCBgeC55LnpgIHN0cmluZyBvciBvbmUgb2YgdGhlXG4gKiBjaGFubmVsIGFsaWFzZXMge0BsaW5rIFBVQkxJQ19MQVRFU1R9IC8ge0BsaW5rIENBVEFMWVNUX0xBVEVTVH0sIHdoaWNoIHJlc29sdmVcbiAqIGFnYWluc3QgT2JzaWRpYW4ncyBwdWJsaXNoZWQgZGVza3RvcCByZWxlYXNlcyBtYW5pZmVzdC5cbiAqXG4gKiBUaGUgbmV0d29yayBjYWxsIHRoYXQgZmV0Y2hlcyB0aGUgbWFuaWZlc3QgbGl2ZXMgaW4gdGhlIGludGVncmF0aW9uLXRpbWVcbiAqIHZlcnNpb24tc3dpdGNoIG1vZHVsZTsgZXZlcnl0aGluZyBoZXJlIGlzIHB1cmUgYW5kIHVuaXQtdGVzdGVkLlxuICovXG5cbi8qKlxuICogVmVyc2lvbiBzcGVjaWZpZXIgYWxpYXMgcmVzb2x2aW5nIHRvIHRoZSBsYXRlc3QgKipwdWJsaWMqKiBkZXNrdG9wIHJlbGVhc2VcbiAqICh0aGUgbWFuaWZlc3QncyBgbGF0ZXN0VmVyc2lvbmApLlxuICovXG5leHBvcnQgY29uc3QgUFVCTElDX0xBVEVTVCA9ICdwdWJsaWMtbGF0ZXN0JztcblxuLyoqXG4gKiBWZXJzaW9uIHNwZWNpZmllciBhbGlhcyByZXNvbHZpbmcgdG8gdGhlIGxhdGVzdCAqKmNhdGFseXN0KiogKGVhcmx5IGFjY2VzcyAvXG4gKiBpbnNpZGVyKSBkZXNrdG9wIHJlbGVhc2UgKHRoZSBtYW5pZmVzdCdzIGBiZXRhLmxhdGVzdFZlcnNpb25gKS5cbiAqL1xuZXhwb3J0IGNvbnN0IENBVEFMWVNUX0xBVEVTVCA9ICdjYXRhbHlzdC1sYXRlc3QnO1xuXG4vKipcbiAqIFVSTCBvZiBPYnNpZGlhbidzIGRlc2t0b3AgcmVsZWFzZXMgbWFuaWZlc3QgKHJhdyBKU09OKS5cbiAqL1xuZXhwb3J0IGNvbnN0IERFU0tUT1BfUkVMRUFTRVNfTUFOSUZFU1RfVVJMID0gJ2h0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9vYnNpZGlhbm1kL29ic2lkaWFuLXJlbGVhc2VzL21hc3Rlci9kZXNrdG9wLXJlbGVhc2VzLmpzb24nO1xuXG5jb25zdCBFWFBMSUNJVF9WRVJTSU9OX1BBVFRFUk4gPSAvXlxcZCtcXC5cXGQrXFwuXFxkKyQvO1xuY29uc3QgVkVSU0lPTl9TRUdNRU5UX0NPVU5UID0gMztcblxuLyoqXG4gKiBBIHZlcnNpb24gc3BlY2lmaWVyIHJlc29sdmVkIGFnYWluc3QgYSByZWxlYXNlIGNoYW5uZWwuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQ2hhbm5lbFZlcnNpb25TcGVjIHtcbiAgLyoqIFRoZSBjaGFubmVsIHRvIHJlc29sdmUgYWdhaW5zdCB0aGUgbWFuaWZlc3QuICovXG4gIHJlYWRvbmx5IGNoYW5uZWw6IFJlbGVhc2VDaGFubmVsO1xuXG4gIC8qKiBEaXNjcmltaW5hbnQuICovXG4gIHJlYWRvbmx5IGtpbmQ6ICdjaGFubmVsJztcbn1cblxuLyoqXG4gKiBUaGUgYGJldGFgIChjYXRhbHlzdCkgZW50cnkgb2Yge0BsaW5rIERlc2t0b3BSZWxlYXNlc01hbmlmZXN0fS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBEZXNrdG9wUmVsZWFzZXNCZXRhIHtcbiAgLyoqIFRoZSBsYXRlc3QgY2F0YWx5c3QgdmVyc2lvbiwgZS5nLiBgJzEuMTMuMSdgLiAqL1xuICByZWFkb25seSBsYXRlc3RWZXJzaW9uOiBzdHJpbmc7XG59XG5cbi8qKlxuICogVGhlIHN1YnNldCBvZiBPYnNpZGlhbidzIGBkZXNrdG9wLXJlbGVhc2VzLmpzb25gIHRoaXMgbGlicmFyeSByZWFkcy5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBEZXNrdG9wUmVsZWFzZXNNYW5pZmVzdCB7XG4gIC8qKlxuICAgKiBUaGUgbGF0ZXN0IGNhdGFseXN0IChlYXJseSBhY2Nlc3MgLyBpbnNpZGVyKSByZWxlYXNlLCB3aGVuIHByZXNlbnQuXG4gICAqL1xuICByZWFkb25seSBiZXRhPzogRGVza3RvcFJlbGVhc2VzQmV0YTtcblxuICAvKipcbiAgICogVGhlIGxhdGVzdCBwdWJsaWMgKHN0YWJsZSkgdmVyc2lvbiwgZS5nLiBgJzEuMTIuNydgLlxuICAgKi9cbiAgcmVhZG9ubHkgbGF0ZXN0VmVyc2lvbjogc3RyaW5nO1xufVxuXG4vKipcbiAqIEEgdmVyc2lvbiBzcGVjaWZpZXIgbmFtaW5nIGEgY29uY3JldGUgYHgueS56YCB2ZXJzaW9uLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIEV4cGxpY2l0VmVyc2lvblNwZWMge1xuICAvKiogRGlzY3JpbWluYW50LiAqL1xuICByZWFkb25seSBraW5kOiAnZXhwbGljaXQnO1xuXG4gIC8qKiBUaGUgY29uY3JldGUgYHgueS56YCB2ZXJzaW9uLiAqL1xuICByZWFkb25seSB2ZXJzaW9uOiBzdHJpbmc7XG59XG5cbi8qKlxuICogQSByZWxlYXNlIGNoYW5uZWwgcmVzb2x2ZWQgZnJvbSBhIGNoYW5uZWwtYWxpYXMgc3BlY2lmaWVyLlxuICpcbiAqIC0gYHB1YmxpY2AgXHUyMDE0IHRoZSBsYXRlc3Qgc3RhYmxlIHJlbGVhc2UuXG4gKiAtIGBjYXRhbHlzdGAgXHUyMDE0IHRoZSBsYXRlc3QgZWFybHkgYWNjZXNzIC8gaW5zaWRlciByZWxlYXNlLlxuICovXG5leHBvcnQgdHlwZSBSZWxlYXNlQ2hhbm5lbCA9ICdjYXRhbHlzdCcgfCAncHVibGljJztcblxuLyoqXG4gKiBUaGUgcGFyc2VkIGZvcm0gb2YgYSB2ZXJzaW9uIHNwZWNpZmllci5cbiAqXG4gKiAtIGBleHBsaWNpdGAgXHUyMDE0IGEgY29uY3JldGUgYHgueS56YCB2ZXJzaW9uLlxuICogLSBgY2hhbm5lbGAgXHUyMDE0IGEgY2hhbm5lbCBhbGlhcyB0byBiZSByZXNvbHZlZCBhZ2FpbnN0IHRoZSBtYW5pZmVzdC5cbiAqL1xuZXhwb3J0IHR5cGUgVmVyc2lvblNwZWMgPSBDaGFubmVsVmVyc2lvblNwZWMgfCBFeHBsaWNpdFZlcnNpb25TcGVjO1xuXG4vKipcbiAqIENvbXBhcmVzIHR3byBgeC55LnpgIHZlcnNpb24gc3RyaW5ncyBudW1lcmljYWxseSwgc2VnbWVudCBieSBzZWdtZW50LlxuICpcbiAqIEBwYXJhbSBhIC0gVGhlIGZpcnN0IHZlcnNpb24uXG4gKiBAcGFyYW0gYiAtIFRoZSBzZWNvbmQgdmVyc2lvbi5cbiAqIEByZXR1cm5zIEEgbmVnYXRpdmUgbnVtYmVyIGlmIGBhIDwgYmAsIGAwYCBpZiBlcXVhbCwgYSBwb3NpdGl2ZSBudW1iZXIgaWYgYGEgPiBiYC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNvbXBhcmVWZXJzaW9ucyhhOiBzdHJpbmcsIGI6IHN0cmluZyk6IG51bWJlciB7XG4gIGNvbnN0IGFTZWdtZW50cyA9IHBhcnNlVmVyc2lvblNlZ21lbnRzKGEpO1xuICBjb25zdCBiU2VnbWVudHMgPSBwYXJzZVZlcnNpb25TZWdtZW50cyhiKTtcblxuICBmb3IgKGxldCBpID0gMDsgaSA8IFZFUlNJT05fU0VHTUVOVF9DT1VOVDsgaSsrKSB7XG4gICAgY29uc3QgZGlmZiA9IChhU2VnbWVudHNbaV0gPz8gMCkgLSAoYlNlZ21lbnRzW2ldID8/IDApO1xuICAgIGlmIChkaWZmICE9PSAwKSB7XG4gICAgICByZXR1cm4gZGlmZjtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gMDtcbn1cblxuLyoqXG4gKiBSZXR1cm5zIHRoZSB1c2VyLWRhdGEgYXNhciBmaWxlIG5hbWUgZm9yIGEgZ2l2ZW4gdmVyc2lvbiwgbWF0Y2hpbmcgdGhlIG5hbWVcbiAqIE9ic2lkaWFuIGl0c2VsZiB1c2VzIHdoZW4gaXQgZG93bmxvYWRzIGFuIHVwZGF0ZSAoYG9ic2lkaWFuLTx2ZXJzaW9uPi5hc2FyYCkuXG4gKlxuICogQHBhcmFtIHZlcnNpb24gLSBBIGNvbmNyZXRlIGB4LnkuemAgdmVyc2lvbi5cbiAqIEByZXR1cm5zIFRoZSBhc2FyIGZpbGUgbmFtZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldFZlcnNpb25Bc2FyRmlsZU5hbWUodmVyc2lvbjogc3RyaW5nKTogc3RyaW5nIHtcbiAgcmV0dXJuIGBvYnNpZGlhbi0ke3ZlcnNpb259LmFzYXJgO1xufVxuXG4vKipcbiAqIFBhcnNlcyBhIHZlcnNpb24gc3BlY2lmaWVyIGludG8gZWl0aGVyIGFuIGV4cGxpY2l0IHZlcnNpb24gb3IgYSBjaGFubmVsIGFsaWFzLlxuICpcbiAqIEBwYXJhbSBzcGVjIC0gVGhlIHNwZWNpZmllcjogYW4gYHgueS56YCBzdHJpbmcsIHtAbGluayBQVUJMSUNfTEFURVNUfSwgb3Ige0BsaW5rIENBVEFMWVNUX0xBVEVTVH0uXG4gKiBAcmV0dXJucyBUaGUgcGFyc2VkIHtAbGluayBWZXJzaW9uU3BlY30uXG4gKiBAdGhyb3dzIEVycm9yIGlmIHRoZSBzcGVjaWZpZXIgaXMgbmVpdGhlciBhIHZhbGlkIGB4LnkuemAgdmVyc2lvbiBub3IgYSBrbm93biBhbGlhcy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlVmVyc2lvblNwZWMoc3BlYzogc3RyaW5nKTogVmVyc2lvblNwZWMge1xuICBpZiAoc3BlYyA9PT0gUFVCTElDX0xBVEVTVCkge1xuICAgIHJldHVybiB7IGNoYW5uZWw6ICdwdWJsaWMnLCBraW5kOiAnY2hhbm5lbCcgfTtcbiAgfVxuXG4gIGlmIChzcGVjID09PSBDQVRBTFlTVF9MQVRFU1QpIHtcbiAgICByZXR1cm4geyBjaGFubmVsOiAnY2F0YWx5c3QnLCBraW5kOiAnY2hhbm5lbCcgfTtcbiAgfVxuXG4gIGlmIChFWFBMSUNJVF9WRVJTSU9OX1BBVFRFUk4udGVzdChzcGVjKSkge1xuICAgIHJldHVybiB7IGtpbmQ6ICdleHBsaWNpdCcsIHZlcnNpb246IHNwZWMgfTtcbiAgfVxuXG4gIHRocm93IG5ldyBFcnJvcihcbiAgICBgSW52YWxpZCBPYnNpZGlhbiB2ZXJzaW9uIFwiJHtzcGVjfVwiLiBFeHBlY3RlZCBhbiBcIngueS56XCIgdmVyc2lvbiwgXCIke1BVQkxJQ19MQVRFU1R9XCIsIG9yIFwiJHtDQVRBTFlTVF9MQVRFU1R9XCIuYFxuICApO1xufVxuXG4vKipcbiAqIFJlc29sdmVzIGEgY2hhbm5lbCB0byBhIGNvbmNyZXRlIHZlcnNpb24gdXNpbmcgYSBkZXNrdG9wIHJlbGVhc2VzIG1hbmlmZXN0LlxuICpcbiAqIEBwYXJhbSBtYW5pZmVzdCAtIFRoZSBwYXJzZWQgbWFuaWZlc3QuXG4gKiBAcGFyYW0gY2hhbm5lbCAtIFRoZSBjaGFubmVsIHRvIHJlc29sdmUuXG4gKiBAcmV0dXJucyBUaGUgY29uY3JldGUgYHgueS56YCB2ZXJzaW9uIGZvciB0aGUgY2hhbm5lbC5cbiAqIEB0aHJvd3MgRXJyb3IgaWYgdGhlIGNhdGFseXN0IGNoYW5uZWwgaXMgcmVxdWVzdGVkIGJ1dCB0aGUgbWFuaWZlc3QgaGFzIG5vIGBiZXRhYCBlbnRyeS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlc29sdmVWZXJzaW9uRnJvbU1hbmlmZXN0KG1hbmlmZXN0OiBEZXNrdG9wUmVsZWFzZXNNYW5pZmVzdCwgY2hhbm5lbDogUmVsZWFzZUNoYW5uZWwpOiBzdHJpbmcge1xuICBpZiAoY2hhbm5lbCA9PT0gJ3B1YmxpYycpIHtcbiAgICByZXR1cm4gbWFuaWZlc3QubGF0ZXN0VmVyc2lvbjtcbiAgfVxuXG4gIGlmICghbWFuaWZlc3QuYmV0YSkge1xuICAgIHRocm93IG5ldyBFcnJvcignRGVza3RvcCByZWxlYXNlcyBtYW5pZmVzdCBoYXMgbm8gY2F0YWx5c3QgKGJldGEpIHJlbGVhc2UuJyk7XG4gIH1cblxuICByZXR1cm4gbWFuaWZlc3QuYmV0YS5sYXRlc3RWZXJzaW9uO1xufVxuXG4vKipcbiAqIFNwbGl0cyBhbiBgeC55LnpgIHZlcnNpb24gaW50byBpdHMgbnVtZXJpYyBzZWdtZW50cy5cbiAqXG4gKiBAcGFyYW0gdmVyc2lvbiAtIFRoZSB2ZXJzaW9uIHN0cmluZy5cbiAqIEByZXR1cm5zIFRoZSBudW1lcmljIHNlZ21lbnRzLlxuICovXG5mdW5jdGlvbiBwYXJzZVZlcnNpb25TZWdtZW50cyh2ZXJzaW9uOiBzdHJpbmcpOiBudW1iZXJbXSB7XG4gIHJldHVybiB2ZXJzaW9uLnNwbGl0KCcuJykubWFwKChzZWdtZW50KSA9PiBOdW1iZXIucGFyc2VJbnQoc2VnbWVudCwgMTApKTtcbn1cbiJdLAogICJtYXBwaW5ncyI6ICJBQWlCTyxNQUFNLGdCQUFnQjtBQU10QixNQUFNLGtCQUFrQjtBQUt4QixNQUFNLGdDQUFnQztBQUU3QyxNQUFNLDJCQUEyQjtBQUNqQyxNQUFNLHdCQUF3QjtBQXNFdkIsU0FBUyxnQkFBZ0IsR0FBVyxHQUFtQjtBQUM1RCxRQUFNLFlBQVkscUJBQXFCLENBQUM7QUFDeEMsUUFBTSxZQUFZLHFCQUFxQixDQUFDO0FBRXhDLFdBQVMsSUFBSSxHQUFHLElBQUksdUJBQXVCLEtBQUs7QUFDOUMsVUFBTSxRQUFRLFVBQVUsQ0FBQyxLQUFLLE1BQU0sVUFBVSxDQUFDLEtBQUs7QUFDcEQsUUFBSSxTQUFTLEdBQUc7QUFDZCxhQUFPO0FBQUEsSUFDVDtBQUFBLEVBQ0Y7QUFFQSxTQUFPO0FBQ1Q7QUFTTyxTQUFTLHVCQUF1QixTQUF5QjtBQUM5RCxTQUFPLFlBQVksT0FBTztBQUM1QjtBQVNPLFNBQVMsaUJBQWlCLE1BQTJCO0FBQzFELE1BQUksU0FBUyxlQUFlO0FBQzFCLFdBQU8sRUFBRSxTQUFTLFVBQVUsTUFBTSxVQUFVO0FBQUEsRUFDOUM7QUFFQSxNQUFJLFNBQVMsaUJBQWlCO0FBQzVCLFdBQU8sRUFBRSxTQUFTLFlBQVksTUFBTSxVQUFVO0FBQUEsRUFDaEQ7QUFFQSxNQUFJLHlCQUF5QixLQUFLLElBQUksR0FBRztBQUN2QyxXQUFPLEVBQUUsTUFBTSxZQUFZLFNBQVMsS0FBSztBQUFBLEVBQzNDO0FBRUEsUUFBTSxJQUFJO0FBQUEsSUFDUiw2QkFBNkIsSUFBSSxvQ0FBb0MsYUFBYSxVQUFVLGVBQWU7QUFBQSxFQUM3RztBQUNGO0FBVU8sU0FBUywyQkFBMkIsVUFBbUMsU0FBaUM7QUFDN0csTUFBSSxZQUFZLFVBQVU7QUFDeEIsV0FBTyxTQUFTO0FBQUEsRUFDbEI7QUFFQSxNQUFJLENBQUMsU0FBUyxNQUFNO0FBQ2xCLFVBQU0sSUFBSSxNQUFNLDJEQUEyRDtBQUFBLEVBQzdFO0FBRUEsU0FBTyxTQUFTLEtBQUs7QUFDdkI7QUFRQSxTQUFTLHFCQUFxQixTQUEyQjtBQUN2RCxTQUFPLFFBQVEsTUFBTSxHQUFHLEVBQUUsSUFBSSxDQUFDLFlBQVksT0FBTyxTQUFTLFNBQVMsRUFBRSxDQUFDO0FBQ3pFOyIsCiAgIm5hbWVzIjogW10KfQo=
|
|
@@ -4,18 +4,17 @@
|
|
|
4
4
|
* Desktop CDP transport — evaluates expressions via Chrome DevTools Protocol
|
|
5
5
|
* over WebSocket and manages vaults via Electron IPC.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* Two modes:
|
|
8
|
+
* - **Owned (default)**: the transport launches and owns an isolated Obsidian
|
|
9
|
+
* instance against a temporary `--user-data-dir` on a free `--remote-debugging-port`,
|
|
10
|
+
* never touching the user's Obsidian. Supports version pinning via the user-data asar.
|
|
11
|
+
* - **Attach**: when an explicit CDP port is configured, the transport connects
|
|
12
|
+
* to an already-running Obsidian on that port.
|
|
10
13
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* - No "CLI enabled" setting required in Obsidian
|
|
14
|
-
* - Lower overhead (WebSocket vs. process spawn per eval)
|
|
14
|
+
* It connects to page targets, sends `Runtime.evaluate` commands, and routes to
|
|
15
|
+
* the correct vault target using `getBasePath()` probing.
|
|
15
16
|
*
|
|
16
|
-
* Requirements:
|
|
17
|
-
* - Obsidian must be running with remote debugging enabled (port 8315)
|
|
18
|
-
* - Node.js 22+ (uses built-in `WebSocket` and `fetch` globals)
|
|
17
|
+
* Requirements: Node.js 22+ (uses built-in `WebSocket` and `fetch` globals).
|
|
19
18
|
*/
|
|
20
19
|
import type { ObsidianTransport, TransportEvalOptions } from './transport.mjs';
|
|
21
20
|
/**
|
|
@@ -27,7 +26,9 @@ export interface DesktopCdpTransportConfig {
|
|
|
27
26
|
*/
|
|
28
27
|
cdpHost?: string;
|
|
29
28
|
/**
|
|
30
|
-
* CDP port
|
|
29
|
+
* CDP port for **attach** mode (the `--remote-debugging-port` the running
|
|
30
|
+
* Obsidian was launched with). In owned-instance mode this is ignored — a
|
|
31
|
+
* free port is chosen at launch.
|
|
31
32
|
*/
|
|
32
33
|
cdpPort?: number;
|
|
33
34
|
/**
|
|
@@ -35,6 +36,37 @@ export interface DesktopCdpTransportConfig {
|
|
|
35
36
|
* Defaults to `30000`.
|
|
36
37
|
*/
|
|
37
38
|
commandTimeoutInMilliseconds?: number;
|
|
39
|
+
/**
|
|
40
|
+
* When set, the transport launches and owns an isolated Obsidian instance
|
|
41
|
+
* instead of attaching to a running one. This is the default desktop mode.
|
|
42
|
+
*/
|
|
43
|
+
ownedInstance?: OwnedInstanceConfig;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* An asar to provision into a harness-owned instance's user-data dir before launch.
|
|
47
|
+
*/
|
|
48
|
+
export interface OwnedInstanceAsar {
|
|
49
|
+
/** Absolute path to the cached/source asar file. */
|
|
50
|
+
readonly path: string;
|
|
51
|
+
/** The asar's `x.y.z` version. */
|
|
52
|
+
readonly version: string;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Configuration for a harness-owned, isolated Obsidian instance.
|
|
56
|
+
*
|
|
57
|
+
* When present, the transport launches and owns its own Obsidian process
|
|
58
|
+
* against an isolated user-data dir instead of attaching to a running instance.
|
|
59
|
+
*/
|
|
60
|
+
export interface OwnedInstanceConfig {
|
|
61
|
+
/** Optional asar to provision into {@link userDataDir} before launch. */
|
|
62
|
+
readonly asar?: OwnedInstanceAsar | undefined;
|
|
63
|
+
/** Absolute path to the Obsidian shell executable to launch. */
|
|
64
|
+
readonly exePath: string;
|
|
65
|
+
/**
|
|
66
|
+
* Absolute path to the isolated user-data dir. Created and owned by the
|
|
67
|
+
* transport, and deleted on dispose.
|
|
68
|
+
*/
|
|
69
|
+
readonly userDataDir: string;
|
|
38
70
|
}
|
|
39
71
|
/**
|
|
40
72
|
* Transport that communicates with Desktop Obsidian via Chrome DevTools Protocol.
|
|
@@ -48,10 +80,13 @@ export declare class DesktopCdpTransport implements ObsidianTransport {
|
|
|
48
80
|
*/
|
|
49
81
|
readonly isMobile = false;
|
|
50
82
|
private activeVaultPath;
|
|
51
|
-
private readonly
|
|
52
|
-
private
|
|
83
|
+
private readonly cdpHost;
|
|
84
|
+
private cdpPort;
|
|
85
|
+
private cdpUrl;
|
|
53
86
|
private readonly commandTimeoutInMilliseconds;
|
|
54
87
|
private messageId;
|
|
88
|
+
private readonly ownedConfig;
|
|
89
|
+
private ownedInstance;
|
|
55
90
|
private ws;
|
|
56
91
|
/**
|
|
57
92
|
* Creates a new CDP transport.
|
|
@@ -60,9 +95,19 @@ export declare class DesktopCdpTransport implements ObsidianTransport {
|
|
|
60
95
|
*/
|
|
61
96
|
constructor(config?: DesktopCdpTransportConfig);
|
|
62
97
|
/**
|
|
63
|
-
* Disposes of the active WebSocket connection
|
|
98
|
+
* Disposes of the active WebSocket connection and, in owned-instance mode,
|
|
99
|
+
* kills the owned Obsidian process and removes its isolated user-data dir.
|
|
100
|
+
*
|
|
101
|
+
* The removal is retried because Windows briefly holds the just-killed
|
|
102
|
+
* process's file handles, which would otherwise fail `rmSync` with `EPERM`.
|
|
64
103
|
*/
|
|
65
104
|
dispose(): Promise<void>;
|
|
105
|
+
/**
|
|
106
|
+
* Synchronous disposal — kills the owned instance and makes a best-effort
|
|
107
|
+
* removal of its user-data dir. Safe to call from a process `exit` handler
|
|
108
|
+
* (where async retries are impossible; a leftover temp dir is acceptable).
|
|
109
|
+
*/
|
|
110
|
+
disposeSync(): void;
|
|
66
111
|
/**
|
|
67
112
|
* Evaluates a JavaScript expression inside Obsidian via CDP `Runtime.evaluate`.
|
|
68
113
|
*
|
|
@@ -170,6 +215,15 @@ export declare class DesktopCdpTransport implements ObsidianTransport {
|
|
|
170
215
|
* @returns The vault's base path.
|
|
171
216
|
*/
|
|
172
217
|
private probeVaultPath;
|
|
218
|
+
/**
|
|
219
|
+
* Launches and connects to a harness-owned, isolated Obsidian instance for a
|
|
220
|
+
* vault: provisions the asar (if any), pre-seeds the isolated `obsidian.json`
|
|
221
|
+
* so the vault opens directly, launches the instance on a free CDP port, then
|
|
222
|
+
* waits until the vault window is ready and dismisses the trust dialog.
|
|
223
|
+
*
|
|
224
|
+
* @param vaultPath - The absolute path to the vault folder.
|
|
225
|
+
*/
|
|
226
|
+
private registerVaultInOwnedInstance;
|
|
173
227
|
/**
|
|
174
228
|
* Sends a CDP command over WebSocket and waits for the response.
|
|
175
229
|
*
|
|
@@ -192,4 +246,11 @@ export declare class DesktopCdpTransport implements ObsidianTransport {
|
|
|
192
246
|
* @param vaultPath - The vault path to evaluate in.
|
|
193
247
|
*/
|
|
194
248
|
private waitForLayoutReady;
|
|
249
|
+
/**
|
|
250
|
+
* Polls the owned instance until the vault target exists, layout is ready, and
|
|
251
|
+
* the trust dialog (if any) has been dismissed.
|
|
252
|
+
*
|
|
253
|
+
* @param vaultPath - The absolute path to the vault folder.
|
|
254
|
+
*/
|
|
255
|
+
private waitForOwnedVaultReady;
|
|
195
256
|
}
|