obsidian-integration-testing 17.2.0 → 17.3.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/dist/lib/cjs/apply-obsidian-theme.cjs +95 -0
- package/dist/lib/cjs/apply-obsidian-theme.d.cts +99 -0
- package/dist/lib/cjs/capture-obsidian-screenshot.cjs +17 -1
- package/dist/lib/cjs/capture-obsidian-screenshot.d.cts +41 -2
- package/dist/lib/cjs/deterministic-raster.cjs +31 -0
- package/dist/lib/cjs/deterministic-raster.d.cts +37 -0
- package/dist/lib/cjs/eval-in-obsidian.cjs +1 -1
- package/dist/lib/cjs/eval-in-obsidian.d.cts +60 -0
- package/dist/lib/cjs/index.cjs +9 -1
- package/dist/lib/cjs/index.d.cts +4 -0
- package/dist/lib/cjs/library.cjs +1 -1
- package/dist/lib/cjs/namespace-bootstrap.cjs +51 -7
- package/dist/lib/cjs/pin-window-focus.cjs +60 -0
- package/dist/lib/cjs/pin-window-focus.d.cts +76 -0
- package/dist/lib/cjs/soft-keyboard.cjs +16 -1
- package/dist/lib/cjs/soft-keyboard.d.cts +2 -1
- package/dist/lib/cjs/transport-desktop-cdp.cjs +3 -1
- package/dist/lib/esm/apply-obsidian-theme.d.mts +99 -0
- package/dist/lib/esm/apply-obsidian-theme.mjs +70 -0
- package/dist/lib/esm/capture-obsidian-screenshot.d.mts +41 -2
- package/dist/lib/esm/capture-obsidian-screenshot.mjs +17 -1
- package/dist/lib/esm/deterministic-raster.d.mts +37 -0
- package/dist/lib/esm/deterministic-raster.mjs +7 -0
- package/dist/lib/esm/eval-in-obsidian.d.mts +60 -0
- package/dist/lib/esm/eval-in-obsidian.mjs +1 -1
- package/dist/lib/esm/index.d.mts +4 -0
- package/dist/lib/esm/index.mjs +9 -1
- package/dist/lib/esm/library.mjs +1 -1
- package/dist/lib/esm/namespace-bootstrap.mjs +51 -7
- package/dist/lib/esm/pin-window-focus.d.mts +76 -0
- package/dist/lib/esm/pin-window-focus.mjs +36 -0
- package/dist/lib/esm/soft-keyboard.d.mts +2 -1
- package/dist/lib/esm/soft-keyboard.mjs +16 -1
- package/dist/lib/esm/transport-desktop-cdp.mjs +3 -1
- package/package.json +1 -1
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file
|
|
3
|
+
*
|
|
4
|
+
* Switches the driven Obsidian to its dark or light theme, and makes the switch
|
|
5
|
+
* survive a config reload.
|
|
6
|
+
*
|
|
7
|
+
* `app.changeTheme` only sets the theme in the in-memory config and SCHEDULES
|
|
8
|
+
* the save, a second later (`requestSaveConfig` is debounced). Until that save
|
|
9
|
+
* lands, any file-watcher event on `.obsidian/app.json` or
|
|
10
|
+
* `.obsidian/appearance.json` makes Obsidian run `vault.reloadConfig`, which
|
|
11
|
+
* re-reads both files and deletes every in-memory key the disk does not have —
|
|
12
|
+
* `theme` included. The body then falls back to the light theme, and a capture
|
|
13
|
+
* suite that set the dark theme shoots every frame light, silently writing over
|
|
14
|
+
* the frames it has committed. Read from the 1.14.2 `app.js`, and reproduced in a
|
|
15
|
+
* plugin's capture suite: one external rewrite of `app.json` straight after
|
|
16
|
+
* `changeTheme` turned all five of its desktop frames light.
|
|
17
|
+
*
|
|
18
|
+
* {@link applyObsidianTheme} saves the config at once, so a reload finds the
|
|
19
|
+
* theme on disk and has nothing to drop, and waits until the body carries the
|
|
20
|
+
* theme's class and `appearance.json` carries its name. It also records the
|
|
21
|
+
* theme it applied, so `captureObsidianScreenshot` can refuse a frame the theme
|
|
22
|
+
* has left since.
|
|
23
|
+
*/
|
|
24
|
+
import type { ObsidianTransport } from './transport.mjs';
|
|
25
|
+
/**
|
|
26
|
+
* Parameters for {@link applyObsidianTheme}.
|
|
27
|
+
*/
|
|
28
|
+
export interface ApplyObsidianThemeParams {
|
|
29
|
+
/**
|
|
30
|
+
* The theme to switch to.
|
|
31
|
+
*/
|
|
32
|
+
readonly theme: ObsidianTheme;
|
|
33
|
+
/**
|
|
34
|
+
* How long to wait for the theme to be applied and saved.
|
|
35
|
+
*
|
|
36
|
+
* @default 10000
|
|
37
|
+
*/
|
|
38
|
+
readonly timeoutInMilliseconds?: number;
|
|
39
|
+
/**
|
|
40
|
+
* Override the transport. When omitted, the transport the current test
|
|
41
|
+
* context is driving is used.
|
|
42
|
+
*/
|
|
43
|
+
readonly transport?: ObsidianTransport;
|
|
44
|
+
/**
|
|
45
|
+
* The vault whose Obsidian window to switch. When omitted, the current test
|
|
46
|
+
* context's vault is used.
|
|
47
|
+
*/
|
|
48
|
+
readonly vaultPath?: string;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Parameters for {@link assertObsidianThemeUnchanged}.
|
|
52
|
+
*/
|
|
53
|
+
export interface AssertObsidianThemeUnchangedParams {
|
|
54
|
+
/**
|
|
55
|
+
* What the refusal is refusing, for its message, e.g. `capture a screenshot`.
|
|
56
|
+
*/
|
|
57
|
+
readonly action: string;
|
|
58
|
+
/**
|
|
59
|
+
* Override the transport. When omitted, the transport the current test
|
|
60
|
+
* context is driving is used.
|
|
61
|
+
*/
|
|
62
|
+
readonly transport?: ObsidianTransport;
|
|
63
|
+
/**
|
|
64
|
+
* The vault whose Obsidian window to check. When omitted, the current test
|
|
65
|
+
* context's vault is used.
|
|
66
|
+
*/
|
|
67
|
+
readonly vaultPath?: string;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* One of Obsidian's two built-in base themes.
|
|
71
|
+
*/
|
|
72
|
+
export type ObsidianTheme = 'dark' | 'light';
|
|
73
|
+
/**
|
|
74
|
+
* Switches Obsidian to its dark or light theme, saves the config at once, and
|
|
75
|
+
* waits until the theme is both on screen and on disk.
|
|
76
|
+
*
|
|
77
|
+
* Use it instead of `app.changeTheme` in a capture suite: see the module
|
|
78
|
+
* comment for the reload that silently undoes a bare `changeTheme`. The theme
|
|
79
|
+
* is recorded, and `captureObsidianScreenshot` then refuses any frame whose body
|
|
80
|
+
* is no longer in it, so a theme lost after this call fails the capture by name
|
|
81
|
+
* instead of rewriting a committed frame.
|
|
82
|
+
*
|
|
83
|
+
* @param params - The theme, how long to wait, and transport / vault overrides.
|
|
84
|
+
* @returns A {@link Promise} that resolves once the theme is applied and saved.
|
|
85
|
+
* @throws Error if the theme is not applied and saved within the timeout.
|
|
86
|
+
*/
|
|
87
|
+
export declare function applyObsidianTheme(params: ApplyObsidianThemeParams): Promise<void>;
|
|
88
|
+
/**
|
|
89
|
+
* Throws when the body has left the theme {@link applyObsidianTheme} applied.
|
|
90
|
+
*
|
|
91
|
+
* Nothing is checked when no theme was applied through it, since there is then
|
|
92
|
+
* no expectation to hold the frame to.
|
|
93
|
+
*
|
|
94
|
+
* @param params - What is being refused, and transport / vault overrides.
|
|
95
|
+
* @returns A {@link Promise} that resolves when the theme still holds, or none
|
|
96
|
+
* was applied.
|
|
97
|
+
* @throws Error naming the applied theme and the one on screen, if they differ.
|
|
98
|
+
*/
|
|
99
|
+
export declare function assertObsidianThemeUnchanged(params: AssertObsidianThemeUnchangedParams): Promise<void>;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { evalInObsidian } from "./eval-in-obsidian.mjs";
|
|
2
|
+
import { normalizeOptionalProperties } from "./normalize-optional-properties.mjs";
|
|
3
|
+
const DEFAULT_TIMEOUT_IN_MILLISECONDS = 1e4;
|
|
4
|
+
async function applyObsidianTheme(params) {
|
|
5
|
+
const {
|
|
6
|
+
theme,
|
|
7
|
+
timeoutInMilliseconds = DEFAULT_TIMEOUT_IN_MILLISECONDS,
|
|
8
|
+
transport,
|
|
9
|
+
vaultPath
|
|
10
|
+
} = params;
|
|
11
|
+
await evalInObsidian(normalizeOptionalProperties({
|
|
12
|
+
async callback({ app, lib: { waitUntil }, theme: requestedTheme, timeoutInMilliseconds: timeout }) {
|
|
13
|
+
const themeName = requestedTheme === "dark" ? "obsidian" : "moonstone";
|
|
14
|
+
const bodyClass = `theme-${requestedTheme}`;
|
|
15
|
+
app.changeTheme(themeName);
|
|
16
|
+
await app.vault.saveConfig();
|
|
17
|
+
await waitUntil({
|
|
18
|
+
message: `the ${requestedTheme} theme to be applied and saved to appearance.json`,
|
|
19
|
+
async predicate() {
|
|
20
|
+
const appearance = await app.vault.readConfigJson("appearance");
|
|
21
|
+
return document.body.classList.contains(bodyClass) && appearance?.theme === themeName;
|
|
22
|
+
},
|
|
23
|
+
timeoutInMilliseconds: timeout
|
|
24
|
+
});
|
|
25
|
+
globalThis.__obsidianIntegrationTestingAppliedTheme = requestedTheme;
|
|
26
|
+
return void 0;
|
|
27
|
+
},
|
|
28
|
+
input: {
|
|
29
|
+
theme,
|
|
30
|
+
timeoutInMilliseconds
|
|
31
|
+
},
|
|
32
|
+
transport,
|
|
33
|
+
vaultPath
|
|
34
|
+
}));
|
|
35
|
+
}
|
|
36
|
+
async function assertObsidianThemeUnchanged(params) {
|
|
37
|
+
const {
|
|
38
|
+
action,
|
|
39
|
+
transport,
|
|
40
|
+
vaultPath
|
|
41
|
+
} = params;
|
|
42
|
+
const mismatch = await evalInObsidian(normalizeOptionalProperties({
|
|
43
|
+
callback() {
|
|
44
|
+
const appliedTheme = globalThis.__obsidianIntegrationTestingAppliedTheme;
|
|
45
|
+
if (appliedTheme === void 0 || document.body.classList.contains(`theme-${appliedTheme}`)) {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
let shownTheme = "neither dark nor light";
|
|
49
|
+
if (document.body.classList.contains("theme-dark")) {
|
|
50
|
+
shownTheme = "dark";
|
|
51
|
+
} else if (document.body.classList.contains("theme-light")) {
|
|
52
|
+
shownTheme = "light";
|
|
53
|
+
}
|
|
54
|
+
return `applyObsidianTheme applied the ${appliedTheme} theme, but the body is now ${shownTheme}`;
|
|
55
|
+
},
|
|
56
|
+
input: {},
|
|
57
|
+
transport,
|
|
58
|
+
vaultPath
|
|
59
|
+
}));
|
|
60
|
+
if (mismatch !== null) {
|
|
61
|
+
throw new Error(
|
|
62
|
+
`Refusing to ${action}: ${mismatch}. Something reset the theme after it was applied - typically a bare app.changeTheme, or a config reload. Call applyObsidianTheme again, or pass shouldVerifyTheme: false to capture the frame as it is.`
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
export {
|
|
67
|
+
applyObsidianTheme,
|
|
68
|
+
assertObsidianThemeUnchanged
|
|
69
|
+
};
|
|
70
|
+
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vc3JjL2FwcGx5LW9ic2lkaWFuLXRoZW1lLnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyIvKipcbiAqIEBmaWxlXG4gKlxuICogU3dpdGNoZXMgdGhlIGRyaXZlbiBPYnNpZGlhbiB0byBpdHMgZGFyayBvciBsaWdodCB0aGVtZSwgYW5kIG1ha2VzIHRoZSBzd2l0Y2hcbiAqIHN1cnZpdmUgYSBjb25maWcgcmVsb2FkLlxuICpcbiAqIGBhcHAuY2hhbmdlVGhlbWVgIG9ubHkgc2V0cyB0aGUgdGhlbWUgaW4gdGhlIGluLW1lbW9yeSBjb25maWcgYW5kIFNDSEVEVUxFU1xuICogdGhlIHNhdmUsIGEgc2Vjb25kIGxhdGVyIChgcmVxdWVzdFNhdmVDb25maWdgIGlzIGRlYm91bmNlZCkuIFVudGlsIHRoYXQgc2F2ZVxuICogbGFuZHMsIGFueSBmaWxlLXdhdGNoZXIgZXZlbnQgb24gYC5vYnNpZGlhbi9hcHAuanNvbmAgb3JcbiAqIGAub2JzaWRpYW4vYXBwZWFyYW5jZS5qc29uYCBtYWtlcyBPYnNpZGlhbiBydW4gYHZhdWx0LnJlbG9hZENvbmZpZ2AsIHdoaWNoXG4gKiByZS1yZWFkcyBib3RoIGZpbGVzIGFuZCBkZWxldGVzIGV2ZXJ5IGluLW1lbW9yeSBrZXkgdGhlIGRpc2sgZG9lcyBub3QgaGF2ZSBcdTIwMTRcbiAqIGB0aGVtZWAgaW5jbHVkZWQuIFRoZSBib2R5IHRoZW4gZmFsbHMgYmFjayB0byB0aGUgbGlnaHQgdGhlbWUsIGFuZCBhIGNhcHR1cmVcbiAqIHN1aXRlIHRoYXQgc2V0IHRoZSBkYXJrIHRoZW1lIHNob290cyBldmVyeSBmcmFtZSBsaWdodCwgc2lsZW50bHkgd3JpdGluZyBvdmVyXG4gKiB0aGUgZnJhbWVzIGl0IGhhcyBjb21taXR0ZWQuIFJlYWQgZnJvbSB0aGUgMS4xNC4yIGBhcHAuanNgLCBhbmQgcmVwcm9kdWNlZCBpbiBhXG4gKiBwbHVnaW4ncyBjYXB0dXJlIHN1aXRlOiBvbmUgZXh0ZXJuYWwgcmV3cml0ZSBvZiBgYXBwLmpzb25gIHN0cmFpZ2h0IGFmdGVyXG4gKiBgY2hhbmdlVGhlbWVgIHR1cm5lZCBhbGwgZml2ZSBvZiBpdHMgZGVza3RvcCBmcmFtZXMgbGlnaHQuXG4gKlxuICoge0BsaW5rIGFwcGx5T2JzaWRpYW5UaGVtZX0gc2F2ZXMgdGhlIGNvbmZpZyBhdCBvbmNlLCBzbyBhIHJlbG9hZCBmaW5kcyB0aGVcbiAqIHRoZW1lIG9uIGRpc2sgYW5kIGhhcyBub3RoaW5nIHRvIGRyb3AsIGFuZCB3YWl0cyB1bnRpbCB0aGUgYm9keSBjYXJyaWVzIHRoZVxuICogdGhlbWUncyBjbGFzcyBhbmQgYGFwcGVhcmFuY2UuanNvbmAgY2FycmllcyBpdHMgbmFtZS4gSXQgYWxzbyByZWNvcmRzIHRoZVxuICogdGhlbWUgaXQgYXBwbGllZCwgc28gYGNhcHR1cmVPYnNpZGlhblNjcmVlbnNob3RgIGNhbiByZWZ1c2UgYSBmcmFtZSB0aGUgdGhlbWVcbiAqIGhhcyBsZWZ0IHNpbmNlLlxuICovXG5cbi8qIHY4IGlnbm9yZSBzdGFydCAtLSBJbnRlZ3JhdGlvbi10aW1lIGNvZGUgKGRyaXZlcyBhIGxpdmUgT2JzaWRpYW4pIGNvdmVyZWQgYnkgaW50ZWdyYXRpb24gdGVzdHMsIG5vdCB1bml0IHRlc3RzLiAqL1xuXG5pbXBvcnQgdHlwZSB7XG4gIEV2YWxJbk9ic2lkaWFuUGFyYW1zLFxuICBHZW5lcmljT2JqZWN0XG59IGZyb20gJy4vZXZhbC1pbi1vYnNpZGlhbi5tanMnO1xuaW1wb3J0IHR5cGUgeyBPYnNpZGlhblRyYW5zcG9ydCB9IGZyb20gJy4vdHJhbnNwb3J0Lm1qcyc7XG5cbmltcG9ydCB7IGV2YWxJbk9ic2lkaWFuIH0gZnJvbSAnLi9ldmFsLWluLW9ic2lkaWFuLm1qcyc7XG5pbXBvcnQgeyBub3JtYWxpemVPcHRpb25hbFByb3BlcnRpZXMgfSBmcm9tICcuL25vcm1hbGl6ZS1vcHRpb25hbC1wcm9wZXJ0aWVzLm1qcyc7XG5cbi8qKlxuICogUGFyYW1ldGVycyBmb3Ige0BsaW5rIGFwcGx5T2JzaWRpYW5UaGVtZX0uXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQXBwbHlPYnNpZGlhblRoZW1lUGFyYW1zIHtcbiAgLyoqXG4gICAqIFRoZSB0aGVtZSB0byBzd2l0Y2ggdG8uXG4gICAqL1xuICByZWFkb25seSB0aGVtZTogT2JzaWRpYW5UaGVtZTtcblxuICAvKipcbiAgICogSG93IGxvbmcgdG8gd2FpdCBmb3IgdGhlIHRoZW1lIHRvIGJlIGFwcGxpZWQgYW5kIHNhdmVkLlxuICAgKlxuICAgKiBAZGVmYXVsdCAxMDAwMFxuICAgKi9cbiAgcmVhZG9ubHkgdGltZW91dEluTWlsbGlzZWNvbmRzPzogbnVtYmVyO1xuXG4gIC8qKlxuICAgKiBPdmVycmlkZSB0aGUgdHJhbnNwb3J0LiBXaGVuIG9taXR0ZWQsIHRoZSB0cmFuc3BvcnQgdGhlIGN1cnJlbnQgdGVzdFxuICAgKiBjb250ZXh0IGlzIGRyaXZpbmcgaXMgdXNlZC5cbiAgICovXG4gIHJlYWRvbmx5IHRyYW5zcG9ydD86IE9ic2lkaWFuVHJhbnNwb3J0O1xuXG4gIC8qKlxuICAgKiBUaGUgdmF1bHQgd2hvc2UgT2JzaWRpYW4gd2luZG93IHRvIHN3aXRjaC4gV2hlbiBvbWl0dGVkLCB0aGUgY3VycmVudCB0ZXN0XG4gICAqIGNvbnRleHQncyB2YXVsdCBpcyB1c2VkLlxuICAgKi9cbiAgcmVhZG9ubHkgdmF1bHRQYXRoPzogc3RyaW5nO1xufVxuXG4vKipcbiAqIFBhcmFtZXRlcnMgZm9yIHtAbGluayBhc3NlcnRPYnNpZGlhblRoZW1lVW5jaGFuZ2VkfS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBBc3NlcnRPYnNpZGlhblRoZW1lVW5jaGFuZ2VkUGFyYW1zIHtcbiAgLyoqXG4gICAqIFdoYXQgdGhlIHJlZnVzYWwgaXMgcmVmdXNpbmcsIGZvciBpdHMgbWVzc2FnZSwgZS5nLiBgY2FwdHVyZSBhIHNjcmVlbnNob3RgLlxuICAgKi9cbiAgcmVhZG9ubHkgYWN0aW9uOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIE92ZXJyaWRlIHRoZSB0cmFuc3BvcnQuIFdoZW4gb21pdHRlZCwgdGhlIHRyYW5zcG9ydCB0aGUgY3VycmVudCB0ZXN0XG4gICAqIGNvbnRleHQgaXMgZHJpdmluZyBpcyB1c2VkLlxuICAgKi9cbiAgcmVhZG9ubHkgdHJhbnNwb3J0PzogT2JzaWRpYW5UcmFuc3BvcnQ7XG5cbiAgLyoqXG4gICAqIFRoZSB2YXVsdCB3aG9zZSBPYnNpZGlhbiB3aW5kb3cgdG8gY2hlY2suIFdoZW4gb21pdHRlZCwgdGhlIGN1cnJlbnQgdGVzdFxuICAgKiBjb250ZXh0J3MgdmF1bHQgaXMgdXNlZC5cbiAgICovXG4gIHJlYWRvbmx5IHZhdWx0UGF0aD86IHN0cmluZztcbn1cblxuLyoqXG4gKiBPbmUgb2YgT2JzaWRpYW4ncyB0d28gYnVpbHQtaW4gYmFzZSB0aGVtZXMuXG4gKi9cbmV4cG9ydCB0eXBlIE9ic2lkaWFuVGhlbWUgPSAnZGFyaycgfCAnbGlnaHQnO1xuXG5pbnRlcmZhY2UgQXBwZWFyYW5jZUNvbmZpZyB7XG4gIHJlYWRvbmx5IHRoZW1lPzogdW5rbm93bjtcbn1cblxuLy8gQSBgd2luZG93YCBwcm9wZXJ0eSByYXRoZXIgdGhhbiBhIGNsb3N1cmUgdmFyaWFibGU6IHRoZSBhcHBseSBhbmQgdGhlIGNoZWNrXG4vLyBhcmUgc2VwYXJhdGUgZXZhbHVhdGlvbnMuIFNwZWxsZWQgb3V0IGluIHRoZSBob2xkZXIgcmF0aGVyIHRoYW4gc2hhcmVkIHRocm91Z2hcbi8vIGEgY29uc3RhbnQsIGJlY2F1c2UgYSBjbG9zdXJlIGlzIHNlcmlhbGl6ZWQgYW5kIGNhbm5vdCByZWFjaCBtb2R1bGUgc2NvcGUuXG4vL1xuLy8gS2VwdCBsb2NhbCByYXRoZXIgdGhhbiBkZWNsYXJlZCBnbG9iYWxseSwgbGlrZSBldmVyeSBvdGhlciBob2xkZXIgb2YgYVxuLy8gaGFybmVzcyBgd2luZG93YCBwcm9wZXJ0eSwgc28gaXQgbmV2ZXIgbGVha3MgaW50byBjb25zdW1lciB0eXBlcy5cbmludGVyZmFjZSBBcHBsaWVkVGhlbWVIb2xkZXIge1xuICBfX29ic2lkaWFuSW50ZWdyYXRpb25UZXN0aW5nQXBwbGllZFRoZW1lPzogT2JzaWRpYW5UaGVtZSB8IHVuZGVmaW5lZDtcbn1cblxuaW50ZXJmYWNlIEFwcGx5VGhlbWVJbnB1dCBleHRlbmRzIEdlbmVyaWNPYmplY3Qge1xuICByZWFkb25seSB0aGVtZTogT2JzaWRpYW5UaGVtZTtcbiAgcmVhZG9ubHkgdGltZW91dEluTWlsbGlzZWNvbmRzOiBudW1iZXI7XG59XG5cbmNvbnN0IERFRkFVTFRfVElNRU9VVF9JTl9NSUxMSVNFQ09ORFMgPSAxMF8wMDA7XG5cbi8qKlxuICogU3dpdGNoZXMgT2JzaWRpYW4gdG8gaXRzIGRhcmsgb3IgbGlnaHQgdGhlbWUsIHNhdmVzIHRoZSBjb25maWcgYXQgb25jZSwgYW5kXG4gKiB3YWl0cyB1bnRpbCB0aGUgdGhlbWUgaXMgYm90aCBvbiBzY3JlZW4gYW5kIG9uIGRpc2suXG4gKlxuICogVXNlIGl0IGluc3RlYWQgb2YgYGFwcC5jaGFuZ2VUaGVtZWAgaW4gYSBjYXB0dXJlIHN1aXRlOiBzZWUgdGhlIG1vZHVsZVxuICogY29tbWVudCBmb3IgdGhlIHJlbG9hZCB0aGF0IHNpbGVudGx5IHVuZG9lcyBhIGJhcmUgYGNoYW5nZVRoZW1lYC4gVGhlIHRoZW1lXG4gKiBpcyByZWNvcmRlZCwgYW5kIGBjYXB0dXJlT2JzaWRpYW5TY3JlZW5zaG90YCB0aGVuIHJlZnVzZXMgYW55IGZyYW1lIHdob3NlIGJvZHlcbiAqIGlzIG5vIGxvbmdlciBpbiBpdCwgc28gYSB0aGVtZSBsb3N0IGFmdGVyIHRoaXMgY2FsbCBmYWlscyB0aGUgY2FwdHVyZSBieSBuYW1lXG4gKiBpbnN0ZWFkIG9mIHJld3JpdGluZyBhIGNvbW1pdHRlZCBmcmFtZS5cbiAqXG4gKiBAcGFyYW0gcGFyYW1zIC0gVGhlIHRoZW1lLCBob3cgbG9uZyB0byB3YWl0LCBhbmQgdHJhbnNwb3J0IC8gdmF1bHQgb3ZlcnJpZGVzLlxuICogQHJldHVybnMgQSB7QGxpbmsgUHJvbWlzZX0gdGhhdCByZXNvbHZlcyBvbmNlIHRoZSB0aGVtZSBpcyBhcHBsaWVkIGFuZCBzYXZlZC5cbiAqIEB0aHJvd3MgRXJyb3IgaWYgdGhlIHRoZW1lIGlzIG5vdCBhcHBsaWVkIGFuZCBzYXZlZCB3aXRoaW4gdGhlIHRpbWVvdXQuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBhcHBseU9ic2lkaWFuVGhlbWUocGFyYW1zOiBBcHBseU9ic2lkaWFuVGhlbWVQYXJhbXMpOiBQcm9taXNlPHZvaWQ+IHtcbiAgY29uc3Qge1xuICAgIHRoZW1lLFxuICAgIHRpbWVvdXRJbk1pbGxpc2Vjb25kcyA9IERFRkFVTFRfVElNRU9VVF9JTl9NSUxMSVNFQ09ORFMsXG4gICAgdHJhbnNwb3J0LFxuICAgIHZhdWx0UGF0aFxuICB9ID0gcGFyYW1zO1xuXG4gIGF3YWl0IGV2YWxJbk9ic2lkaWFuKG5vcm1hbGl6ZU9wdGlvbmFsUHJvcGVydGllczxFdmFsSW5PYnNpZGlhblBhcmFtczxBcHBseVRoZW1lSW5wdXQsIHVuZGVmaW5lZD4+KHtcbiAgICBhc3luYyBjYWxsYmFjayh7IGFwcCwgbGliOiB7IHdhaXRVbnRpbCB9LCB0aGVtZTogcmVxdWVzdGVkVGhlbWUsIHRpbWVvdXRJbk1pbGxpc2Vjb25kczogdGltZW91dCB9KTogUHJvbWlzZTx1bmRlZmluZWQ+IHtcbiAgICAgIGNvbnN0IHRoZW1lTmFtZSA9IHJlcXVlc3RlZFRoZW1lID09PSAnZGFyaycgPyAnb2JzaWRpYW4nIDogJ21vb25zdG9uZSc7XG4gICAgICBjb25zdCBib2R5Q2xhc3MgPSBgdGhlbWUtJHtyZXF1ZXN0ZWRUaGVtZX1gO1xuXG4gICAgICBhcHAuY2hhbmdlVGhlbWUodGhlbWVOYW1lKTtcbiAgICAgIC8vIFNhdmluZyBub3csIHJhdGhlciB0aGFuIG9uIGBjaGFuZ2VUaGVtZWAncyBvd24gZGVib3VuY2VkIHNjaGVkdWxlLCBpcyB0aGVcbiAgICAgIC8vIHdob2xlIGZpeDogYSByZWxvYWQgdGhhdCBmaW5kcyB0aGUgdGhlbWUgb24gZGlzayBoYXMgbm90aGluZyB0byBkcm9wLlxuICAgICAgYXdhaXQgYXBwLnZhdWx0LnNhdmVDb25maWcoKTtcblxuICAgICAgYXdhaXQgd2FpdFVudGlsKHtcbiAgICAgICAgbWVzc2FnZTogYHRoZSAke3JlcXVlc3RlZFRoZW1lfSB0aGVtZSB0byBiZSBhcHBsaWVkIGFuZCBzYXZlZCB0byBhcHBlYXJhbmNlLmpzb25gLFxuICAgICAgICBhc3luYyBwcmVkaWNhdGUoKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgICAgICAgY29uc3QgYXBwZWFyYW5jZSA9IGF3YWl0IGFwcC52YXVsdC5yZWFkQ29uZmlnSnNvbignYXBwZWFyYW5jZScpIGFzIEFwcGVhcmFuY2VDb25maWcgfCBudWxsO1xuICAgICAgICAgIHJldHVybiBkb2N1bWVudC5ib2R5LmNsYXNzTGlzdC5jb250YWlucyhib2R5Q2xhc3MpICYmIGFwcGVhcmFuY2U/LnRoZW1lID09PSB0aGVtZU5hbWU7XG4gICAgICAgIH0sXG4gICAgICAgIHRpbWVvdXRJbk1pbGxpc2Vjb25kczogdGltZW91dFxuICAgICAgfSk7XG5cbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby1yZXN0cmljdGVkLXN5bnRheCAtLSBBcHByb3ZlZCBkb3VibGUgY2FzdDogdGhlIGFwcGxpZWQgdGhlbWUgaXMgdGhpcyBoZWxwZXIncyBvd24gV2luZG93IHByb3BlcnR5LCBrZXB0IGxvY2FsIHJhdGhlciB0aGFuIGRlY2xhcmVkIGdsb2JhbGx5LlxuICAgICAgKGdsb2JhbFRoaXMgYXMgdW5rbm93biBhcyBBcHBsaWVkVGhlbWVIb2xkZXIpLl9fb2JzaWRpYW5JbnRlZ3JhdGlvblRlc3RpbmdBcHBsaWVkVGhlbWUgPSByZXF1ZXN0ZWRUaGVtZTtcbiAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfSxcbiAgICBpbnB1dDoge1xuICAgICAgdGhlbWUsXG4gICAgICB0aW1lb3V0SW5NaWxsaXNlY29uZHNcbiAgICB9LFxuICAgIHRyYW5zcG9ydCxcbiAgICB2YXVsdFBhdGhcbiAgfSkpO1xufVxuXG4vKipcbiAqIFRocm93cyB3aGVuIHRoZSBib2R5IGhhcyBsZWZ0IHRoZSB0aGVtZSB7QGxpbmsgYXBwbHlPYnNpZGlhblRoZW1lfSBhcHBsaWVkLlxuICpcbiAqIE5vdGhpbmcgaXMgY2hlY2tlZCB3aGVuIG5vIHRoZW1lIHdhcyBhcHBsaWVkIHRocm91Z2ggaXQsIHNpbmNlIHRoZXJlIGlzIHRoZW5cbiAqIG5vIGV4cGVjdGF0aW9uIHRvIGhvbGQgdGhlIGZyYW1lIHRvLlxuICpcbiAqIEBwYXJhbSBwYXJhbXMgLSBXaGF0IGlzIGJlaW5nIHJlZnVzZWQsIGFuZCB0cmFuc3BvcnQgLyB2YXVsdCBvdmVycmlkZXMuXG4gKiBAcmV0dXJucyBBIHtAbGluayBQcm9taXNlfSB0aGF0IHJlc29sdmVzIHdoZW4gdGhlIHRoZW1lIHN0aWxsIGhvbGRzLCBvciBub25lXG4gKiAgIHdhcyBhcHBsaWVkLlxuICogQHRocm93cyBFcnJvciBuYW1pbmcgdGhlIGFwcGxpZWQgdGhlbWUgYW5kIHRoZSBvbmUgb24gc2NyZWVuLCBpZiB0aGV5IGRpZmZlci5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGFzc2VydE9ic2lkaWFuVGhlbWVVbmNoYW5nZWQocGFyYW1zOiBBc3NlcnRPYnNpZGlhblRoZW1lVW5jaGFuZ2VkUGFyYW1zKTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IHtcbiAgICBhY3Rpb24sXG4gICAgdHJhbnNwb3J0LFxuICAgIHZhdWx0UGF0aFxuICB9ID0gcGFyYW1zO1xuXG4gIGNvbnN0IG1pc21hdGNoID0gYXdhaXQgZXZhbEluT2JzaWRpYW4obm9ybWFsaXplT3B0aW9uYWxQcm9wZXJ0aWVzPEV2YWxJbk9ic2lkaWFuUGFyYW1zPFJlY29yZDxzdHJpbmcsIG5ldmVyPiwgbnVsbCB8IHN0cmluZz4+KHtcbiAgICBjYWxsYmFjaygpOiBudWxsIHwgc3RyaW5nIHtcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby1yZXN0cmljdGVkLXN5bnRheCAtLSBBcHByb3ZlZCBkb3VibGUgY2FzdDogdGhlIGFwcGxpZWQgdGhlbWUgaXMgdGhpcyBoZWxwZXIncyBvd24gV2luZG93IHByb3BlcnR5LCBrZXB0IGxvY2FsIHJhdGhlciB0aGFuIGRlY2xhcmVkIGdsb2JhbGx5LlxuICAgICAgY29uc3QgYXBwbGllZFRoZW1lID0gKGdsb2JhbFRoaXMgYXMgdW5rbm93biBhcyBBcHBsaWVkVGhlbWVIb2xkZXIpLl9fb2JzaWRpYW5JbnRlZ3JhdGlvblRlc3RpbmdBcHBsaWVkVGhlbWU7XG4gICAgICBpZiAoYXBwbGllZFRoZW1lID09PSB1bmRlZmluZWQgfHwgZG9jdW1lbnQuYm9keS5jbGFzc0xpc3QuY29udGFpbnMoYHRoZW1lLSR7YXBwbGllZFRoZW1lfWApKSB7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgICAgfVxuXG4gICAgICBsZXQgc2hvd25UaGVtZSA9ICduZWl0aGVyIGRhcmsgbm9yIGxpZ2h0JztcbiAgICAgIGlmIChkb2N1bWVudC5ib2R5LmNsYXNzTGlzdC5jb250YWlucygndGhlbWUtZGFyaycpKSB7XG4gICAgICAgIHNob3duVGhlbWUgPSAnZGFyayc7XG4gICAgICB9IGVsc2UgaWYgKGRvY3VtZW50LmJvZHkuY2xhc3NMaXN0LmNvbnRhaW5zKCd0aGVtZS1saWdodCcpKSB7XG4gICAgICAgIHNob3duVGhlbWUgPSAnbGlnaHQnO1xuICAgICAgfVxuICAgICAgcmV0dXJuIGBhcHBseU9ic2lkaWFuVGhlbWUgYXBwbGllZCB0aGUgJHthcHBsaWVkVGhlbWV9IHRoZW1lLCBidXQgdGhlIGJvZHkgaXMgbm93ICR7c2hvd25UaGVtZX1gO1xuICAgIH0sXG4gICAgaW5wdXQ6IHt9LFxuICAgIHRyYW5zcG9ydCxcbiAgICB2YXVsdFBhdGhcbiAgfSkpO1xuXG4gIGlmIChtaXNtYXRjaCAhPT0gbnVsbCkge1xuICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgIGBSZWZ1c2luZyB0byAke2FjdGlvbn06ICR7bWlzbWF0Y2h9LiBTb21ldGhpbmcgcmVzZXQgdGhlIHRoZW1lIGFmdGVyIGl0IHdhcyBhcHBsaWVkIC0gdHlwaWNhbGx5IGEgYmFyZSBhcHAuY2hhbmdlVGhlbWUsIG9yIGEgY29uZmlnIHJlbG9hZC4gQ2FsbCBhcHBseU9ic2lkaWFuVGhlbWUgYWdhaW4sIG9yIHBhc3Mgc2hvdWxkVmVyaWZ5VGhlbWU6IGZhbHNlIHRvIGNhcHR1cmUgdGhlIGZyYW1lIGFzIGl0IGlzLmBcbiAgICApO1xuICB9XG59XG5cbi8qIHY4IGlnbm9yZSBzdG9wICovXG4iXSwKICAibWFwcGluZ3MiOiAiQUFnQ0EsU0FBUyxzQkFBc0I7QUFDL0IsU0FBUyxtQ0FBbUM7QUE2RTVDLE1BQU0sa0NBQWtDO0FBZ0J4QyxlQUFzQixtQkFBbUIsUUFBaUQ7QUFDeEYsUUFBTTtBQUFBLElBQ0o7QUFBQSxJQUNBLHdCQUF3QjtBQUFBLElBQ3hCO0FBQUEsSUFDQTtBQUFBLEVBQ0YsSUFBSTtBQUVKLFFBQU0sZUFBZSw0QkFBOEU7QUFBQSxJQUNqRyxNQUFNLFNBQVMsRUFBRSxLQUFLLEtBQUssRUFBRSxVQUFVLEdBQUcsT0FBTyxnQkFBZ0IsdUJBQXVCLFFBQVEsR0FBdUI7QUFDckgsWUFBTSxZQUFZLG1CQUFtQixTQUFTLGFBQWE7QUFDM0QsWUFBTSxZQUFZLFNBQVMsY0FBYztBQUV6QyxVQUFJLFlBQVksU0FBUztBQUd6QixZQUFNLElBQUksTUFBTSxXQUFXO0FBRTNCLFlBQU0sVUFBVTtBQUFBLFFBQ2QsU0FBUyxPQUFPLGNBQWM7QUFBQSxRQUM5QixNQUFNLFlBQThCO0FBQ2xDLGdCQUFNLGFBQWEsTUFBTSxJQUFJLE1BQU0sZUFBZSxZQUFZO0FBQzlELGlCQUFPLFNBQVMsS0FBSyxVQUFVLFNBQVMsU0FBUyxLQUFLLFlBQVksVUFBVTtBQUFBLFFBQzlFO0FBQUEsUUFDQSx1QkFBdUI7QUFBQSxNQUN6QixDQUFDO0FBR0QsTUFBQyxXQUE2QywyQ0FBMkM7QUFDekYsYUFBTztBQUFBLElBQ1Q7QUFBQSxJQUNBLE9BQU87QUFBQSxNQUNMO0FBQUEsTUFDQTtBQUFBLElBQ0Y7QUFBQSxJQUNBO0FBQUEsSUFDQTtBQUFBLEVBQ0YsQ0FBQyxDQUFDO0FBQ0o7QUFhQSxlQUFzQiw2QkFBNkIsUUFBMkQ7QUFDNUcsUUFBTTtBQUFBLElBQ0o7QUFBQSxJQUNBO0FBQUEsSUFDQTtBQUFBLEVBQ0YsSUFBSTtBQUVKLFFBQU0sV0FBVyxNQUFNLGVBQWUsNEJBQXdGO0FBQUEsSUFDNUgsV0FBMEI7QUFFeEIsWUFBTSxlQUFnQixXQUE2QztBQUNuRSxVQUFJLGlCQUFpQixVQUFhLFNBQVMsS0FBSyxVQUFVLFNBQVMsU0FBUyxZQUFZLEVBQUUsR0FBRztBQUMzRixlQUFPO0FBQUEsTUFDVDtBQUVBLFVBQUksYUFBYTtBQUNqQixVQUFJLFNBQVMsS0FBSyxVQUFVLFNBQVMsWUFBWSxHQUFHO0FBQ2xELHFCQUFhO0FBQUEsTUFDZixXQUFXLFNBQVMsS0FBSyxVQUFVLFNBQVMsYUFBYSxHQUFHO0FBQzFELHFCQUFhO0FBQUEsTUFDZjtBQUNBLGFBQU8sa0NBQWtDLFlBQVksK0JBQStCLFVBQVU7QUFBQSxJQUNoRztBQUFBLElBQ0EsT0FBTyxDQUFDO0FBQUEsSUFDUjtBQUFBLElBQ0E7QUFBQSxFQUNGLENBQUMsQ0FBQztBQUVGLE1BQUksYUFBYSxNQUFNO0FBQ3JCLFVBQU0sSUFBSTtBQUFBLE1BQ1IsZUFBZSxNQUFNLEtBQUssUUFBUTtBQUFBLElBQ3BDO0FBQUEsRUFDRjtBQUNGOyIsCiAgIm5hbWVzIjogW10KfQo=
|
|
@@ -15,7 +15,14 @@
|
|
|
15
15
|
* name — see `hide-vault-name.ts` for why a `temp-vault-<random>` bleeds
|
|
16
16
|
* through the caption band and rewrites a checked-in PNG on every run — and by
|
|
17
17
|
* hiding the focused element's blinking caret for the length of the capture —
|
|
18
|
-
* see `hide-caret.ts` for why that is a transparent caret and not a blur
|
|
18
|
+
* see `hide-caret.ts` for why that is a transparent caret and not a blur —
|
|
19
|
+
* and by drawing the window focused whether or not the OS gave it focus — see
|
|
20
|
+
* `pin-window-focus.ts` for the title bar that otherwise darkens one run in
|
|
21
|
+
* five.
|
|
22
|
+
*
|
|
23
|
+
* And it refuses a frame whose theme has changed since `applyObsidianTheme` set
|
|
24
|
+
* it — see `apply-obsidian-theme.ts` for the config reload that silently turns a
|
|
25
|
+
* dark capture run light.
|
|
19
26
|
*/
|
|
20
27
|
import type { ObsidianTransport } from './transport.mjs';
|
|
21
28
|
/**
|
|
@@ -56,6 +63,33 @@ export interface CaptureObsidianScreenshotOptions {
|
|
|
56
63
|
* @default `true`
|
|
57
64
|
*/
|
|
58
65
|
readonly shouldHideVaultName?: boolean;
|
|
66
|
+
/**
|
|
67
|
+
* Whether to draw the window as focused while capturing, so the frame does
|
|
68
|
+
* not depend on whether the operating system gave the window foreground
|
|
69
|
+
* focus that run.
|
|
70
|
+
*
|
|
71
|
+
* Obsidian darkens the title bar of an unfocused window, and a freshly
|
|
72
|
+
* launched one is routinely refused the foreground. The `is-focused` class is
|
|
73
|
+
* added for the capture and handed back to Obsidian afterwards; the window's
|
|
74
|
+
* real focus is never touched. Turn it off only to photograph the unfocused
|
|
75
|
+
* chrome itself, and expect such a frame to differ between runs.
|
|
76
|
+
*
|
|
77
|
+
* @default `true`
|
|
78
|
+
*/
|
|
79
|
+
readonly shouldPinWindowFocus?: boolean;
|
|
80
|
+
/**
|
|
81
|
+
* Whether to refuse the frame when the body is no longer in the theme
|
|
82
|
+
* `applyObsidianTheme` last applied.
|
|
83
|
+
*
|
|
84
|
+
* A theme lost after it was applied fails nothing on its own: the frame is
|
|
85
|
+
* simply shot in the other theme and written over the committed one. Refusing
|
|
86
|
+
* turns that into a named error. Nothing is checked when no theme was applied
|
|
87
|
+
* through `applyObsidianTheme`. Turn it off only for a frame that changes the
|
|
88
|
+
* theme on purpose.
|
|
89
|
+
*
|
|
90
|
+
* @default `true`
|
|
91
|
+
*/
|
|
92
|
+
readonly shouldVerifyTheme?: boolean;
|
|
59
93
|
/**
|
|
60
94
|
* Override the transport. When omitted, the transport the current test
|
|
61
95
|
* context is driving is used.
|
|
@@ -83,10 +117,15 @@ export interface CaptureObsidianScreenshotOptions {
|
|
|
83
117
|
* photograph it. The focused element's caret is hidden for the capture too, and
|
|
84
118
|
* restored after it, so a frame with a focused field does not alternate between
|
|
85
119
|
* two blink phases; {@link CaptureObsidianScreenshotOptions.shouldHideCaret}
|
|
120
|
+
* turns that off. The window is drawn focused whether or not the OS gave it
|
|
121
|
+
* focus; {@link CaptureObsidianScreenshotOptions.shouldPinWindowFocus} turns
|
|
122
|
+
* that off. A frame whose body has left the theme `applyObsidianTheme`
|
|
123
|
+
* applied is refused; {@link CaptureObsidianScreenshotOptions.shouldVerifyTheme}
|
|
86
124
|
* turns that off.
|
|
87
125
|
*
|
|
88
126
|
* @param options - Optional size, transport and vault overrides.
|
|
89
127
|
* @returns A {@link Promise} that resolves to the raw PNG bytes.
|
|
90
|
-
* @throws Error if the active transport cannot capture screenshots
|
|
128
|
+
* @throws Error if the active transport cannot capture screenshots, or if the
|
|
129
|
+
* theme has changed since `applyObsidianTheme` applied it.
|
|
91
130
|
*/
|
|
92
131
|
export declare function captureObsidianScreenshot(options?: CaptureObsidianScreenshotOptions): Promise<Uint8Array>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import process from "node:process";
|
|
2
|
+
import { assertObsidianThemeUnchanged } from "./apply-obsidian-theme.mjs";
|
|
2
3
|
import {
|
|
3
4
|
getTransportOptions,
|
|
4
5
|
getVaultPath
|
|
@@ -6,12 +7,15 @@ import {
|
|
|
6
7
|
import { hideCaret } from "./hide-caret.mjs";
|
|
7
8
|
import { hideVaultName } from "./hide-vault-name.mjs";
|
|
8
9
|
import { normalizeOptionalProperties } from "./normalize-optional-properties.mjs";
|
|
10
|
+
import { pinWindowFocus } from "./pin-window-focus.mjs";
|
|
9
11
|
import { getOrCreateTransport } from "./transport-factory.mjs";
|
|
10
12
|
async function captureObsidianScreenshot(options) {
|
|
11
13
|
const {
|
|
12
14
|
heightInPixels,
|
|
13
15
|
shouldHideCaret = true,
|
|
14
16
|
shouldHideVaultName = true,
|
|
17
|
+
shouldPinWindowFocus = true,
|
|
18
|
+
shouldVerifyTheme = true,
|
|
15
19
|
transport: transportOverride,
|
|
16
20
|
vaultPath,
|
|
17
21
|
widthInPixels
|
|
@@ -21,6 +25,13 @@ async function captureObsidianScreenshot(options) {
|
|
|
21
25
|
if (!transport.captureScreenshot) {
|
|
22
26
|
throw new Error("captureObsidianScreenshot: the active transport cannot capture screenshots.");
|
|
23
27
|
}
|
|
28
|
+
if (shouldVerifyTheme) {
|
|
29
|
+
await assertObsidianThemeUnchanged({
|
|
30
|
+
action: "capture a screenshot",
|
|
31
|
+
transport,
|
|
32
|
+
vaultPath: cwd
|
|
33
|
+
});
|
|
34
|
+
}
|
|
24
35
|
if (shouldHideVaultName) {
|
|
25
36
|
await hideVaultName({
|
|
26
37
|
transport,
|
|
@@ -31,6 +42,10 @@ async function captureObsidianScreenshot(options) {
|
|
|
31
42
|
transport,
|
|
32
43
|
vaultPath: cwd
|
|
33
44
|
}) : void 0;
|
|
45
|
+
const pinnedWindowFocus = shouldPinWindowFocus ? await pinWindowFocus({
|
|
46
|
+
transport,
|
|
47
|
+
vaultPath: cwd
|
|
48
|
+
}) : void 0;
|
|
34
49
|
try {
|
|
35
50
|
return await transport.captureScreenshot(normalizeOptionalProperties({
|
|
36
51
|
cwd,
|
|
@@ -38,10 +53,11 @@ async function captureObsidianScreenshot(options) {
|
|
|
38
53
|
widthInPixels
|
|
39
54
|
}));
|
|
40
55
|
} finally {
|
|
56
|
+
await pinnedWindowFocus?.restore();
|
|
41
57
|
await hiddenCaret?.restore();
|
|
42
58
|
}
|
|
43
59
|
}
|
|
44
60
|
export {
|
|
45
61
|
captureObsidianScreenshot
|
|
46
62
|
};
|
|
47
|
-
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vc3JjL2NhcHR1cmUtb2JzaWRpYW4tc2NyZWVuc2hvdC50cyJdLAogICJzb3VyY2VzQ29udGVudCI6IFsiLyoqXG4gKiBAZmlsZVxuICpcbiAqIENhcHR1cmVzIGEgc2NyZWVuc2hvdCBvZiB0aGUgT2JzaWRpYW4gaW5zdGFuY2UgdGhlIGN1cnJlbnQgdGVzdCBjb250ZXh0IGlzXG4gKiBhbHJlYWR5IGRyaXZpbmcuXG4gKlxuICogVGhlIHRyYW5zcG9ydC1sZXZlbCBgY2FwdHVyZVNjcmVlbnNob3RgIG5lZWRzIGEgdHJhbnNwb3J0IGluIGhhbmQsIHdoaWNoIGFcbiAqIHRlc3QgcnVubmluZyB1bmRlciB0aGUgaGFybmVzcydzIGdsb2JhbCBzZXR1cCBuZXZlciBoYXMgXHUyMDE0IHRoZSBpbnN0YW5jZSBpc1xuICogb3duZWQgYnkgdGhhdCBzZXR1cCBhbmQgcmVhY2hlZCB0aHJvdWdoIHRoZSBjb250ZXh0IHByb3ZpZGVyLiBUaGlzIGlzIHRoZVxuICogY29udGV4dC1yZXNvbHZpbmcgZW50cnkgcG9pbnQsIHRoZSBzY3JlZW5zaG90IGNvdW50ZXJwYXJ0IG9mXG4gKiBgZXZhbEluT2JzaWRpYW5gIC8gYHBvbGxJbk9ic2lkaWFuYDogd2l0aCBubyBhcmd1bWVudHMgYXQgYWxsIGl0IGNhcHR1cmVzXG4gKiB3aGF0ZXZlciBpbnN0YW5jZSB0aGUgYWN0aXZlIHByb2plY3QgaXMgZHJpdmluZywgZGVza3RvcCBvciBtb2JpbGUuXG4gKlxuICogSXQgYWxzbyBtYWtlcyB0aGUgZnJhbWUgUkVQUk9EVUNJQkxFIGJlZm9yZSB0YWtpbmcgaXQsIGJ5IGhpZGluZyB0aGUgdmF1bHQnc1xuICogbmFtZSBcdTIwMTQgc2VlIGBoaWRlLXZhdWx0LW5hbWUudHNgIGZvciB3aHkgYSBgdGVtcC12YXVsdC08cmFuZG9tPmAgYmxlZWRzXG4gKiB0aHJvdWdoIHRoZSBjYXB0aW9uIGJhbmQgYW5kIHJld3JpdGVzIGEgY2hlY2tlZC1pbiBQTkcgb24gZXZlcnkgcnVuIFx1MjAxNCBhbmQgYnlcbiAqIGhpZGluZyB0aGUgZm9jdXNlZCBlbGVtZW50J3MgYmxpbmtpbmcgY2FyZXQgZm9yIHRoZSBsZW5ndGggb2YgdGhlIGNhcHR1cmUgXHUyMDE0XG4gKiBzZWUgYGhpZGUtY2FyZXQudHNgIGZvciB3aHkgdGhhdCBpcyBhIHRyYW5zcGFyZW50IGNhcmV0IGFuZCBub3QgYSBibHVyLlxuICovXG5cbi8qIHY4IGlnbm9yZSBzdGFydCAtLSBJbnRlZ3JhdGlvbi10aW1lIGNvZGUgKGRyaXZlcyBhIGxpdmUgT2JzaWRpYW4pIGNvdmVyZWQgYnkgaW50ZWdyYXRpb24gdGVzdHMsIG5vdCB1bml0IHRlc3RzLiAqL1xuXG5pbXBvcnQgcHJvY2VzcyBmcm9tICdub2RlOnByb2Nlc3MnO1xuXG5pbXBvcnQgdHlwZSB7IENhcHR1cmVTY3JlZW5zaG90UGFyYW1zIH0gZnJvbSAnLi9jYXB0dXJlLXNjcmVlbnNob3QubWpzJztcbmltcG9ydCB0eXBlIHsgT2JzaWRpYW5UcmFuc3BvcnQgfSBmcm9tICcuL3RyYW5zcG9ydC5tanMnO1xuXG5pbXBvcnQge1xuICBnZXRUcmFuc3BvcnRPcHRpb25zLFxuICBnZXRWYXVsdFBhdGhcbn0gZnJvbSAnLi9jb250ZXh0LXByb3ZpZGVyLm1qcyc7XG5pbXBvcnQgeyBoaWRlQ2FyZXQgfSBmcm9tICcuL2hpZGUtY2FyZXQubWpzJztcbmltcG9ydCB7IGhpZGVWYXVsdE5hbWUgfSBmcm9tICcuL2hpZGUtdmF1bHQtbmFtZS5tanMnO1xuaW1wb3J0IHsgbm9ybWFsaXplT3B0aW9uYWxQcm9wZXJ0aWVzIH0gZnJvbSAnLi9ub3JtYWxpemUtb3B0aW9uYWwtcHJvcGVydGllcy5tanMnO1xuaW1wb3J0IHsgZ2V0T3JDcmVhdGVUcmFuc3BvcnQgfSBmcm9tICcuL3RyYW5zcG9ydC1mYWN0b3J5Lm1qcyc7XG5cbi8qKlxuICogT3B0aW9ucyBmb3Ige0BsaW5rIGNhcHR1cmVPYnNpZGlhblNjcmVlbnNob3R9LlxuICovXG5leHBvcnQgaW50ZXJmYWNlIENhcHR1cmVPYnNpZGlhblNjcmVlbnNob3RPcHRpb25zIHtcbiAgLyoqXG4gICAqIFRoZSBleGFjdCBoZWlnaHQgaW4gcGl4ZWxzIHRoZSBjYXB0dXJlZCBpbWFnZSBzaG91bGQgaGF2ZS5cbiAgICpcbiAgICogRGVza3RvcCBvbmx5LCBhbmQgb25seSBtZWFuaW5nZnVsIHRvZ2V0aGVyIHdpdGgge0BsaW5rIHdpZHRoSW5QaXhlbHN9LlxuICAgKiBJZ25vcmVkIG9uIG1vYmlsZSwgd2hlcmUgdGhlIGltYWdlIGlzIGFsd2F5cyB0aGUgZGV2aWNlJ3MgbmF0aXZlXG4gICAqIGZyYW1lYnVmZmVyIFx1MjAxNCBzaXplIHRob3NlIGJ5IGNob29zaW5nIGFuIEFWRCB3aXRoIHRoZSB3YW50ZWQgc2NyZWVuXG4gICAqIGdlb21ldHJ5LlxuICAgKi9cbiAgcmVhZG9ubHkgaGVpZ2h0SW5QaXhlbHM/OiBudW1iZXI7XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgdG8gaGlkZSB0aGUgZm9jdXNlZCBlbGVtZW50J3MgY2FyZXQgd2hpbGUgY2FwdHVyaW5nLCBzbyB0aGUgZnJhbWVcbiAgICogZG9lcyBub3QgZGVwZW5kIG9uIHdoaWNoIHBoYXNlIG9mIGl0cyBibGluayB0aGUgY2FwdHVyZSBjYXVnaHQuXG4gICAqXG4gICAqIFRoZSBjYXJldCBpcyBtYWRlIHRyYW5zcGFyZW50LCBub3QgYmx1cnJlZDogdGhlIGZvY3VzLCBpdHMgcmluZyBhbmRcbiAgICogYW55dGhpbmcgb3BlbiBiZWNhdXNlIG9mIGl0IFx1MjAxNCBhIHN1Z2dlc3RlciB1bmRlciBhbiBpbnB1dCBcdTIwMTQgYWxsIHN0YXkgYXMgdGhlXG4gICAqIHRlc3QgYnVpbHQgdGhlbSwgYW5kIHRoZSBjYXJldCBpcyBwdXQgYmFjayBvbmNlIHRoZSBmcmFtZSBpcyB0YWtlbi4gVHVybiBpdFxuICAgKiBvZmYgb25seSB0byBwaG90b2dyYXBoIHRoZSBjYXJldCBpdHNlbGYsIGFuZCBleHBlY3Qgc3VjaCBhIGZyYW1lIHRvIGRpZmZlclxuICAgKiBiZXR3ZWVuIHJ1bnMuXG4gICAqXG4gICAqIEBkZWZhdWx0IGB0cnVlYFxuICAgKi9cbiAgcmVhZG9ubHkgc2hvdWxkSGlkZUNhcmV0PzogYm9vbGVhbjtcblxuICAvKipcbiAgICogV2hldGhlciB0byBoaWRlIHRoZSB2YXVsdCdzIG5hbWUgYmVmb3JlIGNhcHR1cmluZywgc28gdGhlIGZyYW1lIGRvZXMgbm90XG4gICAqIGRlcGVuZCBvbiB0aGUgcmFuZG9tIHN1ZmZpeCBvZiB0aGUgaGFybmVzcydzIHRlbXBvcmFyeSB2YXVsdC5cbiAgICpcbiAgICogQSBkZWZhdWx0IHJhdGhlciB0aGFuIGEga25vYjogcmVwcm9kdWNpYmlsaXR5IGlzIHdoYXQgYSBjaGVja2VkLWluXG4gICAqIHNjcmVlbnNob3QgaXMgZm9yLCBhbmQgdGhlIHJvdyBpdCBjb2xsYXBzZXMgc2l0cyB1bmRlciB0aGUgY2FwdGlvbiBiYW5kLFxuICAgKiBzbyBub3RoaW5nIGEgcmVhZGVyIHNlZXMgbW92ZXMuIFR1cm4gaXQgb2ZmIG9ubHkgdG8gcGhvdG9ncmFwaCB0aGUgdmF1bHRcbiAgICogc3dpdGNoZXIgaXRzZWxmLlxuICAgKlxuICAgKiBAZGVmYXVsdCBgdHJ1ZWBcbiAgICovXG4gIHJlYWRvbmx5IHNob3VsZEhpZGVWYXVsdE5hbWU/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBPdmVycmlkZSB0aGUgdHJhbnNwb3J0LiBXaGVuIG9taXR0ZWQsIHRoZSB0cmFuc3BvcnQgdGhlIGN1cnJlbnQgdGVzdFxuICAgKiBjb250ZXh0IGlzIGRyaXZpbmcgaXMgdXNlZC5cbiAgICovXG4gIHJlYWRvbmx5IHRyYW5zcG9ydD86IE9ic2lkaWFuVHJhbnNwb3J0O1xuXG4gIC8qKlxuICAgKiBUaGUgdmF1bHQgcGF0aCB0byBjYXB0dXJlLiBXaGVuIG9taXR0ZWQsIHRoZSBjdXJyZW50IHRlc3QgY29udGV4dCdzIHZhdWx0XG4gICAqIGlzIHVzZWQuXG4gICAqL1xuICByZWFkb25seSB2YXVsdFBhdGg/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSBleGFjdCB3aWR0aCBpbiBwaXhlbHMgdGhlIGNhcHR1cmVkIGltYWdlIHNob3VsZCBoYXZlLlxuICAgKlxuICAgKiBTZWUge0BsaW5rIGhlaWdodEluUGl4ZWxzfSBcdTIwMTQgdGhlIHR3byBhcmUgc2V0IHRvZ2V0aGVyIG9yIG5vdCBhdCBhbGwuXG4gICAqL1xuICByZWFkb25seSB3aWR0aEluUGl4ZWxzPzogbnVtYmVyO1xufVxuXG4vKipcbiAqIENhcHR1cmVzIGEgUE5HIHNjcmVlbnNob3Qgb2YgdGhlIHJ1bm5pbmcgT2JzaWRpYW4gaW5zdGFuY2UsIHJlc29sdmluZyB0aGVcbiAqIHRyYW5zcG9ydCBhbmQgdmF1bHQgZnJvbSB0aGUgY3VycmVudCB0ZXN0IGNvbnRleHQuXG4gKlxuICogVGhlIHZhdWx0J3MgbmFtZSBpcyBoaWRkZW4gZmlyc3QsIHNvIHR3byBydW5zIG9mIHRoZSBzYW1lIHN1aXRlIGFnYWluc3QgdHdvXG4gKiBkaWZmZXJlbnRseS1uYW1lZCB0ZW1wb3JhcnkgdmF1bHRzIHByb2R1Y2UgYnl0ZS1pZGVudGljYWwgUE5Hcy4gUGFzc1xuICoge0BsaW5rIENhcHR1cmVPYnNpZGlhblNjcmVlbnNob3RPcHRpb25zLnNob3VsZEhpZGVWYXVsdE5hbWV9IGFzIGBmYWxzZWAgdG9cbiAqIHBob3RvZ3JhcGggaXQuIFRoZSBmb2N1c2VkIGVsZW1lbnQncyBjYXJldCBpcyBoaWRkZW4gZm9yIHRoZSBjYXB0dXJlIHRvbywgYW5kXG4gKiByZXN0b3JlZCBhZnRlciBpdCwgc28gYSBmcmFtZSB3aXRoIGEgZm9jdXNlZCBmaWVsZCBkb2VzIG5vdCBhbHRlcm5hdGUgYmV0d2VlblxuICogdHdvIGJsaW5rIHBoYXNlczsge0BsaW5rIENhcHR1cmVPYnNpZGlhblNjcmVlbnNob3RPcHRpb25zLnNob3VsZEhpZGVDYXJldH1cbiAqIHR1cm5zIHRoYXQgb2ZmLlxuICpcbiAqIEBwYXJhbSBvcHRpb25zIC0gT3B0aW9uYWwgc2l6ZSwgdHJhbnNwb3J0IGFuZCB2YXVsdCBvdmVycmlkZXMuXG4gKiBAcmV0dXJucyBBIHtAbGluayBQcm9taXNlfSB0aGF0IHJlc29sdmVzIHRvIHRoZSByYXcgUE5HIGJ5dGVzLlxuICogQHRocm93cyBFcnJvciBpZiB0aGUgYWN0aXZlIHRyYW5zcG9ydCBjYW5ub3QgY2FwdHVyZSBzY3JlZW5zaG90cy5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNhcHR1cmVPYnNpZGlhblNjcmVlbnNob3Qob3B0aW9ucz86IENhcHR1cmVPYnNpZGlhblNjcmVlbnNob3RPcHRpb25zKTogUHJvbWlzZTxVaW50OEFycmF5PiB7XG4gIGNvbnN0IHtcbiAgICBoZWlnaHRJblBpeGVscyxcbiAgICBzaG91bGRIaWRlQ2FyZXQgPSB0cnVlLFxuICAgIHNob3VsZEhpZGVWYXVsdE5hbWUgPSB0cnVlLFxuICAgIHRyYW5zcG9ydDogdHJhbnNwb3J0T3ZlcnJpZGUsXG4gICAgdmF1bHRQYXRoLFxuICAgIHdpZHRoSW5QaXhlbHNcbiAgfSA9IG9wdGlvbnMgPz8ge307XG5cbiAgY29uc3QgY3dkID0gdmF1bHRQYXRoID8/IGdldFZhdWx0UGF0aCgpID8/IHByb2Nlc3MuY3dkKCk7XG4gIGNvbnN0IHRyYW5zcG9ydCA9IHRyYW5zcG9ydE92ZXJyaWRlID8/IGF3YWl0IGdldE9yQ3JlYXRlVHJhbnNwb3J0KGdldFRyYW5zcG9ydE9wdGlvbnMoKSk7XG5cbiAgaWYgKCF0cmFuc3BvcnQuY2FwdHVyZVNjcmVlbnNob3QpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ2NhcHR1cmVPYnNpZGlhblNjcmVlbnNob3Q6IHRoZSBhY3RpdmUgdHJhbnNwb3J0IGNhbm5vdCBjYXB0dXJlIHNjcmVlbnNob3RzLicpO1xuICB9XG5cbiAgaWYgKHNob3VsZEhpZGVWYXVsdE5hbWUpIHtcbiAgICBhd2FpdCBoaWRlVmF1bHROYW1lKHtcbiAgICAgIHRyYW5zcG9ydCxcbiAgICAgIHZhdWx0UGF0aDogY3dkXG4gICAgfSk7XG4gIH1cblxuICBjb25zdCBoaWRkZW5DYXJldCA9IHNob3VsZEhpZGVDYXJldFxuICAgID8gYXdhaXQgaGlkZUNhcmV0KHtcbiAgICAgIHRyYW5zcG9ydCxcbiAgICAgIHZhdWx0UGF0aDogY3dkXG4gICAgfSlcbiAgICA6IHVuZGVmaW5lZDtcblxuICB0cnkge1xuICAgIHJldHVybiBhd2FpdCB0cmFuc3BvcnQuY2FwdHVyZVNjcmVlbnNob3Qobm9ybWFsaXplT3B0aW9uYWxQcm9wZXJ0aWVzPENhcHR1cmVTY3JlZW5zaG90UGFyYW1zPih7XG4gICAgICBjd2QsXG4gICAgICBoZWlnaHRJblBpeGVscyxcbiAgICAgIHdpZHRoSW5QaXhlbHNcbiAgICB9KSk7XG4gIH0gZmluYWxseSB7XG4gICAgYXdhaXQgaGlkZGVuQ2FyZXQ/LnJlc3RvcmUoKTtcbiAgfVxufVxuXG4vKiB2OCBpZ25vcmUgc3RvcCAqL1xuIl0sCiAgIm1hcHBpbmdzIjogIkFBc0JBLE9BQU8sYUFBYTtBQUtwQjtBQUFBLEVBQ0U7QUFBQSxFQUNBO0FBQUEsT0FDSztBQUNQLFNBQVMsaUJBQWlCO0FBQzFCLFNBQVMscUJBQXFCO0FBQzlCLFNBQVMsbUNBQW1DO0FBQzVDLFNBQVMsNEJBQTRCO0FBK0VyQyxlQUFzQiwwQkFBMEIsU0FBaUU7QUFDL0csUUFBTTtBQUFBLElBQ0o7QUFBQSxJQUNBLGtCQUFrQjtBQUFBLElBQ2xCLHNCQUFzQjtBQUFBLElBQ3RCLFdBQVc7QUFBQSxJQUNYO0FBQUEsSUFDQTtBQUFBLEVBQ0YsSUFBSSxXQUFXLENBQUM7QUFFaEIsUUFBTSxNQUFNLGFBQWEsYUFBYSxLQUFLLFFBQVEsSUFBSTtBQUN2RCxRQUFNLFlBQVkscUJBQXFCLE1BQU0scUJBQXFCLG9CQUFvQixDQUFDO0FBRXZGLE1BQUksQ0FBQyxVQUFVLG1CQUFtQjtBQUNoQyxVQUFNLElBQUksTUFBTSw2RUFBNkU7QUFBQSxFQUMvRjtBQUVBLE1BQUkscUJBQXFCO0FBQ3ZCLFVBQU0sY0FBYztBQUFBLE1BQ2xCO0FBQUEsTUFDQSxXQUFXO0FBQUEsSUFDYixDQUFDO0FBQUEsRUFDSDtBQUVBLFFBQU0sY0FBYyxrQkFDaEIsTUFBTSxVQUFVO0FBQUEsSUFDaEI7QUFBQSxJQUNBLFdBQVc7QUFBQSxFQUNiLENBQUMsSUFDQztBQUVKLE1BQUk7QUFDRixXQUFPLE1BQU0sVUFBVSxrQkFBa0IsNEJBQXFEO0FBQUEsTUFDNUY7QUFBQSxNQUNBO0FBQUEsTUFDQTtBQUFBLElBQ0YsQ0FBQyxDQUFDO0FBQUEsRUFDSixVQUFFO0FBQ0EsVUFBTSxhQUFhLFFBQVE7QUFBQSxFQUM3QjtBQUNGOyIsCiAgIm5hbWVzIjogW10KfQo=
|
|
63
|
+
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vc3JjL2NhcHR1cmUtb2JzaWRpYW4tc2NyZWVuc2hvdC50cyJdLAogICJzb3VyY2VzQ29udGVudCI6IFsiLyoqXG4gKiBAZmlsZVxuICpcbiAqIENhcHR1cmVzIGEgc2NyZWVuc2hvdCBvZiB0aGUgT2JzaWRpYW4gaW5zdGFuY2UgdGhlIGN1cnJlbnQgdGVzdCBjb250ZXh0IGlzXG4gKiBhbHJlYWR5IGRyaXZpbmcuXG4gKlxuICogVGhlIHRyYW5zcG9ydC1sZXZlbCBgY2FwdHVyZVNjcmVlbnNob3RgIG5lZWRzIGEgdHJhbnNwb3J0IGluIGhhbmQsIHdoaWNoIGFcbiAqIHRlc3QgcnVubmluZyB1bmRlciB0aGUgaGFybmVzcydzIGdsb2JhbCBzZXR1cCBuZXZlciBoYXMgXHUyMDE0IHRoZSBpbnN0YW5jZSBpc1xuICogb3duZWQgYnkgdGhhdCBzZXR1cCBhbmQgcmVhY2hlZCB0aHJvdWdoIHRoZSBjb250ZXh0IHByb3ZpZGVyLiBUaGlzIGlzIHRoZVxuICogY29udGV4dC1yZXNvbHZpbmcgZW50cnkgcG9pbnQsIHRoZSBzY3JlZW5zaG90IGNvdW50ZXJwYXJ0IG9mXG4gKiBgZXZhbEluT2JzaWRpYW5gIC8gYHBvbGxJbk9ic2lkaWFuYDogd2l0aCBubyBhcmd1bWVudHMgYXQgYWxsIGl0IGNhcHR1cmVzXG4gKiB3aGF0ZXZlciBpbnN0YW5jZSB0aGUgYWN0aXZlIHByb2plY3QgaXMgZHJpdmluZywgZGVza3RvcCBvciBtb2JpbGUuXG4gKlxuICogSXQgYWxzbyBtYWtlcyB0aGUgZnJhbWUgUkVQUk9EVUNJQkxFIGJlZm9yZSB0YWtpbmcgaXQsIGJ5IGhpZGluZyB0aGUgdmF1bHQnc1xuICogbmFtZSBcdTIwMTQgc2VlIGBoaWRlLXZhdWx0LW5hbWUudHNgIGZvciB3aHkgYSBgdGVtcC12YXVsdC08cmFuZG9tPmAgYmxlZWRzXG4gKiB0aHJvdWdoIHRoZSBjYXB0aW9uIGJhbmQgYW5kIHJld3JpdGVzIGEgY2hlY2tlZC1pbiBQTkcgb24gZXZlcnkgcnVuIFx1MjAxNCBhbmQgYnlcbiAqIGhpZGluZyB0aGUgZm9jdXNlZCBlbGVtZW50J3MgYmxpbmtpbmcgY2FyZXQgZm9yIHRoZSBsZW5ndGggb2YgdGhlIGNhcHR1cmUgXHUyMDE0XG4gKiBzZWUgYGhpZGUtY2FyZXQudHNgIGZvciB3aHkgdGhhdCBpcyBhIHRyYW5zcGFyZW50IGNhcmV0IGFuZCBub3QgYSBibHVyIFx1MjAxNFxuICogYW5kIGJ5IGRyYXdpbmcgdGhlIHdpbmRvdyBmb2N1c2VkIHdoZXRoZXIgb3Igbm90IHRoZSBPUyBnYXZlIGl0IGZvY3VzIFx1MjAxNCBzZWVcbiAqIGBwaW4td2luZG93LWZvY3VzLnRzYCBmb3IgdGhlIHRpdGxlIGJhciB0aGF0IG90aGVyd2lzZSBkYXJrZW5zIG9uZSBydW4gaW5cbiAqIGZpdmUuXG4gKlxuICogQW5kIGl0IHJlZnVzZXMgYSBmcmFtZSB3aG9zZSB0aGVtZSBoYXMgY2hhbmdlZCBzaW5jZSBgYXBwbHlPYnNpZGlhblRoZW1lYCBzZXRcbiAqIGl0IFx1MjAxNCBzZWUgYGFwcGx5LW9ic2lkaWFuLXRoZW1lLnRzYCBmb3IgdGhlIGNvbmZpZyByZWxvYWQgdGhhdCBzaWxlbnRseSB0dXJucyBhXG4gKiBkYXJrIGNhcHR1cmUgcnVuIGxpZ2h0LlxuICovXG5cbi8qIHY4IGlnbm9yZSBzdGFydCAtLSBJbnRlZ3JhdGlvbi10aW1lIGNvZGUgKGRyaXZlcyBhIGxpdmUgT2JzaWRpYW4pIGNvdmVyZWQgYnkgaW50ZWdyYXRpb24gdGVzdHMsIG5vdCB1bml0IHRlc3RzLiAqL1xuXG5pbXBvcnQgcHJvY2VzcyBmcm9tICdub2RlOnByb2Nlc3MnO1xuXG5pbXBvcnQgdHlwZSB7IENhcHR1cmVTY3JlZW5zaG90UGFyYW1zIH0gZnJvbSAnLi9jYXB0dXJlLXNjcmVlbnNob3QubWpzJztcbmltcG9ydCB0eXBlIHsgT2JzaWRpYW5UcmFuc3BvcnQgfSBmcm9tICcuL3RyYW5zcG9ydC5tanMnO1xuXG5pbXBvcnQgeyBhc3NlcnRPYnNpZGlhblRoZW1lVW5jaGFuZ2VkIH0gZnJvbSAnLi9hcHBseS1vYnNpZGlhbi10aGVtZS5tanMnO1xuaW1wb3J0IHtcbiAgZ2V0VHJhbnNwb3J0T3B0aW9ucyxcbiAgZ2V0VmF1bHRQYXRoXG59IGZyb20gJy4vY29udGV4dC1wcm92aWRlci5tanMnO1xuaW1wb3J0IHsgaGlkZUNhcmV0IH0gZnJvbSAnLi9oaWRlLWNhcmV0Lm1qcyc7XG5pbXBvcnQgeyBoaWRlVmF1bHROYW1lIH0gZnJvbSAnLi9oaWRlLXZhdWx0LW5hbWUubWpzJztcbmltcG9ydCB7IG5vcm1hbGl6ZU9wdGlvbmFsUHJvcGVydGllcyB9IGZyb20gJy4vbm9ybWFsaXplLW9wdGlvbmFsLXByb3BlcnRpZXMubWpzJztcbmltcG9ydCB7IHBpbldpbmRvd0ZvY3VzIH0gZnJvbSAnLi9waW4td2luZG93LWZvY3VzLm1qcyc7XG5pbXBvcnQgeyBnZXRPckNyZWF0ZVRyYW5zcG9ydCB9IGZyb20gJy4vdHJhbnNwb3J0LWZhY3RvcnkubWpzJztcblxuLyoqXG4gKiBPcHRpb25zIGZvciB7QGxpbmsgY2FwdHVyZU9ic2lkaWFuU2NyZWVuc2hvdH0uXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQ2FwdHVyZU9ic2lkaWFuU2NyZWVuc2hvdE9wdGlvbnMge1xuICAvKipcbiAgICogVGhlIGV4YWN0IGhlaWdodCBpbiBwaXhlbHMgdGhlIGNhcHR1cmVkIGltYWdlIHNob3VsZCBoYXZlLlxuICAgKlxuICAgKiBEZXNrdG9wIG9ubHksIGFuZCBvbmx5IG1lYW5pbmdmdWwgdG9nZXRoZXIgd2l0aCB7QGxpbmsgd2lkdGhJblBpeGVsc30uXG4gICAqIElnbm9yZWQgb24gbW9iaWxlLCB3aGVyZSB0aGUgaW1hZ2UgaXMgYWx3YXlzIHRoZSBkZXZpY2UncyBuYXRpdmVcbiAgICogZnJhbWVidWZmZXIgXHUyMDE0IHNpemUgdGhvc2UgYnkgY2hvb3NpbmcgYW4gQVZEIHdpdGggdGhlIHdhbnRlZCBzY3JlZW5cbiAgICogZ2VvbWV0cnkuXG4gICAqL1xuICByZWFkb25seSBoZWlnaHRJblBpeGVscz86IG51bWJlcjtcblxuICAvKipcbiAgICogV2hldGhlciB0byBoaWRlIHRoZSBmb2N1c2VkIGVsZW1lbnQncyBjYXJldCB3aGlsZSBjYXB0dXJpbmcsIHNvIHRoZSBmcmFtZVxuICAgKiBkb2VzIG5vdCBkZXBlbmQgb24gd2hpY2ggcGhhc2Ugb2YgaXRzIGJsaW5rIHRoZSBjYXB0dXJlIGNhdWdodC5cbiAgICpcbiAgICogVGhlIGNhcmV0IGlzIG1hZGUgdHJhbnNwYXJlbnQsIG5vdCBibHVycmVkOiB0aGUgZm9jdXMsIGl0cyByaW5nIGFuZFxuICAgKiBhbnl0aGluZyBvcGVuIGJlY2F1c2Ugb2YgaXQgXHUyMDE0IGEgc3VnZ2VzdGVyIHVuZGVyIGFuIGlucHV0IFx1MjAxNCBhbGwgc3RheSBhcyB0aGVcbiAgICogdGVzdCBidWlsdCB0aGVtLCBhbmQgdGhlIGNhcmV0IGlzIHB1dCBiYWNrIG9uY2UgdGhlIGZyYW1lIGlzIHRha2VuLiBUdXJuIGl0XG4gICAqIG9mZiBvbmx5IHRvIHBob3RvZ3JhcGggdGhlIGNhcmV0IGl0c2VsZiwgYW5kIGV4cGVjdCBzdWNoIGEgZnJhbWUgdG8gZGlmZmVyXG4gICAqIGJldHdlZW4gcnVucy5cbiAgICpcbiAgICogQGRlZmF1bHQgYHRydWVgXG4gICAqL1xuICByZWFkb25seSBzaG91bGRIaWRlQ2FyZXQ/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBXaGV0aGVyIHRvIGhpZGUgdGhlIHZhdWx0J3MgbmFtZSBiZWZvcmUgY2FwdHVyaW5nLCBzbyB0aGUgZnJhbWUgZG9lcyBub3RcbiAgICogZGVwZW5kIG9uIHRoZSByYW5kb20gc3VmZml4IG9mIHRoZSBoYXJuZXNzJ3MgdGVtcG9yYXJ5IHZhdWx0LlxuICAgKlxuICAgKiBBIGRlZmF1bHQgcmF0aGVyIHRoYW4gYSBrbm9iOiByZXByb2R1Y2liaWxpdHkgaXMgd2hhdCBhIGNoZWNrZWQtaW5cbiAgICogc2NyZWVuc2hvdCBpcyBmb3IsIGFuZCB0aGUgcm93IGl0IGNvbGxhcHNlcyBzaXRzIHVuZGVyIHRoZSBjYXB0aW9uIGJhbmQsXG4gICAqIHNvIG5vdGhpbmcgYSByZWFkZXIgc2VlcyBtb3Zlcy4gVHVybiBpdCBvZmYgb25seSB0byBwaG90b2dyYXBoIHRoZSB2YXVsdFxuICAgKiBzd2l0Y2hlciBpdHNlbGYuXG4gICAqXG4gICAqIEBkZWZhdWx0IGB0cnVlYFxuICAgKi9cbiAgcmVhZG9ubHkgc2hvdWxkSGlkZVZhdWx0TmFtZT86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgdG8gZHJhdyB0aGUgd2luZG93IGFzIGZvY3VzZWQgd2hpbGUgY2FwdHVyaW5nLCBzbyB0aGUgZnJhbWUgZG9lc1xuICAgKiBub3QgZGVwZW5kIG9uIHdoZXRoZXIgdGhlIG9wZXJhdGluZyBzeXN0ZW0gZ2F2ZSB0aGUgd2luZG93IGZvcmVncm91bmRcbiAgICogZm9jdXMgdGhhdCBydW4uXG4gICAqXG4gICAqIE9ic2lkaWFuIGRhcmtlbnMgdGhlIHRpdGxlIGJhciBvZiBhbiB1bmZvY3VzZWQgd2luZG93LCBhbmQgYSBmcmVzaGx5XG4gICAqIGxhdW5jaGVkIG9uZSBpcyByb3V0aW5lbHkgcmVmdXNlZCB0aGUgZm9yZWdyb3VuZC4gVGhlIGBpcy1mb2N1c2VkYCBjbGFzcyBpc1xuICAgKiBhZGRlZCBmb3IgdGhlIGNhcHR1cmUgYW5kIGhhbmRlZCBiYWNrIHRvIE9ic2lkaWFuIGFmdGVyd2FyZHM7IHRoZSB3aW5kb3cnc1xuICAgKiByZWFsIGZvY3VzIGlzIG5ldmVyIHRvdWNoZWQuIFR1cm4gaXQgb2ZmIG9ubHkgdG8gcGhvdG9ncmFwaCB0aGUgdW5mb2N1c2VkXG4gICAqIGNocm9tZSBpdHNlbGYsIGFuZCBleHBlY3Qgc3VjaCBhIGZyYW1lIHRvIGRpZmZlciBiZXR3ZWVuIHJ1bnMuXG4gICAqXG4gICAqIEBkZWZhdWx0IGB0cnVlYFxuICAgKi9cbiAgcmVhZG9ubHkgc2hvdWxkUGluV2luZG93Rm9jdXM/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBXaGV0aGVyIHRvIHJlZnVzZSB0aGUgZnJhbWUgd2hlbiB0aGUgYm9keSBpcyBubyBsb25nZXIgaW4gdGhlIHRoZW1lXG4gICAqIGBhcHBseU9ic2lkaWFuVGhlbWVgIGxhc3QgYXBwbGllZC5cbiAgICpcbiAgICogQSB0aGVtZSBsb3N0IGFmdGVyIGl0IHdhcyBhcHBsaWVkIGZhaWxzIG5vdGhpbmcgb24gaXRzIG93bjogdGhlIGZyYW1lIGlzXG4gICAqIHNpbXBseSBzaG90IGluIHRoZSBvdGhlciB0aGVtZSBhbmQgd3JpdHRlbiBvdmVyIHRoZSBjb21taXR0ZWQgb25lLiBSZWZ1c2luZ1xuICAgKiB0dXJucyB0aGF0IGludG8gYSBuYW1lZCBlcnJvci4gTm90aGluZyBpcyBjaGVja2VkIHdoZW4gbm8gdGhlbWUgd2FzIGFwcGxpZWRcbiAgICogdGhyb3VnaCBgYXBwbHlPYnNpZGlhblRoZW1lYC4gVHVybiBpdCBvZmYgb25seSBmb3IgYSBmcmFtZSB0aGF0IGNoYW5nZXMgdGhlXG4gICAqIHRoZW1lIG9uIHB1cnBvc2UuXG4gICAqXG4gICAqIEBkZWZhdWx0IGB0cnVlYFxuICAgKi9cbiAgcmVhZG9ubHkgc2hvdWxkVmVyaWZ5VGhlbWU/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBPdmVycmlkZSB0aGUgdHJhbnNwb3J0LiBXaGVuIG9taXR0ZWQsIHRoZSB0cmFuc3BvcnQgdGhlIGN1cnJlbnQgdGVzdFxuICAgKiBjb250ZXh0IGlzIGRyaXZpbmcgaXMgdXNlZC5cbiAgICovXG4gIHJlYWRvbmx5IHRyYW5zcG9ydD86IE9ic2lkaWFuVHJhbnNwb3J0O1xuXG4gIC8qKlxuICAgKiBUaGUgdmF1bHQgcGF0aCB0byBjYXB0dXJlLiBXaGVuIG9taXR0ZWQsIHRoZSBjdXJyZW50IHRlc3QgY29udGV4dCdzIHZhdWx0XG4gICAqIGlzIHVzZWQuXG4gICAqL1xuICByZWFkb25seSB2YXVsdFBhdGg/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSBleGFjdCB3aWR0aCBpbiBwaXhlbHMgdGhlIGNhcHR1cmVkIGltYWdlIHNob3VsZCBoYXZlLlxuICAgKlxuICAgKiBTZWUge0BsaW5rIGhlaWdodEluUGl4ZWxzfSBcdTIwMTQgdGhlIHR3byBhcmUgc2V0IHRvZ2V0aGVyIG9yIG5vdCBhdCBhbGwuXG4gICAqL1xuICByZWFkb25seSB3aWR0aEluUGl4ZWxzPzogbnVtYmVyO1xufVxuXG4vKipcbiAqIENhcHR1cmVzIGEgUE5HIHNjcmVlbnNob3Qgb2YgdGhlIHJ1bm5pbmcgT2JzaWRpYW4gaW5zdGFuY2UsIHJlc29sdmluZyB0aGVcbiAqIHRyYW5zcG9ydCBhbmQgdmF1bHQgZnJvbSB0aGUgY3VycmVudCB0ZXN0IGNvbnRleHQuXG4gKlxuICogVGhlIHZhdWx0J3MgbmFtZSBpcyBoaWRkZW4gZmlyc3QsIHNvIHR3byBydW5zIG9mIHRoZSBzYW1lIHN1aXRlIGFnYWluc3QgdHdvXG4gKiBkaWZmZXJlbnRseS1uYW1lZCB0ZW1wb3JhcnkgdmF1bHRzIHByb2R1Y2UgYnl0ZS1pZGVudGljYWwgUE5Hcy4gUGFzc1xuICoge0BsaW5rIENhcHR1cmVPYnNpZGlhblNjcmVlbnNob3RPcHRpb25zLnNob3VsZEhpZGVWYXVsdE5hbWV9IGFzIGBmYWxzZWAgdG9cbiAqIHBob3RvZ3JhcGggaXQuIFRoZSBmb2N1c2VkIGVsZW1lbnQncyBjYXJldCBpcyBoaWRkZW4gZm9yIHRoZSBjYXB0dXJlIHRvbywgYW5kXG4gKiByZXN0b3JlZCBhZnRlciBpdCwgc28gYSBmcmFtZSB3aXRoIGEgZm9jdXNlZCBmaWVsZCBkb2VzIG5vdCBhbHRlcm5hdGUgYmV0d2VlblxuICogdHdvIGJsaW5rIHBoYXNlczsge0BsaW5rIENhcHR1cmVPYnNpZGlhblNjcmVlbnNob3RPcHRpb25zLnNob3VsZEhpZGVDYXJldH1cbiAqIHR1cm5zIHRoYXQgb2ZmLiBUaGUgd2luZG93IGlzIGRyYXduIGZvY3VzZWQgd2hldGhlciBvciBub3QgdGhlIE9TIGdhdmUgaXRcbiAqIGZvY3VzOyB7QGxpbmsgQ2FwdHVyZU9ic2lkaWFuU2NyZWVuc2hvdE9wdGlvbnMuc2hvdWxkUGluV2luZG93Rm9jdXN9IHR1cm5zXG4gKiB0aGF0IG9mZi4gQSBmcmFtZSB3aG9zZSBib2R5IGhhcyBsZWZ0IHRoZSB0aGVtZSBgYXBwbHlPYnNpZGlhblRoZW1lYFxuICogYXBwbGllZCBpcyByZWZ1c2VkOyB7QGxpbmsgQ2FwdHVyZU9ic2lkaWFuU2NyZWVuc2hvdE9wdGlvbnMuc2hvdWxkVmVyaWZ5VGhlbWV9XG4gKiB0dXJucyB0aGF0IG9mZi5cbiAqXG4gKiBAcGFyYW0gb3B0aW9ucyAtIE9wdGlvbmFsIHNpemUsIHRyYW5zcG9ydCBhbmQgdmF1bHQgb3ZlcnJpZGVzLlxuICogQHJldHVybnMgQSB7QGxpbmsgUHJvbWlzZX0gdGhhdCByZXNvbHZlcyB0byB0aGUgcmF3IFBORyBieXRlcy5cbiAqIEB0aHJvd3MgRXJyb3IgaWYgdGhlIGFjdGl2ZSB0cmFuc3BvcnQgY2Fubm90IGNhcHR1cmUgc2NyZWVuc2hvdHMsIG9yIGlmIHRoZVxuICogICB0aGVtZSBoYXMgY2hhbmdlZCBzaW5jZSBgYXBwbHlPYnNpZGlhblRoZW1lYCBhcHBsaWVkIGl0LlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY2FwdHVyZU9ic2lkaWFuU2NyZWVuc2hvdChvcHRpb25zPzogQ2FwdHVyZU9ic2lkaWFuU2NyZWVuc2hvdE9wdGlvbnMpOiBQcm9taXNlPFVpbnQ4QXJyYXk+IHtcbiAgY29uc3Qge1xuICAgIGhlaWdodEluUGl4ZWxzLFxuICAgIHNob3VsZEhpZGVDYXJldCA9IHRydWUsXG4gICAgc2hvdWxkSGlkZVZhdWx0TmFtZSA9IHRydWUsXG4gICAgc2hvdWxkUGluV2luZG93Rm9jdXMgPSB0cnVlLFxuICAgIHNob3VsZFZlcmlmeVRoZW1lID0gdHJ1ZSxcbiAgICB0cmFuc3BvcnQ6IHRyYW5zcG9ydE92ZXJyaWRlLFxuICAgIHZhdWx0UGF0aCxcbiAgICB3aWR0aEluUGl4ZWxzXG4gIH0gPSBvcHRpb25zID8/IHt9O1xuXG4gIGNvbnN0IGN3ZCA9IHZhdWx0UGF0aCA/PyBnZXRWYXVsdFBhdGgoKSA/PyBwcm9jZXNzLmN3ZCgpO1xuICBjb25zdCB0cmFuc3BvcnQgPSB0cmFuc3BvcnRPdmVycmlkZSA/PyBhd2FpdCBnZXRPckNyZWF0ZVRyYW5zcG9ydChnZXRUcmFuc3BvcnRPcHRpb25zKCkpO1xuXG4gIGlmICghdHJhbnNwb3J0LmNhcHR1cmVTY3JlZW5zaG90KSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdjYXB0dXJlT2JzaWRpYW5TY3JlZW5zaG90OiB0aGUgYWN0aXZlIHRyYW5zcG9ydCBjYW5ub3QgY2FwdHVyZSBzY3JlZW5zaG90cy4nKTtcbiAgfVxuXG4gIGlmIChzaG91bGRWZXJpZnlUaGVtZSkge1xuICAgIGF3YWl0IGFzc2VydE9ic2lkaWFuVGhlbWVVbmNoYW5nZWQoe1xuICAgICAgYWN0aW9uOiAnY2FwdHVyZSBhIHNjcmVlbnNob3QnLFxuICAgICAgdHJhbnNwb3J0LFxuICAgICAgdmF1bHRQYXRoOiBjd2RcbiAgICB9KTtcbiAgfVxuXG4gIGlmIChzaG91bGRIaWRlVmF1bHROYW1lKSB7XG4gICAgYXdhaXQgaGlkZVZhdWx0TmFtZSh7XG4gICAgICB0cmFuc3BvcnQsXG4gICAgICB2YXVsdFBhdGg6IGN3ZFxuICAgIH0pO1xuICB9XG5cbiAgY29uc3QgaGlkZGVuQ2FyZXQgPSBzaG91bGRIaWRlQ2FyZXRcbiAgICA/IGF3YWl0IGhpZGVDYXJldCh7XG4gICAgICB0cmFuc3BvcnQsXG4gICAgICB2YXVsdFBhdGg6IGN3ZFxuICAgIH0pXG4gICAgOiB1bmRlZmluZWQ7XG5cbiAgY29uc3QgcGlubmVkV2luZG93Rm9jdXMgPSBzaG91bGRQaW5XaW5kb3dGb2N1c1xuICAgID8gYXdhaXQgcGluV2luZG93Rm9jdXMoe1xuICAgICAgdHJhbnNwb3J0LFxuICAgICAgdmF1bHRQYXRoOiBjd2RcbiAgICB9KVxuICAgIDogdW5kZWZpbmVkO1xuXG4gIHRyeSB7XG4gICAgcmV0dXJuIGF3YWl0IHRyYW5zcG9ydC5jYXB0dXJlU2NyZWVuc2hvdChub3JtYWxpemVPcHRpb25hbFByb3BlcnRpZXM8Q2FwdHVyZVNjcmVlbnNob3RQYXJhbXM+KHtcbiAgICAgIGN3ZCxcbiAgICAgIGhlaWdodEluUGl4ZWxzLFxuICAgICAgd2lkdGhJblBpeGVsc1xuICAgIH0pKTtcbiAgfSBmaW5hbGx5IHtcbiAgICBhd2FpdCBwaW5uZWRXaW5kb3dGb2N1cz8ucmVzdG9yZSgpO1xuICAgIGF3YWl0IGhpZGRlbkNhcmV0Py5yZXN0b3JlKCk7XG4gIH1cbn1cblxuLyogdjggaWdub3JlIHN0b3AgKi9cbiJdLAogICJtYXBwaW5ncyI6ICJBQTZCQSxPQUFPLGFBQWE7QUFLcEIsU0FBUyxvQ0FBb0M7QUFDN0M7QUFBQSxFQUNFO0FBQUEsRUFDQTtBQUFBLE9BQ0s7QUFDUCxTQUFTLGlCQUFpQjtBQUMxQixTQUFTLHFCQUFxQjtBQUM5QixTQUFTLG1DQUFtQztBQUM1QyxTQUFTLHNCQUFzQjtBQUMvQixTQUFTLDRCQUE0QjtBQWlIckMsZUFBc0IsMEJBQTBCLFNBQWlFO0FBQy9HLFFBQU07QUFBQSxJQUNKO0FBQUEsSUFDQSxrQkFBa0I7QUFBQSxJQUNsQixzQkFBc0I7QUFBQSxJQUN0Qix1QkFBdUI7QUFBQSxJQUN2QixvQkFBb0I7QUFBQSxJQUNwQixXQUFXO0FBQUEsSUFDWDtBQUFBLElBQ0E7QUFBQSxFQUNGLElBQUksV0FBVyxDQUFDO0FBRWhCLFFBQU0sTUFBTSxhQUFhLGFBQWEsS0FBSyxRQUFRLElBQUk7QUFDdkQsUUFBTSxZQUFZLHFCQUFxQixNQUFNLHFCQUFxQixvQkFBb0IsQ0FBQztBQUV2RixNQUFJLENBQUMsVUFBVSxtQkFBbUI7QUFDaEMsVUFBTSxJQUFJLE1BQU0sNkVBQTZFO0FBQUEsRUFDL0Y7QUFFQSxNQUFJLG1CQUFtQjtBQUNyQixVQUFNLDZCQUE2QjtBQUFBLE1BQ2pDLFFBQVE7QUFBQSxNQUNSO0FBQUEsTUFDQSxXQUFXO0FBQUEsSUFDYixDQUFDO0FBQUEsRUFDSDtBQUVBLE1BQUkscUJBQXFCO0FBQ3ZCLFVBQU0sY0FBYztBQUFBLE1BQ2xCO0FBQUEsTUFDQSxXQUFXO0FBQUEsSUFDYixDQUFDO0FBQUEsRUFDSDtBQUVBLFFBQU0sY0FBYyxrQkFDaEIsTUFBTSxVQUFVO0FBQUEsSUFDaEI7QUFBQSxJQUNBLFdBQVc7QUFBQSxFQUNiLENBQUMsSUFDQztBQUVKLFFBQU0sb0JBQW9CLHVCQUN0QixNQUFNLGVBQWU7QUFBQSxJQUNyQjtBQUFBLElBQ0EsV0FBVztBQUFBLEVBQ2IsQ0FBQyxJQUNDO0FBRUosTUFBSTtBQUNGLFdBQU8sTUFBTSxVQUFVLGtCQUFrQiw0QkFBcUQ7QUFBQSxNQUM1RjtBQUFBLE1BQ0E7QUFBQSxNQUNBO0FBQUEsSUFDRixDQUFDLENBQUM7QUFBQSxFQUNKLFVBQUU7QUFDQSxVQUFNLG1CQUFtQixRQUFRO0FBQ2pDLFVBQU0sYUFBYSxRQUFRO0FBQUEsRUFDN0I7QUFDRjsiLAogICJuYW1lcyI6IFtdCn0K
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file
|
|
3
|
+
*
|
|
4
|
+
* The Chromium switches that make an owned desktop instance rasterize the same
|
|
5
|
+
* frame to the same bytes every time it is captured.
|
|
6
|
+
*
|
|
7
|
+
* A sized capture pins the viewport with `Emulation.setDeviceMetricsOverride`
|
|
8
|
+
* and clears the override afterwards, so every capture re-rasterizes the page
|
|
9
|
+
* at the requested size. With GPU rasterization on, that re-raster is not
|
|
10
|
+
* deterministic: the soft `box-shadow` of a modal and of a suggester come back
|
|
11
|
+
* one value off in a single channel in a fraction of the captures, with nothing
|
|
12
|
+
* visibly different. Measured on a 1200x800 frame with a modal and a suggester
|
|
13
|
+
* open, 300 captures each:
|
|
14
|
+
*
|
|
15
|
+
* | Launch | Distinct frames |
|
|
16
|
+
* | --- | --- |
|
|
17
|
+
* | default | 3 (253 / 39 / 8) |
|
|
18
|
+
* | `--disable-partial-raster` | 3 (201 / 83 / 16) |
|
|
19
|
+
* | `--force-color-profile=srgb` | 3 (209 / 78 / 13) |
|
|
20
|
+
* | no size override at all | 1 |
|
|
21
|
+
* | `--disable-gpu-rasterization` | 1 |
|
|
22
|
+
*
|
|
23
|
+
* So the noise is the GPU rasterizer redoing the page after a resize, and the
|
|
24
|
+
* resize cannot go, because a sized capture is the whole point of the size
|
|
25
|
+
* options. Rasterizing on the CPU closes it while compositing stays on the GPU,
|
|
26
|
+
* which is why this is `--disable-gpu-rasterization` and not `--disable-gpu`
|
|
27
|
+
* (also stable, but it moves compositing to software as well). It cost no
|
|
28
|
+
* capture time in the same measurement.
|
|
29
|
+
*/
|
|
30
|
+
/**
|
|
31
|
+
* Chromium switches passed to every **owned** desktop instance so its captures
|
|
32
|
+
* are byte-reproducible.
|
|
33
|
+
*
|
|
34
|
+
* Only an owned instance gets them: an attached Obsidian was launched by
|
|
35
|
+
* somebody else, and its switches are not the harness's to choose.
|
|
36
|
+
*/
|
|
37
|
+
export declare const DETERMINISTIC_RASTER_LAUNCH_FLAGS: readonly string[];
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
const DETERMINISTIC_RASTER_LAUNCH_FLAGS = [
|
|
2
|
+
"--disable-gpu-rasterization"
|
|
3
|
+
];
|
|
4
|
+
export {
|
|
5
|
+
DETERMINISTIC_RASTER_LAUNCH_FLAGS
|
|
6
|
+
};
|
|
7
|
+
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vc3JjL2RldGVybWluaXN0aWMtcmFzdGVyLnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyIvKipcbiAqIEBmaWxlXG4gKlxuICogVGhlIENocm9taXVtIHN3aXRjaGVzIHRoYXQgbWFrZSBhbiBvd25lZCBkZXNrdG9wIGluc3RhbmNlIHJhc3Rlcml6ZSB0aGUgc2FtZVxuICogZnJhbWUgdG8gdGhlIHNhbWUgYnl0ZXMgZXZlcnkgdGltZSBpdCBpcyBjYXB0dXJlZC5cbiAqXG4gKiBBIHNpemVkIGNhcHR1cmUgcGlucyB0aGUgdmlld3BvcnQgd2l0aCBgRW11bGF0aW9uLnNldERldmljZU1ldHJpY3NPdmVycmlkZWBcbiAqIGFuZCBjbGVhcnMgdGhlIG92ZXJyaWRlIGFmdGVyd2FyZHMsIHNvIGV2ZXJ5IGNhcHR1cmUgcmUtcmFzdGVyaXplcyB0aGUgcGFnZVxuICogYXQgdGhlIHJlcXVlc3RlZCBzaXplLiBXaXRoIEdQVSByYXN0ZXJpemF0aW9uIG9uLCB0aGF0IHJlLXJhc3RlciBpcyBub3RcbiAqIGRldGVybWluaXN0aWM6IHRoZSBzb2Z0IGBib3gtc2hhZG93YCBvZiBhIG1vZGFsIGFuZCBvZiBhIHN1Z2dlc3RlciBjb21lIGJhY2tcbiAqIG9uZSB2YWx1ZSBvZmYgaW4gYSBzaW5nbGUgY2hhbm5lbCBpbiBhIGZyYWN0aW9uIG9mIHRoZSBjYXB0dXJlcywgd2l0aCBub3RoaW5nXG4gKiB2aXNpYmx5IGRpZmZlcmVudC4gTWVhc3VyZWQgb24gYSAxMjAweDgwMCBmcmFtZSB3aXRoIGEgbW9kYWwgYW5kIGEgc3VnZ2VzdGVyXG4gKiBvcGVuLCAzMDAgY2FwdHVyZXMgZWFjaDpcbiAqXG4gKiB8IExhdW5jaCB8IERpc3RpbmN0IGZyYW1lcyB8XG4gKiB8IC0tLSB8IC0tLSB8XG4gKiB8IGRlZmF1bHQgfCAzICgyNTMgLyAzOSAvIDgpIHxcbiAqIHwgYC0tZGlzYWJsZS1wYXJ0aWFsLXJhc3RlcmAgfCAzICgyMDEgLyA4MyAvIDE2KSB8XG4gKiB8IGAtLWZvcmNlLWNvbG9yLXByb2ZpbGU9c3JnYmAgfCAzICgyMDkgLyA3OCAvIDEzKSB8XG4gKiB8IG5vIHNpemUgb3ZlcnJpZGUgYXQgYWxsIHwgMSB8XG4gKiB8IGAtLWRpc2FibGUtZ3B1LXJhc3Rlcml6YXRpb25gIHwgMSB8XG4gKlxuICogU28gdGhlIG5vaXNlIGlzIHRoZSBHUFUgcmFzdGVyaXplciByZWRvaW5nIHRoZSBwYWdlIGFmdGVyIGEgcmVzaXplLCBhbmQgdGhlXG4gKiByZXNpemUgY2Fubm90IGdvLCBiZWNhdXNlIGEgc2l6ZWQgY2FwdHVyZSBpcyB0aGUgd2hvbGUgcG9pbnQgb2YgdGhlIHNpemVcbiAqIG9wdGlvbnMuIFJhc3Rlcml6aW5nIG9uIHRoZSBDUFUgY2xvc2VzIGl0IHdoaWxlIGNvbXBvc2l0aW5nIHN0YXlzIG9uIHRoZSBHUFUsXG4gKiB3aGljaCBpcyB3aHkgdGhpcyBpcyBgLS1kaXNhYmxlLWdwdS1yYXN0ZXJpemF0aW9uYCBhbmQgbm90IGAtLWRpc2FibGUtZ3B1YFxuICogKGFsc28gc3RhYmxlLCBidXQgaXQgbW92ZXMgY29tcG9zaXRpbmcgdG8gc29mdHdhcmUgYXMgd2VsbCkuIEl0IGNvc3Qgbm9cbiAqIGNhcHR1cmUgdGltZSBpbiB0aGUgc2FtZSBtZWFzdXJlbWVudC5cbiAqL1xuXG4vKipcbiAqIENocm9taXVtIHN3aXRjaGVzIHBhc3NlZCB0byBldmVyeSAqKm93bmVkKiogZGVza3RvcCBpbnN0YW5jZSBzbyBpdHMgY2FwdHVyZXNcbiAqIGFyZSBieXRlLXJlcHJvZHVjaWJsZS5cbiAqXG4gKiBPbmx5IGFuIG93bmVkIGluc3RhbmNlIGdldHMgdGhlbTogYW4gYXR0YWNoZWQgT2JzaWRpYW4gd2FzIGxhdW5jaGVkIGJ5XG4gKiBzb21lYm9keSBlbHNlLCBhbmQgaXRzIHN3aXRjaGVzIGFyZSBub3QgdGhlIGhhcm5lc3MncyB0byBjaG9vc2UuXG4gKi9cbmV4cG9ydCBjb25zdCBERVRFUk1JTklTVElDX1JBU1RFUl9MQVVOQ0hfRkxBR1M6IHJlYWRvbmx5IHN0cmluZ1tdID0gW1xuICAnLS1kaXNhYmxlLWdwdS1yYXN0ZXJpemF0aW9uJ1xuXTtcbiJdLAogICJtYXBwaW5ncyI6ICJBQXFDTyxNQUFNLG9DQUF1RDtBQUFBLEVBQ2xFO0FBQ0Y7IiwKICAibmFtZXMiOiBbXQp9Cg==
|
|
@@ -22,6 +22,10 @@ export interface ClickElementParams {
|
|
|
22
22
|
* The element to click. The pointer is moved to its center. This is a live
|
|
23
23
|
* renderer DOM node — the callback runs in-renderer, so no cross-process
|
|
24
24
|
* serialization is needed (same as {@link TypeIntoEditorParams.editor}).
|
|
25
|
+
*
|
|
26
|
+
* The input goes to the window that owns the element (its
|
|
27
|
+
* `ownerDocument.defaultView`), so an element in a popout is driven in that
|
|
28
|
+
* popout with no extra parameter.
|
|
25
29
|
*/
|
|
26
30
|
readonly element: HTMLElement;
|
|
27
31
|
/**
|
|
@@ -49,6 +53,18 @@ export interface ClickMouseParams {
|
|
|
49
53
|
* @default `[]`
|
|
50
54
|
*/
|
|
51
55
|
readonly modifiers?: readonly Modifier[];
|
|
56
|
+
/**
|
|
57
|
+
* The Obsidian window to click in: the main window or a popout. Pass the
|
|
58
|
+
* window that owns the target, e.g. `leaf.view.containerEl.win` for a popout
|
|
59
|
+
* leaf. Each Obsidian window is its own Electron web contents, so a click
|
|
60
|
+
* sent to one never reaches another, and the coordinates are in the named
|
|
61
|
+
* window's viewport.
|
|
62
|
+
*
|
|
63
|
+
* **On mobile** there are no popouts, so any window but the main one throws.
|
|
64
|
+
*
|
|
65
|
+
* @default the main window (`globalThis`)
|
|
66
|
+
*/
|
|
67
|
+
readonly window?: Window;
|
|
52
68
|
/**
|
|
53
69
|
* The x coordinate (web-contents DIP) to click at.
|
|
54
70
|
*/
|
|
@@ -148,6 +164,10 @@ export interface HoverElementParams {
|
|
|
148
164
|
* The element to hover. The pointer is moved to its center. This is a live
|
|
149
165
|
* renderer DOM node — the callback runs in-renderer, so no cross-process
|
|
150
166
|
* serialization is needed (same as {@link TypeIntoEditorParams.editor}).
|
|
167
|
+
*
|
|
168
|
+
* The input goes to the window that owns the element (its
|
|
169
|
+
* `ownerDocument.defaultView`), so an element in a popout is driven in that
|
|
170
|
+
* popout with no extra parameter.
|
|
151
171
|
*/
|
|
152
172
|
readonly element: HTMLElement;
|
|
153
173
|
}
|
|
@@ -226,6 +246,10 @@ export interface Lib {
|
|
|
226
246
|
* A real context menu actually opens, so a suite driving a right click must
|
|
227
247
|
* close it (or remove the leftover `.menu` element) before the next test.
|
|
228
248
|
*
|
|
249
|
+
* It clicks in the main window unless {@link ClickMouseParams.window} names a
|
|
250
|
+
* popout. {@link Lib.clickElement} needs no such parameter: it clicks in the
|
|
251
|
+
* window that owns its element.
|
|
252
|
+
*
|
|
229
253
|
* **On mobile** the button model does not survive the port: touch has no
|
|
230
254
|
* buttons, so `'left'` (the default) is a **tap**, `'right'` is the
|
|
231
255
|
* **long-press** that opens Obsidian Mobile's context menu, and `'middle'`
|
|
@@ -313,6 +337,9 @@ export interface Lib {
|
|
|
313
337
|
* **Desktop only — it throws on mobile**, for the same reason as
|
|
314
338
|
* {@link Lib.hoverElement}: there is no touch pointer to move.
|
|
315
339
|
*
|
|
340
|
+
* It moves the pointer in the main window unless
|
|
341
|
+
* {@link MoveMouseParams.window} names a popout.
|
|
342
|
+
*
|
|
316
343
|
* **Must be awaited** — see {@link Lib.clickElement}.
|
|
317
344
|
*
|
|
318
345
|
* @param params - The web-contents DIP coordinates to move to.
|
|
@@ -371,6 +398,10 @@ export interface Lib {
|
|
|
371
398
|
* expected effect via {@link Lib.waitUntil}. It targets the single shared
|
|
372
399
|
* window's **global** focus, so only the DOM-focused element receives the key.
|
|
373
400
|
*
|
|
401
|
+
* It presses the key in the main window unless
|
|
402
|
+
* {@link PressKeyParams.window} names a popout. Each Obsidian window is its
|
|
403
|
+
* own web contents, so a key pressed in one never reaches another.
|
|
404
|
+
*
|
|
374
405
|
* **On mobile** the same sequence is injected through the WebView's debugger
|
|
375
406
|
* (`Input.dispatchKeyEvent`), which is equally trusted. Named keys (`'Enter'`,
|
|
376
407
|
* `'Escape'`, `'Tab'`, `'Backspace'`, `'Delete'`, the arrows) and single
|
|
@@ -461,6 +492,17 @@ export type MouseButton = 'left' | 'middle' | 'right';
|
|
|
461
492
|
* Parameters for {@link Lib.moveMouse}.
|
|
462
493
|
*/
|
|
463
494
|
export interface MoveMouseParams {
|
|
495
|
+
/**
|
|
496
|
+
* The Obsidian window to move the pointer in: the main window or a popout.
|
|
497
|
+
* Each Obsidian window is its own Electron web contents with its own pointer,
|
|
498
|
+
* and the coordinates are in the named window's viewport.
|
|
499
|
+
*
|
|
500
|
+
* Mobile has no pointer to move, so {@link Lib.moveMouse} throws there
|
|
501
|
+
* whatever this is.
|
|
502
|
+
*
|
|
503
|
+
* @default the main window (`globalThis`)
|
|
504
|
+
*/
|
|
505
|
+
readonly window?: Window;
|
|
464
506
|
/**
|
|
465
507
|
* The x coordinate (web-contents DIP) to move the pointer to.
|
|
466
508
|
*/
|
|
@@ -515,6 +557,18 @@ export interface PressKeyParams {
|
|
|
515
557
|
* @default `[]`
|
|
516
558
|
*/
|
|
517
559
|
readonly modifiers?: readonly Modifier[];
|
|
560
|
+
/**
|
|
561
|
+
* The Obsidian window to press the key in: the main window or a popout. Pass
|
|
562
|
+
* the window that owns the focused target, e.g. `leaf.view.containerEl.win`
|
|
563
|
+
* for a popout leaf. Each Obsidian window is its own Electron web contents,
|
|
564
|
+
* so the key goes to the DOM-focused element of the window named here,
|
|
565
|
+
* whichever window the OS has focused, and never reaches another window.
|
|
566
|
+
*
|
|
567
|
+
* **On mobile** there are no popouts, so any window but the main one throws.
|
|
568
|
+
*
|
|
569
|
+
* @default the main window (`globalThis`)
|
|
570
|
+
*/
|
|
571
|
+
readonly window?: Window;
|
|
518
572
|
}
|
|
519
573
|
/**
|
|
520
574
|
* Parameters for {@link Lib.typeIntoEditor}.
|
|
@@ -523,6 +577,9 @@ export interface TypeIntoEditorParams {
|
|
|
523
577
|
/**
|
|
524
578
|
* The editor to type into. It is focused (with the caret moved to the end of
|
|
525
579
|
* the document) before the keystrokes are injected.
|
|
580
|
+
*
|
|
581
|
+
* The keystrokes go to the window that owns the editor, so an editor in a
|
|
582
|
+
* popout is typed into in that popout with no extra parameter.
|
|
526
583
|
*/
|
|
527
584
|
readonly editor: Editor;
|
|
528
585
|
/**
|
|
@@ -540,6 +597,9 @@ export interface UnhoverElementParams {
|
|
|
540
597
|
* just outside its bounding box. This is a live renderer DOM node — the
|
|
541
598
|
* callback runs in-renderer, so no cross-process serialization is needed
|
|
542
599
|
* (same as {@link TypeIntoEditorParams.editor}).
|
|
600
|
+
*
|
|
601
|
+
* The move goes to the window that owns the element, so an element in a
|
|
602
|
+
* popout is driven in that popout with no extra parameter.
|
|
543
603
|
*/
|
|
544
604
|
readonly element: HTMLElement;
|
|
545
605
|
}
|