obsidian-integration-testing 4.3.0 → 5.0.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/global-setup-core.cjs +39 -12
- 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 +2 -3
- 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/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/setup-lock.cjs +158 -0
- package/dist/lib/cjs/setup-lock.d.cts +55 -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/global-setup-core.d.mts +1 -1
- package/dist/lib/esm/global-setup-core.mjs +39 -12
- package/dist/lib/esm/index.d.mts +2 -3
- 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/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/setup-lock.d.mts +55 -0
- package/dist/lib/esm/setup-lock.mjs +132 -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.0.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.3.0.tgz +0 -0
|
@@ -1,58 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file
|
|
3
3
|
*
|
|
4
|
-
* Reads and queries
|
|
5
|
-
*/
|
|
6
|
-
/**
|
|
7
|
-
* A registered vault entry returned by {@link getRegisteredVaults}.
|
|
8
|
-
*/
|
|
9
|
-
export interface RegisteredVault {
|
|
10
|
-
/**
|
|
11
|
-
* The hex vault ID from `obsidian.json`.
|
|
12
|
-
*/
|
|
13
|
-
id: string;
|
|
14
|
-
/**
|
|
15
|
-
* Whether the vault is currently marked as open.
|
|
16
|
-
*/
|
|
17
|
-
open: boolean;
|
|
18
|
-
/**
|
|
19
|
-
* The absolute path to the vault folder.
|
|
20
|
-
*/
|
|
21
|
-
path: string;
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Enables the CLI in Obsidian's `obsidian.json` config file.
|
|
25
|
-
*
|
|
26
|
-
* Sets `cli: true` so that Obsidian starts its CLI server on next launch.
|
|
27
|
-
* If the config file doesn't exist, creates it with an empty vaults object.
|
|
28
|
-
*/
|
|
29
|
-
export declare function enableCliInConfig(): void;
|
|
30
|
-
/**
|
|
31
|
-
* Returns the absolute path of any currently-open vault.
|
|
32
|
-
*
|
|
33
|
-
* Prefer this over {@link getAnyRegisteredVaultPath} when the path is going
|
|
34
|
-
* to be used as the target of an `obsidian eval` call: targeting a registered
|
|
35
|
-
* but **closed** vault causes Obsidian's CLI handler to spawn a fresh window
|
|
36
|
-
* for it (`pe(o, false)` in `main.js`), leaving a stray window behind.
|
|
4
|
+
* Reads and queries the user's Obsidian local configuration (`obsidian.json`).
|
|
37
5
|
*
|
|
38
|
-
*
|
|
6
|
+
* Used by the CDP transport's **attach** mode (targeting an already-running,
|
|
7
|
+
* user-scope Obsidian). Harness-owned isolated instances write their own
|
|
8
|
+
* `obsidian.json` directly into a temporary user-data dir and do not use these
|
|
9
|
+
* helpers.
|
|
39
10
|
*/
|
|
40
|
-
export declare function getAnyOpenVaultPath(): string | undefined;
|
|
41
11
|
/**
|
|
42
|
-
* Returns the path
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
* window (e.g., to issue IPC commands that register or remove other vaults).
|
|
12
|
+
* Returns the platform-specific path to the **user's** Obsidian config (user-data)
|
|
13
|
+
* directory — `%APPDATA%\obsidian` on Windows, `~/Library/Application Support/obsidian`
|
|
14
|
+
* on macOS, `$XDG_CONFIG_HOME/obsidian` (or `~/.config/obsidian`) on Linux.
|
|
46
15
|
*
|
|
47
|
-
*
|
|
48
|
-
|
|
49
|
-
export declare function getAnyRegisteredVaultPath(): string | undefined;
|
|
50
|
-
/**
|
|
51
|
-
* Returns all registered vaults from Obsidian's `obsidian.json` registry.
|
|
16
|
+
* This is the user-scope directory; harness-owned isolated instances use their
|
|
17
|
+
* own temporary user-data dir instead.
|
|
52
18
|
*
|
|
53
|
-
* @returns
|
|
19
|
+
* @returns The absolute path to the `obsidian/` config directory.
|
|
54
20
|
*/
|
|
55
|
-
export declare function
|
|
21
|
+
export declare function getObsidianConfigDir(): string;
|
|
56
22
|
/**
|
|
57
23
|
* Returns the hex vault ID for a given vault path from Obsidian's registry.
|
|
58
24
|
*
|
|
@@ -60,22 +26,6 @@ export declare function getRegisteredVaults(): RegisteredVault[];
|
|
|
60
26
|
* @returns The vault ID, or `undefined` if the vault is not registered.
|
|
61
27
|
*/
|
|
62
28
|
export declare function getVaultId(vaultPath: string): string | undefined;
|
|
63
|
-
/**
|
|
64
|
-
* Checks whether the Obsidian CLI is enabled in Obsidian's settings.
|
|
65
|
-
*
|
|
66
|
-
* @returns `true` if the CLI is enabled, `false` otherwise.
|
|
67
|
-
*/
|
|
68
|
-
export declare function isCliEnabled(): boolean;
|
|
69
|
-
/**
|
|
70
|
-
* Checks whether a vault is marked as open in Obsidian's vault registry.
|
|
71
|
-
*
|
|
72
|
-
* Note: This checks the `open` flag in `obsidian.json`, which is updated
|
|
73
|
-
* asynchronously by Obsidian. It may not reflect the current runtime state.
|
|
74
|
-
*
|
|
75
|
-
* @param vaultPath - The absolute path to the vault folder.
|
|
76
|
-
* @returns `true` if the vault is registered and marked as open, `false` otherwise.
|
|
77
|
-
*/
|
|
78
|
-
export declare function isVaultOpen(vaultPath: string): boolean;
|
|
79
29
|
/**
|
|
80
30
|
* Checks whether a vault path is registered in Obsidian's vault registry.
|
|
81
31
|
*
|
|
@@ -83,16 +33,6 @@ export declare function isVaultOpen(vaultPath: string): boolean;
|
|
|
83
33
|
* @returns `true` if the vault is registered, `false` otherwise.
|
|
84
34
|
*/
|
|
85
35
|
export declare function isVaultRegistered(vaultPath: string): boolean;
|
|
86
|
-
/**
|
|
87
|
-
* Registers a vault directly in Obsidian's `obsidian.json` config file.
|
|
88
|
-
*
|
|
89
|
-
* This writes a new vault entry with a random hex ID. Used when no existing
|
|
90
|
-
* vault is available to send IPC commands through — the vault is registered
|
|
91
|
-
* "offline" so Obsidian will open it on next launch.
|
|
92
|
-
*
|
|
93
|
-
* @param vaultPath - The absolute path to the vault folder.
|
|
94
|
-
*/
|
|
95
|
-
export declare function registerVaultInConfig(vaultPath: string): void;
|
|
96
36
|
/**
|
|
97
37
|
* Removes a vault entry from Obsidian's `obsidian.json` config file.
|
|
98
38
|
*
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { randomBytes } from "node:crypto";
|
|
2
1
|
import {
|
|
3
2
|
readFileSync,
|
|
4
3
|
writeFileSync
|
|
@@ -9,41 +8,17 @@ import {
|
|
|
9
8
|
resolve
|
|
10
9
|
} from "node:path";
|
|
11
10
|
import process from "node:process";
|
|
12
|
-
function
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
function getAnyOpenVaultPath() {
|
|
18
|
-
const config = readObsidianJson();
|
|
19
|
-
if (!config) {
|
|
20
|
-
return void 0;
|
|
21
|
-
}
|
|
22
|
-
for (const entry of Object.values(config.vaults)) {
|
|
23
|
-
if (entry.open === true) {
|
|
24
|
-
return entry.path;
|
|
11
|
+
function getObsidianConfigDir() {
|
|
12
|
+
if (process.platform === "win32") {
|
|
13
|
+
const appData = process.env["APPDATA"];
|
|
14
|
+
if (appData) {
|
|
15
|
+
return join(appData, "obsidian");
|
|
25
16
|
}
|
|
26
17
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
function getAnyRegisteredVaultPath() {
|
|
30
|
-
const config = readObsidianJson();
|
|
31
|
-
if (!config) {
|
|
32
|
-
return void 0;
|
|
33
|
-
}
|
|
34
|
-
const firstEntry = Object.values(config.vaults)[0];
|
|
35
|
-
return firstEntry?.path;
|
|
36
|
-
}
|
|
37
|
-
function getRegisteredVaults() {
|
|
38
|
-
const config = readObsidianJson();
|
|
39
|
-
if (!config) {
|
|
40
|
-
return [];
|
|
18
|
+
if (process.platform === "darwin") {
|
|
19
|
+
return join(homedir(), "Library", "Application Support", "obsidian");
|
|
41
20
|
}
|
|
42
|
-
return
|
|
43
|
-
id,
|
|
44
|
-
open: entry.open === true,
|
|
45
|
-
path: entry.path
|
|
46
|
-
}));
|
|
21
|
+
return join(process.env["XDG_CONFIG_HOME"] ?? join(homedir(), ".config"), "obsidian");
|
|
47
22
|
}
|
|
48
23
|
function getVaultId(vaultPath) {
|
|
49
24
|
const config = readObsidianJson();
|
|
@@ -58,34 +33,9 @@ function getVaultId(vaultPath) {
|
|
|
58
33
|
}
|
|
59
34
|
return void 0;
|
|
60
35
|
}
|
|
61
|
-
function isCliEnabled() {
|
|
62
|
-
const config = readObsidianJson();
|
|
63
|
-
return config?.cli === true;
|
|
64
|
-
}
|
|
65
|
-
function isVaultOpen(vaultPath) {
|
|
66
|
-
const config = readObsidianJson();
|
|
67
|
-
if (!config) {
|
|
68
|
-
return false;
|
|
69
|
-
}
|
|
70
|
-
const normalizedTarget = normalizePath(vaultPath);
|
|
71
|
-
for (const entry of Object.values(config.vaults)) {
|
|
72
|
-
if (normalizePath(entry.path) === normalizedTarget) {
|
|
73
|
-
return entry.open === true;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
return false;
|
|
77
|
-
}
|
|
78
36
|
function isVaultRegistered(vaultPath) {
|
|
79
37
|
return getVaultId(vaultPath) !== void 0;
|
|
80
38
|
}
|
|
81
|
-
function registerVaultInConfig(vaultPath) {
|
|
82
|
-
const config = readObsidianJson() ?? { vaults: {} };
|
|
83
|
-
const VAULT_ID_BYTE_LENGTH = 8;
|
|
84
|
-
const id = randomBytes(VAULT_ID_BYTE_LENGTH).toString("hex");
|
|
85
|
-
config.vaults[id] = { path: vaultPath, ts: Date.now() };
|
|
86
|
-
config.cli = true;
|
|
87
|
-
writeObsidianJson(config);
|
|
88
|
-
}
|
|
89
39
|
function removeVaultFromConfig(vaultPath) {
|
|
90
40
|
const config = readObsidianJson();
|
|
91
41
|
if (!config) {
|
|
@@ -105,18 +55,6 @@ function removeVaultFromConfig(vaultPath) {
|
|
|
105
55
|
}
|
|
106
56
|
return wasFound;
|
|
107
57
|
}
|
|
108
|
-
function getObsidianConfigDir() {
|
|
109
|
-
if (process.platform === "win32") {
|
|
110
|
-
const appData = process.env["APPDATA"];
|
|
111
|
-
if (appData) {
|
|
112
|
-
return join(appData, "obsidian");
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
if (process.platform === "darwin") {
|
|
116
|
-
return join(homedir(), "Library", "Application Support", "obsidian");
|
|
117
|
-
}
|
|
118
|
-
return join(process.env["XDG_CONFIG_HOME"] ?? join(homedir(), ".config"), "obsidian");
|
|
119
|
-
}
|
|
120
58
|
function normalizePath(vaultPath) {
|
|
121
59
|
const resolved = resolve(vaultPath);
|
|
122
60
|
return process.platform === "win32" ? resolved.toLowerCase() : resolved;
|
|
@@ -135,15 +73,9 @@ function writeObsidianJson(config) {
|
|
|
135
73
|
writeFileSync(configPath, JSON.stringify(config));
|
|
136
74
|
}
|
|
137
75
|
export {
|
|
138
|
-
|
|
139
|
-
getAnyOpenVaultPath,
|
|
140
|
-
getAnyRegisteredVaultPath,
|
|
141
|
-
getRegisteredVaults,
|
|
76
|
+
getObsidianConfigDir,
|
|
142
77
|
getVaultId,
|
|
143
|
-
isCliEnabled,
|
|
144
|
-
isVaultOpen,
|
|
145
78
|
isVaultRegistered,
|
|
146
|
-
registerVaultInConfig,
|
|
147
79
|
removeVaultFromConfig
|
|
148
80
|
};
|
|
149
|
-
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vc3JjL29ic2lkaWFuLWNvbmZpZy50cyJdLAogICJzb3VyY2VzQ29udGVudCI6IFsiLyoqXG4gKiBAZmlsZVxuICpcbiAqIFJlYWRzIGFuZCBxdWVyaWVzIE9ic2lkaWFuJ3MgbG9jYWwgY29uZmlndXJhdGlvbiAoYG9ic2lkaWFuLmpzb25gKS5cbiAqL1xuXG5pbXBvcnQgeyByYW5kb21CeXRlcyB9IGZyb20gJ25vZGU6Y3J5cHRvJztcbmltcG9ydCB7XG4gIHJlYWRGaWxlU3luYyxcbiAgd3JpdGVGaWxlU3luY1xufSBmcm9tICdub2RlOmZzJztcbmltcG9ydCB7IGhvbWVkaXIgfSBmcm9tICdub2RlOm9zJztcbmltcG9ydCB7XG4gIGpvaW4sXG4gIHJlc29sdmVcbn0gZnJvbSAnbm9kZTpwYXRoJztcbmltcG9ydCBwcm9jZXNzIGZyb20gJ25vZGU6cHJvY2Vzcyc7XG5cbi8qKlxuICogQSByZWdpc3RlcmVkIHZhdWx0IGVudHJ5IHJldHVybmVkIGJ5IHtAbGluayBnZXRSZWdpc3RlcmVkVmF1bHRzfS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBSZWdpc3RlcmVkVmF1bHQge1xuICAvKipcbiAgICogVGhlIGhleCB2YXVsdCBJRCBmcm9tIGBvYnNpZGlhbi5qc29uYC5cbiAgICovXG4gIGlkOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgdGhlIHZhdWx0IGlzIGN1cnJlbnRseSBtYXJrZWQgYXMgb3Blbi5cbiAgICovXG4gIG9wZW46IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIFRoZSBhYnNvbHV0ZSBwYXRoIHRvIHRoZSB2YXVsdCBmb2xkZXIuXG4gICAqL1xuICBwYXRoOiBzdHJpbmc7XG59XG5cbi8qKlxuICogVGhlIHRvcC1sZXZlbCBzdHJ1Y3R1cmUgb2YgT2JzaWRpYW4ncyBgb2JzaWRpYW4uanNvbmAgY29uZmlnIGZpbGUuXG4gKi9cbmludGVyZmFjZSBPYnNpZGlhbkpzb24ge1xuICAvKipcbiAgICogV2hldGhlciB0aGUgQ0xJIGlzIGVuYWJsZWQgaW4gT2JzaWRpYW4gc2V0dGluZ3MuXG4gICAqL1xuICBjbGk/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBNYXAgb2YgdmF1bHQgSURzIHRvIHZhdWx0IGVudHJpZXMuXG4gICAqL1xuICB2YXVsdHM6IFJlY29yZDxzdHJpbmcsIE9ic2lkaWFuVmF1bHRFbnRyeT47XG59XG5cbi8qKlxuICogQSBzaW5nbGUgdmF1bHQgZW50cnkgaW4gYG9ic2lkaWFuLmpzb25gLlxuICovXG5pbnRlcmZhY2UgT2JzaWRpYW5WYXVsdEVudHJ5IHtcbiAgLyoqXG4gICAqIFdoZXRoZXIgdGhlIHZhdWx0IGlzIGN1cnJlbnRseSBvcGVuLlxuICAgKi9cbiAgb3Blbj86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIFRoZSBhYnNvbHV0ZSBwYXRoIHRvIHRoZSB2YXVsdCBmb2xkZXIuXG4gICAqL1xuICBwYXRoOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRpbWVzdGFtcCBvZiB0aGUgbGFzdCBhY2Nlc3MuXG4gICAqL1xuICB0czogbnVtYmVyO1xufVxuXG4vKipcbiAqIEVuYWJsZXMgdGhlIENMSSBpbiBPYnNpZGlhbidzIGBvYnNpZGlhbi5qc29uYCBjb25maWcgZmlsZS5cbiAqXG4gKiBTZXRzIGBjbGk6IHRydWVgIHNvIHRoYXQgT2JzaWRpYW4gc3RhcnRzIGl0cyBDTEkgc2VydmVyIG9uIG5leHQgbGF1bmNoLlxuICogSWYgdGhlIGNvbmZpZyBmaWxlIGRvZXNuJ3QgZXhpc3QsIGNyZWF0ZXMgaXQgd2l0aCBhbiBlbXB0eSB2YXVsdHMgb2JqZWN0LlxuICovXG5leHBvcnQgZnVuY3Rpb24gZW5hYmxlQ2xpSW5Db25maWcoKTogdm9pZCB7XG4gIGNvbnN0IGNvbmZpZyA9IHJlYWRPYnNpZGlhbkpzb24oKSA/PyB7IHZhdWx0czoge30gfTtcbiAgY29uZmlnLmNsaSA9IHRydWU7XG4gIHdyaXRlT2JzaWRpYW5Kc29uKGNvbmZpZyk7XG59XG5cbi8qKlxuICogUmV0dXJucyB0aGUgYWJzb2x1dGUgcGF0aCBvZiBhbnkgY3VycmVudGx5LW9wZW4gdmF1bHQuXG4gKlxuICogUHJlZmVyIHRoaXMgb3ZlciB7QGxpbmsgZ2V0QW55UmVnaXN0ZXJlZFZhdWx0UGF0aH0gd2hlbiB0aGUgcGF0aCBpcyBnb2luZ1xuICogdG8gYmUgdXNlZCBhcyB0aGUgdGFyZ2V0IG9mIGFuIGBvYnNpZGlhbiBldmFsYCBjYWxsOiB0YXJnZXRpbmcgYSByZWdpc3RlcmVkXG4gKiBidXQgKipjbG9zZWQqKiB2YXVsdCBjYXVzZXMgT2JzaWRpYW4ncyBDTEkgaGFuZGxlciB0byBzcGF3biBhIGZyZXNoIHdpbmRvd1xuICogZm9yIGl0IChgcGUobywgZmFsc2UpYCBpbiBgbWFpbi5qc2ApLCBsZWF2aW5nIGEgc3RyYXkgd2luZG93IGJlaGluZC5cbiAqXG4gKiBAcmV0dXJucyBUaGUgYWJzb2x1dGUgcGF0aCB0byBhbiBvcGVuIHZhdWx0LCBvciBgdW5kZWZpbmVkYCBpZiBub25lIGFyZSBvcGVuLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0QW55T3BlblZhdWx0UGF0aCgpOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICBjb25zdCBjb25maWcgPSByZWFkT2JzaWRpYW5Kc29uKCk7XG4gIGlmICghY29uZmlnKSB7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxuXG4gIGZvciAoY29uc3QgZW50cnkgb2YgT2JqZWN0LnZhbHVlcyhjb25maWcudmF1bHRzKSkge1xuICAgIGlmIChlbnRyeS5vcGVuID09PSB0cnVlKSB7XG4gICAgICByZXR1cm4gZW50cnkucGF0aDtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIHVuZGVmaW5lZDtcbn1cblxuLyoqXG4gKiBSZXR1cm5zIHRoZSBwYXRoIG9mIGFueSB2YXVsdCB0aGF0IGlzIGN1cnJlbnRseSByZWdpc3RlcmVkIGluIE9ic2lkaWFuJ3MgcmVnaXN0cnkuXG4gKlxuICogVGhpcyBpcyB1c2VmdWwgd2hlbiBhbiBgb2JzaWRpYW4gZXZhbGAgY2FsbCBtdXN0IHJ1biBpbnNpZGUgYW4gZXhpc3RpbmcgdmF1bHRcbiAqIHdpbmRvdyAoZS5nLiwgdG8gaXNzdWUgSVBDIGNvbW1hbmRzIHRoYXQgcmVnaXN0ZXIgb3IgcmVtb3ZlIG90aGVyIHZhdWx0cykuXG4gKlxuICogQHJldHVybnMgVGhlIGFic29sdXRlIHBhdGggdG8gYSByZWdpc3RlcmVkIHZhdWx0LCBvciBgdW5kZWZpbmVkYCBpZiBubyB2YXVsdHMgYXJlIHJlZ2lzdGVyZWQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRBbnlSZWdpc3RlcmVkVmF1bHRQYXRoKCk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIGNvbnN0IGNvbmZpZyA9IHJlYWRPYnNpZGlhbkpzb24oKTtcbiAgaWYgKCFjb25maWcpIHtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG5cbiAgY29uc3QgZmlyc3RFbnRyeSA9IE9iamVjdC52YWx1ZXMoY29uZmlnLnZhdWx0cylbMF07XG4gIHJldHVybiBmaXJzdEVudHJ5Py5wYXRoO1xufVxuXG4vKipcbiAqIFJldHVybnMgYWxsIHJlZ2lzdGVyZWQgdmF1bHRzIGZyb20gT2JzaWRpYW4ncyBgb2JzaWRpYW4uanNvbmAgcmVnaXN0cnkuXG4gKlxuICogQHJldHVybnMgQW4gYXJyYXkgb2YgcmVnaXN0ZXJlZCB2YXVsdCBlbnRyaWVzLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0UmVnaXN0ZXJlZFZhdWx0cygpOiBSZWdpc3RlcmVkVmF1bHRbXSB7XG4gIGNvbnN0IGNvbmZpZyA9IHJlYWRPYnNpZGlhbkpzb24oKTtcbiAgaWYgKCFjb25maWcpIHtcbiAgICByZXR1cm4gW107XG4gIH1cblxuICByZXR1cm4gT2JqZWN0LmVudHJpZXMoY29uZmlnLnZhdWx0cykubWFwKChbaWQsIGVudHJ5XSkgPT4gKHtcbiAgICBpZCxcbiAgICBvcGVuOiBlbnRyeS5vcGVuID09PSB0cnVlLFxuICAgIHBhdGg6IGVudHJ5LnBhdGhcbiAgfSkpO1xufVxuXG4vKipcbiAqIFJldHVybnMgdGhlIGhleCB2YXVsdCBJRCBmb3IgYSBnaXZlbiB2YXVsdCBwYXRoIGZyb20gT2JzaWRpYW4ncyByZWdpc3RyeS5cbiAqXG4gKiBAcGFyYW0gdmF1bHRQYXRoIC0gVGhlIGFic29sdXRlIHBhdGggdG8gdGhlIHZhdWx0IGZvbGRlci5cbiAqIEByZXR1cm5zIFRoZSB2YXVsdCBJRCwgb3IgYHVuZGVmaW5lZGAgaWYgdGhlIHZhdWx0IGlzIG5vdCByZWdpc3RlcmVkLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0VmF1bHRJZCh2YXVsdFBhdGg6IHN0cmluZyk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIGNvbnN0IGNvbmZpZyA9IHJlYWRPYnNpZGlhbkpzb24oKTtcbiAgaWYgKCFjb25maWcpIHtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG5cbiAgY29uc3Qgbm9ybWFsaXplZFRhcmdldCA9IG5vcm1hbGl6ZVBhdGgodmF1bHRQYXRoKTtcblxuICBmb3IgKGNvbnN0IFtpZCwgZW50cnldIG9mIE9iamVjdC5lbnRyaWVzKGNvbmZpZy52YXVsdHMpKSB7XG4gICAgaWYgKG5vcm1hbGl6ZVBhdGgoZW50cnkucGF0aCkgPT09IG5vcm1hbGl6ZWRUYXJnZXQpIHtcbiAgICAgIHJldHVybiBpZDtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gdW5kZWZpbmVkO1xufVxuXG4vKipcbiAqIENoZWNrcyB3aGV0aGVyIHRoZSBPYnNpZGlhbiBDTEkgaXMgZW5hYmxlZCBpbiBPYnNpZGlhbidzIHNldHRpbmdzLlxuICpcbiAqIEByZXR1cm5zIGB0cnVlYCBpZiB0aGUgQ0xJIGlzIGVuYWJsZWQsIGBmYWxzZWAgb3RoZXJ3aXNlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNDbGlFbmFibGVkKCk6IGJvb2xlYW4ge1xuICBjb25zdCBjb25maWcgPSByZWFkT2JzaWRpYW5Kc29uKCk7XG4gIHJldHVybiBjb25maWc/LmNsaSA9PT0gdHJ1ZTtcbn1cblxuLyoqXG4gKiBDaGVja3Mgd2hldGhlciBhIHZhdWx0IGlzIG1hcmtlZCBhcyBvcGVuIGluIE9ic2lkaWFuJ3MgdmF1bHQgcmVnaXN0cnkuXG4gKlxuICogTm90ZTogVGhpcyBjaGVja3MgdGhlIGBvcGVuYCBmbGFnIGluIGBvYnNpZGlhbi5qc29uYCwgd2hpY2ggaXMgdXBkYXRlZFxuICogYXN5bmNocm9ub3VzbHkgYnkgT2JzaWRpYW4uIEl0IG1heSBub3QgcmVmbGVjdCB0aGUgY3VycmVudCBydW50aW1lIHN0YXRlLlxuICpcbiAqIEBwYXJhbSB2YXVsdFBhdGggLSBUaGUgYWJzb2x1dGUgcGF0aCB0byB0aGUgdmF1bHQgZm9sZGVyLlxuICogQHJldHVybnMgYHRydWVgIGlmIHRoZSB2YXVsdCBpcyByZWdpc3RlcmVkIGFuZCBtYXJrZWQgYXMgb3BlbiwgYGZhbHNlYCBvdGhlcndpc2UuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc1ZhdWx0T3Blbih2YXVsdFBhdGg6IHN0cmluZyk6IGJvb2xlYW4ge1xuICBjb25zdCBjb25maWcgPSByZWFkT2JzaWRpYW5Kc29uKCk7XG4gIGlmICghY29uZmlnKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgY29uc3Qgbm9ybWFsaXplZFRhcmdldCA9IG5vcm1hbGl6ZVBhdGgodmF1bHRQYXRoKTtcblxuICBmb3IgKGNvbnN0IGVudHJ5IG9mIE9iamVjdC52YWx1ZXMoY29uZmlnLnZhdWx0cykpIHtcbiAgICBpZiAobm9ybWFsaXplUGF0aChlbnRyeS5wYXRoKSA9PT0gbm9ybWFsaXplZFRhcmdldCkge1xuICAgICAgcmV0dXJuIGVudHJ5Lm9wZW4gPT09IHRydWU7XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIGZhbHNlO1xufVxuXG4vKipcbiAqIENoZWNrcyB3aGV0aGVyIGEgdmF1bHQgcGF0aCBpcyByZWdpc3RlcmVkIGluIE9ic2lkaWFuJ3MgdmF1bHQgcmVnaXN0cnkuXG4gKlxuICogQHBhcmFtIHZhdWx0UGF0aCAtIFRoZSBhYnNvbHV0ZSBwYXRoIHRvIHRoZSB2YXVsdCBmb2xkZXIuXG4gKiBAcmV0dXJucyBgdHJ1ZWAgaWYgdGhlIHZhdWx0IGlzIHJlZ2lzdGVyZWQsIGBmYWxzZWAgb3RoZXJ3aXNlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNWYXVsdFJlZ2lzdGVyZWQodmF1bHRQYXRoOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgcmV0dXJuIGdldFZhdWx0SWQodmF1bHRQYXRoKSAhPT0gdW5kZWZpbmVkO1xufVxuXG4vKipcbiAqIFJlZ2lzdGVycyBhIHZhdWx0IGRpcmVjdGx5IGluIE9ic2lkaWFuJ3MgYG9ic2lkaWFuLmpzb25gIGNvbmZpZyBmaWxlLlxuICpcbiAqIFRoaXMgd3JpdGVzIGEgbmV3IHZhdWx0IGVudHJ5IHdpdGggYSByYW5kb20gaGV4IElELiBVc2VkIHdoZW4gbm8gZXhpc3RpbmdcbiAqIHZhdWx0IGlzIGF2YWlsYWJsZSB0byBzZW5kIElQQyBjb21tYW5kcyB0aHJvdWdoIFx1MjAxNCB0aGUgdmF1bHQgaXMgcmVnaXN0ZXJlZFxuICogXCJvZmZsaW5lXCIgc28gT2JzaWRpYW4gd2lsbCBvcGVuIGl0IG9uIG5leHQgbGF1bmNoLlxuICpcbiAqIEBwYXJhbSB2YXVsdFBhdGggLSBUaGUgYWJzb2x1dGUgcGF0aCB0byB0aGUgdmF1bHQgZm9sZGVyLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVnaXN0ZXJWYXVsdEluQ29uZmlnKHZhdWx0UGF0aDogc3RyaW5nKTogdm9pZCB7XG4gIGNvbnN0IGNvbmZpZyA9IHJlYWRPYnNpZGlhbkpzb24oKSA/PyB7IHZhdWx0czoge30gfTtcbiAgY29uc3QgVkFVTFRfSURfQllURV9MRU5HVEggPSA4O1xuICBjb25zdCBpZCA9IHJhbmRvbUJ5dGVzKFZBVUxUX0lEX0JZVEVfTEVOR1RIKS50b1N0cmluZygnaGV4Jyk7XG4gIGNvbmZpZy52YXVsdHNbaWRdID0geyBwYXRoOiB2YXVsdFBhdGgsIHRzOiBEYXRlLm5vdygpIH07XG4gIGNvbmZpZy5jbGkgPSB0cnVlO1xuICB3cml0ZU9ic2lkaWFuSnNvbihjb25maWcpO1xufVxuXG4vKipcbiAqIFJlbW92ZXMgYSB2YXVsdCBlbnRyeSBmcm9tIE9ic2lkaWFuJ3MgYG9ic2lkaWFuLmpzb25gIGNvbmZpZyBmaWxlLlxuICpcbiAqIEBwYXJhbSB2YXVsdFBhdGggLSBUaGUgYWJzb2x1dGUgcGF0aCB0byB0aGUgdmF1bHQgZm9sZGVyLlxuICogQHJldHVybnMgYHRydWVgIGlmIHRoZSB2YXVsdCB3YXMgZm91bmQgYW5kIHJlbW92ZWQsIGBmYWxzZWAgb3RoZXJ3aXNlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVtb3ZlVmF1bHRGcm9tQ29uZmlnKHZhdWx0UGF0aDogc3RyaW5nKTogYm9vbGVhbiB7XG4gIGNvbnN0IGNvbmZpZyA9IHJlYWRPYnNpZGlhbkpzb24oKTtcbiAgaWYgKCFjb25maWcpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICBjb25zdCBub3JtYWxpemVkVGFyZ2V0ID0gbm9ybWFsaXplUGF0aCh2YXVsdFBhdGgpO1xuICBsZXQgd2FzRm91bmQgPSBmYWxzZTtcblxuICBmb3IgKGNvbnN0IFtpZCwgZW50cnldIG9mIE9iamVjdC5lbnRyaWVzKGNvbmZpZy52YXVsdHMpKSB7XG4gICAgaWYgKG5vcm1hbGl6ZVBhdGgoZW50cnkucGF0aCkgPT09IG5vcm1hbGl6ZWRUYXJnZXQpIHtcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tZHluYW1pYy1kZWxldGUgLS0gUmVtb3ZpbmcgYSB2YXVsdCBlbnRyeSBieSBpdHMgZHluYW1pYyBrZXkuXG4gICAgICBkZWxldGUgY29uZmlnLnZhdWx0c1tpZF07XG4gICAgICB3YXNGb3VuZCA9IHRydWU7XG4gICAgICBicmVhaztcbiAgICB9XG4gIH1cblxuICBpZiAod2FzRm91bmQpIHtcbiAgICB3cml0ZU9ic2lkaWFuSnNvbihjb25maWcpO1xuICB9XG5cbiAgcmV0dXJuIHdhc0ZvdW5kO1xufVxuXG4vKipcbiAqIFJldHVybnMgdGhlIHBsYXRmb3JtLXNwZWNpZmljIHBhdGggdG8gT2JzaWRpYW4ncyBjb25maWcgZGlyZWN0b3J5LlxuICpcbiAqIEByZXR1cm5zIFRoZSBhYnNvbHV0ZSBwYXRoIHRvIHRoZSBgb2JzaWRpYW4vYCBjb25maWcgZGlyZWN0b3J5LlxuICovXG5mdW5jdGlvbiBnZXRPYnNpZGlhbkNvbmZpZ0RpcigpOiBzdHJpbmcge1xuICBpZiAocHJvY2Vzcy5wbGF0Zm9ybSA9PT0gJ3dpbjMyJykge1xuICAgIGNvbnN0IGFwcERhdGEgPSBwcm9jZXNzLmVudlsnQVBQREFUQSddO1xuICAgIGlmIChhcHBEYXRhKSB7XG4gICAgICByZXR1cm4gam9pbihhcHBEYXRhLCAnb2JzaWRpYW4nKTtcbiAgICB9XG4gIH1cblxuICBpZiAocHJvY2Vzcy5wbGF0Zm9ybSA9PT0gJ2RhcndpbicpIHtcbiAgICByZXR1cm4gam9pbihob21lZGlyKCksICdMaWJyYXJ5JywgJ0FwcGxpY2F0aW9uIFN1cHBvcnQnLCAnb2JzaWRpYW4nKTtcbiAgfVxuXG4gIHJldHVybiBqb2luKHByb2Nlc3MuZW52WydYREdfQ09ORklHX0hPTUUnXSA/PyBqb2luKGhvbWVkaXIoKSwgJy5jb25maWcnKSwgJ29ic2lkaWFuJyk7XG59XG5cbi8qKlxuICogTm9ybWFsaXplcyBhIHZhdWx0IHBhdGggZm9yIGNvbXBhcmlzb24uXG4gKiBPbiBXaW5kb3dzLCBwYXRocyBhcmUgY2FzZS1pbnNlbnNpdGl2ZSBhbmQgc2VwYXJhdG9ycyBtYXkgdmFyeS5cbiAqXG4gKiBAcGFyYW0gdmF1bHRQYXRoIC0gVGhlIHBhdGggdG8gbm9ybWFsaXplLlxuICogQHJldHVybnMgVGhlIG5vcm1hbGl6ZWQgcGF0aC5cbiAqL1xuZnVuY3Rpb24gbm9ybWFsaXplUGF0aCh2YXVsdFBhdGg6IHN0cmluZyk6IHN0cmluZyB7XG4gIGNvbnN0IHJlc29sdmVkID0gcmVzb2x2ZSh2YXVsdFBhdGgpO1xuICByZXR1cm4gcHJvY2Vzcy5wbGF0Zm9ybSA9PT0gJ3dpbjMyJyA/IHJlc29sdmVkLnRvTG93ZXJDYXNlKCkgOiByZXNvbHZlZDtcbn1cblxuLyoqXG4gKiBSZWFkcyBhbmQgcGFyc2VzIE9ic2lkaWFuJ3MgYG9ic2lkaWFuLmpzb25gIGNvbmZpZyBmaWxlLlxuICpcbiAqIEByZXR1cm5zIFRoZSBwYXJzZWQgY29uZmlnLCBvciBgdW5kZWZpbmVkYCBpZiB0aGUgZmlsZSBkb2Vzbid0IGV4aXN0IG9yIGNhbid0IGJlIHBhcnNlZC5cbiAqL1xuZnVuY3Rpb24gcmVhZE9ic2lkaWFuSnNvbigpOiBPYnNpZGlhbkpzb24gfCB1bmRlZmluZWQge1xuICBjb25zdCBjb25maWdQYXRoID0gam9pbihnZXRPYnNpZGlhbkNvbmZpZ0RpcigpLCAnb2JzaWRpYW4uanNvbicpO1xuICB0cnkge1xuICAgIGNvbnN0IGNvbnRlbnQgPSByZWFkRmlsZVN5bmMoY29uZmlnUGF0aCwgJ3V0Zi04Jyk7XG4gICAgcmV0dXJuIEpTT04ucGFyc2UoY29udGVudCkgYXMgT2JzaWRpYW5Kc29uO1xuICB9IGNhdGNoIHtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG59XG5cbi8qKlxuICogV3JpdGVzIHRoZSBnaXZlbiBjb25maWcgb2JqZWN0IHRvIE9ic2lkaWFuJ3MgYG9ic2lkaWFuLmpzb25gIGZpbGUuXG4gKlxuICogQHBhcmFtIGNvbmZpZyAtIFRoZSBjb25maWcgdG8gd3JpdGUuXG4gKi9cbmZ1bmN0aW9uIHdyaXRlT2JzaWRpYW5Kc29uKGNvbmZpZzogT2JzaWRpYW5Kc29uKTogdm9pZCB7XG4gIGNvbnN0IGNvbmZpZ1BhdGggPSBqb2luKGdldE9ic2lkaWFuQ29uZmlnRGlyKCksICdvYnNpZGlhbi5qc29uJyk7XG4gIHdyaXRlRmlsZVN5bmMoY29uZmlnUGF0aCwgSlNPTi5zdHJpbmdpZnkoY29uZmlnKSk7XG59XG4iXSwKICAibWFwcGluZ3MiOiAiQUFNQSxTQUFTLG1CQUFtQjtBQUM1QjtBQUFBLEVBQ0U7QUFBQSxFQUNBO0FBQUEsT0FDSztBQUNQLFNBQVMsZUFBZTtBQUN4QjtBQUFBLEVBQ0U7QUFBQSxFQUNBO0FBQUEsT0FDSztBQUNQLE9BQU8sYUFBYTtB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
|
|
81
|
+
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vc3JjL29ic2lkaWFuLWNvbmZpZy50cyJdLAogICJzb3VyY2VzQ29udGVudCI6IFsiLyoqXG4gKiBAZmlsZVxuICpcbiAqIFJlYWRzIGFuZCBxdWVyaWVzIHRoZSB1c2VyJ3MgT2JzaWRpYW4gbG9jYWwgY29uZmlndXJhdGlvbiAoYG9ic2lkaWFuLmpzb25gKS5cbiAqXG4gKiBVc2VkIGJ5IHRoZSBDRFAgdHJhbnNwb3J0J3MgKiphdHRhY2gqKiBtb2RlICh0YXJnZXRpbmcgYW4gYWxyZWFkeS1ydW5uaW5nLFxuICogdXNlci1zY29wZSBPYnNpZGlhbikuIEhhcm5lc3Mtb3duZWQgaXNvbGF0ZWQgaW5zdGFuY2VzIHdyaXRlIHRoZWlyIG93blxuICogYG9ic2lkaWFuLmpzb25gIGRpcmVjdGx5IGludG8gYSB0ZW1wb3JhcnkgdXNlci1kYXRhIGRpciBhbmQgZG8gbm90IHVzZSB0aGVzZVxuICogaGVscGVycy5cbiAqL1xuXG5pbXBvcnQge1xuICByZWFkRmlsZVN5bmMsXG4gIHdyaXRlRmlsZVN5bmNcbn0gZnJvbSAnbm9kZTpmcyc7XG5pbXBvcnQgeyBob21lZGlyIH0gZnJvbSAnbm9kZTpvcyc7XG5pbXBvcnQge1xuICBqb2luLFxuICByZXNvbHZlXG59IGZyb20gJ25vZGU6cGF0aCc7XG5pbXBvcnQgcHJvY2VzcyBmcm9tICdub2RlOnByb2Nlc3MnO1xuXG4vKipcbiAqIFRoZSB0b3AtbGV2ZWwgc3RydWN0dXJlIG9mIE9ic2lkaWFuJ3MgYG9ic2lkaWFuLmpzb25gIGNvbmZpZyBmaWxlLlxuICovXG5pbnRlcmZhY2UgT2JzaWRpYW5Kc29uIHtcbiAgLyoqXG4gICAqIE1hcCBvZiB2YXVsdCBJRHMgdG8gdmF1bHQgZW50cmllcy5cbiAgICovXG4gIHZhdWx0czogUmVjb3JkPHN0cmluZywgT2JzaWRpYW5WYXVsdEVudHJ5Pjtcbn1cblxuLyoqXG4gKiBBIHNpbmdsZSB2YXVsdCBlbnRyeSBpbiBgb2JzaWRpYW4uanNvbmAuXG4gKi9cbmludGVyZmFjZSBPYnNpZGlhblZhdWx0RW50cnkge1xuICAvKipcbiAgICogVGhlIGFic29sdXRlIHBhdGggdG8gdGhlIHZhdWx0IGZvbGRlci5cbiAgICovXG4gIHBhdGg6IHN0cmluZztcblxuICAvKipcbiAgICogVGltZXN0YW1wIG9mIHRoZSBsYXN0IGFjY2Vzcy5cbiAgICovXG4gIHRzOiBudW1iZXI7XG59XG5cbi8qKlxuICogUmV0dXJucyB0aGUgcGxhdGZvcm0tc3BlY2lmaWMgcGF0aCB0byB0aGUgKip1c2VyJ3MqKiBPYnNpZGlhbiBjb25maWcgKHVzZXItZGF0YSlcbiAqIGRpcmVjdG9yeSBcdTIwMTQgYCVBUFBEQVRBJVxcb2JzaWRpYW5gIG9uIFdpbmRvd3MsIGB+L0xpYnJhcnkvQXBwbGljYXRpb24gU3VwcG9ydC9vYnNpZGlhbmBcbiAqIG9uIG1hY09TLCBgJFhER19DT05GSUdfSE9NRS9vYnNpZGlhbmAgKG9yIGB+Ly5jb25maWcvb2JzaWRpYW5gKSBvbiBMaW51eC5cbiAqXG4gKiBUaGlzIGlzIHRoZSB1c2VyLXNjb3BlIGRpcmVjdG9yeTsgaGFybmVzcy1vd25lZCBpc29sYXRlZCBpbnN0YW5jZXMgdXNlIHRoZWlyXG4gKiBvd24gdGVtcG9yYXJ5IHVzZXItZGF0YSBkaXIgaW5zdGVhZC5cbiAqXG4gKiBAcmV0dXJucyBUaGUgYWJzb2x1dGUgcGF0aCB0byB0aGUgYG9ic2lkaWFuL2AgY29uZmlnIGRpcmVjdG9yeS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldE9ic2lkaWFuQ29uZmlnRGlyKCk6IHN0cmluZyB7XG4gIGlmIChwcm9jZXNzLnBsYXRmb3JtID09PSAnd2luMzInKSB7XG4gICAgY29uc3QgYXBwRGF0YSA9IHByb2Nlc3MuZW52WydBUFBEQVRBJ107XG4gICAgaWYgKGFwcERhdGEpIHtcbiAgICAgIHJldHVybiBqb2luKGFwcERhdGEsICdvYnNpZGlhbicpO1xuICAgIH1cbiAgfVxuXG4gIGlmIChwcm9jZXNzLnBsYXRmb3JtID09PSAnZGFyd2luJykge1xuICAgIHJldHVybiBqb2luKGhvbWVkaXIoKSwgJ0xpYnJhcnknLCAnQXBwbGljYXRpb24gU3VwcG9ydCcsICdvYnNpZGlhbicpO1xuICB9XG5cbiAgcmV0dXJuIGpvaW4ocHJvY2Vzcy5lbnZbJ1hER19DT05GSUdfSE9NRSddID8/IGpvaW4oaG9tZWRpcigpLCAnLmNvbmZpZycpLCAnb2JzaWRpYW4nKTtcbn1cblxuLyoqXG4gKiBSZXR1cm5zIHRoZSBoZXggdmF1bHQgSUQgZm9yIGEgZ2l2ZW4gdmF1bHQgcGF0aCBmcm9tIE9ic2lkaWFuJ3MgcmVnaXN0cnkuXG4gKlxuICogQHBhcmFtIHZhdWx0UGF0aCAtIFRoZSBhYnNvbHV0ZSBwYXRoIHRvIHRoZSB2YXVsdCBmb2xkZXIuXG4gKiBAcmV0dXJucyBUaGUgdmF1bHQgSUQsIG9yIGB1bmRlZmluZWRgIGlmIHRoZSB2YXVsdCBpcyBub3QgcmVnaXN0ZXJlZC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldFZhdWx0SWQodmF1bHRQYXRoOiBzdHJpbmcpOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICBjb25zdCBjb25maWcgPSByZWFkT2JzaWRpYW5Kc29uKCk7XG4gIGlmICghY29uZmlnKSB7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxuXG4gIGNvbnN0IG5vcm1hbGl6ZWRUYXJnZXQgPSBub3JtYWxpemVQYXRoKHZhdWx0UGF0aCk7XG5cbiAgZm9yIChjb25zdCBbaWQsIGVudHJ5XSBvZiBPYmplY3QuZW50cmllcyhjb25maWcudmF1bHRzKSkge1xuICAgIGlmIChub3JtYWxpemVQYXRoKGVudHJ5LnBhdGgpID09PSBub3JtYWxpemVkVGFyZ2V0KSB7XG4gICAgICByZXR1cm4gaWQ7XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHVuZGVmaW5lZDtcbn1cblxuLyoqXG4gKiBDaGVja3Mgd2hldGhlciBhIHZhdWx0IHBhdGggaXMgcmVnaXN0ZXJlZCBpbiBPYnNpZGlhbidzIHZhdWx0IHJlZ2lzdHJ5LlxuICpcbiAqIEBwYXJhbSB2YXVsdFBhdGggLSBUaGUgYWJzb2x1dGUgcGF0aCB0byB0aGUgdmF1bHQgZm9sZGVyLlxuICogQHJldHVybnMgYHRydWVgIGlmIHRoZSB2YXVsdCBpcyByZWdpc3RlcmVkLCBgZmFsc2VgIG90aGVyd2lzZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzVmF1bHRSZWdpc3RlcmVkKHZhdWx0UGF0aDogc3RyaW5nKTogYm9vbGVhbiB7XG4gIHJldHVybiBnZXRWYXVsdElkKHZhdWx0UGF0aCkgIT09IHVuZGVmaW5lZDtcbn1cblxuLyoqXG4gKiBSZW1vdmVzIGEgdmF1bHQgZW50cnkgZnJvbSBPYnNpZGlhbidzIGBvYnNpZGlhbi5qc29uYCBjb25maWcgZmlsZS5cbiAqXG4gKiBAcGFyYW0gdmF1bHRQYXRoIC0gVGhlIGFic29sdXRlIHBhdGggdG8gdGhlIHZhdWx0IGZvbGRlci5cbiAqIEByZXR1cm5zIGB0cnVlYCBpZiB0aGUgdmF1bHQgd2FzIGZvdW5kIGFuZCByZW1vdmVkLCBgZmFsc2VgIG90aGVyd2lzZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlbW92ZVZhdWx0RnJvbUNvbmZpZyh2YXVsdFBhdGg6IHN0cmluZyk6IGJvb2xlYW4ge1xuICBjb25zdCBjb25maWcgPSByZWFkT2JzaWRpYW5Kc29uKCk7XG4gIGlmICghY29uZmlnKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgY29uc3Qgbm9ybWFsaXplZFRhcmdldCA9IG5vcm1hbGl6ZVBhdGgodmF1bHRQYXRoKTtcbiAgbGV0IHdhc0ZvdW5kID0gZmFsc2U7XG5cbiAgZm9yIChjb25zdCBbaWQsIGVudHJ5XSBvZiBPYmplY3QuZW50cmllcyhjb25maWcudmF1bHRzKSkge1xuICAgIGlmIChub3JtYWxpemVQYXRoKGVudHJ5LnBhdGgpID09PSBub3JtYWxpemVkVGFyZ2V0KSB7XG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLWR5bmFtaWMtZGVsZXRlIC0tIFJlbW92aW5nIGEgdmF1bHQgZW50cnkgYnkgaXRzIGR5bmFtaWMga2V5LlxuICAgICAgZGVsZXRlIGNvbmZpZy52YXVsdHNbaWRdO1xuICAgICAgd2FzRm91bmQgPSB0cnVlO1xuICAgICAgYnJlYWs7XG4gICAgfVxuICB9XG5cbiAgaWYgKHdhc0ZvdW5kKSB7XG4gICAgd3JpdGVPYnNpZGlhbkpzb24oY29uZmlnKTtcbiAgfVxuXG4gIHJldHVybiB3YXNGb3VuZDtcbn1cblxuLyoqXG4gKiBOb3JtYWxpemVzIGEgdmF1bHQgcGF0aCBmb3IgY29tcGFyaXNvbi5cbiAqIE9uIFdpbmRvd3MsIHBhdGhzIGFyZSBjYXNlLWluc2Vuc2l0aXZlIGFuZCBzZXBhcmF0b3JzIG1heSB2YXJ5LlxuICpcbiAqIEBwYXJhbSB2YXVsdFBhdGggLSBUaGUgcGF0aCB0byBub3JtYWxpemUuXG4gKiBAcmV0dXJucyBUaGUgbm9ybWFsaXplZCBwYXRoLlxuICovXG5mdW5jdGlvbiBub3JtYWxpemVQYXRoKHZhdWx0UGF0aDogc3RyaW5nKTogc3RyaW5nIHtcbiAgY29uc3QgcmVzb2x2ZWQgPSByZXNvbHZlKHZhdWx0UGF0aCk7XG4gIHJldHVybiBwcm9jZXNzLnBsYXRmb3JtID09PSAnd2luMzInID8gcmVzb2x2ZWQudG9Mb3dlckNhc2UoKSA6IHJlc29sdmVkO1xufVxuXG4vKipcbiAqIFJlYWRzIGFuZCBwYXJzZXMgT2JzaWRpYW4ncyBgb2JzaWRpYW4uanNvbmAgY29uZmlnIGZpbGUuXG4gKlxuICogQHJldHVybnMgVGhlIHBhcnNlZCBjb25maWcsIG9yIGB1bmRlZmluZWRgIGlmIHRoZSBmaWxlIGRvZXNuJ3QgZXhpc3Qgb3IgY2FuJ3QgYmUgcGFyc2VkLlxuICovXG5mdW5jdGlvbiByZWFkT2JzaWRpYW5Kc29uKCk6IE9ic2lkaWFuSnNvbiB8IHVuZGVmaW5lZCB7XG4gIGNvbnN0IGNvbmZpZ1BhdGggPSBqb2luKGdldE9ic2lkaWFuQ29uZmlnRGlyKCksICdvYnNpZGlhbi5qc29uJyk7XG4gIHRyeSB7XG4gICAgY29uc3QgY29udGVudCA9IHJlYWRGaWxlU3luYyhjb25maWdQYXRoLCAndXRmLTgnKTtcbiAgICByZXR1cm4gSlNPTi5wYXJzZShjb250ZW50KSBhcyBPYnNpZGlhbkpzb247XG4gIH0gY2F0Y2gge1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbn1cblxuLyoqXG4gKiBXcml0ZXMgdGhlIGdpdmVuIGNvbmZpZyBvYmplY3QgdG8gT2JzaWRpYW4ncyBgb2JzaWRpYW4uanNvbmAgZmlsZS5cbiAqXG4gKiBAcGFyYW0gY29uZmlnIC0gVGhlIGNvbmZpZyB0byB3cml0ZS5cbiAqL1xuZnVuY3Rpb24gd3JpdGVPYnNpZGlhbkpzb24oY29uZmlnOiBPYnNpZGlhbkpzb24pOiB2b2lkIHtcbiAgY29uc3QgY29uZmlnUGF0aCA9IGpvaW4oZ2V0T2JzaWRpYW5Db25maWdEaXIoKSwgJ29ic2lkaWFuLmpzb24nKTtcbiAgd3JpdGVGaWxlU3luYyhjb25maWdQYXRoLCBKU09OLnN0cmluZ2lmeShjb25maWcpKTtcbn1cbiJdLAogICJtYXBwaW5ncyI6ICJBQVdBO0FBQUEsRUFDRTtBQUFBLEVBQ0E7QUFBQSxPQUNLO0FBQ1AsU0FBUyxlQUFlO0FBQ3hCO0FBQUEsRUFDRTtBQUFBLEVBQ0E7QUFBQSxPQUNLO0FBQ1AsT0FBTyxhQUFhO0FBcUNiLFNBQVMsdUJBQStCO0FBQzdDLE1BQUksUUFBUSxhQUFhLFNBQVM7QUFDaEMsVUFBTSxVQUFVLFFBQVEsSUFBSSxTQUFTO0FBQ3JDLFFBQUksU0FBUztBQUNYLGFBQU8sS0FBSyxTQUFTLFVBQVU7QUFBQSxJQUNqQztBQUFBLEVBQ0Y7QUFFQSxNQUFJLFFBQVEsYUFBYSxVQUFVO0FBQ2pDLFdBQU8sS0FBSyxRQUFRLEdBQUcsV0FBVyx1QkFBdUIsVUFBVTtBQUFBLEVBQ3JFO0FBRUEsU0FBTyxLQUFLLFFBQVEsSUFBSSxpQkFBaUIsS0FBSyxLQUFLLFFBQVEsR0FBRyxTQUFTLEdBQUcsVUFBVTtBQUN0RjtBQVFPLFNBQVMsV0FBVyxXQUF1QztBQUNoRSxRQUFNLFNBQVMsaUJBQWlCO0FBQ2hDLE1BQUksQ0FBQyxRQUFRO0FBQ1gsV0FBTztBQUFBLEVBQ1Q7QUFFQSxRQUFNLG1CQUFtQixjQUFjLFNBQVM7QUFFaEQsYUFBVyxDQUFDLElBQUksS0FBSyxLQUFLLE9BQU8sUUFBUSxPQUFPLE1BQU0sR0FBRztBQUN2RCxRQUFJLGNBQWMsTUFBTSxJQUFJLE1BQU0sa0JBQWtCO0FBQ2xELGFBQU87QUFBQSxJQUNUO0FBQUEsRUFDRjtBQUVBLFNBQU87QUFDVDtBQVFPLFNBQVMsa0JBQWtCLFdBQTRCO0FBQzVELFNBQU8sV0FBVyxTQUFTLE1BQU07QUFDbkM7QUFRTyxTQUFTLHNCQUFzQixXQUE0QjtBQUNoRSxRQUFNLFNBQVMsaUJBQWlCO0FBQ2hDLE1BQUksQ0FBQyxRQUFRO0FBQ1gsV0FBTztBQUFBLEVBQ1Q7QUFFQSxRQUFNLG1CQUFtQixjQUFjLFNBQVM7QUFDaEQsTUFBSSxXQUFXO0FBRWYsYUFBVyxDQUFDLElBQUksS0FBSyxLQUFLLE9BQU8sUUFBUSxPQUFPLE1BQU0sR0FBRztBQUN2RCxRQUFJLGNBQWMsTUFBTSxJQUFJLE1BQU0sa0JBQWtCO0FBRWxELGFBQU8sT0FBTyxPQUFPLEVBQUU7QUFDdkIsaUJBQVc7QUFDWDtBQUFBLElBQ0Y7QUFBQSxFQUNGO0FBRUEsTUFBSSxVQUFVO0FBQ1osc0JBQWtCLE1BQU07QUFBQSxFQUMxQjtBQUVBLFNBQU87QUFDVDtBQVNBLFNBQVMsY0FBYyxXQUEyQjtBQUNoRCxRQUFNLFdBQVcsUUFBUSxTQUFTO0FBQ2xDLFNBQU8sUUFBUSxhQUFhLFVBQVUsU0FBUyxZQUFZLElBQUk7QUFDakU7QUFPQSxTQUFTLG1CQUE2QztBQUNwRCxRQUFNLGFBQWEsS0FBSyxxQkFBcUIsR0FBRyxlQUFlO0FBQy9ELE1BQUk7QUFDRixVQUFNLFVBQVUsYUFBYSxZQUFZLE9BQU87QUFDaEQsV0FBTyxLQUFLLE1BQU0sT0FBTztBQUFBLEVBQzNCLFFBQVE7QUFDTixXQUFPO0FBQUEsRUFDVDtBQUNGO0FBT0EsU0FBUyxrQkFBa0IsUUFBNEI7QUFDckQsUUFBTSxhQUFhLEtBQUsscUJBQXFCLEdBQUcsZUFBZTtBQUMvRCxnQkFBYyxZQUFZLEtBQUssVUFBVSxNQUFNLENBQUM7QUFDbEQ7IiwKICAibmFtZXMiOiBbXQp9Cg==
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file
|
|
3
|
+
*
|
|
4
|
+
* Integration-time helpers for resolving the Obsidian **shell** (the Electron
|
|
5
|
+
* runtime / installer build) to launch.
|
|
6
|
+
*
|
|
7
|
+
* By default the harness uses the installed shell. When a specific installer
|
|
8
|
+
* version is requested, it downloads that version's GitHub release asset and
|
|
9
|
+
* extracts a portable shell into a cache, returning the executable to launch.
|
|
10
|
+
*
|
|
11
|
+
* GitHub release assets exist for **public** releases only; catalyst (beta)
|
|
12
|
+
* builds publish only the asar, so installer-pinning supports public versions.
|
|
13
|
+
* The extracted shell's bundled `resources/obsidian.asar` is that version, so
|
|
14
|
+
* pinning the installer is how you run a version **older** than the installed
|
|
15
|
+
* shell (asar-swap is upgrade-only — see `obsidian-version-switch.ts`).
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* A resolved Obsidian shell executable.
|
|
19
|
+
*/
|
|
20
|
+
export interface ResolvedShell {
|
|
21
|
+
/** Absolute path to the Obsidian executable to launch. */
|
|
22
|
+
readonly exePath: string;
|
|
23
|
+
/** The shell's version, or `undefined` if it could not be detected. */
|
|
24
|
+
readonly version: string | undefined;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Detects the version of an installed Obsidian shell from its executable.
|
|
28
|
+
*
|
|
29
|
+
* - Windows: the executable's PE `FileVersion`.
|
|
30
|
+
* - macOS: `CFBundleShortVersionString` from the app bundle's `Info.plist`.
|
|
31
|
+
* - Linux: best-effort parse from the executable path (often `undefined`).
|
|
32
|
+
*
|
|
33
|
+
* @param exePath - Absolute path to the Obsidian executable.
|
|
34
|
+
* @returns The `x.y.z` version, or `undefined` if it cannot be determined.
|
|
35
|
+
*/
|
|
36
|
+
export declare function detectInstalledShellVersion(exePath: string): string | undefined;
|
|
37
|
+
/**
|
|
38
|
+
* Ensures a portable Obsidian shell for the given version is extracted into the
|
|
39
|
+
* cache, downloading and extracting its GitHub release asset if necessary.
|
|
40
|
+
*
|
|
41
|
+
* @param version - A concrete public `x.y.z` version.
|
|
42
|
+
* @returns The absolute path to the cached shell executable.
|
|
43
|
+
* @throws Error if the asset cannot be downloaded or extracted.
|
|
44
|
+
*/
|
|
45
|
+
export declare function ensureShellCached(version: string): Promise<string>;
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import {
|
|
2
|
+
execFileSync,
|
|
3
|
+
spawnSync
|
|
4
|
+
} from "node:child_process";
|
|
5
|
+
import {
|
|
6
|
+
existsSync,
|
|
7
|
+
mkdirSync,
|
|
8
|
+
readFileSync,
|
|
9
|
+
rmSync,
|
|
10
|
+
writeFileSync
|
|
11
|
+
} from "node:fs";
|
|
12
|
+
import { tmpdir } from "node:os";
|
|
13
|
+
import {
|
|
14
|
+
basename,
|
|
15
|
+
dirname,
|
|
16
|
+
join
|
|
17
|
+
} from "node:path";
|
|
18
|
+
import process from "node:process";
|
|
19
|
+
import { log } from "./log.mjs";
|
|
20
|
+
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";
|
|
21
|
+
const CACHE_ROOT = join(tmpdir(), "obsidian-integration-testing");
|
|
22
|
+
const SHELL_CACHE_DIR = join(CACHE_ROOT, "shell-cache");
|
|
23
|
+
const MAC_PLIST_VERSION_PATTERN = /<key>CFBundleShortVersionString<\/key>\s*<string>(?<version>[^<]+)<\/string>/;
|
|
24
|
+
function detectInstalledShellVersion(exePath) {
|
|
25
|
+
if (process.platform === "win32") {
|
|
26
|
+
return detectWindowsFileVersion(exePath);
|
|
27
|
+
}
|
|
28
|
+
if (process.platform === "darwin") {
|
|
29
|
+
return detectMacBundleVersion(exePath);
|
|
30
|
+
}
|
|
31
|
+
return detectVersionFromPath(exePath);
|
|
32
|
+
}
|
|
33
|
+
async function ensureShellCached(version) {
|
|
34
|
+
const shellDir = join(SHELL_CACHE_DIR, version);
|
|
35
|
+
const exePath = getCachedShellExePath(shellDir);
|
|
36
|
+
if (existsSync(exePath)) {
|
|
37
|
+
log(`[installer] Using cached shell for ${version}.`);
|
|
38
|
+
return exePath;
|
|
39
|
+
}
|
|
40
|
+
mkdirSync(shellDir, { recursive: true });
|
|
41
|
+
const assetName = getInstallerAssetName(version);
|
|
42
|
+
const assetPath = join(shellDir, assetName);
|
|
43
|
+
await downloadReleaseAsset(version, assetName, assetPath);
|
|
44
|
+
extractShell(assetPath, shellDir);
|
|
45
|
+
rmSync(assetPath, { force: true });
|
|
46
|
+
if (!existsSync(exePath)) {
|
|
47
|
+
throw new Error(`Extracted Obsidian shell ${version} but executable not found at ${exePath}.`);
|
|
48
|
+
}
|
|
49
|
+
log(`[installer] Extracted shell ${version} -> ${exePath}`);
|
|
50
|
+
return exePath;
|
|
51
|
+
}
|
|
52
|
+
function assertCommandAvailable(command, hint) {
|
|
53
|
+
const probe = process.platform === "win32" ? "where.exe" : "which";
|
|
54
|
+
const result = spawnSync(probe, [command], { stdio: "ignore" });
|
|
55
|
+
if (result.status !== 0) {
|
|
56
|
+
throw new Error(`Required command "${command}" was not found on PATH. ${hint}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function detectMacBundleVersion(exePath) {
|
|
60
|
+
try {
|
|
61
|
+
const contentsDir = dirname(dirname(exePath));
|
|
62
|
+
const plist = readFileSync(join(contentsDir, "Info.plist"), "utf-8");
|
|
63
|
+
const match = MAC_PLIST_VERSION_PATTERN.exec(plist);
|
|
64
|
+
return match?.groups?.["version"];
|
|
65
|
+
} catch {
|
|
66
|
+
return void 0;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
function detectVersionFromPath(value) {
|
|
70
|
+
const match = /(?<version>\d+\.\d+\.\d+)/.exec(value);
|
|
71
|
+
return match?.groups?.["version"];
|
|
72
|
+
}
|
|
73
|
+
function detectWindowsFileVersion(exePath) {
|
|
74
|
+
try {
|
|
75
|
+
const output = execFileSync(
|
|
76
|
+
"powershell",
|
|
77
|
+
["-NoProfile", "-Command", `(Get-Item -LiteralPath ${JSON.stringify(exePath)}).VersionInfo.FileVersion`],
|
|
78
|
+
{ encoding: "utf-8" }
|
|
79
|
+
);
|
|
80
|
+
const version = output.trim();
|
|
81
|
+
return version.length > 0 ? version : void 0;
|
|
82
|
+
} catch {
|
|
83
|
+
return void 0;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
async function downloadReleaseAsset(version, assetName, dest) {
|
|
87
|
+
const url = `https://github.com/obsidianmd/obsidian-releases/releases/download/v${version}/${assetName}`;
|
|
88
|
+
log(`[installer] Downloading installer ${version} from ${url} ...`);
|
|
89
|
+
const response = await fetch(url, { headers: { "User-Agent": DOWNLOAD_USER_AGENT } });
|
|
90
|
+
if (!response.ok) {
|
|
91
|
+
throw new Error(
|
|
92
|
+
`Failed to download Obsidian installer ${version}: HTTP ${String(response.status)} from ${url}. Catalyst/beta versions have no public installer \u2014 pin an asar version on a public/installed shell instead.`
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
writeFileSync(dest, Buffer.from(await response.arrayBuffer()));
|
|
96
|
+
}
|
|
97
|
+
function extractLinuxShell(assetPath, shellDir) {
|
|
98
|
+
run("tar", ["xzf", assetPath, "-C", shellDir, "--strip-components=1"]);
|
|
99
|
+
}
|
|
100
|
+
function extractMacShell(assetPath, shellDir) {
|
|
101
|
+
const mountPoint = join(shellDir, "__mnt");
|
|
102
|
+
mkdirSync(mountPoint, { recursive: true });
|
|
103
|
+
run("hdiutil", ["attach", "-nobrowse", "-mountpoint", mountPoint, assetPath]);
|
|
104
|
+
try {
|
|
105
|
+
run("cp", ["-R", join(mountPoint, "Obsidian.app"), shellDir]);
|
|
106
|
+
} finally {
|
|
107
|
+
run("hdiutil", ["detach", mountPoint]);
|
|
108
|
+
}
|
|
109
|
+
rmSync(mountPoint, { force: true, recursive: true });
|
|
110
|
+
}
|
|
111
|
+
function extractShell(assetPath, shellDir) {
|
|
112
|
+
if (process.platform === "win32") {
|
|
113
|
+
extractWindowsShell(assetPath, shellDir);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
if (process.platform === "darwin") {
|
|
117
|
+
extractMacShell(assetPath, shellDir);
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
extractLinuxShell(assetPath, shellDir);
|
|
121
|
+
}
|
|
122
|
+
function extractWindowsShell(assetPath, shellDir) {
|
|
123
|
+
assertCommandAvailable("7z", "Install 7-Zip (e.g. `scoop install 7zip`) to extract a pinned Obsidian installer.");
|
|
124
|
+
const nsisExtractDir = join(shellDir, "__nsis");
|
|
125
|
+
run("7z", ["x", "-y", `-o${nsisExtractDir}`, assetPath]);
|
|
126
|
+
const innerArchive = join(nsisExtractDir, "$PLUGINSDIR", "app-64.7z");
|
|
127
|
+
run("7z", ["x", "-y", `-o${shellDir}`, innerArchive]);
|
|
128
|
+
rmSync(nsisExtractDir, { force: true, recursive: true });
|
|
129
|
+
}
|
|
130
|
+
function getCachedShellExePath(shellDir) {
|
|
131
|
+
if (process.platform === "win32") {
|
|
132
|
+
return join(shellDir, "Obsidian.exe");
|
|
133
|
+
}
|
|
134
|
+
if (process.platform === "darwin") {
|
|
135
|
+
return join(shellDir, "Obsidian.app", "Contents", "MacOS", "Obsidian");
|
|
136
|
+
}
|
|
137
|
+
return join(shellDir, "obsidian");
|
|
138
|
+
}
|
|
139
|
+
function getInstallerAssetName(version) {
|
|
140
|
+
if (process.platform === "win32") {
|
|
141
|
+
return `Obsidian-${version}.exe`;
|
|
142
|
+
}
|
|
143
|
+
if (process.platform === "darwin") {
|
|
144
|
+
return `Obsidian-${version}.dmg`;
|
|
145
|
+
}
|
|
146
|
+
return `obsidian-${version}.tar.gz`;
|
|
147
|
+
}
|
|
148
|
+
function run(command, args) {
|
|
149
|
+
const result = spawnSync(command, args, { stdio: "ignore" });
|
|
150
|
+
if (result.status !== 0) {
|
|
151
|
+
throw new Error(`Command failed: ${command} ${args.map((arg) => basename(arg)).join(" ")} (exit ${String(result.status)})`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
export {
|
|
155
|
+
detectInstalledShellVersion,
|
|
156
|
+
ensureShellCached
|
|
157
|
+
};
|
|
158
|
+
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vc3JjL29ic2lkaWFuLWluc3RhbGxlci50cyJdLAogICJzb3VyY2VzQ29udGVudCI6IFsiLyoqXG4gKiBAZmlsZVxuICpcbiAqIEludGVncmF0aW9uLXRpbWUgaGVscGVycyBmb3IgcmVzb2x2aW5nIHRoZSBPYnNpZGlhbiAqKnNoZWxsKiogKHRoZSBFbGVjdHJvblxuICogcnVudGltZSAvIGluc3RhbGxlciBidWlsZCkgdG8gbGF1bmNoLlxuICpcbiAqIEJ5IGRlZmF1bHQgdGhlIGhhcm5lc3MgdXNlcyB0aGUgaW5zdGFsbGVkIHNoZWxsLiBXaGVuIGEgc3BlY2lmaWMgaW5zdGFsbGVyXG4gKiB2ZXJzaW9uIGlzIHJlcXVlc3RlZCwgaXQgZG93bmxvYWRzIHRoYXQgdmVyc2lvbidzIEdpdEh1YiByZWxlYXNlIGFzc2V0IGFuZFxuICogZXh0cmFjdHMgYSBwb3J0YWJsZSBzaGVsbCBpbnRvIGEgY2FjaGUsIHJldHVybmluZyB0aGUgZXhlY3V0YWJsZSB0byBsYXVuY2guXG4gKlxuICogR2l0SHViIHJlbGVhc2UgYXNzZXRzIGV4aXN0IGZvciAqKnB1YmxpYyoqIHJlbGVhc2VzIG9ubHk7IGNhdGFseXN0IChiZXRhKVxuICogYnVpbGRzIHB1Ymxpc2ggb25seSB0aGUgYXNhciwgc28gaW5zdGFsbGVyLXBpbm5pbmcgc3VwcG9ydHMgcHVibGljIHZlcnNpb25zLlxuICogVGhlIGV4dHJhY3RlZCBzaGVsbCdzIGJ1bmRsZWQgYHJlc291cmNlcy9vYnNpZGlhbi5hc2FyYCBpcyB0aGF0IHZlcnNpb24sIHNvXG4gKiBwaW5uaW5nIHRoZSBpbnN0YWxsZXIgaXMgaG93IHlvdSBydW4gYSB2ZXJzaW9uICoqb2xkZXIqKiB0aGFuIHRoZSBpbnN0YWxsZWRcbiAqIHNoZWxsIChhc2FyLXN3YXAgaXMgdXBncmFkZS1vbmx5IFx1MjAxNCBzZWUgYG9ic2lkaWFuLXZlcnNpb24tc3dpdGNoLnRzYCkuXG4gKi9cblxuLyogdjggaWdub3JlIHN0YXJ0IC0tIEludGVncmF0aW9uLXRpbWUgZG93bmxvYWQvZXh0cmFjdGlvbiBnbHVlIGNvdmVyZWQgYnkgaW50ZWdyYXRpb24gdGVzdHMsIG5vdCB1bml0IHRlc3RzLiAqL1xuXG5pbXBvcnQge1xuICBleGVjRmlsZVN5bmMsXG4gIHNwYXduU3luY1xufSBmcm9tICdub2RlOmNoaWxkX3Byb2Nlc3MnO1xuaW1wb3J0IHtcbiAgZXhpc3RzU3luYyxcbiAgbWtkaXJTeW5jLFxuICByZWFkRmlsZVN5bmMsXG4gIHJtU3luYyxcbiAgd3JpdGVGaWxlU3luY1xufSBmcm9tICdub2RlOmZzJztcbmltcG9ydCB7IHRtcGRpciB9IGZyb20gJ25vZGU6b3MnO1xuaW1wb3J0IHtcbiAgYmFzZW5hbWUsXG4gIGRpcm5hbWUsXG4gIGpvaW5cbn0gZnJvbSAnbm9kZTpwYXRoJztcbmltcG9ydCBwcm9jZXNzIGZyb20gJ25vZGU6cHJvY2Vzcyc7XG5cbmltcG9ydCB7IGxvZyB9IGZyb20gJy4vbG9nLm1qcyc7XG5cbi8qKlxuICogQnJvd3NlciBVc2VyLUFnZW50IGZvciBkb3dubG9hZGluZyByZWxlYXNlIGFzc2V0cyAoQ2xvdWRmbGFyZS1nYXRlZCkuXG4gKi9cbmNvbnN0IERPV05MT0FEX1VTRVJfQUdFTlQgPSAnTW96aWxsYS81LjAgKFdpbmRvd3MgTlQgMTAuMDsgV2luNjQ7IHg2NCkgQXBwbGVXZWJLaXQvNTM3LjM2IChLSFRNTCwgbGlrZSBHZWNrbykgQ2hyb21lLzg2LjAuNDI0MC4xODMgU2FmYXJpLzUzNy4zNic7XG5cbmNvbnN0IENBQ0hFX1JPT1QgPSBqb2luKHRtcGRpcigpLCAnb2JzaWRpYW4taW50ZWdyYXRpb24tdGVzdGluZycpO1xuY29uc3QgU0hFTExfQ0FDSEVfRElSID0gam9pbihDQUNIRV9ST09ULCAnc2hlbGwtY2FjaGUnKTtcbmNvbnN0IE1BQ19QTElTVF9WRVJTSU9OX1BBVFRFUk4gPSAvPGtleT5DRkJ1bmRsZVNob3J0VmVyc2lvblN0cmluZzxcXC9rZXk+XFxzKjxzdHJpbmc+KD88dmVyc2lvbj5bXjxdKyk8XFwvc3RyaW5nPi87XG5cbi8qKlxuICogQSByZXNvbHZlZCBPYnNpZGlhbiBzaGVsbCBleGVjdXRhYmxlLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFJlc29sdmVkU2hlbGwge1xuICAvKiogQWJzb2x1dGUgcGF0aCB0byB0aGUgT2JzaWRpYW4gZXhlY3V0YWJsZSB0byBsYXVuY2guICovXG4gIHJlYWRvbmx5IGV4ZVBhdGg6IHN0cmluZztcblxuICAvKiogVGhlIHNoZWxsJ3MgdmVyc2lvbiwgb3IgYHVuZGVmaW5lZGAgaWYgaXQgY291bGQgbm90IGJlIGRldGVjdGVkLiAqL1xuICByZWFkb25seSB2ZXJzaW9uOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG59XG5cbi8qKlxuICogRGV0ZWN0cyB0aGUgdmVyc2lvbiBvZiBhbiBpbnN0YWxsZWQgT2JzaWRpYW4gc2hlbGwgZnJvbSBpdHMgZXhlY3V0YWJsZS5cbiAqXG4gKiAtIFdpbmRvd3M6IHRoZSBleGVjdXRhYmxlJ3MgUEUgYEZpbGVWZXJzaW9uYC5cbiAqIC0gbWFjT1M6IGBDRkJ1bmRsZVNob3J0VmVyc2lvblN0cmluZ2AgZnJvbSB0aGUgYXBwIGJ1bmRsZSdzIGBJbmZvLnBsaXN0YC5cbiAqIC0gTGludXg6IGJlc3QtZWZmb3J0IHBhcnNlIGZyb20gdGhlIGV4ZWN1dGFibGUgcGF0aCAob2Z0ZW4gYHVuZGVmaW5lZGApLlxuICpcbiAqIEBwYXJhbSBleGVQYXRoIC0gQWJzb2x1dGUgcGF0aCB0byB0aGUgT2JzaWRpYW4gZXhlY3V0YWJsZS5cbiAqIEByZXR1cm5zIFRoZSBgeC55LnpgIHZlcnNpb24sIG9yIGB1bmRlZmluZWRgIGlmIGl0IGNhbm5vdCBiZSBkZXRlcm1pbmVkLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZGV0ZWN0SW5zdGFsbGVkU2hlbGxWZXJzaW9uKGV4ZVBhdGg6IHN0cmluZyk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIGlmIChwcm9jZXNzLnBsYXRmb3JtID09PSAnd2luMzInKSB7XG4gICAgcmV0dXJuIGRldGVjdFdpbmRvd3NGaWxlVmVyc2lvbihleGVQYXRoKTtcbiAgfVxuXG4gIGlmIChwcm9jZXNzLnBsYXRmb3JtID09PSAnZGFyd2luJykge1xuICAgIHJldHVybiBkZXRlY3RNYWNCdW5kbGVWZXJzaW9uKGV4ZVBhdGgpO1xuICB9XG5cbiAgcmV0dXJuIGRldGVjdFZlcnNpb25Gcm9tUGF0aChleGVQYXRoKTtcbn1cblxuLyoqXG4gKiBFbnN1cmVzIGEgcG9ydGFibGUgT2JzaWRpYW4gc2hlbGwgZm9yIHRoZSBnaXZlbiB2ZXJzaW9uIGlzIGV4dHJhY3RlZCBpbnRvIHRoZVxuICogY2FjaGUsIGRvd25sb2FkaW5nIGFuZCBleHRyYWN0aW5nIGl0cyBHaXRIdWIgcmVsZWFzZSBhc3NldCBpZiBuZWNlc3NhcnkuXG4gKlxuICogQHBhcmFtIHZlcnNpb24gLSBBIGNvbmNyZXRlIHB1YmxpYyBgeC55LnpgIHZlcnNpb24uXG4gKiBAcmV0dXJucyBUaGUgYWJzb2x1dGUgcGF0aCB0byB0aGUgY2FjaGVkIHNoZWxsIGV4ZWN1dGFibGUuXG4gKiBAdGhyb3dzIEVycm9yIGlmIHRoZSBhc3NldCBjYW5ub3QgYmUgZG93bmxvYWRlZCBvciBleHRyYWN0ZWQuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBlbnN1cmVTaGVsbENhY2hlZCh2ZXJzaW9uOiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4ge1xuICBjb25zdCBzaGVsbERpciA9IGpvaW4oU0hFTExfQ0FDSEVfRElSLCB2ZXJzaW9uKTtcbiAgY29uc3QgZXhlUGF0aCA9IGdldENhY2hlZFNoZWxsRXhlUGF0aChzaGVsbERpcik7XG4gIGlmIChleGlzdHNTeW5jKGV4ZVBhdGgpKSB7XG4gICAgbG9nKGBbaW5zdGFsbGVyXSBVc2luZyBjYWNoZWQgc2hlbGwgZm9yICR7dmVyc2lvbn0uYCk7XG4gICAgcmV0dXJuIGV4ZVBhdGg7XG4gIH1cblxuICBta2RpclN5bmMoc2hlbGxEaXIsIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xuICBjb25zdCBhc3NldE5hbWUgPSBnZXRJbnN0YWxsZXJBc3NldE5hbWUodmVyc2lvbik7XG4gIGNvbnN0IGFzc2V0UGF0aCA9IGpvaW4oc2hlbGxEaXIsIGFzc2V0TmFtZSk7XG4gIGF3YWl0IGRvd25sb2FkUmVsZWFzZUFzc2V0KHZlcnNpb24sIGFzc2V0TmFtZSwgYXNzZXRQYXRoKTtcbiAgZXh0cmFjdFNoZWxsKGFzc2V0UGF0aCwgc2hlbGxEaXIpO1xuICBybVN5bmMoYXNzZXRQYXRoLCB7IGZvcmNlOiB0cnVlIH0pO1xuXG4gIGlmICghZXhpc3RzU3luYyhleGVQYXRoKSkge1xuICAgIHRocm93IG5ldyBFcnJvcihgRXh0cmFjdGVkIE9ic2lkaWFuIHNoZWxsICR7dmVyc2lvbn0gYnV0IGV4ZWN1dGFibGUgbm90IGZvdW5kIGF0ICR7ZXhlUGF0aH0uYCk7XG4gIH1cbiAgbG9nKGBbaW5zdGFsbGVyXSBFeHRyYWN0ZWQgc2hlbGwgJHt2ZXJzaW9ufSAtPiAke2V4ZVBhdGh9YCk7XG4gIHJldHVybiBleGVQYXRoO1xufVxuXG4vKipcbiAqIFRocm93cyBhIGRlc2NyaXB0aXZlIGVycm9yIGlmIGEgcmVxdWlyZWQgY29tbWFuZCBpcyBub3Qgb24gYFBBVEhgLlxuICpcbiAqIEBwYXJhbSBjb21tYW5kIC0gVGhlIGNvbW1hbmQgbmFtZS5cbiAqIEBwYXJhbSBoaW50IC0gQWN0aW9uYWJsZSBndWlkYW5jZSBhcHBlbmRlZCB0byB0aGUgZXJyb3IuXG4gKi9cbmZ1bmN0aW9uIGFzc2VydENvbW1hbmRBdmFpbGFibGUoY29tbWFuZDogc3RyaW5nLCBoaW50OiBzdHJpbmcpOiB2b2lkIHtcbiAgY29uc3QgcHJvYmUgPSBwcm9jZXNzLnBsYXRmb3JtID09PSAnd2luMzInID8gJ3doZXJlLmV4ZScgOiAnd2hpY2gnO1xuICBjb25zdCByZXN1bHQgPSBzcGF3blN5bmMocHJvYmUsIFtjb21tYW5kXSwgeyBzdGRpbzogJ2lnbm9yZScgfSk7XG4gIGlmIChyZXN1bHQuc3RhdHVzICE9PSAwKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBSZXF1aXJlZCBjb21tYW5kIFwiJHtjb21tYW5kfVwiIHdhcyBub3QgZm91bmQgb24gUEFUSC4gJHtoaW50fWApO1xuICB9XG59XG5cbi8qKlxuICogUmVhZHMgYENGQnVuZGxlU2hvcnRWZXJzaW9uU3RyaW5nYCBmcm9tIGEgbWFjT1MgYXBwIGJ1bmRsZSdzIGBJbmZvLnBsaXN0YC5cbiAqXG4gKiBAcGFyYW0gZXhlUGF0aCAtIFBhdGggdG8gYC4uLi9PYnNpZGlhbi5hcHAvQ29udGVudHMvTWFjT1MvT2JzaWRpYW5gLlxuICogQHJldHVybnMgVGhlIGB4LnkuemAgdmVyc2lvbiwgb3IgYHVuZGVmaW5lZGAuXG4gKi9cbmZ1bmN0aW9uIGRldGVjdE1hY0J1bmRsZVZlcnNpb24oZXhlUGF0aDogc3RyaW5nKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgdHJ5IHtcbiAgICBjb25zdCBjb250ZW50c0RpciA9IGRpcm5hbWUoZGlybmFtZShleGVQYXRoKSk7XG4gICAgY29uc3QgcGxpc3QgPSByZWFkRmlsZVN5bmMoam9pbihjb250ZW50c0RpciwgJ0luZm8ucGxpc3QnKSwgJ3V0Zi04Jyk7XG4gICAgY29uc3QgbWF0Y2ggPSBNQUNfUExJU1RfVkVSU0lPTl9QQVRURVJOLmV4ZWMocGxpc3QpO1xuICAgIHJldHVybiBtYXRjaD8uZ3JvdXBzPy5bJ3ZlcnNpb24nXTtcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxufVxuXG4vKipcbiAqIEJlc3QtZWZmb3J0IHBhcnNlIG9mIGFuIGB4LnkuemAgdmVyc2lvbiBlbWJlZGRlZCBpbiBhIHBhdGguXG4gKlxuICogQHBhcmFtIHZhbHVlIC0gVGhlIHBhdGggb3Igc3RyaW5nIHRvIHNjYW4uXG4gKiBAcmV0dXJucyBUaGUgZmlyc3QgYHgueS56YCBtYXRjaCwgb3IgYHVuZGVmaW5lZGAuXG4gKi9cbmZ1bmN0aW9uIGRldGVjdFZlcnNpb25Gcm9tUGF0aCh2YWx1ZTogc3RyaW5nKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgY29uc3QgbWF0Y2ggPSAvKD88dmVyc2lvbj5cXGQrXFwuXFxkK1xcLlxcZCspLy5leGVjKHZhbHVlKTtcbiAgcmV0dXJuIG1hdGNoPy5ncm91cHM/LlsndmVyc2lvbiddO1xufVxuXG4vKipcbiAqIFJlYWRzIHRoZSBQRSBgRmlsZVZlcnNpb25gIG9mIGEgV2luZG93cyBleGVjdXRhYmxlIHZpYSBQb3dlclNoZWxsLlxuICpcbiAqIEBwYXJhbSBleGVQYXRoIC0gQWJzb2x1dGUgcGF0aCB0byB0aGUgZXhlY3V0YWJsZS5cbiAqIEByZXR1cm5zIFRoZSBgeC55LnpgIHZlcnNpb24sIG9yIGB1bmRlZmluZWRgLlxuICovXG5mdW5jdGlvbiBkZXRlY3RXaW5kb3dzRmlsZVZlcnNpb24oZXhlUGF0aDogc3RyaW5nKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgdHJ5IHtcbiAgICBjb25zdCBvdXRwdXQgPSBleGVjRmlsZVN5bmMoXG4gICAgICAncG93ZXJzaGVsbCcsXG4gICAgICBbJy1Ob1Byb2ZpbGUnLCAnLUNvbW1hbmQnLCBgKEdldC1JdGVtIC1MaXRlcmFsUGF0aCAke0pTT04uc3RyaW5naWZ5KGV4ZVBhdGgpfSkuVmVyc2lvbkluZm8uRmlsZVZlcnNpb25gXSxcbiAgICAgIHsgZW5jb2Rpbmc6ICd1dGYtOCcgfVxuICAgICk7XG4gICAgY29uc3QgdmVyc2lvbiA9IG91dHB1dC50cmltKCk7XG4gICAgcmV0dXJuIHZlcnNpb24ubGVuZ3RoID4gMCA/IHZlcnNpb24gOiB1bmRlZmluZWQ7XG4gIH0gY2F0Y2gge1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbn1cblxuLyoqXG4gKiBEb3dubG9hZHMgYSBHaXRIdWIgcmVsZWFzZSBhc3NldCBmb3IgYSB2ZXJzaW9uIHRvIGEgZGVzdGluYXRpb24gZmlsZS5cbiAqXG4gKiBAcGFyYW0gdmVyc2lvbiAtIFRoZSByZWxlYXNlIHZlcnNpb24gKHRhZyBgdjx2ZXJzaW9uPmApLlxuICogQHBhcmFtIGFzc2V0TmFtZSAtIFRoZSBhc3NldCBmaWxlIG5hbWUuXG4gKiBAcGFyYW0gZGVzdCAtIERlc3RpbmF0aW9uIGZpbGUgcGF0aC5cbiAqIEB0aHJvd3MgRXJyb3IgaWYgdGhlIGRvd25sb2FkIGZhaWxzIChlLmcuIG5vIHB1YmxpYyBpbnN0YWxsZXIgZm9yIHRoZSB2ZXJzaW9uKS5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gZG93bmxvYWRSZWxlYXNlQXNzZXQodmVyc2lvbjogc3RyaW5nLCBhc3NldE5hbWU6IHN0cmluZywgZGVzdDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IHVybCA9IGBodHRwczovL2dpdGh1Yi5jb20vb2JzaWRpYW5tZC9vYnNpZGlhbi1yZWxlYXNlcy9yZWxlYXNlcy9kb3dubG9hZC92JHt2ZXJzaW9ufS8ke2Fzc2V0TmFtZX1gO1xuICBsb2coYFtpbnN0YWxsZXJdIERvd25sb2FkaW5nIGluc3RhbGxlciAke3ZlcnNpb259IGZyb20gJHt1cmx9IC4uLmApO1xuICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGZldGNoKHVybCwgeyBoZWFkZXJzOiB7ICdVc2VyLUFnZW50JzogRE9XTkxPQURfVVNFUl9BR0VOVCB9IH0pO1xuICBpZiAoIXJlc3BvbnNlLm9rKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgYEZhaWxlZCB0byBkb3dubG9hZCBPYnNpZGlhbiBpbnN0YWxsZXIgJHt2ZXJzaW9ufTogSFRUUCAke1N0cmluZyhyZXNwb25zZS5zdGF0dXMpfSBmcm9tICR7dXJsfS4gYFxuICAgICAgICArICdDYXRhbHlzdC9iZXRhIHZlcnNpb25zIGhhdmUgbm8gcHVibGljIGluc3RhbGxlciBcdTIwMTQgcGluIGFuIGFzYXIgdmVyc2lvbiBvbiBhIHB1YmxpYy9pbnN0YWxsZWQgc2hlbGwgaW5zdGVhZC4nXG4gICAgKTtcbiAgfVxuICB3cml0ZUZpbGVTeW5jKGRlc3QsIEJ1ZmZlci5mcm9tKGF3YWl0IHJlc3BvbnNlLmFycmF5QnVmZmVyKCkpKTtcbn1cblxuLyoqXG4gKiBFeHRyYWN0cyBhIExpbnV4IGAudGFyLmd6YCBwb3J0YWJsZSBidWlsZC5cbiAqXG4gKiBAcGFyYW0gYXNzZXRQYXRoIC0gUGF0aCB0byB0aGUgZG93bmxvYWRlZCBgLnRhci5nemAuXG4gKiBAcGFyYW0gc2hlbGxEaXIgLSBEZXN0aW5hdGlvbiBzaGVsbCBkaXJlY3RvcnkuXG4gKi9cbmZ1bmN0aW9uIGV4dHJhY3RMaW51eFNoZWxsKGFzc2V0UGF0aDogc3RyaW5nLCBzaGVsbERpcjogc3RyaW5nKTogdm9pZCB7XG4gIHJ1bigndGFyJywgWyd4emYnLCBhc3NldFBhdGgsICctQycsIHNoZWxsRGlyLCAnLS1zdHJpcC1jb21wb25lbnRzPTEnXSk7XG59XG5cbi8qKlxuICogRXh0cmFjdHMgYSBtYWNPUyBgLmRtZ2AgYnkgbW91bnRpbmcgaXQgYW5kIGNvcHlpbmcgdGhlIGFwcCBidW5kbGUuXG4gKlxuICogQHBhcmFtIGFzc2V0UGF0aCAtIFBhdGggdG8gdGhlIGRvd25sb2FkZWQgYC5kbWdgLlxuICogQHBhcmFtIHNoZWxsRGlyIC0gRGVzdGluYXRpb24gc2hlbGwgZGlyZWN0b3J5LlxuICovXG5mdW5jdGlvbiBleHRyYWN0TWFjU2hlbGwoYXNzZXRQYXRoOiBzdHJpbmcsIHNoZWxsRGlyOiBzdHJpbmcpOiB2b2lkIHtcbiAgY29uc3QgbW91bnRQb2ludCA9IGpvaW4oc2hlbGxEaXIsICdfX21udCcpO1xuICBta2RpclN5bmMobW91bnRQb2ludCwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gIHJ1bignaGRpdXRpbCcsIFsnYXR0YWNoJywgJy1ub2Jyb3dzZScsICctbW91bnRwb2ludCcsIG1vdW50UG9pbnQsIGFzc2V0UGF0aF0pO1xuICB0cnkge1xuICAgIHJ1bignY3AnLCBbJy1SJywgam9pbihtb3VudFBvaW50LCAnT2JzaWRpYW4uYXBwJyksIHNoZWxsRGlyXSk7XG4gIH0gZmluYWxseSB7XG4gICAgcnVuKCdoZGl1dGlsJywgWydkZXRhY2gnLCBtb3VudFBvaW50XSk7XG4gIH1cbiAgcm1TeW5jKG1vdW50UG9pbnQsIHsgZm9yY2U6IHRydWUsIHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcbn1cblxuLyoqXG4gKiBFeHRyYWN0cyBhIGRvd25sb2FkZWQgaW5zdGFsbGVyIGFzc2V0IGludG8gYSBzaGVsbCBkaXJlY3RvcnksIHBlciBwbGF0Zm9ybS5cbiAqXG4gKiBAcGFyYW0gYXNzZXRQYXRoIC0gVGhlIGRvd25sb2FkZWQgYXNzZXQgcGF0aC5cbiAqIEBwYXJhbSBzaGVsbERpciAtIFRoZSBkZXN0aW5hdGlvbiBzaGVsbCBkaXJlY3RvcnkuXG4gKi9cbmZ1bmN0aW9uIGV4dHJhY3RTaGVsbChhc3NldFBhdGg6IHN0cmluZywgc2hlbGxEaXI6IHN0cmluZyk6IHZvaWQge1xuICBpZiAocHJvY2Vzcy5wbGF0Zm9ybSA9PT0gJ3dpbjMyJykge1xuICAgIGV4dHJhY3RXaW5kb3dzU2hlbGwoYXNzZXRQYXRoLCBzaGVsbERpcik7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgaWYgKHByb2Nlc3MucGxhdGZvcm0gPT09ICdkYXJ3aW4nKSB7XG4gICAgZXh0cmFjdE1hY1NoZWxsKGFzc2V0UGF0aCwgc2hlbGxEaXIpO1xuICAgIHJldHVybjtcbiAgfVxuXG4gIGV4dHJhY3RMaW51eFNoZWxsKGFzc2V0UGF0aCwgc2hlbGxEaXIpO1xufVxuXG4vKipcbiAqIEV4dHJhY3RzIGEgV2luZG93cyBOU0lTIGluc3RhbGxlcidzIGlubmVyIGFwcCBwYXlsb2FkIHZpYSA3LVppcC5cbiAqXG4gKiBUaGUgYE9ic2lkaWFuLTx2Pi5leGVgIE5TSVMgaW5zdGFsbGVyIGNvbnRhaW5zIGAkUExVR0lOU0RJUi9hcHAtNjQuN3pgLCB3aGljaFxuICogaG9sZHMgdGhlIHBvcnRhYmxlIGFwcCAobWlycm9ycyBob3cgdGhlIHNjb29wIG1hbmlmZXN0IGluc3RhbGxzIE9ic2lkaWFuKS5cbiAqXG4gKiBAcGFyYW0gYXNzZXRQYXRoIC0gUGF0aCB0byB0aGUgZG93bmxvYWRlZCBgLmV4ZWAuXG4gKiBAcGFyYW0gc2hlbGxEaXIgLSBEZXN0aW5hdGlvbiBzaGVsbCBkaXJlY3RvcnkuXG4gKi9cbmZ1bmN0aW9uIGV4dHJhY3RXaW5kb3dzU2hlbGwoYXNzZXRQYXRoOiBzdHJpbmcsIHNoZWxsRGlyOiBzdHJpbmcpOiB2b2lkIHtcbiAgYXNzZXJ0Q29tbWFuZEF2YWlsYWJsZSgnN3onLCAnSW5zdGFsbCA3LVppcCAoZS5nLiBgc2Nvb3AgaW5zdGFsbCA3emlwYCkgdG8gZXh0cmFjdCBhIHBpbm5lZCBPYnNpZGlhbiBpbnN0YWxsZXIuJyk7XG4gIGNvbnN0IG5zaXNFeHRyYWN0RGlyID0gam9pbihzaGVsbERpciwgJ19fbnNpcycpO1xuICBydW4oJzd6JywgWyd4JywgJy15JywgYC1vJHtuc2lzRXh0cmFjdERpcn1gLCBhc3NldFBhdGhdKTtcbiAgY29uc3QgaW5uZXJBcmNoaXZlID0gam9pbihuc2lzRXh0cmFjdERpciwgJyRQTFVHSU5TRElSJywgJ2FwcC02NC43eicpO1xuICBydW4oJzd6JywgWyd4JywgJy15JywgYC1vJHtzaGVsbERpcn1gLCBpbm5lckFyY2hpdmVdKTtcbiAgcm1TeW5jKG5zaXNFeHRyYWN0RGlyLCB7IGZvcmNlOiB0cnVlLCByZWN1cnNpdmU6IHRydWUgfSk7XG59XG5cbi8qKlxuICogUmV0dXJucyB0aGUgZXhwZWN0ZWQgY2FjaGVkIHNoZWxsIGV4ZWN1dGFibGUgcGF0aCBmb3IgdGhlIGN1cnJlbnQgcGxhdGZvcm0uXG4gKlxuICogQHBhcmFtIHNoZWxsRGlyIC0gVGhlIHNoZWxsIGNhY2hlIGRpcmVjdG9yeSBmb3IgYSB2ZXJzaW9uLlxuICogQHJldHVybnMgVGhlIGV4ZWN1dGFibGUgcGF0aC5cbiAqL1xuZnVuY3Rpb24gZ2V0Q2FjaGVkU2hlbGxFeGVQYXRoKHNoZWxsRGlyOiBzdHJpbmcpOiBzdHJpbmcge1xuICBpZiAocHJvY2Vzcy5wbGF0Zm9ybSA9PT0gJ3dpbjMyJykge1xuICAgIHJldHVybiBqb2luKHNoZWxsRGlyLCAnT2JzaWRpYW4uZXhlJyk7XG4gIH1cblxuICBpZiAocHJvY2Vzcy5wbGF0Zm9ybSA9PT0gJ2RhcndpbicpIHtcbiAgICByZXR1cm4gam9pbihzaGVsbERpciwgJ09ic2lkaWFuLmFwcCcsICdDb250ZW50cycsICdNYWNPUycsICdPYnNpZGlhbicpO1xuICB9XG5cbiAgcmV0dXJuIGpvaW4oc2hlbGxEaXIsICdvYnNpZGlhbicpO1xufVxuXG4vKipcbiAqIFJldHVybnMgdGhlIEdpdEh1YiByZWxlYXNlIGFzc2V0IG5hbWUgZm9yIHRoZSBjdXJyZW50IHBsYXRmb3JtLlxuICpcbiAqIEBwYXJhbSB2ZXJzaW9uIC0gVGhlIHJlbGVhc2UgdmVyc2lvbi5cbiAqIEByZXR1cm5zIFRoZSBhc3NldCBmaWxlIG5hbWUuXG4gKi9cbmZ1bmN0aW9uIGdldEluc3RhbGxlckFzc2V0TmFtZSh2ZXJzaW9uOiBzdHJpbmcpOiBzdHJpbmcge1xuICBpZiAocHJvY2Vzcy5wbGF0Zm9ybSA9PT0gJ3dpbjMyJykge1xuICAgIHJldHVybiBgT2JzaWRpYW4tJHt2ZXJzaW9ufS5leGVgO1xuICB9XG5cbiAgaWYgKHByb2Nlc3MucGxhdGZvcm0gPT09ICdkYXJ3aW4nKSB7XG4gICAgcmV0dXJuIGBPYnNpZGlhbi0ke3ZlcnNpb259LmRtZ2A7XG4gIH1cblxuICByZXR1cm4gYG9ic2lkaWFuLSR7dmVyc2lvbn0udGFyLmd6YDtcbn1cblxuLyoqXG4gKiBSdW5zIGEgY29tbWFuZCBzeW5jaHJvbm91c2x5LCB0aHJvd2luZyBvbiBhIG5vbi16ZXJvIGV4aXQuXG4gKlxuICogQHBhcmFtIGNvbW1hbmQgLSBUaGUgY29tbWFuZC5cbiAqIEBwYXJhbSBhcmdzIC0gVGhlIGFyZ3VtZW50cy5cbiAqL1xuZnVuY3Rpb24gcnVuKGNvbW1hbmQ6IHN0cmluZywgYXJnczogc3RyaW5nW10pOiB2b2lkIHtcbiAgY29uc3QgcmVzdWx0ID0gc3Bhd25TeW5jKGNvbW1hbmQsIGFyZ3MsIHsgc3RkaW86ICdpZ25vcmUnIH0pO1xuICBpZiAocmVzdWx0LnN0YXR1cyAhPT0gMCkge1xuICAgIHRocm93IG5ldyBFcnJvcihgQ29tbWFuZCBmYWlsZWQ6ICR7Y29tbWFuZH0gJHthcmdzLm1hcCgoYXJnKSA9PiBiYXNlbmFtZShhcmcpKS5qb2luKCcgJyl9IChleGl0ICR7U3RyaW5nKHJlc3VsdC5zdGF0dXMpfSlgKTtcbiAgfVxufVxuXG4vKiB2OCBpZ25vcmUgc3RvcCAqL1xuIl0sCiAgIm1hcHBpbmdzIjogIkFBbUJBO0FBQUEsRUFDRTtBQUFBLEVBQ0E7QUFBQSxPQUNLO0FBQ1A7QUFBQSxFQUNFO0FBQUEsRUFDQTtBQUFBLEVBQ0E7QUFBQSxFQUNBO0FBQUEsRUFDQTtBQUFBLE9BQ0s7QUFDUCxTQUFTLGNBQWM7QUFDdkI7QUFBQSxFQUNFO0FBQUEsRUFDQTtBQUFBLEVBQ0E7QUFBQSxPQUNLO0FBQ1AsT0FBTyxhQUFhO0FBRXBCLFNBQVMsV0FBVztBQUtwQixNQUFNLHNCQUFzQjtBQUU1QixNQUFNLGFBQWEsS0FBSyxPQUFPLEdBQUcsOEJBQThCO0FBQ2hFLE1BQU0sa0JBQWtCLEtBQUssWUFBWSxhQUFhO0FBQ3RELE1BQU0sNEJBQTRCO0FBdUIzQixTQUFTLDRCQUE0QixTQUFxQztBQUMvRSxNQUFJLFFBQVEsYUFBYSxTQUFTO0FBQ2hDLFdBQU8seUJBQXlCLE9BQU87QUFBQSxFQUN6QztBQUVBLE1BQUksUUFBUSxhQUFhLFVBQVU7QUFDakMsV0FBTyx1QkFBdUIsT0FBTztBQUFBLEVBQ3ZDO0FBRUEsU0FBTyxzQkFBc0IsT0FBTztBQUN0QztBQVVBLGVBQXNCLGtCQUFrQixTQUFrQztBQUN4RSxRQUFNLFdBQVcsS0FBSyxpQkFBaUIsT0FBTztBQUM5QyxRQUFNLFVBQVUsc0JBQXNCLFFBQVE7QUFDOUMsTUFBSSxXQUFXLE9BQU8sR0FBRztBQUN2QixRQUFJLHNDQUFzQyxPQUFPLEdBQUc7QUFDcEQsV0FBTztBQUFBLEVBQ1Q7QUFFQSxZQUFVLFVBQVUsRUFBRSxXQUFXLEtBQUssQ0FBQztBQUN2QyxRQUFNLFlBQVksc0JBQXNCLE9BQU87QUFDL0MsUUFBTSxZQUFZLEtBQUssVUFBVSxTQUFTO0FBQzFDLFFBQU0scUJBQXFCLFNBQVMsV0FBVyxTQUFTO0FBQ3hELGVBQWEsV0FBVyxR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
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file
|
|
3
|
+
*
|
|
4
|
+
* Launches and manages a harness-owned, isolated Obsidian desktop instance.
|
|
5
|
+
*
|
|
6
|
+
* The instance runs against a dedicated `--user-data-dir` (so it never touches
|
|
7
|
+
* the user's Obsidian config, registry, or running window) and exposes CDP on a
|
|
8
|
+
* dedicated `--remote-debugging-port`. Because Electron's single-instance lock
|
|
9
|
+
* is keyed to the user-data dir, the owned instance runs in parallel with the
|
|
10
|
+
* user's own Obsidian. Confirmed by the Phase 0 spike (see the project plan).
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Parameters for {@link launchOwnedObsidianInstance}.
|
|
14
|
+
*/
|
|
15
|
+
export interface LaunchOwnedObsidianInstanceParams {
|
|
16
|
+
/**
|
|
17
|
+
* CDP host to bind/poll.
|
|
18
|
+
*
|
|
19
|
+
* @default `'127.0.0.1'`
|
|
20
|
+
*/
|
|
21
|
+
readonly cdpHost?: string;
|
|
22
|
+
/** Absolute path to the Obsidian executable (shell) to launch. */
|
|
23
|
+
readonly exePath: string;
|
|
24
|
+
/** Absolute path to the isolated user-data dir to pass via `--user-data-dir`. */
|
|
25
|
+
readonly userDataDir: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* A running, harness-owned Obsidian instance.
|
|
29
|
+
*/
|
|
30
|
+
export interface OwnedObsidianInstance {
|
|
31
|
+
/** Base CDP URL, e.g. `http://127.0.0.1:51888`. */
|
|
32
|
+
readonly cdpUrl: string;
|
|
33
|
+
/** Kills the instance and its entire process tree. */
|
|
34
|
+
kill(): void;
|
|
35
|
+
/** The CDP remote-debugging port the instance was launched with. */
|
|
36
|
+
readonly port: number;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Launches an isolated, harness-owned Obsidian instance and waits until its CDP
|
|
40
|
+
* endpoint is serving page targets.
|
|
41
|
+
*
|
|
42
|
+
* @param params - Launch parameters.
|
|
43
|
+
* @returns The running owned instance.
|
|
44
|
+
* @throws Error if CDP does not become reachable within the timeout.
|
|
45
|
+
*/
|
|
46
|
+
export declare function launchOwnedObsidianInstance(params: LaunchOwnedObsidianInstanceParams): Promise<OwnedObsidianInstance>;
|
|
47
|
+
/**
|
|
48
|
+
* Picks a free TCP port by binding to port `0` and reading the assigned port.
|
|
49
|
+
*
|
|
50
|
+
* There is a small time-of-check/time-of-use window between releasing the port
|
|
51
|
+
* here and Obsidian binding it; in practice it is negligible for test runs.
|
|
52
|
+
*
|
|
53
|
+
* @returns A free TCP port.
|
|
54
|
+
*/
|
|
55
|
+
export declare function pickFreePort(): Promise<number>;
|